jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ang...@apache.org
Subject svn commit: r738422 [1/3] - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/ main/java/org/apache/jackrabbit/core/lock/ main/java/org/apache/jackrabbit/core/retention/ main/java/org/apache/jackrabbit/core/security/authori...
Date Wed, 28 Jan 2009 09:50:51 GMT
Author: angela
Date: Wed Jan 28 09:50:50 2009
New Revision: 738422

URL: http://svn.apache.org/viewvc?rev=738422&view=rev
Log:
JCR-1589: JSR 283 Retention & Hold Management (work in progress)
JCR-1957: Move common validation checks to a single place

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ProtectedItemModifier.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/HoldImpl.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionPolicyImpl.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistry.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionRegistryImpl.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/HoldEffectTest.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/HoldTest.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/RetentionPolicyEffectTest.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/RetentionPolicyTest.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/TestAll.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/RetentionRegistryImplTest.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/retention/
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/retention/HoldTest.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/retention/RetentionPolicyTest.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/retention/TestAll.java   (with props)
Removed:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SecurityItemModifier.java
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemValidator.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/PropertyImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.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/WorkspaceImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/SessionLockManager.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/RetentionManagerImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/acl/ACLEditor.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authorization/principalbased/ACLEditor.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java
    jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd
    jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.xml
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/SessionRemoveItemTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/retention/AbstractRetentionTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/security/RSessionAccessControlTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/TestAll.java
    jackrabbit/trunk/jackrabbit-core/src/test/resources/repositoryStubImpl.properties

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java?rev=738422&r1=738421&r2=738422&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/BatchedItemOperations.java Wed Jan 28 09:50:50 2009
@@ -81,45 +81,11 @@
     protected static final int CLONE_REMOVE_EXISTING = 2;
 
     /**
-     * option for <code>{@link #checkAddNode}</code> and
-     * <code>{@link #checkRemoveNode}</code> methods:<p/>
-     * check access rights
-     */
-    public static final int CHECK_ACCESS = 1;
-    /**
-     * option for <code>{@link #checkAddNode}</code> and
-     * <code>{@link #checkRemoveNode}</code> methods:<p/>
-     * check lock status
-     */
-    public static final int CHECK_LOCK = 2;
-    /**
-     * option for <code>{@link #checkAddNode}</code> and
-     * <code>{@link #checkRemoveNode}</code> methods:<p/>
-     * check checked-out status
-     */
-    public static final int CHECK_VERSIONING = 4;
-    /**
-     * option for <code>{@link #checkAddNode}</code> and
-     * <code>{@link #checkRemoveNode}</code> methods:<p/>
-     * check constraints defined in node type
-     */
-    public static final int CHECK_CONSTRAINTS = 16;
-    /**
-     * option for <code>{@link #checkRemoveNode}</code> method:<p/>
-     * check that target node is not being referenced
-     */
-    public static final int CHECK_REFERENCES = 8;
-
-    /**
      * wrapped item state manager
      */
     protected final UpdatableItemStateManager stateMgr;
     /**
-     * lock manager used for checking locking status
-     */
-    protected final LockManager lockMgr;
-    /**
-     * current session used for checking access rights and locking status
+     * current session used for checking access rights
      */
     protected final SessionImpl session;
 
@@ -131,15 +97,15 @@
      * @param lockMgr    lock manager
      * @param session    current session
      * @param hierMgr    hierarchy manager
+     * @throws RepositoryException
      */
     public BatchedItemOperations(UpdatableItemStateManager stateMgr,
                                  NodeTypeRegistry ntReg,
                                  LockManager lockMgr,
                                  SessionImpl session,
-                                 HierarchyManager hierMgr) {
-        super(ntReg, hierMgr, session);
+                                 HierarchyManager hierMgr) throws RepositoryException {
+        super(ntReg, hierMgr, session, lockMgr, session.getAccessManager(), session.getRetentionRegistry());
         this.stateMgr = stateMgr;
-        this.lockMgr = lockMgr;
         this.session = session;
     }
 
@@ -301,7 +267,7 @@
         // 2. check access rights, lock status, node type constraints, etc.
         checkAddNode(destParentState, destName,
                 srcState.getNodeTypeName(), CHECK_ACCESS | CHECK_LOCK
-                | CHECK_VERSIONING | CHECK_CONSTRAINTS);
+                | CHECK_VERSIONING | CHECK_CONSTRAINTS | CHECK_HOLD | CHECK_RETENTION);
 
         // 3. verify that source has mixin mix:shareable
         if (!isShareable(srcState)) {
@@ -435,7 +401,7 @@
 
         checkAddNode(destParentState, destName.getName(),
                 srcState.getNodeTypeName(), CHECK_ACCESS | CHECK_LOCK
-                | CHECK_VERSIONING | CHECK_CONSTRAINTS);
+                | CHECK_VERSIONING | CHECK_CONSTRAINTS | CHECK_HOLD | CHECK_RETENTION);
         // check read access right on source node using source access manager
         try {
             if (!srcAccessMgr.isGranted(srcPath, Permission.READ)) {
@@ -580,10 +546,11 @@
         // 2. check if target state can be removed from old/added to new parent
 
         checkRemoveNode(target, srcParent.getNodeId(),
-                CHECK_ACCESS | CHECK_LOCK | CHECK_VERSIONING | CHECK_CONSTRAINTS);
+                CHECK_ACCESS | CHECK_LOCK | CHECK_VERSIONING | CHECK_CONSTRAINTS |
+                        CHECK_HOLD | CHECK_RETENTION);
         checkAddNode(destParent, destName.getName(),
                 target.getNodeTypeName(), CHECK_ACCESS | CHECK_LOCK
-                | CHECK_VERSIONING | CHECK_CONSTRAINTS);
+                | CHECK_VERSIONING | CHECK_CONSTRAINTS | CHECK_HOLD | CHECK_RETENTION);
 
         // 3. do move operation (modify and store affected states)
         boolean renameOnly = srcParent.getNodeId().equals(destParent.getNodeId());
@@ -670,7 +637,7 @@
         // 2. check if target state can be removed from parent
         checkRemoveNode(target, parentId,
                 CHECK_ACCESS | CHECK_LOCK | CHECK_VERSIONING
-                | CHECK_CONSTRAINTS | CHECK_REFERENCES);
+                | CHECK_CONSTRAINTS | CHECK_REFERENCES | CHECK_HOLD | CHECK_RETENTION);
 
         // 3. do remove operation
         removeNodeState(target);
