jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mdue...@apache.org
Subject svn commit: r794012 - in /jackrabbit/branches/1.5: jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/ jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/ jackrabbit-jcr2spi/src/test/resources/ jackrabbit-jcr2spi/src/test/...
Date Tue, 14 Jul 2009 18:48:04 GMT
Author: mduerig
Date: Tue Jul 14 18:48:04 2009
New Revision: 794012

URL: http://svn.apache.org/viewvc?rev=794012&view=rev
Log:
JCR-1797: SPI: RepositoryService.getItemInfos should be allowed to return entries outside of the requested tree.

Added:
    jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/AbstractJCR2SPITest.java   (with props)
    jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/AbstractRepositoryService.java   (with props)
    jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/GetItemsTest.java   (with props)
    jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/resources/
    jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/resources/org/
    jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/resources/org/apache/
    jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/resources/org/apache/jackrabbit/
    jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/resources/org/apache/jackrabbit/jcr2spi/
    jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/resources/org/apache/jackrabbit/jcr2spi/default-nodetypes.cnd   (with props)
Modified:
    jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java
    jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/TestAll.java
    jackrabbit/branches/1.5/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java

Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java?rev=794012&r1=794011&r2=794012&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/main/java/org/apache/jackrabbit/jcr2spi/state/WorkspaceItemStateFactory.java Tue Jul 14 18:48:04 2009
@@ -195,38 +195,46 @@
     private synchronized NodeState createItemStates(NodeId nodeId, Iterator itemInfos,
                                                     NodeEntry entry, boolean isDeep)
             throws ItemNotFoundException, RepositoryException {
-        NodeState nodeState;
+        NodeState nodeState = null;
         ItemInfos infos = new ItemInfos(itemInfos);
-        // first entry in the iterator is the originally requested Node.
-        if (infos.hasNext()) {
-            NodeInfo first = (NodeInfo) infos.next();
-            if (isDeep) {
-                // for a deep state, the hierarchy entry does not correspond to
-                // the given NodeEntry -> retrieve NodeState before executing
-                // validation check.
-                nodeState = createDeepNodeState(first, entry, infos);
-                assertValidState(nodeState, first);
-            } else {
-                // 'isDeep' == false -> the given NodeEntry must match to the
-                // first ItemInfo retrieved from the iterator.
-                assertMatchingPath(first, entry);
-                nodeState = createNodeState(first, entry);
-            }
-        } else {
-            // empty iterator
-            throw new ItemNotFoundException("Node with id " + nodeId + " could not be found.");
-        }
 
-        // deal with all additional ItemInfos that may be present.
-        NodeEntry parentEntry = nodeState.getNodeEntry();
+        // Assuming locality of the itemInfos, we keep an estimate of a parent entry.
+        // This reduces the part of the hierarchy to traverse. For large batches this
+        // optimization results in about 25% speed up.
+        NodeEntry aproxParentEntry = entry;
+
         while (infos.hasNext()) {
             ItemInfo info = (ItemInfo) infos.next();
             if (info.denotesNode()) {
-                createDeepNodeState((NodeInfo) info, parentEntry, infos);
+                NodeInfo nodeInfo = (NodeInfo) info;
+
+                if (nodeId.equals(nodeInfo.getId())) {
+                    // This is the originally requested node
+                    if (isDeep) {
+                        // for a deep state, the hierarchy entry does not correspond to
+                        // the given NodeEntry -> retrieve NodeState before executing
+                        // validation check.
+                        nodeState = createDeepNodeState(nodeInfo, entry, infos);
+                        assertValidState(nodeState, nodeInfo);
+                    } else {
+                        // 'isDeep' == false -> the given NodeEntry must match the
+                        // ItemInfo for the originally requested node
+                        assertMatchingPath(nodeInfo, entry);
+                        nodeState = createNodeState(nodeInfo, entry);
+                    }
+                } else {
+                    // deal with additional nodeInfo
+                    aproxParentEntry = createDeepNodeState(nodeInfo, aproxParentEntry, infos).getNodeEntry();
+                }
             } else {
-                createDeepPropertyState((PropertyInfo) info, parentEntry, infos);
+                // deal with additional propertyInfo
+                createDeepPropertyState((PropertyInfo) info, aproxParentEntry, infos);
             }
         }
+
+        if (nodeState == null) {
+            throw new ItemNotFoundException("Node with id " + nodeId + " could not be found.");
+        }
         return nodeState;
     }
 
@@ -360,9 +368,17 @@
 
             NodeEntry entry = anyParent;
             for (int i = 0; i < missingElems.length; i++) {
-                Name name = missingElems[i].getName();
-                int index = missingElems[i].getNormalizedIndex();
-                entry = createIntermediateNodeEntry(entry, name, index, infos);
+                if (missingElems[i].denotesParent()) {
+                    // Walk up the hierarchy for 'negative' paths
+                    // until the smallest common root is found
+                    entry = entry.getParent();
+                }
+                else {
+                    // Add missing elements starting from the smallest common root
+                    Name name = missingElems[i].getName();
+                    int index = missingElems[i].getNormalizedIndex();
+                    entry = createIntermediateNodeEntry(entry, name, index, infos);
+                }
             }
             if (entry == anyParent) {
                 throw new RepositoryException("Internal error while getting deep itemState");
@@ -401,9 +417,17 @@
             int i = 0;
             // NodeEntries except for the very last 'missingElem'
             while (i < missingElems.length - 1) {
-                Name name = missingElems[i].getName();
-                int index = missingElems[i].getNormalizedIndex();
-                entry = createIntermediateNodeEntry(entry, name, index, infos);
+                if (missingElems[i].denotesParent()) {
+                    // Walk up the hierarchy for 'negative' paths
+                    // until the smallest common root is found
+                    entry = entry.getParent();
+                }
+                else {
+                    // Add missing elements starting from the smallest common root
+                    Name name = missingElems[i].getName();
+                    int index = missingElems[i].getNormalizedIndex();
+                    entry = createIntermediateNodeEntry(entry, name, index, infos);
+                }
                 i++;
             }
             // create PropertyEntry for the last element if not existing yet
@@ -474,7 +498,7 @@
     }
 
     /**
-     * Returns true if the given <code>missingElems</code> start with a parent (..),
+     * Returns true if the given <code>missingElems</code> start with
      * a current (.) or the root element, in which case the info is not within
      * the tree as it is expected.
      * See also #JCR-1797 for the corresponding enhancement request.
@@ -484,7 +508,7 @@
      */
     private static boolean startsWithIllegalElement(Path.Element[] missingElems) {
         if (missingElems.length > 0) {
-            return !missingElems[0].denotesName();
+            return !(missingElems[0].denotesName() || missingElems[0].denotesParent());
         }
         return false;
     }

