blob: 332b6a4d928bd925161e8a755ed346adc046d3fe [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2013, 2016 CEA LIST, Christian W. Damus, 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:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
* Christian W. Damus - bugs 496439, 496299
* Vincent Lorenzo - bug 496176
*****************************************************************************/
package org.eclipse.papyrus.interoperability.common.transformation;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.Assert;
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.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.DiagnosticException;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.ExtendedMetaData;
import org.eclipse.emf.ecore.xmi.XMIResource;
import org.eclipse.emf.ecore.xmi.XMLResource;
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.jface.dialogs.MessageDialog;
import org.eclipse.m2m.qvt.oml.BasicModelExtent;
import org.eclipse.m2m.qvt.oml.ExecutionContext;
import org.eclipse.m2m.qvt.oml.ExecutionContextImpl;
import org.eclipse.m2m.qvt.oml.ExecutionDiagnostic;
import org.eclipse.m2m.qvt.oml.ModelExtent;
import org.eclipse.m2m.qvt.oml.TransformationExecutor;
import org.eclipse.m2m.qvt.oml.util.ISessionData;
import org.eclipse.m2m.qvt.oml.util.Trace;
import org.eclipse.m2m.qvt.oml.util.WriterLog;
import org.eclipse.papyrus.infra.emf.resource.ShardResourceHelper;
import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import org.eclipse.papyrus.interoperability.common.Activator;
import org.eclipse.papyrus.interoperability.common.MigrationParameters.MigrationParametersFactory;
import org.eclipse.papyrus.interoperability.common.MigrationParameters.ThreadConfig;
import org.eclipse.papyrus.interoperability.common.concurrent.ExecutorsPool;
import org.eclipse.papyrus.interoperability.common.internal.extension.TransformationExtension;
import org.eclipse.papyrus.m2m.qvto.TraceHelper;
import org.eclipse.papyrus.m2m.qvto.TransformationUI;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.uml2.common.util.CacheAdapter;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Extension;
import org.eclipse.uml2.uml.resource.UMLResource;
import org.eclipse.uml2.uml.util.UMLUtil;
/**
* Executes a single import-to-Papyrus transformation
*
* @author Vincent Lorenzo
*
*/
public abstract class AbstractImportTransformation implements IImportTransformation {
/** For debug purpose */
protected static boolean DEBUG = true;
// SourceURI is the input
protected final URI sourceURI;
// targetURI is computed during the transformation
protected URI targetURI;
protected ModelExtent outUML, outNotation, outSashModel, inParameters, inPapyrusProfiles, sysML11Profile;
protected MigrationResourceSet resourceSet;
protected Job job;
protected Resource umlResource;
protected ThreadConfig parameters;
protected boolean complete = false;
// For logging purpose (Bug 455001)
// Starts when the job starts; ends when the job returns
/** Execution time, in nano-seconds */
protected long executionTime = 0L;
/** Execution time of the initial model loading / ns */
protected long loadingTime = 0L;
/** Execution time for handling dangling references / ns */
protected long danglingRefTime = 0L;
/** Execution time for executing the UML-RT transformation / ns */
protected long importExtensionsTime = 0L;
/** Source URI to Target URI map (For Models/Libraries/Fragments) */
protected final Map<URI, URI> uriMappings = new HashMap<>();
/** Source URI to Target URI map (For Profiles) */
protected final Map<URI, URI> profileURIMappings = new HashMap<>();
protected List<Diagram> diagramsToDelete = new LinkedList<>();
protected static final ExecutorsPool executorsPool = new ExecutorsPool(2);
// TODO : check if sourceEPackages is required for Rpy and common tranfo
/** EPackages corresponding to source native profiles with specific support in the transformation */
protected static final Set<EPackage> sourceEPackages = new HashSet<>();
protected final IDependencyAnalysisHelper analysisHelper;
/** Extensions contributed via other plug-ins */
protected final List<TransformationExtension> extensions;
/** Accumulation of incremental update traces from each transformation. */
private Trace trace = Trace.createEmptyTrace();
/** Transformation execution context used for all transformation runs. */
protected ExecutionContext context;
public AbstractImportTransformation(URI sourceURI) {
this(sourceURI, MigrationParametersFactory.eINSTANCE.createThreadConfig(), null);
}
public AbstractImportTransformation(URI sourceURI, ThreadConfig config, IDependencyAnalysisHelper analysisHelper) {
Assert.isNotNull(sourceURI);
this.sourceURI = sourceURI;
this.parameters = config;
this.analysisHelper = analysisHelper;
this.extensions = getAllExtensions();
}
/**
* Instantiate all the extensions for a specific transformation
*
* @return
* A non-null (potentially empty) list of extensions
*/
protected static List<TransformationExtension> getAllExtensions() {
// TODO probably RSA only or the extension point must be rewritten
return Collections.emptyList();
}
/**
* Executes the transformation
*
* The transformation will be executed asynchronously in a Job
*/
public void run(final boolean isUserJob) {
job = new Job("Import " + getModelName()) {
@Override
protected IStatus run(IProgressMonitor monitor) {
long begin = System.nanoTime();
IStatus result = AbstractImportTransformation.this.run(monitor);
long end = System.nanoTime();
executionTime = end - begin;
return result;
}
};
job.setUser(isUserJob);
job.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
complete = true;
if (isUserJob) {
if (event.getResult().getSeverity() == IStatus.OK) {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
MessageDialog.openInformation(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), job.getName(), String.format("Model %s has been successfully imported", getModelName()));
}
});
} else if (event.getResult().getSeverity() == IStatus.CANCEL) {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
MessageDialog.openInformation(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), job.getName(), String.format("Operation canceled: %s", getModelName()));
}
});
} else {
StatusManager.getManager().handle(event.getResult(), StatusManager.BLOCK);
}
}
}
});
job.schedule();
}
public void waitForCompletion() {
try {
job.join();
} catch (InterruptedException ex) {
Activator.log.error(ex);
}
}
public boolean isComplete() {
return complete;
}
public IStatus getStatus() {
if (job == null) { // If job hasn't been created, the operation has probably been canceled before the transformation is ran
return new Status(IStatus.CANCEL, Activator.PLUGIN_ID, "Operation canceled");
}
return job.getResult();
}
public long getExecutionTime() {
return executionTime;
}
public long getLoadingTime() {
return loadingTime;
}
public long getHandleDanglingRefTime() {
return danglingRefTime;
}
public long getImportExtensionsTime() {
// TODO maybe only for RSa!
return importExtensionsTime;
}
public URI getTargetURI() {
return targetURI;
}
/**
* Initializes the resource set, and resolve all dependencies
*/
protected void initResourceSet(IProgressMonitor monitor) {
resourceSet = new MigrationResourceSetImpl();
synchronized (UMLUtil.class) {
UMLUtil.init(resourceSet);
}
resourceSet.getLoadOptions().put(XMLResource.OPTION_DEFER_ATTACHMENT, true);
resourceSet.getLoadOptions().put(XMLResource.OPTION_DEFER_IDREF_RESOLUTION, true);
resourceSet.getLoadOptions().put(XMLResource.OPTION_RECORD_UNKNOWN_FEATURE, Boolean.TRUE);
resourceSet.getLoadOptions().put(XMLResource.OPTION_USE_PACKAGE_NS_URI_AS_LOCATION, Boolean.FALSE);
monitor.subTask("Loading source model " + getModelName());
try {
resourceSet.getResource(sourceURI, true);
loadInPapyrusProfiles();
} catch (Exception ex) {
Activator.log.error("An error occurred while loading " + getModelName(), ex);
}
}
protected abstract int countSupportedElements(); // TODO
protected IStatus loadTransformations(IProgressMonitor monitor) {
for (URI transformationURI : getAllTransformationURIs()) {
executorsPool.preLoad(transformationURI);
monitor.worked(1);
}
return Status.OK_STATUS;
}
// MemoryLeak: Don't rely on BasicDiagnostic.toIStatus
// The source Diagnostic contains references to the QVTo ModelExtents, referencing the Model elements (used in #extractPapyrusProfiles())
// When using the standard conversion, these references are not discarded
protected static IStatus createStatusFromDiagnostic(Diagnostic diagnostic) {
return new Status(diagnostic.getSeverity(),
diagnostic.getSource(),
diagnostic.getMessage(),
diagnostic.getException());
}
/**
* Actually runs the transformation (in the current thread)
*
* @param monitor
* @return The transformation IStatus
*/
// TODO maybe more common stuff with RSA import here
// TODO : maybe in the interface if we keep it!
protected abstract IStatus run(final IProgressMonitor monitor);
/**
* Functional interface to abstract {@link TransformationExtension#executeBefore(ExecutionContext, IProgressMonitor)}
* and {@link TransformationExtension#executeAfter(ExecutionContext, IProgressMonitor)}
*
* @author Camille Letavernier
*
*/
@FunctionalInterface
protected static interface ExtensionFunction {
public IStatus apply(TransformationExtension extension, ExecutionContext context, IProgressMonitor monitor);
/**
* Implements ExtensionFunction
*
* Delegates to {@link TransformationExtension#executeBefore(ExecutionContext, IProgressMonitor)}
*/
public static IStatus executeBefore(TransformationExtension extension, ExecutionContext context, IProgressMonitor monitor) {
return extension.executeBefore(context, monitor);
}
/**
* Implements ExtensionFunction
*
* Delegates to {@link TransformationExtension#executeAfter(ExecutionContext, IProgressMonitor)}
*/
public static IStatus executeAfter(TransformationExtension extension, ExecutionContext context, IProgressMonitor monitor) {
return extension.executeAfter(context, monitor);
}
}
protected void prepareExtensions() {
for (TransformationExtension extension : extensions) {
extension.setResourceSet(resourceSet);
extension.setExecutorsPool(executorsPool);
extension.setTransformation(this);
}
}
protected IStatus importExtensions(ExecutionContext context, IProgressMonitor monitor, ExtensionFunction function) {
List<IStatus> allResults = new ArrayList<>(extensions.size());
for (TransformationExtension extension : extensions) {
IStatus result = function.apply(extension, context, monitor);
allResults.add(result);
}
if (allResults.isEmpty()) {
return Status.OK_STATUS;
} else if (allResults.size() == 1) {
return allResults.get(0);
} else {
return aggregateStatus(allResults);
}
}
// FIXME implement properly
public static MultiStatus aggregateStatus(List<IStatus> statuses) {
return new MultiStatus(Activator.PLUGIN_ID, IStatus.OK, statuses.toArray(new IStatus[statuses.size()]), "", null);
}
/**
* @param resource
*/
protected void cleanMetadataAnnotations(Resource resource) {
// Bug 471684: UML2.x to UML2.5 creates (invalid) Ecore Metadata EAnnotations, which then cause OCL validation to fail
// Remove these EAnnotations from the model to avoid side effects
Iterator<EObject> rootElementsIterator = resource.getContents().iterator();
while (rootElementsIterator.hasNext()) {
EObject root = rootElementsIterator.next();
if (root instanceof EAnnotation) {
EAnnotation annotation = (EAnnotation) root;
if (ExtendedMetaData.ANNOTATION_URI.equals(annotation.getSource())) {
rootElementsIterator.remove();
}
}
}
}
protected void handleDanglingURIs(Collection<Resource> resourcesToSave) {
if (analysisHelper != null) {
resourceSet.freeze();
try {
analysisHelper.computeURIMappings(resourcesToSave);
} finally {
resourceSet.unfreeze();
}
}
}
protected void unloadResourceSet(ResourceSet resourceSet) {
EMFHelper.unload(resourceSet);
}
protected TransformationExecutor getTransformation(URI transformationURI, IProgressMonitor monitor) throws DiagnosticException {
return executorsPool.getExecutor(transformationURI);
}
protected ModelExtent getInProfileDefinitions() {
//TODO : not used, useful for common and Rpy import
return null;
}
protected ModelExtent getInPapyrusProfiles() {
if (inPapyrusProfiles == null) {
loadInPapyrusProfiles();
}
return inPapyrusProfiles;
}
protected abstract Diagnostic loadInPapyrusProfiles(); // TODO : add path of profile are parameters ?
protected void checkResource(Resource resource) {
Assert.isNotNull(resource);
Assert.isTrue(!resource.getContents().isEmpty(), "The resource " + resource.getURI() + " is empty");
for (EObject rootElement : resource.getContents()) {
Assert.isTrue(!rootElement.eIsProxy());
}
}
protected abstract Resource createUMLResource(ResourceSet resourceSet, URI sourceResourceURI, URI targetResourceURI);
protected ModelExtent getInConfig() {
if (inParameters == null) {
inParameters = new BasicModelExtent(Collections.singletonList(parameters));
}
return inParameters;
}
protected Collection<Resource> handleFragments(Resource umlResource, Resource notationResource, Resource sashResource) {
Collection<Resource> result = new HashSet<>();
result.add(umlResource);
result.add(notationResource);
result.add(sashResource);
ResourceSet resourceSet = umlResource.getResourceSet();
Iterator<EObject> elementIterator = umlResource.getAllContents();
Set<Resource> fragmentResources = new HashSet<>();
List<EAnnotation> rsaAnnotations = new ArrayList<>();
while (elementIterator.hasNext()) {
EObject element = elementIterator.next();
Resource possibleFragment = element.eResource();
if ((possibleFragment != umlResource) && possibleFragment.getContents().contains(element)) { // Controlled/Fragment root
fragmentResources.add(possibleFragment);
}
// TODO commented because it is RSA import only
// collectRSAAnnotations(element, rsaAnnotations);
}
// Strip all RSA fragment annotations
rsaAnnotations.forEach(EcoreUtil::remove);
List<Resource> fragmentUMLResources = new LinkedList<>();
for (Resource fragmentResource : fragmentResources) {
URI papyrusFragmentURI = convertToPapyrus(fragmentResource.getURI(), UMLResource.FILE_EXTENSION);
uriMappings.put(fragmentResource.getURI(), papyrusFragmentURI);
Resource newResource = resourceSet.getResource(papyrusFragmentURI, false);
if (newResource == null) {
newResource = createUMLResource(resourceSet, fragmentResource.getURI(), papyrusFragmentURI);
fragmentUMLResources.add(newResource);
Resource fragmentNotationResource = new GMFResource(convertToPapyrus(papyrusFragmentURI, "notation"));
Resource fragmentDiResource = new XMIResourceImpl(convertToPapyrus(papyrusFragmentURI, "di"));
result.add(fragmentNotationResource);
result.add(fragmentDiResource);
resourceSet.getResources().add(fragmentNotationResource);
resourceSet.getResources().add(fragmentDiResource);
}
newResource.getContents().addAll(fragmentResource.getContents());
// Make it a Papyrus controlled unit of the "shard" variety
try (ShardResourceHelper shard = new ShardResourceHelper(newResource)) {
shard.setShard(true);
}
result.add(newResource);
}
deleteSourceStereotypes(fragmentResources);
List<EObject> importedElements = new LinkedList<>(notationResource.getContents());
for (EObject notationElement : importedElements) {
if (notationElement instanceof Diagram) {
EObject semanticElement = ((Diagram) notationElement).getElement();
if (semanticElement.eResource() != umlResource && semanticElement.eResource() != null) {
URI notationFragmentURI = convertToPapyrus(semanticElement.eResource().getURI(), "notation");
Resource newNotationResource = resourceSet.getResource(notationFragmentURI, false);
if (newNotationResource == null) {
newNotationResource = new GMFResource(notationFragmentURI);
resourceSet.getResources().add(newNotationResource);
}
newNotationResource.getContents().add(notationElement);
result.add(newNotationResource);
}
}
}
handleFragmentStereotypes(umlResource, fragmentUMLResources);
for (Resource resource : result) {
if (resource instanceof XMIResource) {
configureResource((XMIResource) resource);
}
}
return result;
}
/*
* Bug 447097: [Model Import] Importing a fragmented model causes stereotype applications to be lost in resulting submodel
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=447097
*
* Before the transformation, We moved all root elements from the fragment resources to the main
* resource, then we transformed some of them to Papyrus Stereotype Applications. We need to move
* these stereotype applications back to the proper fragment resource
*/
protected void handleFragmentStereotypes(Resource mainUMLResource, List<Resource> umlResources) {
Iterator<EObject> rootElementIterator = mainUMLResource.getContents().iterator();
while (rootElementIterator.hasNext()) {
EObject rootElement = rootElementIterator.next();
if (rootElement instanceof Element) {
continue;
}
Resource targetStereotypeResource = getTargetStereotypeResource(rootElement, umlResources);
if (targetStereotypeResource != null && targetStereotypeResource != mainUMLResource) {
rootElementIterator.remove(); // To avoid ConcurrentModificationException when moving to the other resource
targetStereotypeResource.getContents().add(rootElement);
}
}
}
protected Resource getTargetStereotypeResource(EObject rootElement, List<Resource> umlResources) {
for (EReference eReference : rootElement.eClass().getEAllReferences()) {
if (eReference.getName().startsWith(Extension.METACLASS_ROLE_PREFIX)) {
Object value = rootElement.eGet(eReference);
if (value instanceof Element) {
return ((Element) value).eResource();
}
}
}
return null;
}
protected void deleteSourceStereotypes(Collection<Resource> fragmentResources) {
Set<Resource> allResources = new HashSet<>(fragmentResources);
allResources.add(umlResource);
for (Resource resource : allResources) {
// For performance reasons, RSA RT Stereotypes have not been deleted during the QVTo transformation (Bug 444379)
// Delete them as a post-action. Iterate on all controlled models and delete the RealTime stereotypes at the root of each resource
List<EObject> resourceContents = new LinkedList<>(resource.getContents());
for (EObject rootElement : resourceContents) {
if (sourceEPackages.contains(rootElement.eClass().getEPackage())) {
delete(rootElement);
}
}
}
}
protected abstract URI convertToPapyrus(URI rsaURI, String extension);
/**
* Runs a transformation using the context shared by all transformations.
*
* @param transformationURI
* the transformation to run
* @param extents
* the extents on which to apply the transformation
* @param monitor
* progress monitor
*
* @return the result of the transformation execution
*/
public IStatus runTransformation(URI transformationURI, List<ModelExtent> extents, IProgressMonitor monitor) {
return runTransformation(transformationURI, context, monitor, extents);
}
protected IStatus runTransformation(URI transformationURI, ExecutionContext context, IProgressMonitor monitor, List<ModelExtent> extents) {
if (monitor.isCanceled()) {
return new Status(IStatus.CANCEL, Activator.PLUGIN_ID, "Operation canceled");
}
TransformationExecutor executor;
try {
executor = getTransformation(transformationURI, monitor);
} catch (DiagnosticException ex) {
Diagnostic diagnostic = ex.getDiagnostic();
Activator.log.warn(String.format("Cannot load the transformation : %s. Diagnostic: %s", transformationURI, diagnostic.getMessage()));
return createStatusFromDiagnostic(diagnostic);
}
ExecutionDiagnostic result;
synchronized (executor) {
try {
// Gather the new execution traces
Trace newTraces = Trace.createEmptyTrace();
@SuppressWarnings("restriction")
ISessionData.SimpleEntry<Trace> traceKey = org.eclipse.m2m.internal.qvt.oml.evaluator.QVTEvaluationOptions.INCREMENTAL_UPDATE_TRACE;
context.getSessionData().setValue(traceKey, newTraces);
result = executor.execute(context, extents.toArray(new ModelExtent[0]));
// Append to our history
List<EObject> history = new ArrayList<>(trace.getTraceContent());
history.addAll(newTraces.getTraceContent());
trace.setTraceContent(history);
} finally {
executor.cleanup();
executorsPool.releaseExecutor(executor);
}
}
return createStatusFromDiagnostic(result);
}
protected ExecutionContext createExecutionContext(final IProgressMonitor monitor, final MultiStatus generationStatus) {
ExecutionContextImpl context = new ExecutionContextImpl();
context.setConfigProperty("keepModeling", true); //$NON-NLS-1$ o
context.setConfigProperty(TransformationUI.MONITOR, monitor);
// context.setProgressMonitor(monitor);
context.setLog(new WriterLog(new OutputStreamWriter(System.out)) {
@Override
public void log(String message) {
super.log(message);
}
@Override
public void log(String message, Object param) {
super.log(message, param);
}
@Override
public void log(int level, String message) {
super.log(level, message);
if (level >= 1) {
generationStatus.merge(new Status(level, Activator.PLUGIN_ID, message));
}
}
@Override
public void log(int level, String message, Object param) {
super.log(level, message, param);
if (level >= 1) {
generationStatus.merge(new Status(level, Activator.PLUGIN_ID, message + ", data:" + param));
}
}
});
initTransformationProperties(context);
// Invoke extensions as incremental transformations
context.getSessionData().setValue(TraceHelper.TRACE_HISTORY, trace);
return context;
}
/**
* Initializes the ExecutionContext with configuration properties required by transformations
*
* This is a lightweight mechanism to avoid initializing ModelExtents for a single EObject reference, or for non-EMF values
*
* Typically used by blackbox methods
*
* @param context
*/
protected abstract void initTransformationProperties(ExecutionContextImpl context);
protected void configureResource(XMIResource resource) {
Map<Object, Object> saveOptions = new HashMap<>();
// default save options.
saveOptions.put(XMLResource.OPTION_DECLARE_XML, Boolean.TRUE);
saveOptions.put(XMLResource.OPTION_PROCESS_DANGLING_HREF, XMLResource.OPTION_PROCESS_DANGLING_HREF_DISCARD);
saveOptions.put(XMLResource.OPTION_SCHEMA_LOCATION, Boolean.TRUE);
saveOptions.put(XMIResource.OPTION_USE_XMI_TYPE, Boolean.TRUE);
saveOptions.put(XMLResource.OPTION_SAVE_TYPE_INFORMATION, Boolean.TRUE);
saveOptions.put(XMLResource.OPTION_SKIP_ESCAPE_URI, Boolean.FALSE);
saveOptions.put(XMLResource.OPTION_ENCODING, "UTF-8");
// see bug 397987: [Core][Save] The referenced plugin models are saved using relative path
saveOptions.put(XMLResource.OPTION_URI_HANDLER, new org.eclipse.emf.ecore.xmi.impl.URIHandlerImpl.PlatformSchemeAware());
resource.setEncoding("UTF-8");
resource.getDefaultSaveOptions().putAll(saveOptions);
}
protected abstract List<ModelExtent> getModelExtents();
public abstract ModelExtent getInOutUMLModel();
/* Notation model is initially empty, but will be filled successively by each transformation */
public ModelExtent getInoutNotationModel() {
if (outNotation == null) {
outNotation = new BasicModelExtent();
}
return outNotation;
}
protected ModelExtent getOutSashModel() {
if (outSashModel == null) {
outSashModel = new BasicModelExtent();
}
return outSashModel;
}
protected abstract Collection<URI> getDiagramTransformationURIs();
//TODO : warning, the RSA code will probably be changed and this method will not used for RSA, because it is called after diagrams transformation for RSA.
protected abstract URI getSemanticTransformationURI();
protected abstract Collection<URI> getProfilesTransformationURI();
protected Collection<URI> getAdditionalTransformationURIs() {
return Collections.emptyList();
}
//currently abstract because We probably doesn't apply the transformation in the same order for Rpy than for RSA
protected abstract Collection<URI> getAllTransformationURIs();
protected URI getTransformationURI(String transformationName, String pluginID) {
return URI.createPlatformPluginURI(String.format("%s/transform/%s.qvto", pluginID, transformationName), true); //$NON-NLS-1$
}
public String getModelName() {
return URI.decode(sourceURI.lastSegment());
}
public void cancel() {
job.cancel();
}
/** Lightweight delete operation, which only removes the object from its parent. Incoming references are not deleted */
public void delete(EObject elementToDelete) {
CacheAdapter adapter = CacheAdapter.getCacheAdapter(elementToDelete);
if (adapter == null) {
adapter = CacheAdapter.getInstance();
}
adapter.unsetTarget(elementToDelete);
if (elementToDelete.eResource() != null) {
elementToDelete.eResource().getContents().remove(elementToDelete);
}
EObject parent = elementToDelete.eContainer();
if (parent == null) {
return;
}
EReference containmentFeature = elementToDelete.eContainmentFeature();
if (containmentFeature.getUpperBound() == 1) {
parent.eUnset(containmentFeature);
} else {
List<?> values = (List<?>) parent.eGet(containmentFeature);
values.remove(elementToDelete);
}
}
/**
*
* @return
* the trace of the transformation
*/
protected Trace getTrace() {
return this.trace;
}
}