jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mreut...@apache.org
Subject svn commit: r157120 - in incubator/jackrabbit/trunk: applications/test/ src/java/org/apache/jackrabbit/core/search/ src/java/org/apache/jackrabbit/core/search/lucene/ src/java/org/apache/jackrabbit/core/search/sql/ src/java/org/apache/jackrabbit/core/search/xpath/ src/test/org/apache/jackrabbit/core/ src/test/org/apache/jackrabbit/core/search/ src/test/org/apache/jackrabbit/init/ src/test/org/apache/jackrabbit/test/api/ src/test/org/apache/jackrabbit/test/api/query/
Date Fri, 11 Mar 2005 17:31:32 GMT
Author: mreutegg
Date: Fri Mar 11 09:31:27 2005
New Revision: 157120

URL: http://svn.apache.org/viewcvs?view=rev&rev=157120
Log:
Implement jcrfn:deref() function for XPath. Level 1 test cases for jcrfn:deref()

Added:
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/DerefQueryNode.java   (with props)
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/DerefQuery.java   (with props)
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/DerefQueryLevel1Test.java   (with props)
Modified:
    incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/DefaultQueryNodeVisitor.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNode.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNodeVisitor.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIndexer.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/QueryFormat.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/QueryFormat.java
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/JackrabbitRepositoryStub.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/search/FulltextQueryTest.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/init/NodeTestData.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/PropertyUtil.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/AbstractQueryTest.java
    incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/TestAll.java

Modified: incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties?view=diff&r1=157119&r2=157120
==============================================================================
--- incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties (original)
+++ incubator/jackrabbit/trunk/applications/test/repositoryStubImpl.properties Fri Mar 11 09:31:27 2005
@@ -271,6 +271,9 @@
 # Test class: SQLOrderByTest
 javax.jcr.tck.SQLOrderByTest.testroot=/testdata/query
 
+# Test class: DerefQueryLevel1Test
+javax.jcr.tck.DerefQueryLevel1Test.testroot=/testdata
+
 # ==============================================================================
 # JAVAX.JCR.VERSIONING CONFIGURATION
 # ==============================================================================

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/DefaultQueryNodeVisitor.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/DefaultQueryNodeVisitor.java?view=diff&r1=157119&r2=157120
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/DefaultQueryNodeVisitor.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/DefaultQueryNodeVisitor.java Fri Mar 11 09:31:27 2005
@@ -65,4 +65,8 @@
     public Object visit(OrderQueryNode node, Object data) {
         return data;
     }
