/**
* 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;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.model.BaseWorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.osgi.framework.Bundle;
import edu.toronto.cs.se.mmint.mid.ExtendibleElement;
import edu.toronto.cs.se.mmint.mid.GenericElement;
import edu.toronto.cs.se.mmint.mid.MID;
import edu.toronto.cs.se.mmint.mid.MIDPackage;
import edu.toronto.cs.se.mmint.mid.Model;
import edu.toronto.cs.se.mmint.mid.editor.Diagram;
import edu.toronto.cs.se.mmint.mid.editor.Editor;
import edu.toronto.cs.se.mmint.mid.operator.GenericEndpoint;
import edu.toronto.cs.se.mmint.mid.operator.Operator;
import edu.toronto.cs.se.mmint.mid.operator.OperatorInput;
import edu.toronto.cs.se.mmint.mid.reasoning.MIDConstraintChecker;
import edu.toronto.cs.se.mmint.mid.relationship.BinaryMapping;
import edu.toronto.cs.se.mmint.mid.relationship.BinaryMappingReference;
import edu.toronto.cs.se.mmint.mid.relationship.BinaryModelRel;
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.ModelElementReference;
import edu.toronto.cs.se.mmint.mid.relationship.ModelRel;
import edu.toronto.cs.se.mmint.mid.ui.ImportModelDialogFilter;
import edu.toronto.cs.se.mmint.mid.ui.ImportModelDialogSelectionValidator;
import edu.toronto.cs.se.mmint.mid.ui.MIDDialogLabelProvider;
import edu.toronto.cs.se.mmint.mid.ui.MIDTreeSelectionDialog;
import edu.toronto.cs.se.mmint.mid.ui.NewGenericTypeDialogContentProvider;
import edu.toronto.cs.se.mmint.mid.ui.NewMappingReferenceDialogContentProvider;
import edu.toronto.cs.se.mmint.mid.ui.NewMappingTypeReferenceDialogContentProvider;
import edu.toronto.cs.se.mmint.mid.ui.NewModelDialogContentProvider;
import edu.toronto.cs.se.mmint.mid.ui.NewModelDialogSelectionValidator;
import edu.toronto.cs.se.mmint.mid.ui.NewModelElementEndpointReferenceDialogContentProvider;
import edu.toronto.cs.se.mmint.mid.ui.NewModelEndpointDialogContentProvider;
import edu.toronto.cs.se.mmint.mid.ui.NewModelRelDialogContentProvider;
import edu.toronto.cs.se.mmint.mid.ui.NewModelRelTypeDialogContentProvider;
import edu.toronto.cs.se.mmint.mid.ui.NewModelTypeDialogContentProvider;
import edu.toronto.cs.se.mmint.mid.ui.NewOperatorTypeDialogFilter;
import edu.toronto.cs.se.mmint.mid.ui.NewOperatorTypeDialogSelectionValidator;
import edu.toronto.cs.se.mmint.mid.ui.NewWorkflowModelDialogContentProvider;
import edu.toronto.cs.se.mmint.mid.utils.FileUtils;
import edu.toronto.cs.se.mmint.mid.utils.MIDRegistry;
/**
* The registry for querying the types.
*
* @author Alessio Di Sandro
*
*/
public class MIDTypeRegistry {
/**
* Gets a type from the repository.
*
* @param typeUri
* The uri of the type.
* @return The type, null if the uri is not found or found not to be of the
* desired class of types.
*/
public static <T extends ExtendibleElement> @Nullable T getType(@NonNull String typeUri) {
return MMINT.cachedTypeMID.getExtendibleElement(typeUri);
}
/**
* Gets the list of operator types in the repository.
*
* @return The list of operator types in the repository.
*/
public static List<Operator> getOperatorTypes() {
return MMINT.cachedTypeMID.getOperators();
}
/**
* Gets the list of model types in the repository.
*
* @return The list of model types in the repository.
*/
public static List<Model> getModelTypes() {
return MMINT.cachedTypeMID.getModels();
}
/**
* Gets the list of generic types in the repository.
*
* @return The list of generic types in the repository.
*/
public static List<GenericElement> getGenericTypes() {
List<GenericElement> genericTypes = new ArrayList<>();
genericTypes.addAll(getModelTypes());
genericTypes.addAll(getOperatorTypes());
return genericTypes;
}
/**
* Gets the list of editor types in the repository.
*
* @return The list of editor types in the repository.
*/
public static EList<Editor> getEditorTypes() {
return MMINT.cachedTypeMID.getEditors();
}
/**
* Gets the list of model relationship types in the repository.
*
* @return The list of model relationship types in the repository.
*/
public static EList<ModelRel> getModelRelTypes() {
return MMINT.cachedTypeMID.getModelRels();
}
/**
* Gets the list of file extensions for all model types in the repository.
*
* @return The list of file extensions for model types.
*/
public static List<String> getModelTypeFileExtensions() {
List<String> fileExtensions = getModelTypes().stream()
.map(Model::getFileExtension)
.collect(Collectors.toList());
return fileExtensions;
}
public static @Nullable Model getMIDModelType() {
return MIDTypeRegistry.getType(MIDPackage.eNS_URI);
}
public static @Nullable Diagram getMIDDiagramType() {
Model midModelType = MIDTypeRegistry.getMIDModelType();
if (midModelType == null) {
return null;
}
return MIDRegistry.getModelDiagram(midModelType);
}
/**
* Gets a tree dialog that shows all model types in the Type MID, in order
* to create a new "light" model type.
*
* @param typeMID
* The Type MID.
* @return The tree dialog to create a new "light" model type.
*/
public static MIDTreeSelectionDialog getModelTypeCreationDialog(MID typeMID) {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
MIDTreeSelectionDialog dialog = new MIDTreeSelectionDialog(
shell,
new MIDDialogLabelProvider(),
new NewModelTypeDialogContentProvider(),
typeMID
);
return dialog;
}
/**
* Gets a tree dialog that shows all model relationship types in the Type MID, in order to create a new "light"
* model relationship type.
*
* @param newSrcModelType
* The model type that is going to be the target of the source
* model type endpoint, null if the model relationship type to be
* created is not binary.
* @param newTgtModelType
* The model type that is going to be the target of the target
* model type endpoint, null if the model relationship type to be
* created is not binary.
* @param typeMID
* The Type MID.
*
* @return The tree dialog to create a new "light" model relationship type.
*/
public static MIDTreeSelectionDialog getModelRelTypeCreationDialog(Model newSrcModelType, Model newTgtModelType, MID typeMID) {
List<String> modelRelTypeUris = null;
if (newSrcModelType != null && newTgtModelType != null) {
String newSrcUri = newSrcModelType.getUri();
String newTgtUri = newTgtModelType.getUri();
modelRelTypeUris = new ArrayList<String>();
for (ModelRel modelRelType : typeMID.getModelRels()) {
// binary can only inherit from root or binary
if (MIDTypeHierarchy.isRootType(modelRelType)) {
modelRelTypeUris.add(modelRelType.getUri());
continue;
}
if (!(modelRelType instanceof BinaryModelRel)) {
continue;
}
String srcUri = modelRelType.getModelEndpoints().get(0).getTargetUri();
String tgtUri = modelRelType.getModelEndpoints().get(1).getTargetUri();
// new model rel type with same endpoints or overriding one or two endpoints
if (
(newSrcUri.equals(srcUri) && newTgtUri.equals(tgtUri)) ||
(MIDTypeHierarchy.isSubtypeOf(newSrcUri, srcUri, typeMID) && newTgtUri.equals(tgtUri)) ||
(newSrcUri.equals(srcUri) && MIDTypeHierarchy.isSubtypeOf(newTgtUri, tgtUri, typeMID)) ||
(MIDTypeHierarchy.isSubtypeOf(newSrcUri, srcUri, typeMID) && MIDTypeHierarchy.isSubtypeOf(newTgtUri, tgtUri, typeMID))
) {
modelRelTypeUris.add(modelRelType.getUri());
}
}
}
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
MIDTreeSelectionDialog dialog = new MIDTreeSelectionDialog(
shell,
new MIDDialogLabelProvider(),
new NewModelRelTypeDialogContentProvider(modelRelTypeUris),
typeMID
);
return dialog;
}
/**
* Gets a tree dialog that shows all mapping types in a model relationship
* type, in order to create a new "light" mapping type and a reference to it.
*
* @param newSrcModelElemTypeRef
* The reference to the model element type that is going to be
* the target of the source model element type endpoint, null if
* the mapping type to be created is not binary.
* @param newTgtModelElemTypeRef
* The reference to the model element type that is going to be
* the target of the target model element type endpoint, null if
* the mapping type to be created is not binary.
* @param modelRelType
* The model relationship type that contains the mapping types.
* @return The tree dialog to create a new "light" mapping type.
*/
public static MIDTreeSelectionDialog getMappingTypeReferenceCreationDialog(ModelElementReference newSrcModelElemTypeRef, ModelElementReference newTgtModelElemTypeRef, ModelRel modelRelType) {
List<String> mappingTypeUris = null;
if (newSrcModelElemTypeRef != null && newTgtModelElemTypeRef != null) {
MID typeMID = modelRelType.getMIDContainer();
String newSrcUri = newSrcModelElemTypeRef.getUri();
String newTgtUri = newTgtModelElemTypeRef.getUri();
mappingTypeUris = new ArrayList<String>();
for (MappingReference mappingTypeRef : modelRelType.getMappingRefs()) {
// binary can only inherit from root or binary
if (!(mappingTypeRef instanceof BinaryMappingReference)) {
continue;
}
BinaryMapping mappingType = ((BinaryMappingReference) mappingTypeRef).getObject();
String srcUri = mappingType.getModelElemEndpoints().get(0).getTargetUri();
String tgtUri = mappingType.getModelElemEndpoints().get(1).getTargetUri();
// new link type with same endpoints or overriding one or two endpoints
if (
(newSrcUri.equals(srcUri) && newTgtUri.equals(tgtUri)) ||
(MIDTypeHierarchy.isSubtypeOf(newSrcUri, srcUri, typeMID) && newTgtUri.equals(tgtUri)) ||
(newSrcUri.equals(srcUri) && MIDTypeHierarchy.isSubtypeOf(newTgtUri, tgtUri, typeMID)) ||
(MIDTypeHierarchy.isSubtypeOf(newSrcUri, srcUri, typeMID) && MIDTypeHierarchy.isSubtypeOf(newTgtUri, tgtUri, typeMID))
) {
mappingTypeUris.add(mappingTypeRef.getUri());
}
}
}
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
MIDTreeSelectionDialog dialog = new MIDTreeSelectionDialog(
shell,
new MIDDialogLabelProvider(),
new NewMappingTypeReferenceDialogContentProvider(modelRelType, mappingTypeUris),
modelRelType
);
return dialog;
}
public static MIDTreeSelectionDialog getOperatorTypeCreationDialog(MID typeMID) {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
MIDTreeSelectionDialog dialog = new MIDTreeSelectionDialog(
shell,
new WorkbenchLabelProvider(),
new BaseWorkbenchContentProvider(),
ResourcesPlugin.getWorkspace().getRoot()
);
dialog.addFilter(new NewOperatorTypeDialogFilter());
dialog.setValidator(new NewOperatorTypeDialogSelectionValidator());
return dialog;
}
public static MIDTreeSelectionDialog getGenericTypeCreationDialog(GenericEndpoint genericSuperTypeEndpoint, EList<OperatorInput> inputs) {
Operator operatorType = (Operator) genericSuperTypeEndpoint.eContainer();
MID typeMID = operatorType.getMIDContainer();
GenericElement genericSuperType = genericSuperTypeEndpoint.getTarget();
List<GenericElement> genericTypes = MIDTypeHierarchy.getGenericSubtypes(genericSuperType);
genericTypes.add(0, genericSuperType);
Set<GenericElement> filteredGenericTypes = new HashSet<>();
for (GenericElement genericType : genericTypes) {
try {
if (genericType.isAbstract()) {
continue;
}
if (!operatorType.isAllowedGeneric(genericSuperTypeEndpoint, genericType, inputs)) {
//TODO MMINT[GENERICS] Can we check that the generic type is consistent with the input, or is it always done by the operator itself?
continue;
}
filteredGenericTypes.add(genericType);
}
catch (MMINTException e) {
continue;
}
}
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
MIDTreeSelectionDialog dialog = new MIDTreeSelectionDialog(
shell,
new MIDDialogLabelProvider(),
new NewGenericTypeDialogContentProvider(filteredGenericTypes),
typeMID
);
return dialog;
}
/**
* Gets a tree dialog that shows all model types in the repository and their
* editor types, in order to create a new model.
*
* @return The tree dialog to create a new model.
*/
public static MIDTreeSelectionDialog getModelCreationDialog() {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
MIDTreeSelectionDialog dialog = new MIDTreeSelectionDialog(
shell,
new MIDDialogLabelProvider(),
new NewModelDialogContentProvider(MMINT.cachedTypeMID),
MMINT.cachedTypeMID
);
dialog.setValidator(new NewModelDialogSelectionValidator());
return dialog;
}
/**
* Gets a tree dialog that shows all model files in the workspace, in order
* to import an existing model.
*
* @return The tree dialog to import an existing model.
*/
public static MIDTreeSelectionDialog getModelImportDialog() {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
MIDTreeSelectionDialog dialog = new MIDTreeSelectionDialog(
shell,
new WorkbenchLabelProvider(),
new BaseWorkbenchContentProvider(),
ResourcesPlugin.getWorkspace().getRoot()
);
dialog.addFilter(new ImportModelDialogFilter());
dialog.setValidator(new ImportModelDialogSelectionValidator());
return dialog;
}
/**
* Gets a tree dialog that shows all model relationship types in the
* repository, in order to create a new model relationship.
*
* @param targetSrcModel
* The model that is going to be the target of the source model
* endpoint, null if the model relationship to be created is not
* binary.
* @param targetTgtModel
* The model that is going to be the target of the target model
* endpoint, null if the model relationship to be created is not
* binary.
* @return The tree dialog to create a new model relationship.
*/
public static MIDTreeSelectionDialog getModelRelCreationDialog(Model targetSrcModel, Model targetTgtModel) {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
MIDTreeSelectionDialog dialog = new MIDTreeSelectionDialog(
shell,
new MIDDialogLabelProvider(),
new NewModelRelDialogContentProvider(MIDConstraintChecker.getAllowedModelRelTypes(targetSrcModel, targetTgtModel)),
MMINT.cachedTypeMID
);
return dialog;
}
/**
* Gets a tree dialog that shows all model type endpoints in a model
* relationship type, in order to create a new model endpoint.
*
* @param modelRel
* The model relationship that will contain the model endpoint to
* be created.
* @param modelTypeEndpointUris
* The list of allowed uris of the model type endpoints, can be
* null if all are allowed.
* @return The tree dialog to create a new model endpoint.
*/
public static MIDTreeSelectionDialog getModelEndpointCreationDialog(ModelRel modelRel, List<String> modelTypeEndpointUris) {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
MIDTreeSelectionDialog dialog = new MIDTreeSelectionDialog(
shell,
new MIDDialogLabelProvider(),
new NewModelEndpointDialogContentProvider(modelTypeEndpointUris),
modelRel.getMetatype()
);
return dialog;
}
/**
* Gets a tree dialog that shows all mapping types in a model relationship
* type, in order to create a new mapping and a reference to it.
*
* @param targetSrcModelElemRef
* The reference to the model element that is going to be the
* target of the source model element endpoint, null if the mapping
* to be created is not binary.
* @param targetTgtModelElemRef
* The reference to the model element that is going to be the
* target of the target model element endpoint, null if the mapping
* to be created is not binary.
* @param modelRel
* The model relationship that will contain the mapping to be
* created.
* @return The tree dialog to create a new mapping.
*/
public static MIDTreeSelectionDialog getMappingReferenceCreationDialog(ModelElementReference targetSrcModelElemRef, ModelElementReference targetTgtModelElemRef, ModelRel modelRel) {
ModelRel modelRelType = modelRel.getMetatype();
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
MIDTreeSelectionDialog dialog = new MIDTreeSelectionDialog(
shell,
new MIDDialogLabelProvider(),
new NewMappingReferenceDialogContentProvider(MIDConstraintChecker.getAllowedMappingTypeReferences(modelRelType, targetSrcModelElemRef, targetTgtModelElemRef)),
modelRelType
);
return dialog;
}
/**
* Gets a tree dialog that shows all model element type endpoints in a mapping
* type, in order to create a new model element endpoint.
*
* @param mappingRef
* The reference to the mapping that will contain the model element
* endpoint to be created.
* @param modelElemTypeEndpointUris
* The list of allowed uris of the model element type endpoints,
* can be null if all are allowed.
* @return The tree dialog to create a new model element endpoint.
*/
public static MIDTreeSelectionDialog getModelElementEndpointCreationDialog(MappingReference mappingRef, List<String> modelElemTypeEndpointUris) {
Mapping mappingType = mappingRef.getObject().getMetatype();
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
MIDTreeSelectionDialog dialog = new MIDTreeSelectionDialog(
shell,
new MIDDialogLabelProvider(),
new NewModelElementEndpointReferenceDialogContentProvider(modelElemTypeEndpointUris),
mappingType
);
return dialog;
}
public static MIDTreeSelectionDialog getWorkflowModelCreationDialog() {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
MIDTreeSelectionDialog dialog = new MIDTreeSelectionDialog(
shell,
new MIDDialogLabelProvider(),
new NewWorkflowModelDialogContentProvider(MMINT.cachedTypeMID),
MMINT.cachedTypeMID
);
return dialog;
}
public static MIDTreeSelectionDialog getWorkflowModelRelCreationDialog(Model targetSrcModel, Model targetTgtModel) {
return MIDTypeRegistry.getModelRelCreationDialog(targetSrcModel, targetTgtModel);
}
/**
* Gets the bundle (Eclipse plugin) that declares a type.
*
* @param typeUri
* The uri of the type.
* @return The bundle that declares a type, null if it can't be found.
*/
public static @Nullable Bundle getTypeBundle(@NonNull String typeUri) {
Bundle bundle = null;
String bundleName = MMINT.bundleTable.get(typeUri);
if (bundleName != null) {
return Platform.getBundle(bundleName);
}
return bundle;
}
/**
* Gets the uri of the metamodel of a metamodel-extended "light" model type.
*
* @param modelType
* The metamodel-extended "light" model type.
* @return The uri of the metamodel extension if it exists, null if it
* doesn't exist or if the model type is not "light".
*/
public static String getExtendedMetamodelPath(Model modelType) {
if (!modelType.isDynamic()) {
return null;
}
String metamodelUri = modelType.getName() + MMINT.MODEL_FILEEXTENSION_SEPARATOR + EcorePackage.eNAME;
return (FileUtils.isFileOrDirectoryInState(metamodelUri)) ?
FileUtils.prependStatePathToUri(metamodelUri) :
null;
}
}