| /***************************************************************************** |
| * Copyright (c) 2016 CEA LIST and others. |
| * |
| * 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: |
| * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation |
| * |
| *****************************************************************************/ |
| |
| package org.eclipse.papyrus.interoperability.rpy.transformations; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.MultiStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.emf.common.util.Diagnostic; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EAnnotation; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.emf.ecore.xmi.XMIResource; |
| import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; |
| import org.eclipse.gmf.runtime.emf.core.resources.GMFResource; |
| import org.eclipse.gmf.runtime.notation.Diagram; |
| import org.eclipse.gmf.runtime.notation.Style; |
| import org.eclipse.gmf.runtime.notation.View; |
| import org.eclipse.m2m.internal.qvt.oml.library.Context; |
| import org.eclipse.m2m.qvt.oml.BasicModelExtent; |
| import org.eclipse.m2m.qvt.oml.ExecutionContextImpl; |
| import org.eclipse.m2m.qvt.oml.ModelExtent; |
| import org.eclipse.papyrus.infra.internationalization.resource.InternationalizationResource; |
| import org.eclipse.papyrus.infra.internationalization.utils.InternationalizationResourceOptionsConstants; |
| import org.eclipse.papyrus.infra.internationalization.utils.PropertiesFilesUtils; |
| import org.eclipse.papyrus.infra.tools.util.ListHelper; |
| import org.eclipse.papyrus.interoperability.rpy.Activator; |
| import org.eclipse.papyrus.interoperability.rpy.xmi.PreserveRpySemanticIDHelper; |
| import org.eclipse.papyrus.uml.internationalization.utils.UMLInternationalizationKeyResolver; |
| import org.eclipse.papyrus.uml.m2m.qvto.common.MigrationParameters.ThreadConfig; |
| import org.eclipse.papyrus.uml.m2m.qvto.common.concurrent.ResourceAccessHelper; |
| import org.eclipse.papyrus.uml.m2m.qvto.common.transformation.AbstractImportTransformation; |
| import org.eclipse.papyrus.uml.m2m.qvto.common.transformation.IDependencyAnalysisHelper; |
| import org.eclipse.uml2.uml.resource.UMLResource; |
| |
| /** |
| * @author Vincent Lorenzo |
| * |
| */ |
| public class RpyImportTransformation extends AbstractImportTransformation { |
| |
| /** |
| * The file used to store the labels defined in the Rhaposdy Model |
| */ |
| private InternationalizationResource propertiesResource; |
| |
| public RpyImportTransformation(URI sourceURI, ThreadConfig config, IDependencyAnalysisHelper analysisHelper) { |
| super(sourceURI, config, analysisHelper); |
| DEBUG = true; |
| } |
| |
| public RpyImportTransformation(URI sourceURI) { |
| super(sourceURI); |
| } |
| |
| /** |
| * @see org.eclipse.papyrus.interoperability.rpy..transformations.NEW_AbstractImportTransformation_NEW#run(org.eclipse.core.runtime.IProgressMonitor) |
| * |
| * @param monitor |
| * @return |
| */ |
| @Override |
| protected IStatus run(IProgressMonitor monitor) { |
| // |
| // INITIALIZATION / LOADING |
| // |
| |
| monitor.subTask("Loading source model " + getModelName()); |
| |
| long startLoad = System.nanoTime(); |
| initResourceSet(monitor); |
| |
| int numberOfElements = countSupportedElements(); |
| |
| monitor.beginTask("Importing " + getModelName(), numberOfElements); |
| |
| monitor.subTask("Loading transformations (This may take a few seconds for the first import)..."); |
| |
| loadTransformations(monitor); |
| |
| List<ModelExtent> extents = getModelExtents(); |
| |
| String statusMessage = String.format("Import %s", getModelName()); |
| MultiStatus generationStatus = new MultiStatus(Activator.PLUGIN_ID, IStatus.OK, statusMessage, null); |
| |
| context = createExecutionContext(monitor, generationStatus); |
| |
| try { |
| getInPapyrusProfiles(); // Preload profiles |
| |
| long endLoad = System.nanoTime(); |
| loadingTime = endLoad - startLoad; |
| |
| // |
| // TRANSFORMATIONS |
| // |
| |
| IStatus result; // Result of an individual transformation (Will be aggregated to the complete GenerationStatus) |
| |
| prepareExtensions(); |
| |
| // TODO useful for the Rpy import ? |
| long startExtensions = System.nanoTime(); |
| result = importExtensions(context, monitor, ExtensionFunction::executeBefore); |
| long endExtensions = System.nanoTime(); |
| |
| this.importExtensionsTime = endExtensions - startExtensions; |
| generationStatus.add(result); |
| |
| // TODO : warning, this step is not in RSA |
| monitor.subTask("Importing semantic model..."); |
| URI semanticTransformationURI = getSemanticTransformationURI(); |
| if (null != semanticTransformationURI) { |
| result = runTransformation(semanticTransformationURI, extents, monitor); |
| generationStatus.add(result); |
| } |
| // Diagrams |
| Collection<URI> transformations = getDiagramTransformationURIs(); |
| |
| monitor.subTask("Importing diagrams..."); |
| for (URI transformationURI : transformations) { |
| result = runTransformation(transformationURI, extents, monitor); |
| generationStatus.add(result); |
| } |
| |
| // TODO : it seems to be an additional transfo for RSA import |
| // // Semantic model changes (Default language for OpaqueExpressions...) |
| // monitor.subTask("Importing semantic model..."); |
| // result = runTransformation(getSemanticTransformationURI(), extents, monitor); |
| // generationStatus.add(result); |
| |
| // TODO : remove me, not required for Rpy import |
| // if (!monitor.isCanceled()) { |
| // monitor.subTask("Handle additional profiles..."); |
| // // Default.epx and ProfileBase.epx |
| // result = importRSAProfiles(context, monitor); |
| // generationStatus.add(result); |
| // } |
| |
| Collection<URI> additional = getAdditionalTransformationURIs(); |
| if (!additional.isEmpty()) { |
| monitor.subTask("Additional transformations..."); |
| for (URI transformationURI : additional) { |
| result = runTransformation(transformationURI, extents, monitor); |
| generationStatus.add(result); |
| } |
| } |
| |
| long startExtensionsAfter = System.nanoTime(); |
| result = importExtensions(context, monitor, ExtensionFunction::executeAfter); |
| long endExtensionsAfter = System.nanoTime(); |
| this.importExtensionsTime += endExtensionsAfter - startExtensionsAfter; |
| } finally { |
| // context = null; |
| } |
| |
| // |
| // FRAGMENTS & SAVE |
| // |
| |
| if (generationStatus.getSeverity() <= Diagnostic.WARNING) { |
| |
| monitor.subTask("Cleaning-up target model..."); |
| URI notationModelURI = null; |
| URI sashModelURI = null; |
| |
| targetURI = convertToPapyrus(sourceURI, UMLResource.FILE_EXTENSION); |
| notationModelURI = convertToPapyrus(sourceURI, "notation"); // TODO use constant |
| sashModelURI = convertToPapyrus(sourceURI, "di"); // TODO use constant |
| |
| // TODO : remove epx here! |
| if ("epx".equals(sourceURI.fileExtension())) { |
| profileURIMappings.put(sourceURI, targetURI); |
| } |
| // Profile mappings are also library mappings |
| uriMappings.put(sourceURI, targetURI); |
| |
| umlResource = createUMLResource(resourceSet, sourceURI, targetURI); |
| |
| // This list contains all the objects from the initial ModelExtent, plus all the ones |
| // which were created during the QVTo transformations. |
| List<EObject> outUMLObjects = getInOutUMLModel().getContents(); |
| umlResource.getContents().addAll(outUMLObjects); |
| |
| PreserveRpySemanticIDHelper helper = new PreserveRpySemanticIDHelper(new Context(context)); |
| helper.keepIdForUMLResource((XMIResource) this.umlResource); |
| |
| context = null; |
| |
| GMFResource notationResource = new GMFResource(notationModelURI); // GMF Resource content type? |
| resourceSet.getResources().add(notationResource); |
| List<EObject> outNotationObjects = getInoutNotationModel().getContents(); |
| notationResource.getContents().addAll(outNotationObjects); |
| |
| // Cleanup empty diagrams (FIXME: They should not be generated) |
| List<EObject> contentsCopy = new LinkedList<>(notationResource.getContents()); |
| for (EObject next : contentsCopy) { |
| if (next instanceof Diagram) { |
| Diagram diagram = (Diagram) next; |
| if (diagram.getType() == null || "".equals(diagram.getType())) { |
| delete(diagram); |
| } |
| } |
| } |
| |
| final URI propertyURI = convertToPapyrus(sourceURI, PropertiesFilesUtils.PROPERTIES_FILE_EXTENSION); |
| propertiesResource = createAndConfigureInternationalizationResource(propertyURI); |
| resourceSet.getResources().add(propertiesResource); |
| propertiesResource.getContents().addAll(getInOutInternationalizationModel().getContents()); |
| |
| XMIResource sashResource = new XMIResourceImpl(sashModelURI); |
| resourceSet.getResources().add(sashResource); |
| List<EObject> sashModelObjects = getOutSashModel().getContents(); |
| sashResource.getContents().addAll(sashModelObjects); |
| |
| configureResource(sashResource); |
| configureResource(notationResource); |
| configureResource((XMIResource) umlResource); |
| // configureResource((XMIResource)propertiesResource); //not required |
| |
| // Handle orphaned elements: remove them and log a warning (Log temporarily disabled to avoid spamming the console) |
| List<EObject> notationRootElements = new LinkedList<>(notationResource.getContents()); |
| for (EObject rootElement : notationRootElements) { |
| if (rootElement instanceof View) { |
| View rootView = (View) rootElement; |
| if (!(rootView instanceof Diagram)) { |
| if (DEBUG) { |
| String objectType = rootView.getElement() == null ? "None" : rootView.getElement().eClass().getName(); |
| String viewType = rootView.getType() == null ? "None" : rootView.getType(); |
| generationStatus.add(new Status(IStatus.WARNING, Activator.PLUGIN_ID, "An orphaned view has been found after the migration. It will be removed. View Type: " + viewType + ", semantic type: " + objectType)); |
| } |
| |
| delete(rootElement); |
| } |
| } else if (rootElement instanceof Style) { |
| |
| if (DEBUG) { |
| String styleType = rootElement.eClass().getName(); |
| generationStatus.add(new Status(IStatus.WARNING, Activator.PLUGIN_ID, "An orphaned style has been found after the migration. It will be removed. Style Type: " + styleType)); |
| } |
| |
| delete(rootElement); |
| } |
| } |
| |
| |
| monitor.subTask("Handling fragments..."); |
| |
| |
| Collection<Resource> resourcesToSave = handleFragments(umlResource, notationResource, sashResource); |
| resourcesToSave.add(propertiesResource); |
| // TODO : commented because it probably concerns only RSa |
| // for (Resource resource : resourcesToSave) { |
| // List<EObject> rootElements = new LinkedList<>(resource.getContents()); |
| // for (EObject rootElement : rootElements) { |
| // EPackage ePackage = rootElement.eClass().getEPackage(); |
| // if (ePackage == ProfileBasePackage.eINSTANCE || ePackage == DefaultPackage.eINSTANCE) { |
| // delete(rootElement); |
| // } |
| // } |
| // } |
| |
| monitor.subTask("Deleting source diagrams..."); |
| |
| for (Diagram diagram : diagramsToDelete) { |
| EObject container = diagram.eContainer(); |
| delete(diagram); |
| if (container instanceof EAnnotation) { |
| EAnnotation annotation = (EAnnotation) container; |
| if (annotation.getContents().isEmpty()) { |
| delete(annotation); |
| } |
| } |
| } |
| |
| diagramsToDelete.clear(); |
| |
| monitor.subTask("Analyzing dangling references..."); |
| |
| long startDangling = System.nanoTime(); |
| handleDanglingURIs(resourcesToSave); |
| long endDangling = System.nanoTime(); |
| this.danglingRefTime = endDangling - startDangling; |
| |
| monitor.subTask("Saving models..."); |
| |
| for (Resource resource : resourcesToSave) { |
| try { |
| cleanMetadataAnnotations(resource); |
| ResourceAccessHelper.INSTANCE.saveResource(resource, null); |
| } catch (Exception ex) { |
| Activator.log.error(ex); |
| generationStatus.add(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "An exception occurred during save", ex)); |
| } |
| } |
| } |
| |
| monitor.subTask("Releasing memory..."); |
| |
| unloadResourceSet(this.resourceSet); |
| |
| this.resourceSet = null; |
| this.umlResource = null; |
| // TODO : we ùust clean all ModelExtends and all resource (a method will help us!) |
| this.outNotation = this.inParameters = this.outSashModel = this.outUML = null; |
| |
| monitor.done(); |
| return generationStatus; |
| } |
| |
| /** |
| * |
| * @param propertyURI |
| * the uri of the property file |
| * @return |
| * the Resource to use for internationlization |
| */ |
| protected InternationalizationResource createAndConfigureInternationalizationResource(final URI propertyURI) { |
| if (null == this.propertiesResource) { |
| this.propertiesResource = new InternationalizationResource(propertyURI); |
| this.propertiesResource.getDefaultSaveOptions().put(InternationalizationResourceOptionsConstants.SAVE_OPTION_SORT, Boolean.TRUE); |
| this.propertiesResource.getDefaultSaveOptions().put(InternationalizationResourceOptionsConstants.LOAD_SAVE_OPTION_KEY_RESOLVER, UMLInternationalizationKeyResolver.getInstance()); |
| } |
| return this.propertiesResource; |
| } |
| |
| |
| /** |
| * @see org.eclipse.papyrus.interoperability.rpy..transformations.NEW_AbstractImportTransformation_NEW#loadInPapyrusProfiles() |
| * |
| * @return |
| */ |
| @Override |
| protected Diagnostic loadInPapyrusProfiles() { |
| |
| |
| // currently there is nothing to do for Rpy import |
| return null; |
| } |
| |
| /** |
| * @see org.eclipse.papyrus.interoperability.rpy..transformations.NEW_AbstractImportTransformation_NEW#countSupportedElements() |
| * |
| * @return |
| */ |
| @Override |
| protected int countSupportedElements() { |
| // TODO Auto-generated method stub |
| return 1000; |
| } |
| |
| /** |
| * @see org.eclipse.papyrus.interoperability.rpy..transformations.NEW_AbstractImportTransformation_NEW#getDiagramTransformationURIs() |
| * |
| * @return |
| */ |
| @Override |
| protected Collection<URI> getDiagramTransformationURIs() { |
| return ListHelper.asList(new URI[] { getTransformationURI("Rpy2PapyrusNotation", Activator.PLUGIN_ID), |
| |
| }); |
| } |
| |
| /** |
| * @see org.eclipse.papyrus.interoperability.rpy..transformations.NEW_AbstractImportTransformation_NEW#getSemanticTransformationURI() |
| * |
| * @return |
| */ |
| @Override |
| protected URI getSemanticTransformationURI() { |
| // TODO never call, called from the Rpy2PapyrusNotation transform to make the link between uml created elements and their representation |
| // return ListHelper.asList(new URI[] { getTransformationURI("Rpy2PapyrusSemanticElements"), |
| // |
| // }); |
| |
| return null; |
| } |
| |
| /** |
| * @see org.eclipse.papyrus.interoperability.rpy..transformations.NEW_AbstractImportTransformation_NEW#getProfilesTransformationURI() |
| * |
| * @return |
| */ |
| @Override |
| protected Collection<URI> getProfilesTransformationURI() { |
| return Collections.emptyList(); |
| } |
| |
| /** |
| * @see org.eclipse.papyrus.uml.m2m.qvto.common.transformation.AbstractImportTransformation#getAllTransformationURIs() |
| * |
| * @return |
| */ |
| @Override |
| protected Collection<URI> getAllTransformationURIs() { |
| final Collection<URI> allTransformations = new ArrayList<URI>(); |
| final URI semanticTransformationURI = getSemanticTransformationURI(); |
| if (null != semanticTransformationURI) { |
| allTransformations.add(semanticTransformationURI); |
| } |
| final Collection<URI> diagramTransformationURI = getDiagramTransformationURIs(); |
| if (null != diagramTransformationURI) { |
| allTransformations.addAll(diagramTransformationURI); |
| } |
| final Collection<URI> profilesTransformationURI = getProfilesTransformationURI(); |
| if (null != profilesTransformationURI) { |
| allTransformations.addAll(profilesTransformationURI); |
| } |
| final Collection<URI> additionalTransformationURIs = getAdditionalTransformationURIs(); |
| if (null != additionalTransformationURIs) { |
| allTransformations.addAll(additionalTransformationURIs); |
| } |
| return allTransformations; |
| |
| } |
| |
| /** |
| * @see org.eclipse.papyrus.interoperability.rpy..transformations.NEW_AbstractImportTransformation_NEW#getModelExtents() |
| * |
| * @return |
| */ |
| @Override |
| protected List<ModelExtent> getModelExtents() { |
| List<ModelExtent> allExtents = new LinkedList<ModelExtent>(); |
| allExtents.add(getInRpyModel()); |
| allExtents.add(getInoutNotationModel()); |
| allExtents.add(getInOutUMLModel()); |
| allExtents.add(getSysML1_1Profile()); |
| allExtents.add(getInUMLPrimitivesTypes()); |
| allExtents.add(getInOutInternationalizationModel()); |
| return allExtents; |
| } |
| |
| |
| public ModelExtent getInUMLPrimitivesTypes() { |
| URI umlPrimitivesTypesURI = URI.createURI("pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml"); |
| Resource umlPrimitivesTypesResource = resourceSet.getResource(umlPrimitivesTypesURI, true); |
| umlPrimitivesTypes = new BasicModelExtent(umlPrimitivesTypesResource.getContents()); |
| return umlPrimitivesTypes; |
| } |
| |
| private ModelExtent inRpyModel, umlPrimitivesTypes, labels; |
| |
| public ModelExtent getInRpyModel() { |
| if (inRpyModel == null) { |
| Resource resource = resourceSet.getResource(sourceURI, true); |
| inRpyModel = new BasicModelExtent(resource.getContents()); |
| } |
| return inRpyModel; |
| } |
| |
| public ModelExtent getSysML1_1Profile() { |
| URI sysMLProfile = URI.createURI("pathmap://SysML_PROFILES/SysML.profile.uml"); |
| Resource fCMProfile = resourceSet.getResource(sysMLProfile, true); |
| sysML11Profile = new BasicModelExtent(fCMProfile.getContents()); |
| return sysML11Profile; |
| } |
| |
| |
| /** |
| * |
| * @return |
| * the model extends to use to create the required file .property |
| */ |
| public ModelExtent getInOutInternationalizationModel() { |
| if (this.labels == null) { |
| this.labels = new BasicModelExtent(); |
| } |
| return this.labels; |
| } |
| |
| |
| /** |
| * @see org.eclipse.papyrus.interoperability.rpy..transformations.NEW_AbstractImportTransformation_NEW#initTransformationProperties(org.eclipse.m2m.qvt.oml.ExecutionContextImpl) |
| * |
| * @param context |
| */ |
| @Override |
| protected void initTransformationProperties(ExecutionContextImpl context) { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| /** |
| * @see org.eclipse.papyrus.interoperability.rpy..transformations.NEW_AbstractImportTransformation_NEW#convertToPapyrus(org.eclipse.emf.common.util.URI, java.lang.String) |
| * |
| * @param initialModelURI |
| * @param extension |
| * @return |
| */ |
| @Override |
| protected URI convertToPapyrus(URI initialModelURI, String extension) { |
| return initialModelURI.trimFileExtension().appendFileExtension(extension); |
| } |
| |
| /** |
| * @see org.eclipse.papyrus.interoperability.rpy..transformations.NEW_AbstractImportTransformation_NEW#createUMLResource(org.eclipse.emf.ecore.resource.ResourceSet, org.eclipse.emf.common.util.URI, org.eclipse.emf.common.util.URI) |
| * |
| * @param resourceSet |
| * @param sourceResourceURI |
| * @param targetResourceURI |
| * @return |
| */ |
| @Override |
| protected Resource createUMLResource(ResourceSet resourceSet, URI sourceResourceURI, URI targetResourceURI) { |
| Resource resource = resourceSet.createResource(targetResourceURI, UMLResource.UML_5_0_0_CONTENT_TYPE_IDENTIFIER); |
| return resource; |
| } |
| |
| /** |
| * @see org.eclipse.papyrus.interoperability.rpy..transformations.NEW_AbstractImportTransformation_NEW#getInOutUMLModel() |
| * |
| * @return |
| */ |
| @Override |
| public ModelExtent getInOutUMLModel() { |
| if (outUML == null) { |
| outUML = new BasicModelExtent(); |
| } |
| return outUML; |
| } |
| |
| |
| |
| |
| } |