Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2016-02-11 21:38:52 +0000
committerChristian W. Damus2016-02-24 22:26:27 +0000
commit09fde7a4087685b065b7f1e40375686fb9f19f2a (patch)
tree36668c0515a08586179a74cefcf1dc6197311d70 /plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly
parent2f0dd86c51f8543f56a99cd4371965a01287fcaa (diff)
downloadorg.eclipse.papyrus-09fde7a4087685b065b7f1e40375686fb9f19f2a.tar.gz
org.eclipse.papyrus-09fde7a4087685b065b7f1e40375686fb9f19f2a.tar.xz
org.eclipse.papyrus-09fde7a4087685b065b7f1e40375686fb9f19f2a.zip
Bug 485220: [Architecture] Provide a more modular architecture
https://bugs.eclipse.org/bugs/show_bug.cgi?id=485220 Implement version management: PDE API Tooling and Oomph Version Management. Introduce two new plug-in projects to manage versioning using Oomph: * org.eclipse.papyrus.releng.main.release for the Main bundles and features * org.eclipse.papyrus.releng.dev.release for the Dev Tools Add new menu actions to the Dev Tools: * main menu bar: * synchronize POM and manifest versions * "Configure" context menu on bundle projects and MANIFEST.MF * optimize bundle dependencies and re-exports * update dependency version ranges to match current workspace and PDE target Remove obsolete menu actions from the Dev Tools: * main menu bar: * Set all Papyrus feature versions * Set all Papyrus plug-in versions * Set versions of all Papyrus dependencies in Papyrus plug-ins Fix versioning errors reported by PDE and Oomph. Ensure proper version ranges consistent with latest build target. Optimize the dependencies of all Papyrus Main bundles and Dev Tools. Remove version- and reexport-checking tests in the BundlesTests that are now not needed because, on the one hand, we now implement discrete bundle versioning (managed by PDE/Oomph) and on the other, we now use re-exports properly to ensure classpath consistency in clients of a bundle's API. Thorough overhaul of the "project editors" API, including: * rationalize the API interfaces * refactor the all-in-one PluginEditor class from the customization bundle to the project-editors bundle * update clients in the Customization and DSML Validation components * fix a bunch of operations that didn't work * add missing operations required by the new Dev Tools actions * complete some unimplemented APIs * add a comprehensive JUnit test suite covering all of the project-editors API Change-Id: I6a699d93909f61099226ceb994140f03ea99a70f
Diffstat (limited to 'plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly')
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/.project80
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/META-INF/MANIFEST.MF17
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/pom.xml4
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyManager.java1179
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/spi/IReadOnlyManagerProcessor.java4
5 files changed, 653 insertions, 631 deletions
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/.project b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/.project
index ebfa82252ba..0d1f05526ae 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/.project
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/.project
@@ -1,28 +1,52 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.eclipse.papyrus.infra.emf.readonly</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.papyrus.infra.emf.readonly</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.oomph.version.VersionBuilder</name>
+ <arguments>
+ <dictionary>
+ <key>check.maven.pom</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>ignore.lower.bound.dependency.ranges</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>release.path</key>
+ <value>/org.eclipse.papyrus.releng.main.release/release.xml</value>
+ </dictionary>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+ <nature>org.eclipse.oomph.version.VersionNature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/META-INF/MANIFEST.MF b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/META-INF/MANIFEST.MF
index 09cd9998ca9..9845b1cdb2b 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/META-INF/MANIFEST.MF
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/META-INF/MANIFEST.MF
@@ -2,19 +2,14 @@ Manifest-Version: 1.0
Export-Package: org.eclipse.papyrus.infra.emf.readonly,
org.eclipse.papyrus.infra.emf.readonly.internal;x-friends:="org.eclipse.papyrus.infra.ui.emf",
org.eclipse.papyrus.infra.emf.readonly.spi
-Require-Bundle: org.eclipse.papyrus.infra.onefile;bundle-version="1.2.0",
- org.eclipse.core.expressions;bundle-version="3.4.300",
- org.eclipse.emf.workspace;bundle-version="1.4.0",
- org.eclipse.gmf.runtime.common.core;bundle-version="1.4.1",
- org.eclipse.papyrus.infra.core.log;bundle-version="1.2.0",
- org.eclipse.papyrus.infra.emf.gmf;bundle-version="1.2.0",
- org.eclipse.papyrus.infra.core;bundle-version="1.2.0",
- org.eclipse.papyrus.infra.emf;bundle-version="1.2.0",
- com.google.guava;bundle-version="11.0.0",
- org.eclipse.papyrus.infra.tools;bundle-version="1.2.0"
+Require-Bundle: org.eclipse.papyrus.infra.onefile;bundle-version="[2.0.0,3.0.0)",
+ org.eclipse.gmf.runtime.common.core;bundle-version="[1.7.0,2.0.0)";visibility:=reexport,
+ org.eclipse.papyrus.infra.emf.gmf;bundle-version="[1.2.0,2.0.0)",
+ org.eclipse.papyrus.infra.core;bundle-version="[2.0.0,3.0.0)";visibility:=reexport,
+ org.eclipse.papyrus.infra.emf;bundle-version="[2.0.0,3.0.0)";visibility:=reexport
Bundle-Vendor: %providerName
Bundle-ActivationPolicy: lazy
-Bundle-Version: 1.2.0.qualifier
+Bundle-Version: 2.0.0.qualifier
Bundle-Name: %pluginName
Bundle-Localization: plugin
Bundle-ManifestVersion: 2
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/pom.xml b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/pom.xml
index ead630febec..c801f2cf18f 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/pom.xml
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/pom.xml
@@ -7,6 +7,6 @@
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.papyrus.infra.emf.readonly</artifactId>
- <version>1.2.0-SNAPSHOT</version>
+ <version>2.0.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
-</project>
+</project> \ No newline at end of file
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyManager.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyManager.java
index 83d35ab9af5..45ca48d7724 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyManager.java
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/ReadOnlyManager.java
@@ -1,589 +1,590 @@
-/*****************************************************************************
- * Copyright (c) 2011, 2016 Atos Origin, CEA, Christian W. Damus, and others.
- *
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Mathieu Velten (Atos Origin) mathieu.velten@atosorigin.com - Initial API and implementation
- * Christian W. Damus (CEA) - support non-IFile resources and object-level permissions (CDO)
- * Christian W. Damus (CEA) - bugs 323802, 429826, 422257, 437217
- * Christian W. Damus - bugs 457560, 463564, 485220
- *
- *****************************************************************************/
-package org.eclipse.papyrus.infra.emf.readonly;
-
-import static org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis.permissionAxes;
-
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import org.eclipse.core.runtime.IConfigurationElement;
-import org.eclipse.core.runtime.Platform;
-import org.eclipse.emf.common.util.URI;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.edit.domain.EditingDomain;
-import org.eclipse.papyrus.infra.core.resource.AbstractReadOnlyHandler;
-import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler;
-import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2;
-import org.eclipse.papyrus.infra.core.resource.IReadOnlyListener;
-import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
-import org.eclipse.papyrus.infra.core.resource.ReadOnlyEvent;
-
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.common.collect.MapMaker;
-
-
-public class ReadOnlyManager implements IReadOnlyHandler2 {
-
- // Use weak values because the values otherwise retain the keys (indirectly)
- protected static final ConcurrentMap<EditingDomain, IReadOnlyHandler2> roHandlers = new MapMaker().weakKeys().weakValues().makeMap();
-
- private final CopyOnWriteArrayList<IReadOnlyListener> listeners = new CopyOnWriteArrayList<IReadOnlyListener>();
-
- private final ReadOnlyCache cache;
-
- private IReadOnlyListener forwardingListener;
-
- public static IReadOnlyHandler2 getReadOnlyHandler(EditingDomain editingDomain) {
- IReadOnlyHandler2 roHandler = IReadOnlyHandler2.NULL;
-
- if (editingDomain != null) {
- roHandler = roHandlers.get(editingDomain);
- if (roHandler == null) {
- roHandler = new ReadOnlyManager(editingDomain);
- process((ReadOnlyManager) roHandler, editingDomain);
- IReadOnlyHandler2 existing = roHandlers.putIfAbsent(editingDomain, roHandler);
- if (existing != null) {
- // Another thread beat us to it since we checked for an existing instance
- ((ReadOnlyManager) roHandler).cache.dispose();
- roHandler = existing;
- }
- }
- }
-
- return roHandler;
- }
-
- private static void process(ReadOnlyManager manager, EditingDomain domain) {
- Activator.getDefault().getReadOnlyManagerProcessors().forEach(p -> p.processReadOnlyManager(manager, domain));
- }
-
- protected static class HandlerPriorityPair implements Comparable<HandlerPriorityPair> {
-
- public Class<?> handlerClass;
-
- public int priority;
-
- public Set<ReadOnlyAxis> axes;
-
- @Override
- public int compareTo(HandlerPriorityPair o) {
- if (o.priority > priority) {
- return 1;
- } else if (o.priority < priority) {
- return -1;
- } else {
- return 0;
- }
- }
- }
-
- protected static final Map<Class<?>, Set<ReadOnlyAxis>> orderedHandlerClasses;
-
- static {
- IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor("org.eclipse.papyrus.infra.emf.readonly", "readOnlyHandler");
-
- List<HandlerPriorityPair> handlerPriorityPairs = new LinkedList<HandlerPriorityPair>();
- Map<String, HandlerPriorityPair> idMap = new HashMap<String, HandlerPriorityPair>();
-
- for (IConfigurationElement elem : configElements) {
- if ("readOnlyHandler".equals(elem.getName())) {
- try {
- HandlerPriorityPair handlerPriorityPair = new HandlerPriorityPair();
- String className = elem.getAttribute("class");
- handlerPriorityPair.handlerClass = Platform.getBundle(elem.getContributor().getName()).loadClass(className);
-
- handlerPriorityPair.priority = Integer.parseInt(elem.getAttribute("priority"));
-
- IConfigurationElement[] affinities = elem.getChildren("affinity");
- if ((affinities == null) || (affinities.length == 0)) {
- // implicit affinity is with any axis
- handlerPriorityPair.axes = ReadOnlyAxis.anyAxis();
- } else {
- handlerPriorityPair.axes = EnumSet.noneOf(ReadOnlyAxis.class);
- for (IConfigurationElement next : affinities) {
- handlerPriorityPair.axes.add(ReadOnlyAxis.valueOf(next.getAttribute("axis").toUpperCase()));
- }
- }
-
- String id = elem.getAttribute("id");
- if (id != null) {
- // if any then the handler could be overrided by another registration
- HandlerPriorityPair oldHandler = idMap.get(id);
- if (oldHandler == null) {
- idMap.put(id, handlerPriorityPair);
- handlerPriorityPairs.add(handlerPriorityPair);
- } else {
- if (oldHandler.priority < handlerPriorityPair.priority) {
- handlerPriorityPairs.remove(oldHandler);
- handlerPriorityPairs.add(handlerPriorityPair);
- }
- }
- } else {
- // If none the handler can not be overrided
- handlerPriorityPairs.add(handlerPriorityPair);
- }
- } catch (Throwable t) {
- // FIXME: We need to catch Throwables because we rely on external contributions. It is required to also catch Errors (such as compilation errors).
- // Move this code to an initialization method, because if a throwable is not caught, this will prevent the whole class initialization
- Activator.log.error(t);
- }
- }
- }
-
- Collections.sort(handlerPriorityPairs);
-
- orderedHandlerClasses = new LinkedHashMap<Class<?>, Set<ReadOnlyAxis>>();
-
- for (HandlerPriorityPair next : handlerPriorityPairs) {
- orderedHandlerClasses.put(next.handlerClass, next.axes);
- }
- }
-
-
- @SuppressWarnings("deprecation")
- protected static IReadOnlyHandler2 create(final Class<?> handlerClass, EditingDomain editingDomain) {
- boolean isEditingDomainConstructor = true;
- Constructor<?> constructor = null;
- try {
- constructor = handlerClass.getConstructor(EditingDomain.class);
- if (constructor == null) {
- isEditingDomainConstructor = false;
- constructor = handlerClass.getConstructor();
- }
-
- if (IReadOnlyHandler2.class.isAssignableFrom(constructor.getDeclaringClass())) {
- if (isEditingDomainConstructor) {
- return (IReadOnlyHandler2) constructor.newInstance(editingDomain);
- } else {
- return (IReadOnlyHandler2) constructor.newInstance();
- }
- } else if (IReadOnlyHandler.class.isAssignableFrom(constructor.getDeclaringClass())) {
- if (isEditingDomainConstructor) {
- return AbstractReadOnlyHandler.adapt((IReadOnlyHandler) constructor.newInstance(editingDomain), editingDomain);
- } else {
- return AbstractReadOnlyHandler.adapt((IReadOnlyHandler) constructor.newInstance(), editingDomain);
- }
- } else if (org.eclipse.papyrus.infra.emf.readonly.IReadOnlyHandler.class.isAssignableFrom(constructor.getDeclaringClass())) {
- return new OldStyleHandlerAdapter((org.eclipse.papyrus.infra.emf.readonly.IReadOnlyHandler) constructor.newInstance(), editingDomain);
- }
- } catch (Exception e) {
- }
-
- return null;
- }
-
- protected Map<ReadOnlyAxis, IReadOnlyHandler2[]> orderedHandlersByAxis;
-
- public ReadOnlyManager(final EditingDomain editingDomain) {
- // Create our transaction cache
- cache = ReadOnlyCache.create(this, Activator.getDefault().getReadOnlyCacheExecutor());
-
- final Map<ReadOnlyAxis, List<IReadOnlyHandler2>> handlers = new EnumMap<ReadOnlyAxis, List<IReadOnlyHandler2>>(ReadOnlyAxis.class);
- cache.run(new Runnable() {
-
- @Override
- public void run() {
- for (Map.Entry<Class<?>, Set<ReadOnlyAxis>> roClass : orderedHandlerClasses.entrySet()) {
- IReadOnlyHandler2 h = create(roClass.getKey(), editingDomain);
- if (h != null) {
- h.addReadOnlyListener(getForwardingListener());
-
- for (ReadOnlyAxis axis : roClass.getValue()) {
- List<IReadOnlyHandler2> list = handlers.get(axis);
- if (list == null) {
- list = new ArrayList<IReadOnlyHandler2>();
- handlers.put(axis, list);
- }
- list.add(h);
- }
- }
- }
- }
- });
-
- // Iterate the enumeration to make sure all axes are represented (even if only by an empty array)
- orderedHandlersByAxis = new EnumMap<ReadOnlyAxis, IReadOnlyHandler2[]>(ReadOnlyAxis.class);
- for (ReadOnlyAxis axis : ReadOnlyAxis.values()) {
- List<IReadOnlyHandler2> list = handlers.get(axis);
- if (list == null) {
- orderedHandlersByAxis.put(axis, new IReadOnlyHandler2[0]);
- } else {
- orderedHandlersByAxis.put(axis, list.toArray(new IReadOnlyHandler2[list.size()]));
- }
- }
- }
-
- @Override
- public Optional<Boolean> anyReadOnly(Set<ReadOnlyAxis> axes, URI[] uris) {
- final Set<URI> uriSet = ImmutableSet.copyOf(uris);
- Optional<Boolean> result = cache.getResources(axes, uriSet);
- if (result == null) {
- result = Optional.absent();
-
- ReadOnlyAxis[] all = ReadOnlyAxis.values();
- for (int i = 0; (i < all.length) && !result.or(Boolean.FALSE); i++) {
- if (axes.contains(all[i])) {
- result = anyReadOnly(all[i], uris);
- }
- }
-
- cache.putResources(axes, uriSet, result);
- }
-
- return result.isPresent() ? result : Optional.of(Boolean.FALSE);
- }
-
- private Optional<Boolean> anyReadOnly(ReadOnlyAxis axis, URI[] uris) {
- final Set<URI> uriSet = ImmutableSet.copyOf(uris);
- Set<ReadOnlyAxis> axes = axis.singleton();
- Optional<Boolean> result = cache.getResources(axes, uriSet);
- if (result == null) {
- result = Optional.absent();
-
- IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
- for (int i = 0; (i < orderedHandlers.length) && !result.isPresent(); i++) {
- result = orderedHandlers[i].anyReadOnly(axes, uris);
- }
-
- cache.putResources(axes, uriSet, result);
- }
-
- return result.isPresent() ? result : Optional.of(Boolean.FALSE);
- }
-
- @Override
- public Optional<Boolean> isReadOnly(Set<ReadOnlyAxis> axes, EObject eObject) {
- Optional<Boolean> result = cache.getObject(axes, eObject);
- if (result == null) {
- result = Optional.absent();
-
- ReadOnlyAxis[] all = ReadOnlyAxis.values();
- for (int i = 0; (i < all.length) && !result.or(Boolean.FALSE); i++) {
- if (axes.contains(all[i])) {
- result = isReadOnly(all[i], eObject);
- }
- }
-
- cache.putObject(axes, eObject, result);
- }
-
- return result.isPresent() ? result : Optional.of(Boolean.FALSE);
- }
-
- private Optional<Boolean> isReadOnly(ReadOnlyAxis axis, EObject eObject) {
- Set<ReadOnlyAxis> axes = axis.singleton();
- Optional<Boolean> result = cache.getObject(axes, eObject);
- if (result == null) {
- result = Optional.absent();
-
- IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
- for (int i = 0; (i < orderedHandlers.length) && !result.isPresent(); i++) {
- result = orderedHandlers[i].isReadOnly(axes, eObject);
- }
-
- cache.putObject(axes, eObject, result);
- }
-
- return result.isPresent() ? result : Optional.of(Boolean.FALSE);
- }
-
- @Override
- public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, URI[] uris) {
- Boolean finalResult = true;
-
- ReadOnlyAxis[] all = ReadOnlyAxis.values();
- for (int i = 0; (i < all.length) && finalResult; i++) {
- if (axes.contains(all[i])) {
- finalResult = makeWritable(all[i], uris);
- }
- }
-
- return Optional.of(finalResult);
- }
-
- private Boolean makeWritable(ReadOnlyAxis axis, URI[] uris) {
- Set<ReadOnlyAxis> axes = axis.singleton();
- Boolean finalResult = true;
-
- try {
- IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
- for (int i = 0; (i < orderedHandlers.length); i++) {
- Optional<Boolean> isRO = orderedHandlers[i].anyReadOnly(axes, uris);
- if (isRO.or(Boolean.FALSE)) {
- Optional<Boolean> result = orderedHandlers[i].makeWritable(axes, uris);
- // makeWritable should provide an answer since anyReadOnly returned a positive value.
- // If no answer consider it a failure
- if (!result.or(Boolean.FALSE)) {
- finalResult = false;
- break;
- }
- }
- }
- } finally {
- cache.clear();
- }
-
- return finalResult;
- }
-
- @Override
- public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, EObject eObject) {
- Boolean finalResult = true;
-
- ReadOnlyAxis[] all = ReadOnlyAxis.values();
- for (int i = 0; (i < all.length) && finalResult; i++) {
- if (axes.contains(all[i])) {
- finalResult = makeWritable(all[i], eObject);
- }
- }
-
- return Optional.of(finalResult);
- }
-
- private Boolean makeWritable(ReadOnlyAxis axis, EObject eObject) {
- Set<ReadOnlyAxis> axes = axis.singleton();
- Boolean finalResult = true;
-
- try {
- IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
- for (int i = 0; (i < orderedHandlers.length); i++) {
- Optional<Boolean> isRO = orderedHandlers[i].isReadOnly(axes, eObject);
- if (isRO.or(Boolean.FALSE)) {
- Optional<Boolean> result = orderedHandlers[i].makeWritable(axes, eObject);
- // makeWritable should provide an answer since anyReadOnly returned a positive value
- // if no answer consider it a failure
- if (!result.or(Boolean.FALSE)) {
- finalResult = false;
- break;
- }
- }
- }
- } finally {
- cache.clear();
- }
-
- return finalResult;
- }
-
- @Override
- public Optional<Boolean> canMakeWritable(Set<ReadOnlyAxis> axes, URI[] uris) {
- Boolean result = false;
-
- ReadOnlyAxis[] all = ReadOnlyAxis.values();
- for (int i = 0; (i < all.length) && !result; i++) {
- if (axes.contains(all[i])) {
- result = canMakeWritable(all[i], uris);
- }
- }
-
- return Optional.of(result);
- }
-
- private Boolean canMakeWritable(ReadOnlyAxis axis, URI[] uris) {
- Set<ReadOnlyAxis> axes = axis.singleton();
- Boolean result = false;
-
- IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
- for (int i = 0; (i < orderedHandlers.length); i++) {
- if (orderedHandlers[i].anyReadOnly(axes, uris).or(false)) {
- // Only ask a handler about making writable what it considers to be read-only
- Optional<Boolean> canMakeWritable = orderedHandlers[i].canMakeWritable(axes, uris);
- if (canMakeWritable.isPresent()) {
- result = canMakeWritable.get();
- break;
- }
- }
- }
-
- return result;
- }
-
- @Override
- public Optional<Boolean> canMakeWritable(Set<ReadOnlyAxis> axes, EObject object) {
- Boolean result = false;
-
- ReadOnlyAxis[] all = ReadOnlyAxis.values();
- for (int i = 0; (i < all.length) && !result; i++) {
- if (axes.contains(all[i])) {
- result = canMakeWritable(all[i], object);
- }
- }
-
- return Optional.of(result);
- }
-
- private Boolean canMakeWritable(ReadOnlyAxis axis, EObject object) {
- Set<ReadOnlyAxis> axes = axis.singleton();
- Boolean result = false;
-
- IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
- for (int i = 0; (i < orderedHandlers.length); i++) {
- if (orderedHandlers[i].isReadOnly(axes, object).or(false)) {
- // Only ask a handler about making writable what it considers to be read-only
- Optional<Boolean> canMakeWritable = orderedHandlers[i].canMakeWritable(axes, object);
- if (canMakeWritable.isPresent()) {
- result = canMakeWritable.get();
- break;
- }
- }
- }
-
- return result;
- }
-
- @Override
- public void addReadOnlyListener(IReadOnlyListener listener) {
- listeners.addIfAbsent(listener);
- }
-
- @Override
- public void removeReadOnlyListener(IReadOnlyListener listener) {
- listeners.remove(listener);
- }
-
- private IReadOnlyListener getForwardingListener() {
- if (forwardingListener == null) {
- forwardingListener = new IReadOnlyListener() {
-
- @Override
- public void readOnlyStateChanged(ReadOnlyEvent event) {
- ReadOnlyEvent myEvent;
-
- switch (event.getEventType()) {
- case ReadOnlyEvent.OBJECT_READ_ONLY_STATE_CHANGED:
- myEvent = new ReadOnlyEvent(ReadOnlyManager.this, event.getAxis(), event.getObject(), event.isReadOnly());
- break;
- default:
- myEvent = new ReadOnlyEvent(ReadOnlyManager.this, event.getAxis(), event.getResourceURI(), event.isReadOnly());
- break;
- }
-
- notifyReadOnlyStateChanged(myEvent);
- }
- };
- }
-
- return forwardingListener;
- }
-
- protected void notifyReadOnlyStateChanged(ReadOnlyEvent event) {
- if (!listeners.isEmpty()) {
- for (IReadOnlyListener next : listeners) {
- try {
- next.readOnlyStateChanged(event);
- } catch (Exception e) {
- Activator.log.error("Uncaught exception in read-only state change listener.", e); //$NON-NLS-1$
- }
- }
- }
- }
-
- /**
- * Obtains a snapshot of the read-only handlers currently registered with me.
- *
- * @return my read-only handlers, by axis of affiliation. Changes to this collection
- * do not affect my registered handlers
- */
- public final Map<ReadOnlyAxis, Collection<IReadOnlyHandler2>> getReadOnlyHandlers() {
- Map<ReadOnlyAxis, Collection<IReadOnlyHandler2>> result = new HashMap<>();
-
- // Be sure not to provide lists that are actually backed by the arrays!
- orderedHandlersByAxis.forEach((axis, handlers) -> result.put(axis, Lists.newArrayList(handlers)));
-
- return result;
- }
-
- //
- // Deprecated API
- //
-
- @Override
- @Deprecated
- public Optional<Boolean> anyReadOnly(URI[] uris) {
- return anyReadOnly(permissionAxes(), uris);
- }
-
- @Override
- @Deprecated
- public Optional<Boolean> isReadOnly(EObject eObject) {
- return isReadOnly(permissionAxes(), eObject);
- }
-
- @Override
- @Deprecated
- public Optional<Boolean> makeWritable(URI[] uris) {
- return makeWritable(permissionAxes(), uris);
- }
-
- @Override
- @Deprecated
- public Optional<Boolean> makeWritable(EObject eObject) {
- return makeWritable(permissionAxes(), eObject);
- }
-
- //
- // Legacy adapters
- //
-
- @SuppressWarnings("deprecation")
- private static final class OldStyleHandlerAdapter extends AbstractReadOnlyHandler {
-
- private final org.eclipse.papyrus.infra.emf.readonly.IReadOnlyHandler delegate;
-
- OldStyleHandlerAdapter(org.eclipse.papyrus.infra.emf.readonly.IReadOnlyHandler handler, EditingDomain editingDomain) {
- super(editingDomain);
-
- this.delegate = handler;
- }
-
- @Override
- public Optional<Boolean> anyReadOnly(Set<ReadOnlyAxis> axes, URI[] uris) {
-
- // the old API contract is that handlers only return true if they
- // know it to be true, because the manager takes the first positive
- // answer. Moreover, they only dealt with permission-based read-only-ness
- boolean delegateResult = axes.contains(ReadOnlyAxis.PERMISSION) && delegate.isReadOnly(uris, getEditingDomain());
- return delegateResult ? Optional.of(Boolean.TRUE) : Optional.<Boolean> absent();
- }
-
- @Override
- public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, URI[] uris) {
-
- // the old API contract is that handlers only return false if they
- // tried to but could not make the resources writable, because the
- // manager takes the first negative answer (this is opposite to the
- // isReadOnly logic). Moreover, they only dealt with permission-based
- // read-only-ness
- boolean delegateResult = axes.contains(ReadOnlyAxis.PERMISSION) && delegate.enableWrite(uris, getEditingDomain());
- return delegateResult ? Optional.<Boolean> absent() : Optional.of(Boolean.FALSE);
- }
- }
-}
+/*****************************************************************************
+ * Copyright (c) 2011, 2016 Atos Origin, CEA, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathieu Velten (Atos Origin) mathieu.velten@atosorigin.com - Initial API and implementation
+ * Christian W. Damus (CEA) - support non-IFile resources and object-level permissions (CDO)
+ * Christian W. Damus (CEA) - bugs 323802, 429826, 422257, 437217
+ * Christian W. Damus - bugs 457560, 463564, 485220
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.emf.readonly;
+
+import static org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis.permissionAxes;
+
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.papyrus.infra.core.resource.AbstractReadOnlyHandler;
+import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler;
+import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2;
+import org.eclipse.papyrus.infra.core.resource.IReadOnlyListener;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyEvent;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.MapMaker;
+
+
+public class ReadOnlyManager implements IReadOnlyHandler2 {
+
+ // Use weak values because the values otherwise retain the keys (indirectly)
+ protected static final ConcurrentMap<EditingDomain, IReadOnlyHandler2> roHandlers = new MapMaker().weakKeys().weakValues().makeMap();
+
+ private final CopyOnWriteArrayList<IReadOnlyListener> listeners = new CopyOnWriteArrayList<IReadOnlyListener>();
+
+ private final ReadOnlyCache cache;
+
+ private IReadOnlyListener forwardingListener;
+
+ public static IReadOnlyHandler2 getReadOnlyHandler(EditingDomain editingDomain) {
+ IReadOnlyHandler2 roHandler = IReadOnlyHandler2.NULL;
+
+ if (editingDomain != null) {
+ roHandler = roHandlers.get(editingDomain);
+ if (roHandler == null) {
+ roHandler = new ReadOnlyManager(editingDomain);
+ process((ReadOnlyManager) roHandler, editingDomain);
+ IReadOnlyHandler2 existing = roHandlers.putIfAbsent(editingDomain, roHandler);
+ if (existing != null) {
+ // Another thread beat us to it since we checked for an existing instance
+ ((ReadOnlyManager) roHandler).cache.dispose();
+ roHandler = existing;
+ }
+ }
+ }
+
+ return roHandler;
+ }
+
+ private static void process(ReadOnlyManager manager, EditingDomain domain) {
+ Activator.getDefault().getReadOnlyManagerProcessors().forEach(p -> p.processReadOnlyManager(manager, domain));
+ }
+
+ protected static class HandlerPriorityPair implements Comparable<HandlerPriorityPair> {
+
+ public Class<?> handlerClass;
+
+ public int priority;
+
+ public Set<ReadOnlyAxis> axes;
+
+ @Override
+ public int compareTo(HandlerPriorityPair o) {
+ if (o.priority > priority) {
+ return 1;
+ } else if (o.priority < priority) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ protected static final Map<Class<?>, Set<ReadOnlyAxis>> orderedHandlerClasses;
+
+ static {
+ IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor("org.eclipse.papyrus.infra.emf.readonly", "readOnlyHandler");
+
+ List<HandlerPriorityPair> handlerPriorityPairs = new LinkedList<HandlerPriorityPair>();
+ Map<String, HandlerPriorityPair> idMap = new HashMap<String, HandlerPriorityPair>();
+
+ for (IConfigurationElement elem : configElements) {
+ if ("readOnlyHandler".equals(elem.getName())) {
+ try {
+ HandlerPriorityPair handlerPriorityPair = new HandlerPriorityPair();
+ String className = elem.getAttribute("class");
+ handlerPriorityPair.handlerClass = Platform.getBundle(elem.getContributor().getName()).loadClass(className);
+
+ handlerPriorityPair.priority = Integer.parseInt(elem.getAttribute("priority"));
+
+ IConfigurationElement[] affinities = elem.getChildren("affinity");
+ if ((affinities == null) || (affinities.length == 0)) {
+ // implicit affinity is with any axis
+ handlerPriorityPair.axes = ReadOnlyAxis.anyAxis();
+ } else {
+ handlerPriorityPair.axes = EnumSet.noneOf(ReadOnlyAxis.class);
+ for (IConfigurationElement next : affinities) {
+ handlerPriorityPair.axes.add(ReadOnlyAxis.valueOf(next.getAttribute("axis").toUpperCase()));
+ }
+ }
+
+ String id = elem.getAttribute("id");
+ if (id != null) {
+ // if any then the handler could be overrided by another registration
+ HandlerPriorityPair oldHandler = idMap.get(id);
+ if (oldHandler == null) {
+ idMap.put(id, handlerPriorityPair);
+ handlerPriorityPairs.add(handlerPriorityPair);
+ } else {
+ if (oldHandler.priority < handlerPriorityPair.priority) {
+ handlerPriorityPairs.remove(oldHandler);
+ handlerPriorityPairs.add(handlerPriorityPair);
+ }
+ }
+ } else {
+ // If none the handler can not be overrided
+ handlerPriorityPairs.add(handlerPriorityPair);
+ }
+ } catch (Throwable t) {
+ // FIXME: We need to catch Throwables because we rely on external contributions. It is required to also catch Errors (such as compilation errors).
+ // Move this code to an initialization method, because if a throwable is not caught, this will prevent the whole class initialization
+ Activator.log.error(t);
+ }
+ }
+ }
+
+ Collections.sort(handlerPriorityPairs);
+
+ orderedHandlerClasses = new LinkedHashMap<Class<?>, Set<ReadOnlyAxis>>();
+
+ for (HandlerPriorityPair next : handlerPriorityPairs) {
+ orderedHandlerClasses.put(next.handlerClass, next.axes);
+ }
+ }
+
+
+ @SuppressWarnings("deprecation")
+ protected static IReadOnlyHandler2 create(final Class<?> handlerClass, EditingDomain editingDomain) {
+ boolean isEditingDomainConstructor = true;
+ Constructor<?> constructor = null;
+ try {
+ constructor = handlerClass.getConstructor(EditingDomain.class);
+ if (constructor == null) {
+ isEditingDomainConstructor = false;
+ constructor = handlerClass.getConstructor();
+ }
+
+ if (IReadOnlyHandler2.class.isAssignableFrom(constructor.getDeclaringClass())) {
+ if (isEditingDomainConstructor) {
+ return (IReadOnlyHandler2) constructor.newInstance(editingDomain);
+ } else {
+ return (IReadOnlyHandler2) constructor.newInstance();
+ }
+ } else if (IReadOnlyHandler.class.isAssignableFrom(constructor.getDeclaringClass())) {
+ if (isEditingDomainConstructor) {
+ return AbstractReadOnlyHandler.adapt((IReadOnlyHandler) constructor.newInstance(editingDomain), editingDomain);
+ } else {
+ return AbstractReadOnlyHandler.adapt((IReadOnlyHandler) constructor.newInstance(), editingDomain);
+ }
+ } else if (org.eclipse.papyrus.infra.emf.readonly.IReadOnlyHandler.class.isAssignableFrom(constructor.getDeclaringClass())) {
+ return new OldStyleHandlerAdapter((org.eclipse.papyrus.infra.emf.readonly.IReadOnlyHandler) constructor.newInstance(), editingDomain);
+ }
+ } catch (Exception e) {
+ }
+
+ return null;
+ }
+
+ protected Map<ReadOnlyAxis, IReadOnlyHandler2[]> orderedHandlersByAxis;
+
+ public ReadOnlyManager(final EditingDomain editingDomain) {
+ // Create our transaction cache
+ cache = ReadOnlyCache.create(this, Activator.getDefault().getReadOnlyCacheExecutor());
+
+ final Map<ReadOnlyAxis, List<IReadOnlyHandler2>> handlers = new EnumMap<ReadOnlyAxis, List<IReadOnlyHandler2>>(ReadOnlyAxis.class);
+ cache.run(new Runnable() {
+
+ @Override
+ public void run() {
+ for (Map.Entry<Class<?>, Set<ReadOnlyAxis>> roClass : orderedHandlerClasses.entrySet()) {
+ IReadOnlyHandler2 h = create(roClass.getKey(), editingDomain);
+ if (h != null) {
+ h.addReadOnlyListener(getForwardingListener());
+
+ for (ReadOnlyAxis axis : roClass.getValue()) {
+ List<IReadOnlyHandler2> list = handlers.get(axis);
+ if (list == null) {
+ list = new ArrayList<IReadOnlyHandler2>();
+ handlers.put(axis, list);
+ }
+ list.add(h);
+ }
+ }
+ }
+ }
+ });
+
+ // Iterate the enumeration to make sure all axes are represented (even if only by an empty array)
+ orderedHandlersByAxis = new EnumMap<ReadOnlyAxis, IReadOnlyHandler2[]>(ReadOnlyAxis.class);
+ for (ReadOnlyAxis axis : ReadOnlyAxis.values()) {
+ List<IReadOnlyHandler2> list = handlers.get(axis);
+ if (list == null) {
+ orderedHandlersByAxis.put(axis, new IReadOnlyHandler2[0]);
+ } else {
+ orderedHandlersByAxis.put(axis, list.toArray(new IReadOnlyHandler2[list.size()]));
+ }
+ }
+ }
+
+ @Override
+ public Optional<Boolean> anyReadOnly(Set<ReadOnlyAxis> axes, URI[] uris) {
+ final Set<URI> uriSet = ImmutableSet.copyOf(uris);
+ Optional<Boolean> result = cache.getResources(axes, uriSet);
+ if (result == null) {
+ result = Optional.absent();
+
+ ReadOnlyAxis[] all = ReadOnlyAxis.values();
+ for (int i = 0; (i < all.length) && !result.or(Boolean.FALSE); i++) {
+ if (axes.contains(all[i])) {
+ result = anyReadOnly(all[i], uris);
+ }
+ }
+
+ cache.putResources(axes, uriSet, result);
+ }
+
+ return result.isPresent() ? result : Optional.of(Boolean.FALSE);
+ }
+
+ private Optional<Boolean> anyReadOnly(ReadOnlyAxis axis, URI[] uris) {
+ final Set<URI> uriSet = ImmutableSet.copyOf(uris);
+ Set<ReadOnlyAxis> axes = axis.singleton();
+ Optional<Boolean> result = cache.getResources(axes, uriSet);
+ if (result == null) {
+ result = Optional.absent();
+
+ IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
+ for (int i = 0; (i < orderedHandlers.length) && !result.isPresent(); i++) {
+ result = orderedHandlers[i].anyReadOnly(axes, uris);
+ }
+
+ cache.putResources(axes, uriSet, result);
+ }
+
+ return result.isPresent() ? result : Optional.of(Boolean.FALSE);
+ }
+
+ @Override
+ public Optional<Boolean> isReadOnly(Set<ReadOnlyAxis> axes, EObject eObject) {
+ Optional<Boolean> result = cache.getObject(axes, eObject);
+ if (result == null) {
+ result = Optional.absent();
+
+ ReadOnlyAxis[] all = ReadOnlyAxis.values();
+ for (int i = 0; (i < all.length) && !result.or(Boolean.FALSE); i++) {
+ if (axes.contains(all[i])) {
+ result = isReadOnly(all[i], eObject);
+ }
+ }
+
+ cache.putObject(axes, eObject, result);
+ }
+
+ return result.isPresent() ? result : Optional.of(Boolean.FALSE);
+ }
+
+ private Optional<Boolean> isReadOnly(ReadOnlyAxis axis, EObject eObject) {
+ Set<ReadOnlyAxis> axes = axis.singleton();
+ Optional<Boolean> result = cache.getObject(axes, eObject);
+ if (result == null) {
+ result = Optional.absent();
+
+ IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
+ for (int i = 0; (i < orderedHandlers.length) && !result.isPresent(); i++) {
+ result = orderedHandlers[i].isReadOnly(axes, eObject);
+ }
+
+ cache.putObject(axes, eObject, result);
+ }
+
+ return result.isPresent() ? result : Optional.of(Boolean.FALSE);
+ }
+
+ @Override
+ public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, URI[] uris) {
+ Boolean finalResult = true;
+
+ ReadOnlyAxis[] all = ReadOnlyAxis.values();
+ for (int i = 0; (i < all.length) && finalResult; i++) {
+ if (axes.contains(all[i])) {
+ finalResult = makeWritable(all[i], uris);
+ }
+ }
+
+ return Optional.of(finalResult);
+ }
+
+ private Boolean makeWritable(ReadOnlyAxis axis, URI[] uris) {
+ Set<ReadOnlyAxis> axes = axis.singleton();
+ Boolean finalResult = true;
+
+ try {
+ IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
+ for (int i = 0; (i < orderedHandlers.length); i++) {
+ Optional<Boolean> isRO = orderedHandlers[i].anyReadOnly(axes, uris);
+ if (isRO.or(Boolean.FALSE)) {
+ Optional<Boolean> result = orderedHandlers[i].makeWritable(axes, uris);
+ // makeWritable should provide an answer since anyReadOnly returned a positive value.
+ // If no answer consider it a failure
+ if (!result.or(Boolean.FALSE)) {
+ finalResult = false;
+ break;
+ }
+ }
+ }
+ } finally {
+ cache.clear();
+ }
+
+ return finalResult;
+ }
+
+ @Override
+ public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, EObject eObject) {
+ Boolean finalResult = true;
+
+ ReadOnlyAxis[] all = ReadOnlyAxis.values();
+ for (int i = 0; (i < all.length) && finalResult; i++) {
+ if (axes.contains(all[i])) {
+ finalResult = makeWritable(all[i], eObject);
+ }
+ }
+
+ return Optional.of(finalResult);
+ }
+
+ private Boolean makeWritable(ReadOnlyAxis axis, EObject eObject) {
+ Set<ReadOnlyAxis> axes = axis.singleton();
+ Boolean finalResult = true;
+
+ try {
+ IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
+ for (int i = 0; (i < orderedHandlers.length); i++) {
+ Optional<Boolean> isRO = orderedHandlers[i].isReadOnly(axes, eObject);
+ if (isRO.or(Boolean.FALSE)) {
+ Optional<Boolean> result = orderedHandlers[i].makeWritable(axes, eObject);
+ // makeWritable should provide an answer since anyReadOnly returned a positive value
+ // if no answer consider it a failure
+ if (!result.or(Boolean.FALSE)) {
+ finalResult = false;
+ break;
+ }
+ }
+ }
+ } finally {
+ cache.clear();
+ }
+
+ return finalResult;
+ }
+
+ @Override
+ public Optional<Boolean> canMakeWritable(Set<ReadOnlyAxis> axes, URI[] uris) {
+ Boolean result = false;
+
+ ReadOnlyAxis[] all = ReadOnlyAxis.values();
+ for (int i = 0; (i < all.length) && !result; i++) {
+ if (axes.contains(all[i])) {
+ result = canMakeWritable(all[i], uris);
+ }
+ }
+
+ return Optional.of(result);
+ }
+
+ private Boolean canMakeWritable(ReadOnlyAxis axis, URI[] uris) {
+ Set<ReadOnlyAxis> axes = axis.singleton();
+ Boolean result = false;
+
+ IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
+ for (int i = 0; (i < orderedHandlers.length); i++) {
+ if (orderedHandlers[i].anyReadOnly(axes, uris).or(false)) {
+ // Only ask a handler about making writable what it considers to be read-only
+ Optional<Boolean> canMakeWritable = orderedHandlers[i].canMakeWritable(axes, uris);
+ if (canMakeWritable.isPresent()) {
+ result = canMakeWritable.get();
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public Optional<Boolean> canMakeWritable(Set<ReadOnlyAxis> axes, EObject object) {
+ Boolean result = false;
+
+ ReadOnlyAxis[] all = ReadOnlyAxis.values();
+ for (int i = 0; (i < all.length) && !result; i++) {
+ if (axes.contains(all[i])) {
+ result = canMakeWritable(all[i], object);
+ }
+ }
+
+ return Optional.of(result);
+ }
+
+ private Boolean canMakeWritable(ReadOnlyAxis axis, EObject object) {
+ Set<ReadOnlyAxis> axes = axis.singleton();
+ Boolean result = false;
+
+ IReadOnlyHandler2[] orderedHandlers = orderedHandlersByAxis.get(axis);
+ for (int i = 0; (i < orderedHandlers.length); i++) {
+ if (orderedHandlers[i].isReadOnly(axes, object).or(false)) {
+ // Only ask a handler about making writable what it considers to be read-only
+ Optional<Boolean> canMakeWritable = orderedHandlers[i].canMakeWritable(axes, object);
+ if (canMakeWritable.isPresent()) {
+ result = canMakeWritable.get();
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public void addReadOnlyListener(IReadOnlyListener listener) {
+ listeners.addIfAbsent(listener);
+ }
+
+ @Override
+ public void removeReadOnlyListener(IReadOnlyListener listener) {
+ listeners.remove(listener);
+ }
+
+ private IReadOnlyListener getForwardingListener() {
+ if (forwardingListener == null) {
+ forwardingListener = new IReadOnlyListener() {
+
+ @Override
+ public void readOnlyStateChanged(ReadOnlyEvent event) {
+ ReadOnlyEvent myEvent;
+
+ switch (event.getEventType()) {
+ case ReadOnlyEvent.OBJECT_READ_ONLY_STATE_CHANGED:
+ myEvent = new ReadOnlyEvent(ReadOnlyManager.this, event.getAxis(), event.getObject(), event.isReadOnly());
+ break;
+ default:
+ myEvent = new ReadOnlyEvent(ReadOnlyManager.this, event.getAxis(), event.getResourceURI(), event.isReadOnly());
+ break;
+ }
+
+ notifyReadOnlyStateChanged(myEvent);
+ }
+ };
+ }
+
+ return forwardingListener;
+ }
+
+ protected void notifyReadOnlyStateChanged(ReadOnlyEvent event) {
+ if (!listeners.isEmpty()) {
+ for (IReadOnlyListener next : listeners) {
+ try {
+ next.readOnlyStateChanged(event);
+ } catch (Exception e) {
+ Activator.log.error("Uncaught exception in read-only state change listener.", e); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ /**
+ * Obtains a snapshot of the read-only handlers currently registered with me.
+ *
+ * @return my read-only handlers, by axis of affiliation. Changes to this collection
+ * do not affect my registered handlers
+ * @since 2.0
+ */
+ public final Map<ReadOnlyAxis, Collection<IReadOnlyHandler2>> getReadOnlyHandlers() {
+ Map<ReadOnlyAxis, Collection<IReadOnlyHandler2>> result = new HashMap<>();
+
+ // Be sure not to provide lists that are actually backed by the arrays!
+ orderedHandlersByAxis.forEach((axis, handlers) -> result.put(axis, Lists.newArrayList(handlers)));
+
+ return result;
+ }
+
+ //
+ // Deprecated API
+ //
+
+ @Override
+ @Deprecated
+ public Optional<Boolean> anyReadOnly(URI[] uris) {
+ return anyReadOnly(permissionAxes(), uris);
+ }
+
+ @Override
+ @Deprecated
+ public Optional<Boolean> isReadOnly(EObject eObject) {
+ return isReadOnly(permissionAxes(), eObject);
+ }
+
+ @Override
+ @Deprecated
+ public Optional<Boolean> makeWritable(URI[] uris) {
+ return makeWritable(permissionAxes(), uris);
+ }
+
+ @Override
+ @Deprecated
+ public Optional<Boolean> makeWritable(EObject eObject) {
+ return makeWritable(permissionAxes(), eObject);
+ }
+
+ //
+ // Legacy adapters
+ //
+
+ @SuppressWarnings("deprecation")
+ private static final class OldStyleHandlerAdapter extends AbstractReadOnlyHandler {
+
+ private final org.eclipse.papyrus.infra.emf.readonly.IReadOnlyHandler delegate;
+
+ OldStyleHandlerAdapter(org.eclipse.papyrus.infra.emf.readonly.IReadOnlyHandler handler, EditingDomain editingDomain) {
+ super(editingDomain);
+
+ this.delegate = handler;
+ }
+
+ @Override
+ public Optional<Boolean> anyReadOnly(Set<ReadOnlyAxis> axes, URI[] uris) {
+
+ // the old API contract is that handlers only return true if they
+ // know it to be true, because the manager takes the first positive
+ // answer. Moreover, they only dealt with permission-based read-only-ness
+ boolean delegateResult = axes.contains(ReadOnlyAxis.PERMISSION) && delegate.isReadOnly(uris, getEditingDomain());
+ return delegateResult ? Optional.of(Boolean.TRUE) : Optional.<Boolean> absent();
+ }
+
+ @Override
+ public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, URI[] uris) {
+
+ // the old API contract is that handlers only return false if they
+ // tried to but could not make the resources writable, because the
+ // manager takes the first negative answer (this is opposite to the
+ // isReadOnly logic). Moreover, they only dealt with permission-based
+ // read-only-ness
+ boolean delegateResult = axes.contains(ReadOnlyAxis.PERMISSION) && delegate.enableWrite(uris, getEditingDomain());
+ return delegateResult ? Optional.<Boolean> absent() : Optional.of(Boolean.FALSE);
+ }
+ }
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/spi/IReadOnlyManagerProcessor.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/spi/IReadOnlyManagerProcessor.java
index e56620c8fec..9fa0c779ada 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/spi/IReadOnlyManagerProcessor.java
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/spi/IReadOnlyManagerProcessor.java
@@ -18,7 +18,7 @@ import org.eclipse.papyrus.infra.emf.readonly.ReadOnlyManager;
/**
* <p>
- * An OSGi service interface for hooks to process the a new {@link ReadOnlyManager}
+ * An OSGi service interface for hooks to process a new {@link ReadOnlyManager}
* upon its creation. There is no special provision for notification of when the
* manager is no longer being used.
* </p>
@@ -26,6 +26,8 @@ import org.eclipse.papyrus.infra.emf.readonly.ReadOnlyManager;
* Any number of of implementations of this service may be registered; all will be
* invoked for each read-only manager.
* </p>
+ *
+ * @since 2.0
*/
@FunctionalInterface
public interface IReadOnlyManagerProcessor {

Back to the top