/** * 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.mid.utils; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import edu.toronto.cs.se.mmint.MIDTypeHierarchy; import edu.toronto.cs.se.mmint.MMINT; import edu.toronto.cs.se.mmint.MMINTException; import edu.toronto.cs.se.mmint.mid.EMFInfo; import edu.toronto.cs.se.mmint.mid.ExtendibleElement; import edu.toronto.cs.se.mmint.mid.ExtendibleElementConstraint; import edu.toronto.cs.se.mmint.mid.ExtendibleElementEndpoint; import edu.toronto.cs.se.mmint.mid.MID; import edu.toronto.cs.se.mmint.mid.MIDLevel; import edu.toronto.cs.se.mmint.mid.Model; import edu.toronto.cs.se.mmint.mid.ModelElement; import edu.toronto.cs.se.mmint.mid.ModelEndpoint; import edu.toronto.cs.se.mmint.mid.editor.Editor; import edu.toronto.cs.se.mmint.mid.operator.ConversionOperator; import edu.toronto.cs.se.mmint.mid.operator.Operator; import edu.toronto.cs.se.mmint.mid.operator.OperatorConstraint; import edu.toronto.cs.se.mmint.mid.operator.OperatorConstraintParameter; import edu.toronto.cs.se.mmint.mid.operator.OperatorConstraintRule; import edu.toronto.cs.se.mmint.mid.relationship.BinaryModelRel; import edu.toronto.cs.se.mmint.mid.relationship.ExtendibleElementReference; 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; /** * The factory to create/modify/remove all types. * * @author Alessio Di Sandro * */ public class MIDTypeFactory { public final static String ECORE_PIVOT_URI = "http://www.eclipse.org/emf/2002/Ecore/OCL/Pivot"; public final static String ECORE_INVOCATION_DELEGATE = "invocationDelegates"; public final static String ECORE_SETTING_DELEGATE = "settingDelegates"; public final static String ECORE_VALIDATION_DELEGATE = "validationDelegates"; public final static String ECORE_VALIDATION_CONSTRAINTS = "constraints"; public final static String ECORE_REFLECTIVE_FILE_EXTENSION = "xmi"; /** * Adds a type to the Type MID. * * @param newType * The new type to be added. * @param type * The supertype of the new type, null only for root types. * @param newTypeUri * The uri of the new type. * @param newTypeName * The name of the new type. * @param typeMID * The Type MID. * @throws MMINTException * If the uri of the new type is already registered in the Type MID. */ public static void addType(@NonNull ExtendibleElement newType, @Nullable ExtendibleElement type, @NonNull String newTypeUri, @NonNull String newTypeName, @NonNull MID typeMID) throws MMINTException { if (typeMID.getExtendibleTable().containsKey(newTypeUri)) { throw new MMINTException("Type with uri " + newTypeUri + " is already registered"); } newType.setUri(newTypeUri); newType.setName(newTypeName); newType.setLevel(MIDLevel.TYPES); newType.setSupertype(type); typeMID.getExtendibleTable().put(newTypeUri, newType); } /** * Adds the cardinality to a type endpoint. * * @param typeEndpoint * The type endpoint. * @param lowerBound * The lower cardinality. * @param upperBound * The upper cardinality, -1 for infinite. */ public static void addTypeEndpointCardinality(@NonNull ExtendibleElementEndpoint typeEndpoint, int lowerBound, int upperBound) { typeEndpoint.setLowerBound(lowerBound); typeEndpoint.setUpperBound(upperBound); } /** * Adds the target to a new type endpoint. * * @param newTypeEndpoint * The new type endpoint. * @param newType * The new type that is the target of the new type endpoint. */ protected static void addTypeEndpoint(ExtendibleElementEndpoint newTypeEndpoint, ExtendibleElement newType) { newTypeEndpoint.setTarget(newType); addTypeEndpointCardinality(newTypeEndpoint, 1, 1); } /** * Adds additional info for a reference to a type. * * @param newTypeRef * The new reference being added. * @param newType * The new type for which the reference was created. * @param typeRef * The reference to the supertype of the new type, null if such * reference doesn't exist. * @param isModifiable * True if the new reference will allow modifications of the * referenced type, false otherwise. * @param isContainer * True if the new reference is also the actual container of the * new type and not just a pointer to it, false otherwise. */ public static void addTypeReference(ExtendibleElementReference newTypeRef, ExtendibleElement newType, ExtendibleElementReference typeRef, boolean isModifiable, boolean isContainer) { if (isContainer) { newTypeRef.setContainedObject(newType); } else { newTypeRef.setReferencedObject(newType); } newTypeRef.setModifiable(isModifiable); newTypeRef.setSupertypeRef(typeRef); } public static void addTypeConstraint(@NonNull ExtendibleElementConstraint newTypeConstraint, @NonNull String language, @NonNull String implementation, @NonNull ExtendibleElement constrainedType) { newTypeConstraint.setLanguage(language); newTypeConstraint.setImplementation(implementation); constrainedType.setConstraint(newTypeConstraint); } /** * Adds a model type to the Type MID. * * @param newModelType * The new model type to be added. * @param typeMID * The Type MID. */ public static void addModelType(@NonNull Model newModelType, @NonNull MID typeMID) { typeMID.getModels().add(newModelType); } /** * Adds a model element type to a model type. * * @param newModelElemType * The new model element type being added. * @param eInfo * The EMF info of the new model element type. * @param modelType * The model type that will contain the new model element type. */ public static void addModelElementType(ModelElement newModelElemType, EMFInfo eInfo, Model modelType) { newModelElemType.setEInfo(eInfo); modelType.getModelElems().add(newModelElemType); } /** * Adds additional info for a model relationship type. * * @param newModelRelType * The new model relationship type being added. * @param modelRelType * The supertype of the new model relationship type. * @throws MMINTException */ public static void addModelRelType(ModelRel newModelRelType, ModelRel modelRelType) throws MMINTException { List<MappingReference> skipMappingRefs = new ArrayList<>(); // copy model type references Iterator<ModelEndpointReference> modelTypeEndpointRefIter = MIDTypeHierarchy.getTypeRefHierarchyIterator(modelRelType.getModelEndpointRefs()); while (modelTypeEndpointRefIter.hasNext()) { ModelEndpointReference modelTypeEndpointRefSuper = modelTypeEndpointRefIter.next(); if (MIDTypeHierarchy.isRootType(modelTypeEndpointRefSuper.getObject().getTarget())) { // don't copy model type endpoints to the root model type for (ModelElementReference modelElemTypeRefSuper : modelTypeEndpointRefSuper.getModelElemRefs()) { for (ModelElementEndpointReference modelElemTypeEndpointRefSuper : modelElemTypeRefSuper.getModelElemEndpointRefs()) { skipMappingRefs.add((MappingReference) modelElemTypeEndpointRefSuper.eContainer()); } } continue; } ModelEndpointReference newModelTypeEndpointRef = modelTypeEndpointRefSuper.getObject().createTypeReference(false, newModelRelType); // copy model element type references Iterator<ModelElementReference> modelElemTypeRefIter = MIDTypeHierarchy.getTypeRefHierarchyIterator(modelTypeEndpointRefSuper.getModelElemRefs()); while (modelElemTypeRefIter.hasNext()) { ModelElementReference modelElemTypeRefSuper = modelElemTypeRefIter.next(); ModelElementReference modelElemTypeRef = MIDRegistry.getReference(modelElemTypeRefSuper.getSupertypeRef(), newModelTypeEndpointRef.getModelElemRefs()); modelElemTypeRefSuper.getObject().createTypeReference(modelElemTypeRef, false, newModelTypeEndpointRef); } } // copy link type references Iterator<MappingReference> mappingTypeRefIter = MIDTypeHierarchy.getTypeRefHierarchyIterator(modelRelType.getMappingRefs()); while (mappingTypeRefIter.hasNext()) { MappingReference mappingTypeRefSuper = mappingTypeRefIter.next(); if (skipMappingRefs.contains(mappingTypeRefSuper)) { // don't copy link types using model element types from the root model type continue; } MappingReference mappingTypeRef = MIDRegistry.getReference(mappingTypeRefSuper.getSupertypeRef(), newModelRelType.getMappingRefs()); MappingReference newMappingTypeRef = mappingTypeRefSuper.getObject().createTypeReference(mappingTypeRef, false, newModelRelType); // connect it to model element type references (takes care of binary too) Iterator<ModelElementEndpointReference> modelElemTypeEndpointRefIter = MIDTypeHierarchy.getTypeRefHierarchyIterator(mappingTypeRefSuper.getModelElemEndpointRefs()); while (modelElemTypeEndpointRefIter.hasNext()) { ModelElementEndpointReference modelElemTypeEndpointRefSuper = modelElemTypeEndpointRefIter.next(); ModelElementEndpointReference modelElemTypeEndpointRef = null; ModelElementEndpointReference modelElemTypeEndpointRefSuper2 = modelElemTypeEndpointRefSuper.getSupertypeRef(); if (modelElemTypeEndpointRefSuper2 != null) { MappingReference mappingTypeRefSuper2 = (MappingReference) modelElemTypeEndpointRefSuper2.eContainer(); MappingReference mappingTypeRef2 = MIDRegistry.getReference(mappingTypeRefSuper2, newModelRelType.getMappingRefs()); modelElemTypeEndpointRef = MIDRegistry.getReference(modelElemTypeEndpointRefSuper2, mappingTypeRef2.getModelElemEndpointRefs()); } ModelElementReference modelElemTypeRefSuper = modelElemTypeEndpointRefSuper.getModelElemRef(); ModelEndpointReference modelTypeEndpointRef = MIDRegistry.getReference((ModelEndpointReference) modelElemTypeRefSuper.eContainer(), newModelRelType.getModelEndpointRefs()); ModelElementReference newModelElemTypeRef = MIDRegistry.getReference(modelElemTypeRefSuper, modelTypeEndpointRef.getModelElemRefs()); modelElemTypeEndpointRefSuper.getObject().createTypeReference(modelElemTypeEndpointRef, newModelElemTypeRef, false, false, newMappingTypeRef); } } } /** * Adds a model type endpoint to a model relationship type. * * @param newModelTypeEndpoint * The new model type endpoint to be added. * @param targetModelType * The new model type that is the target of the new model type * endpoint. * @param isBinarySrc * (Only for a binary model relationship type container) True if * the target model type is the source in the binary model * relationship type container, false otherwise. * @param containerModelRelType * The model relationship type that will contain the new model * type endpoint. * @throws MMINTException * If the container model relationship is a model relationship * instance. */ public static void addModelTypeEndpoint(@NonNull ModelEndpoint newModelTypeEndpoint, @NonNull Model targetModelType, boolean isBinarySrc, @NonNull ModelRel containerModelRelType) throws MMINTException { addTypeEndpoint(newModelTypeEndpoint, targetModelType); containerModelRelType.getModelEndpoints().add(newModelTypeEndpoint); if (containerModelRelType instanceof BinaryModelRel) { ((BinaryModelRel) containerModelRelType).addModelType(targetModelType, isBinarySrc); } } /** * Adds a model type endpoint to an operator type. * * @param newModelTypeEndpoint * The new model type endpoint to be added. * @param targetModelType * The new model type that is the target of the new model type * endpoint. * @param containerOperatorType * The operator type that will contain the new model type * endpoint. * @param containerFeatureName * The name of the feature in the operator type that will contain * the new model type endpoint. * @throws MMINTException * If the feature name is not found in the container operator * type. */ public static void addModelTypeEndpoint(@NonNull ModelEndpoint newModelTypeEndpoint, @NonNull Model targetModelType, @NonNull Operator containerOperatorType, @NonNull String containerFeatureName) throws MMINTException { addTypeEndpoint(newModelTypeEndpoint, targetModelType); FileUtils.setModelObjectFeature(containerOperatorType, containerFeatureName, newModelTypeEndpoint); } /** * Adds a mapping type to a model relationship type. * * @param newMappingType * The new mapping type to be added. * @param mappingType * The supertype of the new mapping type. * @param modelRelType * The model relationship type that will contain the new mapping * type. */ public static void addMappingType(Mapping newMappingType, Mapping mappingType, ModelRel modelRelType) { // keep track of inherited model elements, but not root ones if (mappingType != null && !mappingType.getUri().equals(MMINT.ROOT_MAPPING_URI)) { for (ModelElementEndpointReference modelElemTypeEndpointRef : mappingType.getModelElemEndpointRefs()) { newMappingType.getModelElemEndpointRefs().add(modelElemTypeEndpointRef); } } modelRelType.getMappings().add(newMappingType); } /** * Adds a model element type endpoint to a mapping type. * * @param newModelElemTypeEndpoint * The new model element type endpoint to be added. * @param targetModelElemType * The new model element type that is the target of the new model * element type endpoint. * @param containerMappingType * The mapping type that will contain the new model element type * endpoint. */ public static void addModelElementTypeEndpoint(ModelElementEndpoint newModelElemTypeEndpoint, ModelElement targetModelElemType, Mapping containerMappingType) { addTypeEndpoint(newModelElemTypeEndpoint, targetModelElemType); containerMappingType.getModelElemEndpoints().add(newModelElemTypeEndpoint); } /** * Adds additional info for a reference to a model element type endpoint. * * @param newModelElemTypeEndpointRef * The new reference to the new model element type endpoint being * added. * @param mappingType * The mapping type that contains the referenced model element type * endpoint. */ public static void addModelElementTypeEndpointReference(ModelElementEndpointReference newModelElemTypeEndpointRef, Mapping mappingType) { mappingType.getModelElemEndpointRefs().add(newModelElemTypeEndpointRef); } /** * Adds an editor type to a multimodel. * * @param newEditorType * The new editor type to be added. * @param modelTypeUri * The uri of the model type handled by the new editor type. * @param editorId * The id of the corresponding Eclipse editor. * @param wizardId * The wizard id of the corresponding Eclipse editor. * @param wizardDialogClassName * The fully qualified name of a Java class that handles the * creation of the model type through the new editor type. * @param mid * The MID that will contain the new editor type. */ public static void addEditorType(Editor newEditorType, String modelTypeUri, String editorId, String wizardId, String wizardDialogClassName, MID mid) { newEditorType.setModelUri(modelTypeUri); newEditorType.setId(editorId); newEditorType.setWizardId(wizardId); newEditorType.setWizardDialogClass(wizardDialogClassName); mid.getEditors().add(newEditorType); } /** * Adds a editor type to a model type. * * @param editorType * The editor type. * @param modelType * The model type handled by the editor type. */ public static void addModelTypeEditor(Editor editorType, Model modelType) { modelType.getEditors().add(editorType); } /** * Adds an operator type to the Type MID. * * @param newOperatorType * The new operator type to be added. * @param typeMID * The Type MID. */ public static void addOperatorType(Operator newOperatorType, MID typeMID) { newOperatorType.setCommutative(false); typeMID.getOperators().add(newOperatorType); } /** * Adds additional info for a conversion operator type. * * @param operatorType * The conversion operator type being added. */ public static void addOperatorTypeConversion(ConversionOperator operatorType) { operatorType.getInputs().get(0).getTarget().getConversionOperators().add(operatorType); } public static void addOperatorTypeConstraintRuleEndpoint(OperatorConstraintParameter constraintParam, OperatorConstraintRule constraintRule, ModelEndpointReference modelTypeEndpointRef, int endpointIndex, String ruleFeatureName) throws MMINTException { constraintParam.setParameterRef(modelTypeEndpointRef); constraintParam.setEndpointIndex(endpointIndex); FileUtils.setModelObjectFeature(constraintRule, ruleFeatureName, constraintParam); } public static void addOperatorTypeConstraintRule(OperatorConstraintRule constraintRule, OperatorConstraint constraint, ModelEndpoint modelRelTypeEndpoint) throws MMINTException { constraint.getRules().add(constraintRule); } }