Added: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/AbstractJCR2SPITest.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/AbstractJCR2SPITest.java?rev=794012&view=auto
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/AbstractJCR2SPITest.java (added)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/AbstractJCR2SPITest.java Tue Jul 14 18:48:04 2009
@@ -0,0 +1,402 @@
+/*
+ * 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 java.io.InputStream;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.jcr.Credentials;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+
+import junit.framework.TestCase;
+
+import org.apache.jackrabbit.jcr2spi.config.RepositoryConfig;
+import org.apache.jackrabbit.spi.Batch;
+import org.apache.jackrabbit.spi.EventBundle;
+import org.apache.jackrabbit.spi.EventFilter;
+import org.apache.jackrabbit.spi.IdFactory;
+import org.apache.jackrabbit.spi.ItemId;
+import org.apache.jackrabbit.spi.LockInfo;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.NameFactory;
+import org.apache.jackrabbit.spi.NodeId;
+import org.apache.jackrabbit.spi.NodeInfo;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.PathFactory;
+import org.apache.jackrabbit.spi.PropertyId;
+import org.apache.jackrabbit.spi.PropertyInfo;
+import org.apache.jackrabbit.spi.QNodeDefinition;
+import org.apache.jackrabbit.spi.QPropertyDefinition;
+import org.apache.jackrabbit.spi.QValueFactory;
+import org.apache.jackrabbit.spi.QueryInfo;
+import org.apache.jackrabbit.spi.RepositoryService;
+import org.apache.jackrabbit.spi.SessionInfo;
+import org.apache.jackrabbit.spi.Subscription;
+
+/**
+ * Abstract base class for jcr2spi tests. This class implements {@link RepositoryService}
+ * by delegation to {@link AbstractRepositoryService}. Implementors can overrid individual
+ * methods as needed.
+ */
+public abstract class AbstractJCR2SPITest extends TestCase implements RepositoryService {
+    protected RepositoryService repositoryService;
+    protected RepositoryConfig config;
+    protected Repository repository;
+
+    public void setUp() throws Exception {
+        super.setUp();
+        repositoryService = getRepositoryService();
+        config = getRepositoryConfig();
+        repository = getRepository();
+    }
+
+    protected RepositoryService getRepositoryService() throws RepositoryException {
+        return new AbstractRepositoryService() {
+            public Iterator getChildInfos(SessionInfo sessionInfo, NodeId parentId)
+                    throws RepositoryException {
+
+                return AbstractJCR2SPITest.this.getChildInfos(sessionInfo, parentId);
+            }
+
+            public Iterator getItemInfos(SessionInfo sessionInfo, NodeId nodeId) throws RepositoryException {
+                return AbstractJCR2SPITest.this.getItemInfos(sessionInfo, nodeId);
+            }
+
+            public NodeInfo getNodeInfo(SessionInfo sessionInfo, NodeId nodeId) throws RepositoryException {
+                return AbstractJCR2SPITest.this.getNodeInfo(sessionInfo, nodeId);
+            }
+
+            public PropertyInfo getPropertyInfo(SessionInfo sessionInfo, PropertyId propertyId) {
+                return AbstractJCR2SPITest.this.getPropertyInfo(sessionInfo, propertyId);
+            }
+        };
+    }
+
+    protected RepositoryConfig getRepositoryConfig() {
+        return new AbstractRepositoryConfig() {
+            public RepositoryService getRepositoryService() throws RepositoryException {
+                return repositoryService;
+            }
+        };
+    }
+
+    protected Repository getRepository() throws RepositoryException {
+        return RepositoryImpl.create(config);
+    }
+
+    // -----------------------------------------------------< RepositoryService >---
+
+    public IdFactory getIdFactory() throws RepositoryException {
+        return repositoryService.getIdFactory();
+    }
+
+    public NameFactory getNameFactory() throws RepositoryException {
+        return repositoryService.getNameFactory();
+    }
+
+    public PathFactory getPathFactory() throws RepositoryException {
+        return repositoryService.getPathFactory();
+    }
+
+    public QValueFactory getQValueFactory() throws RepositoryException {
+        return repositoryService.getQValueFactory();
+    }
+
+    public Map getRepositoryDescriptors() throws RepositoryException {
+        return repositoryService.getRepositoryDescriptors();
+    }
+
+
+    //-----------------------------------< SessionInfo creation and release >---
+
+    public SessionInfo obtain(Credentials credentials, String workspaceName) throws RepositoryException {
+        return repositoryService.obtain(credentials, workspaceName);
+    }
+
+    public SessionInfo obtain(SessionInfo sessionInfo, String workspaceName) throws RepositoryException {
+        return repositoryService.obtain(sessionInfo, workspaceName);
+    }
+
+    public SessionInfo impersonate(SessionInfo sessionInfo, Credentials credentials)
+            throws RepositoryException {
+
+        return repositoryService.impersonate(sessionInfo, credentials);
+    }
+
+    public void dispose(SessionInfo sessionInfo) throws RepositoryException {
+        repositoryService.dispose(sessionInfo);
+    }
+
+    public String[] getWorkspaceNames(SessionInfo sessionInfo) throws RepositoryException {
+        return repositoryService.getWorkspaceNames(sessionInfo);
+    }
+
+
+    //-----------------------------------------------------< Access Control >---
+
+    public boolean isGranted(SessionInfo sessionInfo, ItemId itemId, String[] actions)
+            throws RepositoryException {
+
+        return repositoryService.isGranted(sessionInfo, itemId, actions);
+    }
+
+
+    //------------------------------------------------------< Reading items >---
+
+    public QNodeDefinition getNodeDefinition(SessionInfo sessionInfo, NodeId nodeId)
+            throws RepositoryException {
+
+        return repositoryService.getNodeDefinition(sessionInfo, nodeId);
+    }
+
+    public QPropertyDefinition getPropertyDefinition(SessionInfo sessionInfo, PropertyId propertyId)
+            throws RepositoryException {
+
+        return getPropertyDefinition(sessionInfo, propertyId);
+    }
+
+    public abstract NodeInfo getNodeInfo(SessionInfo sessionInfo, NodeId nodeId) throws RepositoryException;
+
+    public abstract Iterator getItemInfos(SessionInfo sessionInfo, NodeId nodeId) throws RepositoryException;
+
+    public abstract Iterator getChildInfos(SessionInfo sessionInfo, NodeId parentId) throws RepositoryException;
+
+    public abstract PropertyInfo getPropertyInfo(SessionInfo sessionInfo, PropertyId propertyId);
+
+    //-----------------------------------------------< general modification >---
+
+    public Batch createBatch(SessionInfo sessionInfo, ItemId itemId) throws RepositoryException {
+        return repositoryService.createBatch(sessionInfo, itemId);
+    }
+
+    public void submit(Batch batch) throws RepositoryException {
+        repositoryService.submit(batch);
+    }
+
+
+    //-------------------------------------------------------------< Import >---
+
+    public void importXml(SessionInfo sessionInfo, NodeId parentId, InputStream xmlStream, int uuidBehaviour)
+            throws RepositoryException {
+
+        repositoryService.importXml(sessionInfo, parentId, xmlStream, uuidBehaviour);
+    }
+
+
+    //---------------------------------------------------------< Copy, Move >---
+
+    public void move(SessionInfo sessionInfo, NodeId srcNodeId, NodeId destParentNodeId, Name destName)
+            throws RepositoryException {
+
+        repositoryService.move(sessionInfo, srcNodeId, destParentNodeId, destName);
+    }
+
+    public void copy(SessionInfo sessionInfo, String srcWorkspaceName, NodeId srcNodeId,
+            NodeId destParentNodeId, Name destName) throws RepositoryException {
+
+        repositoryService.copy(sessionInfo, srcWorkspaceName, srcNodeId, destParentNodeId, destName);
+    }
+
+
+    //------------------------------------------------------< Update, Clone >---
+
+    public void update(SessionInfo sessionInfo, NodeId nodeId, String srcWorkspaceName)
+            throws RepositoryException {
+
+        repositoryService.update(sessionInfo, nodeId, srcWorkspaceName);
+    }
+
+    public void clone(SessionInfo sessionInfo, String srcWorkspaceName, NodeId srcNodeId,
+            NodeId destParentNodeId, Name destName, boolean removeExisting) throws RepositoryException {
+
+        repositoryService.clone(sessionInfo, srcWorkspaceName, srcNodeId, destParentNodeId, destName, removeExisting);
+    }
+
+
+    //------------------------------------------------------------< Locking >---
+
+    public LockInfo getLockInfo(SessionInfo sessionInfo, NodeId nodeId) throws RepositoryException {
+        return repositoryService.getLockInfo(sessionInfo, nodeId);
+    }
+
+    public LockInfo lock(SessionInfo sessionInfo, NodeId nodeId, boolean deep, boolean sessionScoped)
+            throws RepositoryException {
+
+        return repositoryService.lock(sessionInfo, nodeId, deep, sessionScoped);
+    }
+
+    public void refreshLock(SessionInfo sessionInfo, NodeId nodeId)
+            throws RepositoryException {
+
+        repositoryService.refreshLock(sessionInfo, nodeId);
+    }
+
+    public void unlock(SessionInfo sessionInfo, NodeId nodeId)
+            throws  RepositoryException {
+
+        repositoryService.unlock(sessionInfo, nodeId);
+    }
+
+
+    //---------------------------------------------------------< Versioning >---
+
+    public NodeId checkin(SessionInfo sessionInfo, NodeId nodeId) throws RepositoryException {
+        return repositoryService.checkin(sessionInfo, nodeId);
+    }
+
+    public void checkout(SessionInfo sessionInfo, NodeId nodeId) throws RepositoryException {
+        repositoryService.checkout(sessionInfo, nodeId);
+    }
+
+    public void removeVersion(SessionInfo sessionInfo, NodeId versionHistoryId, NodeId versionId)
+            throws RepositoryException {
+
+        repositoryService.removeVersion(sessionInfo, versionHistoryId, versionId);
+    }
+
+    public void restore(SessionInfo sessionInfo, NodeId[] versionIds, boolean removeExisting)
+            throws RepositoryException {
+
+        repositoryService.restore(sessionInfo, versionIds, removeExisting);
+    }
+
+    public void restore(SessionInfo sessionInfo, NodeId nodeId, NodeId versionId, boolean removeExisting)
+            throws RepositoryException {
+
+        repositoryService.restore(sessionInfo, nodeId, versionId, removeExisting);
+    }
+
+    public Iterator merge(SessionInfo sessionInfo, NodeId nodeId, String srcWorkspaceName, boolean bestEffort)
+            throws RepositoryException {
+
+        return repositoryService.merge(sessionInfo, nodeId, srcWorkspaceName, bestEffort);
+    }
+
+    public void resolveMergeConflict(SessionInfo sessionInfo, NodeId nodeId, NodeId[] mergeFailedIds,
+            NodeId[] predecessorIds) throws RepositoryException {
+
+        repositoryService.resolveMergeConflict(sessionInfo, nodeId, mergeFailedIds, predecessorIds);
+    }
+
+    public void addVersionLabel(SessionInfo sessionInfo, NodeId versionHistoryId, NodeId versionId,
+            Name label, boolean moveLabel) throws RepositoryException {
+
+        addVersionLabel(sessionInfo, versionHistoryId, versionId, label, moveLabel);
+    }
+
+    public void removeVersionLabel(SessionInfo sessionInfo, NodeId versionHistoryId, NodeId versionId,
+            Name label) throws RepositoryException {
+
+        repositoryService.removeVersionLabel(sessionInfo, versionHistoryId, versionId, label);
+    }
+
+
+    //----------------------------------------------------------< Searching >---
+
+    public String[] getSupportedQueryLanguages(SessionInfo sessionInfo) throws RepositoryException {
+        return repositoryService.getSupportedQueryLanguages(sessionInfo);
+    }
+
+
+    public void checkQueryStatement(SessionInfo sessionInfo, String statement, String language,
+            Map namespaces) throws RepositoryException {
+
+        repositoryService.checkQueryStatement(sessionInfo, statement, language, namespaces);
+    }
+
+    public QueryInfo executeQuery(SessionInfo sessionInfo, String statement, String language,
+            Map namespaces) throws RepositoryException {
+
+        return repositoryService.executeQuery(sessionInfo, statement, language, namespaces);
+    }
+
+
+    //--------------------------------------------------------< Observation >---
+
+    public EventFilter createEventFilter(SessionInfo sessionInfo, int eventTypes, Path absPath,
+            boolean isDeep, String[] uuid, Name[] nodeTypeName, boolean noLocal) throws RepositoryException {
+
+        return repositoryService.createEventFilter(sessionInfo, eventTypes, absPath, isDeep, uuid, nodeTypeName, noLocal);
+    }
+
+    public Subscription createSubscription(SessionInfo sessionInfo, EventFilter[] filters)
+            throws RepositoryException {
+
+        return repositoryService.createSubscription(sessionInfo, filters);
+    }
+
+    public void updateEventFilters(Subscription subscription, EventFilter[] filters)
+            throws RepositoryException {
+
+        repositoryService.updateEventFilters(subscription, filters);
+    }
+
+    public EventBundle[] getEvents(Subscription subscription, long timeout) throws RepositoryException,
+            InterruptedException {
+
+        return repositoryService.getEvents(subscription, timeout);
+    }
+
+    public void dispose(Subscription subscription) throws RepositoryException {
+        repositoryService.dispose(subscription);
+    }
+
+
+    //---------------------------------------------------------< Namespaces >---
+
+    public Map getRegisteredNamespaces(SessionInfo sessionInfo) throws RepositoryException {
+        return repositoryService.getRegisteredNamespaces(sessionInfo);
+    }
+
+    public String getNamespaceURI(SessionInfo sessionInfo, String prefix)
+            throws RepositoryException {
+
+        return repositoryService.getNamespaceURI(sessionInfo, prefix);
+    }
+
+    public String getNamespacePrefix(SessionInfo sessionInfo, String uri)
+            throws RepositoryException {
+
+        return repositoryService.getNamespacePrefix(sessionInfo, uri);
+    }
+
+    public void registerNamespace(SessionInfo sessionInfo, String prefix, String uri)
+            throws RepositoryException {
+
+        repositoryService.registerNamespace(sessionInfo, prefix, uri);
+    }
+
+    public void unregisterNamespace(SessionInfo sessionInfo, String uri) throws RepositoryException {
+        repositoryService.unregisterNamespace(sessionInfo, uri);
+    }
+
+
+    //----------------------------------------------------------< NodeTypes >---
+
+    public Iterator getQNodeTypeDefinitions(SessionInfo sessionInfo) throws RepositoryException {
+        return repositoryService.getQNodeTypeDefinitions(sessionInfo);
+    }
+
+    public Iterator getQNodeTypeDefinitions(SessionInfo sessionInfo, Name[] nodeTypeNames)
+            throws RepositoryException {
+
+        return repositoryService.getQNodeTypeDefinitions(sessionInfo, nodeTypeNames);
+    }
+
+}