@@ -697,7 +664,8 @@
      *                     parent node is checked-out</li>
      *                     <li><code>{@link #CHECK_CONSTRAINTS}</code>:
      *                     make sure no node type constraints would be violated</li>
-     *                     <li><code>{@link #CHECK_REFERENCES}</code></li>
+     *                     <li><code>{@link #CHECK_HOLD}</code>: check for effective holds preventing the add operation</li>
+     *                     <li><code>{@link #CHECK_RETENTION}</code>: check for effective retention policy preventing the add operation</code></li>
      *                     </ul>
      * @throws ConstraintViolationException
      * @throws AccessDeniedException
@@ -732,7 +700,6 @@
         // 3. access rights
 
         if ((options & CHECK_ACCESS) == CHECK_ACCESS) {
-            AccessManager accessMgr = session.getAccessManager();
             // make sure current session is granted read access on parent node
             if (!accessMgr.isGranted(parentPath, Permission.READ)) {
                 throw new ItemNotFoundException(safeGetJCRPath(parentState.getNodeId()));
@@ -796,6 +763,17 @@
                 }
             }
         }
+
+        if ((options & CHECK_HOLD) == CHECK_HOLD) {
+            if (retentionReg.hasEffectiveHold(parentPath, false)) {
+                throw new RepositoryException("Unable to add node. Parent is affected by a hold.");
+            }
+        }
+        if ((options & CHECK_RETENTION) == CHECK_RETENTION) {
+            if (retentionReg.hasEffectiveRetention(parentPath, false)) {
+                throw new RepositoryException("Unable to add node. Parent is affected by a retention.");
+            }
+        }
     }
 
     /**
@@ -816,6 +794,8 @@
      *                    make sure no node type constraints would be violated</li>
      *                    <li><code>{@link #CHECK_REFERENCES}</code>:
      *                    make sure no references exist on target node</li>
+     *                    <li><code>{@link #CHECK_HOLD}</code>: check for effective holds preventing the add operation</li>
+     *                    <li><code>{@link #CHECK_RETENTION}</code: check for effective retention policy preventing the add operation</code></li>
      *                    </ul>
      * @throws ConstraintViolationException
      * @throws AccessDeniedException
@@ -852,6 +832,8 @@
      *                    make sure no node type constraints would be violated</li>
      *                    <li><code>{@link #CHECK_REFERENCES}</code>:
      *                    make sure no references exist on target node</li>
+     *                    <li><code>{@link #CHECK_HOLD}</code>: check for effective holds preventing the add operation</li>
+     *                    <li><code>{@link #CHECK_RETENTION}</code>: check for effective retention policy preventing the add operation</code></li>
      *                    </ul>
      * @throws ConstraintViolationException
      * @throws AccessDeniedException
@@ -892,7 +874,6 @@
         // 3. access rights
 
         if ((options & CHECK_ACCESS) == CHECK_ACCESS) {
-            AccessManager accessMgr = session.getAccessManager();
             try {
                 // make sure current session is granted read access on parent node
                 if (!accessMgr.isGranted(targetPath, Permission.READ)) {
@@ -952,6 +933,17 @@
                 }
             }
         }
+
+        if ((options & CHECK_HOLD) == CHECK_HOLD) {
+            if (retentionReg.hasEffectiveHold(targetPath, true)) {
+                throw new RepositoryException("Unable to perform removal. Node is affected by a hold.");
+            }
+        }
+        if ((options & CHECK_RETENTION) == CHECK_RETENTION) {
+            if (retentionReg.hasEffectiveRetention(targetPath, true)) {
+                throw new RepositoryException("Unable to perform removal. Node is affected by a retention.");
+            }
+        }
     }
 
     /**
@@ -963,6 +955,7 @@
      * <li>the node must not be locked by another session</li>
      * <li>the node must not be checked-in</li>
      * <li>the node must not be protected</li>
+     * <li>the node must not be affected by a hold or a retention policy</li>
      * </ul>
      *
      * @param nodePath path of node to check
@@ -988,7 +981,6 @@
         NodeState node = getNodeState(nodePath);
 
         // access rights
-        AccessManager accessMgr = session.getAccessManager();
         // make sure current session is granted read access on node
         if (!accessMgr.isGranted(nodePath, Permission.READ)) {
             throw new PathNotFoundException(safeGetJCRPath(node.getNodeId()));
@@ -1007,6 +999,13 @@
 
         // versioning status
         verifyCheckedOut(nodePath);
+
+        if (retentionReg.hasEffectiveHold(nodePath, false)) {
+            throw new RepositoryException("Unable to write. Node is affected by a hold.");
+        }
+        if (retentionReg.hasEffectiveRetention(nodePath, false)) {
+            throw new RepositoryException("Unable to write. Node is affected by a retention.");
+        }
     }
 
     /**
@@ -1027,7 +1026,6 @@
     public void verifyCanRead(Path nodePath)
             throws PathNotFoundException, RepositoryException {
         // access rights
-        AccessManager accessMgr = session.getAccessManager();
         // make sure current session is granted read access on node
         if (!accessMgr.isGranted(nodePath, Permission.READ)) {
             throw new PathNotFoundException(safeGetJCRPath(nodePath));
@@ -1599,13 +1597,17 @@
                 try {
                     NodeState nodeState = (NodeState) stateMgr.getItemState(nodeId);
                     // check if child node can be removed
-                    // (access rights, locking & versioning status);
+                    // (access rights, locking & versioning status as well
+                    //  as retention and hold);
                     // referential integrity (references) is checked
                     // on commit
                     checkRemoveNode(nodeState, targetState.getNodeId(),
                             CHECK_ACCESS
                             | CHECK_LOCK
-                            | CHECK_VERSIONING);
+                            | CHECK_VERSIONING
+                            | CHECK_HOLD
+                            | CHECK_RETENTION
+                    );
                     // remove child node
                     recursiveRemoveNodeState(nodeState);
                 } catch (ItemStateException ise) {
@@ -1728,12 +1730,14 @@
 
                         // check if existing can be removed
                         // (access rights, locking & versioning status,
-                        // node type constraints)
+                        // node type constraints and retention/hold)
                         checkRemoveNode(existingState,
                                 CHECK_ACCESS
                                 | CHECK_LOCK
                                 | CHECK_VERSIONING
-                                | CHECK_CONSTRAINTS);
+                                | CHECK_CONSTRAINTS
+                                | CHECK_HOLD
+                                | CHECK_RETENTION);
                         // do remove existing
                         removeNodeState(existingState);
                     }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java?rev=738422&r1=738421&r2=738422&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java Wed Jan 28 09:50:50 2009
@@ -53,7 +53,6 @@
 import javax.jcr.ItemVisitor;
 import javax.jcr.Node;
 import javax.jcr.PathNotFoundException;
-import javax.jcr.Property;
 import javax.jcr.PropertyType;
 import javax.jcr.ReferentialIntegrityException;
 import javax.jcr.RepositoryException;
@@ -814,32 +813,16 @@
         }
 
         NodeImpl parentNode = (NodeImpl) getParent();
-
         if (!noChecks) {
-            // check if protected
-            ItemDefinition definition;
-            if (isNode()) {
-                definition = ((Node) this).getDefinition();
-            } else {
-                definition = ((Property) this).getDefinition();
-            }
-            if (definition.isProtected()) {
-                throw new ConstraintViolationException(
-                        "Cannot remove a protected item: " + this);
-            }
-
-            // verify that parent node is checked-out and not protected
-            if (!parentNode.internalIsCheckedOut()) {
-                throw new VersionException(
-                        "Cannot remove a child of a checked-in node: " + this);
-            }
-            if (parentNode.getDefinition().isProtected()) {
-                throw new ConstraintViolationException(
-                        "Cannot remove a child of a protected node: " + this);
-            }
-
-            // check lock status
-            parentNode.checkLock();
+            // check if protected and not under retention/hold
+            int options = ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD |
+                    ItemValidator.CHECK_RETENTION;
+            session.getValidator().checkRemove(this, options, Permission.NONE);
+
+            // parent node: make sure it is checked-out and not protected nor locked.
+            options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING |
+                    ItemValidator.CHECK_CONSTRAINTS;
+            session.getValidator().checkModify(parentNode, options, Permission.NONE);
         }
 
         // delegate the removal of the child item to the parent node

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemValidator.java?rev=738422&r1=738421&r2=738422&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemValidator.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemValidator.java Wed Jan 28 09:50:50 2009
@@ -24,6 +24,10 @@
 import org.apache.jackrabbit.core.state.NodeState;
 import org.apache.jackrabbit.core.state.PropertyState;
 import org.apache.jackrabbit.core.value.InternalValue;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.security.AccessManager;
+import org.apache.jackrabbit.core.lock.LockManager;
+import org.apache.jackrabbit.core.retention.RetentionRegistry;
 import org.apache.jackrabbit.spi.Path;
 import org.apache.jackrabbit.spi.commons.conversion.PathResolver;
 import org.apache.jackrabbit.spi.Name;
@@ -34,7 +38,13 @@
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.ItemNotFoundException;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.lock.LockException;
+import javax.jcr.version.VersionException;
 import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.ItemDefinition;
 
 /**
  * Utility class for validating an item against constraints
@@ -43,6 +53,50 @@
 public class ItemValidator {
 
     /**
+     * check access permissions
+     */
+    public static final int CHECK_ACCESS = 1;
+
+    /**
+     * option to check lock status
+     */
+    public static final int CHECK_LOCK = 2;
+    /**
+     * option to check checked-out status
+     */
+    public static final int CHECK_VERSIONING = 4;
+
+    /**
+     * check for referential integrity upon removal
+     */
+    public static final int CHECK_REFERENCES = 8;
+
+    /**
+     * option to check if the item is protected by it's nt definition
+     */
+    public static final int CHECK_CONSTRAINTS = 16;
+
+    /**
+     * option to check for pending changes on the session
+     */
+    public static final int CHECK_PENDING_CHANGES = 32;
+
+    /**
+     * option to check for pending changes on the specified node
+     */
+    public static final int CHECK_PENDING_CHANGES_ON_NODE = 64;
+
+    /**
+     * option to check for effective holds
+     */
+    public static final int CHECK_HOLD = 128;
+
+    /**
+     * option to check for effective retention policies
+     */
+    public static final int CHECK_RETENTION = 256;
+    
+    /**
      * Logger instance for this class
      */
     private static Logger log = LoggerFactory.getLogger(ItemValidator.class);
@@ -66,18 +120,49 @@
     protected final PathResolver resolver;
 
     /**
+     *
+     */
+    protected final LockManager lockMgr;
+
+    protected final AccessManager accessMgr;
+
+    protected final RetentionRegistry retentionReg;
+
+    /**
      * Creates a new <code>ItemValidator</code> instance.
      *
      * @param ntReg      node type registry
      * @param hierMgr    hierarchy manager
-     * @param resolver   path resolver
+     * @param session    session
      */
     public ItemValidator(NodeTypeRegistry ntReg,
                          HierarchyManager hierMgr,
-                         PathResolver resolver) {
+                         SessionImpl session) throws RepositoryException {
+        this(ntReg, hierMgr, session, session.getLockManager(), session.getAccessManager(), session.getRetentionRegistry());
+    }
+
+    /**
+     * Creates a new <code>ItemValidator</code> instance.
+     *
+     * @param ntReg      node type registry
+     * @param hierMgr    hierarchy manager
+     * @param resolver   resolver
+     * @param lockMgr    lockMgr
+     * @param accessMgr  accessMgr
+     * @param retentionReg
+     */
+    public ItemValidator(NodeTypeRegistry ntReg,
+                         HierarchyManager hierMgr,
+                         PathResolver resolver,
+                         LockManager lockMgr,
+                         AccessManager accessMgr,
+                         RetentionRegistry retentionReg) {
         this.ntReg = ntReg;
         this.hierMgr = hierMgr;
         this.resolver = resolver;
+        this.lockMgr = lockMgr;
+        this.accessMgr = accessMgr;
+        this.retentionReg = retentionReg;
     }
 
     /**
@@ -178,6 +263,161 @@
         EffectiveNodeType.checkSetPropertyValueConstraints(def, values);
     }
 
+    public void checkModify(ItemImpl item, int options, int permissions) throws RepositoryException {
+        checkCondition(item, options, permissions, false);
+    }
+
+    public void checkRemove(ItemImpl item, int options, int permissions) throws RepositoryException {
+        checkCondition(item, options, permissions, true);
+    }
+
+    private void checkCondition(ItemImpl item, int options, int permissions, boolean isRemoval) throws RepositoryException {
+        if ((options & CHECK_PENDING_CHANGES) == CHECK_PENDING_CHANGES) {
+            if (item.getSession().hasPendingChanges()) {
+                String msg = "Unable to perform operation. Session has pending changes.";
+                log.debug(msg);
+                throw new InvalidItemStateException(msg);
+            }
+        }
+        if ((options & CHECK_PENDING_CHANGES_ON_NODE) == CHECK_PENDING_CHANGES_ON_NODE) {
+            if (item.isNode() && ((NodeImpl) item).hasPendingChanges()) {
+                String msg = "Unable to perform operation. Session has pending changes.";
+                log.debug(msg);
+                throw new InvalidItemStateException(msg);
+            }
+        }
+        if ((options & CHECK_CONSTRAINTS) == CHECK_CONSTRAINTS) {
+            if (isProtected(item)) {
+                String msg = "Unable to perform operation. Node is protected.";
+                log.debug(msg);
+                throw new ConstraintViolationException(msg);
+            }
+        }
+        if ((options & CHECK_VERSIONING) == CHECK_VERSIONING) {
+            NodeImpl node = (item.isNode()) ? (NodeImpl) item : (NodeImpl) item.getParent();
+            if (!node.internalIsCheckedOut()) {
+                String msg = "Unable to perform operation. Node is checked-in.";
+                log.debug(msg);
+                throw new VersionException(msg);
+            }
+        }
+        if ((options & CHECK_LOCK) == CHECK_LOCK) {
+            checkLock(item);
+        }
+
+        if (permissions > Permission.NONE) {
+            Path path = item.getPrimaryPath();
+            accessMgr.checkPermission(path, permissions);
+        }
+        if ((options & CHECK_HOLD) == CHECK_HOLD) {
+            if (hasHold(item, isRemoval)) {
+                throw new RepositoryException("Unable to perform operation. Node is affected by a hold.");
+            }
+        }
+        if ((options & CHECK_RETENTION) == CHECK_RETENTION) {
+            if (hasRetention(item, isRemoval)) {
+                throw new RepositoryException("Unable to perform operation. Node is affected by a retention.");
+            }
+        }
+    }
+
+    public boolean canModify(ItemImpl item, int options, int permissions) throws RepositoryException {
+        return hasCondition(item, options, permissions, false);
+    }
+
+    private boolean hasCondition(ItemImpl item, int options, int permissions, boolean isRemoval) throws RepositoryException {
+        if ((options & CHECK_PENDING_CHANGES) == CHECK_PENDING_CHANGES) {
+            if (item.getSession().hasPendingChanges()) {
+                return false;
+            }
+        }
+        if ((options & CHECK_PENDING_CHANGES_ON_NODE) == CHECK_PENDING_CHANGES_ON_NODE) {
+            if (item.isNode() && ((NodeImpl) item).hasPendingChanges()) {
+                return false;
+            }
+        }
+        if ((options & CHECK_CONSTRAINTS) == CHECK_CONSTRAINTS) {
+            if (isProtected(item)) {
+                return false;
+            }
+        }
+        if ((options & CHECK_VERSIONING) == CHECK_VERSIONING) {
+            NodeImpl node = (item.isNode()) ? (NodeImpl) item : (NodeImpl) item.getParent();
+            if (!node.internalIsCheckedOut()) {
+                return false;
+            }
+        }
+        if ((options & CHECK_LOCK) == CHECK_LOCK) {
+            try {
+                checkLock(item);
+            } catch (LockException e) {
+                return false;
+            }
+        }
+        if (permissions > Permission.NONE) {
+            Path path = item.getPrimaryPath();
+            if (!accessMgr.isGranted(item.getPrimaryPath(), permissions)) {
+                return false;
+            }
+        }
+        if ((options & CHECK_HOLD) == CHECK_HOLD) {
+            if (hasHold(item, isRemoval)) {
+                return false;
+            }
+        }
+        if ((options & CHECK_RETENTION) == CHECK_RETENTION) {
+            if (hasRetention(item, isRemoval)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void checkLock(ItemImpl item) throws LockException, RepositoryException {
+        if (item.isNew()) {
+            // a new item needs no check
+            return;
+        }
+        NodeImpl node = (item.isNode()) ? (NodeImpl) item : (NodeImpl) item.getParent();
+        lockMgr.checkLock(node);
+    }
+
+    private boolean isProtected(ItemImpl item) throws RepositoryException {
+        ItemDefinition def;
+        if (item.isNode()) {
+            def = ((Node) item).getDefinition();
+        } else {
+            def = ((Property) item).getDefinition();
+        }
+        return def.isProtected();
+    }
+
+    private boolean hasHold(ItemImpl item, boolean isRemoval) throws RepositoryException {
+        if (item.isNew()) {
+            return false;
+        }
+        Path path = item.getPrimaryPath();
+        if (!item.isNode()) {
+            path = path.getAncestor(1);
+        }
+        boolean checkParent = (item.isNode() && isRemoval);
+        return retentionReg.hasEffectiveHold(path, checkParent);
+    }
+
+    private boolean hasRetention(ItemImpl item, boolean isRemoval) throws RepositoryException {
+        if (item.isNew()) {
+            return false;
+        }
+        Path path = item.getPrimaryPath();
+        if (!item.isNode()) {
+            path = path.getAncestor(1);
+        }
+        boolean checkParent = (item.isNode() && isRemoval);
+        return retentionReg.hasEffectiveRetention(path, checkParent);
+    }
+
+
+    
     //-------------------------------------------------< misc. helper methods >
     /**
      * Helper method that builds the effective (i.e. merged and resolved)

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=738422&r1=738421&r2=738422&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 Wed Jan 28 09:50:50 2009
@@ -45,7 +45,6 @@
 import org.apache.jackrabbit.core.version.VersionImpl;
 import org.apache.jackrabbit.core.version.VersionSelector;
 import org.apache.jackrabbit.core.security.authorization.Permission;
-import org.apache.jackrabbit.core.security.AccessManager;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.Path;
 import org.apache.jackrabbit.spi.commons.conversion.MalformedPathException;
@@ -722,15 +721,9 @@
             throw new PathNotFoundException(relPath);
         }
 
-        // make sure that parent node is checked-out
-        if (!parentNode.internalIsCheckedOut()) {
-            String msg = this + ": cannot add a child to a checked-in node";
-            log.debug(msg);
-            throw new VersionException(msg);
-        }
-
-        // check lock status
-        parentNode.checkLock();
+        // make sure that parent node is checked-out and not locked
+        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING;
+        session.getValidator().checkModify(parentNode, options, Permission.NONE);
 
         // delegate the creation of the child node to the parent node
         return parentNode.internalAddChildNode(nodeName, nodeType, id);
@@ -794,13 +787,10 @@
             }
         }
 
-        // check protected flag of parent (i.e. this) node
-        final NodeDefinition definition = data.getNodeDefinition();
-        if (definition.isProtected()) {
-            String msg = this + ": cannot add a child to a protected node";
-            log.debug(msg);
-            throw new ConstraintViolationException(msg);
-        }
+        // check protected flag of parent (i.e. this) node and retention/hold
+        int options = ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD |
+                ItemValidator.CHECK_RETENTION;
+        session.getValidator().checkModify(this, options, Permission.NONE);
 
         // now do create the child node
         return createChildNode(nodeName, def, nodeType, id);
@@ -1007,33 +997,16 @@
         // check state of this instance
         sanityCheck();
 
-        // make sure this node is checked-out
-        if (!internalIsCheckedOut()) {
-            String msg = this + ": cannot add a mixin node type to a checked-in node";
-            log.debug(msg);
-            throw new VersionException(msg);
-        }
-
-        // check protected flag
-        final NodeDefinition definition = data.getNodeDefinition();
-        if (definition.isProtected()) {
-            String msg = this + ": cannot add a mixin node type to a protected node";
-            log.debug(msg);
-            throw new ConstraintViolationException(msg);
-        }
-
-        // check lock status
-        checkLock();
-        // check permissions
-        Path p = getPrimaryPath();
-        AccessManager acMgr = session.getAccessManager();
-        acMgr.checkPermission(p, Permission.NODE_TYPE_MNGMT);
+        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING |
+                ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
+        int permissions = Permission.NODE_TYPE_MNGMT;
         // special handling of mix:versionable. since adding the mixin alters
         // the version storage jcr:versionManagement privilege is required
         // in addition.
         if (NameConstants.MIX_VERSIONABLE.equals(mixinName)) {
-            acMgr.checkPermission(p, Permission.VERSION_MNGMT);
+            permissions |= Permission.VERSION_MNGMT;
         }
+        session.getValidator().checkModify(this, options, permissions);
 
         NodeTypeManagerImpl ntMgr = session.getNodeTypeManager();
         NodeTypeImpl mixin = ntMgr.getNodeType(mixinName);
@@ -1129,27 +1102,10 @@
         // check state of this instance
         sanityCheck();
 
-        // make sure this node is checked-out
-        if (!internalIsCheckedOut()) {
-            String msg =
-                this + ": cannot remove a mixin node type from a checked-in node";
-            log.debug(msg);
-            throw new VersionException(msg);
-        }
-
-        // check protected flag
-        NodeDefinition definition = data.getNodeDefinition();
-        if (definition.isProtected()) {
-            String msg =
-                this + ": cannot remove a mixin node type from a protected node";
-            log.debug(msg);
-            throw new ConstraintViolationException(msg);
-        }
-
-        // check lock status
-        checkLock();
-        // check permission
-        session.getAccessManager().checkPermission(getPrimaryPath(), Permission.NODE_TYPE_MNGMT);
+        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING |
+                ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
+        int permissions = Permission.NODE_TYPE_MNGMT;
+        session.getValidator().checkModify(this, options, permissions);
 
         // check if mixin is assigned
         final NodeState state = data.getNodeState();
@@ -1325,15 +1281,9 @@
      */
     protected void checkSetProperty()
             throws VersionException, LockException, RepositoryException {
-        // make sure this node is checked-out
-        if (!internalIsCheckedOut()) {
-            String msg = this + ": cannot set property of a checked-in node";
-            log.debug(msg);
-            throw new VersionException(msg);
-        }
-
-        // check lock status
-        checkLock();
+        // make sure this node is checked-out and is not locked
+        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING;
+        session.getValidator().checkModify(this, options, Permission.NONE);
     }
 
     /**
@@ -1590,15 +1540,9 @@
         // check state of this instance
         sanityCheck();
 
-        // make sure this node is checked-out
-        if (!internalIsCheckedOut()) {
-            String msg = this + ": cannot add node to a checked-in node";
-            log.debug(msg);
-            throw new VersionException(msg);
-        }
-
-        // check lock status
-        checkLock();
+        // make sure this node is checked-out and not locked by another session.
+        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING;
+        session.getValidator().checkModify(this, options, Permission.NONE);
 
         NodeTypeImpl nt = null;
         if (nodeTypeName != null) {
@@ -1827,25 +1771,10 @@
                     this + " has no child node with name " + name);
         }
 
-        // make sure this node is checked-out
-        if (!internalIsCheckedOut()) {
-            String msg =
-                this + ": cannot change child node ordering of a checked-in node";
-            log.debug(msg);
-            throw new VersionException(msg);
-        }
-
-        // check protected flag
-        final NodeDefinition definition = data.getNodeDefinition();
-        if (definition.isProtected()) {
-            String msg =
-                this + ": cannot change child node ordering of a protected node";
-            log.debug(msg);
-            throw new ConstraintViolationException(msg);
-        }
-
-        // check lock status
-        checkLock();
+        // make sure this node is checked-out and neither protected nor locked
+        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING |
+                ItemValidator.CHECK_CONSTRAINTS;
+        session.getValidator().checkModify(this, options, Permission.NONE);
 
         ArrayList list = new ArrayList(data.getNodeState().getChildNodeEntries());
         int srcInd = -1, destInd = -1;
@@ -2011,16 +1940,12 @@
         }
 
         // (1) make sure that parent node is checked-out
-        if (!internalIsCheckedOut()) {
-            String msg = this + ": cannot add a child to a checked-in node";
-            log.debug(msg);
-            throw new VersionException(msg);
-        }
-
         // (2) check lock status
-        checkLock();
+        // (3) check protected flag of parent (i.e. this) node
+        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING | ItemValidator.CHECK_CONSTRAINTS;
+        session.getValidator().checkModify(this, options, Permission.NONE);
 
-        // (3) check for name collisions
+        // (4) check for name collisions
         NodeDefinitionImpl def;
         try {
             def = getApplicableChildNodeDefinition(name, null);
@@ -2044,14 +1969,6 @@
             }
         }
 
-        // (4) check protected flag of parent (i.e. this) node
-        final NodeDefinition definition = data.getNodeDefinition();
-        if (definition.isProtected()) {
-            String msg = this + ": cannot add a child to a protected node";
-            log.debug(msg);
-            throw new ConstraintViolationException(msg);
-        }
-
         // (5) do clone operation
         NodeId parentId = getNodeId();
         src.addShareParent(parentId);
@@ -2851,49 +2768,23 @@
         // check state of this instance
         sanityCheck();
 
-        // check checked-out status
-        if (!internalIsCheckedOut()) {
-            return false;
-        }
-
-        // check protected flag
-        if (data.getNodeDefinition().isProtected()) {
-            return false;
-        }
-
-        // check lock status
-        try {
-            checkLock();
-        } catch (LockException le) {
-            return false;
-        }
-
-        Name ntName;
-        try {
-            ntName = session.getQName(mixinName);
-        } catch (NameException e) {
-            throw new RepositoryException(
-                    "invalid mixin type name: " + mixinName, e);
-        }
-
-        // check permissions
-        Path p = getPrimaryPath();
-        AccessManager acMgr = session.getAccessManager();
-        if (!acMgr.isGranted(p, Permission.NODE_TYPE_MNGMT)) {
+        Name ntName = session.getQName(mixinName);
+        NodeTypeManagerImpl ntMgr = session.getNodeTypeManager();
+        NodeTypeImpl mixin = ntMgr.getNodeType(ntName);
+        if (!mixin.isMixin()) {
             return false;
         }
+        
+        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING |
+                ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
+        int permissions = Permission.NODE_TYPE_MNGMT;
         // special handling of mix:versionable. since adding the mixin alters
         // the version storage jcr:versionManagement privilege is required
         // in addition.
         if (NameConstants.MIX_VERSIONABLE.equals(ntName)) {
-            if (!acMgr.isGranted(p, Permission.VERSION_MNGMT)) {
-                return false;
-            }
+            permissions |= Permission.VERSION_MNGMT;
         }
-
-        NodeTypeManagerImpl ntMgr = session.getNodeTypeManager();
-        NodeTypeImpl mixin = ntMgr.getNodeType(ntName);
-        if (!mixin.isMixin()) {
+        if (!session.getValidator().canModify(this, options, permissions)) {
             return false;
         }
 
@@ -3339,17 +3230,9 @@
             return getBaseVersion();
         }
 
-        // check for pending changes
-        if (hasPendingChanges()) {
-            String msg = "Unable to checkin node. Node has pending changes: " + this;
-            log.debug(msg);
-            throw new InvalidItemStateException(msg);
-        }
-
-        // check lock status
-        checkLock();
-        // check permission
-        session.getAccessManager().checkPermission(getPrimaryPath(), Permission.VERSION_MNGMT);
+        // check lock status, holds and permissions
+        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_HOLD | ItemValidator.CHECK_PENDING_CHANGES_ON_NODE;
+        session.getValidator().checkModify(this, options, Permission.VERSION_MNGMT);
 
         Version v = session.getVersionManager().checkin(this);
         boolean success = false;
@@ -3392,10 +3275,8 @@
             return;
         }
 
-        // check lock status
-        checkLock();
-        // check permission
-        session.getAccessManager().checkPermission(getPrimaryPath(), Permission.VERSION_MNGMT);
+        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_HOLD;
+        session.getValidator().checkModify(this, options, Permission.VERSION_MNGMT);
 
         boolean hasPendingChanges = hasPendingChanges();
         Property[] props = new Property[2];
@@ -3487,8 +3368,8 @@
 
         // checks
         sanityCheck();
-        checkSessionHasPending();
-        checkLock();
+        int options = ItemValidator.CHECK_PENDING_CHANGES | ItemValidator.CHECK_LOCK | ItemValidator.CHECK_HOLD;
+        session.getValidator().checkModify(this, options, Permission.NONE);
 
         Version v = getVersionHistory().getVersion(versionName);
         DateVersionSelector gvs = new DateVersionSelector(v.getCreated());
@@ -3506,9 +3387,9 @@
 
         // do checks
         sanityCheck();
-        checkSessionHasPending();
         checkVersionable();
-        checkLock();
+        int options = ItemValidator.CHECK_PENDING_CHANGES | ItemValidator.CHECK_LOCK| ItemValidator.CHECK_HOLD;
+        session.getValidator().checkModify(this, options, Permission.NONE);
 
         // check if 'own' version
         if (!version.getContainingHistory().isSame(getVersionHistory())) {
@@ -3529,8 +3410,8 @@
 
         // do checks
         sanityCheck();
-        checkSessionHasPending();
-        checkLock();
+        int options = ItemValidator.CHECK_PENDING_CHANGES | ItemValidator.CHECK_LOCK | ItemValidator.CHECK_HOLD;
+        session.getValidator().checkModify(this, options, Permission.NONE);
 
         // if node exists, do a 'normal' restore
         if (hasNode(relPath)) {
@@ -3578,8 +3459,8 @@
 
         // do checks
         sanityCheck();
-        checkSessionHasPending();
-        checkLock();
+        int options = ItemValidator.CHECK_PENDING_CHANGES | ItemValidator.CHECK_LOCK| ItemValidator.CHECK_HOLD;
+        session.getValidator().checkModify(this, options, Permission.NONE);
 
         Version v = getVersionHistory().getVersionByLabel(versionLabel);
         if (v == null) {
@@ -3642,24 +3523,6 @@
     }
 
     /**
-     * Checks if this nodes session has pending changes.
-     *
-     * @throws InvalidItemStateException if this nodes session has pending changes
-     * @throws RepositoryException
-     */
-    private void checkSessionHasPending()
-            throws InvalidItemStateException, RepositoryException {
-        // check for pending changes
-        if (session.hasPendingChanges()) {
-            String msg = "Unable to perform operation. Session has pending changes.";
-            log.debug(msg);
-            throw new InvalidItemStateException(msg);
-        }
-
-
-    }
-
-    /**
      * Returns the corresponding node in the workspace of the given session.
      * <p/>
      * Given a node N1 in workspace W1, its corresponding node N2 in workspace
@@ -3834,28 +3697,12 @@
         // check state of this instance
         sanityCheck();
 
-        // check for pending changes
-        if (hasPendingChanges()) {
-            String msg =
-                "Unable to finish merge. Node has pending changes: " + this;
-            log.debug(msg);
-            throw new InvalidItemStateException(msg);
-        }
-
         // check versionable
         checkVersionable();
 
-        // check lock
-        checkLock();
-        // check permission
-        session.getAccessManager().checkPermission(getPrimaryPath(), Permission.VERSION_MNGMT);
-
-        // check if checked out
-        if (!internalIsCheckedOut()) {
-            String msg = "Unable to finish merge. Node is checked-in: " + this;
-            log.error(msg);
-            throw new VersionException(msg);
-        }
+        // check lock, permissions and checkout-status
+        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING | ItemValidator.CHECK_PENDING_CHANGES_ON_NODE | ItemValidator.CHECK_HOLD;
+        session.getValidator().checkModify(this, options, Permission.VERSION_MNGMT);
 
         // check if version is in mergeFailed list
         Set failed = internalGetMergeFailed();
@@ -4089,9 +3936,7 @@
 
         // do checks
         sanityCheck();
-        checkSessionHasPending();
-        // check permission
-        session.getAccessManager().checkPermission(getPrimaryPath(), Permission.VERSION_MNGMT);
+        session.getValidator().checkModify(this, ItemValidator.CHECK_PENDING_CHANGES, Permission.VERSION_MNGMT);
 
         // if same workspace, ignore
         if (srcWorkspaceName.equals(session.getWorkspace().getName())) {
@@ -4151,8 +3996,9 @@
             return;
         }
 
-        // check lock status
-        checkLock();
+        // check lock and hold status
+        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_HOLD;
+        session.getValidator().checkModify(this, options, Permission.NONE);
 
         // update the properties
         PropertyIterator iter = getProperties();
@@ -4616,6 +4462,7 @@
      *
      * @throws LockException       if this node is locked by somebody else
      * @throws RepositoryException if some other error occurs
+     * @deprecated
      */
     protected void checkLock() throws LockException, RepositoryException {
         if (isNew()) {
@@ -4687,19 +4534,11 @@
         // check state of this instance
         sanityCheck();
 
-        // make sure this node is checked-out
-        if (!internalIsCheckedOut()) {
-            String msg = this + ": cannot set primary type of a checked-in node";
-            log.debug(msg);
-            throw new VersionException(msg);
-        }
-
-        // check protected flag
-        if (data.getDefinition().isProtected()) {
-            String msg = this + ": cannot set primary type of a protected node";
-            log.debug(msg);
-            throw new ConstraintViolationException(msg);
-        }
+        // make sure this node is checked-out, neither protected nor locked and
+        // the editing session has sufficient permission to change the primary type.
+        int options = ItemValidator.CHECK_VERSIONING | ItemValidator.CHECK_LOCK |
+                ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
+        session.getValidator().checkModify(this, options, Permission.NODE_TYPE_MNGMT);
 
         final NodeState state = data.getNodeState();
         if (state.getParentId() == null) {
@@ -4708,20 +4547,9 @@
             throw new RepositoryException(msg);
         }
 
-        // check lock status
-        checkLock();
-        // check permission
-        session.getAccessManager().checkPermission(getPrimaryPath(), Permission.NODE_TYPE_MNGMT);
-
-        Name ntName;
-        try {
-            ntName = session.getQName(nodeTypeName);
-        } catch (NameException e) {
-            throw new RepositoryException(
-                    "invalid node type name: " + nodeTypeName, e);
-        }
-
+        Name ntName = session.getQName(nodeTypeName);
         if (ntName.equals(state.getNodeTypeName())) {
+            log.debug("Node already has " + nodeTypeName + " as primary node type.");
             return;
         }
 

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyImpl.java?rev=738422&r1=738421&r2=738422&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyImpl.java Wed Jan 28 09:50:50 2009
@@ -23,6 +23,7 @@
 import org.apache.jackrabbit.core.value.InternalValue;
 import org.apache.jackrabbit.core.nodetype.PropDefId;
 import org.apache.jackrabbit.core.nodetype.PropertyDefinitionImpl;
+import org.apache.jackrabbit.core.security.authorization.Permission;
 import org.apache.jackrabbit.spi.Path;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.value.ValueHelper;
@@ -236,36 +237,22 @@
             RepositoryException {
         NodeImpl parent = (NodeImpl) getParent();
         PropertyDefinition definition = data.getPropertyDefinition();
-
-        // verify that parent node is checked-out
-        if (!parent.internalIsCheckedOut()) {
-            throw new VersionException(
-                    "Cannot set a property of a checked-in node: " + this);
-        }
-
-        // check protected flag
-        if (definition.isProtected()) {
-            throw new ConstraintViolationException(
-                    "Cannot set the value of a protected property: " + this);
-        }
-
         // check multi-value flag
-        if (multipleValues) {
-            if (!definition.isMultiple()) {
-                throw new ValueFormatException(
-                        "Single-valued property can not be set to"
-                        + " an array of values: " + this);
-            }
-        } else {
-            if (definition.isMultiple()) {
-                throw new ValueFormatException(
-                        "Multivalued property can not be set to a single"
-                        + " value (an array of lenght one is OK): " + this);
-            }
+        if (multipleValues != definition.isMultiple()) {
+            String msg = (multipleValues) ?
+                    "Single-valued property can not be set to an array of values:" :
+                    "Multivalued property can not be set to a single value (an array of lenght one is OK): ";
+            throw new ValueFormatException(msg + this);
         }
 
-        // check lock status
-        parent.checkLock();
+        // check protected flag and for retention/hold      
+        int options = ItemValidator.CHECK_CONSTRAINTS;
+        session.getValidator().checkModify(this, options, Permission.NONE);
+        
+        // make sure the parent is checked-out and neither locked nor under retention
+        options = ItemValidator.CHECK_VERSIONING | ItemValidator.CHECK_LOCK |
+                ItemValidator.CHECK_HOLD | ItemValidator.CHECK_RETENTION;
+        session.getValidator().checkModify(parent, options, Permission.NONE);
     }
 
     /**

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ProtectedItemModifier.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ProtectedItemModifier.java?rev=738422&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ProtectedItemModifier.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ProtectedItemModifier.java Wed Jan 28 09:50:50 2009
@@ -0,0 +1,166 @@
+/*
+ * 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;
+
+import org.apache.jackrabbit.core.nodetype.NodeDefinitionImpl;
+import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
+import org.apache.jackrabbit.core.security.AccessManager;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.security.authorization.acl.ACLEditor;
+import org.apache.jackrabbit.core.security.user.UserManagerImpl;
+import org.apache.jackrabbit.core.state.ChildNodeEntry;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.value.InternalValue;
+import org.apache.jackrabbit.core.retention.RetentionManagerImpl;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ItemExistsException;
+import javax.jcr.AccessDeniedException;
+
+/**
+ * <code>SecurityItemModifier</code>: An abstract helper class to allow classes
+ * of the security API residing outside of the core package to modify and remove
+ * protected items for security. The protected item definitions are required in
+ * order not to have security relevant content being changed through common
+ * item operations but forcing the usage of the security API. The latter asserts
+ * that implementation specific constraints are not violated.
+ */
+public abstract class ProtectedItemModifier {
+
+    private static final int DEFAULT_PERM_CHECK = -1;
+    private final int permission;
+
+    protected ProtectedItemModifier() {
+        this(DEFAULT_PERM_CHECK);
+    }
+
+    protected ProtectedItemModifier(int permission) {
+        Class cl = getClass();
+        if (!(cl.equals(UserManagerImpl.class) ||
+              cl.equals(RetentionManagerImpl.class) ||
+              cl.equals(ACLEditor.class) ||
+              cl.equals(org.apache.jackrabbit.core.security.authorization.principalbased.ACLEditor.class))) {
+            throw new IllegalArgumentException("Only UserManagerImpl, RetentionManagerImpl and ACLEditor may extend from the ProtectedItemModifier");
+        }
+        this.permission = permission;
+    }
+
+    protected NodeImpl addNode(NodeImpl parentImpl, Name name, Name ntName) throws RepositoryException {
+        checkPermission(parentImpl, name, getPermission(true, false));
+        // validation: make sure Node is not locked or checked-in.
+        parentImpl.checkSetProperty();
+
+        NodeTypeImpl nodeType = parentImpl.session.getNodeTypeManager().getNodeType(ntName);
+        NodeDefinitionImpl def = parentImpl.getApplicableChildNodeDefinition(name, ntName);
+
+        // check for name collisions
+        // TODO: improve. copied from NodeImpl
+        NodeState thisState = (NodeState) parentImpl.getItemState();
+        ChildNodeEntry cne = thisState.getChildNodeEntry(name, 1);
+        if (cne != null) {
+            // there's already a child node entry with that name;
+            // check same-name sibling setting of new node
+            if (!def.allowsSameNameSiblings()) {
+                throw new ItemExistsException();
+            }
+            // check same-name sibling setting of existing node
+            NodeId newId = cne.getId();
+            NodeImpl n = (NodeImpl) parentImpl.session.getItemManager().getItem(newId);
+            if (!n.getDefinition().allowsSameNameSiblings()) {
+                throw new ItemExistsException();
+            }
+        }
+
+        return parentImpl.createChildNode(name, def, nodeType, null);
+    }
+
+    protected Property setProperty(NodeImpl parentImpl, Name name, Value value) throws RepositoryException {
+        return setProperty(parentImpl, name, value, false);
+    }
+
+    protected Property setProperty(NodeImpl parentImpl, Name name, Value value, boolean ignorePermissions) throws RepositoryException {
+        if (!ignorePermissions) {
+            checkPermission(parentImpl, name, getPermission(false, false));
+        }
+        // validation: make sure Node is not locked or checked-in.
+        parentImpl.checkSetProperty();
+        InternalValue intVs = InternalValue.create(value, parentImpl.session);
+        return parentImpl.internalSetProperty(name, intVs);
+    }
+
+    protected Property setProperty(NodeImpl parentImpl, Name name, Value[] values) throws RepositoryException {
+        checkPermission(parentImpl, name, getPermission(false, false));
+        // validation: make sure Node is not locked or checked-in.
+        parentImpl.checkSetProperty();
+        InternalValue[] intVs = new InternalValue[values.length];
+        for (int i = 0; i < values.length; i++) {
+            intVs[i] = InternalValue.create(values[i], parentImpl.session);
+        }
+        return parentImpl.internalSetProperty(name, intVs);
+    }
+
+    protected void removeItem(ItemImpl itemImpl) throws RepositoryException {
+        NodeImpl n;
+        if (itemImpl.isNode()) {
+            n = (NodeImpl) itemImpl;
+        } else {
+            n = (NodeImpl) itemImpl.getParent();
+        }
+        checkPermission(itemImpl, getPermission(itemImpl.isNode(), true));
+        // validation: make sure Node is not locked or checked-in.
+        n.checkSetProperty();
+        itemImpl.internalRemove(true);
+    }
+
+    private void checkPermission(ItemImpl item, int perm) throws RepositoryException {
+        if (perm > Permission.NONE) {
+            SessionImpl sImpl = (SessionImpl) item.getSession();
+            AccessManager acMgr = sImpl.getAccessManager();
+
+            Path path = item.getPrimaryPath();
+            acMgr.checkPermission(path, perm);
+        }
+    }
+
+    private void checkPermission(NodeImpl node, Name childName, int perm) throws RepositoryException {
+        if (perm > Permission.NONE) {
+            SessionImpl sImpl = (SessionImpl) node.getSession();
+            AccessManager acMgr = sImpl.getAccessManager();
+
+            boolean isGranted = acMgr.isGranted(node.getPrimaryPath(), childName, perm);
+            if (!isGranted) {
+                throw new AccessDeniedException("Permission denied.");
+            }
+        }
+    }
+
+    private int getPermission(boolean isNode, boolean isRemove) {
+        if (permission < Permission.NONE) {
+            if (isNode) {
+                return (isRemove) ? Permission.REMOVE_NODE : Permission.ADD_NODE;
+            } else {
+                return (isRemove) ? Permission.REMOVE_PROPERTY : Permission.SET_PROPERTY;
+            }
+        } else {
+            return permission;
+        }
+    }
+}
\ No newline at end of file

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

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ProtectedItemModifier.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java?rev=738422&r1=738421&r2=738422&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java Wed Jan 28 09:50:50 2009
@@ -67,6 +67,8 @@
 import org.apache.jackrabbit.core.version.VersionManager;
 import org.apache.jackrabbit.core.version.VersionManagerImpl;
 import org.apache.jackrabbit.core.xml.ClonedInputSource;
+import org.apache.jackrabbit.core.retention.RetentionRegistry;
+import org.apache.jackrabbit.core.retention.RetentionRegistryImpl;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
 import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
 import org.apache.jackrabbit.spi.commons.namespace.RegistryNamespaceResolver;
@@ -940,6 +942,21 @@
     }
 
     /**
+     * Returns the {@link org.apache.jackrabbit.core.retention.RetentionRegistry} for the workspace with name
+     * <code>workspaceName</code>
+     *
+     * @param workspaceName workspace name
+     * @return <code>RetentionEvaluator</code> for the workspace
+     * @throws NoSuchWorkspaceException if such a workspace does not exist
+     * @throws RepositoryException      if some other error occurs
+     */
+    RetentionRegistry getRetentionRegistry(String workspaceName) throws NoSuchWorkspaceException, RepositoryException {
+        // check sanity of this instance
+        sanityCheck();
+        return getWorkspaceInfo(workspaceName).getRetentionRegistry();
+    }
+
+    /**
      * Returns the {@link SystemSession} for the workspace with name
      * <code>workspaceName</code>
      *
@@ -1573,6 +1590,12 @@
         private LockManagerImpl lockMgr;
 
         /**
+         * internal manager for evaluation of effective retention policies
+         * and holds
+         */
+        private RetentionRegistryImpl retentionReg;
+
+        /**
          * flag indicating whether this instance has been initialized.
          */
         private boolean initialized;
@@ -1798,6 +1821,24 @@
         }
 
         /**
+         * Return manager used for evaluating effect retention and holds.
+         *
+         * @return
+         * @throws RepositoryException
+         */
+        protected RetentionRegistry getRetentionRegistry() throws RepositoryException {
+            if (!isInitialized()) {
+                throw new IllegalStateException("workspace '" + getName() + "' not initialized");
+            }
+            synchronized (this) {
+                if (retentionReg == null) {
+                    retentionReg = new RetentionRegistryImpl(getSystemSession(), fs);
+                }
+                return retentionReg;
+            }
+        }
+
+        /**
          * Returns the system session for this workspace.
          *
          * @return the system session for this workspace
@@ -2043,12 +2084,17 @@
                 lockMgr = null;
             }
 
+            // close retention registry
+            if (retentionReg != null) {
+                retentionReg.close();
+                retentionReg = null;
+            }
+
             // close workspace file system
             try {
                 fs.close();
             } catch (FileSystemException fse) {
-                log.error("error while closing file system of workspace "
-                        + config.getName(), fse);
+                log.error("error while closing file system of workspace " + config.getName(), fse);
             }
             fs = null;
         }

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=738422&r1=738421&r2=738422&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 Wed Jan 28 09:50:50 2009
@@ -49,6 +49,7 @@
 import org.apache.jackrabbit.core.xml.ImportHandler;
 import org.apache.jackrabbit.core.xml.SessionImporter;
 import org.apache.jackrabbit.core.retention.RetentionManagerImpl;
+import org.apache.jackrabbit.core.retention.RetentionRegistry;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.Path;
 import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
@@ -228,6 +229,12 @@
     private RetentionManager retentionManager;
 
     /**
+     * Internal helper class for common validation checks (lock status, checkout
+     * status, protection etc. etc.)
+     */
+    private ItemValidator validator;
+
+    /**
      * Protected constructor.
      *
      * @param rep
@@ -372,6 +379,17 @@
     }
 
     /**
+     * @return ItemValidator instance for this session.
+     * @throws RepositoryException If an error occurs.
+     */
+    public synchronized ItemValidator getValidator() throws RepositoryException {
+        if (validator == null) {
+            validator = new ItemValidator(rep.getNodeTypeRegistry(), getHierarchyManager(), this);
+        }
+        return validator;
+    }
+
+    /**
      * Returns the <code>Subject</code> associated with this session.
      *
      * @return the <code>Subject</code> associated with this session
@@ -462,6 +480,18 @@
         return versionMgr;
     }
 
+
+    /**
+     * Returns the internal retention manager used for evaluation of effective
+     * retention policies and holds.
+     * 
+     * @return internal retention manager
+     * @throws RepositoryException
+     */
+    protected RetentionRegistry getRetentionRegistry() throws RepositoryException {
+        return wsp.getRetentionRegistry();
+    }
+
     /**
      * Retrieves the referenceable node with the given <code>UUID</code>.
      *
@@ -867,28 +897,6 @@
     }
 
     /**
-     * Determines if there are pending unsaved changes either on the passed
-     * item or on any item in it's subtree.
-     *
-     * @param item Item start of the subtree to be tested for pending changes.
-     * @return <code>true</code> if there are pending unsaved changes,
-     *         <code>false</code> otherwise.
-     * @throws RepositoryException if an error occurred
-     */
-    public boolean hasPendingChanges(Item item) throws RepositoryException {
-        if (!(item instanceof ItemImpl) || ((ItemImpl) item).session != this) {
-            throw new IllegalArgumentException();
-        }
-        sanityCheck();
-        ItemImpl itemImpl = (ItemImpl) item;
-        if (itemImpl.isTransient()) {
-            return true;
-        } else {
-            return item.isNode() && ((NodeImpl) item).hasPendingChanges();
-        }
-    }
-
-    /**
      * {@inheritDoc}
      */
     public void move(String srcAbsPath, String destAbsPath)
@@ -961,20 +969,7 @@
             throw new RepositoryException(msg);
         }
 
-        // verify that both source and destination parent nodes are checked-out
-        if (!srcParentNode.internalIsCheckedOut()) {
-            String msg = srcAbsPath + ": cannot move a child of a checked-in node";
-            log.debug(msg);
-            throw new VersionException(msg);
-        }
-        if (!destParentNode.internalIsCheckedOut()) {
-            String msg = destAbsPath + ": cannot move a target to a checked-in node";
-            log.debug(msg);
-            throw new VersionException(msg);
-        }
-
         // check for name collisions
-
         NodeImpl existing = null;
         try {
             existing = getItemManager().getNode(destPath);
@@ -991,8 +986,15 @@
             // no name collision, fall through
         }
 
-        // check constraints
+        // verify for both source and destination parent nodes that
+        // - they are checked-out
+        // - are not protected neither by node type constraints nor by retention/hold
+        int options = ItemValidator.CHECK_VERSIONING | ItemValidator.CHECK_LOCK |
+                ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD | ItemValidator.CHECK_RETENTION;
+        getValidator().checkRemove(srcParentNode, options, Permission.NONE);
+        getValidator().checkModify(destParentNode, options, Permission.NONE);
 
+        // check constraints
         // get applicable definition of target node at new location
         NodeTypeImpl nt = (NodeTypeImpl) targetNode.getPrimaryNodeType();
         NodeDefinitionImpl newTargetDef;
@@ -1012,22 +1014,6 @@
                     "Same name siblings not allowed: " + existing);
         }
 
