Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCamille Letavernier2020-12-02 15:19:54 +0000
committerCamille Letavernier2021-01-04 10:21:42 +0000
commit27e1b411fd43791d5bf82a881730d1a4c2a2e20b (patch)
tree2c78f8604f772fbc7f7ba02faefb9b6cee3d25c9
parentb90053a38e26051e524e9c1aa1c4cd4838d478e0 (diff)
downloadorg.eclipse.papyrus-27e1b411fd43791d5bf82a881730d1a4c2a2e20b.tar.gz
org.eclipse.papyrus-27e1b411fd43791d5bf82a881730d1a4c2a2e20b.tar.xz
org.eclipse.papyrus-27e1b411fd43791d5bf82a881730d1a4c2a2e20b.zip
Bug 569356: [Toolsmiths] Support regeneration of
ElementTypesConfiguration models https://bugs.eclipse.org/bugs/show_bug.cgi?id=569356 - Add some extra parameters to the generator (and corresponding UI) - Compute the differences between a current version of a Profile and a previously generated ElementTypeConfiguration model - Update the generation templates to take this diff into account, when incremental generation is selected - Fix support for nested Packages/Profiles
-rw-r--r--plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorIncrementalBlock.java68
-rw-r--r--plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorMainPage.java11
-rw-r--r--plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorWizard.java28
-rw-r--r--plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorWizardModel.java106
-rw-r--r--plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/META-INF/MANIFEST.MF6
-rw-r--r--plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/AbstractGenerator.java55
-rw-r--r--plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/ConfigurationSetRule.xtend126
-rw-r--r--plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/DeltaStrategy.java151
-rw-r--r--plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/ElementTypeRule.xtend187
-rw-r--r--plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/ElementTypesGenerator.java18
-rw-r--r--plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/GeneratorModule.java22
-rw-r--r--plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/UML.xtend5
-rw-r--r--plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/strategy/ElementTypeConfigHelper.java292
-rw-r--r--plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/strategy/SimpleDeltaStrategy.java105
14 files changed, 1076 insertions, 104 deletions
diff --git a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorIncrementalBlock.java b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorIncrementalBlock.java
new file mode 100644
index 00000000000..72501a803b3
--- /dev/null
+++ b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorIncrementalBlock.java
@@ -0,0 +1,68 @@
+/*****************************************************************************
+ * Copyright (c) 2020 EclipseSource and others.
+ *
+ * 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
+ * http://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Camille Letavernier - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.profile.types.generator.ui.internal.wizards;
+
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+
+/**
+ * Block presenting the incremental generation options.
+ */
+class GeneratorIncrementalBlock {
+
+ private GeneratorWizardModel model;
+
+ public GeneratorIncrementalBlock(GeneratorWizardModel model) {
+ this.model = model;
+ }
+
+ void createControl(Composite parent) {
+
+ Group incrementalGroup = new Group(parent, SWT.NONE);
+ incrementalGroup.setText("Incremental generation");
+ incrementalGroup.setLayout(new GridLayout(1, true));
+ incrementalGroup.setLayoutData(GridDataFactory.fillDefaults().grab(true, false).span(2, 1).create());
+
+ Button isIncremental = new Button(incrementalGroup, SWT.CHECK);
+ isIncremental.setText("Incremental");
+ isIncremental.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ model.setIncremental(isIncremental.getSelection());
+ model.validatePage();
+ }
+ });
+ isIncremental.setSelection(model.isIncremental());
+
+ Button removeDeleted = new Button(incrementalGroup, SWT.CHECK);
+ removeDeleted.setText("Remove Deleted Types");
+ removeDeleted.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ model.setRemoveDeletedTypes(removeDeleted.getSelection());
+ model.validatePage();
+ }
+ });
+ removeDeleted.setSelection(model.isRemoveDeletedTypes());
+ }
+
+}
diff --git a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorMainPage.java b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorMainPage.java
index ead72e4ba21..5187ab2fbb2 100644
--- a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorMainPage.java
+++ b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorMainPage.java
@@ -1,6 +1,6 @@
/*****************************************************************************
- * Copyright (c) 2014, 2015 Christian W. Damus and others.
- *
+ * Copyright (c) 2014, 2015, 2020 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 2.0
* which accompanies this distribution, and is available at
@@ -10,7 +10,8 @@
*
* Contributors:
* Christian W. Damus - Initial API and implementation
- *
+ * Camille Letavernier - Bug 569356 Incremental Generation
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.profile.types.generator.ui.internal.wizards;
@@ -31,6 +32,7 @@ public class GeneratorMainPage extends WizardNewFileCreationPage implements IGen
private GeneratorParametersBlock parametersBlock;
private BaseElementTypeSetBlock diagramBlock;
+ private GeneratorIncrementalBlock incrementalBlock;
public GeneratorMainPage(GeneratorWizardModel model, String title, String description, String fileExtension) {
super("main", model.getDefaultContainerSelection()); //$NON-NLS-1$
@@ -55,7 +57,10 @@ public class GeneratorMainPage extends WizardNewFileCreationPage implements IGen
parametersBlock.createControl(self);
diagramBlock = new BaseElementTypeSetBlock(model);
diagramBlock.createControl(self);
+ incrementalBlock = new GeneratorIncrementalBlock(model);
+ incrementalBlock.createControl(self);
+ // File selection control
super.createControl(self);
getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
diff --git a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorWizard.java b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorWizard.java
index 8a4fe8a0edb..931e9d83796 100644
--- a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorWizard.java
+++ b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorWizard.java
@@ -28,16 +28,24 @@ import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.URI;
+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.resource.impl.ResourceSetImpl;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.jface.dialogs.DialogSettings;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.infra.types.ElementTypeSetConfiguration;
import org.eclipse.papyrus.infra.ui.util.UIUtil;
import org.eclipse.papyrus.toolsmiths.types.generator.TypesPluginGenerator;
import org.eclipse.papyrus.uml.profile.types.generator.AbstractGenerator;
+import org.eclipse.papyrus.uml.profile.types.generator.DeltaStrategy;
+import org.eclipse.papyrus.uml.profile.types.generator.DeltaStrategy.Diff;
import org.eclipse.papyrus.uml.profile.types.generator.ElementTypesGenerator;
import org.eclipse.papyrus.uml.profile.types.generator.Identifiers;
+import org.eclipse.papyrus.uml.profile.types.generator.strategy.SimpleDeltaStrategy;
import org.eclipse.papyrus.uml.profile.types.generator.ui.internal.Activator;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
@@ -124,6 +132,24 @@ public class GeneratorWizard extends Wizard {
IStatus result = Status.OK_STATUS;
Identifiers identifiers = new Identifiers();
+
+ if (model.getOutputModelFile().exists() && model.isIncremental()) {
+ ResourceSet rs = new ResourceSetImpl();
+ Resource resource = rs.getResource(model.getOutputModelURI(), true);
+ EObject root = resource.getContents().get(0);
+ if (root instanceof ElementTypeSetConfiguration) {
+ ElementTypeSetConfiguration typeSet = (ElementTypeSetConfiguration) root;
+ DeltaStrategy strategy = new SimpleDeltaStrategy();
+ Diff diff = strategy.findDiffs(model.getProfile(), typeSet);
+ model.setDiff(diff);
+
+ if (!model.isRemoveDeletedTypes()) {
+ // Ignore deleted stereotypes and simply preserve their corresponding element types
+ diff.getRemovedStereotypes().clear();
+ }
+ }
+ }
+
if (model.isAddDiPostfixActive()) {
identifiers.setPrefix(model.getIdentifier() + Identifiers.diPostfix());
identifiers.setUseDiPostfix(true);
@@ -212,7 +238,7 @@ public class GeneratorWizard extends Wizard {
}
protected void addGenerators(List<? super AbstractGenerator<Profile, ?>> generators, Identifiers identifiers, GeneratorWizardModel wizardModel) {
- generators.add(new ElementTypesGenerator(identifiers));
+ generators.add(new ElementTypesGenerator(identifiers, wizardModel.getDiff()));
}
protected URI getOutputURI(AbstractGenerator<Profile, ?> generator, Identifiers identifiers, GeneratorWizardModel wizardModel) {
diff --git a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorWizardModel.java b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorWizardModel.java
index d62cae2b1b7..04ee6b2caf2 100644
--- a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorWizardModel.java
+++ b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator.ui/src/org/eclipse/papyrus/uml/profile/types/generator/ui/internal/wizards/GeneratorWizardModel.java
@@ -1,6 +1,6 @@
/*****************************************************************************
- * Copyright (c) 2014, 2015 Christian W. Damus and others.
- *
+ * Copyright (c) 2014, 2015, 2020 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 2.0
* which accompanies this distribution, and is available at
@@ -11,6 +11,7 @@
* Contributors:
* Christian W. Damus - Initial API and implementation
* Ansgar Radermacher - Bug 526156, add postfix, if generating DI element types
+ * Camille Letavernier - Bug 569356 Support incremental generation
*
*****************************************************************************/
@@ -29,6 +30,8 @@ import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.wizard.IWizard;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.papyrus.infra.emf.utils.ResourceUtils;
+import org.eclipse.papyrus.infra.types.ElementTypeSetConfiguration;
+import org.eclipse.papyrus.uml.profile.types.generator.DeltaStrategy;
import org.eclipse.uml2.uml.Profile;
/**
@@ -52,9 +55,17 @@ public class GeneratorWizardModel {
private String fileName;
private boolean suppressSemanticSuperElementTypes;
-
+
private boolean addDiPostfix;
+ private boolean incremental = true;
+
+ private boolean generateExtensionPoint = true;
+
+ private boolean removeDeletedTypes = true;
+
+ private DeltaStrategy.Diff diff;
+
public GeneratorWizardModel(IWizard owner, Profile profile, IDialogSettings settings) {
super();
@@ -119,14 +130,16 @@ public class GeneratorWizardModel {
/**
* Control whether a DI postfix should be used
+ *
* @since 1.3.0
*/
public void setAddDiPostfix(boolean addDiPostfix) {
this.addDiPostfix = addDiPostfix;
}
-
+
/**
* Check whether a DI postfix should be used
+ *
* @since 1.3.0
*/
public boolean isAddDiPostfix() {
@@ -140,7 +153,7 @@ public class GeneratorWizardModel {
public boolean isAddDiPostfixActive() {
return addDiPostfix && BaseElementTypeSetBlock.UMLDI_ELEMENT_TYPE_SET.equals(getSelectedElementTypeSet());
}
-
+
public URI getOutputModelURI() {
return URI.createPlatformResourceURI(containerPath.append(fileName).toString(), true);
}
@@ -190,4 +203,87 @@ public class GeneratorWizardModel {
return result;
}
+
+ public DeltaStrategy.Diff getDiff() {
+ return diff;
+ }
+
+ public void setDiff(DeltaStrategy.Diff diff) {
+ this.diff = diff;
+ }
+
+ /**
+ * <p>
+ * Whether this generation should be incremental. This value is ignored
+ * when generating to a file that doesn't exist yet.
+ * </p>
+ * <p>
+ * If the file exists and this value is false, the file will be overwritten.
+ * If the file exists and this value is true, the target {@link ElementTypeSetConfiguration}
+ * will be updated, preserving user modifications (as much as possible).
+ * </p>
+ *
+ * @return the incremental value
+ */
+ public boolean isIncremental() {
+ return incremental;
+ }
+
+ /**
+ * @param incremental
+ * the incremental to set
+ */
+ public void setIncremental(boolean incremental) {
+ this.incremental = incremental;
+ }
+
+ /**
+ * <p>
+ * Whether the generation should populate the org.eclipse.papyrus.infra.types.core.elementTypeSetConfiguration
+ * extension point. This value is ignored if the output file is not located in an Eclipse plug-in.
+ * </p>
+ * <p>
+ * This value should be set to <code>true</code> if the profile is meant to be used with generic Papyrus UML
+ * models, and <code>false</code> if the profile defines its own Architecture Language (i.e. is meant to be
+ * used as a standalone language). If the profile can be used in both cases, then the value should be
+ * <code>true</code>.
+ * </p>
+ *
+ * @return the generateExtensionPoint value
+ */
+ public boolean isGenerateExtensionPoint() {
+ return generateExtensionPoint;
+ }
+
+ /**
+ * @param generateExtensionPoint
+ * the generateExtensionPoint to set
+ */
+ public void setGenerateExtensionPoint(boolean generateExtensionPoint) {
+ this.generateExtensionPoint = generateExtensionPoint;
+ }
+
+ /**
+ * <p>
+ * Whether ElementTypeConfigurations related to Stereotypes that no longer exist should be removed.
+ * This value is ignored when generating to a file that doesn't exist yet.
+ * </p>
+ * <p>
+ * Set this value to <code>true</code> to automatically clean-up deprecated ElementTypeConfigurations;
+ * set <code>false</code> if the user should clean-up manually (e.g. to migrate/fix broken ElementTypeConfigurations)
+ * </p>
+ *
+ * @return the removeDeletedTypes
+ */
+ public boolean isRemoveDeletedTypes() {
+ return removeDeletedTypes;
+ }
+
+ /**
+ * @param removeDeletedTypes
+ * the removeDeletedTypes to set
+ */
+ public void setRemoveDeletedTypes(boolean removeDeletedTypes) {
+ this.removeDeletedTypes = removeDeletedTypes;
+ }
}
diff --git a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/META-INF/MANIFEST.MF b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/META-INF/MANIFEST.MF
index 90f869e55dc..2ea311dc8a7 100644
--- a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/META-INF/MANIFEST.MF
+++ b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/META-INF/MANIFEST.MF
@@ -10,9 +10,11 @@ Require-Bundle: com.google.inject;bundle-version="[3.0.0,4.0.0)",
org.eclipse.papyrus.infra.types.core;bundle-version="[5.0.0,6.0.0)",
org.eclipse.papyrus.uml.types.core;bundle-version="[5.0.0,6.0.0)",
org.eclipse.uml2.uml.editor;bundle-version="[5.5.0,6.0.0)",
- org.eclipse.xtend.lib;bundle-version="[2.22.0,3.0.0)"
+ org.eclipse.xtend.lib;bundle-version="[2.22.0,3.0.0)",
+ org.eclipse.papyrus.uml.tools.utils;bundle-version="[4.0.0,5.0.0)"
Export-Package: org.eclipse.papyrus.uml.profile.types.generator,
- org.eclipse.papyrus.uml.profile.types.generator.internal;x-internal:=true
+ org.eclipse.papyrus.uml.profile.types.generator.internal;x-internal:=true,
+ org.eclipse.papyrus.uml.profile.types.generator.strategy
Bundle-Vendor: %providerName
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/AbstractGenerator.java b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/AbstractGenerator.java
index 7c814e7156d..ce8a331aa76 100644
--- a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/AbstractGenerator.java
+++ b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/AbstractGenerator.java
@@ -1,6 +1,6 @@
/*****************************************************************************
- * Copyright (c) 2014, 2015, 2018 Christian W. Damus and others.
- *
+ * Copyright (c) 2014, 2015, 2018, 2020 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 2.0
* which accompanies this distribution, and is available at
@@ -11,13 +11,15 @@
* Contributors:
* Christian W. Damus - Initial API and implementation
* Ansgar Radermacher - Bug 526155, re-generation from profile: use ID as XML-ID
- *
+ * Camille Letavernier - Bug 569356: support incremental generation
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.profile.types.generator;
import java.io.IOException;
import java.net.URISyntaxException;
+import java.util.Optional;
import java.util.Set;
import org.eclipse.core.resources.IContainer;
@@ -39,6 +41,7 @@ import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import org.eclipse.papyrus.infra.types.ElementTypeConfiguration;
import org.eclipse.papyrus.infra.types.ElementTypeSetConfiguration;
+import org.eclipse.papyrus.uml.profile.types.generator.DeltaStrategy.Diff;
import org.eclipse.papyrus.uml.profile.types.generator.internal.Activator;
import org.eclipse.uml2.common.util.UML2Util;
@@ -50,9 +53,11 @@ import com.google.inject.Injector;
/**
* Scaffolding for an Xtend model-to-model transformation.
- *
- * @param <T>
- * the kind of model element that I generate from a UML profile
+ *
+ * @param <I>
+ * the kind of model element input
+ * @param <O>
+ * the kind of model element that I generate from &lt;I&gt;
*/
public abstract class AbstractGenerator<I extends EObject, O extends EObject> {
@@ -69,8 +74,11 @@ public abstract class AbstractGenerator<I extends EObject, O extends EObject> {
@Inject
private Identifiers identifiers;
- public AbstractGenerator(Identifiers identifiers) {
- this(new GeneratorModule(identifiers));
+ @Inject
+ private Optional<Diff> diff;
+
+ public AbstractGenerator(Identifiers identifiers, DeltaStrategy.Diff diff) {
+ this(new GeneratorModule(identifiers, diff));
}
public AbstractGenerator(GeneratorModule module) {
@@ -102,10 +110,17 @@ public abstract class AbstractGenerator<I extends EObject, O extends EObject> {
public IStatus generate(I input, URI outputURI) {
IStatus result;
- ResourceSet resourceSet = new ResourceSetImpl();
+ final ResourceSet resourceSet = new ResourceSetImpl();
try {
- Resource output = resourceSet.createResource(outputURI);
+ final Resource output;
+ if (diff.isEmpty()) {
+ output = resourceSet.createResource(outputURI);
+ } else {
+ // TODO If Diff is set, we can probably successfully load this resource.
+ // However, adding a few checks wouldn't hurt...
+ output = resourceSet.getResource(outputURI, true);
+ }
result = generate(input, output.getContents());
// use Identifier as XML-ID. This implies that the same XML-ID is used when re-generating
@@ -115,7 +130,7 @@ public abstract class AbstractGenerator<I extends EObject, O extends EObject> {
String elementTypeSetId = elementTypeSet.getIdentifier();
if (elementTypeSetId != null && elementTypeSetId.length() > 0) {
((XMLResource) output).setID(elementTypeSet, escapeID(elementTypeSetId));
- }
+ }
for (ElementTypeConfiguration elemTypeConfig : elementTypeSet.getElementTypeConfigurations()) {
String id = elemTypeConfig.getIdentifier();
if (id != null && id.length() > 0) {
@@ -141,9 +156,10 @@ public abstract class AbstractGenerator<I extends EObject, O extends EObject> {
/**
* Replace problematic characters in identifier with "_", before using it as XML-id
- * in particular, the :: can be used by the generator.
- *
- * @param id an ID
+ * in particular, the :: can be used by the generator.
+ *
+ * @param id
+ * an ID
* @return
* @since 2.1
*/
@@ -156,13 +172,22 @@ public abstract class AbstractGenerator<I extends EObject, O extends EObject> {
public IStatus generate(I input, EList<? super EObject> output) {
IStatus result = Status.OK_STATUS;
- output.add(generate(input));
+ if (output.isEmpty()) {
+ output.add(generate(input));
+ } else {
+ regenerate(input, output);
+ }
return result;
}
protected abstract O generate(I input);
+ protected O regenerate(I input, EList<? super EObject> originalOutput) {
+ // Don't support incremental generation by default.
+ return generate(input);
+ }
+
protected void refreshContainer(URI resourceURI) throws CoreException {
if (resourceURI.isPlatformResource()) {
IContainer container = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(resourceURI.toPlatformString(true))).getParent();
diff --git a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/ConfigurationSetRule.xtend b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/ConfigurationSetRule.xtend
index 965c01e6a6b..aa99f4e97f7 100644
--- a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/ConfigurationSetRule.xtend
+++ b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/ConfigurationSetRule.xtend
@@ -5,7 +5,7 @@
* 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:
@@ -17,18 +17,30 @@
*****************************************************************************/
package org.eclipse.papyrus.uml.profile.types.generator
+import java.util.ArrayList
import java.util.List
+import java.util.Optional
import javax.inject.Inject
import javax.inject.Singleton
-import org.eclipse.papyrus.infra.types.AbstractAdviceBindingConfiguration
+import org.eclipse.emf.common.util.EList
+import org.eclipse.emf.ecore.EObject
import org.eclipse.papyrus.infra.types.ElementTypeConfiguration
import org.eclipse.papyrus.infra.types.ElementTypeSetConfiguration
import org.eclipse.papyrus.infra.types.ElementTypesConfigurationsFactory
+import org.eclipse.papyrus.uml.profile.types.generator.DeltaStrategy.Diff
+import org.eclipse.papyrus.uml.profile.types.generator.DeltaStrategy.DiffImpl
+import org.eclipse.papyrus.uml.profile.types.generator.strategy.ElementTypeConfigHelper
import org.eclipse.uml2.uml.Profile
import org.eclipse.uml2.uml.UMLPackage
/**
+ * <p>
* Transformation rule for generating an {@link ElementTypeSetConfiguration} from a UML {@link Profile}.
+ * </p>
+ * <p>
+ * Supports incremental (re)generation, if an Optional {@link ElementTypeSetConfiguration} and {@link DeltaStrategy.Diff}
+ * are provided.
+ * </p>
*/
@Singleton
class ConfigurationSetRule {
@@ -39,9 +51,10 @@ class ConfigurationSetRule {
@Inject extension UML
@Inject extension UMLElementTypes
@Inject extension ElementTypeRule
+ @Inject extension ElementTypeConfigHelper
+ @Inject Optional<DeltaStrategy.Diff> diff;
static var List<ElementTypeConfiguration> elementTypeConfigurationList
- var List<AbstractAdviceBindingConfiguration> adviceBindingConfigurationList
static def addElementType(ElementTypeConfiguration elementtype) {
var found = elementTypeConfigurationList.findFirst[el|el.identifier.equals(elementtype.identifier)]
@@ -51,36 +64,113 @@ class ConfigurationSetRule {
} else {
return found
}
+ }
+ /**
+ * <p>
+ * Create or (incrementally) regenerate an ElementTypeSetConfiguration, and populate
+ * it with ElementTypeConfigurations, from the given umlProfile.
+ * </p>
+ *
+ * @param umlProfile
+ * The source profile used to generate the ElementTypeSetConfiguration
+ * @param originalOutput
+ * The contents EList from the existing ElementTypeSetConfiguration, or null if we are generating a new Config.
+ */
+ def ElementTypeSetConfiguration toConfigurationSet(Profile umlProfile, EList<? super EObject> originalOutput) {
+ if (originalOutput != null && ! originalOutput.empty) {
+ if (! diff.isEmpty()) {
+ val typeSet = originalOutput.
+ findFirst[it instanceof ElementTypeSetConfiguration] as ElementTypeSetConfiguration;
+ updateElementTypeSet(umlProfile, typeSet, diff.get());
+ return typeSet;
+ }
+ return null;
+ } else {
+ return newConfigurationSet(umlProfile);
+ }
}
- def create createElementTypeSetConfiguration toConfigurationSet(Profile umlProfile) {
+ /**
+ * <p>
+ * Create a new ElementTypeSetConfiguration and populate it with generated ElementTypeConfigurations,
+ * from the given umlProfile.
+ * </p>
+ */
+ def create createElementTypeSetConfiguration newConfigurationSet(Profile umlProfile) {
- elementTypeConfigurationList = newArrayList()
- adviceBindingConfigurationList = newArrayList()
+ val newDiff = new DiffImpl();
+ newDiff.addedStereotypes.addAll(umlProfile.allStereotypes);
+
+ updateElementTypeSet(umlProfile, it, newDiff);
+ }
+
+ def updateElementTypeSet(Profile umlProfile, ElementTypeSetConfiguration typeSet, Diff diff) {
+ val helper = new ElementTypeConfigHelper();
+
+ elementTypeConfigurationList = newArrayList()
+
// Initialize the generation of IDs
umlProfile.setIdentifierBase
- identifier = "elementTypes".qualified
- metamodelNsURI = baseUMLElementTypeSet?.metamodelNsURI ?: UMLPackage.eNS_URI;
+ typeSet => [
+ identifier = "elementTypes".qualified;
+ metamodelNsURI = baseUMLElementTypeSet?.metamodelNsURI ?: UMLPackage.eNS_URI;
+ ]
+
+ for (addedStereotype : diff.addedStereotypes) {
+ for (ext : addedStereotype.impliedExtensions) {
+ for (element : ext.metaclass.diagramSpecificElementTypes) {
+ val elementtype = ext.toElementType(element)
+ elementTypeConfigurationList.add(elementtype);
+ }
+ }
+ }
- for (ext : umlProfile.allExtensions) {
+ diff.removedStereotypes.forEach [
+ if (it == null || it.empty) {
+ return;
+ }
+ // One stereotype may correspond to multiple element types. Remove all of them.
+ new ArrayList(typeSet.elementTypeConfigurations).forEach[typeConfig |
+ if (typeConfig.stereotypeName == it) {
+ typeSet.elementTypeConfigurations.remove(typeConfig);
+ }
+ ]
+ ]
+
+ for (entry : diff.renamedStereotypes.entrySet) {
+ val oldName = entry.key;
+ val stereotype = entry.value;
+
+ // TODO: Should we manipulate Extensions rather than Stereotypes?
+ typeSet.elementTypeConfigurations
+ .filter(type | helper.getStereotypeName(type) == oldName)
+ .forEach(type | type.setStereotypeName(stereotype));
+
+ // TODO Edit corresponding ElementTypeConfigurations (Change ID, StereotypeQName)
+ }
+
+ for (ext : diff.addedExtensions) {
for (element : ext.metaclass.diagramSpecificElementTypes) {
val elementtype = ext.toElementType(element)
elementTypeConfigurationList.add(elementtype);
}
}
+
+ // Remove all elementTypeConfigurations that correspond to one of the removed extensions
+ typeSet.elementTypeConfigurations.removeIf[type | diff.removedExtensions.contains(type.getExtension(umlProfile))]
- adviceBindingsConfigurations.addAll(adviceBindingConfigurationList.sortBy[identifier])
- elementTypeConfigurations.addAll(elementTypeConfigurationList.sortBy[identifier])
+ typeSet => [
+ // set name (otherwise, the element type set remains invalid)
+ if (useDiPostfix()) {
+ name = umlProfile.name + " DI"
+ } else {
+ name = umlProfile.name
+ }
- // set name (otherwise, the element type set remains invalid)
- if (useDiPostfix()) {
- name = umlProfile.name + " DI"
- }
- else {
- name = umlProfile.name
- }
+ elementTypeConfigurations.addAll(elementTypeConfigurationList.sortBy[identifier])
+ ]
}
}
diff --git a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/DeltaStrategy.java b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/DeltaStrategy.java
new file mode 100644
index 00000000000..1709dcb32de
--- /dev/null
+++ b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/DeltaStrategy.java
@@ -0,0 +1,151 @@
+/*****************************************************************************
+ * Copyright (c) 2020 EclipseSource and others.
+ *
+ * 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
+ * http://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * EclipseSource - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.uml.profile.types.generator;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.eclipse.papyrus.infra.types.ElementTypeSetConfiguration;
+import org.eclipse.uml2.uml.Extension;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.Stereotype;
+
+/**
+ * <p>
+ * A (simple) strategy to determine the changes in a Profile since a previous version,
+ * used for incremental updates of an {@link ElementTypeSetConfiguration}.
+ * </p>
+ * <p>
+ * The differences are limited to Added/Removed/Renamed {@link Stereotype Stereotypes},
+ * as well as Stereotypes with Added/Removed {@link Extension Extensions}.
+ * </p>
+ */
+public interface DeltaStrategy {
+
+ Diff findDiffs(Profile currentProfile, ElementTypeSetConfiguration previousTypes);
+
+ /**
+ * Represents the difference (in terms of Added/Removed/Renamed Stereotypes)
+ * between a current Profile and an {@link ElementTypeSetConfiguration} that
+ * has been generated from this Profile.
+ */
+ interface Diff {
+ /**
+ * @return
+ * The list of removed stereotypes, identified by Qualified Name.
+ */
+ List<String> getRemovedStereotypes();
+
+ /**
+ * @return
+ * The list of removed extensions, when the Stereotype still exists (i.e.
+ * if the stereotype was deleted, use {@link #getRemovedStereotypes()} instead)
+ */
+ List<ImpliedExtension> getRemovedExtensions();
+
+ /**
+ * @return
+ * The list of renamed stereotypes, identified by Qualified Name.
+ * Each map entry represents the old name as the key, and the current
+ * Stereotype as the value.
+ */
+ Map<String, Stereotype> getRenamedStereotypes();
+
+ /**
+ * @return
+ * The list of new Stereotypes
+ */
+ List<Stereotype> getAddedStereotypes();
+
+ /**
+ * @return
+ * The list of new Extensions, for Stereotypes that already existed
+ */
+ List<ImpliedExtension> getAddedExtensions();
+
+ /**
+ *
+ * @return
+ * <code>true</code> if this diff doesn't contain any change;
+ * <code>false</code> if it contains at least one change.
+ */
+ default boolean isEmpty() {
+ return getRemovedStereotypes().isEmpty() &&
+ getRenamedStereotypes().isEmpty() &&
+ getAddedStereotypes().isEmpty() &&
+ getRemovedExtensions().isEmpty() &&
+ getAddedExtensions().isEmpty();
+ }
+ }
+
+ static class DiffImpl implements Diff {
+
+ final List<String> removedStereotypes = new ArrayList<>();
+ final Map<String, Stereotype> renamedStereotypes = new HashMap<>();
+ final List<Stereotype> addedStereotypes = new ArrayList<>();
+ final List<ImpliedExtension> addedExtensions = new ArrayList<>();
+ final List<ImpliedExtension> removedExtensions = new ArrayList<>();
+
+ @Override
+ public List<String> getRemovedStereotypes() {
+ return removedStereotypes;
+ }
+
+ @Override
+ public Map<String, Stereotype> getRenamedStereotypes() {
+ return renamedStereotypes;
+ }
+
+ @Override
+ public List<Stereotype> getAddedStereotypes() {
+ return addedStereotypes;
+ }
+
+ @Override
+ public List<ImpliedExtension> getRemovedExtensions() {
+ return addedExtensions;
+ }
+
+ @Override
+ public List<ImpliedExtension> getAddedExtensions() {
+ return removedExtensions;
+ }
+
+ /**
+ * @see java.lang.Object#toString()
+ *
+ * @return
+ */
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Removed Stereotypes: " + getRemovedStereotypes()).append('\n');
+ builder.append("Added Stereotypes: [" + getAddedStereotypes().stream().map(Stereotype::getQualifiedName).collect(Collectors.joining(", "))).append("]\n");
+ builder.append("Renamed Stereotypes: " + getRenamedStereotypes()).append('\n');
+ builder.append("Added Extensions: " + getAddedExtensions().stream().map(this::toString).collect(Collectors.joining(", "))).append('\n');
+ builder.append("Removed Extensions: " + getRemovedExtensions().stream().map(this::toString).collect(Collectors.joining(", ")));
+ return builder.toString();
+ }
+
+ private String toString(ImpliedExtension ext) {
+ return ext.getStereotype().getQualifiedName() + " -> " + ext.getMetaclass().getName();
+ }
+
+ }
+
+}
diff --git a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/ElementTypeRule.xtend b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/ElementTypeRule.xtend
index be3979e85e6..ab4d81d2312 100644
--- a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/ElementTypeRule.xtend
+++ b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/ElementTypeRule.xtend
@@ -5,9 +5,9 @@
* 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:
* Christian W. Damus - Initial API and implementation
* Ansgar Radermacher - Bug 526155, enable re-generation from profile: copy existing advices
@@ -22,30 +22,38 @@ import javax.inject.Singleton
import org.eclipse.core.resources.ResourcesPlugin
import org.eclipse.emf.common.util.URI
import org.eclipse.emf.ecore.EObject
+import org.eclipse.emf.ecore.util.EcoreUtil
+import org.eclipse.gmf.runtime.emf.type.core.ElementTypeRegistry
import org.eclipse.papyrus.infra.types.ElementTypeConfiguration
import org.eclipse.papyrus.infra.types.ElementTypesConfigurationsFactory
import org.eclipse.papyrus.infra.types.SpecializationTypeConfiguration
+import org.eclipse.papyrus.infra.types.core.impl.ConfiguredHintedSpecializationElementType
+import org.eclipse.papyrus.uml.profile.types.generator.strategy.ElementTypeConfigHelper
+import org.eclipse.papyrus.uml.types.core.advices.applystereotype.ApplyStereotypeAdviceConfiguration
+import org.eclipse.papyrus.uml.types.core.matchers.stereotype.StereotypeApplicationMatcherConfiguration
import org.eclipse.papyrus.uml.types.core.matchers.stereotype.StereotypeApplicationMatcherFactory
+import org.eclipse.papyrus.uml.types.core.matchers.stereotype.StereotypeMatcherAdviceConfiguration
+import org.eclipse.uml2.uml.NamedElement
import org.eclipse.uml2.uml.Stereotype
import static extension org.eclipse.emf.common.util.URI.decode
-import org.eclipse.gmf.runtime.emf.type.core.ElementTypeRegistry
-import org.eclipse.papyrus.infra.types.core.impl.ConfiguredHintedSpecializationElementType
+import org.eclipse.papyrus.infra.types.MetamodelTypeConfiguration
/**
* Transformation rule for generating a {@link SpecializationTypeConfiguration} from a UML metaclass {@link Extension}.
*/
@Singleton
class ElementTypeRule {
- static extension ElementTypesConfigurationsFactory elementtypesconfigurationsFactory = ElementTypesConfigurationsFactory.
- eINSTANCE
- static extension StereotypeApplicationMatcherFactory stereotypeApplicationMatcherConfigurationFactory = StereotypeApplicationMatcherFactory.
- eINSTANCE
+ static extension ElementTypesConfigurationsFactory elementtypesconfigurationsFactory = ElementTypesConfigurationsFactory.
+ eINSTANCE
+ static extension StereotypeApplicationMatcherFactory stereotypeApplicationMatcherConfigurationFactory = StereotypeApplicationMatcherFactory.
+ eINSTANCE
- @Inject extension UMLElementTypes
- @Inject extension Identifiers
+ @Inject extension UMLElementTypes
+ @Inject extension Identifiers
+ @Inject extension ElementTypeConfigHelper
- def create createSpecializationTypeConfiguration toElementType(ImpliedExtension umlExtension,
+ def create createSpecializationTypeConfiguration toElementType(ImpliedExtension umlExtension,
ElementTypeConfiguration supertype) {
// Basics
@@ -58,8 +66,7 @@ class ElementTypeRule {
// base type found, reference it instead of creating a new one
val baseType = (baseTypeFromRegistry as ConfiguredHintedSpecializationElementType).configuration
specializedTypes.add(baseType)
- }
- else {
+ } else {
// Add the base semantic type in addition to the parent visual type
val baseType = createSpecializationTypeConfiguration()
baseType.identifier = umlExtension.toElementTypeID(umlExtension.metaclass.elementTypeConfiguration)
@@ -76,6 +83,7 @@ class ElementTypeRule {
specializedTypes.add(supertype)
hint = supertype.hint
name = umlExtension.toElementTypeName(supertype)
+ source = EcoreUtil.getURI(umlExtension.stereotype).toString();
// copy eventually already existing advices from registry
val elemTypeFromRegistry = ElementTypeRegistry.instance.getType(identifier)
@@ -83,7 +91,8 @@ class ElementTypeRule {
// existing element type found, copy helper advice, if any
val elemTypeConfigFromRegistry = elemTypeFromRegistry.configuration
if (elemTypeConfigFromRegistry instanceof SpecializationTypeConfiguration) {
- val helperAdviceFromRegistry = (elemTypeConfigFromRegistry as SpecializationTypeConfiguration).editHelperAdviceConfiguration
+ val helperAdviceFromRegistry = (elemTypeConfigFromRegistry as SpecializationTypeConfiguration).
+ editHelperAdviceConfiguration
if (helperAdviceFromRegistry != null) {
editHelperAdviceConfiguration = helperAdviceFromRegistry
}
@@ -100,43 +109,115 @@ class ElementTypeRule {
}
}
- private def create createStereotypeMatcherAdviceConfiguration toMatcherConfiguration(ImpliedExtension umlExtension,
- ElementTypeConfiguration supertype) {
-
- val umlStereotype = umlExtension.stereotype
- identifier = umlStereotype.name.toFirstLower.qualified + supertype.hintSuffix;
- stereotypesQualifiedNames.add(umlStereotype.qualifiedName)
- description = "Apply Stereotype "+umlStereotype.name
- }
-
- private def getIconEntry(Stereotype stereotype) {
- val image = stereotype.icons.findFirst[!location.nullOrEmpty]
- if (image != null) {
- val uri = URI.createURI(image.location, true)
-
- if (uri != null) {
- createIconEntry => [
- if (uri.platform) {
-
- // Explicit platform-scheme URI
- bundleId = uri.segment(1)
- iconPath = "/" + uri.segmentsList.drop(2).join("/", [decode])
- } else if (uri.relative) {
-
- // Bundle-relative path. Infer the bundle ID from the containing project
- bundleId = stereotype.containingProject.name
- iconPath = "/" + uri.toString.decode
- } else {
-
- // Absolute URI: use as is; don't decode it
- iconPath = uri.toString
- }
- ]
- }
- }
- }
-
- private def containingProject(EObject object) {
- ResourcesPlugin.workspace.root.getProject(object.eResource.URI.segment(2))
- }
+ /**
+ * Change the stereotype qualified name for this type configuration (i.e. modify
+ * the qualified name of the ApplyStereotypeAdvice and StereotypeMatcher)
+ *
+ * @param typeConfig
+ * The element type to edit
+ * @param stereotype
+ * The current stereotype, that was renamed
+ */
+ def setStereotypeName(ElementTypeConfiguration typeConfig, Stereotype stereotype) {
+ val newName = stereotype.qualifiedName;
+ val ext = getExtension(typeConfig, stereotype);
+
+ val advices = new ElementTypeConfigHelper().getRelatedAdvices(typeConfig);
+
+ // We only expect element types with a single advice. Otherwise, they probably
+ // were not generated by this template, and should be ignored.
+ if (advices.size != 1) {
+ return;
+ }
+
+ val advice = advices.get(0);
+ if (advice instanceof ApplyStereotypeAdviceConfiguration) {
+ // Older type of generated advice (<= 5.0.0). We probably won't get
+ // in this case, as we didn't have a 'source' attribute at this point,
+ // so it's difficult to detect renamed stereotypes that need to be updated.
+ if (advice.stereotypesToApply.size == 1) {
+ val stereotypeToApply = advice.stereotypesToApply.get(0);
+ stereotypeToApply.stereotypeQualifiedName = newName;
+ if (stereotypeToApply.requiredProfiles.size == 1) {
+ val profileName = getProfileName(newName);
+ if (profileName != null) {
+ stereotypeToApply.requiredProfiles.set(0, profileName);
+ }
+ }
+ }
+ } else if (advice instanceof StereotypeMatcherAdviceConfiguration) {
+ // New type of generated advice (> 5.0.0)
+ if (advice.stereotypesQualifiedNames.size == 1) {
+ advice.stereotypesQualifiedNames.set(0, newName);
+ }
+ }
+
+ // Should be the same as StereotypeMatcherAdviceConfiguration,
+ // as this element is used as both a Matcher and an Advice
+ if (typeConfig instanceof SpecializationTypeConfiguration) {
+ val matcher = typeConfig.matcherConfiguration;
+ if (matcher instanceof StereotypeApplicationMatcherConfiguration) {
+ if (matcher.stereotypesQualifiedNames.size == 1) {
+ matcher.stereotypesQualifiedNames.set(0, newName);
+ }
+ }
+ }
+
+ // Update the name and ID of the ElementType
+
+ if (typeConfig instanceof SpecializationTypeConfiguration){
+ val supertype = typeConfig.specializedTypes.get(0);
+ typeConfig.name = ext.toElementTypeName(supertype);
+ typeConfig.identifier = ext.toElementTypeID(supertype);
+ }
+ }
+
+ private def getProfileName(String stereoName){
+ val sep = stereoName.lastIndexOf(NamedElement.SEPARATOR);
+ if (sep > 0) {
+ val profileName = stereoName.substring(0, sep);
+ return profileName;
+ }
+ return null;
+ }
+
+ private def create createStereotypeMatcherAdviceConfiguration toMatcherConfiguration(ImpliedExtension umlExtension,
+ ElementTypeConfiguration supertype) {
+
+ val umlStereotype = umlExtension.stereotype
+ identifier = umlStereotype.name.toFirstLower.qualified + supertype.hintSuffix;
+ stereotypesQualifiedNames.add(umlStereotype.qualifiedName)
+ description = "Apply Stereotype " + umlStereotype.name
+ }
+
+ private def getIconEntry(Stereotype stereotype) {
+ val image = stereotype.icons.findFirst[!location.nullOrEmpty]
+ if (image != null) {
+ val uri = URI.createURI(image.location, true)
+
+ if (uri != null) {
+ createIconEntry => [
+ if (uri.platform) {
+
+ // Explicit platform-scheme URI
+ bundleId = uri.segment(1)
+ iconPath = "/" + uri.segmentsList.drop(2).join("/", [decode])
+ } else if (uri.relative) {
+
+ // Bundle-relative path. Infer the bundle ID from the containing project
+ bundleId = stereotype.containingProject.name
+ iconPath = "/" + uri.toString.decode
+ } else {
+
+ // Absolute URI: use as is; don't decode it
+ iconPath = uri.toString
+ }
+ ]
+ }
+ }
+ }
+
+ private def containingProject(EObject object) {
+ ResourcesPlugin.workspace.root.getProject(object.eResource.URI.segment(2))
+ }
}
diff --git a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/ElementTypesGenerator.java b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/ElementTypesGenerator.java
index 3d01e2f5955..3d3bcf84ad9 100644
--- a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/ElementTypesGenerator.java
+++ b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/ElementTypesGenerator.java
@@ -1,6 +1,6 @@
/*****************************************************************************
* Copyright (c) 2014, 2015 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 2.0
* which accompanies this distribution, and is available at
@@ -10,11 +10,13 @@
*
* Contributors:
* Christian W. Damus - Initial API and implementation
- *
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.profile.types.generator;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
import org.eclipse.papyrus.infra.types.ElementTypeSetConfiguration;
import org.eclipse.uml2.uml.Profile;
@@ -28,8 +30,8 @@ public class ElementTypesGenerator extends AbstractGenerator<Profile, ElementTyp
@Inject
private ConfigurationSetRule mainRule;
- public ElementTypesGenerator(Identifiers identifiers) {
- this(new GeneratorModule(identifiers));
+ public ElementTypesGenerator(Identifiers identifiers, DeltaStrategy.Diff diff) {
+ this(new GeneratorModule(identifiers, diff));
}
public ElementTypesGenerator(GeneratorModule module) {
@@ -38,6 +40,12 @@ public class ElementTypesGenerator extends AbstractGenerator<Profile, ElementTyp
@Override
protected ElementTypeSetConfiguration generate(Profile profile) {
- return mainRule.toConfigurationSet(profile);
+ return mainRule.toConfigurationSet(profile, null);
+ }
+
+ @Override
+ protected ElementTypeSetConfiguration regenerate(Profile input, EList<? super EObject> originalOutput) {
+ return mainRule.toConfigurationSet(input, originalOutput);
}
+
}
diff --git a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/GeneratorModule.java b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/GeneratorModule.java
index 102aadf38a4..7674e9505b7 100644
--- a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/GeneratorModule.java
+++ b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/GeneratorModule.java
@@ -1,6 +1,6 @@
/*****************************************************************************
* Copyright (c) 2014, 2015 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 2.0
* which accompanies this distribution, and is available at
@@ -10,27 +10,37 @@
*
* Contributors:
* Christian W. Damus - Initial API and implementation
- *
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.profile.types.generator;
+import java.util.Optional;
+
import org.eclipse.emf.ecore.EClass;
import org.eclipse.papyrus.infra.types.ElementTypesConfigurationsPackage;
+import org.eclipse.papyrus.uml.profile.types.generator.DeltaStrategy.Diff;
import org.eclipse.uml2.uml.UMLPackage;
import com.google.inject.AbstractModule;
+import com.google.inject.TypeLiteral;
/**
* The base Guice injector module for the UML Profile to Element Types Set Configuration transformation.
*/
public class GeneratorModule extends AbstractModule {
private final Identifiers identifiers;
+ private final Diff diff;
public GeneratorModule(Identifiers identifiers) {
+ this(identifiers, null);
+ }
+
+ public GeneratorModule(Identifiers identifiers, DeltaStrategy.Diff diff) {
super();
this.identifiers = identifiers;
+ this.diff = diff;
}
@Override
@@ -47,6 +57,14 @@ public class GeneratorModule extends AbstractModule {
bindConfigurationSetRule();
bindElementTypeRule();
bindApplyStereotypeAdviceRule();
+
+ // bind the profile difference we want to include, for incremental generation
+ bindDiff();
+ }
+
+ protected void bindDiff() {
+ bind(new TypeLiteral<Optional<Diff>>() {
+ }).toInstance(Optional.ofNullable(diff));
}
protected void bindInputType() {
diff --git a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/UML.xtend b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/UML.xtend
index e24583326f5..bfadb67d514 100644
--- a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/UML.xtend
+++ b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/UML.xtend
@@ -57,6 +57,11 @@ class UML {
+ package_.nestedPackages.map[allExtensions].flatten
}
+ def Iterable<Stereotype> getAllStereotypes(org.eclipse.uml2.uml.Package package_) {
+ package_.ownedTypes.filter(Stereotype)
+ + package_.nestedPackages.map[allStereotypes].flatten
+ }
+
def Iterable<ImpliedExtension> impliedExtensions(Stereotype stereotype) {
stereotype.allExtendedMetaclasses.map[new ImpliedExtension(stereotype, it)]
}
diff --git a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/strategy/ElementTypeConfigHelper.java b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/strategy/ElementTypeConfigHelper.java
new file mode 100644
index 00000000000..256f2eb3c2c
--- /dev/null
+++ b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/strategy/ElementTypeConfigHelper.java
@@ -0,0 +1,292 @@
+/*****************************************************************************
+ * Copyright (c) 2020 EclipseSource and others.
+ *
+ * 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
+ * http://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * EclipseSource - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.profile.types.generator.strategy;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.papyrus.infra.types.AbstractAdviceBindingConfiguration;
+import org.eclipse.papyrus.infra.types.ElementTypeConfiguration;
+import org.eclipse.papyrus.infra.types.ElementTypeSetConfiguration;
+import org.eclipse.papyrus.infra.types.MetamodelTypeConfiguration;
+import org.eclipse.papyrus.infra.types.SpecializationTypeConfiguration;
+import org.eclipse.papyrus.uml.profile.types.generator.ImpliedExtension;
+import org.eclipse.papyrus.uml.profile.types.generator.UML;
+import org.eclipse.papyrus.uml.tools.utils.ElementUtil;
+import org.eclipse.papyrus.uml.types.core.advices.applystereotype.ApplyStereotypeAdviceConfiguration;
+import org.eclipse.papyrus.uml.types.core.matchers.stereotype.StereotypeMatcherAdviceConfiguration;
+import org.eclipse.uml2.uml.PackageableElement;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.Stereotype;
+import org.eclipse.uml2.uml.resource.UMLResource;
+
+/**
+ * A helper to retrieve Stereotype information from an {@link ElementTypeSetConfiguration} model.
+ */
+public class ElementTypeConfigHelper {
+
+ private final UML uml = new UML();
+
+ /**
+ * @param config
+ * @return
+ * The Stereotype Qualified Name represented by this ElementTypeConfiguration,
+ * or <code>null</code> if this Element Type doesn't represent a Stereotype.
+ */
+ public String getStereotypeName(ElementTypeConfiguration config) {
+ // ElementTypes representing Stereotypes are always SpecializationTypes
+ if (config instanceof SpecializationTypeConfiguration) {
+ List<AbstractAdviceBindingConfiguration> relatedAdvices = getRelatedAdvices(config);
+
+ // TODO Limit this to a single Stereotype Advice. If multiple Stereotype Advices
+ // are applied, this ElementType doesn't represent a single generate Stereotype
+ // Specialization Type and should be ignored.
+ for (AbstractAdviceBindingConfiguration advice : relatedAdvices) {
+ if (advice instanceof ApplyStereotypeAdviceConfiguration) {
+ return getStereotypeName((ApplyStereotypeAdviceConfiguration) advice);
+ } else if (advice instanceof StereotypeMatcherAdviceConfiguration) {
+ return getStereotypeName((StereotypeMatcherAdviceConfiguration) advice);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Retrieve all {@link AbstractAdviceBindingConfiguration} related to the selected element type
+ * in its {@link ElementTypeSetConfiguration}
+ *
+ * @param typeConfig
+ * The ElementType
+ * @return
+ * The list of Advices related to this element type (i.e. having this type as their target)
+ */
+ public List<AbstractAdviceBindingConfiguration> getRelatedAdvices(ElementTypeConfiguration typeConfig) {
+ List<AbstractAdviceBindingConfiguration> relatedAdvices = Stream.concat(
+ typeConfig.getOwnedAdvice().stream(), // Directly owned advices
+ typeConfig.getOwningSet().getAdviceBindingsConfigurations().stream() // External Advices (in the same TypeSet) targetting this type
+ .filter(advice -> advice.getTarget() == typeConfig))
+ .collect(Collectors.toList());
+ return relatedAdvices;
+ }
+
+ /**
+ * @param advice
+ * @return
+ */
+ public String getStereotypeName(ApplyStereotypeAdviceConfiguration advice) {
+ if (advice.getStereotypesToApply().size() == 1) {
+ return advice.getStereotypesToApply().get(0).getStereotypeQualifiedName();
+ }
+ // If there are 0 or > 2 stereotypes to apply, this is not a (valid) generated
+ // element type, and should be ignored.
+ return null;
+ }
+
+ /**
+ * @param advice
+ * @return
+ */
+ public String getStereotypeName(StereotypeMatcherAdviceConfiguration advice) {
+ if (advice.getStereotypesQualifiedNames().size() == 1) {
+ return advice.getStereotypesQualifiedNames().get(0);
+ }
+ // If there are 0 or > 2 stereotypes to apply, this is not a (valid) generated
+ // element type, and should be ignored.
+ return null;
+ }
+
+ /**
+ * Tests if the stereotype corresponding to the given ElementTypeConfiguration
+ * still exists in the current version of the profile. This methods returns
+ * <code>true</code> if the stereotype has been renamed, but kept the same URI (In that
+ * case, see {@link #getCurrentName(ElementTypeConfiguration, Profile)})
+ *
+ * @param config
+ * @param currentProfile
+ * @return
+ * An Optional boolean:
+ * <ul>
+ * <li><code>True</code> if the config represents a Stereotype that still exists
+ * <li><code>False</code> if the config represents a Stereotype that no longer exists
+ * <li>{@link Optional#empty}</li> if the config doesn't represent a Stereotype
+ * </ul>
+ */
+ public Optional<Boolean> exists(ElementTypeConfiguration config, Profile currentProfile) {
+ String stereoQName = getStereotypeName(config);
+ URI stereoURI = getStereotypeURI(config);
+ if (stereoURI != null && currentProfile.eResource().getResourceSet().getEObject(stereoURI, false) != null) {
+ // If the URI doesn't exist, don't return false: if the Stereotype was deleted and
+ // re-created with the same name, then it still exists. If it has been copied to
+ // a different resource with a different URI, while keeping the same name, then
+ // it also still exists.
+ return Optional.of(Boolean.TRUE);
+ }
+ if (stereoQName != null) {
+ return Optional.of(
+ StreamSupport.stream(uml.getAllStereotypes(currentProfile).spliterator(), false)
+ .anyMatch(s -> stereoQName.equals(s.getQualifiedName())));
+ }
+
+ // We simply want to ignore this unknown element (which doesn't represent a
+ // Stereotype QName or URI); so testing if the stereotype exists or not doesn't
+ // make sense.
+ return Optional.empty();
+ }
+
+ /**
+ * @param config
+ * @return
+ * The URI of the stereotype that was used to generate this element type, or <code>null</code>
+ */
+ private URI getStereotypeURI(ElementTypeConfiguration config) {
+ if (config.getSource() == null || config.getSource().isEmpty()) {
+ return null;
+ }
+ try {
+ URI uri = URI.createURI(config.getSource());
+ return uri;
+ } catch (IllegalArgumentException ex) {
+ // The source is not a valid URI; probably because the type wasn't generated
+ // with this tool. Simply ignore.
+ return null;
+ }
+ }
+
+ /**
+ * Tests if stereotype already exists in the previous version of the element type set.
+ * This methods returns <code>true</code> if the stereotype has been renamed, but kept
+ * the same URI (In that case, see {@link #getCurrentName(ElementTypeConfiguration, Profile)})
+ *
+ * @param stereotype
+ * @param previousTypes
+ * @return
+ */
+ public boolean exists(Stereotype stereotype, ElementTypeSetConfiguration previousTypes) {
+ String stereoQName = stereotype.getQualifiedName();
+ URI stereotypeURI = EcoreUtil.getURI(stereotype);
+ boolean anyMatch = previousTypes.getElementTypeConfigurations().stream() //
+ .anyMatch(config -> stereoQName.equals(getStereotypeName(config)) //
+ || stereotypeURI.equals(getStereotypeURI(config)));
+ return anyMatch;
+ }
+
+ /**
+ * Retrieve the Stereotype that was used to generate the given config, and return
+ * its current version (from the specified profile).
+ *
+ * This is used to identify e.g. renamed stereotypes (or updated stereotypes, in general).
+ *
+ * @param config
+ * The element type configuration that was (potentially) generated, in the past
+ * @param currentProfile
+ * The current version of the profile
+ * @return
+ * The current stereotype corresponding to the given config, or <code>null</code>.
+ */
+ public Stereotype getCurrentStereotypeByURI(ElementTypeConfiguration config, Profile currentProfile) {
+ URI sourceURI = getStereotypeURI(config);
+ if (sourceURI == null) {
+ return null;
+ }
+
+ // Use loadOnDemand=false. If the stereotype is not already part of the Profile resource set, then
+ // it might match a different profile. We don't want to load these external profiles.
+ EObject eObject = currentProfile.eResource().getResourceSet().getEObject(sourceURI, false);
+ if (eObject instanceof Stereotype) {
+ return ((Stereotype) eObject);
+ }
+ return null;
+ }
+
+ /**
+ * Retrieve the Stereotype corresponding to the given config, and return
+ * its current version (from the specified profile).
+ *
+ * @param config
+ * The element type configuration
+ * @param currentProfile
+ * The current version of the profile
+ * @return
+ * The current stereotype corresponding to the given config, or <code>null</code>.
+ */
+ public Stereotype getCurrentStereotype(ElementTypeConfiguration config, Profile currentProfile) {
+ // Try to find the Stereotype by URI
+ Stereotype stereotype = getCurrentStereotypeByURI(config, currentProfile);
+ if (stereotype != null) {
+ return stereotype;
+ }
+ String stereoQName = getStereotypeName(config);
+ if (stereoQName == null) {
+ // This type doesn't represent a Stereotype
+ return null;
+ }
+
+ // Try to find the Stereotype by Qualified Name
+ return StreamSupport.stream(uml.getAllStereotypes(currentProfile).spliterator(), false).filter(st -> stereoQName.equals(st.getQualifiedName())).findFirst().orElse(null);
+ }
+
+ public ImpliedExtension getExtension(ElementTypeConfiguration config, Profile currentProfile) {
+ Stereotype stereotype = getCurrentStereotype(config, currentProfile);
+ return stereotype == null ? null : getExtension(config, stereotype);
+ }
+
+ public boolean exists(ImpliedExtension extension, Iterable<ImpliedExtension> allExtensions) {
+ return StreamSupport.stream(allExtensions.spliterator(), false).anyMatch(e -> e.equals(extension));
+ }
+
+ /**
+ * Return the Stereotype's {@link ImpliedExtension} corresponding to the given typeConfig.
+ */
+ public ImpliedExtension getExtension(ElementTypeConfiguration typeConfig, Stereotype stereotype) {
+ if (stereotype == null || typeConfig == null) {
+ return null;
+ }
+ if (typeConfig instanceof SpecializationTypeConfiguration) {
+ SpecializationTypeConfiguration type = (SpecializationTypeConfiguration) typeConfig;
+ if (type.getSpecializedTypes().size() == 1) {
+ ElementTypeConfiguration baseType = type.getSpecializedTypes().get(0);
+ if (baseType instanceof MetamodelTypeConfiguration) {
+ EClass metaclass = ((MetamodelTypeConfiguration) baseType).getEClass();
+ if (metaclass != null) {
+ org.eclipse.uml2.uml.Package uml2Metamodel = ElementUtil.contentload(URI.createURI(UMLResource.UML_METAMODEL_URI), stereotype);
+ PackageableElement baseClass = uml2Metamodel.getPackagedElement(metaclass.getName());
+ return baseClass instanceof org.eclipse.uml2.uml.Class ? new ImpliedExtension(stereotype, (org.eclipse.uml2.uml.Class) baseClass) : null;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public boolean exists(ImpliedExtension extension, ElementTypeSetConfiguration previousTypes) {
+ for (ElementTypeConfiguration config : previousTypes.getElementTypeConfigurations()) {
+ ImpliedExtension ext = getExtension(config, extension.getStereotype().getProfile());
+ if (extension.equals(ext)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/strategy/SimpleDeltaStrategy.java b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/strategy/SimpleDeltaStrategy.java
new file mode 100644
index 00000000000..8b91fd76f68
--- /dev/null
+++ b/plugins/toolsmiths/assistants/org.eclipse.papyrus.uml.profile.types.generator/src/org/eclipse/papyrus/uml/profile/types/generator/strategy/SimpleDeltaStrategy.java
@@ -0,0 +1,105 @@
+/*****************************************************************************
+ * Copyright (c) 2020 EclipseSource and others.
+ *
+ * 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
+ * http://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * EclipseSource - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.profile.types.generator.strategy;
+
+import java.util.Optional;
+
+import org.eclipse.papyrus.infra.types.ElementTypeConfiguration;
+import org.eclipse.papyrus.infra.types.ElementTypeSetConfiguration;
+import org.eclipse.papyrus.uml.profile.types.generator.DeltaStrategy;
+import org.eclipse.papyrus.uml.profile.types.generator.ImpliedExtension;
+import org.eclipse.papyrus.uml.profile.types.generator.UML;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.Stereotype;
+
+/**
+ * A {@link DeltaStrategy} based on stereotype qualified name, URI and Extensions comparison.
+ *
+ * <ul>
+ * <li>A Stereotype is considered "added" if Qualified Name and URI don't match any existing element type.</li>
+ * <li>A Stereotype is considered "removed" if Qualified Name and URI of an Element Type don't match any stereotype in the current profile.</li>
+ * <li>A Stereotype is considered "renamed" if the Source URI from the Element Type matches the URI of a current sterotype, but qualified names
+ * are different.</li>
+ * <li>A Stereotype is considered "modified" if it already exists in the current Profile and ElementTypeConfiguration, with a different set of Extensions</li>
+ * </ul>
+ */
+public class SimpleDeltaStrategy implements DeltaStrategy {
+
+ @Override
+ public Diff findDiffs(Profile currentProfile, ElementTypeSetConfiguration previousTypes) {
+ Diff result = new DiffImpl();
+ UML uml = new UML();
+
+ // Added Stereotypes
+ ElementTypeConfigHelper helper = new ElementTypeConfigHelper();
+ for (Stereotype stereotype : uml.getAllStereotypes(currentProfile)) {
+ if (!helper.exists(stereotype, previousTypes)) {
+ result.getAddedStereotypes().add(stereotype);
+ }
+ }
+ // Removed Stereotypes and Extensions
+ Iterable<ImpliedExtension> allExtensions = uml.getAllExtensions(currentProfile);
+
+ for (ElementTypeConfiguration config : previousTypes.getElementTypeConfigurations()) {
+ Optional<Boolean> exists = helper.exists(config, currentProfile);
+ if (exists.isEmpty()) {
+ // This type config doesn't correspond to a stereotype; ignore it
+ continue;
+ }
+ if (!exists.get()) {
+ // The stereotype doesn't exist in the current profile, i.e. it has been deleted
+ result.getRemovedStereotypes().add(helper.getStereotypeName(config));
+ } else {
+ // The stereotype still exists; but some extensions might have been removed
+ ImpliedExtension ext = helper.getExtension(config, currentProfile);
+ // Test if this element type represents an extension. If not, ignore it.
+ if (ext != null && ext.getMetaclass() != null && ext.getStereotype() != null) {
+ if (!helper.exists(ext, allExtensions)) {
+ // The stereotype exists, but this specific extension was removed
+ result.getRemovedExtensions().add(ext);
+ }
+ }
+ }
+ }
+
+ // Renamed Stereotypes (or Profiles)
+ for (ElementTypeConfiguration config : previousTypes.getElementTypeConfigurations()) {
+ String originalName = helper.getStereotypeName(config);
+ Stereotype currentStereotype = helper.getCurrentStereotype(config, currentProfile);
+ if (currentStereotype != null) {
+ String currentName = currentStereotype.getQualifiedName();
+ if (originalName != null && currentName != null && !originalName.equals(currentName)) {
+ result.getRenamedStereotypes().put(originalName, currentStereotype);
+ }
+ }
+ }
+
+ // Identify stereotypes for which Extension(s) have been added or removed
+ for (ImpliedExtension extension : allExtensions) {
+ if (result.getAddedStereotypes().contains(extension.getStereotype())) {
+ // This is a new Stereotype; we only care about extensions that have
+ // been added/removed for an existing stereotype
+ continue;
+ }
+ if (!helper.exists(extension, previousTypes)) {
+ result.getAddedExtensions().add(extension);
+ }
+ }
+
+ return result;
+ }
+
+}

Back to the top