blob: 437320ff3837f342a93dee97a914f21537a49712 [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2013 CEA LIST.
*
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Ansgar Radermacher ansgar.radermacher@cea.fr
*
*****************************************************************************/
package org.eclipse.papyrus.designer.transformation.core.transformations;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.papyrus.designer.deployment.profile.Deployment.DeploymentPlan;
import org.eclipse.papyrus.designer.deployment.tools.DepUtils;
import org.eclipse.papyrus.designer.languages.common.base.TestInfo;
import org.eclipse.papyrus.designer.transformation.base.UIContext;
import org.eclipse.papyrus.designer.transformation.base.utils.CommandSupport;
import org.eclipse.papyrus.designer.transformation.base.utils.ModelManagement;
import org.eclipse.papyrus.designer.transformation.base.utils.TrafoUtils;
import org.eclipse.papyrus.designer.transformation.base.utils.TransformationException;
import org.eclipse.papyrus.designer.transformation.core.Activator;
import org.eclipse.papyrus.designer.transformation.core.EnumService;
import org.eclipse.papyrus.designer.transformation.core.Messages;
import org.eclipse.papyrus.designer.transformation.core.generate.GenerationOptions;
import org.eclipse.papyrus.designer.transformation.core.templates.TemplateInstantiation;
import org.eclipse.papyrus.designer.transformation.core.transformations.LazyCopier.CopyExtResources;
import org.eclipse.papyrus.designer.transformation.core.transformations.filters.FilterLoadReferencedModels;
import org.eclipse.papyrus.designer.transformation.profile.Transformation.M2MTrafoChain;
import org.eclipse.papyrus.uml.tools.utils.PackageUtil;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.uml2.uml.InstanceSpecification;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.PackageableElement;
import org.eclipse.uml2.uml.util.UMLUtil;
/**
* This class executes all transformations during the instantiation of a
* deployment plan or transformation chain.
*/
public class ExecuteTransformationChain {
/**
* Transformations should raise an exception with this reason, if the transformation is abandoned
*/
public static String USER_CANCEL = "abort transformation, canceled by user"; //$NON-NLS-1$
/**
* Constructor
*
* @param rootPackageOrDP
* a package for which we want to execute a transformation. It may be a deployment plan
* @param project
* the project in which to store the transformed (intermediate) model. If null, the project that hosts the current model is used.
*/
public ExecuteTransformationChain(Package rootPackageOrDP, IProject project) {
this.rootPackageOrDP = rootPackageOrDP;
if (project == null) {
String projectName = rootPackageOrDP.eResource().getURI().toString();
this.project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
} else {
this.project = project;
}
}
/**
* Progress monitor of Eclipse.
*/
protected IProgressMonitor monitor = null;
/**
* generation options, currently unused except for REWRITE_SETTINGS (but caller always passes 0)
* It has been used before switching to configurable transformation chains, now
* possibility to have specific options for a certain transformation step would
* be useful.
*/
protected int generationOptions;
/**
* The package for which a transformation should be executed. Could be a deployment plan
*/
protected Package rootPackageOrDP = null;
protected IProject project;
/**
* Execute a transformation chain
*
* @param monitor
* a progress monitor
* @param genOptions
* generation options
*/
public void executeTransformation(IProgressMonitor monitor, int genOptions) {
executeTransformation(null, monitor, genOptions);
}
/**
* Execute a transformation chain
*
* @param chain
* a transformation chain. If null, take transformation chain from model
* @param monitor
* a progress monitor.
* @param genOptions
* select whether to produce an intermediate model only, also
* code, ... @see GenerationOptions
*/
public void executeTransformation(M2MTrafoChain chain, IProgressMonitor monitor, int genOptions) {
try {
this.monitor = monitor;
this.generationOptions = genOptions;
executeTransformation(chain);
} catch (final TransformationException e) {
// unload all resources in case of an exception
ModelManagement.getResourceSet().getResources().clear();
if (e.getMessage() != USER_CANCEL) {
printAndDisplayErrorMessage(e, Messages.InstantiateDepPlan_TransformationException);
}
} catch (final InterruptedException e) {
// do nothing, user interrupted
} finally {
TransformationContext.current = null;
}
}
/**
* Execute a transformation chain.
*
* @param chain
* a transformation chain. If null, the transformation chain is obtained from stereotypes on the model
* @throws Exception
*/
protected void executeTransformation(M2MTrafoChain chain) throws TransformationException, InterruptedException {
ModelManagement intermediateModelManagement = null;
UIContext.monitor = monitor;
UIContext.configureProject = (generationOptions & GenerationOptions.REWRITE_SETTINGS) != 0;
// 1a: create a new model (and applies same profiles / imports)
Model existingModel = rootPackageOrDP.getModel();
TransformationContext tc = new TransformationContext();
TransformationContext.current = tc;
TransformationContext.initialSourceRoot = existingModel;
TransformationContext.initialDeploymentPlan = rootPackageOrDP;
TransformationContext.monitor = monitor;
// TODO - we currently cannot determine the number of steps to execute
monitor.beginTask("execute chain", 50); //$NON-NLS-1$
tc.project = project;
intermediateModelManagement = ModelManagement.createNewModel(existingModel);
TransformationContext.current.mm = intermediateModelManagement;
// get the temporary model
Package intermediateModel = intermediateModelManagement.getModel();
// create a package for global enumerations that are used by xtend code
EnumService.createEnumPackage(intermediateModel);
// create a lazy copier towards the intermediate model
LazyCopier intermediateModelCopier = new LazyCopier(existingModel, intermediateModel, CopyExtResources.ALL, true);
intermediateModelCopier.preCopyListeners.add(FilterLoadReferencedModels.getInstance());
Map<InstanceSpecification, InstanceSpecification> instanceMap = new HashMap<InstanceSpecification, InstanceSpecification>();
if (DepUtils.isDeploymentPlan(rootPackageOrDP)) {
// deployment plan - copy top-level instances
for (InstanceSpecification instance : DepUtils.getInstances(rootPackageOrDP)) {
// InstanceSpecification newInstance = mainModelTrafo.transformInstance(instance, null);
InstanceSpecification newInstance = intermediateModelCopier.getCopy(instance);
checkProgressStatus();
TransformationUtil.propagateAllocation(newInstance);
instanceMap.put(instance, newInstance);
}
} else {
// no deployment plan - copy all packaged elements
intermediateModelCopier.shallowCopy(rootPackageOrDP);
for (PackageableElement pe : rootPackageOrDP.getPackagedElements()) {
intermediateModelCopier.getCopy(pe);
checkProgressStatus();
}
}
if (monitor.isCanceled()) {
throw new TransformationException(USER_CANCEL);
}
tc.copier = intermediateModelCopier;
tc.deploymentPlan = intermediateModelCopier.getCopy(rootPackageOrDP);
tc.modelRoot = PackageUtil.getRootPackage(tc.deploymentPlan);
if (chain == null) {
chain = TrafoUtils.getTransformationChain(tc.deploymentPlan);
}
TemplateInstantiation.init();
ExecuteChainUtil.apply(chain, TrafoUtils.getAdditionalTransformations(rootPackageOrDP));
// --------------------------------------------------------------------
checkProgressStatus();
// --------------------------------------------------------------------
intermediateModelManagement.dispose();
// also dispose additional models
for (ModelManagement mm : tc.copier.getAdditionalRootPkgs()) {
mm.dispose();
}
}
/**
*
* @param canonicalProjectName
* the automatically calculated project name
* @param userProjectName
* the project name chosen by the user
*/
public void updateProjectMapping(final String canonicalProjectName, final String userProjectName) {
CommandSupport.exec(rootPackageOrDP, "Update project mapping", new Runnable() { //$NON-NLS-1$
@Override
public void run() {
DeploymentPlan depPlan = UMLUtil.getStereotypeApplication(rootPackageOrDP, DeploymentPlan.class);
String mapName = canonicalProjectName + "=" + userProjectName; //$NON-NLS-1$
for (String mapping : depPlan.getProjectMappings()) {
if (mapping.startsWith(canonicalProjectName)) {
mapping = mapName;
return;
}
}
depPlan.getProjectMappings().add(mapName);
}
});
}
private void checkProgressStatus() throws InterruptedException {
if (monitor.isCanceled()) {
throw new InterruptedException();
}
monitor.worked(1);
}
private void printAndDisplayErrorMessage(Exception e, final String title) {
String message = e.toString();
e.printStackTrace();
// only display message, if not running headless
if (!TestInfo.runsHeadless()) {
displayError(title, message);
}
Activator.log.error(e);
}
private void displayError(final String title, final String message) {
Display.getDefault().syncExec(new Runnable() {
@Override
public void run() {
Shell shell = Display.getCurrent().getActiveShell();
MessageDialog.openInformation(shell, title, message);
}
});
}
}