| /***************************************************************************** |
| * 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); |
| } |
| }); |
| } |
| } |