Bug 286444 UI model and propagation of context values: add #modify()
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/context/IEclipseContext.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/context/IEclipseContext.java
index 4ed88ce..56dea9b 100644
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/context/IEclipseContext.java
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/context/IEclipseContext.java
@@ -174,6 +174,11 @@
/**
* Modifies the value to be associated with the given name.
* <p>
+ * The value has to be declared as modifiable by the original context before this method can be
+ * used. If the variable with this name has not been declared as modifiable, an
+ * {@link IllegalArgumentException} will be thrown.
+ * </p>
+ * <p>
* The value is modified in the context in which it has been previously set. If none of the
* contexts on the parent chain have a value set for the name, the value will be set in this
* context.
@@ -184,7 +189,18 @@
* @param value
* The value to be stored, or a {@link ContextFunction} that can return the stored
* value.
+ * @throws IllegalArgumentException
+ * if the variable has not been declared as modifiable
*/
public void modify(String name, Object value);
+ /**
+ * Declares the named value as modifiable by descendants of this context. If the value does not
+ * exist in this context, a <code>null</code> value added for the name.
+ *
+ * @param name
+ * the name to be declared as modifiable by descendants
+ */
+ public void declareModifiable(String name);
+
}
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/EclipseContext.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/EclipseContext.java
index 4ff31a1..7d270e9 100644
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/EclipseContext.java
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/internal/context/EclipseContext.java
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.e4.core.services.internal.context;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
@@ -230,6 +231,8 @@
private final IEclipseContextStrategy strategy;
+ private ArrayList modifiable;
+
public EclipseContext(IEclipseContext parent, IEclipseContextStrategy strategy) {
this.strategy = strategy;
set(IContextConstants.PARENT, parent);
@@ -469,6 +472,10 @@
public boolean internalModify(String name, Object value) {
boolean containsKey = localValues.containsKey(name);
if (containsKey) {
+ if (!checkModifiable(name)) {
+ String tmp = "Variable " + name + " is not modifiable in the context " + toString();
+ throw new IllegalArgumentException(tmp);
+ }
Object oldValue = localValues.put(name, value);
if (value != oldValue) {
if (DEBUG_VERBOSE)
@@ -504,4 +511,26 @@
computation.addDependency(this, name);
}
}
+
+ public void declareModifiable(String name) {
+ if (name == null)
+ return;
+ if (modifiable == null)
+ modifiable = new ArrayList(3);
+ modifiable.add(name);
+ if (localValues.containsKey(name))
+ return;
+ localValues.put(name, null);
+ }
+
+ private boolean checkModifiable(String name) {
+ if (modifiable == null)
+ return false;
+ for (Iterator i = modifiable.iterator(); i.hasNext();) {
+ String candidate = (String) i.next();
+ if (candidate.equals(name))
+ return true;
+ }
+ return false;
+ }
}
diff --git a/tests/org.eclipse.e4.core.tests.services/src/org/eclipse/e4/core/services/internal/context/EclipseContextTest.java b/tests/org.eclipse.e4.core.tests.services/src/org/eclipse/e4/core/services/internal/context/EclipseContextTest.java
index 52a9ef0..21b7c61 100644
--- a/tests/org.eclipse.e4.core.tests.services/src/org/eclipse/e4/core/services/internal/context/EclipseContextTest.java
+++ b/tests/org.eclipse.e4.core.tests.services/src/org/eclipse/e4/core/services/internal/context/EclipseContextTest.java
@@ -229,6 +229,10 @@
parent.set("b", "b2");
grandParent.set("c", "c3");
+ child.declareModifiable("a");
+ parent.declareModifiable("b");
+ grandParent.declareModifiable("c");
+
// test pre-conditions
assertNull(grandParent.get("b"));
assertEquals("b2", parent.get("b"));
@@ -266,6 +270,35 @@
assertFalse(grandParent.containsKey("a"));
assertEquals("aNew", child.get("a"));
assertNull(parent.get("a"));
+
+ // test access rules
+ child.set("aNo", "a1");
+ parent.set("bNo", "b2");
+ grandParent.set("cNo", "c3");
+
+ boolean exception = false;
+ try {
+ child.modify("bNo", "new");
+ } catch (IllegalArgumentException e) {
+ exception = true;
+ }
+ assertTrue(exception);
+
+ exception = false;
+ try {
+ grandParent.modify("cNo", "new");
+ } catch (IllegalArgumentException e) {
+ exception = true;
+ }
+ assertTrue(exception);
+
+ exception = false;
+ try {
+ child.modify("aNo", "new");
+ } catch (IllegalArgumentException e) {
+ exception = true;
+ }
+ assertTrue(exception);
}
public void testRemoveValueComputationOnDispose() {