Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2014-03-07 15:39:07 +0000
committerChristian W. Damus2014-03-07 21:45:37 +0000
commitf08cbd7b4497a17388bc220b8af9c60b93e2254b (patch)
tree50994b0208710b8ec44669651095b3551a61260e /plugins/infra
parentb97cafff961eaf540abf031e047b42674b7b68b0 (diff)
downloadorg.eclipse.papyrus-f08cbd7b4497a17388bc220b8af9c60b93e2254b.tar.gz
org.eclipse.papyrus-f08cbd7b4497a17388bc220b8af9c60b93e2254b.tar.xz
org.eclipse.papyrus-f08cbd7b4497a17388bc220b8af9c60b93e2254b.zip
429826: [Read-Only] Orthogonal Classification of Read-Only Concerns
https://bugs.eclipse.org/bugs/show_bug.cgi?id=429826 Add transaction options for enforcement of read-only state on axes selected by the client.
Diffstat (limited to 'plugins/infra')
-rw-r--r--plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/utils/TransactionHelper.java171
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomain.java54
2 files changed, 200 insertions, 25 deletions
diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/utils/TransactionHelper.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/utils/TransactionHelper.java
index 060c29865d2..a697a09ee26 100644
--- a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/utils/TransactionHelper.java
+++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/utils/TransactionHelper.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2014 CEA LIST.
+ * Copyright (c) 2014 CEA LIST and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,9 +8,21 @@
*
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 429826
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.core.utils;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.emf.transaction.Transaction;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
/**
* This helper can be used to run (safe) transactions outside the CommandStack
@@ -22,4 +34,161 @@ public class TransactionHelper extends org.eclipse.papyrus.infra.core.sasheditor
//Refactoring needed. The sasheditor contentprovider should have dependencies to infra.EMF...
+ public static final String TRANSACTION_OPTION_READ_ONLY_AXIS = "papyrus.read_only_axis"; //$NON-NLS-1$
+
+ public static final String TRANSACTION_OPTION_INTERACTIVE = "papyrus.interactive"; //$NON-NLS-1$
+
+ /**
+ * Merges the read-only {@code axis} option into an existing map of {@code options}.
+ *
+ * @param options
+ * an existing (non-{@code null}) options map
+ * @param axis
+ * the axis option to merge
+ * @return the augmented {@code options}
+ */
+ public static Map<String, Object> mergeReadOnlyAxisOption(Map<String, Object> options, ReadOnlyAxis axis) {
+ return mergeReadOnlyAxisOption(options, Collections.singleton(axis));
+ }
+
+ /**
+ * Merges the read-only {@code axes} option into an existing map of {@code options}.
+ *
+ * @param options
+ * an existing (non-{@code null}) options map
+ * @param axes
+ * the axes option to merge
+ * @return the augmented {@code options}
+ */
+ public static Map<String, Object> mergeReadOnlyAxisOption(Map<String, Object> options, Set<ReadOnlyAxis> axes) {
+ options.put(TRANSACTION_OPTION_READ_ONLY_AXIS, axes);
+ return options;
+ }
+
+ /**
+ * Adds the read-only {@code axis} option to a transaction's {@code options}.
+ *
+ * @param options
+ * an options map, which may be {@code null} or immutable
+ * @param axis
+ * the axis option to add
+ * @return a new map based on the {@code options} and including the {@code axis}
+ */
+ public static Map<String, Object> addReadOnlyAxisOption(Map<String, ?> options, ReadOnlyAxis axis) {
+ return addReadOnlyAxisOption(options, Collections.singleton(axis));
+ }
+
+ /**
+ * Adds the read-only {@code axes} option to a transaction's {@code options}.
+ *
+ * @param options
+ * an options map, which may be {@code null} or immutable
+ * @param axes
+ * the axes option to add
+ * @return a new map based on the {@code options} and including the {@code axes}
+ */
+ public static Map<String, Object> addReadOnlyAxisOption(Map<String, ?> options, Set<ReadOnlyAxis> axes) {
+ Map<String, Object> result = (options == null) ? Maps.<String, Object> newHashMap() : Maps.newHashMap(options);
+ result.put(TRANSACTION_OPTION_READ_ONLY_AXIS, axes);
+ return result;
+ }
+
+ /**
+ * Creates a new mutable transaction options map with a read-only {@code axis}.
+ *
+ * @param axis
+ * the axis option
+ * @return a new mutable map including the {@code axis}
+ */
+ public static Map<String, Object> readOnlyAxisOption(ReadOnlyAxis axis) {
+ return readOnlyAxisOption(Collections.singleton(axis));
+ }
+
+ /**
+ * Creates a new mutable transaction options map with a read-only {@code axes}.
+ *
+ * @param axes
+ * the axes option
+ * @return a new mutable map including the {@code axes}
+ */
+ public static Map<String, Object> readOnlyAxisOption(Set<ReadOnlyAxis> axes) {
+ return addReadOnlyAxisOption(null, axes);
+ }
+
+ /**
+ * Queries the read-only axes to be enforced by a {@code transaction}.
+ *
+ * @param transaction
+ * a transaction
+ * @return its read-only axes, which are {@linkplain ReadOnlyAxis#anyAxis() all of them} by default if the option is absent
+ */
+ @SuppressWarnings("unchecked")
+ public static Set<ReadOnlyAxis> getReadOnlyAxisOption(Transaction transaction) {
+ Set<ReadOnlyAxis> result;
+
+ Object value = transaction.getOptions().get(TRANSACTION_OPTION_READ_ONLY_AXIS);
+ if(value instanceof Set<?>) {
+ result = (Set<ReadOnlyAxis>)value;
+ } else if(value instanceof Iterable<?>) {
+ result = Sets.immutableEnumSet((Iterable<ReadOnlyAxis>)value);
+ } else {
+ result = ReadOnlyAxis.anyAxis();
+ }
+
+ return result;
+ }
+
+ /**
+ * Merges the {@code interactive} transaction option into an existing map of {@code options}.
+ *
+ * @param options
+ * an existing (non-{@code null}) options map
+ * @param interactive
+ * whether the transaction is in an user-interactive context
+ * @return the augmented {@code options}
+ */
+ public static Map<String, Object> mergeInteractiveOption(Map<String, Object> options, boolean interactive) {
+ options.put(TRANSACTION_OPTION_INTERACTIVE, interactive);
+ return options;
+ }
+
+ /**
+ * Adds the {@code interactive} option option to a transaction's {@code options}.
+ *
+ * @param options
+ * an options map, which may be {@code null} or immutable
+ * @param interactive
+ * whether the transaction is in an user-interactive context
+ * @return a new map based on the {@code options} and including the {@code interactive} option
+ */
+ public static Map<String, Object> addInteractiveOption(Map<String, ?> options, boolean interactive) {
+ Map<String, Object> result = (options == null) ? Maps.<String, Object> newHashMap() : Maps.newHashMap(options);
+ result.put(TRANSACTION_OPTION_INTERACTIVE, interactive);
+ return result;
+ }
+
+ /**
+ * Creates a new mutable transaction options map with an {@code interactive} option.
+ *
+ * @param interactive
+ * whether the transaction is in an user-interactive context
+ * @return a new mutable map including the {@code interactive} option
+ */
+ public static Map<String, Object> interactiveOption(boolean interactive) {
+ return addInteractiveOption(null, interactive);
+ }
+
+ /**
+ * Queries whether a {@code transaction} is running in a user-interactive context. In practice, this means that it would be appropriate to
+ * prompt the user to make resources/objects writable if necessary.
+ *
+ * @param transaction
+ * a transaction
+ * @return {@code false} if the {@code transaction} has the {@linkplain #TRANSACTION_OPTION_INTERACTIVE interactive option} set {@code false};
+ * {@code true}, otherwise (including the default case of no option set)
+ */
+ public static boolean isInteractive(Transaction transaction) {
+ Object value = transaction.getOptions().get(TRANSACTION_OPTION_INTERACTIVE);
+ return (value instanceof Boolean) ? (Boolean)value : true;
+ }
}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomain.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomain.java
index d5ee21d8470..ebbacd5b4be 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomain.java
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomain.java
@@ -16,6 +16,8 @@
*****************************************************************************/
package org.eclipse.papyrus.infra.emf.readonly;
+import static org.eclipse.papyrus.infra.core.utils.TransactionHelper.isInteractive;
+
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -31,7 +33,6 @@ 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.util.EcoreUtil;
import org.eclipse.emf.transaction.NotificationFilter;
import org.eclipse.emf.transaction.Transaction;
import org.eclipse.emf.transaction.TransactionalCommandStack;
@@ -42,6 +43,7 @@ import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2;
import org.eclipse.papyrus.infra.core.resource.IRollbackStatus;
import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
import org.eclipse.papyrus.infra.core.resource.RollbackStatus;
+import org.eclipse.papyrus.infra.core.utils.TransactionHelper;
import org.eclipse.papyrus.infra.onefile.model.IPapyrusFile;
import org.eclipse.papyrus.infra.onefile.model.PapyrusModelHelper;
import org.eclipse.papyrus.infra.onefile.utils.OneFileUtils;
@@ -55,14 +57,11 @@ public class PapyrusROTransactionalEditingDomain extends TransactionalEditingDom
@Override
public boolean isReadOnly(Resource resource) {
- if((resource != null) && (resource.getURI() != null)) {
- return ReadOnlyManager.getReadOnlyHandler(this).anyReadOnly(ReadOnlyAxis.anyAxis(), new URI[]{ resource.getURI() }).get();
- }
- return false;
+ return isReadOnly(ReadOnlyAxis.anyAxis(), resource);
}
public boolean isReadOnly(EObject eObject) {
- return ReadOnlyManager.getReadOnlyHandler(this).isReadOnly(ReadOnlyAxis.anyAxis(), eObject).get();
+ return isReadOnly(ReadOnlyAxis.anyAxis(), eObject);
}
@Override
@@ -99,6 +98,7 @@ public class PapyrusROTransactionalEditingDomain extends TransactionalEditingDom
&& !Boolean.TRUE.equals(tx.getOptions().get(Transaction.OPTION_UNPROTECTED)) //
&& !willRollBack(tx)) {
+ final Set<ReadOnlyAxis> axes = TransactionHelper.getReadOnlyAxisOption(tx);
boolean readOnly;
// Check for Resource first because CDO resources *are* EObjects
@@ -108,10 +108,12 @@ public class PapyrusROTransactionalEditingDomain extends TransactionalEditingDom
// We must be able to modify read-only resources in order to load them
return;
}
- readOnly = isReadOnly(resource) && !makeWritable(resource);
+ // If it's not an interactive transaction, don't try to make the resource writable because that would prompt the user
+ readOnly = isReadOnly(axes, resource) && !(isInteractive(tx) && makeWritable(axes, resource));
} else if(object instanceof EObject) {
EObject eObject = (EObject)object;
- readOnly = isReadOnly(eObject) && !makeWritable(eObject);
+ // If it's not an interactive transaction, don't try to make the object writable because that would prompt the user
+ readOnly = isReadOnly(axes, eObject) && !(isInteractive(tx) && makeWritable(axes, eObject));
} else {
// If it's not an EMF-managed object, we don't care
readOnly = false;
@@ -124,39 +126,43 @@ public class PapyrusROTransactionalEditingDomain extends TransactionalEditingDom
}
}
}
-
+
private boolean willRollBack(Transaction tx) {
IStatus status = tx.getStatus();
return (status != null) && (status.getSeverity() >= IStatus.ERROR);
}
- protected boolean makeWritable(Resource resource) {
+ protected boolean isReadOnly(Set<ReadOnlyAxis> axes, Resource resource) {
+ if((resource != null) && (resource.getURI() != null)) {
+ return ReadOnlyManager.getReadOnlyHandler(this).anyReadOnly(axes, new URI[]{ resource.getURI() }).get();
+ }
+ return false;
+ }
+
+ protected boolean isReadOnly(Set<ReadOnlyAxis> axes, EObject eObject) {
+ return ReadOnlyManager.getReadOnlyHandler(this).isReadOnly(axes, eObject).get();
+ }
+
+ protected boolean makeWritable(Set<ReadOnlyAxis> axes, Resource resource) {
URI[] uris = getCompositeModelURIs(resource.getURI());
IReadOnlyHandler2 handler = ReadOnlyManager.getReadOnlyHandler(this);
- if(!handler.canMakeWritable(ReadOnlyAxis.anyAxis(), uris).or(false)) {
+ if(!handler.canMakeWritable(axes, uris).or(false)) {
return false;
}
- return handler.makeWritable(ReadOnlyAxis.anyAxis(), uris).get();
+ return handler.makeWritable(axes, uris).get();
}
- protected boolean makeWritable(EObject object) {
+ protected boolean makeWritable(Set<ReadOnlyAxis> axes, EObject object) {
boolean result;
- URI uri = EcoreUtil.getURI(object);
+ IReadOnlyHandler2 handler = ReadOnlyManager.getReadOnlyHandler(this);
- // If it's a workspace resource, we don't have to worry about object-level read-only state
- if(uri.isPlatformResource()) {
- result = makeWritable(object.eResource());
+ if(!handler.canMakeWritable(axes, object).or(false)) {
+ result = false;
} else {
- IReadOnlyHandler2 handler = ReadOnlyManager.getReadOnlyHandler(this);
-
- if(!handler.canMakeWritable(ReadOnlyAxis.anyAxis(), object).or(false)) {
- result = false;
- } else {
- result = handler.makeWritable(ReadOnlyAxis.anyAxis(), object).get();
- }
+ result = handler.makeWritable(axes, object).get();
}
return result;

Back to the top