You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by md...@apache.org on 2012/07/25 15:07:41 UTC

svn commit: r1365564 [1/2] - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/core/ oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/ oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ oak-jcr/src/test/java/or...

Author: mduerig
Date: Wed Jul 25 13:07:40 2012
New Revision: 1365564

URL: http://svn.apache.org/viewvc?rev=1365564&view=rev
Log:
OAK-156  Observation events need Session refresh

Added:
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionOperation.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/ItemImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/NodeImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/PropertyImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionDelegate.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ObservationManagerImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java?rev=1365564&r1=1365563&r2=1365564&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java Wed Jul 25 13:07:40 2012
@@ -20,7 +20,7 @@ package org.apache.jackrabbit.oak.core;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
+
 import javax.annotation.Nonnull;
 
 import org.apache.jackrabbit.oak.api.ChangeExtractor;
@@ -84,12 +84,6 @@ public class RootImpl implements Root {
     }
 
     /**
-     * Reference to a {@code NodeState} of the revision up to which
-     * observation events are generated.
-     */
-    private final AtomicReference<NodeState> observationLimit;
-
-    /**
      * New instance bases on a given {@link NodeStore} and a workspace
      * @param store  node store
      * @param workspaceName  name of the workspace
@@ -98,7 +92,6 @@ public class RootImpl implements Root {
     @SuppressWarnings("UnusedParameters")
     public RootImpl(NodeStore store, String workspaceName) {
         this.store = store;
-        this.observationLimit = new AtomicReference<NodeState>(store.getRoot());
         branch = store.branch();
         rootTree = TreeImpl.createRoot(this);
     }
@@ -149,10 +142,6 @@ public class RootImpl implements Root {
 
     @Override
     public void refresh() {
-        // There is a small race here and we risk to get an "earlier" revision for the
-        // observation limit than for the branch. This is not a problem though since
-        // observation will catch up later on with the next call to ChangeExtractor.getChanges()
-        observationLimit.set(store.getRoot());
         branch = store.branch();
         rootTree = TreeImpl.createRoot(this);
     }
@@ -174,11 +163,11 @@ public class RootImpl implements Root {
     @Nonnull
     public ChangeExtractor getChangeExtractor() {
         return new ChangeExtractor() {
-            private NodeState baseLine = observationLimit.get();
+            private NodeState baseLine = store.getRoot();
 
             @Override
             public void getChanges(NodeStateDiff diff) {
-                NodeState head = observationLimit.get();
+                NodeState head = store.getRoot();
                 head.compareAgainstBaseState(baseLine, diff);
                 baseLine = head;
             }

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/ItemImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/ItemImpl.java?rev=1365564&r1=1365563&r2=1365564&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/ItemImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/ItemImpl.java Wed Jul 25 13:07:40 2012
@@ -54,9 +54,14 @@ abstract class ItemImpl<T extends ItemDe
     @Override
     @Nonnull
     public String getName() throws RepositoryException {
-        String oakName = dlg.getName();
-        // special case name of root node
-        return oakName.isEmpty() ? "" : toJcrPath(dlg.getName());
+        return sessionDelegate.perform(new SessionOperation<String>() {
+            @Override
+            public String perform() throws RepositoryException {
+                String oakName = dlg.getName();
+                // special case name of root node
+                return oakName.isEmpty() ? "" : toJcrPath(dlg.getName());
+            }
+        });
     }
 
     /**
@@ -65,7 +70,12 @@ abstract class ItemImpl<T extends ItemDe
     @Override
     @Nonnull
     public String getPath() throws RepositoryException {
-        return toJcrPath(dlg.getPath());
+        return sessionDelegate.perform(new SessionOperation<String>() {
+            @Override
+            public String perform() throws RepositoryException {
+                return toJcrPath(dlg.getPath());
+            }
+        });
     }
 
     @Override

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/NodeImpl.java?rev=1365564&r1=1365563&r2=1365564&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/NodeImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/NodeImpl.java Wed Jul 25 13:07:40 2012
@@ -110,11 +110,17 @@ public class NodeImpl extends ItemImpl<N
     @Nonnull
     public Node getParent() throws RepositoryException {
         checkStatus();
-        NodeDelegate parent = dlg.getParent();
-        if (parent == null) {
-            throw new ItemNotFoundException("Root has no parent");
-        }
-        return new NodeImpl(parent);
+
+        return sessionDelegate.perform(new SessionOperation<NodeImpl>() {
+            @Override
+            public NodeImpl perform() throws RepositoryException {
+                NodeDelegate parent = dlg.getParent();
+                if (parent == null) {
+                    throw new ItemNotFoundException("Root has no parent");
+                }
+                return new NodeImpl(parent);
+            }
+        });
     }
 
     /**
@@ -123,8 +129,14 @@ public class NodeImpl extends ItemImpl<N
     @Override
     public boolean isNew() {
         try {
-            return !dlg.isStale() && dlg.getStatus() == Status.NEW;
-        } catch (InvalidItemStateException e) {
+            return sessionDelegate.perform(new SessionOperation<Boolean>() {
+                @Override
+                public Boolean perform() throws InvalidItemStateException {
+                    return !dlg.isStale() && dlg.getStatus() == Status.NEW;
+                }
+            });
+        }
+        catch (RepositoryException e) {
             return false;
         }
     }
@@ -135,8 +147,14 @@ public class NodeImpl extends ItemImpl<N
     @Override
     public boolean isModified() {
         try {
-            return !dlg.isStale() && dlg.getStatus() == Status.MODIFIED;
-        } catch (InvalidItemStateException e) {
+            return sessionDelegate.perform(new SessionOperation<Boolean>() {
+                @Override
+                public Boolean perform() throws InvalidItemStateException {
+                    return !dlg.isStale() && dlg.getStatus() == Status.MODIFIED;
+                }
+            });
+        }
+        catch (RepositoryException e) {
             return false;
         }
     }
@@ -147,11 +165,18 @@ public class NodeImpl extends ItemImpl<N
     @Override
     public void remove() throws RepositoryException {
         checkStatus();
-        if (dlg.isRoot()) {
-            throw new RepositoryException("Cannot remove the root node");
-        }
 
-        dlg.remove();
+        sessionDelegate.perform(new SessionOperation<Void>() {
+            @Override
+            public Void perform() throws RepositoryException {
+                if (dlg.isRoot()) {
+                    throw new RepositoryException("Cannot remove the root node");
+                }
+
+                dlg.remove();
+                return null;
+            }
+        });
     }
 
     /**
@@ -176,71 +201,81 @@ public class NodeImpl extends ItemImpl<N
 
     @Override
     @Nonnull
-    public Node addNode(String relPath, String primaryNodeTypeName) throws RepositoryException {
+    public Node addNode(final String relPath, final String primaryNodeTypeName) throws RepositoryException {
         checkStatus();
 
-        String oakPath = sessionDelegate.getOakPathKeepIndexOrThrowNotFound(relPath);
-        String oakName = PathUtils.getName(oakPath);
-        String parentPath = sessionDelegate.getOakPathOrThrow(PathUtils.getParentPath(oakPath));
+        return sessionDelegate.perform(new SessionOperation<Node>() {
+            @Override
+            public Node perform() throws RepositoryException {
+                String oakPath = sessionDelegate.getOakPathKeepIndexOrThrowNotFound(relPath);
+                String oakName = PathUtils.getName(oakPath);
+                String parentPath = sessionDelegate.getOakPathOrThrow(PathUtils.getParentPath(oakPath));
+
+                // handle index
+                if (oakName.contains("[")) {
+                    throw new RepositoryException("Cannot create a new node using a name including an index");
+                }
 
-        // handle index
-        if (oakName.contains("[")) {
-            throw new RepositoryException("Cannot create a new node using a name including an index");
-        }
+                NodeDelegate parent = dlg.getChild(parentPath);
+                if (parent == null) {
+                    // is it a property?
+                    String grandParentPath = PathUtils.getParentPath(parentPath);
+                    NodeDelegate grandParent = dlg.getChild(grandParentPath);
+                    if (grandParent != null) {
+                        String propname = PathUtils.getName(parentPath);
+                        if (grandParent.getProperty(propname) != null) {
+                            throw new ConstraintViolationException("Can't add new node to property.");
+                        }
+                    }
 
-        NodeDelegate parent = dlg.getChild(parentPath);
-        if (parent == null) {
-            // is it a property?
-            String grandParentPath = PathUtils.getParentPath(parentPath);
-            NodeDelegate grandParent = dlg.getChild(grandParentPath);
-            if (grandParent != null) {
-                String propname = PathUtils.getName(parentPath);
-                if (grandParent.getProperty(propname) != null) {
-                    throw new ConstraintViolationException("Can't add new node to property.");
+                    throw new PathNotFoundException(relPath);
                 }
-            }
-
-            throw new PathNotFoundException(relPath);
-        }
 
-        if (parent.getChild(oakName) != null) {
-            throw new ItemExistsException(relPath);
-        }
+                if (parent.getChild(oakName) != null) {
+                    throw new ItemExistsException(relPath);
+                }
 
-        if (primaryNodeTypeName == null) {
-            // TODO retrieve matching nt from effective definition based on name-matching.
-            primaryNodeTypeName = NodeType.NT_UNSTRUCTURED;
-        }
+                // TODO retrieve matching nt from effective definition based on name-matching.
+                String ntName = primaryNodeTypeName == null ? NodeType.NT_UNSTRUCTURED : primaryNodeTypeName;
 
-        // TODO: figure out the right place for this check
-        NodeTypeManager ntm = sessionDelegate.getNodeTypeManager();
-        NodeType nt = ntm.getNodeType(primaryNodeTypeName); // throws on not found
-        if (nt.isAbstract() || nt.isMixin()) {
-            throw new ConstraintViolationException();
-        }
-        // TODO: END
+                // TODO: figure out the right place for this check
+                NodeTypeManager ntm = sessionDelegate.getNodeTypeManager();
+                NodeType nt = ntm.getNodeType(ntName); // throws on not found
+                if (nt.isAbstract() || nt.isMixin()) {
+                    throw new ConstraintViolationException();
+                }
+                // TODO: END
 
-        NodeDelegate added = parent.addChild(oakName);
-        if (added == null) {
-            throw new ItemExistsException();
-        }
+                NodeDelegate added = parent.addChild(oakName);
+                if (added == null) {
+                    throw new ItemExistsException();
+                }
 
-        Node childNode = new NodeImpl(added);
-        childNode.setPrimaryType(primaryNodeTypeName);
-        return childNode;
+                Node childNode = new NodeImpl(added);
+                childNode.setPrimaryType(ntName);
+                return childNode;
+            }
+        });
     }
 
     @Override
-    public void orderBefore(String srcChildRelPath, String destChildRelPath) throws RepositoryException {
+    public void orderBefore(final String srcChildRelPath, final String destChildRelPath) throws RepositoryException {
         checkStatus();
-        String oakSrcChildRelPath =
-                sessionDelegate.getOakPathOrThrowNotFound(srcChildRelPath);
-        String oakDestChildRelPath = null;
-        if (destChildRelPath != null) {
-            oakDestChildRelPath =
-                    sessionDelegate.getOakPathOrThrowNotFound(destChildRelPath);
-        }
-        dlg.orderBefore(oakSrcChildRelPath, oakDestChildRelPath);
+
+        sessionDelegate.perform(new SessionOperation<Void>() {
+            @Override
+            public Void perform() throws RepositoryException {
+                String oakSrcChildRelPath =
+                        sessionDelegate.getOakPathOrThrowNotFound(srcChildRelPath);
+                String oakDestChildRelPath = null;
+                if (destChildRelPath != null) {
+                    oakDestChildRelPath =
+                            sessionDelegate.getOakPathOrThrowNotFound(destChildRelPath);
+                }
+                dlg.orderBefore(oakSrcChildRelPath, oakDestChildRelPath);
+                return null;
+            }
+        });
     }
 
     /**
@@ -261,22 +296,27 @@ public class NodeImpl extends ItemImpl<N
      */
     @Override
     @CheckForNull
