Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Lorenzo2021-03-17 14:31:22 +0000
committerVincent Lorenzo2021-03-26 12:40:31 +0000
commit85070e1988d945c5a33089b3c74d4120d9a1ab44 (patch)
tree8ed35a98b2c125533d3bcd6b322e553f28dd38b7 /plugins/infra/emf
parent61273267dbcc345740b17f1a00bc3f1c5557ca29 (diff)
downloadorg.eclipse.papyrus-85070e1988d945c5a33089b3c74d4120d9a1ab44.tar.gz
org.eclipse.papyrus-85070e1988d945c5a33089b3c74d4120d9a1ab44.tar.xz
org.eclipse.papyrus-85070e1988d945c5a33089b3c74d4120d9a1ab44.zip
Bug 569357: [Toolsmiths] ElementTypes: Model and Plug-in Validation
- fix exception on attempt to clear unmodifiable list when resetting Architecture Context preferences - let the workspace copy of an Architecture Context model supersede the deployed platform copy - ensure that relative cross-document references in the Architecture Context model resolve from workspace to platform where applicable - ensure loading unique copy of any given Architecture Context model even if redundantly added via preferences - ensure that ResourcesUtil works in the absence of PDE - factor out common project builder behaviours, including: - mapping the project for EMF resources to check - separate reporting of diagnostics from creation of markers to avoid creating redundant markers - common framework for EMF model validation checkers on EMF resources - common framework for build.properties checkers - common framework for bundle dependencies checkers - common framework for plugin.xml extensions checkers - implement the common checkers frameworks for element-types - absorb the function of the custom ElementTypesConfigurationsValidator into the builder - add validation of stereotype application matcher and related configurations - add validation of stereotype reference edge advice configurations - add inference of profile resources in the same project that need to be packaged by the build.properties file - handle extraction of bundle dependency name from bundleresource:// URIs - support aggregation of the same diagnostic from different sources into a single marker - add a generic checker for custom model validation rules - implement custom Element Types validation rules for UML Stereotypes - proper progress monitor delegation in the delegating builder - normalize URIs with inclusion of mappings from the workspace also Change-Id: Iefce58ba3a73b985f55b2ef82c45fb114cad4c44 Signed-off-by: Christian W. Damus <give.a.damus@gmail.com> Also-by: Vincent Lorenzo <vincent.lorenzo@cea.fr>
Diffstat (limited to 'plugins/infra/emf')
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/META-INF/MANIFEST.MF2
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/PlatformHelper.java210
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/ResourceUtils.java91
3 files changed, 278 insertions, 25 deletions
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/META-INF/MANIFEST.MF b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/META-INF/MANIFEST.MF
index 184e930d44a..0047aa688a9 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/META-INF/MANIFEST.MF
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/META-INF/MANIFEST.MF
@@ -20,7 +20,7 @@ Require-Bundle: org.eclipse.core.expressions;bundle-version="[3.6.0,4.0.0)",
org.eclipse.papyrus.infra.core.sashwindows.di;bundle-version="[2.0.0,3.0.0)",
org.eclipse.papyrus.infra.tools;bundle-version="[4.0.0,5.0.0)",
org.eclipse.uml2.types;bundle-version="[2.5.0,3.0.0)",
- org.eclipse.pde.core;bundle-version="[3.14.100,4.0.0)"
+ org.eclipse.pde.core;bundle-version="[3.14.100,4.0.0)";resolution:=optional
Bundle-Vendor: Eclipse Modeling Project
Bundle-ActivationPolicy: lazy
Bundle-Version: 4.1.0.qualifier
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/PlatformHelper.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/PlatformHelper.java
new file mode 100644
index 00000000000..a02c050cd1f
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/PlatformHelper.java
@@ -0,0 +1,210 @@
+/*****************************************************************************
+ * Copyright (c) 2020 Christian W. Damus, CEA LIST, 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:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.emf.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.osgi.container.ModuleContainer;
+import org.eclipse.papyrus.infra.emf.Activator;
+import org.eclipse.pde.core.plugin.IPluginElement;
+import org.eclipse.pde.core.plugin.IPluginExtension;
+import org.eclipse.pde.core.plugin.IPluginModelBase;
+import org.eclipse.pde.core.plugin.PluginRegistry;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.namespace.IdentityNamespace;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.FrameworkWiring;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.DefaultHandler2;
+
+/**
+ * Optional support for a PDE Target platform, to discover the plug-ins against
+ * which workspace projects (if any) are overlaid.
+ */
+abstract class PlatformHelper {
+
+ private static final String ECORE_URI_MAPPING_EXTENSION_POINT = "org.eclipse.emf.ecore.uri_mapping"; //$NON-NLS-1$
+ private static final String E_EXTENSION = "extension"; //$NON-NLS-1$
+ private static final String A_POINT = "point"; //$NON-NLS-1$
+ private static final String E_MAPPING = "mapping"; //$NON-NLS-1$
+ private static final String A_SOURCE = "source"; //$NON-NLS-1$
+ private static final String A_TARGET = "target"; //$NON-NLS-1$
+
+ static final PlatformHelper INSTANCE;
+
+ static {
+ PlatformHelper instance;
+
+ try {
+ instance = new PDEHelper();
+ } catch (Exception e) {
+ // PDE is not available
+ instance = new InstallHelper();
+ }
+
+ INSTANCE = instance;
+ }
+
+
+ /**
+ * Get the IDs of all bundles available in the target platform, whether that be the
+ * PDE Target Platform (in case PDE is installed) or else the host installation.
+ *
+ * @return the platform bundle IDs
+ */
+ abstract Collection<String> getPlatformBundleIDs();
+
+ /**
+ * Return the {@code org.eclipse.emf.ecore.uri_mapping} extension declarations in the given {@code project}.
+ *
+ * @param project
+ * a project in the workspace
+ * @return its declared URI mappings
+ */
+ abstract Map<String, String> getLocalUriMappings(IProject project);
+
+ //
+ // Nested types
+ //
+
+ /**
+ * The install helper instance gets all resolved (ready/available) bundles in the current installation.
+ */
+ private static final class InstallHelper extends PlatformHelper {
+
+ private static final int AVAILABLE = Bundle.ACTIVE | Bundle.RESOLVED | Bundle.STARTING;
+
+ @Override
+ Collection<String> getPlatformBundleIDs() {
+ Collection<String> result = new HashSet<>();
+
+ FrameworkWiring wiring = Platform.getBundle(Constants.SYSTEM_BUNDLE_SYMBOLICNAME).adapt(FrameworkWiring.class);
+ Collection<BundleCapability> bundleIdentities = wiring.findProviders(ModuleContainer
+ .createRequirement(IdentityNamespace.IDENTITY_NAMESPACE, Collections.emptyMap(), Collections.emptyMap()));
+ for (BundleCapability next : bundleIdentities) {
+ Bundle bundle = next.getRevision().getBundle();
+ if ((bundle.getState() & AVAILABLE) != 0) {
+ result.add(bundle.getSymbolicName());
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ Map<String, String> getLocalUriMappings(IProject project) {
+ IFile pluginXML = project.getFile("plugin.xml"); //$NON-NLS-1$
+ if (!pluginXML.isAccessible()) {
+ return Map.of();
+ }
+
+ Map<String, String> result = new HashMap<>();
+
+ try (InputStream input = pluginXML.getContents()) {
+ SAXParserFactory.newInstance().newSAXParser().parse(input, new DefaultHandler2() {
+ private boolean inMappings;
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ // plugin.xml does not use namespaces, so the parser provides empty local names and the local names in qName
+ if (E_EXTENSION.equals(qName) && ECORE_URI_MAPPING_EXTENSION_POINT.equals(attributes.getValue(A_POINT))) {
+ inMappings = true;
+ } else if (inMappings && E_MAPPING.equals(qName)) {
+ String source = attributes.getValue(A_SOURCE);
+ String target = attributes.getValue(A_TARGET);
+ if (source != null && !source.isBlank() && target != null && !target.isBlank()) {
+ result.put(source, target);
+ }
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ if (E_EXTENSION.equals(qName)) {
+ inMappings = false;
+ }
+ }
+ });
+ } catch (SAXException | IOException | ParserConfigurationException | CoreException e) {
+ Activator.log.error("Failed to parse plugin.xml in project" + project.getName(), e); //$NON-NLS-1$
+ }
+
+ return result;
+ }
+
+ }
+
+ /**
+ * The PDE helper instance gets all active bundles in the current PDE target platform.
+ */
+ private static final class PDEHelper extends PlatformHelper {
+
+ @Override
+ Collection<String> getPlatformBundleIDs() {
+ IPluginModelBase[] pluginModels = PluginRegistry.getActiveModels();
+ Collection<String> result = new HashSet<>();
+
+ for (IPluginModelBase next : pluginModels) {
+ if (next.getBundleDescription() != null) {
+ result.add(next.getBundleDescription().getSymbolicName());
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ Map<String, String> getLocalUriMappings(IProject project) {
+ HashMap<String, String> localMappings = new HashMap<>();
+ final IPluginModelBase model = PluginRegistry.findModel(project.getName());
+ if (model == null) {
+ // No mappings if no plugin model
+ return localMappings;
+ }
+
+ for (IPluginExtension extension : model.getExtensions().getExtensions()) {
+ if (!Objects.equals(extension.getPoint(), ECORE_URI_MAPPING_EXTENSION_POINT)) {
+ continue;
+ }
+ Arrays.stream(extension.getChildren())
+ .filter(IPluginElement.class::isInstance).map(IPluginElement.class::cast)
+ .filter(element -> Objects.equals(E_MAPPING, element.getName()))
+ .forEach(element -> localMappings.put(element.getAttribute(A_SOURCE).getValue(), element.getAttribute(A_TARGET).getValue()));
+ }
+
+ return localMappings;
+ }
+
+ }
+
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/ResourceUtils.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/ResourceUtils.java
index 038c00c26f3..c86e011eb37 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/ResourceUtils.java
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/ResourceUtils.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2012 CEA LIST.
+ * Copyright (c) 2012, 2020 CEA LIST, Christian W. Damus, and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -11,6 +11,7 @@
*
* Contributors:
* Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 569357
*
*****************************************************************************/
package org.eclipse.papyrus.infra.emf.utils;
@@ -23,7 +24,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@@ -35,25 +35,21 @@ import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.plugin.EcorePlugin;
import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.URIConverter;
+import org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl;
import org.eclipse.emf.ecore.resource.impl.URIMappingRegistryImpl;
import org.eclipse.emf.ecore.xmi.XMIResource;
import org.eclipse.emf.ecore.xmi.XMLResource;
-import org.eclipse.pde.core.plugin.IPluginExtension;
-import org.eclipse.pde.core.plugin.IPluginModelBase;
-import org.eclipse.pde.core.plugin.IPluginObject;
-import org.eclipse.pde.core.plugin.PluginRegistry;
-import org.eclipse.pde.internal.core.text.plugin.PluginElementNode;
/**
*
* This class provides methods for EMF Resource
*
*/
-@SuppressWarnings("restriction")
public class ResourceUtils {
- private static final String ECORE_URI_MAPPING_EXTENSION_POINT = "org.eclipse.emf.ecore.uri_mapping"; //$NON-NLS-1$
private static final String PATH_SEPARATOR = "/";
@@ -155,23 +151,43 @@ public class ResourceUtils {
return getStringURI(relativePath);
}
- /** Return the `org.eclipse.emf.ecore.uri_mapping` extension declarations in the given project. */
- public static Map<String, String> getLocalUriMappings(IProject project) {
- HashMap<String, String> localMappings = new HashMap<>();
- final IPluginModelBase model = PluginRegistry.findModel(project.getName());
- for (IPluginExtension extension : model.getExtensions().getExtensions()) {
- if (!Objects.equals(extension.getPoint(), ECORE_URI_MAPPING_EXTENSION_POINT)) {
- continue;
- }
- List<IPluginObject> pluginObjects = Arrays.stream(extension.getChildren()).filter(child -> Objects.equals("mapping", child.getName())).collect(Collectors.toList()); //$NON-NLS-1$
- pluginObjects.forEach(pluginObject -> {
- if ((pluginObject instanceof PluginElementNode)) {
- PluginElementNode node = (PluginElementNode) pluginObject;
- localMappings.put(node.getAttribute("source").getValue(), node.getAttribute("target").getValue()); //$NON-NLS-1$ //$NON-NLS-2$
+ /**
+ * Create a URI converter that supports not only the registered URI mappings in the target platform, but
+ * also {@linkplain #getLocalUriMappings(IProject) mappings in <tt>plugin.xml</tt> files in workspace projects}.
+ * Mappings from the workspace supersede the same prefixes in mappings from the target platform.
+ * And <tt>platform:/plugin</tt> URIs map into the workspace (and vice-versa) where applicable, per
+ * the {@linkplain #computePlatformResourceMap() platform resource map}.
+ *
+ * @return the workspace-inclusive URI converter
+ *
+ * @see ExtensibleURIConverterImpl#getURIMap()
+ * @see #getLocalUriMappings(IProject)
+ * @see #computePlatformResourceMap()
+ */
+ public static URIConverter createWorkspaceAwareURIConverter() {
+ URIConverter result = new ExtensibleURIConverterImpl();
+ Map<URI, URI> uriMap = result.getURIMap();
+
+ uriMap.putAll(computePlatformResourceMap());
+
+ for (IProject next : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
+ if (next.isAccessible()) {
+ Map<String, String> mappings = getLocalUriMappings(next);
+ for (Map.Entry<String, String> mapping : mappings.entrySet()) {
+ URI prefix = URI.createURI(mapping.getKey());
+ URI target = URI.createURI(mapping.getValue());
+
+ uriMap.put(prefix, target);
}
- });
+ }
}
- return localMappings;
+
+ return result;
+ }
+
+ /** Return the {@code org.eclipse.emf.ecore.uri_mapping} extension declarations in the given {@code project}. */
+ public static Map<String, String> getLocalUriMappings(IProject project) {
+ return PlatformHelper.INSTANCE.getLocalUriMappings(project);
}
/** Returns an encoded string representation of the path. */
@@ -181,4 +197,31 @@ public class ResourceUtils {
.collect(Collectors.joining(PATH_SEPARATOR));
}
+ /**
+ * Compute a mapping of <tt>platform:</tt> scheme URIs for maximal portability of cross-document
+ * references in resources that are saved (as almost always should be) using the
+ * {@linkplain org.eclipse.emf.ecore.xmi.impl.URIHandlerImpl.PlatformSchemeAware platform-scheme-aware URI handler}.
+ * That is the case for all resources saved using the {@linkplain #getSaveOptions() common Papyrus save options}.
+ * The resulting mapping forwards <tt>platform:/plugin/</tt> URIs to </tt>platform:/resource/</tt> for
+ * plug-in projects that are imported and open in the workspace and <tt>platform:/resource/</tt> to <tt>platform:/plugin/</tt>
+ * for all other plug-ins in the PDE Target.
+ *
+ * @return the platform URI mappings
+ *
+ * @see getSaveOptions()
+ * @see EcorePlugin#computePlatformPluginToPlatformResourceMap()
+ * @see EcorePlugin#computePlatformResourceToPlatformPluginMap(Collection)
+ */
+ public static Map<URI, URI> computePlatformResourceMap() {
+ Map<URI, URI> result = new HashMap<>();
+ result.putAll(EcorePlugin.computePlatformPluginToPlatformResourceMap());
+
+ List<URI> platform = PlatformHelper.INSTANCE.getPlatformBundleIDs().stream()
+ .map(name -> URI.createPlatformPluginURI(name, true))
+ .collect(Collectors.toList());
+ result.putAll(EcorePlugin.computePlatformResourceToPlatformPluginMap(platform));
+
+ return result;
+ }
+
}

Back to the top