Propchange: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/AbstractJCR2SPITest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/AbstractRepositoryService.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/AbstractRepositoryService.java?rev=794012&view=auto
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/AbstractRepositoryService.java (added)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/AbstractRepositoryService.java Tue Jul 14 18:48:04 2009
@@ -0,0 +1,550 @@
+/*
+ * 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 java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Credentials;
+import javax.jcr.NamespaceException;
+import javax.jcr.RangeIterator;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.UnsupportedRepositoryOperationException;
+
+import org.apache.commons.collections.iterators.EmptyIterator;
+import org.apache.commons.collections.iterators.ObjectArrayIterator;
+import org.apache.jackrabbit.commons.iterator.RangeIteratorAdapter;
+import org.apache.jackrabbit.spi.Batch;
+import org.apache.jackrabbit.spi.EventBundle;
+import org.apache.jackrabbit.spi.EventFilter;
+import org.apache.jackrabbit.spi.IdFactory;
+import org.apache.jackrabbit.spi.ItemId;
+import org.apache.jackrabbit.spi.LockInfo;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.NameFactory;
+import org.apache.jackrabbit.spi.NodeId;
+import org.apache.jackrabbit.spi.NodeInfo;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.PathFactory;
+import org.apache.jackrabbit.spi.PropertyId;
+import org.apache.jackrabbit.spi.PropertyInfo;
+import org.apache.jackrabbit.spi.QNodeDefinition;
+import org.apache.jackrabbit.spi.QNodeTypeDefinition;
+import org.apache.jackrabbit.spi.QPropertyDefinition;
+import org.apache.jackrabbit.spi.QValueFactory;
+import org.apache.jackrabbit.spi.QueryInfo;
+import org.apache.jackrabbit.spi.RepositoryService;
+import org.apache.jackrabbit.spi.SessionInfo;
+import org.apache.jackrabbit.spi.Subscription;
+import org.apache.jackrabbit.spi.commons.SessionInfoImpl;
+import org.apache.jackrabbit.spi.commons.identifier.IdFactoryImpl;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
+import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
+import org.apache.jackrabbit.spi.commons.namespace.NamespaceMapping;
+import org.apache.jackrabbit.spi.commons.nodetype.compact.CompactNodeTypeDefReader;
+import org.apache.jackrabbit.spi.commons.nodetype.compact.ParseException;
+import org.apache.jackrabbit.spi.commons.nodetype.compact.QNodeTypeDefinitionsBuilderImpl;
+import org.apache.jackrabbit.spi.commons.value.QValueFactoryImpl;
+
+/**
+ * This {@link RepositoryService} implementation can serve as a starting point
+ * for mock implementation for testing purposes.
+ */
+public abstract class AbstractRepositoryService implements RepositoryService {
+    private final NamespaceMapping namespaces = new NamespaceMapping();
+    private final NodeTypeRegistry nodeTypes = new NodeTypeRegistry();
+
+    public AbstractRepositoryService() throws RepositoryException {
+        super();
+        registerNodeTypes();
+    }
+
+    protected void registerNodeTypes() throws RepositoryException {
+        String resourceName = "default-nodetypes.cnd";
+        InputStream is = AbstractRepositoryService.class.getResourceAsStream(resourceName);
+        if (is == null) {
+            throw new RepositoryException(("Resource not found: " + resourceName));
+        }
+
+        Reader reader = new InputStreamReader(new BufferedInputStream(is));
+        try {
+            CompactNodeTypeDefReader cndReader = new CompactNodeTypeDefReader(reader,
+                    "spi2mock", namespaces, new QNodeTypeDefinitionsBuilderImpl());
+
+            for (Iterator ntDefs = cndReader.getNodeTypeDefs().iterator(); ntDefs.hasNext(); ) {
+                nodeTypes.register((QNodeTypeDefinition) ntDefs.next());
+            }
+        }
+        catch (ParseException e) {
+            throw new RepositoryException(e);
+        }
+        finally {
+            try {
+                reader.close();
+            }
+            catch (IOException e) {
+                throw new RepositoryException("Error closing stream", e);
+            }
+        }
+    }
+
+
+    // -----------------------------------------------------< RepositoryService >---
+
+    public IdFactory getIdFactory() throws RepositoryException {
+        return IdFactoryImpl.getInstance();
+    }
+
+    public NameFactory getNameFactory() throws RepositoryException {
+        return NameFactoryImpl.getInstance();
+    }
+
+    public PathFactory getPathFactory() throws RepositoryException {
+        return PathFactoryImpl.getInstance();
+    }
+
+    public QValueFactory getQValueFactory() throws RepositoryException {
+        return QValueFactoryImpl.getInstance();
+    }
+
+    public Map getRepositoryDescriptors() throws RepositoryException {
+        Map descriptorKeys = new HashMap();
+
+        descriptorKeys.put(Repository.LEVEL_1_SUPPORTED, Boolean.TRUE.toString());
+        descriptorKeys.put(Repository.LEVEL_2_SUPPORTED, Boolean.FALSE.toString());
+        descriptorKeys.put(Repository.OPTION_LOCKING_SUPPORTED, Boolean.FALSE.toString());
+        descriptorKeys.put(Repository.OPTION_OBSERVATION_SUPPORTED, Boolean.FALSE.toString());
+        descriptorKeys.put(Repository.OPTION_QUERY_SQL_SUPPORTED, Boolean.FALSE.toString());
+        descriptorKeys.put(Repository.OPTION_TRANSACTIONS_SUPPORTED, Boolean.FALSE.toString());
+        descriptorKeys.put(Repository.OPTION_VERSIONING_SUPPORTED, Boolean.FALSE.toString());
+        descriptorKeys.put(Repository.QUERY_XPATH_DOC_ORDER, Boolean.FALSE.toString());
+        descriptorKeys.put(Repository.QUERY_XPATH_POS_INDEX, Boolean.FALSE.toString());
+        descriptorKeys.put(Repository.REP_NAME_DESC, "Mock Repository");
+        descriptorKeys.put(Repository.REP_VENDOR_DESC, "Apache Software Foundation");
+        descriptorKeys.put(Repository.REP_VENDOR_URL_DESC, "http://www.apache.org/");
+        descriptorKeys.put(Repository.REP_VERSION_DESC, "1.0");
+        descriptorKeys.put(Repository.SPEC_NAME_DESC, "Content Repository API for Java(TM) Technology Specification");
+        descriptorKeys.put(Repository.SPEC_VERSION_DESC, "1.0");
+
+        return descriptorKeys;
+    }
+
+
+    //-----------------------------------< SessionInfo creation and release >---
+
+    public SessionInfo obtain(Credentials credentials, String workspaceName) throws RepositoryException {
+        SessionInfoImpl si = new SessionInfoImpl();
+        si.setWorkspacename(workspaceName);
+        if (credentials instanceof SimpleCredentials) {
+            si.setUserID(((SimpleCredentials) credentials).getUserID());
+        }
+
+        return si;
+    }
+
+    public SessionInfo obtain(SessionInfo sessionInfo, String workspaceName) throws RepositoryException {
+        SessionInfoImpl si = new SessionInfoImpl();
+        si.setWorkspacename(workspaceName);
+        if (sessionInfo instanceof SessionImpl) {
+            si.setUserID(((SessionImpl) sessionInfo).getUserID());
+        }
+        return si;
+    }
+
+    public SessionInfo impersonate(SessionInfo sessionInfo, Credentials credentials)
+            throws RepositoryException {
+
+        SessionInfoImpl si = new SessionInfoImpl();
+        if (credentials instanceof SimpleCredentials) {
+            si.setUserID(((SimpleCredentials) credentials).getUserID());
+        }
+        if (sessionInfo instanceof SessionImpl) {
+            si.setUserID(((SessionImpl) sessionInfo).getUserID());
+        }
+
+        return si;
+    }
+
+    public void dispose(SessionInfo sessionInfo) throws RepositoryException {
+        // empty
+    }
+
+    public String[] getWorkspaceNames(SessionInfo sessionInfo) throws RepositoryException {
+        return new String [] { "default" };
+    }
+
+
+    //-----------------------------------------------------< Access Control >---
+
+    public boolean isGranted(SessionInfo sessionInfo, ItemId itemId, String[] actions)
+            throws RepositoryException {
+
+        return true;
+    }
+
+
+    //------------------------------------------------------< Reading items >---
+
+    public QNodeDefinition getNodeDefinition(SessionInfo sessionInfo, NodeId nodeId)
+            throws RepositoryException {
+
+        QNodeTypeDefinition ntd = nodeTypes.getQNodeTypeDefinition(NameConstants.NT_UNSTRUCTURED);
+        QNodeDefinition[] nds = ntd.getChildNodeDefs();
+        for (int k = 0; k < nds.length; k++) {
+            QNodeDefinition nd = nds[k];
+            if (NameConstants.ANY_NAME.equals(nd.getName())) {
+                return nd;
+            }
+        }
+
+        throw new IllegalStateException(("No node definition for " + nodeId));
+    }
+
+    public QPropertyDefinition getPropertyDefinition(SessionInfo sessionInfo, PropertyId propertyId)
+            throws RepositoryException {
+
+        QNodeTypeDefinition ntd = nodeTypes.getQNodeTypeDefinition(NameConstants.NT_UNSTRUCTURED);
+        QPropertyDefinition[] pds = ntd.getPropertyDefs();
+        for (int k = 0; k < pds.length; k++) {
+            QPropertyDefinition pd = pds[k];
+            if (NameConstants.ANY_NAME.equals(pd)) {
+                return pd;
+            }
+        }
+
+        throw new IllegalStateException(("No property definition for " + propertyId));
+    }
+
+    public abstract NodeInfo getNodeInfo(SessionInfo sessionInfo, NodeId nodeId) throws RepositoryException;
+
+    public abstract Iterator getItemInfos(SessionInfo sessionInfo, NodeId nodeId) throws RepositoryException;
+
+    public abstract Iterator getChildInfos(SessionInfo sessionInfo, NodeId parentId) throws RepositoryException;
+
+    public abstract PropertyInfo getPropertyInfo(SessionInfo sessionInfo, PropertyId propertyId);
+
+    //-----------------------------------------------< general modification >---
+
+    public Batch createBatch(SessionInfo sessionInfo, ItemId itemId) throws RepositoryException {
+        throw new UnsupportedRepositoryOperationException("JCR Level 2 not supported");
+    }
+
+    public void submit(Batch batch) throws RepositoryException {
+        throw new UnsupportedRepositoryOperationException("JCR Level 2 not supported");
+    }
+
+
+    //-------------------------------------------------------------< Import >---
+
+    public void importXml(SessionInfo sessionInfo, NodeId parentId, InputStream xmlStream, int uuidBehaviour)
+            throws RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("JCR Level 2 not supported");
+    }
+
+
+    //---------------------------------------------------------< Copy, Move >---
+
+    public void move(SessionInfo sessionInfo, NodeId srcNodeId, NodeId destParentNodeId, Name destName)
+            throws RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("JCR Level 2 not supported");
+    }
+
+    public void copy(SessionInfo sessionInfo, String srcWorkspaceName, NodeId srcNodeId,
+            NodeId destParentNodeId, Name destName) throws RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("JCR Level 2 not supported");
+    }
+
+
+    //------------------------------------------------------< Update, Clone >---
+
+    public void update(SessionInfo sessionInfo, NodeId nodeId, String srcWorkspaceName)
+            throws RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("JCR Level 2 not supported");
+    }
+
+    public void clone(SessionInfo sessionInfo, String srcWorkspaceName, NodeId srcNodeId,
+            NodeId destParentNodeId, Name destName, boolean removeExisting) throws RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("JCR Level 2 not supported");
+    }
+
+
+    //------------------------------------------------------------< Locking >---
+
+    public LockInfo getLockInfo(SessionInfo sessionInfo, NodeId nodeId) throws RepositoryException {
+        throw new UnsupportedRepositoryOperationException("Locking not supported");
+    }
+
+    public LockInfo lock(SessionInfo sessionInfo, NodeId nodeId, boolean deep, boolean sessionScoped)
+            throws RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("Locking not supported");
+    }
+
+    public void refreshLock(SessionInfo sessionInfo, NodeId nodeId)
+            throws RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("Locking not supported");
+    }
+
+    public void unlock(SessionInfo sessionInfo, NodeId nodeId)
+            throws  RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("Locking not supported");
+    }
+
+
+    //---------------------------------------------------------< Versioning >---
+
+    public NodeId checkin(SessionInfo sessionInfo, NodeId nodeId) throws RepositoryException {
+        throw new UnsupportedRepositoryOperationException("Versioning not supported");
+    }
+
+    public void checkout(SessionInfo sessionInfo, NodeId nodeId) throws RepositoryException {
+        throw new UnsupportedRepositoryOperationException("Versioning not supported");
+    }
+
+    public void removeVersion(SessionInfo sessionInfo, NodeId versionHistoryId, NodeId versionId)
+            throws RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("Versioning not supported");
+    }
+
+    public void restore(SessionInfo sessionInfo, NodeId[] versionIds, boolean removeExisting)
+            throws RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("Versioning not supported");
+    }
+
+    public void restore(SessionInfo sessionInfo, NodeId nodeId, NodeId versionId, boolean removeExisting)
+            throws RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("Versioning not supported");
+    }
+
+    public Iterator merge(SessionInfo sessionInfo, NodeId nodeId, String srcWorkspaceName, boolean bestEffort)
+            throws RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("Versioning not supported");
+    }
+
+    public void resolveMergeConflict(SessionInfo sessionInfo, NodeId nodeId, NodeId[] mergeFailedIds,
+            NodeId[] predecessorIds) throws RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("Versioning not supported");
+    }
+
+    public void addVersionLabel(SessionInfo sessionInfo, NodeId versionHistoryId, NodeId versionId,
+            Name label, boolean moveLabel) throws RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("Versioning not supported");
+    }
+
+    public void removeVersionLabel(SessionInfo sessionInfo, NodeId versionHistoryId, NodeId versionId,
+            Name label) throws RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("Versioning not supported");
+    }
+
+
+    //----------------------------------------------------------< Searching >---
+
+    public String[] getSupportedQueryLanguages(SessionInfo sessionInfo) throws RepositoryException {
+        return new String[] {};
+    }
+
+
+    public void checkQueryStatement(SessionInfo sessionInfo, String statement, String language,
+            Map namespaces) throws RepositoryException {
+
+        // empty
+    }
+
+    public QueryInfo executeQuery(SessionInfo sessionInfo, String statement, String language,
+            Map namespaces) throws RepositoryException {
+
+        return new QueryInfo() {
+            public Name[] getColumnNames() {
+                return new Name[] {};
+            }
+
+            public RangeIterator getRows() {
+                return new RangeIteratorAdapter(EmptyIterator.INSTANCE);
+            }
+        };
+    }
+
+
+    //--------------------------------------------------------< Observation >---
+
+    public EventFilter createEventFilter(SessionInfo sessionInfo, int eventTypes, Path absPath,
+            boolean isDeep, String[] uuid, Name[] nodeTypeName, boolean noLocal) throws RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("Observation not supported");
+    }
+
+    public Subscription createSubscription(SessionInfo sessionInfo, EventFilter[] filters)
+            throws RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("Observation not supported");
+    }
+
+    public void updateEventFilters(Subscription subscription, EventFilter[] filters)
+            throws RepositoryException {
+
+        throw new UnsupportedRepositoryOperationException("Observation not supported");
+    }
+
+    public EventBundle[] getEvents(Subscription subscription, long timeout) throws RepositoryException,
+            InterruptedException {
+
+        throw new UnsupportedRepositoryOperationException("Observation not supported");
+    }
+
+    public void dispose(Subscription subscription) throws RepositoryException {
+        throw new UnsupportedRepositoryOperationException("Observation not supported");
+    }
+
+
+    //---------------------------------------------------------< Namespaces >---
+
+    public Map getRegisteredNamespaces(SessionInfo sessionInfo) throws RepositoryException {
+        return namespaces.getPrefixToURIMapping();
+    }
+
+    public String getNamespaceURI(SessionInfo sessionInfo, String prefix)
+            throws RepositoryException {
+
+        return namespaces.getURI(prefix);
+    }
+
+    public String getNamespacePrefix(SessionInfo sessionInfo, String uri)
+            throws RepositoryException {
+
+        return namespaces.getPrefix(uri);
+    }
+
+    public void registerNamespace(SessionInfo sessionInfo, String prefix, String uri)
+            throws RepositoryException {
+
+        throw new NamespaceException("Cannot register " + uri);
+    }
+
+    public void unregisterNamespace(SessionInfo sessionInfo, String uri) throws RepositoryException {
+        throw new NamespaceException("Cannot register " + uri);
+    }
+
+
+    //----------------------------------------------------------< NodeTypes >---
+
+    public Iterator getQNodeTypeDefinitions(SessionInfo sessionInfo) throws RepositoryException {
+        return new ObjectArrayIterator(nodeTypes.getQNodeTypeDefinitions());
+    }
+
+    public Iterator getQNodeTypeDefinitions(SessionInfo sessionInfo, Name[] nodeTypeNames)
+            throws RepositoryException {
+
+        return new ObjectArrayIterator(nodeTypes.getQNodeTypeDefinitions(nodeTypeNames));
+    }
+
+}
+
+/**
+ * Registry for {@link QNodeTypeDefinition}s. Registered node type definitions can be retrieved by
+ * its name.
+ */
+class NodeTypeRegistry {
+    private final Map definitions = new HashMap();
+
+    /**
+     * Register the given {@link QNodeTypeDefinition} by its name. Registering a node type
+     * definition with a name already in use effectively removes the old definition from the
+     * registry.
+     *
+     * @param nodeTypeDef
+     * @throws IllegalArgumentException if <code>nodeTypeDef</code> is null
+     */
+    public void register(QNodeTypeDefinition nodeTypeDef)  {
+        if (nodeTypeDef == null) {
+            throw new IllegalArgumentException("Cannot register null");
+        }
+
+        definitions.put(nodeTypeDef.getName(), nodeTypeDef);
+    }
+
+    /**
+     * Returns an array of {@link QNodeTypeDefinition}s for the given <code>names</code>.
+     *
+     * @param names Names of the node type definition to look up. If <code>null</code> is passed,
+     *                all registered node types are returned.
+     * @return
+     * @throws RepositoryException If no node type definition is registered for any name in
+     *                 <code>names</code>.
+     */
+    public QNodeTypeDefinition[] getQNodeTypeDefinitions(Name[] names) throws RepositoryException {
+        if (names == null) {
+            return getQNodeTypeDefinitions();
+        }
+
+        List defs = new LinkedList();
+        for (int k = 0; k < names.length; k++) {
+            Object def = definitions.get(names[k]);
+            if (def == null) {
+                throw new RepositoryException(("No such node type definition: " + names[k]));
+            }
+
+            defs.add(def);
+        }
+
+        return (QNodeTypeDefinition[]) defs.toArray(new QNodeTypeDefinition[defs.size()]);
+    }
+
+    /**
+     * Returns the {@link QNodeTypeDefinition} registered with the given name or null if none is
+     * registered.
+     *
+     * @param name
+     * @return
+     */
+    public QNodeTypeDefinition getQNodeTypeDefinition(Name name) {
+        return (QNodeTypeDefinition) definitions.get(name);
+    }
+
+    /**
+     * @return array of all registered {@link QNodeTypeDefinition}s.
+     */
+    public QNodeTypeDefinition[] getQNodeTypeDefinitions() {
+        return (QNodeTypeDefinition[]) definitions.values().toArray(new QNodeTypeDefinition[0]);
+    }
+
+}
+

