You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2010/08/03 10:19:04 UTC

svn commit: r981771 - in /jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core: ./ session/

Author: jukka
Date: Tue Aug  3 08:19:04 2010
New Revision: 981771

URL: http://svn.apache.org/viewvc?rev=981771&view=rev
Log:
JCR-890: concurrent read-only access to a session

Add SessionItemOperation for the itemExists(), getItem(), and remove() methods in Session.

Allow return values from SessionOperations (using generics to avoid type casts).

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionItemOperation.java   (with props)
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemRefreshOperation.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemSaveOperation.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionOperation.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionRefreshOperation.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionSaveOperation.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionState.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemRefreshOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemRefreshOperation.java?rev=981771&r1=981770&r2=981771&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemRefreshOperation.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemRefreshOperation.java Tue Aug  3 08:19:04 2010
@@ -28,7 +28,7 @@ import org.apache.jackrabbit.core.state.
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class ItemRefreshOperation implements SessionOperation {
+public class ItemRefreshOperation implements SessionOperation<Object> {
 
     /**
      * Logger instance.
@@ -42,13 +42,13 @@ public class ItemRefreshOperation implem
         this.state = state;
     }
 
-    public void perform(SessionContext context) throws RepositoryException {
+    public Object perform(SessionContext context) throws RepositoryException {
         SessionItemStateManager stateMgr = context.getItemStateManager();
 
         // Optimisation for the root node
         if (state.getParentId() == null) {
             stateMgr.disposeAllTransientItemStates();
-            return;
+            return this;
         }
 
         // list of transient items that should be discarded
@@ -121,6 +121,8 @@ public class ItemRefreshOperation implem
                 stateMgr.disposeTransientItemStateInAttic(descendant);
             }
         }
+
+        return this;
     }
 
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemSaveOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemSaveOperation.java?rev=981771&r1=981770&r2=981771&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemSaveOperation.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemSaveOperation.java Tue Aug  3 08:19:04 2010
@@ -72,7 +72,7 @@ import org.slf4j.Logger;
 /**
  * The session operation triggered by {@link Item#save()}.
  */
-class ItemSaveOperation implements SessionOperation {
+class ItemSaveOperation implements SessionOperation<Object> {
 
     /**
      * Logger instance.
@@ -86,7 +86,7 @@ class ItemSaveOperation implements Sessi
         this.state = state;
     }
 
-    public void perform(SessionContext context) throws RepositoryException {
+    public Object perform(SessionContext context) throws RepositoryException {
         SessionItemStateManager stateMgr = context.getItemStateManager();
 
         /**
@@ -104,7 +104,7 @@ class ItemSaveOperation implements Sessi
         }
         if (dirty.size() == 0) {
             // no transient items, nothing to do here
-            return;
+            return this;
         }
 
         /**
@@ -286,6 +286,8 @@ class ItemSaveOperation implements Sessi
             // dispose the transient state, it is no longer used
             stateMgr.disposeTransientItemStateInAttic(transientState);
         }
+
+        return this;
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java?rev=981771&r1=981770&r2=981771&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java Tue Aug  3 08:19:04 2010
@@ -1611,23 +1611,11 @@ public class NodeImpl extends ItemImpl i
      * Same as <code>{@link Node#setProperty(String, Value)}</code> except that
      * this method takes a <code>Name</code> name argument instead of a
      * <code>String</code>.
-     *
-     * @param name
-     * @param value
-     * @return
-     * @throws ValueFormatException
-     * @throws VersionException
-     * @throws LockException
-     * @throws ConstraintViolationException
-     * @throws RepositoryException
      */
     public PropertyImpl setProperty(Name name, Value value)
-            throws ValueFormatException, VersionException, LockException,
-            ConstraintViolationException, RepositoryException {
-        SetPropertyOperation operation =
-            new SetPropertyOperation(name, value, false);
-        sessionContext.getSessionState().perform(operation);
-        return operation.getProperty();
+            throws RepositoryException {
+        return sessionContext.getSessionState().perform(
+                new SetPropertyOperation(name, value, false));
     }
 
     /**
@@ -2211,19 +2199,15 @@ public class NodeImpl extends ItemImpl i
         if (value != null && value.getType() != type) {
             value = ValueHelper.convert(value, type, getValueFactory());
         }
-        SetPropertyOperation operation =
-            new SetPropertyOperation(session.getQName(name), value, true);
-        sessionContext.getSessionState().perform(operation);
-        return operation.getProperty();
+        return sessionContext.getSessionState().perform(
+                new SetPropertyOperation(session.getQName(name), value, true));
     }
 
     /** Wrapper around {@link SetPropertyOperation} */
     public Property setProperty(String name, Value value)
             throws RepositoryException {
-        SetPropertyOperation operation =
-            new SetPropertyOperation(session.getQName(name), value, false);
-        sessionContext.getSessionState().perform(operation);
-        return operation.getProperty();
+        return sessionContext.getSessionState().perform(
+                new SetPropertyOperation(session.getQName(name), value, false));
     }
 
     /** Wrapper around {@link #setProperty(String, Value)} */
@@ -2300,7 +2284,7 @@ public class NodeImpl extends ItemImpl i
      * definition and the implementation tries to convert the passed value to
      * that type. If that fails, then a {@link ValueFormatException} is thrown.
      */
-    private class SetPropertyOperation implements SessionOperation {
+    private class SetPropertyOperation implements SessionOperation<PropertyImpl> {
 
         private final Name name;
 
@@ -2308,8 +2292,6 @@ public class NodeImpl extends ItemImpl i
 
         private final boolean enforceType;
 
-        private volatile PropertyImpl property = null;
-
         /**
          * @param name  property name
          * @param value new value of the property,
@@ -2324,15 +2306,9 @@ public class NodeImpl extends ItemImpl i
         }
 
         /**
-         * @return the <code>Property</code> object set, or <code>null</code> if
-         *         this method was used to remove a property (by setting its value
-         *         to <code>null</code>).
-         */
-        public PropertyImpl getProperty() {
-            return property;
-        }
-
-        /**
+         * @return the <code>Property</code> object set,
+         *         or <code>null</code> if this operation was used to remove
+         *         a property (by setting its value to <code>null</code>)
          * @throws ValueFormatException         if <code>value</code> cannot be
          *                                      converted to the specified type or
          *                                      if the property already exists and
@@ -2349,7 +2325,8 @@ public class NodeImpl extends ItemImpl i
          *                                      validation immediately.
          * @throws RepositoryException          if another error occurs.
          */
-        public void perform(SessionContext context) throws RepositoryException {
+        public PropertyImpl perform(SessionContext context)
+                throws RepositoryException {
             itemSanityCheck();
             // check pre-conditions for setting property
             checkSetProperty();
@@ -2360,7 +2337,7 @@ public class NodeImpl extends ItemImpl i
             }
 
             BitSet status = new BitSet();
-            property =
+            PropertyImpl property =
                 getOrCreateProperty(name, type, false, enforceType, status);
             try {
                 property.setValue(value);
@@ -2371,6 +2348,7 @@ public class NodeImpl extends ItemImpl i
                 }
                 throw e; // rethrow
             }
+            return property;
         }
 
     }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java?rev=981771&r1=981770&r2=981771&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java Tue Aug  3 08:19:04 2010
@@ -16,6 +16,45 @@
  */
 package org.apache.jackrabbit.core;
 
+import java.io.File;
+import java.io.PrintStream;
+import java.security.AccessControlException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.Credentials;
+import javax.jcr.Item;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.LoginException;
+import javax.jcr.NamespaceException;
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.ValueFactory;
+import javax.jcr.Workspace;
+import javax.jcr.lock.Lock;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.observation.EventListener;
+import javax.jcr.observation.ObservationManager;
+import javax.jcr.retention.RetentionManager;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.version.VersionException;
+import javax.security.auth.Subject;
+
 import org.apache.commons.collections.IteratorUtils;
 import org.apache.commons.collections.map.ReferenceMap;
 import org.apache.jackrabbit.api.JackrabbitSession;
@@ -36,6 +75,7 @@ import org.apache.jackrabbit.core.securi
 import org.apache.jackrabbit.core.security.authentication.AuthContext;
 import org.apache.jackrabbit.core.security.authorization.Permission;
 import org.apache.jackrabbit.core.session.SessionContext;
+import org.apache.jackrabbit.core.session.SessionItemOperation;
 import org.apache.jackrabbit.core.session.SessionOperation;
 import org.apache.jackrabbit.core.session.SessionRefreshOperation;
 import org.apache.jackrabbit.core.session.SessionSaveOperation;
@@ -60,44 +100,6 @@ import org.slf4j.LoggerFactory;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.InputSource;
 
-import javax.jcr.AccessDeniedException;
-import javax.jcr.Credentials;
-import javax.jcr.Item;
-import javax.jcr.ItemNotFoundException;
-import javax.jcr.LoginException;
-import javax.jcr.NamespaceException;
-import javax.jcr.NoSuchWorkspaceException;
-import javax.jcr.Node;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.Property;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.SimpleCredentials;
-import javax.jcr.UnsupportedRepositoryOperationException;
-import javax.jcr.ValueFactory;
-import javax.jcr.Workspace;
-import javax.jcr.lock.Lock;
-import javax.jcr.lock.LockException;
-import javax.jcr.nodetype.ConstraintViolationException;
-import javax.jcr.observation.EventListener;
-import javax.jcr.observation.ObservationManager;
-import javax.jcr.retention.RetentionManager;
-import javax.jcr.security.AccessControlManager;
-import javax.jcr.version.VersionException;
-import javax.security.auth.Subject;
-import java.io.File;
-import java.io.PrintStream;
-import java.security.AccessControlException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 /**
  * A <code>SessionImpl</code> ...
  */
@@ -357,9 +359,9 @@ public class SessionImpl extends Abstrac
         return repositoryContext.getSecurityManager().getAccessManager(this, ctx);
     }
 
-    private void perform(SessionOperation operation)
+    private <T> T perform(SessionOperation<T> operation)
             throws RepositoryException {
-        context.getSessionState().perform(operation);
+        return context.getSessionState().perform(operation);
     }
 
     /**
@@ -821,23 +823,8 @@ public class SessionImpl extends Abstrac
      * {@inheritDoc}
      */
     @Override
-    public Item getItem(String absPath) throws PathNotFoundException, RepositoryException {
-        // check sanity of this session
-        sanityCheck();
-
-        try {
-            Path p = getQPath(absPath).getNormalizedPath();
-            if (!p.isAbsolute()) {
-                throw new RepositoryException("not an absolute path: " + absPath);
-            }
-            return getItemManager().getItem(p);
-        } catch (AccessDeniedException ade) {
-            throw new PathNotFoundException(absPath);
-        } catch (NameException e) {
-            String msg = "invalid path:" + absPath;
-            log.debug(msg);
-            throw new RepositoryException(msg, e);
-        }
+    public Item getItem(String absPath) throws RepositoryException {
+        return perform(SessionItemOperation.getItem(absPath));
     }
 
     /**
@@ -845,20 +832,7 @@ public class SessionImpl extends Abstrac
      */
     @Override
     public boolean itemExists(String absPath) throws RepositoryException {
-        // check sanity of this session
-        sanityCheck();
-
-        try {
-            Path p = getQPath(absPath).getNormalizedPath();
-            if (!p.isAbsolute()) {
-                throw new RepositoryException("not an absolute path: " + absPath);
-            }
-            return getItemManager().itemExists(p);
-        } catch (NameException e) {
-            String msg = "invalid path:" + absPath;
-            log.debug(msg);
-            throw new RepositoryException(msg, e);
-        }
+        return perform(SessionItemOperation.itemExists(absPath));
     }
 
     /**
@@ -1156,24 +1130,8 @@ public class SessionImpl extends Abstrac
      * @since JCR 2.0
      */
     @Override
-    public Node getNode(String absPath)
-            throws PathNotFoundException, RepositoryException {
-        // check sanity of this session
-        sanityCheck();
-
-        try {
-            Path p = getQPath(absPath).getNormalizedPath();
-            if (!p.isAbsolute()) {
-                throw new RepositoryException("not an absolute path: " + absPath);
-            }
-            return getItemManager().getNode(p);
-        } catch (AccessDeniedException ade) {
-            throw new PathNotFoundException(absPath);
-        } catch (NameException e) {
-            String msg = "invalid path:" + absPath;
-            log.debug(msg);
-            throw new RepositoryException(msg, e);
-        }
+    public Node getNode(String absPath) throws RepositoryException {
+        return perform(SessionItemOperation.getNode(absPath));
     }
 
     /**
@@ -1181,24 +1139,8 @@ public class SessionImpl extends Abstrac
      * @since JCR 2.0
      */
     @Override
-    public Property getProperty(String absPath)
-            throws PathNotFoundException, RepositoryException {
-        // check sanity of this session
-        sanityCheck();
-
-        try {
-            Path p = getQPath(absPath).getNormalizedPath();
-            if (!p.isAbsolute()) {
-                throw new RepositoryException("not an absolute path: " + absPath);
-            }
-            return getItemManager().getProperty(p);
-        } catch (AccessDeniedException ade) {
-            throw new PathNotFoundException(absPath);
-        } catch (NameException e) {
-            String msg = "invalid path:" + absPath;
-            log.debug(msg);
-            throw new RepositoryException(msg, e);
-        }
+    public Property getProperty(String absPath) throws RepositoryException {
+        return perform(SessionItemOperation.getProperty(absPath));
     }
 
     /**
@@ -1207,20 +1149,7 @@ public class SessionImpl extends Abstrac
      */
     @Override
     public boolean nodeExists(String absPath) throws RepositoryException {
-        // check sanity of this session
-        sanityCheck();
-
-        try {
-            Path p = getQPath(absPath).getNormalizedPath();
-            if (!p.isAbsolute()) {
-                throw new RepositoryException("not an absolute path: " + absPath);
-            }
-            return getItemManager().nodeExists(p);
-        } catch (NameException e) {
-            String msg = "invalid path:" + absPath;
-            log.debug(msg);
-            throw new RepositoryException(msg, e);
-        }
+        return perform(SessionItemOperation.nodeExists(absPath));
     }
 
     /**
@@ -1229,20 +1158,7 @@ public class SessionImpl extends Abstrac
      */
     @Override
     public boolean propertyExists(String absPath) throws RepositoryException {
-        // check sanity of this session
-        sanityCheck();
-
-        try {
-            Path p = getQPath(absPath).getNormalizedPath();
-            if (!p.isAbsolute()) {
-                throw new RepositoryException("not an absolute path: " + absPath);
-            }
-            return getItemManager().propertyExists(p);
-        } catch (NameException e) {
-            String msg = "invalid path:" + absPath;
-            log.debug(msg);
-            throw new RepositoryException(msg, e);
-        }
+        return perform(SessionItemOperation.propertyExists(absPath));
     }
 
     /**
@@ -1250,25 +1166,8 @@ public class SessionImpl extends Abstrac
      * @since JCR 2.0
      */
     @Override
-    public void removeItem(String absPath) throws VersionException,
-            LockException, ConstraintViolationException, RepositoryException {
-        // check sanity of this session
-        sanityCheck();
-        Item item;
-        try {
-            Path p = getQPath(absPath).getNormalizedPath();
-            if (!p.isAbsolute()) {
-                throw new RepositoryException("not an absolute path: " + absPath);
-            }
-            item = getItemManager().getItem(p);
-        } catch (AccessDeniedException e) {
-            throw new PathNotFoundException(absPath);
-        } catch (NameException e) {
-            String msg = "invalid path:" + absPath;
-            log.debug(msg);
-            throw new RepositoryException(msg, e);
-        }
-        item.remove();
+    public void removeItem(String absPath) throws RepositoryException {
+        perform(SessionItemOperation.remove(absPath));
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java?rev=981771&r1=981770&r2=981771&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java Tue Aug  3 08:19:04 2010
@@ -36,7 +36,7 @@ import org.apache.jackrabbit.spi.commons
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class SessionMoveOperation implements SessionOperation {
+public class SessionMoveOperation implements SessionOperation<Object> {
 
     private final Logger log =
         LoggerFactory.getLogger(SessionMoveOperation.class);
@@ -102,7 +102,7 @@ public class SessionMoveOperation implem
         }
     }
 
-    public void perform(SessionContext context) throws RepositoryException {
+    public Object perform(SessionContext context) throws RepositoryException {
         // Get node instances
         NodeImpl targetNode = getNode(context, srcPath, srcAbsPath);
         NodeImpl srcParentNode =
@@ -209,6 +209,8 @@ public class SessionMoveOperation implem
                 destParentState.addChildNodeEntry(destName.getName(), targetId);
             }
         }
+
+        return this;
     }
 
 }
\ No newline at end of file

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionItemOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionItemOperation.java?rev=981771&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionItemOperation.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionItemOperation.java Tue Aug  3 08:19:04 2010
@@ -0,0 +1,129 @@
+/*
+ * 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.core.session;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.ItemImpl;
+import org.apache.jackrabbit.core.ItemManager;
+import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.PropertyImpl;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.commons.conversion.NameException;
+
+/**
+ * Session operation for accessing an item at a given path. See the static
+ * methods for factories of different kinds of item operations.
+ */
+public abstract class SessionItemOperation<T> implements SessionOperation<T> {
+
+    private final String path;
+
+    private SessionItemOperation(String path) {
+        this.path = path;
+    }
+
+    public T perform(SessionContext context) throws RepositoryException {
+        try {
+            Path normalized =
+                context.getSessionImpl().getQPath(path).getNormalizedPath();
+            if (normalized.isAbsolute()) {
+                return perform(context.getItemManager(), normalized);
+            } else {
+                throw new RepositoryException("Not an absolute path: " + path);
+            }
+        } catch (AccessDeniedException e) {
+            throw new PathNotFoundException(path);
+        } catch (NameException e) {
+            throw new RepositoryException("Invalid path:" + path, e);
+        }
+    }
+
+    protected abstract T perform(ItemManager manager, Path path)
+            throws RepositoryException;
+
+    public static SessionItemOperation<Boolean> itemExists(String path) {
+        return new SessionItemOperation<Boolean>(path) {
+            @Override @SuppressWarnings("deprecation")
+            protected Boolean perform(ItemManager manager, Path path) {
+                return manager.itemExists(path);
+            }
+        };
+    }
+
+    public static SessionItemOperation<Boolean> propertyExists(String path) {
+        return new SessionItemOperation<Boolean>(path) {
+            @Override
+            protected Boolean perform(ItemManager manager, Path path) {
+                return manager.propertyExists(path);
+            }
+        };
+    }
+
+    public static SessionItemOperation<Boolean> nodeExists(String path) {
+        return new SessionItemOperation<Boolean>(path) {
+            @Override
+            protected Boolean perform(ItemManager manager, Path path) {
+                return manager.nodeExists(path);
+            }
+        };
+    }
+
+    public static SessionItemOperation<ItemImpl> getItem(String path) {
+        return new SessionItemOperation<ItemImpl>(path) {
+            @Override @SuppressWarnings("deprecation")
+            protected ItemImpl perform(ItemManager manager, Path path)
+                    throws RepositoryException {
+                return manager.getItem(path);
+            }
+        };
+    }
+
+    public static SessionItemOperation<PropertyImpl> getProperty(String path) {
+        return new SessionItemOperation<PropertyImpl>(path) {
+            @Override
+            protected PropertyImpl perform(ItemManager manager, Path path)
+                    throws RepositoryException {
+                return manager.getProperty(path);
+            }
+        };
+    }
+
+    public static SessionItemOperation<NodeImpl> getNode(String path) {
+        return new SessionItemOperation<NodeImpl>(path) {
+            @Override
+            protected NodeImpl perform(ItemManager manager, Path path)
+                    throws RepositoryException {
+                return manager.getNode(path);
+            }
+        };
+    }
+
+    public static SessionItemOperation<Object> remove(String path) {
+        return new SessionItemOperation<Object>(path) {
+            @Override  @SuppressWarnings("deprecation")
+            protected Object perform(ItemManager manager, Path path)
+                    throws RepositoryException {
+                manager.getItem(path).remove();
+                return this;
+            }
+        };
+    }
+
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionItemOperation.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionOperation.java?rev=981771&r1=981770&r2=981771&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionOperation.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionOperation.java Tue Aug  3 08:19:04 2010
@@ -23,7 +23,7 @@ import javax.jcr.RepositoryException;
  * generic controls like synchronization and liveness checks on all session
  * operation.
  */
-public interface SessionOperation {
+public interface SessionOperation<T> {
 
     /**
      * Performs the session operation.
@@ -31,6 +31,6 @@ public interface SessionOperation {
      * @param context component context of this session
      * @throws RepositoryException if the operation fails
      */
-    void perform(SessionContext context) throws RepositoryException;
+    T perform(SessionContext context) throws RepositoryException;
 
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionRefreshOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionRefreshOperation.java?rev=981771&r1=981770&r2=981771&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionRefreshOperation.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionRefreshOperation.java Tue Aug  3 08:19:04 2010
@@ -24,7 +24,7 @@ import org.apache.jackrabbit.core.cluste
 /**
  * Operation to refresh the state of a session.
  */
-public class SessionRefreshOperation implements SessionOperation {
+public class SessionRefreshOperation implements SessionOperation<Object> {
 
     private final boolean keepChanges;
 
@@ -35,7 +35,7 @@ public class SessionRefreshOperation imp
         this.clusterSync = clusterSync;
     }
 
-    public void perform(SessionContext context) throws RepositoryException {
+    public Object perform(SessionContext context) throws RepositoryException {
         // JCR-1753: Ensure that we are up to date with cluster changes
         ClusterNode cluster = context.getRepositoryContext().getClusterNode();
         if (cluster != null && clusterSync) {
@@ -54,6 +54,7 @@ public class SessionRefreshOperation imp
             // of all non-transient instances; maybe also
             // have to reset stale ItemState instances
         }
+        return this;
     }
 
 }
\ No newline at end of file

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionSaveOperation.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionSaveOperation.java?rev=981771&r1=981770&r2=981771&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionSaveOperation.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionSaveOperation.java Tue Aug  3 08:19:04 2010
@@ -21,9 +21,9 @@ import javax.jcr.Session;
 
 import org.apache.jackrabbit.core.id.NodeId;
 
-public class SessionSaveOperation implements SessionOperation {
+public class SessionSaveOperation implements SessionOperation<Object> {
 
-    public void perform(SessionContext context) throws RepositoryException {
+    public Object perform(SessionContext context) throws RepositoryException {
         NodeId id;
         // JCR-2425: check whether session is allowed to read root node
         if (context.getSessionImpl().hasPermission("/", Session.ACTION_READ)) {
@@ -32,6 +32,7 @@ public class SessionSaveOperation implem
             id = context.getItemStateManager().getIdOfRootTransientNodeState();
         }
         context.getItemManager().getItem(id).save();
+        return this;
     }
 
 }
\ No newline at end of file

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionState.java?rev=981771&r1=981770&r2=981771&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionState.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/session/SessionState.java Tue Aug  3 08:19:04 2010
@@ -107,7 +107,8 @@ public class SessionState {
      * @throws RepositoryException if the operation fails or
      *                             if the session has already been closed
      */
-    public void perform(SessionOperation operation) throws RepositoryException {
+    public <T> T perform(SessionOperation<T> operation)
+            throws RepositoryException {
         if (!lock.tryLock()) {
             log.warn("Attempt to perform {} while another thread is"
                     + " concurrently accessing the session. Blocking until"
@@ -118,7 +119,7 @@ public class SessionState {
         try {
             checkAlive();
             log.debug("Performing {}", operation);
-            operation.perform(context);
+            return operation.perform(context);
         } finally {
             lock.unlock();
         }