-        // check protected flag of old & new parent
-        if (destParentNode.getDefinition().isProtected()) {
-            String msg = destAbsPath + ": cannot add a child node to a protected node";
-            log.debug(msg);
-            throw new ConstraintViolationException(msg);
-        }
-        if (srcParentNode.getDefinition().isProtected()) {
-            String msg = srcAbsPath + ": cannot remove a child node from a protected node";
-            log.debug(msg);
-            throw new ConstraintViolationException(msg);
-        }
-
-        // check lock status
-        srcParentNode.checkLock();
-        destParentNode.checkLock();
-
         NodeId targetId = targetNode.getNodeId();
         int index = srcName.getIndex();
         if (index == 0) {
@@ -1098,22 +1084,11 @@
             throw new PathNotFoundException(parentAbsPath);
         }
 
-        // verify that parent node is checked-out
-        if (!parent.internalIsCheckedOut()) {
-            String msg = parentAbsPath + ": cannot add a child to a checked-in node";
-            log.debug(msg);
-            throw new VersionException(msg);
-        }
-
-        // check protected flag of parent node
-        if (parent.getDefinition().isProtected()) {
-            String msg = parentAbsPath + ": cannot add a child to a protected node";
-            log.debug(msg);
-            throw new ConstraintViolationException(msg);
-        }
-
-        // check lock status
-        parent.checkLock();
+        // verify that parent node is checked-out, not locked and not protected
+        // by either node type constraints nor by some retention or hold.
+        int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_VERSIONING |
+                ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD | ItemValidator.CHECK_RETENTION;
+        getValidator().checkModify(parent, options, Permission.NONE);
 
         SessionImporter importer = new SessionImporter(parent, this, uuidBehavior);
         return new ImportHandler(importer, this);