Propchange: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/AbstractRepositoryService.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/GetItemsTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/GetItemsTest.java?rev=794012&view=auto
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/GetItemsTest.java (added)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/GetItemsTest.java Tue Jul 14 18:48:04 2009
@@ -0,0 +1,367 @@
+package org.apache.jackrabbit.jcr2spi;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.Item;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.collections.Predicate;
+import org.apache.commons.collections.Transformer;
+import org.apache.commons.collections.functors.NotPredicate;
+import org.apache.commons.collections.iterators.EmptyIterator;
+import org.apache.commons.collections.iterators.FilterIterator;
+import org.apache.commons.collections.iterators.IteratorChain;
+import org.apache.commons.collections.iterators.TransformIterator;
+import org.apache.jackrabbit.spi.ItemInfo;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.NodeId;
+import org.apache.jackrabbit.spi.NodeInfo;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.PropertyId;
+import org.apache.jackrabbit.spi.PropertyInfo;
+import org.apache.jackrabbit.spi.QValue;
+import org.apache.jackrabbit.spi.RepositoryService;
+import org.apache.jackrabbit.spi.SessionInfo;
+import org.apache.jackrabbit.spi.Path.Element;
+import org.apache.jackrabbit.spi.commons.ChildInfoImpl;
+import org.apache.jackrabbit.spi.commons.NodeInfoImpl;
+import org.apache.jackrabbit.spi.commons.PropertyInfoImpl;
+import org.apache.jackrabbit.spi.commons.identifier.IdFactoryImpl;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
+import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
+import org.apache.jackrabbit.spi.commons.value.QValueFactoryImpl;
+
+/**
+ * Test cases for {@link RepositoryService#getItemInfos(SessionInfo, NodeId)}. Sepcifically
+ * for JCR-1797.
+ */
+public class GetItemsTest extends AbstractJCR2SPITest {
+    private List itemInfos;
+    private Session session;
+
+    public void setUp() throws Exception {
+        super.setUp();
+        itemInfos = new ArrayList();
+
+        // build up a hierarchy of items
+        new NodeInfoBuilder()
+            .createNodeInfo("node1")
+                .createNodeInfo("node11").build(itemInfos)
+                .createNodeInfo("node12").build(itemInfos)
+                .createNodeInfo("node13").build(itemInfos)
+                .createPropertyInfo("property11", "value11").build(itemInfos)
+                .createPropertyInfo("property12", "value12").build(itemInfos)
+            .build(itemInfos)
+            .createNodeInfo("node2")
+                .createNodeInfo("node21")
+                    .createNodeInfo("node211")
+                        .createNodeInfo("node2111")
+                            .createNodeInfo("node21111")
+                                .createNodeInfo("node211111")
+                                    .createNodeInfo("node2111111").build(itemInfos)
+                                .build(itemInfos)
+                            .build(itemInfos)
+                        .build(itemInfos)
+                    .build(itemInfos)
+                .build(itemInfos)
+            .build(itemInfos)
+            .createNodeInfo("node3").build(itemInfos)
+            .build(itemInfos);
+
+        session = repository.login();
+    }
+
+    private Iterable itemInfosProvider;
+
+    /**
+     * Check whether we can traverse the hierarchy when the item infos are returned in their
+     * canonical order.
+     * @throws RepositoryException
+     */
+    public void testGetItemInfos() throws RepositoryException {
+        itemInfosProvider = new Iterable() {
+            public Iterator iterator() {
+                return itemInfos.iterator();
+            }
+        };
+
+        checkHierarchy();
+    }
+
+    /**
+     * Check whether we can traverse the hierarchy when the item info for root is
+     * returned first.
+     * @throws RepositoryException
+     */
+    public void testGetItemInfosRootFirst() throws RepositoryException {
+        itemInfosProvider = new Iterable() {
+
+            public Iterator iterator() {
+                Predicate isRoot = new Predicate() {
+                    public boolean evaluate(Object object) {
+                        ItemInfo itemInfo = (ItemInfo) object;
+                        return itemInfo.getPath().denotesRoot();
+                    }
+                };
+
+                return new IteratorChain(
+                    new FilterIterator(itemInfos.iterator(), isRoot),
+                    new FilterIterator(itemInfos.iterator(), NotPredicate.getInstance(isRoot)));
+            }
+        };
+
+        assertTrue(session.getRootNode().getDepth() == 0);
+        checkHierarchy();
+    }
+
+    /**
+     * Check whether we can traverse the hierarchy when the item info for root is
+     * returned last.
+     * @throws RepositoryException
+     */
+    public void testGetItemInfosRootLast() throws RepositoryException {
+        itemInfosProvider = new Iterable() {
+
+            public Iterator iterator() {
+                Predicate isRoot = new Predicate() {
+                    public boolean evaluate(Object object) {
+                        ItemInfo itemInfo = (ItemInfo) object;
+                        return itemInfo.getPath().denotesRoot();
+                    }
+                };
+
+                return new IteratorChain(
+                    new FilterIterator(itemInfos.iterator(), NotPredicate.getInstance(isRoot)),
+                    new FilterIterator(itemInfos.iterator(), isRoot));
+            }
+        };
+
+        assertTrue(session.getRootNode().getDepth() == 0);
+        checkHierarchy();
+    }
+
+    private void checkHierarchy() throws PathNotFoundException, RepositoryException, ItemNotFoundException,
+            AccessDeniedException {
+        for (Iterator itemInfos = itemInfosProvider.iterator(); itemInfos.hasNext();) {
+            ItemInfo itemInfo = (ItemInfo) itemInfos.next();
+            String jcrPath = toJCRPath(itemInfo.getPath());
+            Item item = session.getItem(jcrPath);
+            assertEquals(jcrPath, item.getPath());
+
+            if (item.getDepth() > 0) {
+                Node parent = item.getParent();
+                if (item.isNode()) {
+                    assertEquals(item, parent.getNode(item.getName()));
+                }
+                else {
+                    assertEquals(item, parent.getProperty(item.getName()));
+                }
+            }
+
+        }
+    }
+
+    private static String toJCRPath(Path path) {
+        Element[] elems = path.getElements();
+        StringBuffer jcrPath = new StringBuffer();
+
+        for (int k = 0; k < elems.length; k++) {
+            jcrPath.append(elems[k].getName().getLocalName());
+            if (k + 1 < elems.length || elems.length == 1) {
+                jcrPath.append('/');
+            }
+        }
+
+        return jcrPath.toString();
+    }
+
+    public Iterator getChildInfos(SessionInfo sessionInfo, NodeId parentId) throws RepositoryException {
+        fail("Not implemented");
+        return null;
+    }
+
+    public Iterator getItemInfos(SessionInfo sessionInfo, NodeId nodeId) throws RepositoryException {
+        return itemInfosProvider.iterator();
+    }
+
+    public NodeInfo getNodeInfo(SessionInfo sessionInfo, NodeId nodeId) throws RepositoryException {
+        fail("Not implemented");
+        return null;
+    }
+
+    public PropertyInfo getPropertyInfo(SessionInfo sessionInfo, PropertyId propertyId) {
+        fail("Not implemented");
+        return null;
+    }
+
+    interface Iterable {
+        public Iterator iterator();
+    }
+
+    /**
+     * todo: we might want to grow this in a full blown helper class
+     */
+    class NodeInfoBuilder {
+        private final NodeInfoBuilder parent;
+        private final String name;
+
+        protected boolean stale;
+        private final List itemInfos = new ArrayList();
+        private NodeInfo nodeInfo;
+
+        public NodeInfoBuilder() {
+            this(null, null);
+        }
+
+        public NodeInfoBuilder(NodeInfoBuilder nodeInfoBuilder, String name) {
+            super();
+            parent = nodeInfoBuilder;
+            this.name = name;
+        }
+
+        public PropertyInfoBuilder createPropertyInfo(String name, String value) {
+            return new PropertyInfoBuilder(this, name, value);
+        }
+
+        public NodeInfoBuilder createNodeInfo(String name) {
+            return new NodeInfoBuilder(this, name);
+        }
+
+        public NodeInfoBuilder build(List infos) throws RepositoryException {
+            if (stale) {
+                throw new IllegalStateException("Builder is stale");
+            }
+            else {
+                stale = true;
+
+                NodeId id = getId();
+                Path path = id.getPath();
+
+                Iterator propertyIds = new TransformIterator(new FilterIterator(itemInfos.iterator(),
+                        new Predicate() {
+                            public boolean evaluate(Object object) {
+                                return object instanceof PropertyInfo;
+                            }
+                        }),
+                        new Transformer() {
+                            public Object transform(Object input) {
+                                PropertyInfo info = (PropertyInfo) input;
+                                return info.getId();
+                            }});
+
+                Iterator childInfos = new TransformIterator(itemInfos.iterator(), new Transformer(){
+                    public Object transform(Object input) {
+                        ItemInfo info = (ItemInfo) input;
+                        Name name = info.getPath().getNameElement().getName();
+                        return new ChildInfoImpl(name, null, Path.INDEX_DEFAULT);
+                    }});
+
+                nodeInfo = new NodeInfoImpl(path, id, Path.INDEX_DEFAULT, NameConstants.NT_UNSTRUCTURED,
+                        Name.EMPTY_ARRAY, EmptyIterator.INSTANCE, propertyIds, childInfos);
+
+                if (infos != null) {
+                    infos.add(nodeInfo);
+                }
+
+                if (parent == null) {
+                    return this;
+                }
+                else {
+                    parent.addNodeInfo(nodeInfo);
+                    return parent;
+                }
+            }
+        }
+
+        public NodeInfo getNodeInfo() throws RepositoryException {
+            if (!stale) {
+                build(null);
+            }
+            return nodeInfo;
+        }
+
+        NodeInfoBuilder addPropertyInfo(PropertyInfo propertyInfo) {
+            itemInfos.add(propertyInfo);
+            return this;
+        }
+
+        NodeInfoBuilder addNodeInfo(NodeInfo nodeInfo) {
+            itemInfos.add(nodeInfo);
+            return this;
+        }
+
+        NodeId getId() throws RepositoryException {
+            return IdFactoryImpl.getInstance().createNodeId((String) null, getPath());
+        }
+
+        Path getPath() throws RepositoryException {
+            if (parent == null) {
+                return PathFactoryImpl.getInstance().getRootPath();
+            }
+            else {
+                Name name = NameFactoryImpl.getInstance().create(Name.NS_DEFAULT_URI, this.name);
+                return PathFactoryImpl.getInstance().create(parent.getPath(), name, true);
+            }
+        }
+
+    }
+
+    /**
+     * todo: we might want to grow this in a full blown helper class
+     */
+    class PropertyInfoBuilder {
+        private final NodeInfoBuilder parent;
+        private final String name;
+        private final String value;
+
+        private boolean stale;
+        private PropertyInfo propertyInfo;
+
+        public PropertyInfoBuilder(NodeInfoBuilder nodeInfoBuilder, String name, String value) {
+            super();
+            parent = nodeInfoBuilder;
+            this.name = name;
+            this.value = value;
+        }
+
+        public NodeInfoBuilder build(List infos) throws RepositoryException {
+            if (parent == null) {
+                return null;
+            }
+
+            if (stale) {
+                throw new IllegalStateException("Builder is stale");
+            }
+            else {
+                stale = true;
+
+                NodeId parentId = parent.getId();
+                Name propertyName = NameFactoryImpl.getInstance().create(Name.NS_DEFAULT_URI, this.name);
+                Path path = PathFactoryImpl.getInstance().create(parentId.getPath(), propertyName, true);
+                PropertyId id = IdFactoryImpl.getInstance().createPropertyId(parentId, propertyName);
+                QValue qvalue = QValueFactoryImpl.getInstance().create(value, PropertyType.STRING);
+                propertyInfo = new PropertyInfoImpl(path, id, PropertyType.STRING, false, new QValue[] { qvalue });
+
+                if (infos != null) {
+                    infos.add(propertyInfo);
+                }
+                return parent.addPropertyInfo(propertyInfo);
+            }
+        }
+
+        public PropertyInfo getPropertyInfo() {
+            return propertyInfo;
+        }
+
+    }
+
+}