-    public Property setProperty(String jcrName, Value value, int type)
+    public Property setProperty(final String jcrName, final Value value, final int type)
             throws RepositoryException {
         checkStatus();
 
-        String oakName = sessionDelegate.getOakPathOrThrow(jcrName);
-        if (value == null) {
-            dlg.removeProperty(oakName);
-            return null;
-        } else {
-            int targetType = getTargetType(value, type);
-            Value targetValue =
-                    ValueHelper.convert(value, targetType, getValueFactory());
-            CoreValue oakValue =
-                    ValueConverter.toCoreValue(targetValue, sessionDelegate);
-            return new PropertyImpl(dlg.setProperty(oakName, oakValue));
-        }
+        return sessionDelegate.perform(new SessionOperation<PropertyImpl>() {
+            @Override
+            public PropertyImpl perform() throws RepositoryException {
+                String oakName = sessionDelegate.getOakPathOrThrow(jcrName);
+                if (value == null) {
+                    dlg.removeProperty(oakName);
+                    return null;
+                } else {
+                    int targetType = getTargetType(value, type);
+                    Value targetValue =
+                            ValueHelper.convert(value, targetType, getValueFactory());
+                    CoreValue oakValue =
+                            ValueConverter.toCoreValue(targetValue, sessionDelegate);
+                    return new PropertyImpl(dlg.setProperty(oakName, oakValue));
+                }
+            }
+        });
     }
 
     /**
@@ -296,20 +336,25 @@ public class NodeImpl extends ItemImpl<N
 
     @Override
     @Nonnull
-    public Property setProperty(String jcrName, Value[] values, int type) throws RepositoryException {
+    public Property setProperty(final String jcrName, final Value[] values, final int type) throws RepositoryException {
         checkStatus();
 
-        int targetType = getTargetType(values, type);
-        Value[] targetValues = ValueHelper.convert(values, targetType, getValueFactory());
-        if (targetValues == null) {
-            Property p = getProperty(jcrName);
-            p.remove();
-            return p;
-        } else {
-            String oakName = sessionDelegate.getOakPathOrThrow(jcrName);
-            List<CoreValue> oakValue = ValueConverter.toCoreValues(targetValues, sessionDelegate);
-            return new PropertyImpl(dlg.setProperty(oakName, oakValue));
-        }
+        return sessionDelegate.perform(new SessionOperation<Property>() {
+            @Override
+            public Property perform() throws RepositoryException {
+                int targetType = getTargetType(values, type);
+                Value[] targetValues = ValueHelper.convert(values, targetType, getValueFactory());
+                if (targetValues == null) {
+                    Property p = getProperty(jcrName);
+                    p.remove();
+                    return p;
+                } else {
+                    String oakName = sessionDelegate.getOakPathOrThrow(jcrName);
+                    List<CoreValue> oakValue = ValueConverter.toCoreValues(targetValues, sessionDelegate);
+                    return new PropertyImpl(dlg.setProperty(oakName, oakValue));
+                }
+            }
+        });
     }
 
     /**
@@ -436,17 +481,22 @@ public class NodeImpl extends ItemImpl<N
 
     @Override
     @Nonnull
-    public Node getNode(String relPath) throws RepositoryException {
+    public Node getNode(final String relPath) throws RepositoryException {
         checkStatus();
 
-        String oakPath = sessionDelegate.getOakPathOrThrowNotFound(relPath);
+        return sessionDelegate.perform(new SessionOperation<NodeImpl>() {
+            @Override
+            public NodeImpl perform() throws RepositoryException {
+                String oakPath = sessionDelegate.getOakPathOrThrowNotFound(relPath);
 
-        NodeDelegate nd = dlg.getChild(oakPath);
-        if (nd == null) {
-            throw new PathNotFoundException(relPath);
-        } else {
-            return new NodeImpl(nd);
-        }
+                NodeDelegate nd = dlg.getChild(oakPath);
+                if (nd == null) {
+                    throw new PathNotFoundException(relPath);
+                } else {
+                    return new NodeImpl(nd);
+                }
+            }
+        });
     }
 
     @Override
@@ -454,9 +504,14 @@ public class NodeImpl extends ItemImpl<N
     public NodeIterator getNodes() throws RepositoryException {
         checkStatus();
 
-        Iterator<NodeDelegate> children = dlg.getChildren();
-        long size = dlg.getChildCount();
-        return new NodeIteratorAdapter(nodeIterator(children), size);
+        return sessionDelegate.perform(new SessionOperation<NodeIterator>() {
+            @Override
+            public NodeIterator perform() throws RepositoryException {
+                Iterator<NodeDelegate> children = dlg.getChildren();
+                long size = dlg.getChildCount();
+                return new NodeIteratorAdapter(nodeIterator(children), size);
+            }
+        });
     }
 
     @Override
@@ -465,20 +520,24 @@ public class NodeImpl extends ItemImpl<N
             throws RepositoryException {
         checkStatus();
 
-        Iterator<NodeDelegate> children = Iterators.filter(
-                dlg.getChildren(),
-                new Predicate<NodeDelegate>() {
-                    @Override
-                    public boolean apply(NodeDelegate state) {
-                        try {
-                            return ItemNameMatcher.matches(toJcrPath(state.getName()), namePattern);
-                        } catch (InvalidItemStateException e) {
-                            return false;
-                        }
-                    }
-                });
+        return sessionDelegate.perform(new SessionOperation<NodeIterator>() {
+            @Override
+            public NodeIterator perform() throws RepositoryException {
+                Iterator<NodeDelegate> children = Iterators.filter(dlg.getChildren(),
+                        new Predicate<NodeDelegate>() {
+                            @Override
+                            public boolean apply(NodeDelegate state) {
+                                try {
+                                    return ItemNameMatcher.matches(toJcrPath(state.getName()), namePattern);
+                                } catch (InvalidItemStateException e) {
+                                    return false;
+                                }
+                            }
+                        });
 
-        return new NodeIteratorAdapter(nodeIterator(children));
+                return new NodeIteratorAdapter(nodeIterator(children));
+            }
+        });
     }
 
     @Override
@@ -486,34 +545,43 @@ public class NodeImpl extends ItemImpl<N
     public NodeIterator getNodes(final String[] nameGlobs) throws RepositoryException {
         checkStatus();
 
-        Iterator<NodeDelegate> children = Iterators.filter(
-                dlg.getChildren(),
-                new Predicate<NodeDelegate>() {
-                    @Override
-                    public boolean apply(NodeDelegate state) {
-                        try {
-                            return ItemNameMatcher.matches(toJcrPath(state.getName()), nameGlobs);
-                        } catch (InvalidItemStateException e) {
-                            return false;
-                        }
-                    }
-                });
+        return sessionDelegate.perform(new SessionOperation<NodeIterator>() {
+            @Override
+            public NodeIterator perform() throws RepositoryException {
+                Iterator<NodeDelegate> children = Iterators.filter(dlg.getChildren(),
+                        new Predicate<NodeDelegate>() {
+                            @Override
+                            public boolean apply(NodeDelegate state) {
+                                try {
+                                    return ItemNameMatcher.matches(toJcrPath(state.getName()), nameGlobs);
+                                } catch (InvalidItemStateException e) {
+                                    return false;
+                                }
+                            }
+                        });
 
-        return new NodeIteratorAdapter(nodeIterator(children));
+                return new NodeIteratorAdapter(nodeIterator(children));
+            }
+        });
     }
 
     @Override
     @Nonnull
-    public Property getProperty(String relPath) throws RepositoryException {
+    public Property getProperty(final String relPath) throws RepositoryException {
         checkStatus();
 
-        String oakPath = sessionDelegate.getOakPathOrThrowNotFound(relPath);
-        PropertyDelegate pd = dlg.getProperty(oakPath);
-        if (pd == null) {
-            throw new PathNotFoundException(relPath + " not found on " + getPath());
-        } else {
-            return new PropertyImpl(pd);
-        }
+        return sessionDelegate.perform(new SessionOperation<PropertyImpl>() {
+            @Override
+            public PropertyImpl perform() throws RepositoryException {
+                String oakPath = sessionDelegate.getOakPathOrThrowNotFound(relPath);
+                PropertyDelegate pd = dlg.getProperty(oakPath);
+                if (pd == null) {
+                    throw new PathNotFoundException(relPath + " not found on " + getPath());
+                } else {
+                    return new PropertyImpl(pd);
+                }
+            }
+        });
     }
 
     @Override
@@ -521,9 +589,14 @@ public class NodeImpl extends ItemImpl<N
     public PropertyIterator getProperties() throws RepositoryException {
         checkStatus();
 
-        Iterator<PropertyDelegate> properties = dlg.getProperties();
-        long size = dlg.getPropertyCount();
-        return new PropertyIteratorAdapter(propertyIterator(properties), size);
+        return sessionDelegate.perform(new SessionOperation<PropertyIterator>() {
+            @Override
+            public PropertyIterator perform() throws RepositoryException {
+                Iterator<PropertyDelegate> properties = dlg.getProperties();
+                long size = dlg.getPropertyCount();
+                return new PropertyIteratorAdapter(propertyIterator(properties), size);
+            }
+        });
     }
 
     @Override
@@ -531,20 +604,24 @@ public class NodeImpl extends ItemImpl<N
     public PropertyIterator getProperties(final String namePattern) throws RepositoryException {
         checkStatus();
 
-        Iterator<PropertyDelegate> properties = Iterators.filter(
-                dlg.getProperties(),
-                new Predicate<PropertyDelegate>() {
-                    @Override
-                    public boolean apply(PropertyDelegate entry) {
-                        try {
-                            return ItemNameMatcher.matches(toJcrPath(entry.getName()), namePattern);
-                        } catch (InvalidItemStateException e) {
-                            return false;
-                        }
-                    }
-                });
+        return sessionDelegate.perform(new SessionOperation<PropertyIterator>() {
+            @Override
+            public PropertyIterator perform() throws RepositoryException {
+                Iterator<PropertyDelegate> properties = Iterators.filter(dlg.getProperties(),
+                        new Predicate<PropertyDelegate>() {
+                            @Override
+                            public boolean apply(PropertyDelegate entry) {
+                                try {
+                                    return ItemNameMatcher.matches(toJcrPath(entry.getName()), namePattern);
+                                } catch (InvalidItemStateException e) {
+                                    return false;
+                                }
+                            }
+                        });
 
-        return new PropertyIteratorAdapter(propertyIterator(properties));
+                return new PropertyIteratorAdapter(propertyIterator(properties));
+            }
+        });
     }
 
     @Override
@@ -552,20 +629,24 @@ public class NodeImpl extends ItemImpl<N
     public PropertyIterator getProperties(final String[] nameGlobs) throws RepositoryException {
         checkStatus();
 
-        Iterator<PropertyDelegate> propertyNames = Iterators.filter(
-                dlg.getProperties(),
-                new Predicate<PropertyDelegate>() {
-                    @Override
-                    public boolean apply(PropertyDelegate entry) {
-                        try {
-                            return ItemNameMatcher.matches(toJcrPath(entry.getName()), nameGlobs);
-                        } catch (InvalidItemStateException e) {
-                            return false;
-                        }
-                    }
-                });
+        return sessionDelegate.perform(new SessionOperation<PropertyIterator>() {
+            @Override
+            public PropertyIterator perform() throws RepositoryException {
+                Iterator<PropertyDelegate> propertyNames = Iterators.filter(dlg.getProperties(),
+                        new Predicate<PropertyDelegate>() {
+                            @Override
+                            public boolean apply(PropertyDelegate entry) {
+                                try {
+                                    return ItemNameMatcher.matches(toJcrPath(entry.getName()), nameGlobs);
+                                } catch (InvalidItemStateException e) {
+                                    return false;
+                                }
+                            }
+                        });
 
-        return new PropertyIteratorAdapter(propertyIterator(propertyNames));
+                return new PropertyIteratorAdapter(propertyIterator(propertyNames));
+            }
+        });
     }
 
     /**
@@ -575,17 +656,23 @@ public class NodeImpl extends ItemImpl<N
     @Nonnull
     public Item getPrimaryItem() throws RepositoryException {
         checkStatus();
-        String name = getPrimaryNodeType().getPrimaryItemName();
-        if (name == null) {
-            throw new ItemNotFoundException("No primary item present on node " + this);
-        }
-        if (hasProperty(name)) {
-            return getProperty(name);
-        } else if (hasNode(name)) {
-            return getNode(name);
-        } else {
-            throw new ItemNotFoundException("Primary item " + name + " does not exist on node " + this);
-        }
+
+        return sessionDelegate.perform(new SessionOperation<Item>() {
+            @Override
+            public Item perform() throws RepositoryException {
+                String name = getPrimaryNodeType().getPrimaryItemName();
+                if (name == null) {
+                    throw new ItemNotFoundException("No primary item present on node " + this);
+                }
+                if (hasProperty(name)) {
+                    return getProperty(name);
+                } else if (hasNode(name)) {
+                    return getNode(name);
+                } else {
+                    throw new ItemNotFoundException("Primary item " + name + " does not exist on node " + this);
+                }
+            }
+        });
     }
 
     /**
@@ -596,18 +683,29 @@ public class NodeImpl extends ItemImpl<N
     public String getUUID() throws RepositoryException {
         checkStatus();
 
-        if (isNodeType(NodeType.MIX_REFERENCEABLE)) {
-            return getIdentifier();
-        }
+        return sessionDelegate.perform(new SessionOperation<String>() {
+            @Override
+            public String perform() throws RepositoryException {
+                if (isNodeType(NodeType.MIX_REFERENCEABLE)) {
+                    return getIdentifier();
+                }
 
-        throw new UnsupportedRepositoryOperationException("Node is not referenceable.");
+                throw new UnsupportedRepositoryOperationException("Node is not referenceable.");
+            }
+        });
     }
 
     @Override
     @Nonnull
     public String getIdentifier() throws RepositoryException {
         checkStatus();
-        return dlg.getIdentifier();
+
+        return sessionDelegate.perform(new SessionOperation<String>() {
+            @Override
+            public String perform() throws RepositoryException {
+                return dlg.getIdentifier();
+            }
+        });
     }
 
     @Override
@@ -630,11 +728,16 @@ public class NodeImpl extends ItemImpl<N
     public PropertyIterator getReferences(String name) throws RepositoryException {
         checkStatus();
 
-        if (!isNodeType(JcrConstants.MIX_REFERENCEABLE)) {
-            return PropertyIteratorAdapter.EMPTY;
-        } else {
-            throw new UnsupportedRepositoryOperationException("TODO: Node.getReferences");
-        }
+        return sessionDelegate.perform(new SessionOperation<PropertyIterator>() {
+            @Override
+            public PropertyIterator perform() throws RepositoryException {
+                if (!isNodeType(JcrConstants.MIX_REFERENCEABLE)) {
+                    return PropertyIteratorAdapter.EMPTY;
+                } else {
+                    throw new UnsupportedRepositoryOperationException("TODO: Node.getReferences");
+                }
+            }
+        });
     }
 
     /**
@@ -651,41 +754,66 @@ public class NodeImpl extends ItemImpl<N
     public PropertyIterator getWeakReferences(String name) throws RepositoryException {
         checkStatus();
 
-        if (!isNodeType(JcrConstants.MIX_REFERENCEABLE)) {
-            return PropertyIteratorAdapter.EMPTY;
-        } else {
-            throw new UnsupportedRepositoryOperationException("TODO: Node.getWeakReferences");
-        }
+        return sessionDelegate.perform(new SessionOperation<PropertyIterator>() {
+            @Override
+            public PropertyIterator perform() throws RepositoryException {
+                if (!isNodeType(JcrConstants.MIX_REFERENCEABLE)) {
+                    return PropertyIteratorAdapter.EMPTY;
+                } else {
+                    throw new UnsupportedRepositoryOperationException("TODO: Node.getWeakReferences");
+                }
+            }
+        });
     }
 
     @Override
-    public boolean hasNode(String relPath) throws RepositoryException {
+    public boolean hasNode(final String relPath) throws RepositoryException {
         checkStatus();
 
-        String oakPath = sessionDelegate.getOakPathOrThrow(relPath);
-        return dlg.getChild(oakPath) != null;
+        return sessionDelegate.perform(new SessionOperation<Boolean>() {
+            @Override
+            public Boolean perform() throws RepositoryException {
+                String oakPath = sessionDelegate.getOakPathOrThrow(relPath);
+                return dlg.getChild(oakPath) != null;
+            }
+        });
     }
 
     @Override
-    public boolean hasProperty(String relPath) throws RepositoryException {
+    public boolean hasProperty(final String relPath) throws RepositoryException {
         checkStatus();
 
-        String oakPath = sessionDelegate.getOakPathOrThrow(relPath);
-        return dlg.getProperty(oakPath) != null;
+        return sessionDelegate.perform(new SessionOperation<Boolean>() {
+            @Override
+            public Boolean perform() throws RepositoryException {
+                String oakPath = sessionDelegate.getOakPathOrThrow(relPath);
+                return dlg.getProperty(oakPath) != null;
+            }
+        });
     }
 
     @Override
     public boolean hasNodes() throws RepositoryException {
         checkStatus();
 
-        return dlg.getChildCount() != 0;
+        return sessionDelegate.perform(new SessionOperation<Boolean>() {
+            @Override
+            public Boolean perform() throws RepositoryException {
+                return dlg.getChildCount() != 0;
+            }
+        });
     }
 
     @Override
     public boolean hasProperties() throws RepositoryException {
         checkStatus();
 
-        return dlg.getPropertyCount() != 0;
+        return sessionDelegate.perform(new SessionOperation<Boolean>() {
+            @Override
+            public Boolean perform() throws RepositoryException {
+                return dlg.getPropertyCount() != 0;
+            }
+        });
     }
 
     /**
@@ -696,14 +824,19 @@ public class NodeImpl extends ItemImpl<N
     public NodeType getPrimaryNodeType() throws RepositoryException {
         checkStatus();
 
-        // TODO: check if transient changes to mixin-types are reflected here
-        NodeTypeManager ntMgr = sessionDelegate.getNodeTypeManager();
-        String primaryNtName;
-        primaryNtName = hasProperty(Property.JCR_PRIMARY_TYPE)
-            ? getProperty(Property.JCR_PRIMARY_TYPE).getString()
-            : NodeType.NT_UNSTRUCTURED;
+        return sessionDelegate.perform(new SessionOperation<NodeType>() {
+            @Override
+            public NodeType perform() throws RepositoryException {
+                // TODO: check if transient changes to mixin-types are reflected here
+                NodeTypeManager ntMgr = sessionDelegate.getNodeTypeManager();
+                String primaryNtName;
+                primaryNtName = hasProperty(Property.JCR_PRIMARY_TYPE)
+                        ? getProperty(Property.JCR_PRIMARY_TYPE).getString()
+                        : NodeType.NT_UNSTRUCTURED;
 
-        return ntMgr.getNodeType(primaryNtName);
+                return ntMgr.getNodeType(primaryNtName);
+            }
+        });
     }
 
     /**
@@ -714,129 +847,162 @@ public class NodeImpl extends ItemImpl<N
     public NodeType[] getMixinNodeTypes() throws RepositoryException {
         checkStatus();
 
-        // TODO: check if transient changes to mixin-types are reflected here
-        if (hasProperty(Property.JCR_MIXIN_TYPES)) {
-            NodeTypeManager ntMgr = sessionDelegate.getNodeTypeManager();
-            Value[] mixinNames = getProperty(Property.JCR_MIXIN_TYPES).getValues();
-            NodeType[] mixinTypes = new NodeType[mixinNames.length];
-            for (int i = 0; i < mixinNames.length; i++) {
-                mixinTypes[i] = ntMgr.getNodeType(mixinNames[i].getString());
+        return sessionDelegate.perform(new SessionOperation<NodeType[]>() {
+            @Override
+            public NodeType[] perform() throws RepositoryException {
+                // TODO: check if transient changes to mixin-types are reflected here
+                if (hasProperty(Property.JCR_MIXIN_TYPES)) {
+                    NodeTypeManager ntMgr = sessionDelegate.getNodeTypeManager();
+                    Value[] mixinNames = getProperty(Property.JCR_MIXIN_TYPES).getValues();
+                    NodeType[] mixinTypes = new NodeType[mixinNames.length];
+                    for (int i = 0; i < mixinNames.length; i++) {
+                        mixinTypes[i] = ntMgr.getNodeType(mixinNames[i].getString());
+                    }
+                    return mixinTypes;
+                } else {
+                    return new NodeType[0];
+                }
             }
-            return mixinTypes;
-        } else {
-            return new NodeType[0];
-        }
+        });
     }
 
     @Override
-    public boolean isNodeType(String nodeTypeName) throws RepositoryException {
+    public boolean isNodeType(final String nodeTypeName) throws RepositoryException {
         checkStatus();
 
-        // TODO: might be expanded, need a better way for this
-        NameMapper mapper = sessionDelegate.getNamePathMapper();
-        String oakName = mapper.getOakName(nodeTypeName);
-        if (oakName == null) {
-            return false; // An unknown name can't belong to a valid type
-        }
-        String jcrName = mapper.getJcrName(oakName);
+        return sessionDelegate.perform(new SessionOperation<Boolean>() {
+            @Override
+            public Boolean perform() throws RepositoryException {
+                // TODO: might be expanded, need a better way for this
+                NameMapper mapper = sessionDelegate.getNamePathMapper();
+                String oakName = mapper.getOakName(nodeTypeName);
+                if (oakName == null) {
+                    return false; // An unknown name can't belong to a valid type
+                }
+                String jcrName = mapper.getJcrName(oakName);
 
-        // TODO: figure out the right place for this check
-        NodeTypeManager ntm = sessionDelegate.getNodeTypeManager();
-        NodeType ntToCheck = ntm.getNodeType(jcrName); // throws on not found
-        String nameToCheck = ntToCheck.getName();
+                // TODO: figure out the right place for this check
+                NodeTypeManager ntm = sessionDelegate.getNodeTypeManager();
+                NodeType ntToCheck = ntm.getNodeType(jcrName); // throws on not found
+                String nameToCheck = ntToCheck.getName();
 
-        NodeType currentPrimaryType = getPrimaryNodeType();
-        if (currentPrimaryType.isNodeType(nameToCheck)) {
-            return true;
-        }
+                NodeType currentPrimaryType = getPrimaryNodeType();
+                if (currentPrimaryType.isNodeType(nameToCheck)) {
+                    return true;
+                }
 
-        for (NodeType mixin : getMixinNodeTypes()) {
-            if (mixin.isNodeType(nameToCheck)) {
-                return true;
-            }
-        }
-        // TODO: END
+                for (NodeType mixin : getMixinNodeTypes()) {
+                    if (mixin.isNodeType(nameToCheck)) {
+                        return true;
+                    }
+                }
+                // TODO: END
 
-        return false;
+                return false;
+            }
+        });
     }
 
     @Override
-    public void setPrimaryType(String nodeTypeName) throws RepositoryException {
+    public void setPrimaryType(final String nodeTypeName) throws RepositoryException {
         checkStatus();
 
-        // TODO: figure out the right place for this check
-        NodeTypeManager ntm = sessionDelegate.getNodeTypeManager();
-        NodeType nt = ntm.getNodeType(nodeTypeName); // throws on not found
-        if (nt.isAbstract() || nt.isMixin()) {
-            throw new ConstraintViolationException();
-        }
-        // TODO: END
+        sessionDelegate.perform(new SessionOperation<Void>() {
+            @Override
+            public Void perform() throws RepositoryException {
+                // TODO: figure out the right place for this check
+                NodeTypeManager ntm = sessionDelegate.getNodeTypeManager();
+                NodeType nt = ntm.getNodeType(nodeTypeName); // throws on not found
+                if (nt.isAbstract() || nt.isMixin()) {
+                    throw new ConstraintViolationException();
+                }
+                // TODO: END
 
-        String jcrPrimaryType = sessionDelegate.getOakPathOrThrow(Property.JCR_PRIMARY_TYPE);
-        CoreValue cv = ValueConverter.toCoreValue(nodeTypeName, PropertyType.NAME, sessionDelegate);
-        dlg.setProperty(jcrPrimaryType, cv);
+                String jcrPrimaryType = sessionDelegate.getOakPathOrThrow(Property.JCR_PRIMARY_TYPE);
+                CoreValue cv = ValueConverter.toCoreValue(nodeTypeName, PropertyType.NAME, sessionDelegate);
+                dlg.setProperty(jcrPrimaryType, cv);
+                return null;
+            }
+        });
     }
 
     @Override
-    public void addMixin(String mixinName) throws RepositoryException {
+    public void addMixin(final String mixinName) throws RepositoryException {
         checkStatus();
-        // TODO: figure out the right place for this check
-        NodeTypeManager ntm = sessionDelegate.getNodeTypeManager();
-        NodeType nt = ntm.getNodeType(mixinName); // throws on not found
-        // TODO: END
-
-        String jcrMixinTypes = sessionDelegate.getOakPathOrThrow(Property.JCR_MIXIN_TYPES);
-        PropertyDelegate mixins = dlg.getProperty(jcrMixinTypes);
-
-        CoreValue cv = ValueConverter.toCoreValue(mixinName, PropertyType.NAME, sessionDelegate);
 
-        boolean nodeModified = false;
+        sessionDelegate.perform(new SessionOperation<Void>() {
+            @Override
+            public Void perform() throws RepositoryException {
+                // TODO: figure out the right place for this check
+                NodeTypeManager ntm = sessionDelegate.getNodeTypeManager();
+                NodeType nt = ntm.getNodeType(mixinName); // throws on not found
+                // TODO: END
+
+                String jcrMixinTypes = sessionDelegate.getOakPathOrThrow(Property.JCR_MIXIN_TYPES);
+                PropertyDelegate mixins = dlg.getProperty(jcrMixinTypes);
+
+                CoreValue cv = ValueConverter.toCoreValue(mixinName, PropertyType.NAME, sessionDelegate);
+
+                boolean nodeModified = false;
+
+                if (mixins == null) {
+                    nodeModified = true;
+                    dlg.setProperty(jcrMixinTypes, Collections.singletonList(cv));
+                } else {
+                    List<CoreValue> values = new ArrayList<CoreValue>();
+                    for (CoreValue existingValue : mixins.getValues()) {
+                        if (!values.contains(existingValue)) {
+                            values.add(existingValue);
+                        }
+                    }
+                    if (!values.contains(cv)) {
+                        values.add(cv);
+                        nodeModified = true;
+                        dlg.setProperty(jcrMixinTypes, values);
+                    }
+                }
 
-        if (mixins == null) {
-            nodeModified = true;
-            dlg.setProperty(jcrMixinTypes, Collections.singletonList(cv));
-        } else {
-            List<CoreValue> values = new ArrayList<CoreValue>();
-            for (CoreValue existingValue : mixins.getValues()) {
-                if (!values.contains(existingValue)) {
-                    values.add(existingValue);
+                // TODO: hack -- make sure we assign a UUID
+                if (nodeModified && nt.isNodeType(NodeType.MIX_REFERENCEABLE)) {
+                    String jcrUuid = sessionDelegate.getOakPathOrThrow(Property.JCR_UUID);
+                    dlg.setProperty(jcrUuid, ValueConverter.toCoreValue(UUID.randomUUID().toString(), PropertyType.STRING, sessionDelegate));
                 }
+                return null;
             }
-            if (!values.contains(cv)) {
-                values.add(cv);
-                nodeModified = true;
-                dlg.setProperty(jcrMixinTypes, values);
-            }
-        }
-
-        // TODO: hack -- make sure we assign a UUID
-        if (nodeModified && nt.isNodeType(NodeType.MIX_REFERENCEABLE)) {
-            String jcrUuid = sessionDelegate.getOakPathOrThrow(Property.JCR_UUID);
-            dlg.setProperty(jcrUuid, ValueConverter.toCoreValue(UUID.randomUUID().toString(), PropertyType.STRING, sessionDelegate));
-        }
+        });
     }
 
     @Override
-    public void removeMixin(String mixinName) throws RepositoryException {
+    public void removeMixin(final String mixinName) throws RepositoryException {
         checkStatus();
 
-        if (!isNodeType(mixinName)) {
-            throw new NoSuchNodeTypeException();
-        }
+        sessionDelegate.perform(new SessionOperation<Void>() {
+            @Override
+            public Void perform() throws RepositoryException {
+                if (!isNodeType(mixinName)) {
+                    throw new NoSuchNodeTypeException();
+                }
 
-        throw new ConstraintViolationException();
+                throw new ConstraintViolationException();
+            }
+        });
     }
 
     @Override
-    public boolean canAddMixin(String mixinName) throws RepositoryException {
+    public boolean canAddMixin(final String mixinName) throws RepositoryException {
         checkStatus();
 
-        // TODO: figure out the right place for this check
-        NodeTypeManager ntm = sessionDelegate.getNodeTypeManager();
-        ntm.getNodeType(mixinName); // throws on not found
-        // TODO: END
+        return sessionDelegate.perform(new SessionOperation<Boolean>() {
+            @Override
+            public Boolean perform() throws RepositoryException {
+                // TODO: figure out the right place for this check
+                NodeTypeManager ntm = sessionDelegate.getNodeTypeManager();
+                ntm.getNodeType(mixinName); // throws on not found
+                // TODO: END
 
-        return isSupportedMixinName(mixinName);
+                return isSupportedMixinName(mixinName);
+            }
+        });
     }
 
     @Override

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/PropertyImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/PropertyImpl.java?rev=1365564&r1=1365563&r2=1365564&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/PropertyImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/PropertyImpl.java Wed Jul 25 13:07:40 2012
@@ -24,7 +24,6 @@ import java.util.List;
 
 import javax.annotation.Nonnull;
 import javax.jcr.Binary;
-import javax.jcr.InvalidItemStateException;
 import javax.jcr.ItemNotFoundException;
 import javax.jcr.ItemVisitor;
 import javax.jcr.Node;
@@ -71,7 +70,12 @@ public class PropertyImpl extends ItemIm
     @Override
     @Nonnull
     public Node getParent() throws RepositoryException {
-        return new NodeImpl(dlg.getParent());
+        return sessionDelegate.perform(new SessionOperation<NodeImpl>() {
+            @Override
+            public NodeImpl perform() throws RepositoryException {
+                return new NodeImpl(dlg.getParent());
+            }
+        });
     }
 
     /**
@@ -80,9 +84,14 @@ public class PropertyImpl extends ItemIm
     @Override
     public boolean isNew() {
         try {
-            return dlg.getStatus() == Status.NEW;
+            return sessionDelegate.perform(new SessionOperation<Boolean>() {
+                @Override
+                public Boolean perform() throws RepositoryException {
+                    return dlg.getStatus() == Status.NEW;
+                }
+            });
         }
-        catch (InvalidItemStateException e) {
+        catch (RepositoryException e) {
             return false;
         }
     }
@@ -93,9 +102,14 @@ public class PropertyImpl extends ItemIm
     @Override
     public boolean isModified() {
         try {
-            return dlg.getStatus() == Status.MODIFIED;
+            return sessionDelegate.perform(new SessionOperation<Boolean>() {
+                @Override
+                public Boolean perform() throws RepositoryException {
+                    return dlg.getStatus() == Status.MODIFIED;
+                }
+            });
         }
-        catch (InvalidItemStateException e) {
+        catch (RepositoryException e) {
             return false;
         }
     }
@@ -106,7 +120,14 @@ public class PropertyImpl extends ItemIm
     @Override
     public void remove() throws RepositoryException {
         checkStatus();
-        dlg.remove();
+
+        sessionDelegate.perform(new SessionOperation<Void>() {
+            @Override
+            public Void perform() throws RepositoryException {
+                dlg.remove();
+                return null;
+            }
+        });
     }
 
     /**
@@ -135,30 +156,36 @@ public class PropertyImpl extends ItemIm
      * @see Property#setValue(Value[])
      */
     @Override
