jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ang...@apache.org
Subject svn commit: r421270 [3/23] - in /jackrabbit/trunk/contrib/spi: ./ commons/ commons/src/ commons/src/main/ commons/src/main/java/ commons/src/main/java/org/ commons/src/main/java/org/apache/ commons/src/main/java/org/apache/jackrabbit/ commons/src/main/...
Date Wed, 12 Jul 2006 13:33:27 GMT
Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/CachingHierarchyManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/CachingHierarchyManager.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/CachingHierarchyManager.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/CachingHierarchyManager.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,736 @@
+/*
+ * 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.jcr2spi;
+
+import org.apache.commons.collections.map.ReferenceMap;
+import org.apache.jackrabbit.jcr2spi.state.ItemState;
+import org.apache.jackrabbit.jcr2spi.state.ItemStateException;
+import org.apache.jackrabbit.jcr2spi.state.ItemStateManager;
+import org.apache.jackrabbit.jcr2spi.state.NodeState;
+import org.apache.jackrabbit.jcr2spi.state.NodeStateListener;
+import org.apache.jackrabbit.name.NamespaceResolver;
+import org.apache.jackrabbit.name.Path;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.name.MalformedPathException;
+import org.apache.jackrabbit.util.PathMap;
+import org.apache.jackrabbit.spi.ItemId;
+import org.apache.jackrabbit.spi.NodeId;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Implementation of a <code>HierarchyManager</code> that caches paths of
+ * items.
+ */
+public class CachingHierarchyManager extends HierarchyManagerImpl
+        implements NodeStateListener {
+
+    /**
+     * Default upper limit of cached states
+     */
+    public static final int DEFAULT_UPPER_LIMIT = 10000;
+
+    /**
+     * Logger instance
+     */
+    private static Logger log = LoggerFactory.getLogger(CachingHierarchyManager.class);
+
+    /**
+     * Mapping of paths to children in the path map
+     */
+    private final PathMap pathCache = new PathMap();
+
+    /**
+     * Mapping of item ids to <code>LRUEntry</code> in the path map
+     */
+    private final ReferenceMap idCache = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.HARD);
+
+    /**
+     * Set of items that were moved
+     */
+    private final Set movedIds = new HashSet();
+
+    /**
+     * Cache monitor object
+     */
+    private final Object cacheMonitor = new Object();
+
+    /**
+     * Upper limit
+     */
+    private final int upperLimit;
+
+    /**
+     * Head of LRU
+     */
+    private LRUEntry head;
+
+    /**
+     * Tail of LRU
+     */
+    private LRUEntry tail;
+
+    /**
+     * Create a new instance of this class.
+     *
+     * @param rootNodeId   root node id
+     * @param itemStateManager     item state manager
+     * @param nsResolver   namespace resolver
+     */
+    public CachingHierarchyManager(NodeId rootNodeId,
+                                   ItemStateManager itemStateManager,
+                                   NamespaceResolver nsResolver) {
+        super(rootNodeId, itemStateManager, nsResolver);
+        upperLimit = DEFAULT_UPPER_LIMIT;
+    }
+
+    //-------------------------------------------------< base class overrides >
+    /**
+     * {@inheritDoc}
+     * <p/>
+     * Cache the intermediate item inside our cache.
+     */
+    protected ItemId resolvePath(Path path, ItemState state, int next)
+            throws PathNotFoundException, ItemStateException {
+
+        if (state.isNode() && !isCached(state.getId())) {
+            try {
+                Path.PathBuilder builder = new Path.PathBuilder();
+                Path.PathElement[] elements = path.getElements();
+                for (int i = 0; i < next; i++) {
+                    builder.addLast(elements[i]);
+                }
+                Path parentPath = builder.getPath();
+                cache((NodeState) state, parentPath);
+            } catch (MalformedPathException mpe) {
+                log.warn("Failed to build path of " + state.getId(), mpe);
+            }
+        }
+        return super.resolvePath(path, state, next);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p/>
+     * Overridden method tries to find a mapping for the intermediate item
+     * <code>state</code> and add its path elements to the builder currently
+     * being used. If no mapping is found, the item is cached instead after
+     * the base implementation has been invoked.
+     */
+    protected void buildPath(Path.PathBuilder builder, ItemState state)
+            throws ItemStateException, RepositoryException {
+
+        if (state.isNode()) {
+            PathMap.Element element = get(state.getId());
+            if (element != null) {
+                try {
+                    Path.PathElement[] elements = element.getPath().getElements();
+                    for (int i = elements.length - 1; i >= 0; i--) {
+                        builder.addFirst(elements[i]);
+                    }
+                    return;
+                } catch (MalformedPathException mpe) {
+                    String msg = "Failed to build path of " + state.getId();
+                    log.debug(msg);
+                    throw new RepositoryException(msg, mpe);
+                }
+            }
+        }
+
+        super.buildPath(builder, state);
+
+        if (state.isNode()) {
+            try {
+                cache((NodeState) state, builder.getPath());
+            } catch (org.apache.jackrabbit.name.MalformedPathException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    //-----------------------------------------------------< HierarchyManager >
+    /**
+     * {@inheritDoc}
+     * <p/>
+     * Check the path indicated inside our cache first.
+     */
+    public ItemId getItemId(Path qPath)
+            throws PathNotFoundException, RepositoryException {
+
+        // Run base class shortcut and sanity checks first
+        if (qPath.denotesRoot()) {
+            return rootNodeId;
+        } else if (!qPath.isCanonical()) {
+            String msg = "path is not canonical";
+            log.debug(msg);
+            throw new RepositoryException(msg);
+        }
+
+        PathMap.Element element = map(qPath);
+        if (element == null) {
+            return super.getItemId(qPath);
+        }
+        LRUEntry entry = (LRUEntry) element.get();
+        if (element.hasPath(qPath)) {
+            entry.touch();
+            return entry.getId();
+        }
+        return super.resolvePath(qPath, entry.getId(), element.getDepth() + 1);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p/>
+     * Overridden method simply checks whether we have an item matching the id
+     * and returns its path, otherwise calls base implementation.
+     */
+    public Path getQPath(ItemId id)
+            throws ItemNotFoundException, RepositoryException {
+
+        if (id.denotesNode()) {
+            PathMap.Element element = get(id);
+            if (element != null) {
+                try {
+                    return element.getPath();
+                } catch (MalformedPathException pe) {
+                    String msg = "Failed to build path of " + id;
+                    log.debug(msg);
+                    throw new RepositoryException(msg, pe);
+                }
+            }
+        }
+        return super.getQPath(id);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public QName getQName(ItemId id)
+            throws ItemNotFoundException, RepositoryException {
+
+        if (id.denotesNode()) {
+            PathMap.Element element = get(id);
+            if (element != null) {
+                return element.getName();
+            }
+        }
+        return super.getQName(id);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getDepth(ItemId id)
+            throws ItemNotFoundException, RepositoryException {
+
+        if (id.denotesNode()) {
+            PathMap.Element element = get(id);
+            if (element != null) {
+                return element.getDepth();
+            }
+        }
+        return super.getDepth(id);
+    }
+
+    //----------------------------------------------------< ItemStateListener >
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stateCreated(ItemState created) {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stateModified(ItemState modified) {
+        stateModified((NodeState) modified);
+    }
+
+    /**
+     * Evict moved or renamed items from the cache.
+     */
+    private void stateModified(NodeState modified) {
+        synchronized (cacheMonitor) {
+            LRUEntry entry = (LRUEntry) idCache.get(modified.getNodeId());
+            if (entry == null) {
+                // Item not cached, ignore
+                return;
+            }
+
+            PathMap.Element element = entry.getElement();
+
+            Iterator iter = element.getChildren();
+            while (iter.hasNext()) {
+                PathMap.Element child = (PathMap.Element) iter.next();
+                NodeState.ChildNodeEntry cne = modified.getChildNodeEntry(
+                        child.getName(), child.getNormalizedIndex());
+                if (cne == null) {
+                    // Item does not exist, remove
+                    child.remove();
+                    evict(child);
+                    return;
+                }
+
+                LRUEntry childEntry = (LRUEntry) child.get();
+                if (childEntry != null && !cne.getId().equals(childEntry.getId())) {
+                    // Different child item, remove
+                    child.remove();
+                    evict(child);
+                }
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stateDestroyed(ItemState destroyed) {
+        destroyed.removeListener(this);
+        evict(destroyed.getId());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stateDiscarded(ItemState discarded) {
+        discarded.removeListener(this);
+        evict(discarded.getId());
+    }
+
+    /**
+     * Called when an <code>ItemState</code> has been overlaid by some
+     * other state that now takes its identity. This notification is sent
+     * on the state being overlaid.
+     *
+     * @param overlayer the <code>ItemState</code> that overlays this state
+     */
+    public void stateOverlaid(ItemState overlayer) {
+        if (overlayer.isNode()) {
+            overlayer.getOverlayedState().removeListener(this);
+            overlayer.addListener(this);
+        }
+    }
+
+    /**
+     * Called when an <code>ItemState</code> is about to no longer overlay some
+     * other item state. This notification is sent on the state overlaying
+     * another state.
+     *
+     * @param overlayer the <code>ItemState</code> that overlaid another item
+     *                  state. To get the overlaid state, invoke {@link
+     *                  ItemState#getOverlayedState()}
+     */
+    // DIFF JACKRABBIT: renamed from stateUncovered to stateUncovering
+    public void stateUncovering(ItemState overlayer) {
+        if (overlayer.isNode()) {
+            overlayer.removeListener(this);
+            overlayer.getOverlayedState().addListener(this);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void nodeAdded(NodeState state, QName name, int index, NodeId id) {
+        try {
+            Path path = Path.create(getQPath(state.getNodeId()), name, index, true);
+            insert(path, id);
+        } catch (PathNotFoundException e) {
+            log.warn("Unable to get path of node " + state.getNodeId() +
+                    ", event ignored.");
+        } catch (ItemNotFoundException e) {
+            log.warn("Unable to get path of " + state.getNodeId(), e);
+        } catch (RepositoryException e) {
+            log.warn("Unable to get path of " + state.getNodeId(), e);
+        } catch (MalformedPathException e) {
+            log.warn("Unable to get path of " + state.getNodeId(), e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p/>
+     * Generate subsequent add and remove notifications for every replacement.
+     */
+    public void nodesReplaced(NodeState state) {
+        List entries = state.getReorderedChildNodeEntries();
+        if (entries.size() == 0) {
+            return;
+        }
+
+        Iterator iter = entries.iterator();
+        while (iter.hasNext()) {
+            NodeState.ChildNodeEntry now = (NodeState.ChildNodeEntry) iter.next();
+            NodeState.ChildNodeEntry old =
+                    ((NodeState) state.getOverlayedState()).getChildNodeEntry(now.getId());
+
+            if (old == null) {
+                log.warn("Reordered child node not found in old list.");
+                continue;
+            }
+
+            nodeAdded(state, now.getName(), now.getIndex(), now.getId());
+            nodeRemoved(state, old.getName(), old.getIndex(), old.getId());
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void nodeRemoved(NodeState state, QName name, int index, NodeId id) {
+        try {
+            Path path = Path.create(getQPath(state.getId()), name, index, true);
+            remove(path, id);
+        } catch (PathNotFoundException e) {
+            log.warn("Unable to get path of node " + state.getNodeId() +
+                    ", event ignored.");
+        } catch (ItemNotFoundException e) {
+            log.warn("Unable to get path of " + state.getNodeId(), e);
+        } catch (RepositoryException e) {
+            log.warn("Unable to get path of " + state.getNodeId(), e);
+        } catch (MalformedPathException e) {
+            log.warn("Unable to get path of " + state.getNodeId(), e);
+        }
+    }
+
+    //------------------------------------------------------< private methods >
+
+    /**
+     * Return a cached element in the path map, given its id
+     *
+     * @param id node id
+     * @return cached element, <code>null</code> if not found
+     */
+    private PathMap.Element get(ItemId id) {
+        synchronized (cacheMonitor) {
+            LRUEntry entry = (LRUEntry) idCache.get(id);
+            if (entry != null) {
+                entry.touch();
+                return entry.getElement();
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Return the nearest cached element in the path map, given a path.
+     * The returned element is guaranteed to have an associated object that
+     * is not <code>null</code>.
+     *
+     * @param path path
+     * @return cached element, <code>null</code> if not found
+     */
+    private PathMap.Element map(Path path) {
+        synchronized (cacheMonitor) {
+            PathMap.Element element = pathCache.map(path, false);
+            while (element != null) {
+                LRUEntry entry = (LRUEntry) element.get();
+                if (entry != null) {
+                    entry.touch();
+                    return element;
+                }
+                element = element.getParent();
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Cache an item in the hierarchy given its id and path. Adds a listener
+     * for this item state to get notified about changes.
+     *
+     * @param state node state
+     * @param path  path to item
+     */
+    private void cache(NodeState state, Path path) {
+        NodeId id = state.getNodeId();
+
+        synchronized (cacheMonitor) {
+            if (idCache.get(id) != null) {
+                return;
+            }
+            if (idCache.size() >= upperLimit) {
+                removeLRU();
+            }
+
+            PathMap.Element element = pathCache.put(path);
+            LRUEntry entry = new LRUEntry(id, element);
+            element.set(entry);
+            idCache.put(id, entry);
+
+            state.addListener(this);
+        }
+    }
+
+    /**
+     * Remove least recently used item. Scans the LRU list from head to tail
+     * and removes the first item that has no children.
+     */
+    private void removeLRU() {
+        synchronized (cacheMonitor) {
+            LRUEntry entry = head;
+            while (entry != null) {
+                PathMap.Element element = entry.getElement();
+                if (element.getChildrenCount() == 0) {
+                    evict(entry, true);
+                    return;
+                }
+                entry = entry.getNext();
+            }
+        }
+    }
+
+    /**
+     * Return a flag indicating whether a certain element is cached.
+     *
+     * @param id item id
+     * @return <code>true</code> if the item is already cached;
+     *         <code>false</code> otherwise
+     */
+    private boolean isCached(ItemId id) {
+        synchronized (cacheMonitor) {
+            return idCache.get(id) != null;
+        }
+    }
+
+    /**
+     * Evict item from cache. Evicts the associated <code>LRUEntry</code>
+     *
+     * @param id item id
+     */
+    private void evict(ItemId id) {
+        synchronized (cacheMonitor) {
+            LRUEntry entry = (LRUEntry) idCache.get(id);
+            if (entry != null) {
+                evict(entry, true);
+            }
+        }
+    }
+
+    /**
+     * Evict item from cache
+     *
+     * @param entry               LRU entry
+     * @param removeFromPathCache whether to remove from path cache
+     */
+    private void evict(LRUEntry entry, boolean removeFromPathCache) {
+        synchronized (cacheMonitor) {
+            if (removeFromPathCache) {
+                PathMap.Element element = entry.getElement();
+                evict(element);
+                element.remove();
+            } else {
+                idCache.remove(entry.getId());
+                entry.remove();
+            }
+        }
+    }
+
+    /**
+     * Evict path map element from cache. This will traverse all children
+     * of this element and evict the objects associated with them
+     *
+     * @param element path map element
+     */
+    private void evict(PathMap.Element element) {
+        synchronized (cacheMonitor) {
+            element.traverse(new PathMap.ElementVisitor() {
+                public void elementVisited(PathMap.Element element) {
+                    evict((LRUEntry) element.get(), false);
+                }
+            }, false);
+        }
+    }
+
+    /**
+     * Insert a node into the cache. This will automatically shift
+     * all indexes of sibling nodes having index greater or equal.
+     *
+     * @param path child path
+     * @param id   node id
+     */
+    private void insert(Path path, ItemId id) throws PathNotFoundException {
+        synchronized (cacheMonitor) {
+            PathMap.Element element = null;
+
+            LRUEntry entry = (LRUEntry) idCache.get(id);
+            if (entry != null) {
+                element = entry.getElement();
+                element.remove();
+            }
+
+            PathMap.Element parent = pathCache.map(path.getAncestor(1), true);
+            if (parent != null) {
+                parent.insert(path.getNameElement());
+            }
+            if (element != null) {
+                pathCache.put(path, element);
+
+                /* Remember this as a move */
+                movedIds.add(id);
+            }
+        }
+    }
+
+    /**
+     * Remove an item from the cache in order to shift the indexes
+     * of items following this item.
+     *
+     * @param path child path
+     * @param id   node id
+     */
+    private void remove(Path path, ItemId id) throws PathNotFoundException {
+        synchronized (cacheMonitor) {
+            /* If we remembered this as a move, ignore this event */
+            if (movedIds.remove(id)) {
+                return;
+            }
+            PathMap.Element parent = pathCache.map(path.getAncestor(1), true);
+            if (parent != null) {
+                PathMap.Element element = parent.remove(path.getNameElement());
+                if (element != null) {
+                    evict(element);
+                }
+            }
+        }
+    }
+
+    /**
+     * Entry in the LRU list
+     */
+    private class LRUEntry {
+
+        /**
+         * Previous entry
+         */
+        private LRUEntry previous;
+
+        /**
+         * Next entry
+         */
+        private LRUEntry next;
+
+        /**
+         * Node id
+         */
+        private final NodeId id;
+
+        /**
+         * Element in path map
+         */
+        private final PathMap.Element element;
+
+        /**
+         * Create a new instance of this class
+         *
+         * @param id node id
+         */
+        public LRUEntry(NodeId id, PathMap.Element element) {
+            this.id = id;
+            this.element = element;
+
+            append();
+        }
+
+        /**
+         * Append entry to end of LRU list
+         */
+        public void append() {
+            if (tail == null) {
+                head = tail = this;
+            } else {
+                previous = tail;
+                tail.next = this;
+                tail = this;
+            }
+        }
+
+        /**
+         * Remove entry from LRU list
+         */
+        public void remove() {
+            if (previous != null) {
+                previous.next = next;
+            }
+            if (next != null) {
+                next.previous = previous;
+            }
+            if (head == this) {
+                head = next;
+            }
+            if (tail == this) {
+                tail = previous;
+            }
+            previous = next = null;
+        }
+
+        /**
+         * Touch entry. Removes it from its current position in the LRU list
+         * and moves it to the end.
+         */
+        public void touch() {
+            remove();
+            append();
+        }
+
+        /**
+         * Return previous LRU entry
+         *
+         * @return previous LRU entry
+         */
+        public LRUEntry getPrevious() {
+            return previous;
+        }
+
+        /**
+         * Return next LRU entry
+         *
+         * @return next LRU entry
+         */
+        public LRUEntry getNext() {
+            return next;
+        }
+
+        /**
+         * Return node ID
+         *
+         * @return node ID
+         */
+        public NodeId getId() {
+            return id;
+        }
+
+        /**
+         * Return element in path map
+         *
+         * @return element in path map
+         */
+        public PathMap.Element getElement() {
+            return element;
+        }
+    }
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/CachingHierarchyManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/CachingHierarchyManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/DefaultIdKeyMap.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/DefaultIdKeyMap.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/DefaultIdKeyMap.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/DefaultIdKeyMap.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,72 @@
+/*
+ * 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.jcr2spi;
+
+import org.apache.jackrabbit.spi.ItemId;
+
+import java.util.Set;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.ArrayList;
+
+/**
+ * <code>DefaultIdKeyMap</code>
+ */
+public class DefaultIdKeyMap implements IdKeyMap {
+
+    // TODO: use mixture of Path map and lookup by UUID
+    // TODO: add possibility to limit size of map
+
+    public boolean containsKey(ItemId id) {
+        // TODO
+        return false;
+    }
+
+    public Object get(ItemId id) {
+        // TODO
+        return null;
+    }
+
+    public Object put(ItemId id, Object value) {
+        // TODO
+        return null;
+    }
+
+    public Object remove(ItemId id) {
+        // TODO
+        return null;
+    }
+
+    public Set keySet() {
+        // TODO
+        return new HashSet(0);
+    }
+
+    public Collection values() {
+        // TODO
+        return new ArrayList(0);
+    }
+
+    public int size() {
+        // TODO
+        return 0;
+    }
+
+    public void clear() {
+        // TODO
+    }
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/DefaultIdKeyMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/DefaultIdKeyMap.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/HierarchyManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/HierarchyManager.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/HierarchyManager.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/HierarchyManager.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,123 @@
+/*
+ * 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.jcr2spi;
+
+import org.apache.jackrabbit.name.Path;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.spi.ItemId;
+import org.apache.jackrabbit.spi.NodeId;
+
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+import javax.jcr.Item;
+
+/**
+ * The <code>HierarchyManager</code> interface ...
+ */
+public interface HierarchyManager {
+
+    /**
+     * Returns the id of the given <code>Item</code>.
+     *
+     * @param item
+     * @return
+     * @throws PathNotFoundException
+     * @throws RepositoryException
+     */
+    ItemId getItemId(Item item) throws PathNotFoundException, RepositoryException;
+
+    // DIFF JR: renamed from 'resolveQPath'
+    /**
+     * Resolves a path into an item id.
+     *
+     * @param qPath
+     * @return
+     * @throws PathNotFoundException
+     * @throws RepositoryException
+     */
+    ItemId getItemId(Path qPath) throws PathNotFoundException, RepositoryException;
+
+    /**
+     * Returns the path to the given item.
+     *
+     * @param id
+     * @return
+     * @throws ItemNotFoundException
+     * @throws RepositoryException
+     */
+    Path getQPath(ItemId id) throws ItemNotFoundException, RepositoryException;
+
+    /**
+     * Returns the name of the specified item.
+     *
+     * @param id id of item whose name should be returned
+     * @return
+     * @throws ItemNotFoundException
+     * @throws RepositoryException
+     */
+    QName getQName(ItemId id) throws ItemNotFoundException, RepositoryException;
+
+    /**
+     * Returns the depth of the specified item which is equivalent to
+     * <code>getQPath(id).getAncestorCount()</code>. The depth reflects the
+     * absolute hierarchy level.
+     *
+     * @param id item id
+     * @return the depth of the specified item
+     * @throws ItemNotFoundException if the specified <code>id</code> does not
+     *                               denote an existing item.
+     * @throws RepositoryException   if another error occurs
+     */
+    int getDepth(ItemId id) throws ItemNotFoundException, RepositoryException;
+
+    /**
+     * Returns the depth of the specified descendant relative to the given
+     * ancestor. If <code>ancestorId</code> and <code>descendantId</code>
+     * denote the same item 0 is returned. If <code>ancestorId</code> does not
+     * denote an ancestor -1 is returned.
+     *
+     * @param ancestorId ancestor id
+     * @param descendantId descendant id
+     * @return the relative depth; -1 if <code>ancestorId</code> does not
+     *         denote an ancestor of the item denoted by <code>descendantId</code>
+     *         (or itself).
+     * @throws ItemNotFoundException if either of the specified id's does not
+     *                               denote an existing item.
+     * @throws RepositoryException   if another error occurs
+     */
+    int getRelativeDepth(NodeId ancestorId, ItemId descendantId)
+            throws ItemNotFoundException, RepositoryException;
+
+     /**
+     * Failsafe conversion of an <code>ItemId</code> to JCR path for use in
+     * error messages etc.
+     *
+     * @param itemId id to convert
+     * @return JCR path
+     */
+    String safeGetJCRPath(ItemId itemId);
+
+     /**
+     * Failsafe conversion of internal <code>Path</code> to JCR path for use in
+     * error messages etc.
+     *
+     * @param qPath path to convert
+     * @return JCR path
+     */
+    String safeGetJCRPath(Path qPath);
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/HierarchyManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/HierarchyManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/HierarchyManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/HierarchyManagerImpl.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/HierarchyManagerImpl.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/HierarchyManagerImpl.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,476 @@
+/*
+ * 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.jcr2spi;
+
+import org.apache.jackrabbit.jcr2spi.state.ItemState;
+import org.apache.jackrabbit.jcr2spi.state.ItemStateException;
+import org.apache.jackrabbit.jcr2spi.state.ItemStateManager;
+import org.apache.jackrabbit.jcr2spi.state.NoSuchItemStateException;
+import org.apache.jackrabbit.jcr2spi.state.NodeState;
+import org.apache.jackrabbit.jcr2spi.state.PropertyState;
+import org.apache.jackrabbit.name.NamespaceResolver;
+import org.apache.jackrabbit.name.NoPrefixDeclaredException;
+import org.apache.jackrabbit.spi.NodeId;
+import org.apache.jackrabbit.spi.ItemId;
+import org.apache.jackrabbit.spi.PropertyId;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.name.Path;
+import org.apache.jackrabbit.name.MalformedPathException;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+import javax.jcr.Item;
+
+/**
+ * <code>HierarchyManagerImpl</code> ...
+ */
+public class HierarchyManagerImpl implements HierarchyManager {
+
+    private static Logger log = LoggerFactory.getLogger(HierarchyManagerImpl.class);
+
+    // DIFF JR: QName.ROOT replaces the EMPTY_NAME QName defined in JR....
+
+    // TODO: TO-BE-FIXED. With SPI_ItemId rootId must not be stored separately    
+    protected final NodeId rootNodeId;
+    protected final ItemStateManager itemStateManager;
+    // used for outputting user-friendly paths and names
+    protected final NamespaceResolver nsResolver;
+
+    public HierarchyManagerImpl(NodeId rootNodeId,
+                                ItemStateManager itemStateManager,
+                                NamespaceResolver nsResolver) {
+        this.rootNodeId = rootNodeId;
+        this.itemStateManager = itemStateManager;
+        this.nsResolver = nsResolver;
+    }
+
+    public NodeId getRootNodeId() {
+        return rootNodeId;
+    }
+
+    public NamespaceResolver getNamespaceResolver() {
+        return nsResolver;
+    }
+
+    //---------------------------------------------------------< overridables >
+    /**
+     * Return an item state, given its item id.
+     * <p/>
+     * Low-level hook provided for specialized derived classes.
+     *
+     * @param id item id
+     * @return item state
+     * @throws NoSuchItemStateException if the item does not exist
+     * @throws ItemStateException       if an error occurs
+     * @see ZombieHierarchyManager#getItemState(ItemId)
+     */
+    protected ItemState getItemState(ItemId id)
+            throws NoSuchItemStateException, ItemStateException {
+        return itemStateManager.getItemState(id);
+    }
+
+    /**
+     * Determines whether an item state for a given item id exists.
+     * <p/>
+     * Low-level hook provided for specialized derived classes.
+     *
+     * @param id item id
+     * @return <code>true</code> if an item state exists, otherwise
+     *         <code>false</code>
+     * @see ZombieHierarchyManager#hasItemState(ItemId)
+     */
+    protected boolean hasItemState(ItemId id) {
+        return itemStateManager.hasItemState(id);
+    }
+
+    /**
+     * Returns the <code>parentUUID</code> of the given item.
+     * <p/>
+     * Low-level hook provided for specialized derived classes.
+     *
+     * @param state item state
+     * @return parent <code>NodeId</code> of the given item state
+     * @see ZombieHierarchyManager#getParentId(ItemState)
+     */
+    protected NodeId getParentId(ItemState state) {
+        return state.getParentId();
+    }
+
+    /**
+     * Returns the <code>ChildNodeEntry</code> of <code>parent</code> with the
+     * specified <code>uuid</code> or <code>null</code> if there's no such entry.
+     * <p/>
+     * Low-level hook provided for specialized derived classes.
+     *
+     * @param parent node state
+     * @param id   id of child node entry
+     * @return the <code>ChildNodeEntry</code> of <code>parent</code> with
+     *         the specified <code>uuid</code> or <code>null</code> if there's
+     *         no such entry.
+     * @see ZombieHierarchyManager#getChildNodeEntry(NodeState, NodeId)
+     */
+    protected NodeState.ChildNodeEntry getChildNodeEntry(NodeState parent,
+                                                         NodeId id) {
+        return parent.getChildNodeEntry(id);
+    }
+
+    /**
+     * Returns the <code>ChildNodeEntry</code> of <code>parent</code> with the
+     * specified <code>name</code> and <code>index</code> or <code>null</code>
+     * if there's no such entry.
+     * <p/>
+     * Low-level hook provided for specialized derived classes.
+     *
+     * @param parent node state
+     * @param name   name of child node entry
+     * @param index  index of child node entry
+     * @return the <code>ChildNodeEntry</code> of <code>parent</code> with
+     *         the specified <code>name</code> and <code>index</code> or
+     *         <code>null</code> if there's no such entry.
+     * @see ZombieHierarchyManager#getChildNodeEntry(NodeState, QName, int)
+     */
+    protected NodeState.ChildNodeEntry getChildNodeEntry(NodeState parent,
+                                                         QName name,
+                                                         int index) {
+        return parent.getChildNodeEntry(name, index);
+    }
+
+    /**
+     * Resolve a path into an item id. Recursively invoked method that may be
+     * overridden by some subclass to either return cached responses or add
+     * response to cache.
+     *
+     * @param path full path of item to resolve
+     * @param id   intermediate item id
+     * @param next next path element index to resolve
+     * @return the id of the item denoted by <code>path</code>
+     */
+    protected ItemId resolvePath(Path path, ItemId id, int next)
+            throws RepositoryException {
+
+        try {
+            return resolvePath(path, getItemState(id), next);
+        } catch (NoSuchItemStateException e) {
+            String msg = "failed to retrieve state of intermediary node";
+            log.debug(msg);
+            throw new RepositoryException(msg, e);
+        } catch (ItemStateException e) {
+            String msg = "failed to retrieve state of intermediary node";
+            log.debug(msg);
+            throw new RepositoryException(msg, e);
+        }
+    }
+
+    /**
+     * Resolve a path into an item id. Recursively invoked method that may be
+     * overridden by some subclass to either return cached responses or add
+     * response to cache.
+     *
+     * @param path  full path of item to resolve
+     * @param state intermediate state
+     * @param next  next path element index to resolve
+     * @return the id of the item denoted by <code>path</code>
+     */
+    protected ItemId resolvePath(Path path, ItemState state, int next)
+            throws PathNotFoundException, ItemStateException {
+
+        Path.PathElement[] elements = path.getElements();
+        if (elements.length == next) {
+            return state.getId();
+        }
+        Path.PathElement elem = elements[next];
+
+        QName name = elem.getName();
+        int index = elem.getNormalizedIndex();
+
+        NodeState parentState = (NodeState) state;
+        ItemId childId;
+
+        if (parentState.hasChildNodeEntry(name, index)) {
+            // child node
+            NodeState.ChildNodeEntry nodeEntry = getChildNodeEntry(parentState, name, index);
+            childId = nodeEntry.getId();
+        } else if (parentState.hasPropertyName(name)) {
+            // property
+            if (index > org.apache.jackrabbit.name.Path.INDEX_DEFAULT) {
+                // properties can't have same name siblings
+                throw new PathNotFoundException(safeGetJCRPath(path));
+            } else if (next < elements.length - 1) {
+                // property is not the last element in the path
+                throw new PathNotFoundException(safeGetJCRPath(path));
+            }
+            childId = parentState.getPropertyId(name);
+        } else {
+            // no such item
+            throw new PathNotFoundException(safeGetJCRPath(path));
+        }
+        return resolvePath(path, getItemState(childId), next + 1);
+    }
+
+    /**
+     * Adds the path element of an item id to the path currently being built.
+     * Recursively invoked method that may be overridden by some subclass to
+     * either return cached responses or add response to cache. On exit,
+     * <code>builder</code> contains the path of <code>state</code>.
+     *
+     * @param builder builder currently being used
+     * @param state   item to find path of
+     */
+    protected void buildPath(Path.PathBuilder builder, ItemState state)
+            throws ItemStateException, RepositoryException {
+
+        // shortcut
+        if (state.getId().equals(rootNodeId)) {
+            builder.addRoot();
+            return;
+        }
+
+        NodeId parentId = state.getParentId();
+        if (parentId == null) {
+            String msg = "failed to build path of " + state.getId()
+                    + ": orphaned item";
+            log.debug(msg);
+            throw new ItemNotFoundException(msg);
+        }
+
+        NodeState parent = (NodeState) getItemState(parentId);
+        // recursively build path of parent
+        buildPath(builder, parent);
+
+        if (state.isNode()) {
+            NodeState nodeState = (NodeState) state;
+            NodeId id = nodeState.getNodeId();
+            NodeState.ChildNodeEntry entry = getChildNodeEntry(parent, id);
+            if (entry == null) {
+                String msg = "failed to build path of " + state.getId() + ": "
+                        + parent.getNodeId() + " has no child entry for "
+                        + id;
+                log.debug(msg);
+                throw new ItemNotFoundException(msg);
+            }
+            // add to path
+            if (entry.getIndex() == org.apache.jackrabbit.name.Path.INDEX_DEFAULT) {
+                builder.addLast(entry.getName());
+            } else {
+                builder.addLast(entry.getName(), entry.getIndex());
+            }
+        } else {
+            PropertyState propState = (PropertyState) state;
+            QName name = propState.getName();
+            // add to path
+            builder.addLast(name);
+        }
+    }
+
+    //-----------------------------------------------------< HierarchyManager >
+    /**
+     * {@inheritDoc}
+     */
+    public ItemId getItemId(Item item) throws PathNotFoundException, RepositoryException {
+        if (item instanceof ItemImpl) {
+            return ((ItemImpl)item).getId();
+        } else {
+            try {
+                return getItemId(nsResolver.getQPath(item.getPath()));
+            } catch (MalformedPathException e) {
+                // should not occur.
+                throw new RepositoryException(e);
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ItemId getItemId(Path qPath)
+            throws PathNotFoundException, RepositoryException {
+        // shortcut
+        if (qPath.denotesRoot()) {
+            return rootNodeId;
+        }
+
+        if (!qPath.isCanonical()) {
+            String msg = "path is not canonical";
+            log.debug(msg);
+            throw new RepositoryException(msg);
+        }
+
+        return resolvePath(qPath, rootNodeId, 1);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Path getQPath(ItemId id)
+            throws ItemNotFoundException, RepositoryException {
+        // shortcut
+        if (id.equals(rootNodeId)) {
+            return Path.ROOT;
+        }
+
+        Path.PathBuilder builder = new Path.PathBuilder();
+
+        try {
+            buildPath(builder, getItemState(id));
+            return builder.getPath();
+        } catch (NoSuchItemStateException nsise) {
+            String msg = "failed to build path of " + id;
+            log.debug(msg);
+            throw new ItemNotFoundException(msg, nsise);
+        } catch (ItemStateException ise) {
+            String msg = "failed to build path of " + id;
+            log.debug(msg);
+            throw new RepositoryException(msg, ise);
+        } catch (MalformedPathException e) {
+            String msg = "failed to build path of " + id;
+            throw new RepositoryException(msg, e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public QName getQName(ItemId itemId)
+            throws ItemNotFoundException, RepositoryException {
+        if (itemId.denotesNode()) {
+            NodeId nodeId = (NodeId) itemId;
+            NodeState parentState;
+            try {
+                NodeState nodeState = (NodeState) getItemState(nodeId);
+                NodeId parentId= getParentId(nodeState);
+                if (parentId == null) {
+                    // this is the root or an orphaned node
+                    return QName.ROOT;
+                }
+                parentState = (NodeState) getItemState(parentId);
+            } catch (NoSuchItemStateException nsis) {
+                String msg = "failed to resolve name of " + nodeId;
+                log.debug(msg);
+                throw new ItemNotFoundException(nodeId.toString());
+            } catch (ItemStateException ise) {
+                String msg = "failed to resolve name of " + nodeId;
+                log.debug(msg);
+                throw new RepositoryException(msg, ise);
+            }
+
+            NodeState.ChildNodeEntry entry =
+                    getChildNodeEntry(parentState, nodeId);
+            if (entry == null) {
+                String msg = "failed to resolve name of " + nodeId;
+                log.debug(msg);
+                throw new RepositoryException(msg);
+            }
+            return entry.getName();
+        } else {
+            return ((PropertyId) itemId).getQName();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getDepth(ItemId id)
+            throws ItemNotFoundException, RepositoryException {
+        int depth = org.apache.jackrabbit.name.Path.ROOT_DEPTH;
+        // shortcut
+        if (id.equals(rootNodeId)) {
+            return depth;
+        }
+        try {
+            ItemState state = getItemState(id);
+            NodeId parentId = getParentId(state);
+            while (parentId != null) {
+                depth++;
+                state = getItemState(parentId);
+                parentId = getParentId(state);
+            }
+            return depth;
+        } catch (NoSuchItemStateException nsise) {
+            String msg = "failed to determine depth of " + id;
+            log.debug(msg);
+            throw new ItemNotFoundException(msg, nsise);
+        } catch (ItemStateException ise) {
+            String msg = "failed to determine depth of " + id;
+            log.debug(msg);
+            throw new RepositoryException(msg, ise);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getRelativeDepth(NodeId ancestorId, ItemId descendantId)
+            throws ItemNotFoundException, RepositoryException {
+        if (ancestorId.equals(descendantId)) {
+            return 0;
+        }
+        int depth = 1;
+        try {
+            ItemState state = getItemState(descendantId);
+            NodeId parentId = getParentId(state);
+            while (parentId != null) {
+                if (parentId.equals(ancestorId)) {
+                    return depth;
+                }
+                depth++;
+                state = getItemState(parentId);
+                parentId = getParentId(state);
+            }
+            // not an ancestor
+            return -1;
+        } catch (NoSuchItemStateException nsise) {
+            String msg = "failed to determine depth of " + descendantId
+                    + " relative to " + ancestorId;
+            log.debug(msg);
+            throw new ItemNotFoundException(msg, nsise);
+        } catch (ItemStateException ise) {
+            String msg = "failed to determine depth of " + descendantId
+                    + " relative to " + ancestorId;
+            log.debug(msg);
+            throw new RepositoryException(msg, ise);
+        }
+    }
+
+    /**
+     * @see HierarchyManager#safeGetJCRPath(ItemId)
+     */
+    public String safeGetJCRPath(ItemId itemId) {
+        try {
+            return safeGetJCRPath(getQPath(itemId));
+        } catch (RepositoryException e) {
+            log.error("failed to convert " + itemId + " to JCR path.");
+            return itemId.toString();
+        }
+    }
+
+    /**
+     * @see HierarchyManager#safeGetJCRPath(Path)
+     */
+    public String safeGetJCRPath(Path qPath) {
+        try {
+            return nsResolver.getJCRPath(qPath);
+        } catch (NoPrefixDeclaredException npde) {
+            log.error("failed to convert " + qPath + " to JCR path.");
+            // return string representation of internal path as a fallback
+            return qPath.toString();
+        }
+    }
+}
+

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/HierarchyManagerImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/HierarchyManagerImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/IdKeyMap.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/IdKeyMap.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/IdKeyMap.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/IdKeyMap.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,44 @@
+/*
+ * 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.jcr2spi;
+
+import org.apache.jackrabbit.spi.ItemId;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * <code>IdKeyMap</code>
+ */
+public interface IdKeyMap {
+
+    public boolean containsKey(ItemId id);
+
+    public Object get(ItemId id);
+
+    public Object put(ItemId id, Object value);
+
+    public Object remove(ItemId id);
+
+    public Set keySet();
+
+    public Collection values();
+
+    public int size();
+
+    public void clear();
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/IdKeyMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/IdKeyMap.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemImpl.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemImpl.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemImpl.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,635 @@
+/*
+ * 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.jcr2spi;
+
+import org.apache.commons.collections.map.ReferenceMap;
+import org.apache.jackrabbit.jcr2spi.state.ItemState;
+import org.apache.jackrabbit.jcr2spi.state.SessionItemStateManager;
+import org.apache.jackrabbit.jcr2spi.state.TransientItemStateListener;
+import org.apache.jackrabbit.jcr2spi.state.ItemStateException;
+import org.apache.jackrabbit.jcr2spi.state.StaleItemStateException;
+import org.apache.jackrabbit.jcr2spi.state.ItemStateValidator;
+import org.apache.jackrabbit.jcr2spi.state.NodeState;
+import org.apache.jackrabbit.jcr2spi.state.PropertyState;
+import org.apache.jackrabbit.jcr2spi.operation.Remove;
+import org.apache.jackrabbit.jcr2spi.operation.Operation;
+import org.apache.jackrabbit.name.NoPrefixDeclaredException;
+import org.apache.jackrabbit.name.Path;
+import org.apache.jackrabbit.spi.QPropertyDefinition;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.spi.ItemId;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jcr.lock.LockException;
+import javax.jcr.version.VersionException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.RepositoryException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.AccessDeniedException;
+import javax.jcr.Item;
+import javax.jcr.ItemVisitor;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.ReferentialIntegrityException;
+import javax.jcr.Repository;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Node;
+import javax.jcr.Session;
+
+import java.util.Map;
+import java.util.Collections;
+
+/**
+ * <code>ItemImpl</code>...
+ */
+public abstract class ItemImpl implements Item, TransientItemStateListener {
+
+    private static Logger log = LoggerFactory.getLogger(ItemImpl.class);
+
+    protected static final int STATUS_NORMAL = 0;
+    protected static final int STATUS_MODIFIED = 1;
+    protected static final int STATUS_DESTROYED = 2;
+    protected static final int STATUS_INVALIDATED = 3;
+
+    private ItemId id;
+
+    private int status;
+    private ItemState state;
+
+    protected SessionItemStateManager itemStateMgr;
+    protected ItemManager itemMgr;
+    protected SessionImpl session;
+
+    /**
+     * Listeners (weak references)
+     */
+    protected final Map listeners = Collections.synchronizedMap(new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK));
+
+    public ItemImpl(ItemManager itemManager, SessionImpl session, ItemState state,
+                    ItemLifeCycleListener[] listeners) {
+        this.session = session;
+        //DIFF JACKRABBIT: rep = (RepositoryImpl) session.getRepository();
+        //DIFF JACKRABBIT: stateMgr = session.getSessionItemStateManager();
+        itemStateMgr = session.getSessionItemStateManager();
+        this.id = state.getId();
+        this.itemMgr = itemManager;
+        this.state = state;
+        status = STATUS_NORMAL;
+
+        if (listeners != null) {
+            for (int i = 0; i < listeners.length; i++) {
+                addLifeCycleListener(listeners[i]);
+            }
+        }
+        notifyCreated();
+
+        // add this item as listener to events of the underlying state object
+        this.state.addListener(this);
+    }
+
+    //-----------------------------------------------------< Item interface >---
+    /**
+     * @see javax.jcr.Item#getPath()
+     */
+    public String getPath() throws RepositoryException {
+        checkStatus();
+        try {
+            // DIFF JR: use nsResolver
+            return session.getNamespaceResolver().getJCRPath(getQPath());
+        } catch (NoPrefixDeclaredException npde) {
+            // should never get here...
+            String msg = "Internal error: encountered unregistered namespace";
+            log.debug(msg);
+            throw new RepositoryException(msg, npde);
+        }
+    }
+
+    /**
+     * @see javax.jcr.Item#getName()
+     */
+    public abstract String getName() throws RepositoryException;
+
+    /**
+     * @see javax.jcr.Item#getAncestor(int)
+     */
+    public Item getAncestor(int depth) throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+        checkStatus();
+        if (depth == 0) {
+            return session.getRootNode();
+        }
+        try {
+            // Path.getAncestor requires relative degree, i.e. we need
+            // to convert absolute to relative ancestor degree
+            Path path = getQPath();
+            int relDegree = path.getAncestorCount() - depth;
+            if (relDegree < 0) {
+                throw new ItemNotFoundException();
+            }
+            Path ancestorPath = path.getAncestor(relDegree);
+            return itemMgr.getItem(ancestorPath);
+        } catch (PathNotFoundException pnfe) {
+            throw new ItemNotFoundException();
+        }
+    }
+
+    /**
+     * @see javax.jcr.Item#getParent()
+     */
+    public abstract Node getParent() throws ItemNotFoundException, AccessDeniedException, RepositoryException;
+
+    /**
+     * @see javax.jcr.Item#getDepth()
+     */
+    public int getDepth() throws RepositoryException {
+        checkStatus();
+        if (state.getParentId() == null) {
+            // shortcut
+            return Path.ROOT_DEPTH;
+        }
+        return session.getHierarchyManager().getDepth(id);
+    }
+
+    /**
+     * @see javax.jcr.Item#getSession()
+     */
+    public Session getSession() throws RepositoryException {
+        checkStatus();
+        return session;
+    }
+
+    /**
+     * @see javax.jcr.Item#isNew()
+     */
+    public boolean isNew() {
+        // short-cut: read-only implementations always return false.
+        if (!isSupportedOption(Repository.LEVEL_2_SUPPORTED)) {
+            return false;
+        }
+        return state.isTransient() && state.getOverlayedState() == null;
+    }
+
+    /**
+     * @see javax.jcr.Item#isModified()
+     */
+    public boolean isModified() {
+        // short-cut: read-only implementations always return false.
+        if (!isSupportedOption(Repository.LEVEL_2_SUPPORTED)) {
+            return false;
+        }
+        return state.isTransient() && state.getOverlayedState() != null;
+    }
+
+    /**
+     * @see javax.jcr.Item#isSame(Item)
+     */
+    public boolean isSame(Item otherItem) {
+        if (this == otherItem) {
+            return true;
+        }
+        if (otherItem instanceof ItemImpl) {
+            ItemImpl other = (ItemImpl) otherItem;
+            // 2 items may only be the same if the were accessed from Sessions
+            // bound to the same workspace
+            String otherWspName = other.session.getWorkspace().getName();
+            if (session.getWorkspace().getName().equals(otherWspName)) {
+                // in addition they must provide the same id irrespective of
+                // any transient modifications.
+                // TODO: TO_BE_FIXED check if this is sufficient check (SPI-id)
+                ItemId thisId = (state.hasOverlayedState()) ? state.getOverlayedState().getId() : state.getId();
+                ItemId otherId = (other.getItemState().hasOverlayedState()) ? other.getItemState().getOverlayedState().getId() : other.getId();
+                return thisId.equals(otherId);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @see javax.jcr.Item#accept(ItemVisitor)
+     */
+    public abstract void accept(ItemVisitor visitor) throws RepositoryException;
+
+    /**
+     * @see javax.jcr.Item#isNode()
+     */
+    public abstract boolean isNode();
+
+    /**
+     * @see javax.jcr.Item#save()
+     */
+    public void save() throws AccessDeniedException, ConstraintViolationException, InvalidItemStateException, ReferentialIntegrityException, VersionException, LockException, RepositoryException {
+        // check state of this instance
+        checkStatus();
+        try {
+            itemStateMgr.save(getItemState());
+        } catch (StaleItemStateException e) {
+            throw new InvalidItemStateException(e);
+        } catch (ItemStateException e) {
+            String msg = "Unable to update item (" + safeGetJCRPath() + ")";
+            log.debug(msg);
+            throw new RepositoryException(msg, e);
+        }
+    }
+
+    /**
+     * @see javax.jcr.Item#refresh(boolean)
+     */
+    public void refresh(boolean keepChanges) throws InvalidItemStateException, RepositoryException {
+        checkStatus();
+
+        if (keepChanges) {
+            /** todo FIXME should reset Item#status field to STATUS_NORMAL
+             * of all descendent non-transient instances; maybe also
+             * have to reset stale ItemState instances */
+            return;
+        }
+
+        // check status of this item's state
+        if (isTransient()) {
+            switch (state.getStatus()) {
+                case ItemState.STATUS_NEW:
+                    String msg = "Cannot refresh a new item (" + safeGetJCRPath() + ").";
+                    log.debug(msg);
+                    throw new RepositoryException(msg);
+                case ItemState.STATUS_STALE_DESTROYED:
+                    msg = "Cannot refresh on a deleted item (" + safeGetJCRPath() + ").";
+                    log.debug(msg);
+                    throw new InvalidItemStateException(msg);
+            }
+        }
+        // reset all transient modifications from this item and its decendants.
+        try {
+            itemStateMgr.undo(state);
+        } catch (ItemStateException e) {
+            String msg = "Unable to update item (" + safeGetJCRPath() + ")";
+            log.debug(msg);
+            throw new RepositoryException(msg, e);
+        }
+    }
+
+    /**
+     * @see javax.jcr.Item#remove()
+     */
+    public void remove() throws VersionException, LockException, ConstraintViolationException, RepositoryException {
+        checkSupportedOption(Repository.LEVEL_2_SUPPORTED);
+        checkStatus();
+
+        // validation checks are performed within remove operation
+        Operation rm = Remove.create(getItemState());
+        itemStateMgr.execute(rm);
+    }
+
+    //--------------------------------------------< TransientItemStateListener >
+    /**
+     * {@inheritDoc}
+     */
+    public void stateCreated(ItemState created) {
+        status = STATUS_NORMAL;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stateDestroyed(ItemState destroyed) {
+        // underlying state has been permanently destroyed
+
+        // set state of this instance to 'destroyed'
+        status = STATUS_DESTROYED;
+        // dispose state
+        if (state == destroyed) {
+            state.removeListener(this);
+            state = null;
+        }
+        /**
+         * notify the listeners that this instance has been
+         * permanently invalidated
+         */
+        notifyDestroyed();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stateModified(ItemState modified) {
+        status = STATUS_MODIFIED;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stateDiscarded(ItemState discarded) {
+        /**
+         * the state of this item has been discarded, probably as a result
+         * of calling Node.revert() or ItemImpl.setRemoved()
+         */
+        if (isTransient()) {
+            switch (state.getStatus()) {
+                /**
+                 * persistent item that has been transiently removed
+                 */
+                case ItemState.STATUS_EXISTING_REMOVED:
+                    /**
+                     * persistent item that has been transiently modified
+                     */
+                case ItemState.STATUS_EXISTING_MODIFIED:
+                    /**
+                     * persistent item that has been transiently modified or removed
+                     * and the underlying persistent state has been externally
+                     * modified since the transient modification/removal.
+                     */
+                case ItemState.STATUS_STALE_MODIFIED:
+                    ItemState persistentState = state.getOverlayedState();
+                    /**
+                     * the state is a transient wrapper for the underlying
+                     * persistent state, therefore restore the
+                     * persistent state and resurrect this item instance
+                     * if necessary
+                     */
+                    // DIFF JACKRABBIT: this is now done in stateUncovering()
+//                    state.removeListener(this);
+//                    persistentState.addListener(this);
+//                    itemStateMgr.disconnectTransientItemState(state);
+//                    state = persistentState;
+
+                    return;
+
+                    /**
+                     * persistent item that has been transiently modified or removed
+                     * and the underlying persistent state has been externally
+                     * destroyed since the transient modification/removal.
+                     */
+                case ItemState.STATUS_STALE_DESTROYED:
+                    /**
+                     * first notify the listeners that this instance has been
+                     * permanently invalidated
+                     */
+                    notifyDestroyed();
+                    // now set state of this instance to 'destroyed'
+                    status = STATUS_DESTROYED;
+                    // finally dispose state
+                    state.removeListener(this);
+                    state = null;
+                    return;
+
+                    /**
+                     * new item that has been transiently added
+                     */
+                case ItemState.STATUS_NEW:
+                    /**
+                     * first notify the listeners that this instance has been
+                     * permanently invalidated
+                     */
+                    notifyDestroyed();
+                    // now set state of this instance to 'destroyed'
+                    status = STATUS_DESTROYED;
+                    // finally dispose state
+                    state.removeListener(this);
+                    state = null;
+                    return;
+            }
+        }
+
+        /**
+         * first notify the listeners that this instance has been
+         * invalidated
+         */
+        notifyInvalidated();
+        // now render this instance 'invalid'
+        status = STATUS_INVALIDATED;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public void stateOverlaid(ItemState overlayer) {
+        state.removeListener(this);
+        state = overlayer;
+        state.addListener(this);
+        status = STATUS_MODIFIED;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public void stateUncovering(ItemState overlayer) {
+        state.removeListener(this);
+        state = overlayer.getOverlayedState();
+        state.addListener(this);
+        status = STATUS_NORMAL;
+    }
+
+    //----------------------------------------------------------< LiveCycle >---
+
+    /**
+     * Notify the listeners that this instance has been discarded
+     * (i.e. it has been temporarily rendered 'invalid').
+     */
+    private void notifyCreated() {
+        // copy listeners to array to avoid ConcurrentModificationException
+        ItemLifeCycleListener[] la = (ItemLifeCycleListener[]) listeners.values().toArray(new ItemLifeCycleListener[listeners.size()]);
+        for (int i = 0; i < la.length; i++) {
+            la[i].itemCreated(id, this);
+        }
+    }
+
+    /**
+     * Notify the listeners that this instance has been invalidated
+     * (i.e. it has been temporarily rendered 'invalid').
+     */
+    private  void notifyInvalidated() {
+        // copy listeners to array to avoid ConcurrentModificationException
+        ItemLifeCycleListener[] la = (ItemLifeCycleListener[]) listeners.values().toArray(new ItemLifeCycleListener[listeners.size()]);
+        for (int i = 0; i < la.length; i++) {
+            if (la[i] != null) {
+                la[i].itemInvalidated(id, this);
+            }
+        }
+    }
+
+    /**
+     * Notify the listeners that this instance has been destroyed
+     * (i.e. it has been permanently rendered 'invalid').
+     */
+    private void notifyDestroyed() {
+        // copy listeners to array to avoid ConcurrentModificationException
+        ItemLifeCycleListener[] la = (ItemLifeCycleListener[]) listeners.values().toArray(new ItemLifeCycleListener[listeners.size()]);
+        for (int i = 0; i < la.length; i++) {
+            if (la[i] != null) {
+                la[i].itemDestroyed(id, this);
+            }
+        }
+    }
+
+    /**
+     * Add an <code>ItemLifeCycleListener</code>
+     *
+     * @param listener the new listener to be informed on life cycle changes
+     */
+    void addLifeCycleListener(ItemLifeCycleListener listener) {
+        if (!listeners.containsKey(listener)) {
+            listeners.put(listener, listener);
+        }
+    }
+
+    /**
+     * Remove an <code>ItemLifeCycleListener</code>
+     *
+     * @param listener an existing listener
+     */
+    void removeLifeCycleListener(ItemLifeCycleListener listener) {
+        listeners.remove(listener);
+    }
+
+    //------------------------------------------------------< check methods >---
+    // DIFF TO JACKRABBIT: consistenly naming of 'checkMethods'
+    /**
+     * Performs a sanity check on this item and the associated session.
+     *
+     * @throws RepositoryException if this item has been rendered invalid for some reason
+     */
+    void checkStatus() throws RepositoryException {
+        // check session status
+        session.checkIsAlive();
+        // check status of this item for read operation
+        switch (status) {
+            case STATUS_NORMAL:
+            case STATUS_MODIFIED:
+                return;
+
+            case STATUS_DESTROYED:
+            case STATUS_INVALIDATED:
+                throw new InvalidItemStateException("Item '" + id + "' doesn't exist anymore");
+        }
+    }
+
+    /**
+     * Returns true if the repository supports the given option. False otherwise.
+     *
+     * @param option Any of the option constants defined by {@link Repository}
+     * that either returns 'true' or 'false'. I.e.
+     * <ul>
+     * <li>{@link Repository#LEVEL_1_SUPPORTED}</li>
+     * <li>{@link Repository#LEVEL_2_SUPPORTED}</li>
+     * <li>{@link Repository#OPTION_TRANSACTIONS_SUPPORTED}</li>
+     * <li>{@link Repository#OPTION_VERSIONING_SUPPORTED}</li>
+     * <li>{@link Repository#OPTION_OBSERVATION_SUPPORTED}</li>
+     * <li>{@link Repository#OPTION_LOCKING_SUPPORTED}</li>
+     * <li>{@link Repository#OPTION_QUERY_SQL_SUPPORTED}</li>
+     * </ul>
+     * @return true if the repository supports the given option. False otherwise.
+     */
+    boolean isSupportedOption(String option) {
+        return session.isSupportedOption(option);
+    }
+
+    /**
+     * Check if the given option is supported by the repository.
+     *
+     * @param option Any of the option constants defined by {@link Repository}
+     * that either returns 'true' or 'false'. I.e.
+     * <ul>
+     * <li>{@link Repository#LEVEL_1_SUPPORTED}</li>
+     * <li>{@link Repository#LEVEL_2_SUPPORTED}</li>
+     * <li>{@link Repository#OPTION_TRANSACTIONS_SUPPORTED}</li>
+     * <li>{@link Repository#OPTION_VERSIONING_SUPPORTED}</li>
+     * <li>{@link Repository#OPTION_OBSERVATION_SUPPORTED}</li>
+     * <li>{@link Repository#OPTION_LOCKING_SUPPORTED}</li>
+     * <li>{@link Repository#OPTION_QUERY_SQL_SUPPORTED}</li>
+     * </ul>
+     * @throws UnsupportedRepositoryOperationException
+     * @throws RepositoryException
+     */
+    void checkSupportedOption(String option) throws UnsupportedRepositoryOperationException, RepositoryException {
+        session.checkSupportedOption(option);
+    }
+
+    /**
+     * Checks if the repository supports level 2 (writing) and the status of
+     * this item. Note, that this method does not perform any additional
+     * validation checks such as access restrictions, locking, checkin status
+     * or protection that affect the writing to nodes and properties.
+     *
+     * @throws UnsupportedRepositoryOperationException
+     * @throws RepositoryException
+     * @see ItemStateValidator#checkAddNode(NodeState, QName, QName, int)
+     * @see ItemStateValidator#checkAddProperty(NodeState, QName, QPropertyDefinition, int)
+     * @see ItemStateValidator#checkSetProperty(PropertyState, int)
+     */
+    void checkIsWritable() throws UnsupportedRepositoryOperationException, ConstraintViolationException, RepositoryException {
+        checkSupportedOption(Repository.LEVEL_2_SUPPORTED);
+        checkStatus();
+    }
+
+    //------------------------------------< Implementation specific methods >---
+    /**
+     * Return the id of this <code>Item</code>.
+     *
+     * @return the id of this <code>Item</code>
+     */
+    public ItemId getId() {
+        return id;
+    }
+
+    /**
+     * Same as <code>{@link Item#getName()}</code> except that
+     * this method returns a <code>QName</code> instead of a
+     * <code>String</code>.
+     *
+     * @return the name of this item as <code>QName</code>
+     * @throws RepositoryException if an error occurs.
+     */
+    abstract QName getQName() throws RepositoryException;
+
+    // DIFF JR: getPrimaryPath
+    /**
+     * Returns the primary path to this <code>Item</code>.
+     *
+     * @return the primary path to this <code>Item</code>
+     */
+    Path getQPath() throws RepositoryException {
+        return session.getHierarchyManager().getQPath(id);
+    }
+
+    /**
+     * Returns the item-state associated with this <code>Item</code>.
+     *
+     * @return state associated with this <code>Item</code>
+     */
+    ItemState getItemState() {
+        return state;
+    }
+
+    /**
+     *
+     * @return
+     */
+    boolean isTransient() {
+        return state.isTransient();
+    }
+
+
+    /**
+     * DIFF JACKRABBIT
+     * Failsafe conversion of internal <code>Path</code> to JCR path for use in
+     * error messages etc.
+     *
+     * @return JCR path
+     */
+    String safeGetJCRPath() {
+        return session.getHierarchyManager().safeGetJCRPath(getId());
+    }
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemLifeCycleListener.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemLifeCycleListener.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemLifeCycleListener.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemLifeCycleListener.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,64 @@
+/*
+ * 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.jcr2spi;
+
+import org.apache.jackrabbit.spi.ItemId;
+
+/**
+ * The <code>ItemLifeCycleListener</code> interface allows an implementing
+ * object to be informed about changes on an <code>Item</code> instance.
+ *
+ * @see ItemImpl#addLifeCycleListener
+ */
+public interface ItemLifeCycleListener {
+
+    /**
+     * Called when an <code>Item</code> instance has been created.
+     *
+     * @param id
+     * @param item the instance which has been created
+     */
+    public void itemCreated(ItemId id, ItemImpl item);
+
+    /**
+     * Called when an <code>ItemImpl</code> instance has been invalidated
+     * (i.e. it has been temporarily rendered 'invalid').
+     * <p/>
+     * Note that most <code>{@link javax.jcr.Item}</code>,
+     * <code>{@link javax.jcr.Node}</code> and <code>{@link javax.jcr.Property}</code>
+     * methods will throw an <code>InvalidItemStateException</code> when called
+     * on an 'invalidated' item.
+     *
+     * @param id   the id of the instance that has been discarded
+     * @param item the instance which has been discarded
+     */
+    void itemInvalidated(ItemId id, ItemImpl item);
+
+    /**
+     * Called when an <code>ItemImpl</code> instance has been destroyed
+     * (i.e. it has been permanently rendered 'invalid').
+     * <p/>
+     * Note that most <code>{@link javax.jcr.Item}</code>,
+     * <code>{@link javax.jcr.Node}</code> and <code>{@link javax.jcr.Property}</code>
+     * methods will throw an <code>InvalidItemStateException</code> when called
+     * on a 'destroyed' item.
+     *
+     * @param id   the id of the instance that has been destroyed
+     * @param item the instance which has been destroyed
+     */
+    void itemDestroyed(ItemId id, ItemImpl item);
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemLifeCycleListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemLifeCycleListener.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManager.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManager.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManager.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,119 @@
+/*
+ * 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.jcr2spi;
+
+import org.apache.jackrabbit.name.Path;
+import org.apache.jackrabbit.spi.ItemId;
+import org.apache.jackrabbit.spi.NodeId;
+
+import javax.jcr.PathNotFoundException;
+import javax.jcr.AccessDeniedException;
+import javax.jcr.RepositoryException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.NodeIterator;
+import javax.jcr.PropertyIterator;
+
+/**
+ * <code>ItemManager</code>...
+ */
+public interface ItemManager extends ItemLifeCycleListener {
+
+    // DIFF JR: removed 'getRootNode' shortcut
+    
+    /**
+     * Disposes this <code>ItemManager</code> and frees resources.
+     */
+    public void dispose();
+
+    /**
+     * Checks if the item with the given path exists.
+     *
+     * @param path path to the item to be checked
+     * @return true if the specified item exists
+     */
+    public boolean itemExists(Path path);
+
+    /**
+     * Checks if the item with the given id exists.
+     *
+     * @param id id of the item to be checked
+     * @return true if the specified item exists
+     */
+    public boolean itemExists(ItemId id);
+
+    /**
+     * @param path
+     * @return
+     * @throws javax.jcr.PathNotFoundException
+     * @throws javax.jcr.AccessDeniedException
+     * @throws javax.jcr.RepositoryException
+     */
+    public ItemImpl getItem(Path path)
+            throws PathNotFoundException, AccessDeniedException, RepositoryException;
+
+    /**
+     * @param id
+     * @return
+     * @throws javax.jcr.RepositoryException
+     */
+    public ItemImpl getItem(ItemId id)
+            throws ItemNotFoundException, AccessDeniedException, RepositoryException;
+
+    /**
+     *
+     * @param parentId
+     * @return
+     * @throws ItemNotFoundException
+     * @throws AccessDeniedException
+     * @throws RepositoryException
+     */
+    public boolean hasChildNodes(NodeId parentId) throws ItemNotFoundException,
+        AccessDeniedException, RepositoryException;
+
+    /**
+     *
+     * @param parentId
+     * @return
+     * @throws ItemNotFoundException
+     * @throws AccessDeniedException
+     * @throws RepositoryException
+     */
+    public NodeIterator getChildNodes(NodeId parentId)
+            throws ItemNotFoundException, AccessDeniedException, RepositoryException;
+
+    /**
+     *
+     * @param parentId
+     * @return
+     * @throws ItemNotFoundException
+     * @throws AccessDeniedException
+     * @throws RepositoryException
+     */
+    public boolean hasChildProperties(NodeId parentId)
+            throws ItemNotFoundException, AccessDeniedException, RepositoryException;
+
+    /**
+     *
+     * @param parentId
+     * @return
+     * @throws ItemNotFoundException
+     * @throws AccessDeniedException
+     * @throws RepositoryException
+     */
+    public PropertyIterator getChildProperties(NodeId parentId)
+            throws ItemNotFoundException, AccessDeniedException, RepositoryException;
+}

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url



Mime
View raw message