Propchange: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/GetItemsTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/TestAll.java?rev=794012&r1=794011&r2=794012&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/TestAll.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/java/org/apache/jackrabbit/jcr2spi/TestAll.java Tue Jul 14 18:48:04 2009
@@ -19,6 +19,7 @@
 import junit.framework.Test;
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -34,6 +35,7 @@
         TestSuite suite = new TestSuite("jcr2spi tests");
 
         suite.addTestSuite(AccessByRelativePathTest.class);
+        suite.addTestSuite(GetItemsTest.class);
 
         // get node(s)
         suite.addTestSuite(SNSIndexTest.class);
@@ -85,7 +87,7 @@
         suite.addTestSuite(ReorderNewAndSavedTest.class);
         suite.addTestSuite(ReorderMixedTest.class);
         suite.addTestSuite(ReorderMoveTest.class);
-        
+
         // update
         suite.addTestSuite(UpdateTest.class);
 
@@ -98,7 +100,7 @@
 
         // repository
         suite.addTestSuite(LoginTest.class);
-        
+
         return suite;
     }
 }
\ No newline at end of file

Added: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/resources/org/apache/jackrabbit/jcr2spi/default-nodetypes.cnd
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/resources/org/apache/jackrabbit/jcr2spi/default-nodetypes.cnd?rev=794012&view=auto
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/resources/org/apache/jackrabbit/jcr2spi/default-nodetypes.cnd (added)
+++ jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/resources/org/apache/jackrabbit/jcr2spi/default-nodetypes.cnd Tue Jul 14 18:48:04 2009
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+<''=''>
+<rep='internal'>
+<jcr='http://www.jcp.org/jcr/1.0'>
+<xs='http://www.w3.org/2001/XMLSchema'>
+<nt='http://www.jcp.org/jcr/nt/1.0'>
+<mix='http://www.jcp.org/jcr/mix/1.0'>
+<crx='http://www.day.com/crx/1.0'>
+<sv='http://www.jcp.org/jcr/sv/1.0'>
+<xml='http://www.w3.org/XML/1998/namespace'>
+
+//------------------------------------------------------------------------------
+// B A S E  T Y P E S
+//------------------------------------------------------------------------------
+
+[nt:base]
+  - jcr:primaryType (name) mandatory autocreated protected compute
+  - jcr:mixinTypes (name) protected multiple compute
+
+[nt:unstructured] > nt:base
+  orderable
+  - * (undefined) multiple
+  - * (undefined)
+  + * (nt:base) = nt:unstructured multiple version
+
+[rep:root] > nt:unstructured
+

