<commit_before>package ch.hsr.servicestoolkit.importer;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;

import javax.transaction.Transactional;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import ch.hsr.servicestoolkit.importer.api.BusinessTransaction;
import ch.hsr.servicestoolkit.importer.api.DistanceVariant;
import ch.hsr.servicestoolkit.importer.api.DomainModel;
import ch.hsr.servicestoolkit.importer.api.Entity;
import ch.hsr.servicestoolkit.importer.api.EntityAttribute;
import ch.hsr.servicestoolkit.importer.api.EntityRelation;
import ch.hsr.servicestoolkit.importer.api.EntityRelation.RelationType;
import ch.hsr.servicestoolkit.model.CouplingCriteriaVariant;
import ch.hsr.servicestoolkit.model.CouplingCriterion;
import ch.hsr.servicestoolkit.model.CouplingCriterionFactory;
import ch.hsr.servicestoolkit.model.DataField;
import ch.hsr.servicestoolkit.model.DualCouplingInstance;
import ch.hsr.servicestoolkit.model.Model;
import ch.hsr.servicestoolkit.model.MonoCouplingInstance;
import ch.hsr.servicestoolkit.repository.DataFieldRepository;
import ch.hsr.servicestoolkit.repository.ModelRepository;
import ch.hsr.servicestoolkit.repository.MonoCouplingInstanceRepository;

@Component
@Path("/engine/import")
public class ImportEndpoint {

	private final Logger log = LoggerFactory.getLogger(ImportEndpoint.class);
	private final ModelRepository modelRepository;
	private DataFieldRepository dataFieldRepository;
	private CouplingCriterionFactory couplingCriterionFactory;
	private MonoCouplingInstanceRepository monoCouplingInstanceRepository;

	@Autowired
	public ImportEndpoint(final ModelRepository modelRepository, final DataFieldRepository dataFieldRepository, final CouplingCriterionFactory couplingCriterionFactory,
			final MonoCouplingInstanceRepository monoCouplingInstanceRepository) {
		this.modelRepository = modelRepository;
		this.dataFieldRepository = dataFieldRepository;
		this.couplingCriterionFactory = couplingCriterionFactory;
		this.monoCouplingInstanceRepository = monoCouplingInstanceRepository;
	}

	@POST
	@Consumes(MediaType.APPLICATION_JSON)
	@Produces(MediaType.APPLICATION_JSON)
	@Transactional
	public Map<String, Object> importDomainModel(final DomainModel domainModel) {
		if (domainModel == null) {
			throw new InvalidRestParam();
		}
		Model model = new Model();
		modelRepository.save(model);
		model.setName("imported " + new Date().toString());

		Map<EntityAttribute, String> entityAttributes = new HashMap<>();
		for (Entity entity : domainModel.getEntities()) {
			for (EntityAttribute attribute : entity.getAttributes()) {
				entityAttributes.put(attribute, entity.getName());
			}

		}
		// entities
		CouplingCriteriaVariant sameEntityVariant = couplingCriterionFactory.findOrCreateVariant(CouplingCriterion.IDENTITY_LIFECYCLE, CouplingCriteriaVariant.SAME_ENTITY);
		for (Entry<String, List<EntityAttribute>> entity : findRealEntities(domainModel).entrySet()) {
			MonoCouplingInstance couplingInstance = sameEntityVariant.createInstance();
			monoCouplingInstanceRepository.save(couplingInstance);
			String entityName = entity.getKey();
			couplingInstance.setName(entityName);
			for (EntityAttribute entityAttribute : entity.getValue()) {
				DataField dataField = new DataField();
				dataField.setName(entityAttribute.getName());
				dataField.setContext(entityAttributes.get(entityAttribute));
				model.addDataField(dataField);
				dataFieldRepository.save(dataField);
				couplingInstance.addDataField(dataField);
			}
		}

		// Aggregations
		CouplingCriteriaVariant aggregationVariant = couplingCriterionFactory.findVariant(CouplingCriterion.SEMANTIC_PROXIMITY, CouplingCriteriaVariant.AGGREGATION);
		for (EntityRelation relation : domainModel.getRelations()) {
			if (RelationType.AGGREGATION.equals(relation.getType())) {
				DualCouplingInstance instance = (DualCouplingInstance) aggregationVariant.createInstance();

				monoCouplingInstanceRepository.save(instance);
				List<DataField> originFields = relation.getOrigin().getAttributes().stream().map(attr -> dataFieldRepository.findByNameAndModel(attr.getName(), model)).collect(Collectors.toList());
				List<DataField> destinationFields = relation.getOrigin().getAttributes().stream().map(attr -> dataFieldRepository.findByNameAndModel(attr.getName(), model))
						.collect(Collectors.toList());
				instance.setDataFields(originFields);
				instance.setSecondDataFields(destinationFields);
				instance.setModel(model);
				instance.setName(relation.getOrigin().getName() + "." + relation.getDestination().getName());
			}
		}
		// TODO: remove return value and set location header to URL of generated
		// model
		Map<String, Object> result = new HashMap<>();
		result.put("message", "model " + model.getId() + " has been created");
		result.put("id", model.getId());
		return result;
	}

