You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2006/07/12 15:33:27 UTC

svn commit: r421270 [4/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/...

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManagerImpl.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManagerImpl.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ItemManagerImpl.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,560 @@
+/*
+ * 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.jcr2spi.util.Dumpable;
+import org.apache.jackrabbit.jcr2spi.version.VersionHistoryImpl;
+import org.apache.jackrabbit.jcr2spi.version.VersionImpl;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.name.Path;
+import org.apache.jackrabbit.spi.NodeId;
+import org.apache.jackrabbit.spi.ItemId;
+import org.apache.jackrabbit.spi.PropertyId;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.PropertyIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.PropertyDefinition;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * There's one <code>ItemManagerImpl</code> instance per <code>Session</code>
+ * instance. It is the factory for <code>Node</code> and <code>Property</code>
+ * instances.
+ * <p/>
+ * The <code>ItemManagerImpl</code>'s responsabilities are:
+ * <ul>
+ * <li>providing access to <code>Item</code> instances by <code>ItemId</code>
+ * whereas <code>Node</code> and <code>Item</code> are only providing relative access.
+ * <li>returning the instance of an existing <code>Node</code> or <code>Property</code>,
+ * given its absolute path.
+ * <li>creating the per-session instance of a <code>Node</code>
+ * or <code>Property</code> that doesn't exist yet and needs to be created first.
+ * <li>guaranteeing that there aren't multiple instances representing the same
+ * <code>Node</code> or <code>Property</code> associated with the same
+ * <code>Session</code> instance.
+ * <li>maintaining a cache of the item instances it created.
+ * <li>respecting access rights of associated <code>Session</code> in all methods.
+ * </ul>
+ * <p/>
+ * If the parent <code>Session</code> is an <code>XASession</code>, there is
+ * one <code>ItemManagerImpl</code> instance per started global transaction.
+ */
+public class ItemManagerImpl implements Dumpable, ItemManager {
+
+    private static Logger log = LoggerFactory.getLogger(ItemManagerImpl.class);
+
+    private final SessionImpl session;
+
+    private final ItemStateManager itemStateMgr;
+    private final HierarchyManager hierMgr;
+
+    /**
+     * A cache for item instances created by this <code>ItemManagerImpl</code>
+     */
+    // TODO: TO-BE-FIXED. Usage of SPI-Id required refactoring of the cache
+    private IdKeyMap itemCache;
+
+    /**
+     * Creates a new per-session instance <code>ItemManagerImpl</code> instance.
+     *
+     * @param itemStateMgr the item state itemStateManager associated with
+     * the new instance
+     * @param session the session associated with the new instance
+     */
+    ItemManagerImpl(ItemStateManager itemStateMgr, HierarchyManager hierMgr,
+                    SessionImpl session) {
+        this.itemStateMgr = itemStateMgr;
+        this.hierMgr = hierMgr;
+        this.session = session;
+        // setup item cache with weak references to items
+        itemCache = new DefaultIdKeyMap(); // TODO, JR: new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+    }
+
+    private NodeDefinition getDefinition(NodeState state)
+            throws RepositoryException {
+        NodeId parentId = state.getParentId();
+        NodeState parentState = null;
+        if (parentId != null) {
+            NodeImpl parent = (NodeImpl) getItem(parentId);
+            parentState = (NodeState) parent.getItemState();
+        }
+        NodeDefinition def = session.getItemDefinitionManager().getNodeDefinition(state, parentState);
+        return def;
+    }
+
+    private PropertyDefinition getDefinition(PropertyState state)
+        throws RepositoryException {
+        // fallback: try finding applicable definition
+        NodeId parentId = state.getParentId();
+        NodeImpl parent = (NodeImpl) getItem(parentId);
+        NodeState parentState = (NodeState) parent.getItemState();
+        PropertyDefinition def = session.getItemDefinitionManager().getPropertyDefinition(state, parentState);
+        return def;
+    }
+
+    /**
+     * Retrieves state of item with given <code>id</code>. If the specified item
+     * doesn't exist an <code>ItemNotFoundException</code> will be thrown.
+     * If the item exists but the current session is not granted read access an
+     * <code>AccessDeniedException</code> will be thrown.
+     *
+     * @param id id of item to be retrieved
+     * @return state state of said item
+     * @throws ItemNotFoundException if no item with given <code>id</code> exists
+     * @throws AccessDeniedException if the current session is not allowed to
+     *                               read the said item
+     * @throws RepositoryException   if another error occurs
+     */
+    private ItemState getItemState(ItemId id)
+            throws ItemNotFoundException, AccessDeniedException,
+            RepositoryException {
+        // check privileges
+        if (!session.getAccessManager().canRead(id)) {
+            // clear cache
+            ItemImpl item = retrieveItem(id);
+            if (item != null) {
+                evictItem(id);
+            }
+            throw new AccessDeniedException("cannot read item " + id);
+        }
+
+        try {
+            return itemStateMgr.getItemState(id);
+        } catch (NoSuchItemStateException nsise) {
+            String msg = "no such item: " + id;
+            log.debug(msg);
+            throw new ItemNotFoundException(msg);
+        } catch (ItemStateException ise) {
+            String msg = "failed to retrieve item state of " + id;
+            log.error(msg);
+            throw new RepositoryException(msg, ise);
+        }
+    }
+
+    //-------------------------------------------------< item factory methods >
+    private ItemImpl createItemInstance(ItemId id)
+            throws ItemNotFoundException, RepositoryException {
+        // create instance of item using its state object
+        ItemImpl item;
+        ItemState state;
+        try {
+            state = itemStateMgr.getItemState(id);
+        } catch (NoSuchItemStateException nsise) {
+            throw new ItemNotFoundException(id.toString());
+        } catch (ItemStateException ise) {
+            String msg = "failed to retrieve item state of item " + id;
+            log.error(msg, ise);
+            throw new RepositoryException(msg, ise);
+        }
+
+        if (state.isNode()) {
+            item = createNodeInstance((NodeState) state);
+        } else {
+            item = createPropertyInstance((PropertyState) state);
+        }
+        return item;
+    }
+
+    private NodeImpl createNodeInstance(NodeState state, NodeDefinition def)
+            throws RepositoryException {
+        // DIFF JR: no need to build NodeId from state
+        // we want to be informed on life cycle changes of the new node object
+        // in order to maintain item cache consistency
+        ItemLifeCycleListener[] listeners = new ItemLifeCycleListener[]{this};
+
+        // check special nodes
+        if (state.getNodeTypeName().equals(QName.NT_VERSION)) {
+            // version
+            return new VersionImpl(this, session, state, def, listeners);
+        } else if (state.getNodeTypeName().equals(QName.NT_VERSIONHISTORY)) {
+            // version-history
+            return new VersionHistoryImpl(this, session, state, def, listeners);
+        } else {
+            // create common node object
+            return new NodeImpl(this, session, state, def, listeners);
+        }
+
+    }
+
+    private NodeImpl createNodeInstance(NodeState state) throws RepositoryException {
+        // 1. get definition of the specified node
+        NodeDefinition def = getDefinition(state);
+        // 2. create instance
+        return createNodeInstance(state, def);
+    }
+
+    private PropertyImpl createPropertyInstance(PropertyState state,
+                                                PropertyDefinition def) {
+        // we want to be informed on life cycle changes of the new property object
+        // in order to maintain item cache consistency
+        ItemLifeCycleListener[] listeners = new ItemLifeCycleListener[]{this};
+        // create property object
+        PropertyImpl prop = new PropertyImpl(this, session, state, def, listeners);
+        return prop;
+    }
+
+    private PropertyImpl createPropertyInstance(PropertyState state)
+            throws RepositoryException {
+        // 1. get definition for the specified property
+        PropertyDefinition def = getDefinition(state);
+        // 2. create instance
+        return createPropertyInstance(state, def);
+    }
+
+    //---------------------------------------------------< item cache methods >
+
+    /**
+     * Returns an item reference from the cache.
+     *
+     * @param id id of the item that should be retrieved.
+     * @return the item reference stored in the corresponding cache entry
+     *         or <code>null</code> if there's no corresponding cache entry.
+     */
+    private ItemImpl retrieveItem(ItemId id) {
+        return (ItemImpl) itemCache.get(id);
+    }
+
+    /**
+     * Puts the reference of an item in the cache with
+     * the item's path as the key.
+     *
+     * @param item the item to cache
+     */
+    private void cacheItem(ItemImpl item) {
+        ItemId id = item.getId();
+        if (itemCache.containsKey(id)) {
+            log.warn("overwriting cached item " + id);
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("caching item " + id);
+        }
+        itemCache.put(id, item);
+    }
+
+    /**
+     * Removes a cache entry for a specific item.
+     *
+     * @param id id of the item to remove from the cache
+     */
+    private void evictItem(ItemId id) {
+        if (log.isDebugEnabled()) {
+            log.debug("removing item " + id + " from cache");
+        }
+        itemCache.remove(id);
+    }
+
+    //--------------------------------------------------------< ItemManager >---
+    /**
+     * @inheritdoc
+     */
+    public void dispose() {
+        itemCache.clear();
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public boolean itemExists(Path path) {
+        try {
+            // check sanity of session
+            session.checkIsAlive();
+
+            ItemId id = hierMgr.getItemId(path);
+
+            // check if state exists for the given item
+            if (!itemStateMgr.hasItemState(id)) {
+                return false;
+            }
+
+            // check privileges
+            if (!session.getAccessManager().canRead(id)) {
+                // clear cache
+                evictItem(id);
+                // item exists but the session has not been granted read access
+                return false;
+            }
+            return true;
+        } catch (PathNotFoundException pnfe) {
+            return false;
+        } catch (ItemNotFoundException infe) {
+            return false;
+        } catch (RepositoryException re) {
+            return false;
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public boolean itemExists(ItemId id) {
+        try {
+            // check sanity of session
+            session.checkIsAlive();
+
+            // check if state exists for the given item
+            if (!itemStateMgr.hasItemState(id)) {
+                return false;
+            }
+
+            // check privileges
+            if (!session.getAccessManager().canRead(id)) {
+                // clear cache
+                evictItem(id);
+                // item exists but the session has not been granted read access
+                return false;
+            }
+            return true;
+        } catch (ItemNotFoundException infe) {
+            return false;
+        } catch (RepositoryException re) {
+            return false;
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public synchronized ItemImpl getItem(org.apache.jackrabbit.name.Path path)
+            throws PathNotFoundException, AccessDeniedException, RepositoryException {
+        ItemId id = hierMgr.getItemId(path);
+        try {
+            return getItem(id);
+        } catch (ItemNotFoundException infe) {
+            throw new PathNotFoundException(hierMgr.safeGetJCRPath(path));
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public synchronized ItemImpl getItem(ItemId id)
+            throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+        // check sanity of session
+        session.checkIsAlive();
+
+        // check privileges
+        if (!session.getAccessManager().canRead(id)) {
+            // clear cache
+            evictItem(id);
+            throw new AccessDeniedException("cannot read item " + id);
+        }
+
+        // check cache
+        ItemImpl item = retrieveItem(id);
+        if (item == null) {
+            // create instance of item
+            item = createItemInstance(id);
+        }
+        return item;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public synchronized boolean hasChildNodes(NodeId parentId)
+            throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+        // check sanity of session
+        session.checkIsAlive();
+
+        ItemState state = getItemState(parentId);
+        if (!state.isNode()) {
+            String msg = "can't list child nodes of property " + parentId;
+            log.debug(msg);
+            throw new RepositoryException(msg);
+        }
+        NodeState nodeState = (NodeState) state;
+        Iterator iter = nodeState.getChildNodeEntries().iterator();
+
+        while (iter.hasNext()) {
+            NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) iter.next();
+            NodeId id = entry.getId();
+            // check read access
+            if (session.getAccessManager().canRead(id)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public synchronized NodeIterator getChildNodes(NodeId parentId)
+            throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+        // check sanity of session
+        session.checkIsAlive();
+
+        ItemState state = getItemState(parentId);
+        if (!state.isNode()) {
+            String msg = "can't list child nodes of property " + parentId;
+            log.debug(msg);
+            throw new RepositoryException(msg);
+        }
+        NodeState nodeState = (NodeState) state;
+        ArrayList childIds = new ArrayList();
+        Iterator iter = nodeState.getChildNodeEntries().iterator();
+
+        while (iter.hasNext()) {
+            NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) iter.next();
+            NodeId id = entry.getId();
+            // check read access
+            if (session.getAccessManager().canRead(id)) {
+                childIds.add(id);
+            }
+        }
+
+        return new LazyItemIterator(this, childIds);
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public synchronized boolean hasChildProperties(NodeId parentId)
+            throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+        // check sanity of session
+        session.checkIsAlive();
+
+        ItemState state = getItemState(parentId);
+        if (!state.isNode()) {
+            String msg = "can't list child properties of property " + parentId;
+            log.debug(msg);
+            throw new RepositoryException(msg);
+        }
+        NodeState nodeState = (NodeState) state;
+        Iterator iter = nodeState.getPropertyNames().iterator();
+
+        while (iter.hasNext()) {
+            QName propName = (QName) iter.next();
+
+            PropertyId id = nodeState.getPropertyId(propName);
+            // check read access
+            if (session.getAccessManager().canRead(id)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public synchronized PropertyIterator getChildProperties(NodeId parentId)
+            throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+        // check sanity of session
+        session.checkIsAlive();
+
+        ItemState state = getItemState(parentId);
+        if (!state.isNode()) {
+            String msg = "can't list child properties of property " + parentId;
+            log.debug(msg);
+            throw new RepositoryException(msg);
+        }
+        NodeState nodeState = (NodeState) state;
+        ArrayList childIds = new ArrayList();
+        Iterator iter = nodeState.getPropertyNames().iterator();
+
+        while (iter.hasNext()) {
+            QName propName = (QName) iter.next();
+            PropertyId id = nodeState.getPropertyId(propName);
+            // check read access
+            if (session.getAccessManager().canRead(id)) {
+                childIds.add(id);
+            }
+        }
+
+        return new LazyItemIterator(this, childIds);
+    }
+
+    //------------------------------------------------< ItemLifeCycleListener >
+    /**
+     * {@inheritDoc}
+     */
+    public void itemCreated(ItemId id, ItemImpl item) {
+        if (log.isDebugEnabled()) {
+            log.debug("created item " + id);
+        }
+        // add instance to cache
+        cacheItem(item);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void itemInvalidated(ItemId id, ItemImpl item) {
+        if (log.isDebugEnabled()) {
+            log.debug("invalidated item " + id);
+        }
+        // remove instance from cache
+        evictItem(id);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void itemDestroyed(ItemId id, ItemImpl item) {
+        if (log.isDebugEnabled()) {
+            log.debug("destroyed item " + id);
+        }
+        // we're no longer interested in this item
+        item.removeLifeCycleListener(this);
+        // remove instance from cache
+        evictItem(id);
+    }
+
+    //-------------------------------------------------------------< Dumpable >
+    /**
+     * {@inheritDoc}
+     */
+    public void dump(PrintStream ps) {
+        ps.println("ItemManagerImpl (" + this + ")");
+        ps.println();
+        ps.println("Items in cache:");
+        ps.println();
+        Iterator iter = itemCache.keySet().iterator();
+        while (iter.hasNext()) {
+            ItemId id = (ItemId) iter.next();
+            ItemImpl item = (ItemImpl) itemCache.get(id);
+            if (item.isNode()) {
+                ps.print("Node: ");
+            } else {
+                ps.print("Property: ");
+            }
+            if (item.getItemState().isTransient()) {
+                ps.print("transient ");
+            } else {
+                ps.print("          ");
+            }
+            ps.println(id + "\t" + hierMgr.safeGetJCRPath(id) + " (" + item + ")");
+        }
+    }
+}

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

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

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/LazyItemIterator.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/LazyItemIterator.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/LazyItemIterator.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/LazyItemIterator.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,227 @@
+/*
+ * 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 org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.version.VersionIterator;
+import javax.jcr.version.Version;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * <code>LazyItemIterator</code> is an id-based iterator that instantiates
+ * the <code>Item</code>s only when they are requested.
+ * <p/>
+ * <strong>Important:</strong> <code>Item</code>s that appear to be nonexistent
+ * for some reason (e.g. because of insufficient access rights or because they
+ * have been removed since the iterator has been retrieved) are silently
+ * skipped. As a result the size of the iterator as reported by
+ * {@link #getSize()} might appear to be shrinking while iterating over the
+ * items.
+ * todo should getSize() better always return -1?
+ *
+ * @see #getSize()
+ */
+public class LazyItemIterator implements NodeIterator, PropertyIterator, VersionIterator {
+
+    /** Logger instance for this class */
+    private static Logger log = LoggerFactory.getLogger(LazyItemIterator.class);
+
+    /** the item manager that is used to lazily fetch the items */
+    private final ItemManager itemMgr;
+
+    /** the list of item ids */
+    private final List idList;
+
+    /** the position of the next item */
+    private int pos;
+
+    /** prefetched item to be returned on <code>{@link #next()}</code> */
+    private Item next;
+
+    /**
+     * Creates a new <code>LazyItemIterator</code> instance.
+     *
+     * @param itemMgr item manager
+     * @param ids Collection of item id's
+     */
+    public LazyItemIterator(ItemManager itemMgr, Collection ids) {
+        this.itemMgr = itemMgr;
+        this.idList = new ArrayList(ids);
+        // prefetch first item
+        pos = 0;
+        prefetchNext();
+    }
+
+    /**
+     * Prefetches next item.
+     * <p/>
+     * {@link #next} is set to the next available item in this iterator or to
+     * <code>null</code> in case there are no more items.
+     */
+    private void prefetchNext() {
+        // reset
+        next = null;
+        while (next == null && pos < idList.size()) {
+            ItemId id = (ItemId) idList.get(pos);
+            try {
+                next = itemMgr.getItem(id);
+            } catch (ItemNotFoundException e) {
+                log.debug("ignoring nonexistent item " + id);
+                // remove invalid id
+                idList.remove(pos);
+                // try next
+            } catch (RepositoryException e) {
+                log.error("failed to fetch item " + id + ", skipping...", e);
+                // remove invalid id
+                idList.remove(pos);
+                // try next
+            }
+        }
+    }
+
+    //---------------------------------------------------------< NodeIterator >
+    /**
+     * {@inheritDoc}
+     */
+    public Node nextNode() {
+        return (Node) next();
+    }
+
+    //-----------------------------------------------------< PropertyIterator >
+    /**
+     * {@inheritDoc}
+     */
+    public Property nextProperty() {
+        return (Property) next();
+    }
+
+    //----------------------------------------------------< VersionIterator >---
+    /**
+     * {@inheritDoc}
+     */
+    public Version nextVersion() {
+        return (Version) next();
+    }
+
+    //--------------------------------------------------------< RangeIterator >
+    /**
+     * {@inheritDoc}
+     */
+    public long getPosition() {
+        return pos;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p/>
+     * Note that the size of the iterator as reported by {@link #getSize()}
+     * might appear to be shrinking while iterating because items that for
+     * some reason cannot be retrieved through this iterator are silently
+     * skipped, thus reducing the size of this iterator.
+     *
+     * todo better to always return -1?
+     */
+    public long getSize() {
+        return idList.size();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void skip(long skipNum) {
+        if (skipNum < 0) {
+            throw new IllegalArgumentException("skipNum must not be negative");
+        }
+        if (skipNum == 0) {
+            return;
+        }
+        if (next == null) {
+            throw new NoSuchElementException();
+        }
+
+        // reset
+        next = null;
+        // skip the first (skipNum - 1) items without actually retrieving them
+        while (--skipNum > 0) {
+            pos++;
+            if (pos >= idList.size()) {
+                // skipped past last item
+                throw new NoSuchElementException();
+            }
+            ItemId id = (ItemId) idList.get(pos);
+            // eliminate invalid items from this iterator
+            while (!itemMgr.itemExists(id)) {
+                log.debug("ignoring nonexistent item " + id);
+                // remove invalid id
+                idList.remove(pos);
+                if (pos >= idList.size()) {
+                    // skipped past last item
+                    throw new NoSuchElementException();
+                }
+                id = (ItemId) idList.get(pos);
+                // try next
+                continue;
+            }
+        }
+        // prefetch final item (the one to be returned on next())
+        pos++;
+        prefetchNext();
+    }
+
+    //-------------------------------------------------------------< Iterator >
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasNext() {
+        return next != null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object next() {
+        if (next == null) {
+            throw new NoSuchElementException();
+        }
+        Item item = next;
+        pos++;
+        prefetchNext();
+        return item;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws UnsupportedOperationException always since not implemented
+     */
+    public void remove() {
+        throw new UnsupportedOperationException("remove");
+    }
+}

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

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

Added: jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ManagerProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ManagerProvider.java?rev=421270&view=auto
==============================================================================
--- jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ManagerProvider.java (added)
+++ jackrabbit/trunk/contrib/spi/jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/ManagerProvider.java Wed Jul 12 06:33:19 2006
@@ -0,0 +1,41 @@
+/*
+ * 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.NamespaceResolver;
+import org.apache.jackrabbit.jcr2spi.security.AccessManager;
+import org.apache.jackrabbit.jcr2spi.lock.LockManager;
+import org.apache.jackrabbit.jcr2spi.version.VersionManager;
+import org.apache.jackrabbit.jcr2spi.state.ItemStateManager;
+
+/**
+ * <code>ManagerProvider</code>...
+ */
+public interface ManagerProvider {
+
+    public NamespaceResolver getNamespaceResolver();
+
+    public HierarchyManager getHierarchyManager();
+
+    public ItemStateManager getItemStateManager();
+
+    public AccessManager getAccessManager();
+
+    public LockManager getLockManager();
+
+    public VersionManager getVersionManager();
+}
\ No newline at end of file

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

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