/** * Copyright (c) 2012-2016 Marsha Chechik, Alessio Di Sandro, Michalis Famelis, * Rick Salay. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Alessio Di Sandro - Implementation. */ package edu.toronto.cs.se.mmint.operator.merge; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.EList; import org.eclipse.jdt.annotation.NonNull; import edu.toronto.cs.se.mmint.MMINTException; import edu.toronto.cs.se.mmint.java.reasoning.IJavaOperatorInputConstraint; import edu.toronto.cs.se.mmint.MIDTypeHierarchy; import edu.toronto.cs.se.mmint.mid.GenericElement; import edu.toronto.cs.se.mmint.mid.MID; import edu.toronto.cs.se.mmint.mid.Model; import edu.toronto.cs.se.mmint.mid.ModelElement; import edu.toronto.cs.se.mmint.mid.operator.impl.OperatorImpl; import edu.toronto.cs.se.mmint.mid.relationship.Mapping; import edu.toronto.cs.se.mmint.mid.relationship.MappingReference; import edu.toronto.cs.se.mmint.mid.relationship.ModelElementEndpoint; import edu.toronto.cs.se.mmint.mid.relationship.ModelElementEndpointReference; import edu.toronto.cs.se.mmint.mid.relationship.ModelElementReference; import edu.toronto.cs.se.mmint.mid.relationship.ModelEndpointReference; import edu.toronto.cs.se.mmint.mid.relationship.ModelRel; public class ModelRelComposition extends OperatorImpl { public static class InputConstraint implements IJavaOperatorInputConstraint { @Override public boolean isAllowedInput(Map<String, Model> inputsByName) { ModelRel modelRel1 = (ModelRel) inputsByName.get(IN_MODELREL1); ModelRel modelRel2 = (ModelRel) inputsByName.get(IN_MODELREL2); if (modelRel1.getModelEndpoints().size() != 2 || modelRel2.getModelEndpoints().size() != 2) { return false; } Model model11 = modelRel1.getModelEndpoints().get(0).getTarget(); Model model12 = modelRel1.getModelEndpoints().get(1).getTarget(); Model model21 = modelRel2.getModelEndpoints().get(0).getTarget(); Model model22 = modelRel2.getModelEndpoints().get(1).getTarget(); if (model11 != model21 && model11 != model22 && model12 != model21 && model12 != model22) { return false; } return true; } } // input-output private final static @NonNull String IN_MODELREL1 = "rel1"; private final static @NonNull String IN_MODELREL2 = "rel2"; private final static @NonNull String OUT_MODELREL = "composition"; // constants private final static @NonNull String COMPOSITION_SEPARATOR = "+"; private @NonNull ModelRel compose(@NonNull ModelRel modelRel1, @NonNull ModelRel modelRel2, @NonNull Model model1, @NonNull Model model2, @NonNull Model modelPivot, @NonNull MID instanceMID) throws MMINTException { // TODO MMINT[USABILITY] Modify apis to simplify the creation of models and model rels (e.g. incorporate // createModelFile, add model element creation to link creation) ModelRel composedRel = MIDTypeHierarchy.getRootModelRelType().createBinaryInstanceAndEndpoints( null, model1, model2, instanceMID); composedRel.setName(modelRel1.getName() + COMPOSITION_SEPARATOR + modelRel2.getName()); ModelEndpointReference composedModelEndpointRef1 = composedRel.getModelEndpointRefs().get(0); ModelEndpointReference composedModelEndpointRef2 = composedRel.getModelEndpointRefs().get(1); // loop through mappings in modelRel1 for (Mapping mapping1 : modelRel1.getMappings()) { // get model elements in model1 List<ModelElement> modelElems1 = mapping1.getModelElemEndpoints().stream() .map(ModelElementEndpoint::getTarget) .filter(modelElem -> modelElem.eContainer() == model1) .collect(Collectors.toList()); // get model elements in modelPivot from the modelRel1 side List<ModelElement> modelElemsPivot1 = mapping1.getModelElemEndpoints().stream() .map(ModelElementEndpoint::getTarget) .filter(modelElem -> modelElem.eContainer() == modelPivot) .collect(Collectors.toList()); ModelEndpointReference modelEndpointRefPivot2 = modelRel2.getModelEndpointRefs().stream() .filter(modelEndpointRef -> modelEndpointRef.getObject().getTarget() == modelPivot) .collect(Collectors.toList()).get(0); // loop through model elements in modelPivot from the modelRel2 side for (ModelElementReference modelElemRefPivot2 : modelEndpointRefPivot2.getModelElemRefs()) { if (!modelElemsPivot1.contains(modelElemRefPivot2.getObject())) { continue; } // get model elements in model2 List<MappingReference> mappingRefs2 = modelElemRefPivot2.getModelElemEndpointRefs().stream() .map(modelElemEndpointRef -> (MappingReference) modelElemEndpointRef.eContainer()) .collect(Collectors.toList()); for (MappingReference mappingRef2 : mappingRefs2) { EList<ModelElementReference> targetModelElemRefs = new BasicEList<>(); for (ModelElement modelElem1 : modelElems1) { targetModelElemRefs.add(modelElem1.createInstanceReference(composedModelEndpointRef1)); } List<ModelElement> modelElems2 = mappingRef2.getModelElemEndpointRefs().stream() .map(ModelElementEndpointReference::getModelElemRef) .filter( modelElemRef -> (ModelEndpointReference) modelElemRef.eContainer() != modelEndpointRefPivot2) .map(ModelElementReference::getObject).collect(Collectors.toList()); for (ModelElement modelElem2 : modelElems2) { targetModelElemRefs.add(modelElem2.createInstanceReference(composedModelEndpointRef2)); } // create the composed mapping MappingReference composedMappingRef = MIDTypeHierarchy.getRootMappingType() .createInstanceAndReferenceAndEndpointsAndReferences(false, targetModelElemRefs); composedMappingRef.getObject().setName( mapping1.getName() + COMPOSITION_SEPARATOR + mappingRef2.getObject().getName()); } } } return composedRel; } @Override public Map<String, Model> run(Map<String, Model> inputsByName, java.util.Map<String, GenericElement> genericsByName, Map<String, MID> outputMIDsByName) throws Exception { // input ModelRel modelRel1 = (ModelRel) inputsByName.get(IN_MODELREL1); ModelRel modelRel2 = (ModelRel) inputsByName.get(IN_MODELREL2); Model model11 = modelRel1.getModelEndpoints().get(0).getTarget(); Model model12 = modelRel1.getModelEndpoints().get(1).getTarget(); Model model21 = modelRel2.getModelEndpoints().get(0).getTarget(); Model model22 = modelRel2.getModelEndpoints().get(1).getTarget(); Model modelPivot = null, model1 = null, model2 = null; if (model11 == model21) { modelPivot = model11; model1 = model12; model2 = model22; } else if (model11 == model22) { modelPivot = model11; model1 = model12; model2 = model21; } else if (model12 == model21) { modelPivot = model12; model1 = model11; model2 = model22; } else { // model12 == model22 modelPivot = model12; model1 = model11; model2 = model21; } // compose the two model rels, using the shared model as pivot ModelRel composedRel = compose( modelRel1, modelRel2, model1, model2, modelPivot, outputMIDsByName.get(OUT_MODELREL)); // output Map<String, Model> outputsByName = new HashMap<>(); outputsByName.put(OUT_MODELREL, composedRel); return outputsByName; } }