	private Map<String, List<EntityAttribute>> findRealEntities(final DomainModel domainModel) {
		Map<String, List<EntityAttribute>> realEntities = new HashMap<>();
		for (Entity entity : domainModel.getEntities()) {
			realEntities.put(entity.getName(), entity.getAttributes());
		}

		// Merge composition and inheritance UML-entities together to real
		// entities
		// TODO support second grade compositions (A->B->C)
		for (EntityRelation relation : domainModel.getRelations()) {
			if (RelationType.COMPOSITION.equals(relation.getType())) {
				List<EntityAttribute> list = realEntities.get(relation.getOrigin().getName());
				if (list != null) {
					list.addAll(relation.getDestination().getAttributes());
				} else {
					log.error("ignore relation {}", relation);
				}
				realEntities.remove(relation.getDestination().getName());
			} else if (RelationType.INHERITANCE.equals(relation.getType())) {
				realEntities.get(relation.getDestination().getName()).addAll(relation.getOrigin().getAttributes());
				realEntities.remove(relation.getOrigin().getName());
			}
		}

		return realEntities;
	}

	@POST
	@Path("/{modelId}/businessTransactions/")
	@Consumes(MediaType.APPLICATION_JSON)
	@Transactional
	public void importBusinessTransaction(@PathParam("modelId") final Long modelId, final List<BusinessTransaction> transactions) {
		Model model = modelRepository.findOne(modelId);
		if (model == null) {
			throw new InvalidRestParam();
		}
		// TODO add support for read/write/mixed
		CouplingCriteriaVariant aggregationVariant = couplingCriterionFactory.findVariant(CouplingCriterion.SEMANTIC_PROXIMITY, CouplingCriteriaVariant.SHARED_FIELD_ACCESS);
		for (BusinessTransaction transaction : transactions) {
			DualCouplingInstance instance = (DualCouplingInstance) aggregationVariant.createInstance();
			monoCouplingInstanceRepository.save(instance);
			instance.setName(transaction.getName());
			instance.setModel(model);
			instance.setDataFields(loadDataFields(transaction.getFieldsRead(), model));
			instance.setSecondDataFields(loadDataFields(transaction.getFieldsWritten(), model));
		}<commit_msg>fix wrong association of lifecycle instances with model<commit_after>package ch.hsr.servicestoolkit.importer;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;

import javax.transaction.Transactional;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import ch.hsr.servicestoolkit.importer.api.BusinessTransaction;
import ch.hsr.servicestoolkit.importer.api.DistanceVariant;
import ch.hsr.servicestoolkit.importer.api.DomainModel;
import ch.hsr.servicestoolkit.importer.api.Entity;
import ch.hsr.servicestoolkit.importer.api.EntityAttribute;
import ch.hsr.servicestoolkit.importer.api.EntityRelation;
import ch.hsr.servicestoolkit.importer.api.EntityRelation.RelationType;
import ch.hsr.servicestoolkit.model.CouplingCriteriaVariant;
import ch.hsr.servicestoolkit.model.CouplingCriterion;
import ch.hsr.servicestoolkit.model.CouplingCriterionFactory;
import ch.hsr.servicestoolkit.model.DataField;
import ch.hsr.servicestoolkit.model.DualCouplingInstance;
import ch.hsr.servicestoolkit.model.Model;
import ch.hsr.servicestoolkit.model.MonoCouplingInstance;
import ch.hsr.servicestoolkit.repository.DataFieldRepository;
import ch.hsr.servicestoolkit.repository.ModelRepository;
import ch.hsr.servicestoolkit.repository.MonoCouplingInstanceRepository;

@Component
@Path("/engine/import")
public class ImportEndpoint {

	private final Logger log = LoggerFactory.getLogger(ImportEndpoint.class);
	private final ModelRepository modelRepository;
	private DataFieldRepository dataFieldRepository;
	private CouplingCriterionFactory couplingCriterionFactory;
	private MonoCouplingInstanceRepository monoCouplingInstanceRepository;

	@Autowired
	public ImportEndpoint(final ModelRepository modelRepository, final DataFieldRepository dataFieldRepository, final CouplingCriterionFactory couplingCriterionFactory,
			final MonoCouplingInstanceRepository monoCouplingInstanceRepository) {
		this.modelRepository = modelRepository;
		this.dataFieldRepository = dataFieldRepository;
		this.couplingCriterionFactory = couplingCriterionFactory;
		this.monoCouplingInstanceRepository = monoCouplingInstanceRepository;
	}

	@POST
	@Consumes(MediaType.APPLICATION_JSON)
	@Produces(MediaType.APPLICATION_JSON)
	@Transactional
	public Map<String, Object> importDomainModel(final DomainModel domainModel) {
		if (domainModel == null) {
			throw new InvalidRestParam();
		}
		Model model = new Model();
		modelRepository.save(model);
		model.setName("imported " + new Date().toString());

		Map<EntityAttribute, String> entityAttributes = new HashMap<>();
		for (Entity entity : domainModel.getEntities()) {
			for (EntityAttribute attribute : entity.getAttributes()) {
				entityAttributes.put(attribute, entity.getName());
			}

		}
		// entities
		CouplingCriteriaVariant sameEntityVariant = couplingCriterionFactory.findOrCreateVariant(CouplingCriterion.IDENTITY_LIFECYCLE, CouplingCriteriaVariant.SAME_ENTITY);
		for (Entry<String, List<EntityAttribute>> entity : findRealEntities(domainModel).entrySet()) {
			MonoCouplingInstance couplingInstance = sameEntityVariant.createInstance();
			monoCouplingInstanceRepository.save(couplingInstance);
			String entityName = entity.getKey();
			couplingInstance.setName(entityName);
			couplingInstance.setModel(model);
			for (EntityAttribute entityAttribute : entity.getValue()) {
				DataField dataField = new DataField();
				dataField.setName(entityAttribute.getName());
				dataField.setContext(entityAttributes.get(entityAttribute));
				model.addDataField(dataField);
				dataFieldRepository.save(dataField);
				couplingInstance.addDataField(dataField);
			}
		}

		// Aggregations
		CouplingCriteriaVariant aggregationVariant = couplingCriterionFactory.findVariant(CouplingCriterion.SEMANTIC_PROXIMITY, CouplingCriteriaVariant.AGGREGATION);
		for (EntityRelation relation : domainModel.getRelations()) {
			if (RelationType.AGGREGATION.equals(relation.getType())) {
				DualCouplingInstance instance = (DualCouplingInstance) aggregationVariant.createInstance();

				monoCouplingInstanceRepository.save(instance);
				List<DataField> originFields = relation.getOrigin().getAttributes().stream().map(attr -> dataFieldRepository.findByNameAndModel(attr.getName(), model))
						.collect(Collectors.toList());
				List<DataField> destinationFields = relation.getOrigin().getAttributes().stream().map(attr -> dataFieldRepository.findByNameAndModel(attr.getName(), model))
						.collect(Collectors.toList());
				instance.setDataFields(originFields);
				instance.setSecondDataFields(destinationFields);
				instance.setModel(model);
				instance.setName(relation.getOrigin().getName() + "." + relation.getDestination().getName());
			}
		}
		// TODO: remove return value and set location header to URL of generated
		// model
		Map<String, Object> result = new HashMap<>();
		result.put("message", "model " + model.getId() + " has been created");
		result.put("id", model.getId());
		return result;
	}

	private Map<String, List<EntityAttribute>> findRealEntities(final DomainModel domainModel) {
		Map<String, List<EntityAttribute>> realEntities = new HashMap<>();
		for (Entity entity : domainModel.getEntities()) {
			realEntities.put(entity.getName(), entity.getAttributes());
		}

		// Merge composition and inheritance UML-entities together to real
		// entities
		// TODO support second grade compositions (A->B->C)
		for (EntityRelation relation : domainModel.getRelations()) {
			if (RelationType.COMPOSITION.equals(relation.getType())) {
				List<EntityAttribute> list = realEntities.get(relation.getOrigin().getName());
				if (list != null) {
					list.addAll(relation.getDestination().getAttributes());
				} else {
					log.error("ignore relation {}", relation);
				}
				realEntities.remove(relation.getDestination().getName());
			} else if (RelationType.INHERITANCE.equals(relation.getType())) {
				realEntities.get(relation.getDestination().getName()).addAll(relation.getOrigin().getAttributes());
				realEntities.remove(relation.getOrigin().getName());
			}
		}

		return realEntities;
	}

	@POST
	@Path("/{modelId}/businessTransactions/")
	@Consumes(MediaType.APPLICATION_JSON)
	@Transactional
	public void importBusinessTransaction(@PathParam("modelId") final Long modelId, final List<BusinessTransaction> transactions) {
		Model model = modelRepository.findOne(modelId);
		if (model == null) {
			throw new InvalidRestParam();
		}
		CouplingCriteriaVariant aggregationVariant = couplingCriterionFactory.findVariant(CouplingCriterion.SEMANTIC_PROXIMITY, CouplingCriteriaVariant.SHARED_FIELD_ACCESS);
		for (BusinessTransaction transaction : transactions) {
			DualCouplingInstance instance = (DualCouplingInstance) aggregationVariant.createInstance();
			monoCouplingInstanceRepository.save(instance);
			instance.setName(transaction.getName());
			instance.setModel(model);
			instance.setDataFields(loadDataFields(transaction.getFieldsRead(), model));
			instance.setSecondDataFields(loadDataFields(transaction.getFieldsWritten(), model));
		}
{'fraction_non_alphanumeric': 0.1086064194872485, 'fraction_numerical': 0.00026916089092254896, 'mean_word_length': 6.357425742574257, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4046253', 'n_tokens_mistral': 4582, 'n_tokens_neox': 4252, 'n_words': 708}