+
+    public Object visit(DerefQueryNode node, Object data) {
+        return data;
+    }
 }

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/DerefQueryNode.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/DerefQueryNode.java?view=auto&rev=157120
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/DerefQueryNode.java (added)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/DerefQueryNode.java Fri Mar 11 09:31:27 2005
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.search;
+
+import org.apache.jackrabbit.core.QName;
+
+/**
+ * Represents query node that dereferences a reference property into a node and
+ * does an optional name test on the target node.
+ */
+public class DerefQueryNode extends LocationStepQueryNode {
+
+    /** The name of the reference property */
+    private QName refProperty;
+
+    /**
+     * Creates a new <code>DerefQueryNode</code> without a name set for the
+     * reference property.
+     * @param parent the parent query node.
+     * @param nameTest the name test on the target node, or <code>null</code>
+     *   if no name test should be performed on the target node.
+     * @param descendants if <code>true</code> this location step uses the
+     *   descendant-or-self axis; otherwise the child axis.
+     */
+    public DerefQueryNode(QueryNode parent, QName nameTest, boolean descendants) {
+        super(parent, nameTest, descendants);
+    }
+
+    /**
+     * Sets a new name for the reference property.
+     * @param propertyName the name of the reference property.
+     */
+    public void setRefProperty(QName propertyName) {
+        refProperty = propertyName;
+    }
+
+    /**
+     * Returns the name of the reference property or <code>null</code> if
+     * none is set.
+     * @return the name of the reference property or <code>null</code> if
+     * none is set.
+     */
+    public QName getRefProperty() {
+        return refProperty;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getType() {
+        return TYPE_DEREF;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object accept(QueryNodeVisitor visitor, Object data) {
+        return visitor.visit(this, data);
+    }
+}

Propchange: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/DerefQueryNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNode.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNode.java?view=diff&r1=157119&r2=157120
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNode.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNode.java Fri Mar 11 09:31:27 2005
@@ -56,6 +56,9 @@
     /** Type value for {@link PathQueryNode} */
     public static final int TYPE_PATH = 11;
 
+    /** Type value for {@link DerefQueryNode} */
+    public static final int TYPE_DEREF = 12;
+
     /**
      * References the parent of this <code>QueryNode</code>. If this is the root
      * of a query tree, then <code>parent</code> is <code>null</code>.

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNodeVisitor.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNodeVisitor.java?view=diff&r1=157119&r2=157120
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNodeVisitor.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/QueryNodeVisitor.java Fri Mar 11 09:31:27 2005
@@ -42,4 +42,6 @@
     public Object visit(RelationQueryNode node, Object data);
 
     public Object visit(OrderQueryNode node, Object data);
+
+    public Object visit(DerefQueryNode node, Object data);
 }

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/DerefQuery.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/DerefQuery.java?view=auto&rev=157120
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/DerefQuery.java (added)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/DerefQuery.java Fri Mar 11 09:31:27 2005
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.search.lucene;
+
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Scorer;
+import org.apache.lucene.search.Weight;
+import org.apache.lucene.search.Searcher;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.Explanation;
+import org.apache.lucene.search.Similarity;
+import org.apache.lucene.search.HitCollector;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermDocs;
+
+import java.io.IOException;
+import java.util.BitSet;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * Implements a lucene <code>Query</code> which returns the nodes selected by
+ * a reference property of the context node.
+ */
+class DerefQuery extends Query {
+
+    /**
+     * The context query
+     */
+    private final Query contextQuery;
+
+    /**
+     * The name of the reference property.
+     */
+    private final String refProperty;
+
+    /**
+     * The name of the reference property as multi value.
+     */
+    private final String refPropertyMV;
+
+    /**
+     * The nameTest to apply on target node, or <code>null</code> if all
+     * target nodes should be selected.
+     */
+    private final String nameTest;
+
+    /**
+     * The scorer of the context query
+     */
+    private Scorer contextScorer;
+
+    /**
+     * The scorer of the name test query
+     */
+    private Scorer nameTestScorer;
+
+    /**
+     * Creates a new <code>DerefQuery</code> based on a <code>context</code>
+     * query.
+     *
+     * @param context the context for this query.
+     * @param refProperty the name of the reference property.
+     * @param nameTest a name test or <code>null</code> if any node is
+     *  selected.
+     */
+    DerefQuery(Query context, String refProperty, String nameTest) {
+        this.contextQuery = context;
+        this.refProperty = refProperty;
+        String[] nameParts = refProperty.split(":");
+        this.refPropertyMV = nameParts[0] + ":" + FieldNames.MVP_PREFIX + nameParts[1];
+        this.nameTest = nameTest;
+    }
+
+    /**
+     * Creates a <code>Weight</code> instance for this query.
+     *
+     * @param searcher the <code>Searcher</code> instance to use.
+     * @return a <code>DerefWeight</code>.
+     */
+    protected Weight createWeight(Searcher searcher) {
+        return new DerefWeight(searcher);
+    }
+
+    /**
+     * Always returns 'DerefQuery'.
+     *
+     * @param field the name of a field.
+     * @return 'DerefQuery'.
+     */
+    public String toString(String field) {
+        return "DerefQuery";
+    }
+
+    //-------------------< DerefWeight >------------------------------------
+
+    /**
+     * The <code>Weight</code> implementation for this <code>DerefQuery</code>.
+     */
+    private class DerefWeight implements Weight {
+
+        /**
+         * The searcher in use
+         */
+        private final Searcher searcher;
+
+        /**
+         * Creates a new <code>DerefWeight</code> instance using
+         * <code>searcher</code>.
+         *
+         * @param searcher a <code>Searcher</code> instance.
+         */
+        private DerefWeight(Searcher searcher) {
+            this.searcher = searcher;
+        }
+
+        /**
+         * Returns this <code>DerefQuery</code>.
+         *
+         * @return this <code>DerefQuery</code>.
+         */
+        public Query getQuery() {
+            return DerefQuery.this;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public float getValue() {
+            // @todo implement properly
+            return 0;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public float sumOfSquaredWeights() throws IOException {
+            // @todo implement properly
+            return 0;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void normalize(float norm) {
+            // @todo implement properly
+        }
+
+        /**
+         * Creates a scorer for this <code>DerefQuery</code>.
+         *
+         * @param reader a reader for accessing the index.
+         * @return a <code>DerefScorer</code>.
+         * @throws IOException if an error occurs while reading from the index.
+         */
+        public Scorer scorer(IndexReader reader) throws IOException {
+            contextScorer = contextQuery.weight(searcher).scorer(reader);
+            if (nameTest != null) {
+                nameTestScorer = new TermQuery(new Term(FieldNames.LABEL, nameTest)).weight(searcher).scorer(reader);
+            }
+            return new DerefScorer(searcher.getSimilarity(), reader);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Explanation explain(IndexReader reader, int doc) throws IOException {
+            return new Explanation();
+        }
+    }
+
+    //----------------------< DerefScorer >---------------------------------
+
+    /**
+     * Implements a <code>Scorer</code> for this <code>DerefQuery</code>.
+     */
+    private class DerefScorer extends Scorer {
+
+        /**
+         * An <code>IndexReader</code> to access the index.
+         */
+        private final IndexReader reader;
+
+        /**
+         * BitSet storing the id's of selected documents
+         */
+        private final BitSet hits;
+
+        /**
+         * List of UUIDs of selected nodes
+         */
+        private List uuids = null;
+
+        /**
+         * The next document id to return
+         */
+        private int nextDoc = -1;
+
+        /**
+         * Creates a new <code>DerefScorer</code>.
+         *
+         * @param similarity the <code>Similarity</code> instance to use.
+         * @param reader     for index access.
+         */
+        protected DerefScorer(Similarity similarity, IndexReader reader) {
+            super(similarity);
+            this.reader = reader;
+            this.hits = new BitSet(reader.maxDoc());
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void score(HitCollector hc) throws IOException {
+            calculateChildren();
+
+            int next = hits.nextSetBit(0);
+            while (next > -1) {
+                hc.collect(next, 1.0f);
+                // move to next doc
+                next = hits.nextSetBit(next + 1);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public boolean next() throws IOException {
+            calculateChildren();
+            nextDoc = hits.nextSetBit(nextDoc + 1);
+            return nextDoc > -1;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public int doc() {
+            return nextDoc;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public float score() throws IOException {
+            // todo implement
+            return 1.0f;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public boolean skipTo(int target) throws IOException {
+            nextDoc = hits.nextSetBit(target);
+            return nextDoc > -1;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @throws UnsupportedOperationException this implementation always
+         *                                       throws an <code>UnsupportedOperationException</code>.
+         */
+        public Explanation explain(int doc) throws IOException {
+            throw new UnsupportedOperationException();
+        }
+
+        private void calculateChildren() throws IOException {
+            if (uuids == null) {
+                uuids = new ArrayList();
+                contextScorer.score(new HitCollector() {
+                    public void collect(int doc, float score) {
+                        hits.set(doc);
+                    }
+                });
+
+                // collect nameTest hits
+                final BitSet nameTestHits = new BitSet();
+                if (nameTestScorer != null) {
+                    nameTestScorer.score(new HitCollector() {
+                        public void collect(int doc, float score) {
+                            nameTestHits.set(doc);
+                        }
+                    });
+                }
+
+                // retrieve uuids of target nodes
+                for (int i = hits.nextSetBit(0); i >= 0; i = hits.nextSetBit(i + 1)) {
+                    String targetUUID = reader.document(i).get(refProperty);
+                    if (targetUUID != null) {
+                        uuids.add(targetUUID);
+                    }
+                    // also find multiple values
+                    String[] targetUUIDs = reader.document(i).getValues(refPropertyMV);
+                    if (targetUUIDs != null) {
+                        for (int j = 0; j < targetUUIDs.length; j++) {
+                            uuids.add(targetUUIDs[j]);
+                        }
+                    }
+                }
+
+                // collect the doc ids of all target nodes. we reuse the existing
+                // bitset.
+                hits.clear();
+                for (Iterator it = uuids.iterator(); it.hasNext();) {
+                    TermDocs node = reader.termDocs(new Term(FieldNames.UUID, (String) it.next()));
+                    while (node.next()) {
+                        hits.set(node.doc());
+                    }
+                }
+                // filter out the target nodes that do not match the name test
+                // if there is any name test at all.
+                if (nameTestScorer != null) {
+                    hits.and(nameTestHits);
+                }
+            }
+        }
+    }
+}

Propchange: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/DerefQuery.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java?view=diff&r1=157119&r2=157120
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/LuceneQueryBuilder.java Fri Mar 11 09:31:27 2005
@@ -40,6 +40,7 @@
 import org.apache.jackrabbit.core.search.RelationQueryNode;
 import org.apache.jackrabbit.core.search.TextsearchQueryNode;
 import org.apache.jackrabbit.core.search.QueryNode;
+import org.apache.jackrabbit.core.search.DerefQueryNode;
 import org.apache.log4j.Logger;
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.index.Term;
@@ -450,6 +451,26 @@
         return andQuery;
     }
 
+    public Object visit(DerefQueryNode node, Object data) {
+        Query context = (Query) data;
+        if (context == null) {
+            exceptions.add(new IllegalArgumentException("Unsupported query"));
+        }
+        try {
+            String refProperty = node.getRefProperty().toJCRName(nsMappings);
+            String nameTest = null;
+            if (node.getNameTest() != null) {
+                nameTest = node.getNameTest().toJCRName(nsMappings);
+            }
+            return new DerefQuery(context, refProperty, nameTest);
+        } catch (NoPrefixDeclaredException e) {
+            // should never happen
+            exceptions.add(e);
+        }
+        // fallback in case of exception
+        return context;
+    }
+
     public Object visit(RelationQueryNode node, Object data) {
         Query query;
         String stringValues[] = new String[1];
@@ -614,7 +635,7 @@
     public Object visit(OrderQueryNode node, Object data) {
         return data;
     }
-    
+
     //---------------------------< internal >-----------------------------------
     
     /**

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIndexer.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIndexer.java?view=diff&r1=157119&r2=157120
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIndexer.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/lucene/NodeIndexer.java Fri Mar 11 09:31:27 2005
@@ -225,7 +225,7 @@
                 String uuid = internalValue.toString();
                 doc.add(new Field(fieldName,
                         uuid,
-                        false,
+                        true, // store
                         true,
                         false));
                 break;

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/QueryFormat.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/QueryFormat.java?view=diff&r1=157119&r2=157120
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/QueryFormat.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/sql/QueryFormat.java Fri Mar 11 09:31:27 2005
@@ -30,6 +30,7 @@
 import org.apache.jackrabbit.core.search.OrderQueryNode;
 import org.apache.jackrabbit.core.search.QueryNode;
 import org.apache.jackrabbit.core.search.QueryConstants;
+import org.apache.jackrabbit.core.search.DerefQueryNode;
 import org.apache.jackrabbit.core.NamespaceResolver;
 import org.apache.jackrabbit.core.NoPrefixDeclaredException;
 import org.apache.jackrabbit.core.QName;
@@ -350,6 +351,11 @@
             }
         }
         return sb;
+    }
+
+    public Object visit(DerefQueryNode node, Object data) {
+        exceptions.add(new InvalidQueryException("jcrfn:deref() function not supported in SQL"));
+        return data;
     }
 
     public Object visit(RelationQueryNode node, Object data) {

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/QueryFormat.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/QueryFormat.java?view=diff&r1=157119&r2=157120
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/QueryFormat.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/QueryFormat.java Fri Mar 11 09:31:27 2005
@@ -34,6 +34,7 @@
 import org.apache.jackrabbit.core.search.QueryRootNode;
 import org.apache.jackrabbit.core.search.RelationQueryNode;
 import org.apache.jackrabbit.core.search.TextsearchQueryNode;
+import org.apache.jackrabbit.core.search.DerefQueryNode;
 import org.apache.jackrabbit.core.util.ISO9075;
 
 import javax.jcr.query.InvalidQueryException;
@@ -260,6 +261,25 @@
             sb.append('[');
             predicates[i].accept(this, sb);
             sb.append(']');
+        }
+        return sb;
+    }
+
+    public Object visit(DerefQueryNode node, Object data) {
+        StringBuffer sb = (StringBuffer) data;
+        try {
+            sb.append(XPathQueryBuilder.JCRFN_DEREF.toJCRName(resolver));
+            sb.append("(@");
+            sb.append(ISO9075.encode(node.getRefProperty()).toJCRName(resolver));
+            sb.append(", '");
+            if (node.getNameTest() == null) {
+                sb.append("*");
+            } else {
+                sb.append(ISO9075.encode(node.getNameTest()).toJCRName(resolver));
+            }
+            sb.append("')");
+        } catch (NoPrefixDeclaredException e) {
+            exceptions.add(e);
         }
         return sb;
     }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java?view=diff&r1=157119&r2=157120
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java (original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/search/xpath/XPathQueryBuilder.java Fri Mar 11 09:31:27 2005
@@ -37,6 +37,7 @@
 import org.apache.jackrabbit.core.search.RelationQueryNode;
 import org.apache.jackrabbit.core.search.TextsearchQueryNode;
 import org.apache.jackrabbit.core.search.QueryConstants;
+import org.apache.jackrabbit.core.search.DerefQueryNode;
 import org.apache.jackrabbit.core.util.ISO9075;
 
 import javax.jcr.query.InvalidQueryException;
@@ -276,86 +277,89 @@
      *         <code>data</code>.
      */
     public Object visit(SimpleNode node, Object data) {
+        QueryNode queryNode = (QueryNode) data;
         switch (node.getId()) {
             case JJTXPATH2:
-                data = createPathQueryNode(node);
+                queryNode = createPathQueryNode(node);
                 break;
             case JJTROOT:
             case JJTROOTDESCENDANTS:
-                ((PathQueryNode) data).setAbsolute(true);
+                ((PathQueryNode) queryNode).setAbsolute(true);
                 break;
             case JJTSTEPEXPR:
                 if (isAttributeAxis(node)) {
-                    if (data instanceof RelationQueryNode
-                            || data instanceof OrderQueryNode
-                            || data instanceof PathQueryNode) {
+                    if (queryNode.getType() == QueryNode.TYPE_RELATION
+                            || queryNode.getType() == QueryNode.TYPE_DEREF
+                            || queryNode.getType() == QueryNode.TYPE_ORDER
+                            || queryNode.getType() == QueryNode.TYPE_PATH) {
                         // traverse
-                        node.childrenAccept(this, data);
-                    } else if (data instanceof NotQueryNode) {
+                        node.childrenAccept(this, queryNode);
+                    } else if (queryNode.getType() == QueryNode.TYPE_NOT) {
                         // is null expression
                         RelationQueryNode isNull
-                                = new RelationQueryNode((QueryNode) data,
+                                = new RelationQueryNode(queryNode,
                                         RelationQueryNode.OPERATION_NULL);
                         node.childrenAccept(this, isNull);
-                        NotQueryNode notNode = (NotQueryNode) data;
+                        NotQueryNode notNode = (NotQueryNode) queryNode;
                         NAryQueryNode parent = (NAryQueryNode) notNode.getParent();
                         parent.removeOperand(notNode);
                         parent.addOperand(isNull);
                     } else {
                         // not null expression
                         RelationQueryNode notNull
-                                = new RelationQueryNode((QueryNode) data,
+                                = new RelationQueryNode(queryNode,
                                         RelationQueryNode.OPERATION_NOT_NULL);
                         node.childrenAccept(this, notNull);
-                        ((NAryQueryNode) data).addOperand(notNull);
+                        ((NAryQueryNode) queryNode).addOperand(notNull);
                     }
                 } else {
-                    if (data instanceof PathQueryNode) {
-                        data = createLocationStep(node, (PathQueryNode) data);
+                    if (queryNode.getType() == QueryNode.TYPE_PATH) {
+                        queryNode = createLocationStep(node, (PathQueryNode) queryNode);
                     } else {
                         exceptions.add(new InvalidQueryException("Only attribute axis is allowed in predicate"));
                     }
                 }
                 break;
             case JJTNAMETEST:
-                if (data instanceof LocationStepQueryNode
-                        || data instanceof RelationQueryNode
-                        || data instanceof PathQueryNode) {
-                    createNameTest(node, (QueryNode) data);
-                } else if (data instanceof OrderQueryNode) {
-                    data = createOrderSpec(node, (OrderQueryNode) data);
+                if (queryNode.getType() == QueryNode.TYPE_LOCATION
+                        || queryNode.getType() == QueryNode.TYPE_DEREF
+                        || queryNode.getType() == QueryNode.TYPE_RELATION
+                        || queryNode.getType() == QueryNode.TYPE_PATH) {
+                    createNodeTest(node, queryNode);
+                } else if (queryNode.getType() == QueryNode.TYPE_ORDER) {
+                    createOrderSpec(node, (OrderQueryNode) queryNode);
                 } else {
                     // traverse
-                    node.childrenAccept(this, data);
+                    node.childrenAccept(this, queryNode);
                 }
                 break;
             case JJTOREXPR:
-                NAryQueryNode parent = (NAryQueryNode) data;
-                data = new OrQueryNode(parent);
-                parent.addOperand((QueryNode) data);
+                NAryQueryNode parent = (NAryQueryNode) queryNode;
+                queryNode = new OrQueryNode(parent);
+                parent.addOperand(queryNode);
                 // traverse
-                node.childrenAccept(this, data);
+                node.childrenAccept(this, queryNode);
                 break;
             case JJTANDEXPR:
-                parent = (NAryQueryNode) data;
-                data = new AndQueryNode(parent);
-                parent.addOperand((QueryNode) data);
+                parent = (NAryQueryNode) queryNode;
+                queryNode = new AndQueryNode(parent);
+                parent.addOperand(queryNode);
                 // traverse
-                node.childrenAccept(this, data);
+                node.childrenAccept(this, queryNode);
                 break;
             case JJTCOMPARISONEXPR:
-                createExpression(node, (NAryQueryNode) data);
+                createExpression(node, (NAryQueryNode) queryNode);
                 break;
             case JJTSTRINGLITERAL:
             case JJTDECIMALLITERAL:
             case JJTDOUBLELITERAL:
             case JJTINTEGERLITERAL:
-                if (data instanceof RelationQueryNode) {
-                    assignValue(node, (RelationQueryNode) data);
-                } else if (data instanceof LocationStepQueryNode) {
+                if (queryNode.getType() == QueryNode.TYPE_RELATION) {
+                    assignValue(node, (RelationQueryNode) queryNode);
+                } else if (queryNode.getType() == QueryNode.TYPE_LOCATION) {
                     if (node.getId() == JJTINTEGERLITERAL) {
                         int index = Integer.parseInt(node.getValue());
-                        ((LocationStepQueryNode) data).setIndex(index);
+                        ((LocationStepQueryNode) queryNode).setIndex(index);
                     } else {
                         exceptions.add(new InvalidQueryException("LocationStep only allows integer literal as position index"));
                     }
@@ -364,25 +368,25 @@
                 }
                 break;
             case JJTFUNCTIONCALL:
-                data = createFunction(node, (QueryNode) data);
+                queryNode = createFunction(node, queryNode);
                 break;
             case JJTORDERBYCLAUSE:
                 root.setOrderNode(new OrderQueryNode(root));
-                data = root.getOrderNode();
-                node.childrenAccept(this, data);
+                queryNode = root.getOrderNode();
+                node.childrenAccept(this, queryNode);
                 break;
             case JJTORDERMODIFIER:
                 if (node.jjtGetNumChildren() > 0
                         && ((SimpleNode) node.jjtGetChild(0)).getId() == JJTDESCENDING) {
-                    OrderQueryNode.OrderSpec[] specs = ((OrderQueryNode) data).getOrderSpecs();
+                    OrderQueryNode.OrderSpec[] specs = ((OrderQueryNode) queryNode).getOrderSpecs();
                     specs[specs.length - 1].setAscending(false);
                 }
                 break;
             default:
                 // per default traverse
-                node.childrenAccept(this, data);
+                node.childrenAccept(this, queryNode);
         }
-        return data;
+        return queryNode;
     }
 
     //----------------------< internal >----------------------------------------
@@ -416,31 +420,34 @@
     }
 
     /**
-     * Creates a name test either for a <code>LocationStepQueryNode</code> or
-     * for a <code>RelationQueryNode</code>.
+     * Assigns a QName to one of the follwing QueryNodes:
+     * {@link RelationQueryNode}, {@link DerefQueryNode}, {@link RelationQueryNode},
+     * {@link PathQueryNode}, {@link OrderQueryNode}.
      *
      * @param node      the current node in the xpath syntax tree.
-     * @param queryNode either a <code>LocationStepQueryNode</code> or a
-     *                  <code>RelationQueryNode</code>.
+     * @param queryNode the query node.
      */
-    private void createNameTest(SimpleNode node, QueryNode queryNode) {
+    private void createNodeTest(SimpleNode node, QueryNode queryNode) {
         if (node.jjtGetNumChildren() > 0) {
             SimpleNode child = (SimpleNode) node.jjtGetChild(0);
             if (child.getId() == JJTQNAME) {
                 try {
-                    if (queryNode instanceof LocationStepQueryNode) {
+                    if (queryNode.getType() == QueryNode.TYPE_LOCATION) {
                         QName name = ISO9075.decode(QName.fromJCRName(child.getValue(), resolver));
                         if (name.equals(JCR_ROOT)) {
                             name = new QName("", "");
                         }
                         ((LocationStepQueryNode) queryNode).setNameTest(name);
-                    } else if (queryNode instanceof RelationQueryNode) {
+                    } else if (queryNode.getType() == QueryNode.TYPE_DEREF) {
+                        QName name = ISO9075.decode(QName.fromJCRName(child.getValue(), resolver));
+                        ((DerefQueryNode) queryNode).setRefProperty(name);
+                    } else if (queryNode.getType() == QueryNode.TYPE_RELATION) {
                         QName name = ISO9075.decode(QName.fromJCRName(child.getValue(), resolver));
                         ((RelationQueryNode) queryNode).setProperty(name);
-                    } else if (queryNode instanceof PathQueryNode) {
+                    } else if (queryNode.getType() == QueryNode.TYPE_PATH) {
                         QName name = ISO9075.decode(QName.fromJCRName(child.getValue(), resolver));
                         root.addSelectProperty(name);
-                    } else if (queryNode instanceof OrderQueryNode) {
+                    } else if (queryNode.getType() == QueryNode.TYPE_ORDER) {
                         QName name = ISO9075.decode(QName.fromJCRName(child.getValue(), resolver));
                         root.getOrderNode().addOrderSpec(name, true);
                     }
@@ -450,7 +457,7 @@
                     exceptions.add(new InvalidQueryException("Unknown prefix: " + child.getValue()));
                 }
             } else if (child.getId() == JJTSTAR) {
-                if (queryNode instanceof LocationStepQueryNode) {
+                if (queryNode.getType() == QueryNode.TYPE_LOCATION) {
                     ((LocationStepQueryNode) queryNode).setNameTest(null);
                 }
             } else {
@@ -721,7 +728,43 @@
                     exceptions.add(new InvalidQueryException("Unsupported location for last()"));
                 }
             } else if (JCRFN_DEREF.toJCRName(resolver).equals(fName)) {
-                exceptions.add(new InvalidQueryException("Unsupported function: " + fName));
+                // check number of arguments
+                if (node.jjtGetNumChildren() == 3) {
+                    if (queryNode.getType() == QueryNode.TYPE_PATH) {
+                        PathQueryNode pathNode = (PathQueryNode) queryNode;
+                        DerefQueryNode derefNode = new DerefQueryNode(pathNode, null, false);
+
+                        // assign property name
+                        node.jjtGetChild(1).jjtAccept(this, derefNode);
+                        // check property name
+                        if (derefNode.getRefProperty() == null) {
+                            exceptions.add(new InvalidQueryException("Wrong first argument type for jcrfn:deref"));
+                        }
+
+                        SimpleNode literal = (SimpleNode) node.jjtGetChild(2).jjtGetChild(0);
+                        if (literal.getId() == JJTSTRINGLITERAL) {
+                            String value = literal.getValue();
+                            // strip quotes
+                            value = value.substring(1, value.length() - 1);
+                            if (!value.equals("*")) {
+                                QName name = null;
+                                try {
+                                    name = ISO9075.decode(QName.fromJCRName(value, resolver));
+                                } catch (IllegalNameException e) {
+                                    exceptions.add(new InvalidQueryException("Illegal name: " + value));
+                                } catch (UnknownPrefixException e) {
+                                    exceptions.add(new InvalidQueryException("Unknown prefix: " + value));
+                                }
+                                derefNode.setNameTest(name);
+                            }
+                        } else {
+                            exceptions.add(new InvalidQueryException("Wrong second argument type for jcrfn:like"));
+                        }
+                        pathNode.addPathStep(derefNode);
+                    } else {
+                        exceptions.add(new InvalidQueryException("Unsupported location for jcrfn:deref()"));
+                    }
+                }
             } else {
                 exceptions.add(new InvalidQueryException("Unsupported function: " + fName));
             }

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/JackrabbitRepositoryStub.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/JackrabbitRepositoryStub.java?view=diff&r1=157119&r2=157120
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/JackrabbitRepositoryStub.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/JackrabbitRepositoryStub.java Fri Mar 11 09:31:27 2005
@@ -71,6 +71,10 @@
      */
     public JackrabbitRepositoryStub(Properties env) {
         super(env);
+        // set some attributes on the sessions
+        superuser.setAttribute("jackrabbit", "jackrabbit");
+        readwrite.setAttribute("jackrabbit", "jackrabbit");
+        readonly.setAttribute("jackrabbit", "jackrabbit");
     }
 
     /**

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/search/FulltextQueryTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/search/FulltextQueryTest.java?view=diff&r1=157119&r2=157120
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/search/FulltextQueryTest.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/core/search/FulltextQueryTest.java Fri Mar 11 09:31:27 2005
@@ -21,7 +21,7 @@
 import javax.jcr.query.QueryResult;
 
 /**
- * Performs tests with the <code>TEXTSEARCH</code> clause.
+ * Performs tests with the <code>CONTAINS</code> function.
  */
 public class FulltextQueryTest extends AbstractQueryTest {
 

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/init/NodeTestData.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/init/NodeTestData.java?view=diff&r1=157119&r2=157120
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/init/NodeTestData.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/init/NodeTestData.java Fri Mar 11 09:31:27 2005
@@ -18,6 +18,8 @@
 
 import javax.jcr.RepositoryException;
 import javax.jcr.Node;
+import javax.jcr.Value;
+import javax.jcr.ReferenceValue;
 import java.util.StringTokenizer;
 import java.util.Calendar;
 import java.io.ByteArrayOutputStream;
@@ -103,6 +105,13 @@
         // make this node itself referenceable
         resReference.addMixin(mixReferenceable);
         log.println("Adding node: " + resReference.getPath());
+
+        Node multiReference = dataRoot.addNode("multiReference");
+        Value[] refs = new Value[2];
+        refs[0] = new ReferenceValue(resource);
+        refs[1] = new ReferenceValue(resReference);
+        multiReference.setProperty("ref", refs);
+        log.println("Adding node: " + multiReference.getPath());
 
         superuser.save();
     }

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/PropertyUtil.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/PropertyUtil.java?view=diff&r1=157119&r2=157120
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/PropertyUtil.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/PropertyUtil.java Fri Mar 11 09:31:27 2005
@@ -378,6 +378,39 @@
             for (NodeIterator nodes = node.getNodes(); nodes.hasNext();) {
                 Node n = nodes.nextNode();
                 multiVal = searchMultivalProp(n);
+                if (multiVal != null) {
+                    break;
+                }
+            }
+        }
+        return multiVal;
+    }
+
+    /**
+     * Helper method to find a multivalue property of a given type.
+     *
+     * @param node the node to start the search from.
+     * @param type the property type.
+     * @return a multivalue property or null if not found any.
+     */
+    public static Property searchMultivalProp(Node node, int type) throws RepositoryException {
+        Property multiVal = null;
+        for (PropertyIterator props = node.getProperties(); props.hasNext();) {
+            Property property = props.nextProperty();
+            if (property.getDefinition().isMultiple()
+                    && property.getType() == type) {
+                multiVal = property;
+                break;
+            }
+        }
+
+        if (multiVal == null) {
+            for (NodeIterator nodes = node.getNodes(); nodes.hasNext();) {
+                Node n = nodes.nextNode();
+                multiVal = searchMultivalProp(n, type);
+                if (multiVal != null) {
+                    break;
+                }
             }
         }
         return multiVal;

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/AbstractQueryTest.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/AbstractQueryTest.java?view=diff&r1=157119&r2=157120
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/AbstractQueryTest.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/AbstractQueryTest.java Fri Mar 11 09:31:27 2005
@@ -24,6 +24,12 @@
 import javax.jcr.query.Query;
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Session;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Iterator;
 
 /**
  * Abstract base class for query test cases.
@@ -56,6 +62,11 @@
     protected String jcrfnContains;
 
     /**
+     * Resolved QName for jcrfn:deref
+     */
+    protected String jcrfnDeref;
+
+    /**
      * Set-up the configuration values used for the test. Per default retrieves
      * a session, configures testRoot, and nodetype and checks if the query
      * language for the current language is available.<br>
@@ -66,6 +77,7 @@
         jcrPath = superuser.getNamespacePrefix(NS_JCR_URI) + ":path";
         jcrRoot = superuser.getNamespacePrefix(NS_JCR_URI) + ":root";
         jcrfnContains = superuser.getNamespacePrefix(NS_JCRFN_URI) + ":contains";
+        jcrfnDeref = superuser.getNamespacePrefix(NS_JCRFN_URI) + ":deref";
     }
 
     /**
@@ -223,6 +235,46 @@
         }
     }
 
+    /**
+     * Executes the <code>xpath</code> query and checks the results against
+     * the specified <code>nodes</code>.
+     * @param session the session to use for the query.
+     * @param xpath the xpath query.
+     * @param nodes the expected result nodes.
+     */
+    protected void executeXPathQuery(Session session, String xpath, Node[] nodes)
+            throws RepositoryException {
+        QueryResult res = session.getWorkspace().getQueryManager().createQuery(xpath, Query.XPATH).execute();
+        checkResult(res, nodes);
+    }
+
+    /**
+     * Checks if the result set contains exactly the <code>nodes</code>.
+     * @param result the query result.
+     * @param nodes the expected nodes in the result set.
+     */
+    protected void checkResult(QueryResult result, Node[] nodes)
+            throws RepositoryException {
+        // collect paths
+        Set expectedPaths = new HashSet();
+        for (int i = 0; i < nodes.length; i++) {
+            expectedPaths.add(nodes[i].getPath());
+        }
+        Set resultPaths = new HashSet();
+        for (NodeIterator it = result.getNodes(); it.hasNext();) {
+            resultPaths.add(it.nextNode().getPath());
+        }
+        // check if all expected are in result
+        for (Iterator it = expectedPaths.iterator(); it.hasNext();) {
+            String path = (String) it.next();
+            assertTrue(path + " is not part of the result set", resultPaths.contains(path));
+        }
+        // check result does not contain more than expected
+        for (Iterator it = resultPaths.iterator(); it.hasNext();) {
+            String path = (String) it.next();
+            assertTrue(path + " is not expected to be part of the result set", expectedPaths.contains(path));
+        }
+    }
     /**
      * Test if the requested Descriptor is registred at repository
      *

Added: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/DerefQueryLevel1Test.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/DerefQueryLevel1Test.java?view=auto&rev=157120
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/DerefQueryLevel1Test.java (added)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/DerefQueryLevel1Test.java Fri Mar 11 09:31:27 2005
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed 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.test.api.query;
+
+import org.apache.jackrabbit.test.api.PropertyUtil;
+import org.apache.jackrabbit.test.NotExecutableException;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.PropertyType;
+import javax.jcr.Property;
+import javax.jcr.Node;
+import javax.jcr.Value;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Tests the XPath function jcrfn:deref() in a level 1 repository.
+ *
+ * @test
+ * @sources DerefQueryLevel1Test.java
+ * @executeClass org.apache.jackrabbit.test.api.query.DerefQueryLevel1Test
+ * @keywords level1 deref
+ */
+public class DerefQueryLevel1Test extends AbstractQueryTest {
+
+    /** A read-only session */
+    private Session session;
+
+    /**
+     * Sets up the test cases
+     */
+    protected void setUp() throws Exception {
+        isReadOnly = true;
+        super.setUp();
+        session = helper.getReadOnlySession();
+        testRootNode = session.getRootNode().getNode(testPath);
+    }
+
+    /**
+     * Releases the session acquired in setUp().
+     */
+    protected void tearDown() throws Exception {
+        if (session != null) {
+            session.logout();
+        }
+        super.tearDown();
+    }
+
+    /**
+     * Test a deref query on a single valued reference property with a node test.
+     * @throws NotExecutableException if the workspace does not have sufficient
+     *  content.
+     */
+    public void testDerefSinglePropWithNodeTest()
+            throws RepositoryException, NotExecutableException {
+        Property refProp = PropertyUtil.searchProp(session, testRootNode, PropertyType.REFERENCE);
+        if (refProp == null) {
+            throw new NotExecutableException("Workspace does not contain a node with a reference property.");
+        }
+        Node target = refProp.getNode();
+        String xpath = createStatement(refProp, target.getName());
+        executeXPathQuery(session, xpath, new Node[]{target});
+    }
+
+    /**
+     * Test a deref query on a single valued reference property with a '*' node
+     * test.
+     * @throws NotExecutableException if the workspace does not have sufficient
+     *  content.
+     */
+    public void testDerefSinglePropWithNodeStar()
+            throws RepositoryException, NotExecutableException {
+        Property refProp = PropertyUtil.searchProp(session, testRootNode, PropertyType.REFERENCE);
+        if (refProp == null) {
+            throw new NotExecutableException("Workspace does not contain a node with a reference property.");
+        }
+        Node target = refProp.getNode();
+        String xpath = createStatement(refProp, "*");
+        executeXPathQuery(session, xpath, new Node[]{target});
+    }
+
+    /**
+     * Test a deref query on a multi valued reference property with a node test.
+     * @throws NotExecutableException if the workspace does not have sufficient
+     *  content.
+     */
+    public void testDerefMultiPropWithNodeTest()
+            throws RepositoryException, NotExecutableException {
+        Property refProp = PropertyUtil.searchMultivalProp(testRootNode, PropertyType.REFERENCE);
+        if (refProp == null) {
+            throw new NotExecutableException("Workspace does not contain a node with a multivalue reference property.");
+        }
+        Value[] targets = refProp.getValues();
+        Node[] targetNodes = new Node[targets.length];
+        for (int i = 0; i < targets.length; i++) {
+            targetNodes[i] = session.getNodeByUUID(targets[i].getString());
+        }
+        if (targetNodes.length == 0) {
+            throw new NotExecutableException("Reference property does not contain a value");
+        }
+        String nodeName = targetNodes[0].getName();
+        List resultNodes = new ArrayList();
+        for (int i = 0; i < targetNodes.length; i++) {
+            if (targetNodes[i].getName().equals(nodeName)) {
+                resultNodes.add(targetNodes[i]);
+            }
+        }
+        targetNodes = (Node[]) resultNodes.toArray(new Node[resultNodes.size()]);
+        String xpath = createStatement(refProp, nodeName);
+        executeXPathQuery(session, xpath, targetNodes);
+    }
+
+    /**
+     * Test a deref query on a multi valued reference property with a '*' node.
+     * @throws NotExecutableException if the workspace does not have sufficient
+     *  content.
+     */
+    public void testDerefMultiPropWithNodeStar()
+            throws RepositoryException, NotExecutableException {
+        Property refProp = PropertyUtil.searchMultivalProp(testRootNode, PropertyType.REFERENCE);
+        if (refProp == null) {
+            throw new NotExecutableException("Workspace does not contain a node with a multivalue reference property.");
+        }
+        Value[] targets = refProp.getValues();
+        Node[] targetNodes = new Node[targets.length];
+        for (int i = 0; i < targets.length; i++) {
+            targetNodes[i] = session.getNodeByUUID(targets[i].getString());
+        }
+        if (targetNodes.length == 0) {
+            throw new NotExecutableException("Reference property does not contain a value");
+        }
+        String xpath = createStatement(refProp, "*");
+        executeXPathQuery(session, xpath, targetNodes);
+    }
+
+    //----------------------------< internal >----------------------------------
+
+    /**
+     * Creates a xpath deref statement with a reference property and a nametest.
+     * @param refProperty the reference property.
+     * @param nameTest the nametest.
+     * @return the xpath statement.
+     */
+    private String createStatement(Property refProperty, String nameTest)
+            throws RepositoryException {
+        StringBuffer stmt = new StringBuffer();
+        stmt.append("/").append(jcrRoot).append(refProperty.getParent().getPath());
+        stmt.append("/").append(jcrfnDeref).append("(@");
+        stmt.append(refProperty.getName()).append(", '");
+        stmt.append(nameTest).append("')");
+        return stmt.toString();
+    }
+}

Propchange: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/DerefQueryLevel1Test.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/TestAll.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/TestAll.java?view=diff&r1=157119&r2=157120
==============================================================================
--- incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/TestAll.java (original)
+++ incubator/jackrabbit/trunk/src/test/org/apache/jackrabbit/test/api/query/TestAll.java Fri Mar 11 09:31:27 2005
@@ -45,6 +45,8 @@
         suite.addTestSuite(XPathOrderByTest.class);
         suite.addTestSuite(XPathQueryLevel2Test.class);
 
+        suite.addTestSuite(DerefQueryLevel1Test.class);
+
         return suite;
     }
 }



Mime
View raw message