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 2009/09/08 18:09:45 UTC

svn commit: r812570 [7/24] - in /jackrabbit/sandbox/JCR-1456: ./ jackrabbit-api/ jackrabbit-api/src/main/appended-resources/ jackrabbit-api/src/main/appended-resources/META-INF/ jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/ jackrabbi...

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockInfo.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockInfo.java?rev=812570&r1=812569&r2=812570&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockInfo.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockInfo.java Tue Sep  8 16:09:28 2009
@@ -16,59 +16,188 @@
  */
 package org.apache.jackrabbit.core.lock;
 
+import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.id.NodeId;
 
+import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.lock.LockException;
 
 /**
- * Lock information interface.
+ * Internal lock information.
  */
-public interface LockInfo {
+public abstract class LockInfo {
+
+    /**
+     * The biggest possible timeout hint value (in seconds), used to avoid
+     * overflows when calculating the timeout. 100 years should be plenty
+     * enough for anyone...
+     */
+    private static final long MAXIMUM_TIMEOUT = 100L * 365L * 24L * 60L * 60L;
+
+    /**
+     * Lock holder node id. Used also as the lock token.
+     */
+    private final NodeId id;
+
+    /**
+     * Flag indicating whether lock is session scoped
+     */
+    private final boolean sessionScoped;
+
+    /**
+     * Flag indicating whether lock is deep
+     */
+    private final boolean deep;
+
+    /**
+     * Lock owner, determined on creation time
+     */
+    private final String lockOwner;
+
+    /**
+     * Lock timeout hint (in seconds) given when the lock was created.
+     * Guaranteed to be between 0 and {@link #MAXIMUM_TIMEOUT}. If the value
+     * is 0, then this lock will not timeout.
+     */
+    private final long timeoutHint;
+
+    /**
+     * Time (in seconds since epoch) when this lock will timeout. Set to
+     * {@link Long#MAX_VALUE} if this lock will not timeout.
+     */
+    private long timeoutTime;
+
+    /**
+     * Flag indicating whether this lock is live. See also {@link #timeoutTime}.
+     */
+    private boolean live;
+
+    /**
+     * Session currently holding lock
+     */
+    private SessionImpl lockHolder;
+
+    /**
+     * Create a new instance of this class.
+     *
+     * @param id            lock holder node id
+     * @param sessionScoped whether lock token is session scoped
+     * @param deep          whether lock is deep
+     * @param lockOwner     owner of lock
+     * @param timeoutHint   lock timeout hint in seconds
+     */
+    protected LockInfo(
+            NodeId id, boolean sessionScoped, boolean deep,
+            String lockOwner, long timeoutHint) {
+        this.id = id;
+        this.sessionScoped = sessionScoped;
+        this.deep = deep;
+        this.lockOwner = lockOwner;
+        this.timeoutHint = timeoutHint;
+
+        updateTimeoutTime();
+    }
+
+    protected LockInfo(LockInfo that) {
+        this.id = that.id;
+        this.sessionScoped = that.sessionScoped;
+        this.deep = that.deep;
+        this.lockOwner = that.lockOwner;
+        this.timeoutHint = that.timeoutHint;
+        this.timeoutTime = that.timeoutTime;
+    }
+
+    /**
+     * Return the lock token associated with this lock.
+     *
+     * @return lock token
+     */
+    public String getLockToken() {
+        String uuid = id.toString();
+        return uuid + "-" + getLockTokenCheckDigit(uuid);
+    }
 
     /**
      * Return the ID of the lock holding node
      * @return the id
      */
-    public NodeId getId();
-    
+    public NodeId getId() {
+        return id;
+    }
+
     /**
      * Return the lock owner.
      * 
      * @return lock owner
      */
-    public String getLockOwner();
-    
+    public String getLockOwner() {
+        return lockOwner;
+    }
+
     /**
      * Return a flag indicating whether the lock is deep.
      * 
      * @return <code>true</code> if the lock is deep;
      *         <code>false</code> otherwise
      */
-    public boolean isDeep();
-    
+    public boolean isDeep() {
+        return deep;
+    }
+
     /**
      * Return a flag indicating whether the session given is lock holder. 
      *
      * @param session session to compare with
      */
-    public boolean isLockHolder(Session session);
+    public boolean isLockHolder(Session session) {
+        return lockHolder == session;
+    }
+
+    /**
+     * Return the session currently holding the lock
+     *
+     * @return session currently holding the lock
+     */
+    public SessionImpl getLockHolder() {
+        return lockHolder;
+    }
 
     /**
-     * Return the lock token as seen by the session passed as parameter. If
-     * this session is currently holding the lock, it will get the lock token
-     * itself, otherwise a <code>null</code> string.
+     * Set the session currently holding the lock
      *
-     * @param session The session asking for the lock token.
-     * @return lock token.
+     * @param lockHolder session currently holding the lock
      */
-    public String getLockToken(Session session);
+    public void setLockHolder(SessionImpl lockHolder) {
+        this.lockHolder = lockHolder;
+    }
 
     /**
      * Return a flag indicating whether the lock is live
      *
      * @return <code>true</code> if the lock is live; otherwise <code>false</code>
      */
-    public boolean isLive();
+    public boolean isLive() {
+        return live;
+    }
+
+    /**
+     * Set the live flag
+     *
+     * @param live live flag
+     */
+    public void setLive(boolean live) {
+        this.live = live;
+    }
+
+    /**
+     * Return a flag indicating whether the lock information may still change.
+     *
+     * @return <code>true</code> if the lock is still alive.
+     */
+    public boolean mayChange() {
+        return live;
+    }
 
     /**
      * Return a flag indicating whether the lock is session-scoped
@@ -76,12 +205,155 @@
      * @return <code>true</code> if the lock is session-scoped;
      *         otherwise <code>false</code>
      */
-    public boolean isSessionScoped();
+    public boolean isSessionScoped() {
+        return sessionScoped;
+    }
+
+    /**
+     * Returns the timeout hint given when the lock was created.
+     *
+     * @return timeout hint (in seconds)
+     */
+    public long getTimeoutHint() {
+        return timeoutHint;
+    }
+
+    /**
+     * Returns the time when this lock will expire. 
+     *
+     * @return timeout time in seconds after epoch
+     */
+    public long getTimeoutTime() {
+        return timeoutTime;
+    }
+
+    public boolean isExpired() {
+        return timeoutTime != Long.MAX_VALUE
+            && timeoutTime * 1000 > System.currentTimeMillis();
+    }
+
+    /**
+     * Updates the timeout time of this lock based on current time and
+     * the timeout hint specified for this lock. The timeout time is always
+     * rounded up.
+     */
+    public void updateTimeoutTime() {
+        if (timeoutHint > 0 && timeoutHint <= MAXIMUM_TIMEOUT) {
+            long now = (System.currentTimeMillis() + 999) / 1000; // round up
+            this.timeoutTime = now + timeoutHint;
+        } else {
+            this.timeoutTime = Long.MAX_VALUE;
+        }
+    }
 
     /**
-     * Return the number of seconds remaining until the lock expires.
+     * Utility method that throws a {@link LockException} with the
+     * "failure node path" set to the path of the node that holds this lock.
+     * The given session is used to resolve the path of the lock holder node.
      *
-     * @return number of seconds remaining until the lock expires.
+     * @param message exception message
+     * @param session session that the user was using for the failing operation
+     * @throws LockException always thrown, unless another error occurs
+     * @throws RepositoryException if the path of this lock can not be resolved
      */
-    public long getSecondsRemaining();
+    public void throwLockException(String message, SessionImpl session)
+            throws LockException, RepositoryException {
+        String path;
+        try {
+            path = session.getJCRPath(
+                    session.getHierarchyManager().getPath(id));
+        } catch (RepositoryException ignored) {
+            path = null;
+        }
+        if (path != null) {
+            throw new LockException(
+                    message + " (lock held by node " + path + ")", null, path);
+        } else {
+            throw new LockException(message);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append('(');
+        if (deep) {
+            buffer.append("deep ");
+        }
+        if (sessionScoped) {
+            buffer.append("session ");
+        }
+        buffer.append("holder:");
+        if (lockHolder != null) {
+            buffer.append(lockHolder.getUserID());
+        } else {
+            buffer.append("none");
+        }
+        buffer.append("owner:").append(lockOwner);
+        buffer.append(')');
+        return buffer.toString();
+    }
+
+    /**
+     * Parse a lock token string representation and return the lock
+     * holder node id.
+     *
+     * @param token string representation of lock token
+     * @return lock holder node id
+     * @throws IllegalArgumentException if some field is illegal
+     */
+    public static NodeId parseLockToken(String token)
+            throws IllegalArgumentException {
+        int sep = token.lastIndexOf('-');
+        if (sep == -1 || sep == token.length() - 1) {
+            throw new IllegalArgumentException("Separator not found.");
+        }
+        String uuid = token.substring(0, sep);
+        if (getLockTokenCheckDigit(uuid) != token.charAt(token.length() - 1)) {
+            throw new IllegalArgumentException("Bad check digit.");
+        }
+        return NodeId.valueOf(uuid);
+    }
+
+    /**
+     * Return the check digit for a lock token, given by its UUID
+     * @param uuid uuid
+     * @return check digit
+     */
+    private static char getLockTokenCheckDigit(String uuid) {
+        int result = 0;
+
+        int multiplier = 36;
+        for (int i = 0; i < uuid.length(); i++) {
+            char c = uuid.charAt(i);
+            if (c >= '0' && c <= '9') {
+                int num = c - '0';
+                result += multiplier * num;
+                multiplier--;
+            } else if (c >= 'A' && c <= 'F') {
+                int num = c - 'A' + 10;
+                result += multiplier * num;
+                multiplier--;
+            } else if (c >= 'a' && c <= 'f') {
+                int num = c - 'a' + 10;
+                result += multiplier * num;
+                multiplier--;
+            }
+        }
+
+        int rem = result % 37;
+        if (rem != 0) {
+            rem = 37 - rem;
+        }
+        if (rem >= 0 && rem <= 9) {
+            return (char) ('0' + rem);
+        } else if (rem >= 10 && rem <= 35) {
+            return (char) ('A' + rem - 10);
+        } else {
+            return '+';
+        }
+    }
+
 }

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java?rev=812570&r1=812569&r2=812570&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java Tue Sep  8 16:09:28 2009
@@ -52,7 +52,6 @@
 import org.slf4j.LoggerFactory;
 
 import javax.jcr.ItemNotFoundException;
-import javax.jcr.Node;
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
@@ -70,6 +69,9 @@
 import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Provides the functionality needed for locking and unlocking nodes.
@@ -90,7 +92,7 @@
     /**
      * Path map containing all locks at the leaves.
      */
-    private final PathMap lockMap = new PathMap();
+    private final PathMap<LockInfo> lockMap = new PathMap<LockInfo>();
 
     private final ReentrantLock lockMapLock = new ReentrantLock(){
 
@@ -135,6 +137,11 @@
     };
 
     /**
+     * The periodically invoked lock timeout handler.
+     */
+    private final ScheduledFuture<?> timeoutHandler;
+
+    /**
      * System session
      */
     private final SessionImpl sysSession;
@@ -157,12 +164,14 @@
     /**
      * Create a new instance of this class.
      *
-     * @param session system session
-     * @param fs      file system for persisting locks
+     * @param session  system session
+     * @param fs       file system for persisting locks
+     * @param executor scheduled executor service for handling lock timeouts
      * @throws RepositoryException if an error occurs
      */
-    public LockManagerImpl(SessionImpl session, FileSystem fs)
-            throws RepositoryException {
+    public LockManagerImpl(
+            SessionImpl session, FileSystem fs,
+            ScheduledExecutorService executor) throws RepositoryException {
 
         this.sysSession = session;
         this.locksFile = new FileSystemResource(fs, FileSystem.SEPARATOR + LOCKS_FILE);
@@ -179,16 +188,51 @@
             throw new RepositoryException("I/O error while reading locks from '"
                     + locksFile.getPath() + "'", e);
         }
+
+        timeoutHandler = executor.scheduleWithFixedDelay(
+                new TimeoutHandler(), 1, 1, TimeUnit.SECONDS);
     }
 
     /**
      * Close this lock manager. Writes back all changes.
      */
     public void close() {
+        timeoutHandler.cancel(false);
         save();
     }
 
     /**
+     * Periodically (at one second delay) invoked timeout handler. Traverses
+     * all locks and unlocks those that have expired.
+     *
+     * @see <a href="https://issues.apache.org/jira/browse/JCR-1590">JCR-1590</a>:
+     *      JSR 283: Locking
+     */
+    private class TimeoutHandler implements Runnable {
+        public void run() {
+            lockMap.traverse(new PathMap.ElementVisitor<LockInfo>() {
+                public void elementVisited(PathMap.Element<LockInfo> element) {
+                    LockInfo info = element.get();
+                    if (info != null && info.isLive() && info.isExpired()) {
+                        NodeId id = info.getId();
+                        SessionImpl holder = info.getLockHolder();
+                        if (holder == null) {
+                            info.setLockHolder(sysSession);
+                            holder = sysSession;
+                        }
+                        try {
+                            // FIXME: This session access is not thread-safe!
+                            unlock(holder.getNodeById(id));
+                        } catch (RepositoryException e) {
+                            log.warn("Unable to expire the lock " + id, e);
+                        }
+                    }
+                }
+            }, false);
+        }
+    }
+
+    /**
      * Read locks from locks file and populate path map
      */
     private void load() throws FileSystemException {
@@ -202,7 +246,7 @@
                 if (s == null || s.equals("")) {
                     break;
                 }
-                reapplyLock(LockToken.parse(s));
+                reapplyLock(s);
             }
         } catch (IOException e) {
             throw new FileSystemException("error while reading locks file", e);
@@ -214,22 +258,35 @@
     /**
      * Reapply a lock given a lock token that was read from the locks file
      *
-     * @param lockToken lock token to apply
+     * @param lockTokenLine lock token to apply
      */
-    private void reapplyLock(LockToken lockToken) {
+    private void reapplyLock(String lockTokenLine) {
+        String[] parts = lockTokenLine.split(",");
+        String token = parts[0];
+        long timeoutHint = Long.MAX_VALUE;
+        if (parts.length > 1) {
+            try {
+                timeoutHint = Long.parseLong(parts[1]);
+            } catch (NumberFormatException e) {
+                log.warn("Unexpected timeout hint "
+                        + parts[1] + " for lock token " + token, e);
+            }
+        }
+
         try {
-            NodeImpl node = (NodeImpl)
-                sysSession.getItemManager().getItem(lockToken.getId());
-            Path path = getPath(sysSession, lockToken.getId());
+            NodeId id = LockInfo.parseLockToken(parts[0]);
+            NodeImpl node = (NodeImpl) sysSession.getItemManager().getItem(id);
+            Path path = getPath(sysSession, id);
 
-            InternalLockInfo info = new InternalLockInfo(lockToken, false,
+            InternalLockInfo info = new InternalLockInfo(
+                    id, false,
                     node.getProperty(NameConstants.JCR_LOCKISDEEP).getBoolean(),
-                    node.getProperty(NameConstants.JCR_LOCKOWNER).getString());
+                    node.getProperty(NameConstants.JCR_LOCKOWNER).getString(),
+                    timeoutHint);
             info.setLive(true);
             lockMap.put(path, info);
         } catch (RepositoryException e) {
-            log.warn("Unable to recreate lock '" + lockToken
-                    + "': " + e.getMessage());
+            log.warn("Unable to recreate lock '" + token + "': " + e.getMessage());
             log.debug("Root cause: ", e);
         }
     }
@@ -242,11 +299,11 @@
             return;
         }
 
-        final ArrayList<AbstractLockInfo> list = new ArrayList<AbstractLockInfo>();
+        final ArrayList<LockInfo> list = new ArrayList<LockInfo>();
 
-        lockMap.traverse(new PathMap.ElementVisitor() {
-            public void elementVisited(PathMap.Element element) {
-                AbstractLockInfo info = (AbstractLockInfo) element.get();
+        lockMap.traverse(new PathMap.ElementVisitor<LockInfo>() {
+            public void elementVisited(PathMap.Element<LockInfo> element) {
+                LockInfo info = element.get();
                 if (!info.isSessionScoped()) {
                     list.add(info);
                 }
@@ -259,9 +316,15 @@
         try {
             writer = new BufferedWriter(
                     new OutputStreamWriter(locksFile.getOutputStream()));
-            for (int i = 0; i < list.size(); i++) {
-                AbstractLockInfo info = list.get(i);
+            for (LockInfo info : list) {
                 writer.write(info.getLockToken());
+
+                // Store the timeout hint, if one is specified
+                if (info.getTimeoutHint() != Long.MAX_VALUE) {
+                    writer.write(',');
+                    writer.write(Long.toString(info.getTimeoutHint()));
+                }
+
                 writer.newLine();
             }
         } catch (FileSystemException fse) {
@@ -295,15 +358,15 @@
      * @throws LockException       if the node is already locked
      * @throws RepositoryException if another error occurs
      */
-    AbstractLockInfo internalLock(NodeImpl node, boolean isDeep,
-                                  boolean isSessionScoped, long timeoutHint,
-                                  String ownerInfo)
+    LockInfo internalLock(
+            NodeImpl node, boolean isDeep, boolean isSessionScoped,
+            long timeoutHint, String ownerInfo)
             throws LockException, RepositoryException {
 
         SessionImpl session = (SessionImpl) node.getSession();
         String lockOwner = (ownerInfo != null) ? ownerInfo : session.getUserID();
-        InternalLockInfo info = new InternalLockInfo(new LockToken(node.getNodeId()),
-                isSessionScoped, isDeep, lockOwner, timeoutHint);
+        InternalLockInfo info = new InternalLockInfo(
+                node.getNodeId(), isSessionScoped, isDeep, lockOwner, timeoutHint);
 
         ClusterOperation operation = null;
         boolean successful = false;
@@ -318,20 +381,21 @@
         try {
             // check whether node is already locked
             Path path = getPath(session, node.getId());
-            PathMap.Element element = lockMap.map(path, false);
+            PathMap.Element<LockInfo> element = lockMap.map(path, false);
 
-            LockInfo other = (LockInfo) element.get();
+            LockInfo other = element.get();
             if (other != null) {
                 if (element.hasPath(path)) {
-                    throw new LockException("Node already locked: " + node);
+                    other.throwLockException(
+                            "Node already locked: " + node, session);
                 } else if (other.isDeep()) {
-                    throw new LockException(
-                            "Parent node has a deep lock: " + node);
+                    other.throwLockException(
+                            "Parent node has a deep lock: " + node, session);
                 }
             }
-            if (info.deep && element.hasPath(path)
+            if (info.isDeep() && element.hasPath(path)
                     && element.getChildrenCount() > 0) {
-                throw new LockException("Some child node is locked.");
+                info.throwLockException("Some child node is locked", session);
             }
 
             // create lock token
@@ -378,17 +442,18 @@
         try {
             SessionImpl session = (SessionImpl) node.getSession();
             // check whether node is locked by this session
-            PathMap.Element element = lockMap.map(getPath(session, node.getId()), true);
+            PathMap.Element<LockInfo> element =
+                lockMap.map(getPath(session, node.getId()), true);
             if (element == null) {
                 throw new LockException("Node not locked: " + node);
             }
-            AbstractLockInfo info = (AbstractLockInfo) element.get();
+            LockInfo info = element.get();
             if (info == null) {
                 throw new LockException("Node not locked: " + node);
             }
             checkUnlock(info, session);
 
-            getSessionLockManager(session).lockTokenRemoved(info.getLockToken(session));
+            getSessionLockManager(session).lockTokenRemoved(info.getLockToken());
 
             element.set(null);
             info.setLive(false);
@@ -408,23 +473,22 @@
     }
 
     /**
-     * Package-private low-level helper method returning all
-     * <code>AbstractLockInfo</code>s associated with the specified
-     * session.
+     * Package-private low-level helper method returning all locks
+     * associated with the specified session.
      * @param session session
      * @return an array of <code>AbstractLockInfo</code>s
      */
-    AbstractLockInfo[] getLockInfos(final SessionImpl session) {
+    LockInfo[] getLockInfos(final SessionImpl session) {
         final ArrayList<LockInfo> infos = new ArrayList<LockInfo>();
-        lockMap.traverse(new PathMap.ElementVisitor() {
-            public void elementVisited(PathMap.Element element) {
-                LockInfo info = (LockInfo) element.get();
+        lockMap.traverse(new PathMap.ElementVisitor<LockInfo>() {
+            public void elementVisited(PathMap.Element<LockInfo> element) {
+                LockInfo info = element.get();
                 if (info.isLive() && info.isLockHolder(session)) {
                     infos.add(info);
                 }
             }
         }, false);
-        return infos.toArray(new AbstractLockInfo[infos.size()]);
+        return infos.toArray(new LockInfo[infos.size()]);
     }
 
     /**
@@ -434,7 +498,7 @@
      * @return lock info or <code>null</code> if node is not locked
      * @throws RepositoryException if an error occurs
      */
-    public AbstractLockInfo getLockInfo(NodeId id) throws RepositoryException {
+    public LockInfo getLockInfo(NodeId id) throws RepositoryException {
         Path path;
         try {
             path = getPath(sysSession, id);
@@ -444,8 +508,8 @@
 
         acquire();
         try {
-            PathMap.Element element = lockMap.map(path, false);
-            AbstractLockInfo info = (AbstractLockInfo) element.get();
+            PathMap.Element<LockInfo> element = lockMap.map(path, false);
+            LockInfo info = element.get();
             if (info != null) {
                 if (element.hasPath(path) || info.isDeep()) {
                     return info;
@@ -464,13 +528,13 @@
      */
     public Lock lock(NodeImpl node, boolean isDeep, boolean isSessionScoped)
             throws LockException, RepositoryException {
-        return lock(node, isDeep, isSessionScoped, AbstractLockInfo.TIMEOUT_INFINITE, null);
+        return lock(node, isDeep, isSessionScoped, Long.MAX_VALUE, null);
     }
 
     public Lock lock(NodeImpl node, boolean isDeep, boolean isSessionScoped, long timoutHint, String ownerInfo)
             throws LockException, RepositoryException {
-        AbstractLockInfo info = internalLock(node, isDeep, isSessionScoped, timoutHint, ownerInfo);
-        writeLockProperties(node, info.lockOwner, info.deep);
+        LockInfo info = internalLock(node, isDeep, isSessionScoped, timoutHint, ownerInfo);
+        writeLockProperties(node, info.getLockOwner(), info.isDeep());
 
         return new LockImpl(info, node);
     }
@@ -487,10 +551,11 @@
             SessionImpl session = (SessionImpl) node.getSession();
             Path path = getPath(session, node.getId());
 
-            PathMap.Element element = lockMap.map(path, false);
-            AbstractLockInfo info = (AbstractLockInfo) element.get();
-            if (info != null && (element.hasPath(path) || info.deep)) {
-                Node lockHolder = (Node) session.getItemManager().getItem(info.getId());
+            PathMap.Element<LockInfo> element = lockMap.map(path, false);
+            LockInfo info = element.get();
+            if (info != null && (element.hasPath(path) || info.isDeep())) {
+                NodeImpl lockHolder = (NodeImpl)
+                    session.getItemManager().getItem(info.getId());
                 return new LockImpl(info, lockHolder);
             } else {
                 throw new LockException("Node not locked: " + node);
@@ -509,14 +574,14 @@
 
         acquire();
 
-        AbstractLockInfo[] infos = getLockInfos(session);
+        LockInfo[] infos = getLockInfos(session);
 
         try {
             Lock[] locks = new Lock[infos.length];
             for (int i = 0; i < infos.length; i++) {
-                AbstractLockInfo info = infos[i];
-                Node holder = (Node) session.getItemManager().getItem(info.getId());
-                locks[i] = new LockImpl(info, holder);
+                NodeImpl holder = (NodeImpl)
+                    session.getItemManager().getItem(infos[i].getId());
+                locks[i] = new LockImpl(infos[i], holder);
             }
             return locks;
         } finally {
@@ -544,7 +609,8 @@
 
         try {
             SessionImpl session = (SessionImpl) node.getSession();
-            PathMap.Element element = lockMap.map(getPath(session, node.getId()), true);
+            PathMap.Element<LockInfo> element =
+                lockMap.map(getPath(session, node.getId()), true);
             if (element == null) {
                 return false;
             }
@@ -566,15 +632,15 @@
             SessionImpl session = (SessionImpl) node.getSession();
             Path path = getPath(session, node.getId());
 
-            PathMap.Element element = lockMap.map(path, false);
-            AbstractLockInfo info = (AbstractLockInfo) element.get();
+            PathMap.Element<LockInfo> element = lockMap.map(path, false);
+            LockInfo info = element.get();
             if (info == null) {
                 return false;
             }
             if (element.hasPath(path)) {
                 return true;
             } else {
-                return info.deep;
+                return info.isDeep();
             }
         } catch (ItemNotFoundException e) {
             return false;
@@ -599,8 +665,8 @@
     public void checkLock(Path path, Session session)
             throws LockException, RepositoryException {
 
-        PathMap.Element element = lockMap.map(path, false);
-        LockInfo info = (LockInfo) element.get();
+        PathMap.Element<LockInfo> element = lockMap.map(path, false);
+        LockInfo info = element.get();
         if (info != null) {
             if (element.hasPath(path) || info.isDeep()) {
                 checkLock(info, session);
@@ -635,12 +701,12 @@
             throws LockException, RepositoryException {
 
         // check whether node is locked by this session
-        PathMap.Element element = lockMap.map(getPath((SessionImpl) session,
-                node.getId()), true);
+        PathMap.Element<LockInfo> element =
+            lockMap.map(getPath((SessionImpl) session, node.getId()), true);
         if (element == null) {
             throw new LockException("Node not locked: " + node);
         }
-        AbstractLockInfo info = (AbstractLockInfo) element.get();
+        LockInfo info = element.get();
         if (info == null) {
             throw new LockException("Node not locked: " + node);
         }
@@ -673,13 +739,13 @@
      */
     public void addLockToken(SessionImpl session, String lt) throws LockException, RepositoryException {
         try {
-            LockToken lockToken = LockToken.parse(lt);
+            NodeId id = LockInfo.parseLockToken(lt);
 
-            NodeImpl node = (NodeImpl)
-                this.sysSession.getItemManager().getItem(lockToken.getId());
-            PathMap.Element element = lockMap.map(node.getPrimaryPath(), true);
+            NodeImpl node = (NodeImpl) sysSession.getItemManager().getItem(id);
+            Path path = node.getPrimaryPath();
+            PathMap.Element<LockInfo> element = lockMap.map(path, true);
             if (element != null) {
-                AbstractLockInfo info = (AbstractLockInfo) element.get();
+                LockInfo info = element.get();
                 if (info != null) {
                     if (info.isLockHolder(session)) {
                         // nothing to do
@@ -691,7 +757,7 @@
                     } else {
                         String msg = "Cannot add lock token: lock already held by other session.";
                         log.warn(msg);
-                        throw new LockException(msg);
+                        info.throwLockException(msg, session);
                     }
                 }
             }
@@ -711,13 +777,13 @@
             throws LockException, RepositoryException {
 
         try {
-            LockToken lockToken = LockToken.parse(lt);
+            NodeId id = LockInfo.parseLockToken(lt);
 
-            NodeImpl node = (NodeImpl) this.sysSession.getItemManager()
-                    .getItem(lockToken.getId());
-            PathMap.Element element = lockMap.map(node.getPrimaryPath(), true);
+            NodeImpl node = (NodeImpl) sysSession.getItemManager().getItem(id);
+            PathMap.Element<LockInfo> element =
+                lockMap.map(node.getPrimaryPath(), true);
             if (element != null) {
-                AbstractLockInfo info = (AbstractLockInfo) element.get();
+                LockInfo info = element.get();
                 if (info != null) {
                     if (info.isLockHolder(session)) {
                         info.setLockHolder(null);
@@ -726,7 +792,7 @@
                     } else {
                         String msg = "Cannot remove lock token: lock held by other session.";
                         log.warn(msg);
-                        throw new LockException(msg);
+                        info.throwLockException(msg, session);
                     }
                 }
             }
@@ -979,16 +1045,6 @@
         }
 
         /**
-         * Return the event type. May be {@link Event#NODE_ADDED},
-         * {@link Event#NODE_REMOVED} or a combination of both.\
-         *
-         * @return event type
-         */
-        public int getType() {
-            return type;
-        }
-
-        /**
          * Return the old path if this is a move operation
          *
          * @return old path
@@ -1011,9 +1067,9 @@
      * {@inheritDoc}
      */
     public void onEvent(EventIterator events) {
-        Iterator iter = consolidateEvents(events);
+        Iterator<HierarchyEvent> iter = consolidateEvents(events);
         while (iter.hasNext()) {
-            HierarchyEvent event = (HierarchyEvent) iter.next();
+            HierarchyEvent event = iter.next();
             if (event.type == Event.NODE_ADDED) {
                 nodeAdded(event.path);
             } else if (event.type == Event.NODE_REMOVED) {
@@ -1029,7 +1085,7 @@
      * add and remove operations on nodes with the same UUID into a move
      * operation.
      */
-    private Iterator consolidateEvents(EventIterator events) {
+    private Iterator<HierarchyEvent> consolidateEvents(EventIterator events) {
         LinkedMap eventMap = new LinkedMap();
 
         while (events.hasNext()) {
@@ -1062,15 +1118,14 @@
      * Refresh a non-empty path element whose children might have changed
      * its position.
      */
-    private void refresh(PathMap.Element element) {
-        final ArrayList<AbstractLockInfo> infos = new ArrayList<AbstractLockInfo>();
+    private void refresh(PathMap.Element<LockInfo> element) {
+        final ArrayList<LockInfo> infos = new ArrayList<LockInfo>();
         boolean needsSave = false;
 
         // save away non-empty children
-        element.traverse(new PathMap.ElementVisitor() {
-            public void elementVisited(PathMap.Element element) {
-                AbstractLockInfo info = (AbstractLockInfo) element.get();
-                infos.add(info);
+        element.traverse(new PathMap.ElementVisitor<LockInfo>() {
+            public void elementVisited(PathMap.Element<LockInfo> element) {
+                infos.add(element.get());
             }
         }, false);
 
@@ -1080,7 +1135,7 @@
         // now re-insert at appropriate location or throw away if node
         // does no longer exist
         for (int i = 0; i < infos.size(); i++) {
-            AbstractLockInfo info = infos.get(i);
+            LockInfo info = infos.get(i);
             try {
                 NodeImpl node = (NodeImpl) sysSession.getItemManager().getItem(
                         info.getId());
@@ -1110,7 +1165,8 @@
         acquire();
 
         try {
-            PathMap.Element parent = lockMap.map(path.getAncestor(1), true);
+            PathMap.Element<LockInfo> parent =
+                lockMap.map(path.getAncestor(1), true);
             if (parent != null) {
                 refresh(parent);
             }
@@ -1132,7 +1188,8 @@
         acquire();
 
         try {
-            PathMap.Element parent = lockMap.map(oldPath.getAncestor(1), true);
+            PathMap.Element<LockInfo> parent =
+                lockMap.map(oldPath.getAncestor(1), true);
             if (parent != null) {
                 refresh(parent);
             }
@@ -1153,7 +1210,8 @@
         acquire();
 
         try {
-            PathMap.Element parent = lockMap.map(path.getAncestor(1), true);
+            PathMap.Element<LockInfo> parent =
+                lockMap.map(path.getAncestor(1), true);
             if (parent != null) {
                 refresh(parent);
             }
@@ -1168,20 +1226,7 @@
      * Contains information about a lock and gets placed inside the child
      * information of a {@link org.apache.jackrabbit.spi.commons.name.PathMap}.
      */
-    class InternalLockInfo extends AbstractLockInfo implements SessionListener {
-
-        /**
-         * Create a new instance of this class.
-         *
-         * @param lockToken     lock token
-         * @param sessionScoped whether lock token is session scoped
-         * @param deep          whether lock is deep
-         * @param lockOwner     owner of lock
-         */
-        public InternalLockInfo(LockToken lockToken, boolean sessionScoped,
-                                boolean deep, String lockOwner) {
-            this(lockToken, sessionScoped, deep, lockOwner, TIMEOUT_INFINITE);
-        }
+    class InternalLockInfo extends LockInfo implements SessionListener {
 
         /**
          * Create a new instance of this class.
@@ -1192,7 +1237,7 @@
          * @param lockOwner     owner of lock
          * @param timeoutHint
          */
-        public InternalLockInfo(LockToken lockToken, boolean sessionScoped,
+        public InternalLockInfo(NodeId lockToken, boolean sessionScoped,
                                 boolean deep, String lockOwner, long timeoutHint) {
             super(lockToken, sessionScoped, deep, lockOwner, timeoutHint);
         }
@@ -1268,7 +1313,8 @@
             Path path = getPath(sysSession, nodeId);
 
             // create lock token
-            InternalLockInfo info = new InternalLockInfo(new LockToken(nodeId), false, isDeep, lockOwner);
+            InternalLockInfo info = new InternalLockInfo(
+                    nodeId, false, isDeep, lockOwner, Long.MAX_VALUE);
             info.setLive(true);
             lockMap.put(path, info);
 
@@ -1286,11 +1332,11 @@
 
         try {
             Path path = getPath(sysSession, nodeId);
-            PathMap.Element element = lockMap.map(path, true);
+            PathMap.Element<LockInfo> element = lockMap.map(path, true);
             if (element == null) {
                 throw new LockException("Node not locked: " + path.toString());
             }
-            AbstractLockInfo info = (AbstractLockInfo) element.get();
+            LockInfo info = element.get();
             if (info == null) {
                 throw new LockException("Node not locked: " + path.toString());
             }
@@ -1310,8 +1356,8 @@
      * @param ps print stream to dump to
      */
     public void dump(final PrintStream ps) {
-        lockMap.traverse(new PathMap.ElementVisitor() {
-            public void elementVisited(PathMap.Element element) {
+        lockMap.traverse(new PathMap.ElementVisitor<LockInfo>() {
+            public void elementVisited(PathMap.Element<LockInfo> element) {
                 StringBuffer line = new StringBuffer();
                 for (int i = 0; i < element.getDepth(); i++) {
                     line.append("--");

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XAEnvironment.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XAEnvironment.java?rev=812570&r1=812569&r2=812570&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XAEnvironment.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XAEnvironment.java Tue Sep  8 16:09:28 2009
@@ -108,9 +108,9 @@
      * @throws LockException if node is already locked
      * @throws RepositoryException if an error occurs
      */
-    public AbstractLockInfo lock(NodeImpl node, boolean isDeep, boolean isSessionScoped)
+    public LockInfo lock(NodeImpl node, boolean isDeep, boolean isSessionScoped)
             throws LockException, RepositoryException {
-        return lock(node, isDeep, isSessionScoped, AbstractLockInfo.TIMEOUT_INFINITE, null);
+        return lock(node, isDeep, isSessionScoped, Long.MAX_VALUE, null);
     }
 
     /**
@@ -125,7 +125,7 @@
      * @throws LockException if node is already locked
      * @throws RepositoryException if an error occurs
      */
-    public AbstractLockInfo lock(NodeImpl node, boolean isDeep, boolean isSessionScoped, long timeoutHint, String ownerInfo)
+    public LockInfo lock(NodeImpl node, boolean isDeep, boolean isSessionScoped, long timeoutHint, String ownerInfo)
             throws LockException, RepositoryException {
 
         NodeId id = node.getNodeId();
@@ -134,7 +134,7 @@
         XALockInfo info = unlockedNodesMap.get(id);
         if (info != null) {
             // if settings are compatible, this is effectively a no-op
-            if (info.deep == isDeep && info.sessionScoped == isSessionScoped) {
+            if (info.isDeep() == isDeep && info.isSessionScoped() == isSessionScoped) {
                 unlockedNodesMap.remove(id);
                 operations.remove(info);
                 return lockMgr.getLockInfo(id);
@@ -148,12 +148,12 @@
 
         // create a new lock info for this node
         String lockOwner = (ownerInfo != null) ? ownerInfo : node.getSession().getUserID();
-        info = new XALockInfo(node, new LockToken(id), isSessionScoped, isDeep, lockOwner);
+        info = new XALockInfo(node, isSessionScoped, isDeep, lockOwner);
         SessionImpl session = (SessionImpl) node.getSession();
         info.setLockHolder(session);
         info.setLive(true);
 
-        LockManagerImpl.getSessionLockManager(session).lockTokenAdded(info.lockToken.toString());
+        LockManagerImpl.getSessionLockManager(session).lockTokenAdded(info.getLockToken());
         lockedNodesMap.put(id, info);
         operations.add(info);
 
@@ -170,7 +170,7 @@
         NodeId id = node.getNodeId();
 
         // check positive set first
-        AbstractLockInfo info = lockedNodesMap.get(id);
+        LockInfo info = lockedNodesMap.get(id);
         if (info != null) {
             lockedNodesMap.remove(id);
             operations.remove(info);
@@ -207,7 +207,7 @@
      * @return LockInfo lock info or <code>null</code> if node is not locked
      * @throws RepositoryException if an error occurs
      */
-    public AbstractLockInfo getLockInfo(NodeImpl node) throws RepositoryException {
+    public LockInfo getLockInfo(NodeImpl node) throws RepositoryException {
         NodeId id = node.getNodeId();
 
         // check negative set
@@ -221,7 +221,7 @@
             for (;;) {
                 XALockInfo info = lockedNodesMap.get(current.getId());
                 if (info != null) {
-                    if (info.getId().equals(id) || info.deep) {
+                    if (info.getId().equals(id) || info.isDeep()) {
                         return info;
                     }
                     break;
@@ -237,21 +237,17 @@
     }
 
     /**
-     * Returns all <code>AbstractLockInfo</code>s associated with the specified
-     * session.
+     * Returns all locks associated with the specified session.
      * @param session session
-     * @return an array of <code>AbstractLockInfo</code>s
+     * @return locks associated with the session
      * @throws RepositoryException if an error occurs
      */
-    public AbstractLockInfo[] getLockInfos(SessionImpl session)
+    public LockInfo[] getLockInfos(SessionImpl session)
             throws RepositoryException {
-
-        ArrayList<AbstractLockInfo> result = new ArrayList<AbstractLockInfo>();
+        ArrayList<LockInfo> result = new ArrayList<LockInfo>();
 
         // get lock informations from global lock manager first
-        AbstractLockInfo[] infos = lockMgr.getLockInfos(session);
-        for (int i = 0; i < infos.length; i++) {
-            AbstractLockInfo info = infos[i];
+        for (LockInfo info : lockMgr.getLockInfos(session)) {
             // check negative set
             if (!unlockedNodesMap.containsKey(info.getId())) {
                 result.add(info);
@@ -261,7 +257,7 @@
         // add 'uncommitted' lock informations
         result.addAll(lockedNodesMap.values());
 
-        return (AbstractLockInfo[]) result.toArray(new AbstractLockInfo[result.size()]);
+        return (LockInfo[]) result.toArray(new LockInfo[result.size()]);
     }
 
     /**
@@ -272,9 +268,9 @@
      */
     public void addLockToken(SessionImpl session, String lt) throws RepositoryException {
         try {
-            LockToken lockToken = LockToken.parse(lt);
-            NodeImpl node = (NodeImpl) session.getItemManager().getItem(lockToken.getId());
-            AbstractLockInfo info = getLockInfo(node);
+            NodeId id = LockInfo.parseLockToken(lt);
+            NodeImpl node = (NodeImpl) session.getItemManager().getItem(id);
+            LockInfo info = getLockInfo(node);
             if (info != null) {
                 if (info.isLockHolder(session)) {
                     // nothing to do
@@ -303,10 +299,10 @@
      */
     public void removeLockToken(SessionImpl session, String lt) throws RepositoryException {
         try {
-            LockToken lockToken = LockToken.parse(lt);
+            NodeId id = LockInfo.parseLockToken(lt);
 
-            NodeImpl node = (NodeImpl) session.getItemManager().getItem(lockToken.getId());
-            AbstractLockInfo info = getLockInfo(node);
+            NodeImpl node = (NodeImpl) session.getItemManager().getItem(id);
+            LockInfo info = getLockInfo(node);
             if (info != null) {
                 if (info.isLockHolder(session)) {
                     info.setLockHolder(null);
@@ -416,7 +412,7 @@
      * Return a flag indicating whether a lock info belongs to a different
      * XA environment.
      */
-    public boolean differentXAEnv(AbstractLockInfo info) {
+    public boolean differentXAEnv(LockInfo info) {
         if (info instanceof XALockInfo) {
             XALockInfo lockInfo = (XALockInfo) info;
             return lockInfo.getXAEnv() != this;
@@ -427,7 +423,7 @@
     /**
      * Information about a lock used inside transactions.
      */
-    class XALockInfo extends AbstractLockInfo {
+    class XALockInfo extends LockInfo {
 
         /**
          * Node being locked/unlocked.
@@ -441,30 +437,14 @@
 
         /**
          * Create a new instance of this class.
-         * @param lockToken     lock token
-         * @param sessionScoped whether lock token is session scoped
-         * @param deep          whether lock is deep
-         * @param lockOwner     owner of lock
-         */
-        public XALockInfo(NodeImpl node, LockToken lockToken,
-                          boolean sessionScoped, boolean deep, String lockOwner) {
-
-            this(node, lockToken, sessionScoped, deep, lockOwner,
-                    TIMEOUT_INFINITE);
-        }
-
-        /**
-         * Create a new instance of this class.
-         * @param lockToken     lock token
          * @param sessionScoped whether lock token is session scoped
          * @param deep          whether lock is deep
          * @param lockOwner     owner of lock
          */
-        public XALockInfo(NodeImpl node, LockToken lockToken,
-                          boolean sessionScoped, boolean deep, String lockOwner,
-                          long timeoutHint) {
-
-            super(lockToken, sessionScoped, deep, lockOwner, timeoutHint);
+        public XALockInfo(
+                NodeImpl node,
+                boolean sessionScoped, boolean deep, String lockOwner) {
+            super(node.getNodeId(), sessionScoped, deep, lockOwner, Long.MAX_VALUE);
             this.node = node;
         }
 
@@ -472,9 +452,8 @@
          * Create a new instance of this class. Used to signal an
          * unlock operation on some existing lock information.
          */
-        public XALockInfo(NodeImpl node, AbstractLockInfo info) {
-            super(info.lockToken, info.sessionScoped, info.deep, info.lockOwner, info.getSecondsRemaining());
-
+        public XALockInfo(NodeImpl node, LockInfo info) {
+            super(info);
             this.node = node;
             this.isUnlock = true;
         }
@@ -495,8 +474,10 @@
             if (isUnlock) {
                 lockMgr.internalUnlock(node);
             } else {
-                AbstractLockInfo internalLock = lockMgr.internalLock(node, deep, sessionScoped, getSecondsRemaining(), lockOwner);
-                AbstractLockInfo xaEnvLock = getLockInfo(node);
+                LockInfo internalLock = lockMgr.internalLock(
+                        node, isDeep(), isSessionScoped(),
+                        getTimeoutTime(), getLockOwner());
+                LockInfo xaEnvLock = getLockInfo(node);
                 // Check if the lockToken has been removed in the transaction ...
                 if (xaEnvLock != null && xaEnvLock.getLockHolder() == null) {
                     internalLock.setLockHolder(null);
@@ -509,7 +490,9 @@
          */
         public void undo() throws LockException, RepositoryException {
             if (isUnlock) {
-                lockMgr.internalLock(node, deep, sessionScoped, getSecondsRemaining(), lockOwner);
+                lockMgr.internalLock(
+                        node, isDeep(), isSessionScoped(),
+                        getTimeoutHint(), getLockOwner());
             } else {
                 lockMgr.internalUnlock(node);
             }

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockImpl.java?rev=812570&r1=812569&r2=812570&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockImpl.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockImpl.java Tue Sep  8 16:09:28 2009
@@ -18,7 +18,6 @@
 
 import org.apache.jackrabbit.core.NodeImpl;
 
-import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 
 /**
@@ -32,16 +31,17 @@
     private final XALockManager lockMgr;
     
     /**
-     * Abstract lock info.
+     * The underlying lock info.
      */
-    private final AbstractLockInfo info;
+    private final LockInfo info;
 
     /**
      * Create a new instance of this class.
      * @param info lock information
      * @param node node holding lock
      */
-    public XALockImpl(XALockManager lockMgr, AbstractLockInfo info, Node node) {
+    public XALockImpl(
+            XALockManager lockMgr, LockInfo info, NodeImpl node) {
         super(info, node);
 
         this.info = info;
@@ -56,7 +56,7 @@
     public boolean isLive() throws RepositoryException {
         if (info.mayChange()) {
             if (lockMgr.differentXAEnv(info)) {
-                return lockMgr.holdsLock((NodeImpl) node);
+                return lockMgr.holdsLock(node);
             }
         }
         return super.isLive();

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockManager.java?rev=812570&r1=812569&r2=812570&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockManager.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/lock/XALockManager.java Tue Sep  8 16:09:28 2009
@@ -65,7 +65,7 @@
      */
     public Lock lock(NodeImpl node, boolean isDeep, boolean isSessionScoped)
             throws LockException, RepositoryException {
-        return lock(node, isDeep, isSessionScoped, AbstractLockInfo.TIMEOUT_INFINITE, null);
+        return lock(node, isDeep, isSessionScoped, Long.MAX_VALUE, null);
     }
 
     /**
@@ -73,13 +73,13 @@
      */
     public Lock lock(NodeImpl node, boolean isDeep, boolean isSessionScoped, long timoutHint, String ownerInfo)
             throws LockException, RepositoryException {
-        AbstractLockInfo info;
+        LockInfo info;
         if (isInXA()) {
             info = xaEnv.lock(node, isDeep, isSessionScoped, timoutHint, ownerInfo);
         } else {
             info = lockMgr.internalLock(node, isDeep, isSessionScoped, timoutHint, ownerInfo);
         }
-        lockMgr.writeLockProperties(node, info.lockOwner, info.deep);
+        lockMgr.writeLockProperties(node, info.getLockOwner(), info.isDeep());
         return new XALockImpl(this, info, node);
     }
 
@@ -87,7 +87,7 @@
      * {@inheritDoc}
      */
     public Lock getLock(NodeImpl node) throws LockException, RepositoryException {
-        AbstractLockInfo info;
+        LockInfo info;
         if (isInXA()) {
             info = xaEnv.getLockInfo(node);
         } else {
@@ -105,7 +105,7 @@
      * {@inheritDoc}
      */
     public Lock[] getLocks(SessionImpl session) throws RepositoryException {
-        AbstractLockInfo[] infos;
+        LockInfo[] infos;
         if (isInXA()) {
             infos = xaEnv.getLockInfos(session);
         } else {
@@ -115,7 +115,7 @@
         XALockImpl[] locks = new XALockImpl[infos.length];
 
         for (int i = 0; i < infos.length; i++) {
-            AbstractLockInfo info = infos[i];
+            LockInfo info = infos[i];
             NodeImpl holder = (NodeImpl) session.getItemManager().getItem(info.getId());
             locks[i] = new XALockImpl(this, info, holder);
         }
@@ -138,7 +138,7 @@
      * {@inheritDoc}
      */
     public boolean holdsLock(NodeImpl node) throws RepositoryException {
-        AbstractLockInfo info;
+        LockInfo info;
         if (isInXA()) {
             info = xaEnv.getLockInfo(node);
         } else {
@@ -151,7 +151,7 @@
      * {@inheritDoc}
      */
     public boolean isLocked(NodeImpl node) throws RepositoryException {
-        AbstractLockInfo info;
+        LockInfo info;
         if (isInXA()) {
             info = xaEnv.getLockInfo(node);
         } else {
@@ -164,7 +164,7 @@
      * {@inheritDoc}
      */
     public void checkLock(NodeImpl node) throws LockException, RepositoryException {
-        AbstractLockInfo info;
+        LockInfo info;
         if (isInXA()) {
             info = xaEnv.getLockInfo(node);
             if (info != null && !info.isLockHolder(node.getSession())) {
@@ -196,7 +196,7 @@
             throws LockException, RepositoryException {
 
         if (isInXA()) {
-            AbstractLockInfo info = xaEnv.getLockInfo(node);
+            LockInfo info = xaEnv.getLockInfo(node);
             if (info == null || !info.getId().equals(node.getId())) {
                 throw new LockException("Node not locked: " + node);
             }
@@ -297,7 +297,7 @@
      * Return a flag indicating whether a lock info belongs to a different
      * XA environment.
      */
-    public boolean differentXAEnv(AbstractLockInfo info) {
+    public boolean differentXAEnv(LockInfo info) {
         if (isInXA()) {
             return xaEnv.differentXAEnv(info);
         } else {

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/EffectiveNodeType.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/EffectiveNodeType.java?rev=812570&r1=812569&r2=812570&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/EffectiveNodeType.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/EffectiveNodeType.java Tue Sep  8 16:09:28 2009
@@ -1150,7 +1150,8 @@
             clone.namedItemDefs.put(name, new ArrayList<ItemDef>(list));
         }
         clone.unnamedItemDefs.addAll(unnamedItemDefs);
-
+        clone.orderableChildNodes = orderableChildNodes;
+        clone.primaryItemName = primaryItemName;
         return clone;
     }
 }

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeManagerImpl.java?rev=812570&r1=812569&r2=812570&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeManagerImpl.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeManagerImpl.java Tue Sep  8 16:09:28 2009
@@ -60,6 +60,7 @@
 import org.apache.jackrabbit.spi.QNodeTypeDefinition;
 import org.apache.jackrabbit.spi.QValueConstraint;
 import org.apache.jackrabbit.spi.commons.conversion.NameException;
+import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
 import org.apache.jackrabbit.spi.commons.namespace.NamespaceMapping;
 import org.apache.jackrabbit.spi.commons.nodetype.AbstractNodeTypeManager;
 import org.apache.jackrabbit.spi.commons.nodetype.InvalidConstraintException;
@@ -207,6 +208,13 @@
     }
 
     /**
+     * @see org.apache.jackrabbit.spi.commons.nodetype.AbstractNodeTypeManager#getNamePathResolver() 
+     */
+    public NamePathResolver getNamePathResolver() {
+        return session;
+    }
+
+    /**
      * @return the node type registry
      */
     public NodeTypeRegistry getNodeTypeRegistry() {

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java?rev=812570&r1=812569&r2=812570&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java Tue Sep  8 16:09:28 2009
@@ -1275,8 +1275,11 @@
         // and do some preliminary checks
         for (NodeTypeDef ntd : ntDefs) {
             Name name = ntd.getName();
-            if (name != null && registeredNTDefs.containsKey(name)) {
+            if (name != null && tmpNTDefCache.containsKey(name)) {
                 String msg = name + " already exists";
+                if (tmpNTDefCache.containsKey(name)) {
+                    msg += " locally";
+                }
                 log.debug(msg);
                 throw new InvalidNodeTypeDefException(msg);
             }

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventFilter.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventFilter.java?rev=812570&r1=812569&r2=812570&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventFilter.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventFilter.java Tue Sep  8 16:09:28 2009
@@ -27,6 +27,7 @@
 import org.apache.jackrabbit.spi.Path;
 
 import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeType;
 
 /**
  * The <code>EventFilter</code> class implements the filter logic based
@@ -180,10 +181,10 @@
 
         // check node types
         if (nodeTypes != null) {
-            Set eventTypes = eventState.getNodeTypes(session.getNodeTypeManager());
+            Set<NodeType> eventTypes = eventState.getNodeTypes(session.getNodeTypeManager());
             boolean match = false;
             for (int i = 0; i < nodeTypes.length && !match; i++) {
-                for (Iterator iter = eventTypes.iterator(); iter.hasNext();) {
+                for (Iterator<NodeType> iter = eventTypes.iterator(); iter.hasNext();) {
                     NodeTypeImpl nodeType = (NodeTypeImpl) iter.next();
                     match |= nodeType.getQName().equals(nodeTypes[i].getQName())
                             || nodeType.isDerivedFrom(nodeTypes[i].getQName());

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java?rev=812570&r1=812569&r2=812570&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventImpl.java Tue Sep  8 16:09:28 2009
@@ -18,7 +18,6 @@
 
 import java.util.Map;
 import java.util.HashMap;
-import java.util.Iterator;
 
 import org.apache.jackrabbit.api.observation.JackrabbitEvent;
 import javax.jcr.observation.Event;
@@ -141,11 +140,10 @@
     /**
      * {@inheritDoc}
      */
-    public Map getInfo() throws RepositoryException {
-        Map info = new HashMap();
-        for (Iterator it = eventState.getInfo().entrySet().iterator(); it.hasNext(); ) {
-            Map.Entry entry = (Map.Entry) it.next();
-            InternalValue value = (InternalValue) entry.getValue();
+    public Map<String, String> getInfo() throws RepositoryException {
+        Map<String, String> info = new HashMap<String, String>();
+        for (Map.Entry<String, InternalValue> entry : eventState.getInfo().entrySet()) {
+            InternalValue value = entry.getValue();
             String strValue = null;
             if (value != null) {
                 strValue = ValueFormat.getJCRString(value, session);

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventJournalImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventJournalImpl.java?rev=812570&r1=812569&r2=812570&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventJournalImpl.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventJournalImpl.java Tue Sep  8 16:09:28 2009
@@ -67,7 +67,7 @@
      * Each sorted map has the following structure:
      * Key=Long (timestamp), Value=Long (revision)
      */
-    private static final Map REVISION_SKIP_MAPS = new WeakHashMap();
+    private static final Map<Journal, SortedMap<Long, Long>> REVISION_SKIP_MAPS = new WeakHashMap<Journal, SortedMap<Long, Long>>();
 
     /**
      * Last revision seen by this event journal.
@@ -97,7 +97,7 @@
     /**
      * Buffer of {@link EventBundle}s.
      */
-    private final List eventBundleBuffer = new LinkedList();
+    private final List<EventBundle> eventBundleBuffer = new LinkedList<EventBundle>();
 
     /**
      * The current position of this iterator.
@@ -129,12 +129,12 @@
         long time = System.currentTimeMillis();
 
         // get skip map for this journal
-        SortedMap skipMap = getSkipMap();
+        SortedMap<Long, Long> skipMap = getSkipMap();
         synchronized (skipMap) {
-            SortedMap head = skipMap.headMap(new Long(time));
+            SortedMap<Long, Long> head = skipMap.headMap(new Long(time));
             if (!head.isEmpty()) {
                 eventBundleBuffer.clear();
-                lastRevision = (Long) head.get(head.lastKey());
+                lastRevision = head.get(head.lastKey());
             }
         }
 
@@ -267,7 +267,7 @@
          * {@inheritDoc}
          */
         public void process(ChangeLogRecord record) {
-            List events = record.getEvents();
+            List<EventState> events = record.getEvents();
             if (!events.isEmpty()) {
                 EventBundle bundle = new EventBundle(events,
                         record.getTimestamp(), record.getUserData(), filter);
@@ -304,7 +304,7 @@
      */
     private EventBundle getCurrentBundle() {
         while (!eventBundleBuffer.isEmpty()) {
-            EventBundle bundle = (EventBundle) eventBundleBuffer.get(0);
+            EventBundle bundle = eventBundleBuffer.get(0);
             if (bundle.events.hasNext()) {
                 return bundle;
             } else {
@@ -346,7 +346,7 @@
 
                 if (processor.getNumEvents() >= MIN_BUFFER_SIZE) {
                     // remember in skip map
-                    SortedMap skipMap = getSkipMap();
+                    SortedMap<Long, Long> skipMap = getSkipMap();
                     Long timestamp = new Long(processor.getLastTimestamp());
                     synchronized (skipMap) {
                         if (log.isDebugEnabled()) {
@@ -369,11 +369,11 @@
     /**
      * @return the revision skip map for this journal.
      */
-    private SortedMap getSkipMap() {
+    private SortedMap<Long, Long> getSkipMap() {
         synchronized (REVISION_SKIP_MAPS) {
-            SortedMap map = (SortedMap) REVISION_SKIP_MAPS.get(journal);
+            SortedMap<Long, Long> map = REVISION_SKIP_MAPS.get(journal);
             if (map == null) {
-                map = new TreeMap();
+                map = new TreeMap<Long, Long>();
                 REVISION_SKIP_MAPS.put(journal, map);
             }
             return map;
@@ -403,7 +403,7 @@
          * @param userData the user data associated with this event.
          * @param filter the event filter.
          */
-        private EventBundle(List eventStates,
+        private EventBundle(List<EventState> eventStates,
                             long timestamp,
                             String userData,
                             EventFilter filter) {

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventListenerIteratorImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventListenerIteratorImpl.java?rev=812570&r1=812569&r2=812570&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventListenerIteratorImpl.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventListenerIteratorImpl.java Tue Sep  8 16:09:28 2009
@@ -48,7 +48,7 @@
     /**
      * Current position
      */
-    private long pos = 0;
+    private long pos;
 
     /**
      * Creates a new <code>EventListenerIteratorImpl</code>.

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventState.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventState.java?rev=812570&r1=812569&r2=812570&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventState.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventState.java Tue Sep  8 16:09:28 2009
@@ -33,6 +33,8 @@
 import javax.jcr.Session;
 import javax.jcr.RepositoryException;
 import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeType;
+
 import java.util.Set;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -107,7 +109,7 @@
     /**
      * Set of mixin QNames assigned to the parent node.
      */
-    private final Set mixins;
+    private final Set<Name> mixins;
 
     /**
      * Set of node types. This Set consists of the primary node type and all
@@ -116,7 +118,7 @@
      * This <code>Set</code> is initialized when
      * {@link #getNodeTypes(NodeTypeManagerImpl)} is called for the first time.
      */
-    private Set allTypes;
+    private Set<NodeType> allTypes;
 
     /**
      * The session that caused this event.
@@ -142,13 +144,13 @@
     /**
      * The info Map associated with this event.
      */
-    private Map info = Collections.EMPTY_MAP;
+    private Map<String, InternalValue> info = Collections.emptyMap();
 
     /**
      * If set to <code>true</code>, indicates that the child node of a node
      * added or removed event is a shareable node.
      */
-    private boolean shareableNode = false;
+    private boolean shareableNode;
 
     /**
      * Creates a new <code>EventState</code> instance.
@@ -169,7 +171,7 @@
      */
     private EventState(int type, NodeId parentId, Path parentPath,
                        NodeId childId, Path.Element childPath, Name nodeType,
-                       Set mixins, Session session, boolean external) {
+                       Set<Name> mixins, Session session, boolean external) {
 
         int mask = (Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED);
         if ((type & mask) > 0) {
@@ -214,7 +216,7 @@
                                             NodeId childId,
                                             Path.Element childPath,
                                             Name nodeType,
-                                            Set mixins,
+                                            Set<Name> mixins,
                                             Session session) {
 
         return childNodeAdded(parentId, parentPath, childId,
@@ -242,7 +244,7 @@
                                             NodeId childId,
                                             Path.Element childPath,
                                             Name nodeType,
-                                            Set mixins,
+                                            Set<Name> mixins,
                                             Session session,
                                             boolean external) {
 
@@ -270,7 +272,7 @@
                                               NodeId childId,
                                               Path.Element childPath,
                                               Name nodeType,
-                                              Set mixins,
+                                              Set<Name> mixins,
                                               Session session) {
 
         return childNodeRemoved(parentId, parentPath, childId,
@@ -298,7 +300,7 @@
                                               NodeId childId,
                                               Path.Element childPath,
                                               Name nodeType,
-                                              Set mixins,
+                                              Set<Name> mixins,
                                               Session session,
                                               boolean external) {
 
@@ -330,7 +332,7 @@
                                        NodeId childId,
                                        Path.Element childPath,
                                        Name nodeType,
-                                       Set mixins,
+                                       Set<Name> mixins,
                                        Session session,
                                        boolean external) {
 
@@ -361,7 +363,7 @@
                                        NodeId childId,
                                        Path srcPath,
                                        Name nodeType,
-                                       Set mixins,
+                                       Set<Name> mixins,
                                        Session session,
                                        boolean external)
             throws ItemStateException {
@@ -369,7 +371,7 @@
             EventState es = nodeMoved(parentId, destPath.getAncestor(1),
                     childId, destPath.getNameElement(), nodeType, mixins,
                     session, external);
-            Map info = new HashMap();
+            Map<String, InternalValue> info = new HashMap<String, InternalValue>();
             info.put(SRC_ABS_PATH, InternalValue.create(srcPath));
             info.put(DEST_ABS_PATH, InternalValue.create(destPath));
             es.setInfo(info);
@@ -412,12 +414,12 @@
                                            Path.Element srcChildPath,
                                            Path.Element beforeChildPath,
                                            Name nodeType,
-                                           Set mixins,
+                                           Set<Name> mixins,
                                            Session session,
                                            boolean external) {
         EventState es = nodeMoved(parentId, parentPath, childId, destChildPath,
                nodeType, mixins, session, external);
-        Map info = new HashMap();
+        Map<String, InternalValue> info = new HashMap<String, InternalValue>();
         info.put(SRC_CHILD_REL_PATH, createValue(srcChildPath));
         InternalValue value = null;
         if (beforeChildPath != null) {
@@ -446,7 +448,7 @@
                                            Path parentPath,
                                            Path.Element childPath,
                                            Name nodeType,
-                                           Set mixins,
+                                           Set<Name> mixins,
                                            Session session) {
 
         return propertyAdded(parentId, parentPath, childPath,
@@ -472,7 +474,7 @@
                                            Path parentPath,
                                            Path.Element childPath,
                                            Name nodeType,
-                                           Set mixins,
+                                           Set<Name> mixins,
                                            Session session,
                                            boolean external) {
 
@@ -498,7 +500,7 @@
                                              Path parentPath,
                                              Path.Element childPath,
                                              Name nodeType,
-                                             Set mixins,
+                                             Set<Name> mixins,
                                              Session session) {
 
         return propertyRemoved(parentId, parentPath, childPath,
@@ -524,7 +526,7 @@
                                              Path parentPath,
                                              Path.Element childPath,
                                              Name nodeType,
-                                             Set mixins,
+                                             Set<Name> mixins,
                                              Session session,
                                              boolean external) {
 
@@ -550,7 +552,7 @@
                                              Path parentPath,
                                              Path.Element childPath,
                                              Name nodeType,
-                                             Set mixins,
+                                             Set<Name> mixins,
                                              Session session) {
 
         return propertyChanged(parentId, parentPath, childPath,
@@ -576,7 +578,7 @@
                                              Path parentPath,
                                              Path.Element childPath,
                                              Name nodeType,
-                                             Set mixins,
+                                             Set<Name> mixins,
                                              Session session,
                                              boolean external) {
 
@@ -645,7 +647,7 @@
      *
      * @return the mixin names as <code>Name</code>s.
      */
-    public Set getMixinNames() {
+    public Set<Name> getMixinNames() {
         return mixins;
     }
 
@@ -657,17 +659,17 @@
      *
      * @return <code>Set</code> of {@link javax.jcr.nodetype.NodeType}s.
      */
-    public Set getNodeTypes(NodeTypeManagerImpl ntMgr) {
+    public Set<NodeType> getNodeTypes(NodeTypeManagerImpl ntMgr) {
         if (allTypes == null) {
-            Set tmp = new HashSet();
+            Set<NodeType> tmp = new HashSet<NodeType>();
             try {
                 tmp.add(ntMgr.getNodeType(nodeType));
             } catch (NoSuchNodeTypeException e) {
                 log.warn("Unknown node type: " + nodeType);
             }
-            Iterator it = mixins.iterator();
+            Iterator<Name> it = mixins.iterator();
             while (it.hasNext()) {
-                Name mixinName = (Name) it.next();
+                Name mixinName = it.next();
                 try {
                     tmp.add(ntMgr.getNodeType(mixinName));
                 } catch (NoSuchNodeTypeException e) {
@@ -725,7 +727,7 @@
     /**
      * @return an unmodifiable info Map.
      */
-    public Map getInfo() {
+    public Map<String, InternalValue> getInfo() {
         return info;
     }
 
@@ -734,8 +736,8 @@
      *
      * @param info the new info map.
      */
-    public void setInfo(Map info) {
-        this.info = Collections.unmodifiableMap(new HashMap(info));
+    public void setInfo(Map<String, InternalValue> info) {
+        this.info = Collections.unmodifiableMap(new HashMap<String, InternalValue>(info));
     }
 
     /**

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventStateCollection.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventStateCollection.java?rev=812570&r1=812569&r2=812570&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventStateCollection.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/observation/EventStateCollection.java Tue Sep  8 16:09:28 2009
@@ -562,7 +562,13 @@
                 if (n.getParentId().equals(parentId)) {
                     continue;
                 }
-                NodeState parent = (NodeState) changes.get(parentId);
+                NodeState parent = null;
+                try {
+                    parent = (NodeState) changes.get(parentId);
+                } catch (NoSuchItemStateException e) {
+                    // parent has been removed as well
+                    // ignore and retrieve from stateMgr
+                }
                 if (parent == null) {
                     // happens when mix:shareable is removed from an existing
                     // node. Usually the parent node state is in the change log

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceCopier.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceCopier.java?rev=812570&r1=812569&r2=812570&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceCopier.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceCopier.java Tue Sep  8 16:09:28 2009
@@ -16,9 +16,15 @@
  */
 package org.apache.jackrabbit.core.persistence;
 
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.HashSet;
 import java.util.Set;
 
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.data.DataStore;
 import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.id.PropertyId;
 import org.apache.jackrabbit.core.state.ChangeLog;
@@ -27,6 +33,7 @@
 import org.apache.jackrabbit.core.state.NodeReferences;
 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.spi.Name;
 
 /**
@@ -48,6 +55,11 @@
     private final PersistenceManager target;
 
     /**
+     * Target data store, possibly <code>null</code>.
+     */
+    private final DataStore store;
+
+    /**
      * Identifiers of the nodes that have already been copied or that
      * should explicitly not be copied. Used to avoid duplicate copies
      * of shareable nodes and to avoid trying to copy "missing" nodes
@@ -61,11 +73,14 @@
      *
      * @param source source persistence manager
      * @param target target persistence manager
+     * @param store target data store
      */
     public PersistenceCopier(
-            PersistenceManager source, PersistenceManager target) {
+            PersistenceManager source,  PersistenceManager target,
+            DataStore store) {
         this.source = source;
         this.target = target;
+        this.store = store;
     }
 
     /**
@@ -84,18 +99,22 @@
      * are automatically skipped.
      *
      * @param id identifier of the node to be copied
-     * @throws ItemStateException if the copy operation fails
+     * @throws RepositoryException if the copy operation fails
      */
-    public void copy(NodeId id) throws ItemStateException {
+    public void copy(NodeId id) throws RepositoryException {
         if (!exclude.contains(id)) {
-            NodeState node = source.load(id);
+            try {
+                NodeState node = source.load(id);
 
-            for (ChildNodeEntry entry : node.getChildNodeEntries()) {
-                copy(entry.getId());
+                for (ChildNodeEntry entry : node.getChildNodeEntries()) {
+                    copy(entry.getId());
+                }
+
+                copy(node);
+                exclude.add(id);
+            } catch (ItemStateException e) {
+                throw new RepositoryException("Unable to copy " + id, e);
             }
-
-            copy(node);
-            exclude.add(id);
         }
     }
 
@@ -104,54 +123,71 @@
      * to the target persistence manager.
      *
      * @param sourceNode source node state
-     * @throws ItemStateException if the copy operation fails
+     * @throws RepositoryException if the copy operation fails
      */
-    private void copy(NodeState sourceNode) throws ItemStateException {
-        ChangeLog changes = new ChangeLog();
+    private void copy(NodeState sourceNode) throws RepositoryException {
+        try {
+            ChangeLog changes = new ChangeLog();
+
+            // Copy the node state
+            NodeState targetNode = target.createNew(sourceNode.getNodeId());
+            targetNode.setParentId(sourceNode.getParentId());
+            targetNode.setDefinitionId(sourceNode.getDefinitionId());
+            targetNode.setNodeTypeName(sourceNode.getNodeTypeName());
+            targetNode.setMixinTypeNames(sourceNode.getMixinTypeNames());
+            targetNode.setPropertyNames(sourceNode.getPropertyNames());
+            targetNode.setChildNodeEntries(sourceNode.getChildNodeEntries());
+            if (target.exists(targetNode.getNodeId())) {
+                changes.modified(targetNode);
+            } else {
+                changes.added(targetNode);
+            }
 
-        // Copy the node state
-        NodeState targetNode = target.createNew(sourceNode.getNodeId());
-        targetNode.setParentId(sourceNode.getParentId());
-        targetNode.setDefinitionId(sourceNode.getDefinitionId());
-        targetNode.setNodeTypeName(sourceNode.getNodeTypeName());
-        targetNode.setMixinTypeNames(sourceNode.getMixinTypeNames());
-        targetNode.setPropertyNames(sourceNode.getPropertyNames());
-        targetNode.setChildNodeEntries(sourceNode.getChildNodeEntries());
-        if (target.exists(targetNode.getNodeId())) {
-            changes.modified(targetNode);
-        } else {
-            changes.added(targetNode);
-        }
+            // Copy all associated property states
+            for (Name name : sourceNode.getPropertyNames()) {
+                PropertyId id = new PropertyId(sourceNode.getNodeId(), name);
+                PropertyState sourceState = source.load(id);
+                PropertyState targetState = target.createNew(id);
+                targetState.setDefinitionId(sourceState.getDefinitionId());
+                targetState.setType(sourceState.getType());
+                targetState.setMultiValued(sourceState.isMultiValued());
+                InternalValue[] values = sourceState.getValues();
+                if (sourceState.getType() == PropertyType.BINARY) {
+                    for (int i = 0; i < values.length; i++) {
+                        InputStream stream = values[i].getStream();
+                        try {
+                            values[i] = InternalValue.create(stream, store);
+                        } finally {
+                            stream.close();
+                        }
+                    }
+                }
+                targetState.setValues(values);
+                if (target.exists(targetState.getPropertyId())) {
+                    changes.modified(targetState);
+                } else {
+                    changes.added(targetState);
+                }
+            }
 
-        // Copy all associated property states
-        for (Name name : sourceNode.getPropertyNames()) {
-            PropertyId id = new PropertyId(sourceNode.getNodeId(), name);
-            PropertyState sourceState = source.load(id);
-            PropertyState targetState = target.createNew(id);
-            targetState.setDefinitionId(sourceState.getDefinitionId());
-            targetState.setType(sourceState.getType());
-            targetState.setMultiValued(sourceState.isMultiValued());
-            // TODO: Copy binaries?
-            targetState.setValues(sourceState.getValues());
-            if (target.exists(targetState.getPropertyId())) {
-                changes.modified(targetState);
-            } else {
-                changes.added(targetState);
+            // Copy all node references
+            if (source.existsReferencesTo(sourceNode.getNodeId())) {
+                changes.modified(source.loadReferencesTo(sourceNode.getNodeId()));
+            } else if (target.existsReferencesTo(sourceNode.getNodeId())) {
+                NodeReferences references =
+                    target.loadReferencesTo(sourceNode.getNodeId());
+                references.clearAllReferences();
+                changes.modified(references);
             }
-        }
 
-        // Copy all node references
-        if (source.existsReferencesTo(sourceNode.getNodeId())) {
-            changes.modified(source.loadReferencesTo(sourceNode.getNodeId()));
-        } else if (target.existsReferencesTo(sourceNode.getNodeId())) {
-            NodeReferences references =
-                target.loadReferencesTo(sourceNode.getNodeId());
-            references.clearAllReferences();
-            changes.modified(references);
+            // Persist the copied states
+            target.store(changes);
+        } catch (IOException e) {
+            throw new RepositoryException(
+                    "Unable to copy binary values of " + sourceNode, e);
+        } catch (ItemStateException e) {
+            throw new RepositoryException("Unable to copy " + sourceNode, e);
         }
-
-        // Persist the copied states
-        target.store(changes);
     }
 
 }