-    public void setValue(Value[] values) throws RepositoryException {
+    public void setValue(final Value[] values) throws RepositoryException {
         checkStatus();
 
-        // assert equal types for all values entries
-        int valueType = PropertyType.UNDEFINED;
-        if (values != null) {
-            for (Value value : values) {
-                if (value == null) {
-                    // skip null values as those will be purged later
-                    continue;
-                }
-                if (valueType == PropertyType.UNDEFINED) {
-                    valueType = value.getType();
-                }
-                else if (valueType != value.getType()) {
-                    String msg = "Inhomogeneous type of values (" + this + ')';
-                    log.debug(msg);
-                    throw new ValueFormatException(msg);
+        sessionDelegate.perform(new SessionOperation<Void>() {
+            @Override
+            public Void perform() throws RepositoryException {
+                // assert equal types for all values entries
+                int valueType = PropertyType.UNDEFINED;
+                if (values != null) {
+                    for (Value value : values) {
+                        if (value == null) {
+                            // skip null values as those will be purged later
+                            continue;
+                        }
+                        if (valueType == PropertyType.UNDEFINED) {
+                            valueType = value.getType();
+                        }
+                        else if (valueType != value.getType()) {
+                            String msg = "Inhomogeneous type of values (" + this + ')';
+                            log.debug(msg);
+                            throw new ValueFormatException(msg);
+                        }
+                    }
                 }
-            }
-        }
 
-        int reqType = getRequiredType(valueType);
-        setValues(values, reqType);
+                int reqType = getRequiredType(valueType);
+                setValues(values, reqType);
+                return null;
+            }
+        });
     }
 
     /**
@@ -310,22 +337,34 @@ public class PropertyImpl extends ItemIm
     @Nonnull
     public Value getValue() throws RepositoryException {
         checkStatus();
-        if (isMultiple()) {
-            throw new ValueFormatException(this + " is multi-valued.");
-        }
 
-        return ValueConverter.toValue(dlg.getValue(), sessionDelegate);
+        return sessionDelegate.perform(new SessionOperation<Value>() {
+            @Override
+            public Value perform() throws RepositoryException {
+                if (isMultiple()) {
+                    throw new ValueFormatException(this + " is multi-valued.");
+                }
+
+                return ValueConverter.toValue(dlg.getValue(), sessionDelegate);
+            }
+        });
     }
 
     @Override
     @Nonnull
     public Value[] getValues() throws RepositoryException {
         checkStatus();
-        if (!isMultiple()) {
-            throw new ValueFormatException(this + " is not multi-valued.");
-        }
 
-        return ValueConverter.toValues(dlg.getValues(), sessionDelegate);
+        return sessionDelegate.perform(new SessionOperation<Value[]>() {
+            @Override
+            public Value[] perform() throws RepositoryException {
+                if (!isMultiple()) {
+                    throw new ValueFormatException(this + " is not multi-valued.");
+                }
+
+                return ValueConverter.toValues(dlg.getValues(), sessionDelegate);
+            }
+        });
     }
 
     /**
@@ -404,48 +443,53 @@ public class PropertyImpl extends ItemIm
     @Override
     @Nonnull
     public Node getNode() throws RepositoryException {
-        Value value = getValue();
-        switch (value.getType()) {
-            case PropertyType.REFERENCE:
-            case PropertyType.WEAKREFERENCE:
-                return getSession().getNodeByIdentifier(value.getString());
-
-            case PropertyType.PATH:
-            case PropertyType.NAME:
-                String path = value.getString();
-                if (path.startsWith("[") && path.endsWith("]")) {
-                    // TODO OAK-23
-                    // TODO correct for NAME?
-                    return getSession().getNodeByIdentifier(path.substring(1, path.length() - 1));
-                }
-                else {
-                    try {
-                        return (path.charAt(0) == '/') ? getSession().getNode(path) : getParent().getNode(path);
-                    } catch (PathNotFoundException e) {
-                        throw new ItemNotFoundException(path);
-                    }
-                }
+        return sessionDelegate.perform(new SessionOperation<Node>() {
+            @Override
+            public Node perform() throws RepositoryException {
+                Value value = getValue();
+                switch (value.getType()) {
+                    case PropertyType.REFERENCE:
+                    case PropertyType.WEAKREFERENCE:
+                        return getSession().getNodeByIdentifier(value.getString());
+
+                    case PropertyType.PATH:
+                    case PropertyType.NAME:
+                        String path = value.getString();
+                        if (path.startsWith("[") && path.endsWith("]")) {
+                            // TODO OAK-23
+                            // TODO correct for NAME?
+                            return getSession().getNodeByIdentifier(path.substring(1, path.length() - 1));
+                        }
+                        else {
+                            try {
+                                return (path.charAt(0) == '/') ? getSession().getNode(path) : getParent().getNode(path);
+                            } catch (PathNotFoundException e) {
+                                throw new ItemNotFoundException(path);
+                            }
+                        }
+
+                    case PropertyType.STRING:
+                        try {
+                            Value refValue = ValueHelper.convert(value, PropertyType.REFERENCE, getValueFactory());
+                            return getSession().getNodeByIdentifier(refValue.getString());
+                        } catch (ItemNotFoundException e) {
+                            throw e;
+                        } catch (RepositoryException e) {
+                            // try if STRING value can be interpreted as PATH value
+                            Value pathValue = ValueHelper.convert(value, PropertyType.PATH, getValueFactory());
+                            path = pathValue.getString();
+                            try {
+                                return (path.charAt(0) == '/') ? getSession().getNode(path) : getParent().getNode(path);
+                            } catch (PathNotFoundException e1) {
+                                throw new ItemNotFoundException(pathValue.getString());
+                            }
+                        }
 
-            case PropertyType.STRING:
-                try {
-                    Value refValue = ValueHelper.convert(value, PropertyType.REFERENCE, getValueFactory());
-                    return getSession().getNodeByIdentifier(refValue.getString());
-                } catch (ItemNotFoundException e) {
-                    throw e;
-                } catch (RepositoryException e) {
-                    // try if STRING value can be interpreted as PATH value
-                    Value pathValue = ValueHelper.convert(value, PropertyType.PATH, getValueFactory());
-                    path = pathValue.getString();
-                    try {
-                        return (path.charAt(0) == '/') ? getSession().getNode(path) : getParent().getNode(path);
-                    } catch (PathNotFoundException e1) {
-                        throw new ItemNotFoundException(pathValue.getString());
-                    }
+                    default:
+                        throw new ValueFormatException("Property value cannot be converted to a PATH, REFERENCE or WEAKREFERENCE");
                 }
-
-            default:
-                throw new ValueFormatException("Property value cannot be converted to a PATH, REFERENCE or WEAKREFERENCE");
-        }
+            }
+        });
     }
 
     /**
@@ -454,14 +498,19 @@ public class PropertyImpl extends ItemIm
     @Override
     @Nonnull
     public Property getProperty() throws RepositoryException {
-        Value value = getValue();
-        Value pathValue = ValueHelper.convert(value, PropertyType.PATH, getValueFactory());
-        String path = pathValue.getString();
-        try {
-            return (path.charAt(0) == '/') ? getSession().getProperty(path) : getParent().getProperty(path);
-        } catch (PathNotFoundException e) {
-            throw new ItemNotFoundException(path);
-        }
+        return sessionDelegate.perform(new SessionOperation<Property>() {
+            @Override
+            public Property perform() throws RepositoryException {
+                Value value = getValue();
+                Value pathValue = ValueHelper.convert(value, PropertyType.PATH, getValueFactory());
+                String path = pathValue.getString();
+                try {
+                    return (path.charAt(0) == '/') ? getSession().getProperty(path) : getParent().getProperty(path);
+                } catch (PathNotFoundException e) {
+                    throw new ItemNotFoundException(path);
+                }
+            }
+        });
     }
 
     /**
@@ -490,7 +539,12 @@ public class PropertyImpl extends ItemIm
     @Override
     @Nonnull
     public PropertyDefinition getDefinition() throws RepositoryException {
-        return dlg.getDefinition();
+        return sessionDelegate.perform(new SessionOperation<PropertyDefinition>() {
+            @Override
+            public PropertyDefinition perform() {
+                return dlg.getDefinition();
+            }
+        });
     }
 
     /**
@@ -498,23 +552,34 @@ public class PropertyImpl extends ItemIm
      */
     @Override
     public int getType() throws RepositoryException {
-        if (isMultiple()) {
-            Value[] values = getValues();
-            if (values.length == 0) {
-                // retrieve the type from the property definition
-                return getRequiredType(PropertyType.UNDEFINED);
-            } else {
-                return values[0].getType();
+        return sessionDelegate.perform(new SessionOperation<Integer>() {
+            @Override
+            public Integer perform() throws RepositoryException {
+                if (isMultiple()) {
+                    Value[] values = getValues();
+                    if (values.length == 0) {
+                        // retrieve the type from the property definition
+                        return getRequiredType(PropertyType.UNDEFINED);
+                    } else {
+                        return values[0].getType();
+                    }
+                } else {
+                    return getValue().getType();
+                }
             }
-        } else {
-            return getValue().getType();
-        }
+        });
     }
 
     @Override
     public boolean isMultiple() throws RepositoryException {
         checkStatus();
-        return dlg.isMultivalue();
+
+        return sessionDelegate.perform(new SessionOperation<Boolean>() {
+            @Override
+            public Boolean perform() throws RepositoryException {
+                return dlg.isMultivalue();
+            }
+        });
     }
 
     //------------------------------------------------------------< private >---

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionDelegate.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionDelegate.java?rev=1365564&r1=1365563&r2=1365564&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionDelegate.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionDelegate.java Wed Jul 25 13:07:40 2012
@@ -76,6 +76,7 @@ public class SessionDelegate {
 
     private ObservationManagerImpl observationManager;
     private boolean isAlive = true;
+    private int sessionOpCount;
 
     SessionDelegate(Repository repository, LazyValue<Timer> observationTimer, ContentSession contentSession)
             throws RepositoryException {
@@ -92,6 +93,36 @@ public class SessionDelegate {
         this.conflictHandler = new AnnotatingConflictHandler(contentSession.getCoreValueFactory());
     }
 
+    /**
+     * Performs the passed {@code SessionOperation} in a safe execution context. This
+     * context ensures that the session is refreshed if necessary and that refreshing
+     * occurs before the session operation is performed and the refreshing is done only
+     * once.
+     *
+     * @param sessionOperation  the {@code SessionOperation} to perform
+     * @param <T>  return type of {@code sessionOperation}
+     * @return  the result of {@code sessionOperation.perform()}
+     * @throws RepositoryException
+     */
+    public <T> T perform(SessionOperation<T> sessionOperation) throws RepositoryException {
+        try {
+            sessionOpCount++;
+            if (refreshNeeded()) {
+                refresh(true);
+            }
+            return sessionOperation.perform();
+        }
+        finally {
+            sessionOpCount--;
+        }
+    }
+
+    private boolean refreshNeeded() {
+        // Refresh is needed only for non re-entrant session operations and only if
+        // observation events have actually been delivered
+        return sessionOpCount <= 1 && observationManager != null && observationManager.hasEvents();
+    }
+
     public boolean isAlive() {
         return isAlive;
     }

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionImpl.java?rev=1365564&r1=1365563&r2=1365564&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionImpl.java Wed Jul 25 13:07:40 2012
@@ -113,7 +113,13 @@ public class SessionImpl extends Abstrac
     @Nonnull
     public Node getRootNode() throws RepositoryException {
         ensureIsAlive();
-        return new NodeImpl(dlg.getRoot());
+
+        return dlg.perform(new SessionOperation<NodeImpl>() {
+            @Override
+            public NodeImpl perform() {
+                return new NodeImpl(dlg.getRoot());
+            }
+        });
     }
 
     @Override
@@ -124,30 +130,43 @@ public class SessionImpl extends Abstrac
 
     @Override
     @Nonnull
-    public Node getNodeByIdentifier(String id) throws RepositoryException {
+    public Node getNodeByIdentifier(final String id) throws RepositoryException {
         ensureIsAlive();
-        NodeDelegate d = dlg.getNodeByIdentifier(id);
-        if (d == null) {
-            throw new ItemNotFoundException("Node with id " + id + " does not exist.");
-        }
-        return new NodeImpl(d);
+
+        return dlg.perform(new SessionOperation<NodeImpl>() {
+            @Override
+            public NodeImpl perform() throws RepositoryException {
+                NodeDelegate d = dlg.getNodeByIdentifier(id);
+                if (d == null) {
+                    throw new ItemNotFoundException("Node with id " + id + " does not exist.");
+                }
+                return new NodeImpl(d);
+            }
+        });
     }
 
     @Override
-    public void move(String srcAbsPath, String destAbsPath) throws RepositoryException {
+    public void move(final String srcAbsPath, final String destAbsPath) throws RepositoryException {
         ensureIsAlive();
 
-        String oakPath = dlg.getOakPathKeepIndexOrThrowNotFound(destAbsPath);
-        String oakName = PathUtils.getName(oakPath);
-        // handle index
-        if (oakName.contains("[")) {
-            throw new RepositoryException("Cannot create a new node using a name including an index");
-        }
+        dlg.perform(new SessionOperation<Void>() {
+            @Override
+            public Void perform() throws RepositoryException {
+                String oakPath = dlg.getOakPathKeepIndexOrThrowNotFound(destAbsPath);
+                String oakName = PathUtils.getName(oakPath);
+                // handle index
+                if (oakName.contains("[")) {
+                    throw new RepositoryException("Cannot create a new node using a name including an index");
+                }
 
-        dlg.move(
-                dlg.getOakPathOrThrowNotFound(srcAbsPath),
-                dlg.getOakPathOrThrowNotFound(oakPath),
-                true);
+                dlg.move(
+                        dlg.getOakPathOrThrowNotFound(srcAbsPath),
+                        dlg.getOakPathOrThrowNotFound(oakPath),
+                        true);
+
+                return null;
+            }
+        });
     }
 
     @Override

Added: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionOperation.java?rev=1365564&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionOperation.java (added)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionOperation.java Wed Jul 25 13:07:40 2012
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.oak.jcr;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * A {@code SessionOperation} provides an execution context for executing session scoped operations.
+ */
+public interface SessionOperation<T> {
+    T perform() throws RepositoryException;
+}

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java?rev=1365564&r1=1365563&r2=1365564&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ChangeProcessor.java Wed Jul 25 13:07:40 2012
@@ -25,6 +25,8 @@ import java.util.concurrent.atomic.Atomi
 import javax.jcr.observation.Event;
 import javax.jcr.observation.EventListener;
 
+import com.google.common.base.Function;
+import com.google.common.collect.Iterators;
 import org.apache.jackrabbit.commons.iterator.EventIteratorAdapter;
 import org.apache.jackrabbit.oak.api.ChangeExtractor;
 import org.apache.jackrabbit.oak.api.PropertyState;
@@ -35,10 +37,8 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
 import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
 
-import com.google.common.base.Function;
-import com.google.common.collect.Iterators;
-
 class ChangeProcessor extends TimerTask {
+    private final ObservationManagerImpl observationManager;
     private final NamePathMapper namePathMapper;
     private final ChangeExtractor changeExtractor;
     private final EventListener listener;
@@ -46,10 +46,10 @@ class ChangeProcessor extends TimerTask 
 
     private volatile boolean stopped;
 
-    public ChangeProcessor(NamePathMapper namePathMapper, ChangeExtractor changeExtractor, EventListener listener,
-            ChangeFilter filter) {
-        this.namePathMapper = namePathMapper;
-        this.changeExtractor = changeExtractor;
+    public ChangeProcessor(ObservationManagerImpl observationManager, EventListener listener, ChangeFilter filter) {
+        this.observationManager = observationManager;
+        this.namePathMapper = observationManager.getNamePathMapper();
+        this.changeExtractor = observationManager.getChangeExtractor();
         this.listener = listener;
         filterRef = new AtomicReference<ChangeFilter>(filter);
     }
@@ -67,6 +67,7 @@ class ChangeProcessor extends TimerTask 
     public void run() {
         EventGeneratingNodeStateDiff diff = new EventGeneratingNodeStateDiff();
         changeExtractor.getChanges(diff);
+        observationManager.setHasEvents();
         diff.sendEvents();
     }
 

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ObservationManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ObservationManagerImpl.java?rev=1365564&r1=1365563&r2=1365564&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ObservationManagerImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/observation/ObservationManagerImpl.java Wed Jul 25 13:07:40 2012
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.oak.jcr.ob
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Timer;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.jcr.RepositoryException;
 import javax.jcr.UnsupportedRepositoryOperationException;
@@ -31,6 +32,7 @@ import org.apache.jackrabbit.commons.ite
 import org.apache.jackrabbit.oak.api.ChangeExtractor;
 import org.apache.jackrabbit.oak.jcr.SessionDelegate;
 import org.apache.jackrabbit.oak.jcr.util.LazyValue;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 
 public class ObservationManagerImpl implements ObservationManager {
     private final SessionDelegate sessionDelegate;
@@ -38,6 +40,7 @@ public class ObservationManagerImpl impl
             new HashMap<EventListener, ChangeProcessor>();
 
     private final LazyValue<Timer> timer;
+    private final AtomicBoolean hasEvents = new AtomicBoolean(false);
 
     public ObservationManagerImpl(SessionDelegate sessionDelegate, LazyValue<Timer> timer) {
         this.sessionDelegate = sessionDelegate;
@@ -50,6 +53,15 @@ public class ObservationManagerImpl impl
         }
     }
 
+    /**
+     * Determine whether events have been generated since the time this method has been called.
+     * @return  {@code true} if this {@code ObservationManager} instance has generated events
+     *          since the last time this method has been called, {@code false} otherwise.
+     */
+    public boolean hasEvents() {
+        return hasEvents.getAndSet(false);
+    }
+
     @Override
     public void addEventListener(EventListener listener, int eventTypes, String absPath,
             boolean isDeep, String[] uuid, String[] nodeTypeName, boolean noLocal)
@@ -57,10 +69,8 @@ public class ObservationManagerImpl impl
 
         ChangeProcessor processor = processors.get(listener);
         if (processor == null) {
-            ChangeExtractor extractor = sessionDelegate.getChangeExtractor();
             ChangeFilter filter = new ChangeFilter(eventTypes, absPath, isDeep, uuid, nodeTypeName, noLocal);
-            ChangeProcessor changeProcessor = new ChangeProcessor(sessionDelegate.getNamePathMapper(), extractor,
-                    listener, filter);
+            ChangeProcessor changeProcessor = new ChangeProcessor(this, listener, filter);
             processors.put(listener, changeProcessor);
             timer.get().schedule(changeProcessor, 100, 1000);
         }
@@ -99,4 +109,17 @@ public class ObservationManagerImpl impl
         throw new UnsupportedRepositoryOperationException();
     }
 
+    //------------------------------------------------------------< internal >---
+
+    NamePathMapper getNamePathMapper() {
+        return sessionDelegate.getNamePathMapper();
+    }
+
+    ChangeExtractor getChangeExtractor() {
+        return sessionDelegate.getChangeExtractor();
+    }
+
+    void setHasEvents() {
+        hasEvents.set(true);
+    }
 }