@@ -1522,9 +1497,14 @@
      * @see org.apache.jackrabbit.api.jsr283.Session#getRetentionManager()
      * @since JCR 2.0
      */
-    public synchronized RetentionManager getRetentionManager()
+    public RetentionManager getRetentionManager()
             throws UnsupportedRepositoryOperationException, RepositoryException {
+        // check sanity of this session
+        sanityCheck();
         if (retentionManager == null) {
+            // make sure the internal retention manager exists.
+            getRetentionRegistry();
+            // create the api level retention manager.
             retentionManager = new RetentionManagerImpl(this);
         }
         return retentionManager;

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceImpl.java?rev=738422&r1=738421&r2=738422&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/WorkspaceImpl.java Wed Jan 28 09:50:50 2009
@@ -37,6 +37,7 @@
 import org.apache.jackrabbit.core.xml.WorkspaceImporter;
 import org.apache.jackrabbit.core.cluster.ClusterNode;
 import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
+import org.apache.jackrabbit.core.retention.RetentionRegistry;
 import org.apache.jackrabbit.commons.AbstractWorkspace;
 import org.apache.jackrabbit.spi.commons.conversion.NameException;
 import org.apache.jackrabbit.spi.Path;
@@ -119,9 +120,19 @@
      */
     protected LockManager lockMgr;
 
+    /**
+     * The API LockManager for this workspace, used to create and release
+     * locks and determine the lock status.
+     */
     private org.apache.jackrabbit.api.jsr283.lock.LockManager jcr283LockManager;
 
     /**
+     * The internal manager used to evaluate effective retention policies and
+     * holds.
+     */
+    private RetentionRegistry retentionRegistry;
+
+    /**
      * Protected constructor.
      *
      * @param wspConfig The workspace configuration
@@ -520,6 +531,22 @@
         return lockMgr;
     }
 
+    /**
+     * Return the internal effective retention/hold manager for this workspace.
+     * If not already done, creates a new instance.
+     *
+     * @return effective retention/hold manager for this workspace
+     * @throws RepositoryException if an error occurs
+     */
+    synchronized RetentionRegistry getRetentionRegistry() throws RepositoryException {
+        // check state of this instance
+        sanityCheck();
+        if (retentionRegistry == null) {
+            retentionRegistry = rep.getRetentionRegistry(wspConfig.getName());
+        }
+        return retentionRegistry;
+    }
+
     //------------------------------------------------------------< Workspace >
     /**
      * {@inheritDoc}
@@ -864,7 +891,7 @@
             log.debug(msg);
             throw new InvalidItemStateException(msg);
         }
-
+        // TODO: add checks for lock/hold...
         boolean success = false;
         try {
             // now restore all versions that have a node in the ws

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/SessionLockManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/SessionLockManager.java?rev=738422&r1=738421&r2=738422&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/SessionLockManager.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/SessionLockManager.java Wed Jan 28 09:50:50 2009
@@ -19,6 +19,7 @@
 import org.apache.jackrabbit.api.jsr283.lock.Lock;
 import org.apache.jackrabbit.core.NodeImpl;
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.ItemValidator;
 import org.apache.jackrabbit.core.security.authorization.Permission;
 import org.apache.jackrabbit.spi.commons.name.NameConstants;
 import org.slf4j.Logger;
@@ -150,14 +151,10 @@
     public Lock lock(String absPath, boolean isDeep, boolean isSessionScoped,
                      long timeoutHint, String ownerInfo) throws RepositoryException {
         NodeImpl node = (NodeImpl) session.getNode(absPath);
-
-        if (session.hasPendingChanges(node)) {
-            String msg = "Unable to lock node. Node has pending changes: " + this;
-            log.debug(msg);
-            throw new InvalidItemStateException(msg);
-        }
+        
+        int options = ItemValidator.CHECK_HOLD | ItemValidator.CHECK_PENDING_CHANGES_ON_NODE;
+        session.getValidator().checkModify(node, options, Permission.LOCK_MNGMT);
         checkLockable(node);
-        session.getAccessManager().checkPermission(session.getQPath(node.getPath()), Permission.LOCK_MNGMT);
 
         synchronized (systemLockMgr) {
             return (Lock) systemLockMgr.lock(node, isDeep, isSessionScoped, timeoutHint, ownerInfo);
@@ -173,13 +170,9 @@
             RepositoryException {
 
         NodeImpl node = (NodeImpl) session.getNode(absPath);
-        if (session.hasPendingChanges(node)) {
-            String msg = "Unable to unlock node. Node has pending changes: " + this;
-            log.debug(msg);
-            throw new InvalidItemStateException(msg);
-        }
+        int options = ItemValidator.CHECK_HOLD | ItemValidator.CHECK_PENDING_CHANGES_ON_NODE;
+        session.getValidator().checkModify(node, options, Permission.LOCK_MNGMT);
         checkLockable(node);
-        session.getAccessManager().checkPermission(session.getQPath(node.getPath()), Permission.LOCK_MNGMT);
 
         synchronized (systemLockMgr) {
             // basic checks if unlock can be called on the node.

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/HoldImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/HoldImpl.java?rev=738422&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/HoldImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/HoldImpl.java Wed Jan 28 09:50:50 2009
@@ -0,0 +1,126 @@
+/*
+ * 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.retention;
+
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.NameFactory;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
+import org.apache.jackrabbit.spi.commons.conversion.NameResolver;
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.PropertyImpl;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.api.jsr283.retention.Hold;
+
+import javax.jcr.Value;
+import javax.jcr.RepositoryException;
+import javax.jcr.ValueFactory;
+
+/**
+ * <code>HoldImpl</code>...
+ */
+class HoldImpl implements Hold {
+
+    private static final NameFactory NAME_FACTORY = NameFactoryImpl.getInstance();
+    
+    private static final String DEEP = "D_";
+    private static final String SHALLOW = "S_";
+
+    private final Name name;
+    private final boolean isDeep;
+    private final NodeId nodeId;
+
+    private final NameResolver resolver;
+
+    private int hashCode = 0;
+
+    HoldImpl(Name name, boolean isDeep, NodeId nodeId, NameResolver resolver) {
+        this.name = name;
+        this.isDeep = isDeep;
+        this.nodeId = nodeId;
+        this.resolver = resolver;
+    }
+
+    NodeId getNodeId() {
+        return nodeId;
+    }
+
+    Value toValue(ValueFactory valueFactory) throws RepositoryException {
+        String str = ((isDeep) ? DEEP : SHALLOW) + name.toString();
+        return valueFactory.createValue(str);
+    }
+
+    static Hold createFromValue(Value val, NodeId nodeId, NameResolver resolver) throws RepositoryException {
+        String str = val.getString();
+        Name name = NAME_FACTORY.create(str.substring(2));
+        boolean isDeep = str.startsWith(DEEP);
+        return new HoldImpl(name, isDeep, nodeId, resolver);
+    }
+
+    static Hold[] createFromProperty(PropertyImpl property, NodeId nodeId) throws RepositoryException {
+        Value[] vs = property.getValues();
+        Hold[] holds = new Hold[vs.length];
+        for (int i = 0; i < vs.length; i++) {
+            holds[i] = createFromValue(vs[i], nodeId, (SessionImpl) property.getSession());
+        }
+        return holds;
+    }
+
+    //-----------------------------------------------------------< Hold >---
+    /**
+     * @see org.apache.jackrabbit.api.jsr283.retention.Hold#isDeep()
+     */
+    public boolean isDeep() throws RepositoryException {
+        return isDeep;
+    }
+
+    /**
+     * @see org.apache.jackrabbit.api.jsr283.retention.Hold#getName()
+     */
+    public String getName() throws RepositoryException {
+        return resolver.getJCRName(name);
+    }
+
+    //---------------------------------------------------------< Object >---
+    /**
+     * @see Object#hashCode()
+     */
+    public int hashCode() {
+        if (hashCode == 0) {
+            int h = 17;
+            h = 37 * h + name.hashCode();
+            h = 37 * h + nodeId.hashCode();
+            h = 37 * h + Boolean.valueOf(isDeep).hashCode();
+            hashCode = h;
+        }
+        return hashCode;
+    }
+
+    /**
+     * @see Object#equals(Object)
+     */
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (obj instanceof HoldImpl) {
+            HoldImpl other = (HoldImpl) obj;
+            return isDeep == other.isDeep && name.equals(other.name) && nodeId.equals(other.nodeId);
+        }
+        return false;
+    }
+}
\ No newline at end of file

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

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/retention/HoldImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url



Mime
View raw message