blob: bdc4b2bb0fff57730de802da97d4bc29edc05d1c [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2014, 2017 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, 505330
*
*****************************************************************************/
package org.eclipse.papyrus.interoperability.rsa.transformation;
import java.io.IOException;
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.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
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.SubMonitor;
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.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.transaction.RollbackException;
import org.eclipse.emf.transaction.Transaction;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
import org.eclipse.gmf.runtime.notation.DecorationNode;
import org.eclipse.gmf.runtime.notation.NotationFactory;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.runtime.notation.StringValueStyle;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.m2m.qvt.oml.ExecutionContext;
import org.eclipse.m2m.qvt.oml.util.Trace;
import org.eclipse.papyrus.infra.core.resource.IEMFModel;
import org.eclipse.papyrus.infra.core.resource.IModel;
import org.eclipse.papyrus.infra.core.resource.ModelMultiException;
import org.eclipse.papyrus.infra.core.resource.ModelSet;
import org.eclipse.papyrus.infra.emf.resource.DependencyManagementHelper;
import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import org.eclipse.papyrus.infra.tools.util.StringHelper;
import org.eclipse.papyrus.interoperability.rsa.Activator;
import org.eclipse.papyrus.interoperability.rsa.RSAToPapyrusParameters.Config;
import org.eclipse.papyrus.interoperability.rsa.RSAToPapyrusParameters.MappingParameters;
import org.eclipse.papyrus.interoperability.rsa.RSAToPapyrusParameters.URIMapping;
import org.eclipse.papyrus.interoperability.rsa.concurrent.ResourceAccessHelper;
import org.eclipse.papyrus.interoperability.rsa.internal.extension.PostProcessExtension;
import org.eclipse.papyrus.interoperability.rsa.internal.schedule.JobWrapper;
import org.eclipse.papyrus.interoperability.rsa.internal.schedule.Schedulable;
import org.eclipse.papyrus.interoperability.rsa.internal.schedule.Scheduler;
import org.eclipse.papyrus.interoperability.rsa.internal.schedule.TransformationWrapper;
import org.eclipse.papyrus.interoperability.rsa.transformation.ImportTransformation.ExtensionFunction;
import org.eclipse.papyrus.interoperability.rsa.transformation.ui.URIMappingDialog;
import org.eclipse.papyrus.uml.m2m.qvto.common.utils.TraceHelper;
import org.eclipse.papyrus.uml.tools.model.UmlModel;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleManager;
import org.eclipse.ui.console.MessageConsole;
import org.eclipse.ui.console.MessageConsoleStream;
import org.eclipse.ui.dialogs.SelectionDialog;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Profile;
import org.eclipse.uml2.uml.ProfileApplication;
import org.eclipse.uml2.uml.Stereotype;
/**
* Executes a batch of {@link ImportTransformation}s, then restores the dependencies (References)
* between each other
*
* @author Camille Letavernier
*
*/
public class ImportTransformationLauncher {
// Nano to Second
protected final static long SECOND = 1000 * 1000 * 1000;
// Nano to Milliseconds
protected final static long MILLIS = 1000 * 1000;
protected final Config config;
protected final Control baseControl;
/**
* Own execution time, in nano-seconds. Doesn't take individual transformation's exec
* time into account. Also ignores the time when Blocking user Dialogs are opened
*/
protected long ownExecutionTime;
/**
* Own loading time (For initial model loading)
*/
protected long ownLoadingTime;
/**
* Own cumulated execution time for repairing stereotypes
*/
protected long ownRepairStereotypesTime;
/**
* Own cumulated execution time for post-processing extensions
*/
protected long ownPostProcessingTime;
/**
* Own cumulated execution time for repairing libraries
*/
protected long ownRepairLibrariesTime;
/**
* Own execution time for resolving all matches for broken profiles/libraries
*/
protected long resolveAllDependencies;
/**
* The top-level job for this transformation
*/
protected Job importDependenciesJob;
/**
* Total time for all invidivual transformations to complete. Since they are executed in parallel,
* this may be different from their cumulated execution time (Unless a single thread is used)
*/
protected long transformationsExecutionTime = 0L;
protected DependencyAnalysisHelper analysisHelper;
public ImportTransformationLauncher(Config config) {
this(config, null);
}
public ImportTransformationLauncher(Config config, Control baseControl) {
this.config = config;
this.baseControl = baseControl;
}
/**
* Executes the transformation (Asynchronous)
*
* @param urisToImport
*/
public void run(List<URI> urisToImport) {
List<ImportTransformation> transformations = new LinkedList<ImportTransformation>();
analysisHelper = new DependencyAnalysisHelper(config);
for (URI uri : urisToImport) {
ImportTransformation transformation = createTransformation(uri);
transformations.add(transformation);
}
// Always use the batch launcher, even if there is only 1 transformation (Bug 455012)
importModels(transformations);
}
protected ImportTransformation createTransformation(URI transformationURI) {
return new ImportTransformation(transformationURI, config, analysisHelper);
}
/**
* Start a Job and delegate to {@link #importModels(IProgressMonitor, List)}
*
* @param transformations
*/
protected void importModels(final List<ImportTransformation> transformations) {
importDependenciesJob = new Job("Import Models") {
@Override
protected IStatus run(IProgressMonitor monitor) {
IStatus result = ImportTransformationLauncher.this.importModels(monitor, transformations);
if (monitor.isCanceled()) {
return new Status(IStatus.CANCEL, Activator.PLUGIN_ID, "Operation Canceled");
}
long cumulatedLoadingTime = 0L;
long cumulatedTransformationTime = 0L;
long cumulatedHandleDanglingTime = 0L;
long cumulatedImportExtensionsTime = 0L;
for (ImportTransformation transformation : transformations) {
cumulatedLoadingTime += transformation.getLoadingTime();
cumulatedImportExtensionsTime += transformation.getImportExtensionsTime();
cumulatedHandleDanglingTime += transformation.getHandleDanglingRefTime();
cumulatedTransformationTime += transformation.getExecutionTime();
log("Import " + transformation.getModelName());
log("First phase (0-50%):");
log("\tTotal loading time: " + timeFormat(transformation.getLoadingTime()));
log("\tTotal Import Extensions time: " + timeFormat(transformation.getImportExtensionsTime()));
log("\tTotal Handle Dangling References time: " + timeFormat(transformation.getHandleDanglingRefTime()));
log("\tTotal execution time: " + timeFormat(transformation.getExecutionTime()));
Long loadingTime = loadingTimeV2.get(transformation);
Long repairProxiesTime = proxiesTime.get(transformation);
Long repairStereoTime = stereoTime.get(transformation);
Long postTime = postProcessTime.get(transformation);
Long totalPhase2 = totalTimeV2.get(transformation);
log("Second phase (50-100%):");
log("\tTotal loading time: " + timeFormat(loadingTime));
log("\tTotal fix proxies time: " + timeFormat(repairProxiesTime));
log("\tTotal fix stereotypes time: " + timeFormat(repairStereoTime));
log("\tTotal post-processing time: " + timeFormat(postTime));
log("\tTotal execution time: " + timeFormat(totalPhase2));
log("Total");
log("\tTotal execution time: " + timeFormat(transformation.getExecutionTime() + totalPhase2));
log("\n");
}
int nbThreads = Math.max(1, config.getMaxThreads());
log("First phase (0-50%) / " + nbThreads + " Threads");
log("\tCumulated Transformation Time: " + timeFormat(cumulatedTransformationTime));
log("\tCumulated Loading Time: " + timeFormat(cumulatedLoadingTime));
log("\tCumulated Handle Dangling Refs Time: " + timeFormat(cumulatedHandleDanglingTime));
log("\tCumulated Import Extensions Time: " + timeFormat(cumulatedImportExtensionsTime));
log("\tTotal Transformation Time: " + timeFormat(transformationsExecutionTime));
log("Second phase (50-100%) / " + nbThreads + " Threads");
log("\tTotal Handle all Dangling References: " + timeFormat(resolveAllDependencies));
log("\tCumulated Loading Time: " + timeFormat(ownLoadingTime));
log("\tCumulated Fix Libraries Time: " + timeFormat(ownRepairLibrariesTime));
log("\tCumulated Fix Stereotypes Time: " + timeFormat(ownRepairStereotypesTime));
log("\tCumulated Post-processing Time: " + timeFormat(ownPostProcessingTime));
log("\tTotal Fix Dependencies Time: " + timeFormat(ownExecutionTime));
log("Total");
log("\tCumulated Total time: " + timeFormat(ownExecutionTime + cumulatedTransformationTime));
log("\tTotal time: " + timeFormat(ownExecutionTime + transformationsExecutionTime));
log("Import Complete");
log("");
return result;
}
};
importDependenciesJob.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
MultiStatus multiStatus = new MultiStatus(Activator.PLUGIN_ID, IStatus.OK, "", null);
multiStatus.merge(event.getResult());
for (ImportTransformation transformation : transformations) {
multiStatus.merge(transformation.getStatus());
}
int severity = multiStatus.getSeverity();
String message;
switch (severity) {
case IStatus.OK:
message = "The selected models have been successfully imported";
break;
case IStatus.CANCEL:
message = "Operation canceled";
break;
case IStatus.WARNING:
message = "The selected models have been imported; some warnings have been reported";
break;
default:
message = "Some errors occurred during model import";
break;
}
handle(new MultiStatus(Activator.PLUGIN_ID, severity, multiStatus.getChildren(), message, null));
}
protected void handle(final IStatus status) {
if (baseControl == null) {
int severity = status.getSeverity();
if (severity == IStatus.OK || severity == IStatus.CANCEL) {
return;
}
StatusManager.getManager().handle(status, StatusManager.LOG);
return;
}
Display display = baseControl.getDisplay();
if (status.getSeverity() == IStatus.OK) {
display.asyncExec(new Runnable() {
@Override
public void run() {
MessageDialog.openInformation(baseControl.getShell(), "Import models", status.getMessage());
}
});
} else if (status.getSeverity() == IStatus.CANCEL) {
display.asyncExec(new Runnable() {
@Override
public void run() {
MessageDialog.openInformation(baseControl.getShell(), "Import models", status.getMessage());
}
});
} else {
StatusManager.getManager().handle(status, StatusManager.BLOCK);
}
}
});
importDependenciesJob.setUser(true);
importDependenciesJob.schedule();
}
protected void log(String message) {
System.out.println(message);
MessageConsole console = getConsole();
MessageConsoleStream out = console.newMessageStream();
out.println(message);
}
protected static final String CONSOLE_NAME = "Model Import Results"; // The name is both the ID and the Label
protected MessageConsole getConsole() {
ConsolePlugin plugin = ConsolePlugin.getDefault();
IConsoleManager consoleManager = plugin.getConsoleManager();
IConsole[] existing = consoleManager.getConsoles();
for (int i = 0; i < existing.length; i++) {
if (CONSOLE_NAME.equals(existing[i].getName())) {
return (MessageConsole) existing[i];
}
}
// no console found, so create a new one
MessageConsole rsaConsole = new MessageConsole(CONSOLE_NAME, null);
consoleManager.addConsoles(new IConsole[] { rsaConsole });
return rsaConsole;
}
protected String timeFormat(Long nano) {
if (nano == null) {
return "?"; // FIXME: crash?
}
long seconds = nano / SECOND;
if (seconds < 1) {
long millis = nano / MILLIS;
return String.format("%s ms", millis);
}
return String.format("%d:%02d:%02d", seconds / 3600, (seconds % 3600) / 60, (seconds % 60));
}
/**
* Schedules all the individual transformations, wait for completion, then
* call {@link #handleModelDependencies(List, IProgressMonitor)}
*
* @param monitor
* @param transformations
* @return
*/
protected IStatus importModels(IProgressMonitor monitor, List<ImportTransformation> transformations) {
long begin = System.nanoTime();
monitor.setTaskName("Waiting for import tasks to complete...");
int numTasks = transformations.size() * 2; // For each transformation: wait for completion, then handle dependencies
monitor.beginTask("Importing Models...", numTasks);
List<Schedulable> tasks = new LinkedList<Schedulable>();
for (ImportTransformation transformation : transformations) {
tasks.add(new TransformationWrapper(transformation));
}
Scheduler scheduler = new Scheduler(config.getMaxThreads());
scheduler.schedule(monitor, tasks);
long end = System.nanoTime();
transformationsExecutionTime = end - begin;
if (monitor.isCanceled()) {
return new Status(IStatus.CANCEL, Activator.PLUGIN_ID, "Operation canceled");
}
handleModelDependencies(transformations, monitor);
return Status.OK_STATUS;
}
/**
* Convert all model dependencies (For "imported model -> emx library" to "imported model -> imported library")
* Also repairs profile and stereotype applications
*
* @param transformations
* @param monitor
*/
protected void handleModelDependencies(List<ImportTransformation> transformations, IProgressMonitor monitor) {
long begin = System.nanoTime();
long timeToIgnore = 0L;
final Map<URI, URI> urisToReplace = new HashMap<URI, URI>();
final Map<URI, URI> profileUrisToReplace = new HashMap<URI, URI>();
for (ImportTransformation transformation : transformations) {
urisToReplace.putAll(transformation.getURIMappings());
profileUrisToReplace.putAll(transformation.getProfileURIMappings());
}
monitor.subTask("Analysing unresolved references...");
long startResolveAll = System.nanoTime();
analysisHelper.resolveAllMappings(urisToReplace, profileUrisToReplace);
long endResolveAll = System.nanoTime();
resolveAllDependencies = endResolveAll - startResolveAll;
if (!config.getMappingParameters().getUriMappings().isEmpty() || !config.getMappingParameters().getProfileUriMappings().isEmpty()) {
long beginDialog = System.nanoTime();
MappingParameters parameters = confirmURIMappings(config.getMappingParameters());
long endDialog = System.nanoTime();
timeToIgnore = endDialog - beginDialog;
config.setMappingParameters(parameters);
// Include the user-defined URI mappings
populateURIMap(parameters.getUriMappings(), urisToReplace);
populateURIMap(parameters.getUriMappings(), profileUrisToReplace);
populateURIMap(parameters.getProfileUriMappings(), profileUrisToReplace);
}
removeEmptyMappings(urisToReplace);
List<Schedulable> tasks = new LinkedList<Schedulable>();
for (final ImportTransformation transformation : transformations) {
Job transformationJob = new Job("Importing dependencies for " + transformation.getModelName()) {
@Override
protected IStatus run(IProgressMonitor monitor) {
long startFix = System.nanoTime();
IStatus fixStatus = fixDependencies(transformation, monitor, urisToReplace, profileUrisToReplace);
long endFix = System.nanoTime();
synchronized (ImportTransformationLauncher.this) {
totalTimeV2.put(transformation, endFix - startFix);
}
return fixStatus;
}
};
tasks.add(new JobWrapper(transformationJob));
}
Scheduler scheduler = new Scheduler(config.getMaxThreads());
scheduler.schedule(monitor, tasks);
long end = System.nanoTime();
ownExecutionTime = end - begin - timeToIgnore;
}
protected void removeEmptyMappings(Map<URI, URI> urisToReplace) {
Iterator<Map.Entry<URI, URI>> iterator = urisToReplace.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<URI, URI> entry = iterator.next();
if (entry.getKey().equals(entry.getValue())) {
iterator.remove();
}
}
}
final protected Map<ImportTransformation, Long> loadingTimeV2 = new HashMap<ImportTransformation, Long>();
final protected Map<ImportTransformation, Long> proxiesTime = new HashMap<ImportTransformation, Long>();
final protected Map<ImportTransformation, Long> stereoTime = new HashMap<ImportTransformation, Long>();
final protected Map<ImportTransformation, Long> postProcessTime = new HashMap<ImportTransformation, Long>();
final protected Map<ImportTransformation, Long> totalTimeV2 = new HashMap<ImportTransformation, Long>();
protected IStatus fixDependencies(ImportTransformation transformation, IProgressMonitor monitor, Map<URI, URI> urisToReplace, Map<URI, URI> profileUrisToReplace) {
monitor.subTask("Importing dependencies for " + transformation.getModelName());
final MigrationModelSet modelSet = new MigrationModelSet();
final Collection<Resource> resourcesToRepair;
try {
URI targetURI = transformation.getTargetURI();
if (targetURI == null) {
// The transformation didn't complete properly
monitor.worked(1);
return Status.OK_STATUS;
}
long startLoading = System.nanoTime();
modelSet.loadModels(transformation.getTargetURI());
resourcesToRepair = resolveOwnResources(modelSet);
long endLoading = System.nanoTime();
synchronized (ImportTransformationLauncher.this) {
ownLoadingTime += endLoading - startLoading;
loadingTimeV2.put(transformation, endLoading - startLoading);
}
} catch (ModelMultiException e) {
Activator.log.error(e);
monitor.worked(1);
return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "An exception occurred when repairing library dependencies", e);
}
try {
long startProxies = System.nanoTime();
modelSet.freeze(); // The repairProxies operation will try to load referenced resources, which we want to avoid (For performances)
try {
repairProxies(modelSet, resourcesToRepair, urisToReplace, monitor); // Repairing proxies first will change the Applied Profiles. This helps repairing stereotypes
} finally {
modelSet.unfreeze();
}
long endProxies = System.nanoTime();
synchronized (ImportTransformationLauncher.this) {
ownRepairLibrariesTime += endProxies - startProxies;
proxiesTime.put(transformation, endProxies - startProxies);
}
} catch (Exception ex) {
Activator.log.error(ex);
return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "An exception occurred when repairing library dependencies", ex);
}
RepairStereotypes repairStereotypesAction = new RepairStereotypes(modelSet, resourcesToRepair, profileUrisToReplace);
try {
long startStereotypes = System.nanoTime();
repairStereotypesAction.execute();
long endStereotypes = System.nanoTime();
synchronized (ImportTransformationLauncher.this) {
ownRepairStereotypesTime += endStereotypes - startStereotypes;
stereoTime.put(transformation, endStereotypes - startStereotypes);
}
} catch (Exception ex) {
Activator.log.error(ex);
return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "An exception occurred when repairing profiles/stereotypes", ex);
}
if (config.isRemoveUnmappedProfilesAndStereotypes()) {
try {
for (final Resource resource : resourcesToRepair) {
final List<EObject> eObjectsToDelete = new LinkedList<EObject>();
TreeIterator<EObject> allContents = resource.getAllContents();
while (allContents.hasNext()) {
EObject next = allContents.next();
if (next.eResource() != resource) {
allContents.prune();
continue;
}
// Delete instances of RSA Stereotypes
URI eClassURI = EcoreUtil.getURI(next.eClass());
if (StringHelper.equals("epx", eClassURI.fileExtension())) {
eObjectsToDelete.add(next);
allContents.prune();
continue;
}
// Delete applications of RSA Profiles
if (next instanceof ProfileApplication) {
ProfileApplication profileApplication = (ProfileApplication) next;
Profile appliedProfile = profileApplication.getAppliedProfile();
if (appliedProfile != null) {
URI profileURI = EcoreUtil.getURI(appliedProfile);
if (StringHelper.equals("epx", profileURI.fileExtension())) {
eObjectsToDelete.add(next);
allContents.prune();
continue;
}
}
}
}
Runnable runnable = new Runnable() {
@Override
public void run() {
for (EObject eObject : eObjectsToDelete) {
EObject parentElement = eObject.eContainer();
if (parentElement == null) {
resource.getContents().remove(eObject);
} else {
EStructuralFeature containingFeature = eObject.eContainingFeature();
EcoreUtil.remove(parentElement, containingFeature, eObject);
}
}
}
};
runFastTransaction(modelSet.getTransactionalEditingDomain(), runnable);
}
} catch (Exception ex) {
Activator.log.error(ex);
return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "An exception occurred when repairing profiles/stereotypes", ex);
}
}
IStatus repairDisplayStatus = repairStereotypeDisplay(modelSet, resourcesToRepair);
if (!repairDisplayStatus.isOK()) {
return repairDisplayStatus;
}
IStatus result = Status.OK_STATUS;
// Post-processing extensions
long postProcessors = transformation.getExtensions().stream()
.filter(PostProcessExtension.class::isInstance)
.count();
if (postProcessors > 0L) {
final TransactionalEditingDomain domain = modelSet.getTransactionalEditingDomain();
String statusMessage = String.format("Post-process %s", transformation.getModelName());
MultiStatus postProcessStatus = new MultiStatus(Activator.PLUGIN_ID, IStatus.OK, statusMessage, null);
long startPostProcessing = System.nanoTime();
try {
runFastTransaction(domain, () -> {
// Re-initialize the transformation for the new resource set
transformation.initResourceSet(transformation.getTargetURI(), modelSet);
ExecutionContext context = transformation.createExecutionContext(
SubMonitor.convert(monitor, 1),
postProcessStatus);
// Cannot increment on previous transformations because they were in a different resource set
context.getSessionData().setValue(TraceHelper.TRACE_HISTORY, Trace.createEmptyTrace());
postProcessStatus.merge(transformation.importExtensions(context, monitor, ExtensionFunction::postProcess));
});
} catch (RollbackException ex) {
Activator.log.error(ex);
} catch (InterruptedException ex) {
Activator.log.error(ex);
} finally {
long endPostProcessing = System.nanoTime();
synchronized (ImportTransformationLauncher.this) {
ownPostProcessingTime += endPostProcessing - startPostProcessing;
postProcessTime.put(transformation, endPostProcessing - startPostProcessing);
}
}
if (postProcessStatus.getSeverity() > IStatus.WARNING) {
return postProcessStatus;
}
result = postProcessStatus;
}
try {
for (Resource resource : resourcesToRepair) {
ResourceAccessHelper.INSTANCE.saveResource(resource, null);
}
monitor.worked(1);
TransactionalEditingDomain domain = modelSet.getTransactionalEditingDomain();
runFastTransaction(domain, () -> EMFHelper.unload(modelSet));
domain.dispose();
} catch (IOException ex) {
Activator.log.error(ex);
} catch (RollbackException ex) {
Activator.log.error(ex);
} catch (InterruptedException ex) {
Activator.log.error(ex);
}
return result;
}
protected IStatus repairStereotypeDisplay(ModelSet modelSet, Collection<Resource> resourcesToRepair) {
Map<View, List<DecorationNode>> nodesToCreate = new HashMap<View, List<DecorationNode>>();
final TransactionalEditingDomain domain = modelSet.getTransactionalEditingDomain();
InternalTransactionalEditingDomain internalDomain = (InternalTransactionalEditingDomain) domain;
Map<String, Object> options = new HashMap<String, Object>();
options.put(Transaction.OPTION_NO_UNDO, true);
options.put(Transaction.OPTION_NO_VALIDATION, true);
options.put(Transaction.OPTION_NO_TRIGGERS, true);
options.put(Transaction.OPTION_UNPROTECTED, true);
List<StringValueStyle> stylesToDelete = new LinkedList<StringValueStyle>();
try {
// We're in a batch environment, with no undo/redo support. Run a vanilla transaction to improve performances
Transaction fastTransaction = internalDomain.startTransaction(false, options);
for (Resource resource : resourcesToRepair) {
if ("notation".equals(resource.getURI().fileExtension())) {
TreeIterator<EObject> contents = resource.getAllContents();
while (contents.hasNext()) {
EObject next = contents.next();
if (next instanceof StringValueStyle) {
StringValueStyle style = (StringValueStyle) next;
if ("stereotypeDisplayBackup".equals(style.getName())) {
stylesToDelete.add(style); // Cannot use iterator.remove(), it is not supported. Store and delete later
continue;
}
}
if (!(next instanceof View)) {
contents.prune();
continue;
}
View content = (View) next;
StringValueStyle stereotypeDisplay = (StringValueStyle) content.getNamedStyle(NotationPackage.eINSTANCE.getStringValueStyle(), "stereotypeDisplayBackup");
if (stereotypeDisplay == null) {
continue;
}
final String value = stereotypeDisplay.getStringValue();
if (value == null) {
continue;
}
switch (value) {
case "None": // Other values not handled yet //$NON-NLS-1$
EObject semanticElement = content.getElement();
if (!(semanticElement instanceof Element)) {
continue;
}
Element umlElement = (Element) semanticElement;
List<Stereotype> stereotypes = umlElement.getAppliedStereotypes();
List<DecorationNode> childNodesToCreate = new LinkedList<DecorationNode>();
nodesToCreate.put(content, childNodesToCreate);
for (Stereotype appliedStereotype : stereotypes) {
DecorationNode stereotypeLabel = NotationFactory.eINSTANCE.createDecorationNode();
stereotypeLabel.setType("StereotypeLabel");
stereotypeLabel.setVisible(false);
StringValueStyle stereotypeStyle = (StringValueStyle) stereotypeLabel.createStyle(NotationPackage.eINSTANCE.getStringValueStyle());
stereotypeStyle.setName("stereotype");
stereotypeStyle.setStringValue(appliedStereotype.getQualifiedName());
stereotypeLabel.setElement(appliedStereotype);
stereotypeLabel.setLayoutConstraint(NotationFactory.eINSTANCE.createBounds());
childNodesToCreate.add(stereotypeLabel);
}
break;
default:
// Not handled
}
}
}
}
for (Entry<View, List<DecorationNode>> toCreate : nodesToCreate.entrySet()) {
View parent = toCreate.getKey();
for (DecorationNode decorationNode : toCreate.getValue()) {
parent.getPersistedChildren().add(decorationNode);
}
}
// Simple delete for performances (These styles don't have any incoming reference other than the containment)
for (StringValueStyle styleToDelete : stylesToDelete) {
EObject container = styleToDelete.eContainer();
EReference feature = styleToDelete.eContainmentFeature();
if (container != null && feature != null) {
if (feature.isMany()) {
List<?> values = (List<?>) container.eGet(feature);
values.remove(styleToDelete);
} else {
container.eUnset(feature);
}
}
}
fastTransaction.commit();
} catch (Exception ex) {
Activator.log.error(ex);
return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "An error occurred while trying to migrate Stereotype Display", ex);
}
return Status.OK_STATUS;
}
protected Collection<Resource> resolveOwnResources(ModelSet modelSet) {
UmlModel umlModel = (UmlModel) modelSet.getModel(UmlModel.MODEL_ID);
if (umlModel == null) {
return Collections.emptySet();
}
// Iterate on the main resource's contents (Including fragments).
// The ModelSet will take care of loading any associated resource (notation, di)
Resource mainResource = umlModel.getResource();
if (mainResource == null) {
return Collections.emptySet();
}
Iterator<EObject> contents = mainResource.getAllContents();
while (contents.hasNext()) {
contents.next();
}
Set<Resource> resourcesToRepair = new HashSet<Resource>();
for (Resource resource : modelSet.getResources()) {
if (isMainModelResource(modelSet, resource)) {
resourcesToRepair.add(resource);
}
}
return resourcesToRepair;
}
/**
* A resource belongs to the main model if it is one of the 4-files model (Di, Notation, Uml, Sash), or if it is
* a resource associated to a Sub-model of the main model (i.e. child of the main UML resource,
* or resource associated to a child of the main UML resource)
*
* @param modelSet
* @param resource
* @return
*/
protected boolean isMainModelResource(ModelSet modelSet, Resource resource) {
IModel model = modelSet.getModelFor(resource);
if (model instanceof IEMFModel) {
IEMFModel logicalModel = (IEMFModel) model;
if (logicalModel.getResource() == resource || logicalModel.isControlled(resource)) {
return true;
}
}
return false;
}
protected void repairProxies(final ModelSet modelSet, final Collection<Resource> resourcesToRepair, final Map<URI, URI> urisToReplace, IProgressMonitor monitor) throws InterruptedException, RollbackException {
final TransactionalEditingDomain domain = modelSet.getTransactionalEditingDomain();
Runnable runnable = new Runnable() {
@Override
public void run() {
DependencyManagementHelper.batchUpdateDependencies(urisToReplace, resourcesToRepair, domain);
}
};
runFastTransaction(domain, runnable);
}
protected static final void runFastTransaction(TransactionalEditingDomain domain, Runnable runnable) throws InterruptedException, RollbackException {
InternalTransactionalEditingDomain internalDomain = (InternalTransactionalEditingDomain) domain;
Map<String, Object> options = new HashMap<String, Object>();
options.put(Transaction.OPTION_NO_UNDO, true);
options.put(Transaction.OPTION_NO_VALIDATION, true);
options.put(Transaction.OPTION_NO_TRIGGERS, true);
options.put(Transaction.OPTION_UNPROTECTED, true);
// We're in a batch environment, with no undo/redo support. Run a vanilla transaction to improve performances
Transaction fastTransaction = internalDomain.startTransaction(false, options);
try {
runnable.run();
} finally {
fastTransaction.commit();
}
}
/**
* Convert and add all the URIMappings into the URI Map
*
* @param mappings
* @param uriMap
*/
protected static void populateURIMap(List<URIMapping> mappings, Map<URI, URI> uriMap) {
for (URIMapping mapping : mappings) {
if (mapping == null) {
continue;
}
String source = mapping.getSourceURI();
String target = mapping.getTargetURI();
if (source != null && target != null && !source.trim().isEmpty() && !target.trim().isEmpty()) {
URI sourceURI = URI.createURI(mapping.getSourceURI());
URI targetURI = URI.createURI(mapping.getTargetURI());
if (uriMap.containsKey(sourceURI)) {
continue;
}
uriMap.put(sourceURI, targetURI);
}
}
}
protected MappingParameters confirmURIMappings(final MappingParameters mappingParameters) {
List<URIMapping> flatMappings = analysisHelper.flattenURIMappings(mappingParameters);
analysisHelper.propagateURIMappings(flatMappings, mappingParameters);
if (config.isAlwaysAcceptSuggestedMappings()) {
return mappingParameters;
}
final AtomicReference<MappingParameters> newParameters = new AtomicReference<MappingParameters>(mappingParameters);
if (baseControl != null && !baseControl.isDisposed()) {
baseControl.getDisplay().syncExec(new Runnable() {
@Override
public void run() {
newParameters.set(openMappingsDialog(mappingParameters));
}
});
}
return newParameters.get();
}
protected MappingParameters openMappingsDialog(final MappingParameters mappingParameters) {
final Shell shell = baseControl.getShell();
SelectionDialog dialog = new URIMappingDialog(shell, mappingParameters, analysisHelper);
dialog.open();
return (MappingParameters) dialog.getResult()[0];
}
/** Mainly for test purpose */
public void waitForCompletion() throws Exception {
importDependenciesJob.join();
}
/** Mainly for test purpose */
public IStatus getResult() {
return importDependenciesJob.getResult();
}
}