Propchange: jackrabbit/branches/1.5/jackrabbit-jcr2spi/src/test/resources/org/apache/jackrabbit/jcr2spi/default-nodetypes.cnd
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/branches/1.5/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/1.5/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java?rev=794012&r1=794011&r2=794012&view=diff
==============================================================================
--- jackrabbit/branches/1.5/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java (original)
+++ jackrabbit/branches/1.5/jackrabbit-spi/src/main/java/org/apache/jackrabbit/spi/RepositoryService.java Tue Jul 14 18:48:04 2009
@@ -261,20 +261,16 @@
     public NodeInfo getNodeInfo(SessionInfo sessionInfo, NodeId nodeId) throws ItemNotFoundException, RepositoryException;
 
     /**
-     * Method used to 'batch-read' from the persistent storage. It returns the
-     * <code>NodeInfo</code> for the given <code>NodeId</code> as the first
-     * element in the <code>Iterator</code>. In addition the iterator may contain
-     * child <code>ItemInfo</code>s down to a certain depth. The configuration
-     * process however is left to the implementation.
+     * Method used to 'batch-read' from the persistent storage. It must contain
+     * the <code>NodeInfo</code> for the given <code>NodeId</code> in the
+     * <code>Iterator</code>. In addition the iterator may contain arbitrary
+     * child <code>ItemInfo</code>s from the entire hierarchy.
      *
      * @param sessionInfo
      * @param nodeId
      * @return An <code>Iterator</code> of <code>ItemInfo</code>s containing
      * at least a single element: the <code>NodeInfo</code> that represents
-     * the Node identified by the given <code>NodeId</code>. If the Iterator
-     * contains multiple elements, the first is expected to represent the Node
-     * identified by the given <code>NodeId</code> and all subsequent elements
-     * must represent children of that <code>Node</code>.
+     * the Node identified by the given <code>NodeId</code>.
      * @throws javax.jcr.ItemNotFoundException
      * @throws javax.jcr.RepositoryException
      * @see javax.jcr.Session#getItem(String)



Mime
View raw message