You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2009/04/27 14:43:31 UTC
svn commit: r768954 [3/4] - in /jackrabbit/trunk:
jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/query/
jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/
jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query...
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/QueryConstraint.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/QueryConstraint.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/QueryConstraint.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/QueryConstraint.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,133 @@
+/*
+ * 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.core.query.lucene.constraint;
+
+import java.io.IOException;
+import java.util.BitSet;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.spi.commons.query.qom.SelectorImpl;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.core.query.lucene.ScoreNode;
+import org.apache.jackrabbit.core.query.lucene.QueryHits;
+import org.apache.jackrabbit.core.query.lucene.Util;
+import org.apache.jackrabbit.core.query.lucene.LuceneQueryFactory;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.index.IndexReader;
+
+/**
+ * <code>QueryConstraint</code> implements a constraint that is based on a
+ * lucene query.
+ */
+public abstract class QueryConstraint extends SelectorBasedConstraint {
+
+ /**
+ * The constraint query.
+ */
+ private final Query constraint;
+
+ /**
+ * The lucene query factory.
+ */
+ private final LuceneQueryFactory factory;
+
+ /**
+ * The bitset with the matching document numbers.
+ */
+ private BitSet matches;
+
+ /**
+ * Creates a new query constraint using the given lucene query.
+ *
+ * @param constraint the lucene query constraint.
+ * @param selector the selector for this constraint.
+ * @param factory the lucene query factory.
+ */
+ public QueryConstraint(Query constraint,
+ SelectorImpl selector,
+ LuceneQueryFactory factory) {
+ super(selector);
+ this.constraint = constraint;
+ this.factory = factory;
+ }
+
+ //----------------------------< Constraint >--------------------------------
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean evaluate(ScoreNode[] row,
+ Name[] selectorNames,
+ EvaluationContext context)
+ throws IOException {
+ ScoreNode sn = row[getSelectorIndex(selectorNames)];
+ return sn != null && evaluate(sn, context);
+ }
+
+ //--------------------------------< internal >------------------------------
+
+ /**
+ * Evaluates this constraint for the given score node <code>sn</code>.
+ *
+ * @param sn the current score node.
+ * @param context the evaluation context.
+ * @return <code>true</code> if this constraint is satisfied for the given
+ * score node <code>sn</code>; <code>false</code> otherwise.
+ * @throws IOException if an error occurs while reading from the index.
+ */
+ private boolean evaluate(ScoreNode sn, EvaluationContext context)
+ throws IOException {
+ initMatches(context);
+ return matches.get(sn.getDoc(context.getIndexReader()));
+ }
+
+ /**
+ * Initializes the matches for the constraint query. If the matches are
+ * already initialized then this method returns immediately.
+ *
+ * @param context the evaluation context.
+ * @throws IOException if an error occurs while reading from the index.
+ */
+ private void initMatches(EvaluationContext context) throws IOException {
+ if (matches == null) {
+ Query selectorQuery;
+ BooleanQuery and = new BooleanQuery();
+ try {
+ selectorQuery = factory.create(getSelector());
+ and.add(selectorQuery, BooleanClause.Occur.MUST);
+ and.add(constraint, BooleanClause.Occur.MUST);
+ } catch (RepositoryException e) {
+ throw Util.createIOException(e);
+ }
+
+ IndexReader reader = context.getIndexReader();
+ QueryHits hits = context.evaluate(and);
+ try {
+ matches = new BitSet();
+ ScoreNode sn;
+ while ((sn = hits.nextScoreNode()) != null) {
+ matches.set(sn.getDoc(reader));
+ }
+ } finally {
+ hits.close();
+ }
+ }
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/QueryConstraint.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/SameNodeConstraint.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/SameNodeConstraint.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/SameNodeConstraint.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/SameNodeConstraint.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,55 @@
+/*
+ * 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.core.query.lucene.constraint;
+
+import java.io.IOException;
+
+import org.apache.jackrabbit.spi.commons.query.qom.SameNodeImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.SelectorImpl;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.core.query.lucene.ScoreNode;
+
+/**
+ * <code>SameNodeConstraint</code> implements a same node constraint.
+ */
+public class SameNodeConstraint extends HierarchyConstraint {
+
+ /**
+ * Creates a same node constraint.
+ *
+ * @param constraint the QOM constraint.
+ * @param selector the selector for this constraint.
+ */
+ public SameNodeConstraint(SameNodeImpl constraint, SelectorImpl selector) {
+ super(constraint.getPath(), selector);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean evaluate(ScoreNode[] row,
+ Name[] selectorNames,
+ EvaluationContext context)
+ throws IOException {
+ ScoreNode sn = row[getSelectorIndex(selectorNames)];
+ if (sn == null) {
+ return false;
+ } else {
+ return sn.getNodeId().equals(getBaseNodeId(context));
+ }
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/SameNodeConstraint.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/SelectorBasedConstraint.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/SelectorBasedConstraint.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/SelectorBasedConstraint.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/SelectorBasedConstraint.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,69 @@
+/*
+ * 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.core.query.lucene.constraint;
+
+import java.util.Arrays;
+
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.query.qom.SelectorImpl;
+
+/**
+ * <code>SelectorBasedConstraint</code> implements a constraint that is based
+ * on a named selector.
+ */
+public abstract class SelectorBasedConstraint implements Constraint {
+
+ /**
+ * The selector this constrained is based on.
+ */
+ private final SelectorImpl selector;
+
+ /**
+ * Cached selector index. Initially set to <code>-1</code>.
+ */
+ private int selectorIndex = -1;
+
+ /**
+ * Creates a new constraint based on the given <code>selector</code>.
+ *
+ * @param selector the selector this constraint is based on.
+ */
+ public SelectorBasedConstraint(SelectorImpl selector) {
+ this.selector = selector;
+ }
+
+ /**
+ * Returns the selector index of this constraint.
+ *
+ * @param names the selector names.
+ * @return the selector index.
+ */
+ protected int getSelectorIndex(Name[] names) {
+ if (selectorIndex == -1) {
+ selectorIndex = Arrays.asList(names).indexOf(
+ selector.getSelectorQName());
+ }
+ return selectorIndex;
+ }
+
+ /**
+ * @return the selector of this constraint.
+ */
+ protected SelectorImpl getSelector() {
+ return selector;
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/SelectorBasedConstraint.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/UpperCaseOperand.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/UpperCaseOperand.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/UpperCaseOperand.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/UpperCaseOperand.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.query.lucene.constraint;
+
+import java.io.IOException;
+
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.query.lucene.ScoreNode;
+import org.apache.jackrabbit.core.query.lucene.Util;
+
+/**
+ * <code>UpperCaseOperand</code> implements an upper case operand.
+ */
+public class UpperCaseOperand extends DynamicOperand {
+
+ /**
+ * The dynamic operand for which to lower case the value.
+ */
+ private final DynamicOperand operand;
+
+ /**
+ * Creates a new upper case operand.
+ *
+ * @param operand the operand to upper case the value.
+ */
+ public UpperCaseOperand(DynamicOperand operand) {
+ super();
+ this.operand = operand;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Value[] getValues(ScoreNode sn, EvaluationContext context)
+ throws IOException {
+ try {
+ ValueFactory vf = context.getSession().getValueFactory();
+ Value[] values = operand.getValues(sn, context);
+ for (int i = 0; i < values.length; i++) {
+ values[i] = vf.createValue(values[i].getString().toUpperCase());
+ }
+ return values;
+ } catch (RepositoryException e) {
+ throw Util.createIOException(e);
+ }
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/UpperCaseOperand.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AbstractCondition.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AbstractCondition.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AbstractCondition.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AbstractCondition.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,75 @@
+/*
+ * 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.core.query.lucene.join;
+
+import java.util.Arrays;
+import java.io.IOException;
+
+import org.apache.jackrabbit.core.query.lucene.MultiColumnQueryHits;
+import org.apache.jackrabbit.spi.Name;
+
+/**
+ * <code>AbstractCondition</code> is a base class for join conditions.
+ */
+public abstract class AbstractCondition implements Condition {
+
+ /**
+ * The inner query hits.
+ */
+ protected final MultiColumnQueryHits inner;
+
+ /**
+ * Creates a new join condition with the given <code>inner</code> query
+ * hits.
+ *
+ * @param inner the inner query hits.
+ */
+ public AbstractCondition(MultiColumnQueryHits inner) {
+ this.inner = inner;
+ }
+
+ /**
+ * @return selector names of the inner query hits.
+ */
+ public Name[] getInnerSelectorNames() {
+ return inner.getSelectorNames();
+ }
+
+ /**
+ * Closes this join condition and frees resources. Namely closes the inner
+ * query hits.
+ *
+ * @throws IOException if an error occurs while closing the inner query
+ * hits.
+ */
+ public void close() throws IOException {
+ inner.close();
+ }
+
+ /**
+ * Returns the index of the selector with the given <code>selectorName</code>
+ * within the given <code>source</code>.
+ *
+ * @param source a source.
+ * @param selectorName a selector name.
+ * @return the index within the source or <code>-1</code> if the name does
+ * not exist in <code>source</code>.
+ */
+ protected static int getIndex(MultiColumnQueryHits source, Name selectorName) {
+ return Arrays.asList(source.getSelectorNames()).indexOf(selectorName);
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AbstractCondition.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AncestorNodeJoin.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AncestorNodeJoin.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AncestorNodeJoin.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AncestorNodeJoin.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,122 @@
+/*
+ * 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.core.query.lucene.join;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.ArrayList;
+
+import org.apache.jackrabbit.core.query.lucene.ScoreNode;
+import org.apache.jackrabbit.core.query.lucene.MultiColumnQueryHits;
+import org.apache.jackrabbit.core.query.lucene.HierarchyResolver;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.lucene.index.IndexReader;
+
+/**
+ * <code>AncestorNodeJoin</code> implements an ancestor node join condition.
+ */
+public class AncestorNodeJoin extends AbstractCondition {
+
+ /**
+ * A score node map with the score nodes from the inner query hits. The
+ * inner score nodes are indexed by the document numbers of their ancestor
+ * nodes.
+ */
+ private final ScoreNodeMap contextIndex = new ScoreNodeMap();
+
+ /**
+ * The index reader.
+ */
+ private final IndexReader reader;
+
+ /**
+ * The hierarchy resolver.
+ */
+ private final HierarchyResolver resolver;
+
+ /**
+ * Reusable array of document numbers.
+ */
+ private int[] docNums = new int[1];
+
+ /**
+ * Reusable list of ancestor document numbers.
+ */
+ private final List ancestors = new ArrayList();
+
+ /**
+ * Creates a new ancestor node join condition.
+ *
+ * @param context the inner query hits.
+ * @param contextSelectorName the selector name for the inner query hits.
+ * @param reader the index reader.
+ * @param resolver the hierarchy resolver.
+ * @throws IOException if an error occurs while reading from the index.
+ */
+ public AncestorNodeJoin(MultiColumnQueryHits context,
+ Name contextSelectorName,
+ IndexReader reader,
+ HierarchyResolver resolver) throws IOException {
+ super(context);
+ this.reader = reader;
+ this.resolver = resolver;
+ int idx = getIndex(context, contextSelectorName);
+ ScoreNode[] nodes;
+ while ((nodes = context.nextScoreNodes()) != null) {
+ Integer docNum = new Integer(nodes[idx].getDoc(reader));
+ ancestors.clear();
+ collectAncestors(docNum.intValue());
+ for (int i = 0; i < ancestors.size(); i++) {
+ Integer doc = (Integer) ancestors.get(i);
+ contextIndex.addScoreNodes(doc, nodes);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * The outer query hits loop contains the ancestor score nodes.
+ */
+ public ScoreNode[][] getMatchingScoreNodes(ScoreNode ancestor)
+ throws IOException {
+ Integer doc = new Integer(ancestor.getDoc(reader));
+ return contextIndex.getScoreNodes(doc);
+ }
+
+ /**
+ * Collects the ancestors of the given <code>doc</code> number into
+ * {@link #ancestors}.
+ *
+ * @param doc the current document number.
+ * @throws IOException if an error occurs while reading from the index.
+ */
+ private void collectAncestors(int doc) throws IOException {
+ docNums = resolver.getParents(doc, docNums);
+ if (docNums.length == 1) {
+ ancestors.add(new Integer(docNums[0]));
+ collectAncestors(docNums[0]);
+ } else if (docNums.length > 1) {
+ // clone because recursion uses docNums again
+ int[] tmp = (int[]) docNums.clone();
+ for (int i = 0; i < tmp.length; i++) {
+ ancestors.add(new Integer(tmp[i]));
+ collectAncestors(tmp[i]);
+ }
+ }
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AncestorNodeJoin.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AncestorPathNodeJoin.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AncestorPathNodeJoin.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AncestorPathNodeJoin.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AncestorPathNodeJoin.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,97 @@
+/*
+ * 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.core.query.lucene.join;
+
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.query.lucene.ScoreNode;
+import org.apache.jackrabbit.core.query.lucene.MultiColumnQueryHits;
+import org.apache.jackrabbit.core.HierarchyManager;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.name.PathBuilder;
+
+/**
+ * <code>AncestorPathNodeJoin</code> implements an ancestor path node join
+ * condition.
+ */
+public class AncestorPathNodeJoin extends AbstractCondition {
+
+ /**
+ * A score node map with the score nodes from the inner query hits, indexed
+ * by the path of the inner query hits.
+ */
+ private final ScoreNodeMap contextIndex = new ScoreNodeMap();
+
+ /**
+ * The hierarchy manager.
+ */
+ private final HierarchyManager hmgr;
+
+ /**
+ * The relative path from the outer to the inner query hits.
+ */
+ private final Path relPath;
+
+ /**
+ * Creates an ancestor path node join.
+ *
+ * @param context the inner query hits.
+ * @param contextSelectorName the selector name for the inner query hits.
+ * @param relPath the relative path of the join condition.
+ * @param hmgr the hierarchy manager of the workspace.
+ * @throws IOException if an error occurs while reading from the index.
+ */
+ public AncestorPathNodeJoin(MultiColumnQueryHits context,
+ Name contextSelectorName,
+ Path relPath,
+ HierarchyManager hmgr) throws IOException {
+ super(context);
+ this.hmgr = hmgr;
+ this.relPath = relPath;
+ int idx = getIndex(context, contextSelectorName);
+ ScoreNode[] nodes;
+ while ((nodes = context.nextScoreNodes()) != null) {
+ try {
+ Path p = hmgr.getPath(nodes[idx].getNodeId());
+ contextIndex.addScoreNodes(p, nodes);
+ } catch (RepositoryException e) {
+ // ignore
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * The outer query hits loop contains the ancestor nodes.
+ */
+ public ScoreNode[][] getMatchingScoreNodes(ScoreNode ancestor)
+ throws IOException {
+ try {
+ Path ancestorPath = hmgr.getPath(ancestor.getNodeId());
+ PathBuilder builder = new PathBuilder(ancestorPath);
+ builder.addAll(relPath.getElements());
+ return contextIndex.getScoreNodes(builder.getPath().getNormalizedPath());
+ } catch (RepositoryException e) {
+ // ignore, probably does not exist anymore
+ return null;
+ }
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AncestorPathNodeJoin.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ChildNodeJoin.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ChildNodeJoin.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ChildNodeJoin.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ChildNodeJoin.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,107 @@
+/*
+ * 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.core.query.lucene.join;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.ArrayList;
+
+import org.apache.jackrabbit.core.query.lucene.MultiColumnQueryHits;
+import org.apache.jackrabbit.core.query.lucene.ScoreNode;
+import org.apache.jackrabbit.core.query.lucene.HierarchyResolver;
+import org.apache.jackrabbit.spi.commons.query.qom.ChildNodeJoinConditionImpl;
+import org.apache.lucene.index.IndexReader;
+
+/**
+ * <code>ChildNodeJoin</code> implements a child node join condition.
+ */
+public class ChildNodeJoin extends AbstractCondition {
+
+ /**
+ * A score node map with the score nodes from the inner query hits, indexed
+ * by the document number of the parent node.
+ */
+ private final ScoreNodeMap parentIndex = new ScoreNodeMap();
+
+ /**
+ * The index reader.
+ */
+ private final IndexReader reader;
+
+ /**
+ * The hierarchy resolver.
+ */
+ private final HierarchyResolver resolver;
+
+ /**
+ * Reusable array of document numbers.
+ */
+ private int[] docNums = new int[1];
+
+ /**
+ * Reusable list of score nodes.
+ */
+ private List tmpScoreNodes = new ArrayList();
+
+ /**
+ * Creates a new child node join condition.
+ *
+ * @param parent the inner query hits.
+ * @param reader the index reader.
+ * @param resolver the hierarchy resolver.
+ * @param condition the QOM child node join condition.
+ * @throws IOException if an error occurs while reading from the index.
+ */
+ public ChildNodeJoin(MultiColumnQueryHits parent,
+ IndexReader reader,
+ HierarchyResolver resolver,
+ ChildNodeJoinConditionImpl condition)
+ throws IOException {
+ super(parent);
+ this.reader = reader;
+ this.resolver = resolver;
+ int idx = getIndex(parent, condition.getParentSelectorQName());
+ ScoreNode[] nodes;
+ while ((nodes = parent.nextScoreNodes()) != null) {
+ Integer docNum = new Integer(nodes[idx].getDoc(reader));
+ parentIndex.addScoreNodes(docNum, nodes);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * The outer query hits loop contains the child nodes.
+ */
+ public ScoreNode[][] getMatchingScoreNodes(ScoreNode child) throws IOException {
+ docNums = resolver.getParents(child.getDoc(reader), docNums);
+ tmpScoreNodes.clear();
+ for (int i = 0; i < docNums.length; i++) {
+ ScoreNode[][] sn = parentIndex.getScoreNodes(new Integer(docNums[i]));
+ if (sn != null) {
+ for (int j = 0; j < sn.length; j++) {
+ tmpScoreNodes.add(sn[j]);
+ }
+ }
+ }
+ if (tmpScoreNodes.isEmpty()) {
+ return null;
+ } else {
+ return (ScoreNode[][]) tmpScoreNodes.toArray(new ScoreNode[tmpScoreNodes.size()][]);
+ }
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ChildNodeJoin.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/Condition.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/Condition.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/Condition.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/Condition.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,51 @@
+/*
+ * 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.core.query.lucene.join;
+
+import java.io.IOException;
+
+import org.apache.jackrabbit.core.query.lucene.ScoreNode;
+import org.apache.jackrabbit.spi.Name;
+
+/**
+ * <code>Condition</code> defines an interface for a join condition.
+ */
+public interface Condition {
+
+ /**
+ * Returns the matching inner score nodes for the given outer score node
+ * <code>sn</code>.
+ *
+ * @param outer the current score nodes of the outer source.
+ * @return the matching score nodes in the inner source.
+ * @throws IOException if an error occurs while evaluating the condition.
+ */
+ public ScoreNode[][] getMatchingScoreNodes(ScoreNode outer)
+ throws IOException;
+
+ /**
+ * @return the selector name of the inner hits.
+ */
+ public Name[] getInnerSelectorNames();
+
+ /**
+ * Closes this condition and frees resources.
+ *
+ * @throws IOException if an error occurs while closing this condition.
+ */
+ public void close() throws IOException;
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/Condition.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/DescendantNodeJoin.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/DescendantNodeJoin.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/DescendantNodeJoin.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/DescendantNodeJoin.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,136 @@
+/*
+ * 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.core.query.lucene.join;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.ArrayList;
+
+import org.apache.jackrabbit.core.query.lucene.MultiColumnQueryHits;
+import org.apache.jackrabbit.core.query.lucene.ScoreNode;
+import org.apache.jackrabbit.core.query.lucene.HierarchyResolver;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.lucene.index.IndexReader;
+
+/**
+ * <code>DescendantNodeJoin</code> implements a descendant node join condition.
+ */
+public class DescendantNodeJoin extends AbstractCondition {
+
+ /**
+ * A score node map with the score nodes from the inner query hits, indexed
+ * by the document number.
+ */
+ private final ScoreNodeMap contextIndex = new ScoreNodeMap();
+
+ /**
+ * The index reader.
+ */
+ private final IndexReader reader;
+
+ /**
+ * The hierarchy resolver.
+ */
+ private final HierarchyResolver resolver;
+
+ /**
+ * Reusable array of document numbers.
+ */
+ private int[] docNums = new int[1];
+
+ /**
+ * Reusable list of document number.
+ */
+ private final List ancestors = new ArrayList();
+
+ /**
+ * Reusable list of score nodes.
+ */
+ private final List scoreNodes = new ArrayList();
+
+ /**
+ * Creates a new descendant node join condition.
+ *
+ * @param context the inner query hits.
+ * @param contextSelectorName the selector name for the inner query hits.
+ * @param reader the index reader.
+ * @param resolver the hierarchy resolver.
+ * @throws IOException if an error occurs while reading fromt the index.
+ */
+ public DescendantNodeJoin(MultiColumnQueryHits context,
+ Name contextSelectorName,
+ IndexReader reader,
+ HierarchyResolver resolver) throws IOException {
+ super(context);
+ this.reader = reader;
+ this.resolver = resolver;
+ int idx = getIndex(context, contextSelectorName);
+ ScoreNode[] nodes;
+ while ((nodes = context.nextScoreNodes()) != null) {
+ Integer docNum = new Integer(nodes[idx].getDoc(reader));
+ contextIndex.addScoreNodes(docNum, nodes);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * The outer query hits loop contains the descendant nodes.
+ */
+ public ScoreNode[][] getMatchingScoreNodes(ScoreNode descendant)
+ throws IOException {
+ ancestors.clear();
+ collectAncestors(descendant.getDoc(reader));
+ scoreNodes.clear();
+ for (int i = 0; i < ancestors.size(); i++) {
+ Integer ancestor = (Integer) ancestors.get(i);
+ ScoreNode[][] sn = contextIndex.getScoreNodes(ancestor);
+ if (sn != null) {
+ for (int j = 0; j < sn.length; j++) {
+ scoreNodes.add(sn[j]);
+ }
+ }
+ }
+ if (scoreNodes.isEmpty()) {
+ return null;
+ } else {
+ return (ScoreNode[][]) scoreNodes.toArray(new ScoreNode[scoreNodes.size()][]);
+ }
+ }
+
+ /**
+ * Collects the ancestors of the given <code>doc</code> number into
+ * {@link #ancestors}.
+ *
+ * @param doc the current document number.
+ * @throws IOException if an error occurs while reading from the index.
+ */
+ private void collectAncestors(int doc) throws IOException {
+ docNums = resolver.getParents(doc, docNums);
+ if (docNums.length == 1) {
+ ancestors.add(new Integer(docNums[0]));
+ collectAncestors(docNums[0]);
+ } else if (docNums.length > 1) {
+ // clone because recursion uses docNums again
+ int[] tmp = (int[]) docNums.clone();
+ for (int i = 0; i < tmp.length; i++) {
+ ancestors.add(new Integer(tmp[i]));
+ collectAncestors(tmp[i]);
+ }
+ }
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/DescendantNodeJoin.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/DescendantPathNodeJoin.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/DescendantPathNodeJoin.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/DescendantPathNodeJoin.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/DescendantPathNodeJoin.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,93 @@
+/*
+ * 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.core.query.lucene.join;
+
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.query.lucene.MultiColumnQueryHits;
+import org.apache.jackrabbit.core.query.lucene.ScoreNode;
+import org.apache.jackrabbit.core.HierarchyManager;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.commons.name.PathBuilder;
+
+/**
+ * <code>DescendantPathNodeJoin</code> implements a descendant path node join
+ * condition.
+ */
+public class DescendantPathNodeJoin extends AbstractCondition {
+
+ /**
+ * A score node map with the score nodes from the inner query hits, indexed
+ * by the path of the of the inner query hits plus the relative path of this
+ * condition.
+ */
+ private final ScoreNodeMap contextIndex = new ScoreNodeMap();
+
+ /**
+ * The hierarchy manager.
+ */
+ private final HierarchyManager hmgr;
+
+ /**
+ * Creates a new descendant path node join condition.
+ *
+ * @param context the inner query hits.
+ * @param contextSelectorName the selector name for the inner query hits.
+ * @param relPath the relative path of the join condition.
+ * @param hmgr the hierarchy manager.
+ * @throws IOException if an error occurs while reading from the index.
+ */
+ public DescendantPathNodeJoin(MultiColumnQueryHits context,
+ Name contextSelectorName,
+ Path relPath,
+ HierarchyManager hmgr) throws IOException {
+ super(context);
+ this.hmgr = hmgr;
+ int idx = getIndex(context, contextSelectorName);
+ ScoreNode[] nodes;
+ while ((nodes = context.nextScoreNodes()) != null) {
+ try {
+ Path p = hmgr.getPath(nodes[idx].getNodeId());
+ PathBuilder builder = new PathBuilder(p);
+ builder.addAll(relPath.getElements());
+ p = builder.getPath().getNormalizedPath();
+ contextIndex.addScoreNodes(p, nodes);
+ } catch (RepositoryException e) {
+ // ignore
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * The outer query hits loop contains the descendant nodes.
+ */
+ public ScoreNode[][] getMatchingScoreNodes(ScoreNode descendant)
+ throws IOException {
+ try {
+ Path p = hmgr.getPath(descendant.getNodeId());
+ return contextIndex.getScoreNodes(p);
+ } catch (RepositoryException e) {
+ // ignore, probably does not exist anymore
+ }
+ return null;
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/DescendantPathNodeJoin.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/EquiJoin.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/EquiJoin.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/EquiJoin.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/EquiJoin.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,98 @@
+/*
+ * 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.core.query.lucene.join;
+
+import java.io.IOException;
+
+import org.apache.jackrabbit.core.query.lucene.MultiColumnQueryHits;
+import org.apache.jackrabbit.core.query.lucene.ScoreNode;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.SortComparatorSource;
+import org.apache.lucene.search.ScoreDocComparator;
+import org.apache.lucene.search.ScoreDoc;
+
+/**
+ * <code>EquiJoin</code> implements an equi join condition.
+ */
+public class EquiJoin extends AbstractCondition {
+
+ /**
+ * Reusable score doc for value lookups.
+ */
+ private final ScoreDoc sDoc = new ScoreDoc(-1, 1.0f);
+
+ /**
+ * The index reader.
+ */
+ private final IndexReader reader;
+
+ /**
+ * Map of inner score nodes indexed by the value of their join property.
+ */
+ private final ScoreNodeMap innerScoreNodes = new ScoreNodeMap();
+
+ /**
+ * The score doc comparator for the outer query hits.
+ */
+ private final ScoreDocComparator outerLookup;
+
+ /**
+ * Creates a new equi join condition.
+ *
+ * @param inner the inner query hits.
+ * @param innerScoreNodeIndex the selector name for the inner query hits.
+ * @param scs the sort comparator source.
+ * @param reader the index reader.
+ * @param innerProperty the name of the property of the inner query
+ * hits.
+ * @param outerProperty the name of the property of the outer query
+ * hits.
+ * @throws IOException if an error occurs while reading from the index.
+ */
+ public EquiJoin(MultiColumnQueryHits inner,
+ int innerScoreNodeIndex,
+ SortComparatorSource scs,
+ IndexReader reader,
+ Name innerProperty,
+ Name outerProperty) throws IOException {
+ super(inner);
+ this.reader = reader;
+ this.outerLookup = scs.newComparator(reader, outerProperty.toString());
+ ScoreDocComparator comparator = scs.newComparator(reader, innerProperty.toString());
+ ScoreNode[] nodes;
+ // create lookup map
+ while ((nodes = inner.nextScoreNodes()) != null) {
+ Integer doc = new Integer(nodes[innerScoreNodeIndex].getDoc(reader));
+ sDoc.doc = doc.intValue();
+ Comparable value = comparator.sortValue(sDoc);
+ if (value != null) {
+ innerScoreNodes.addScoreNodes(value, nodes);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ScoreNode[][] getMatchingScoreNodes(ScoreNode outer)
+ throws IOException {
+ sDoc.doc = outer.getDoc(reader);
+ Comparable value = outerLookup.sortValue(sDoc);
+ return innerScoreNodes.getScoreNodes(value);
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/EquiJoin.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/Join.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/Join.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/Join.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/Join.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,359 @@
+/*
+ * 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.core.query.lucene.join;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Arrays;
+import java.util.LinkedList;
+
+import org.apache.jackrabbit.core.query.lucene.MultiColumnQueryHits;
+import org.apache.jackrabbit.core.query.lucene.ScoreNode;
+import org.apache.jackrabbit.core.query.lucene.HierarchyResolver;
+import org.apache.jackrabbit.core.HierarchyManager;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.query.qom.JoinConditionImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.DefaultQOMTreeVisitor;
+import org.apache.jackrabbit.spi.commons.query.qom.DescendantNodeJoinConditionImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.EquiJoinConditionImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.ChildNodeJoinConditionImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.SameNodeJoinConditionImpl;
+import org.apache.jackrabbit.spi.commons.query.jsr283.qom.QueryObjectModelConstants;
+import org.apache.lucene.search.SortComparatorSource;
+import org.apache.lucene.index.IndexReader;
+
+/**
+ * <code>Join</code> implements the result of a join.
+ */
+public class Join implements MultiColumnQueryHits, QueryObjectModelConstants {
+
+ /**
+ * The outer query hits.
+ */
+ protected final MultiColumnQueryHits outer;
+
+ /**
+ * The score node index of the outer query hits.
+ */
+ protected final int outerScoreNodeIndex;
+
+ /**
+ * Whether this is an inner join.
+ */
+ protected final boolean innerJoin;
+
+ /**
+ * The join condition.
+ */
+ protected final Condition condition;
+
+ /**
+ * The selector names.
+ */
+ protected final Name[] selectorNames;
+
+ /**
+ * An array of empty inner query hits.
+ */
+ protected final ScoreNode[] emptyInnerHits;
+
+ /**
+ * A buffer for joined score node rows.
+ */
+ protected final List buffer = new LinkedList();
+
+ /**
+ * Creates a new join.
+ *
+ * @param outer the outer query hits.
+ * @param outerScoreNodeIndex the score node index of the outer query hits
+ * that is used for the join.
+ * @param innerJoin whether this is an inner join.
+ * @param condition the join condition.
+ */
+ private Join(MultiColumnQueryHits outer,
+ int outerScoreNodeIndex,
+ boolean innerJoin,
+ Condition condition) {
+ this.outer = outer;
+ this.outerScoreNodeIndex = outerScoreNodeIndex;
+ this.innerJoin = innerJoin;
+ this.condition = condition;
+ this.emptyInnerHits = new ScoreNode[condition.getInnerSelectorNames().length];
+ // outer selector names go to the left, inner selector
+ // names go to the right.
+ // this needs to be in sync with ScoreNode[] aggregration/joining
+ // in nextScoreNodes() !
+ this.selectorNames = new Name[outer.getSelectorNames().length + emptyInnerHits.length];
+ System.arraycopy(outer.getSelectorNames(), 0, selectorNames, 0, outer.getSelectorNames().length);
+ System.arraycopy(condition.getInnerSelectorNames(), 0, selectorNames, outer.getSelectorNames().length, emptyInnerHits.length);
+ }
+
+ /**
+ * Creates a new join result.
+ *
+ * @param left the left query hits.
+ * @param right the right query hits.
+ * @param joinType the join type.
+ * @param condition the QOM join condition.
+ * @param reader the index reader.
+ * @param resolver the hierarchy resolver.
+ * @param scs the sort comparator source of the index.
+ * @param hmgr the hierarchy manager of the workspace.
+ * @return the join result.
+ * @throws IOException if an error occurs while executing the join.
+ */
+ public static Join create(final MultiColumnQueryHits left,
+ final MultiColumnQueryHits right,
+ final int joinType,
+ final JoinConditionImpl condition,
+ final IndexReader reader,
+ final HierarchyResolver resolver,
+ final SortComparatorSource scs,
+ final HierarchyManager hmgr)
+ throws IOException {
+ try {
+ return (Join) condition.accept(new DefaultQOMTreeVisitor() {
+
+ private boolean isInner = joinType == JOIN_TYPE_INNER;
+ private MultiColumnQueryHits outer;
+ private int outerIdx;
+
+ public Object visit(DescendantNodeJoinConditionImpl node, Object data)
+ throws Exception {
+ MultiColumnQueryHits ancestor = getSourceWithName(node.getAncestorSelectorQName(), left, right);
+ MultiColumnQueryHits descendant = getSourceWithName(node.getDescendantSelectorQName(), left, right);
+ Condition c;
+ if (isInner || descendant == left && joinType == JOIN_TYPE_LEFT_OUTER
+ || descendant == right && joinType == JOIN_TYPE_RIGHT_OUTER) {
+ // also applies to inner join
+ // assumption: DescendantNodeJoin is more
+ // efficient than AncestorNodeJoin, TODO: verify
+ outer = descendant;
+ outerIdx = getIndex(outer, node.getDescendantSelectorQName());
+ c = new DescendantNodeJoin(ancestor, node.getAncestorSelectorQName(), reader, resolver);
+ } else {
+ // left == ancestor
+ outer = ancestor;
+ outerIdx = getIndex(outer, node.getAncestorSelectorQName());
+ c = new AncestorNodeJoin(descendant, node.getDescendantSelectorQName(), reader, resolver);
+ }
+ return new Join(outer, outerIdx, isInner, c);
+ }
+
+ public Object visit(EquiJoinConditionImpl node, Object data)
+ throws Exception {
+ MultiColumnQueryHits src1 = getSourceWithName(node.getSelector1QName(), left, right);
+ MultiColumnQueryHits src2 = getSourceWithName(node.getSelector2QName(), left, right);
+ MultiColumnQueryHits inner;
+ Name innerName;
+ Name innerPropName;
+ Name outerPropName;
+ if (isInner || src1 == left && joinType == JOIN_TYPE_LEFT_OUTER
+ || src1 == right && joinType == JOIN_TYPE_RIGHT_OUTER) {
+ outer = src1;
+ outerIdx = getIndex(outer, node.getSelector1QName());
+ inner = src2;
+ innerName = node.getSelector2QName();
+ innerPropName = node.getProperty2QName();
+ outerPropName = node.getProperty1QName();
+ } else {
+ outer = src2;
+ outerIdx = getIndex(outer, node.getSelector2QName());
+ inner = src1;
+ innerName = node.getSelector1QName();
+ innerPropName = node.getProperty1QName();
+ outerPropName = node.getProperty2QName();
+ }
+
+ Condition c = new EquiJoin(inner, getIndex(inner, innerName),
+ scs, reader, innerPropName, outerPropName);
+ return new Join(outer, outerIdx, isInner, c);
+ }
+
+ public Object visit(ChildNodeJoinConditionImpl node, Object data)
+ throws Exception {
+ MultiColumnQueryHits child = getSourceWithName(node.getChildSelectorQName(), left, right);
+ MultiColumnQueryHits parent = getSourceWithName(node.getParentSelectorQName(), left, right);
+ Condition c;
+ if (child == left && joinType == JOIN_TYPE_LEFT_OUTER
+ || child == right && joinType == JOIN_TYPE_RIGHT_OUTER) {
+ outer = child;
+ outerIdx = getIndex(outer, node.getChildSelectorQName());
+ c = new ChildNodeJoin(parent, reader, resolver, node);
+ } else {
+ // also applies to inner joins
+ // assumption: ParentNodeJoin is more efficient than
+ // ChildNodeJoin, TODO: verify
+ outer = parent;
+ outerIdx = getIndex(outer, node.getParentSelectorQName());
+ c = new ParentNodeJoin(child, reader, resolver, node);
+ }
+ return new Join(outer, outerIdx, isInner, c);
+ }
+
+ public Object visit(SameNodeJoinConditionImpl node, Object data)
+ throws Exception {
+ MultiColumnQueryHits src1 = getSourceWithName(node.getSelector1QName(), left, right);
+ MultiColumnQueryHits src2 = getSourceWithName(node.getSelector2QName(), left, right);
+ Condition c;
+ if (isInner || src1 == left && joinType == JOIN_TYPE_LEFT_OUTER
+ || src1 == right && joinType == JOIN_TYPE_RIGHT_OUTER) {
+ outer = src1;
+ outerIdx = getIndex(outer, node.getSelector1QName());
+ if (node.getSelector2QPath() != null) {
+ c = new DescendantPathNodeJoin(src2, node.getSelector2QName(),
+ node.getSelector2QPath(), hmgr);
+ } else {
+ c = new SameNodeJoin(src2, node.getSelector2QName(), reader);
+ }
+ } else {
+ outer = src2;
+ outerIdx = getIndex(outer, node.getSelector2QName());
+ if (node.getSelector2QPath() != null) {
+ c = new AncestorPathNodeJoin(src1, node.getSelector1QName(),
+ node.getSelector2QPath(), hmgr);
+ } else {
+ c = new SameNodeJoin(src1, node.getSelector1QName(), reader);
+ }
+ }
+ return new Join(outer, outerIdx, isInner, c);
+ }
+ }, null);
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ IOException ex = new IOException(e.getMessage());
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ScoreNode[] nextScoreNodes() throws IOException {
+ if (!buffer.isEmpty()) {
+ return (ScoreNode[]) buffer.remove(0);
+ }
+ do {
+ // refill buffer
+ ScoreNode[] sn = outer.nextScoreNodes();
+ if (sn == null) {
+ return null;
+ }
+ ScoreNode[][] nodes = condition.getMatchingScoreNodes(sn[outerScoreNodeIndex]);
+ if (nodes != null) {
+ for (int i = 0; i < nodes.length; i++) {
+ ScoreNode[] node = nodes[i];
+ // create array with both outer and inner
+ ScoreNode[] tmp = new ScoreNode[sn.length + node.length];
+ System.arraycopy(sn, 0, tmp, 0, sn.length);
+ System.arraycopy(node, 0, tmp, sn.length, node.length);
+ buffer.add(tmp);
+ }
+ } else if (!innerJoin) {
+ // create array with both inner and outer
+ ScoreNode[] tmp = new ScoreNode[sn.length + emptyInnerHits.length];
+ System.arraycopy(sn, 0, tmp, 0, sn.length);
+ System.arraycopy(emptyInnerHits, 0, tmp, sn.length, emptyInnerHits.length);
+ buffer.add(tmp);
+ }
+ } while (buffer.isEmpty());
+
+ return (ScoreNode[]) buffer.remove(0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Name[] getSelectorNames() {
+ return selectorNames;
+ }
+
+ /**
+ * {@inheritDoc}
+ * Closes {@link #outer} source and the {@link #condition}.
+ */
+ public void close() throws IOException {
+ IOException ex = null;
+ try {
+ outer.close();
+ } catch (IOException e) {
+ ex = e;
+ }
+ try {
+ condition.close();
+ } catch (IOException e) {
+ if (ex == null) {
+ ex = e;
+ }
+ }
+ if (ex != null) {
+ throw ex;
+ }
+ }
+
+ /**
+ * This default implementation always returns <code>-1</code>.
+ *
+ * @return always <code>-1</code>.
+ */
+ public int getSize() {
+ return -1;
+ }
+
+ /**
+ * {@inheritDoc}
+ * Skips by calling {@link #nextScoreNodes()} <code>n</code> times. Sub
+ * classes may provide a more performance implementation.
+ */
+ public void skip(int n) throws IOException {
+ while (n-- > 0) {
+ if (nextScoreNodes() == null) {
+ return;
+ }
+ }
+ }
+
+ protected static MultiColumnQueryHits getSourceWithName(
+ Name selectorName,
+ MultiColumnQueryHits left,
+ MultiColumnQueryHits right) {
+ if (Arrays.asList(left.getSelectorNames()).contains(selectorName)) {
+ return left;
+ } else if (Arrays.asList(right.getSelectorNames()).contains(selectorName)) {
+ return right;
+ } else {
+ throw new IllegalArgumentException("unknown selector name: " + selectorName);
+ }
+ }
+
+ /**
+ * Returns the index of the selector with the given <code>selectorName</code>
+ * within the given <code>source</code>.
+ *
+ * @param source a source.
+ * @param selectorName a selector name.
+ * @return the index within the source or <code>-1</code> if the name does
+ * not exist in <code>source</code>.
+ */
+ protected static int getIndex(MultiColumnQueryHits source,
+ Name selectorName) {
+ return Arrays.asList(source.getSelectorNames()).indexOf(selectorName);
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/Join.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ParentNodeJoin.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ParentNodeJoin.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ParentNodeJoin.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ParentNodeJoin.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,78 @@
+/*
+ * 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.core.query.lucene.join;
+
+import java.io.IOException;
+
+import org.apache.jackrabbit.core.query.lucene.ScoreNode;
+import org.apache.jackrabbit.core.query.lucene.MultiColumnQueryHits;
+import org.apache.jackrabbit.core.query.lucene.HierarchyResolver;
+import org.apache.jackrabbit.spi.commons.query.qom.ChildNodeJoinConditionImpl;
+import org.apache.lucene.index.IndexReader;
+
+/**
+ * <code>ParentNodeJoin</code> implements a parent node join condition.
+ */
+public class ParentNodeJoin extends AbstractCondition {
+
+ /**
+ * The child score nodes indexed by their parent document number.
+ */
+ private final ScoreNodeMap childIndex = new ScoreNodeMap();
+
+ /**
+ * The index reader.
+ */
+ private final IndexReader reader;
+
+ /**
+ * Creates a new parent node join condition.
+ *
+ * @param child the inner query hits.
+ * @param reader the index reader.
+ * @param resolver the hierarchy resolver.
+ * @param condition the QOM child node join condition.
+ * @throws IOException if an error occurs while reading from the index.
+ */
+ public ParentNodeJoin(MultiColumnQueryHits child,
+ IndexReader reader,
+ HierarchyResolver resolver,
+ ChildNodeJoinConditionImpl condition)
+ throws IOException {
+ super(child);
+ this.reader = reader;
+ int idx = getIndex(child, condition.getChildSelectorQName());
+ ScoreNode[] nodes;
+ int[] docNums = new int[1];
+ while ((nodes = child.nextScoreNodes()) != null) {
+ docNums = resolver.getParents(nodes[idx].getDoc(reader), docNums);
+ for (int i = 0; i < docNums.length; i++) {
+ Integer parentId = new Integer(docNums[i]);
+ childIndex.addScoreNodes(parentId, nodes);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * The outer query hits loop contains the parent score nodes.
+ */
+ public ScoreNode[][] getMatchingScoreNodes(ScoreNode parent)
+ throws IOException {
+ return childIndex.getScoreNodes(new Integer(parent.getDoc(reader)));
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ParentNodeJoin.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoin.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoin.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoin.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoin.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,70 @@
+/*
+ * 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.core.query.lucene.join;
+
+import java.io.IOException;
+
+import org.apache.jackrabbit.core.query.lucene.MultiColumnQueryHits;
+import org.apache.jackrabbit.core.query.lucene.ScoreNode;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.lucene.index.IndexReader;
+
+/**
+ * <code>SameNodeJoin</code> implements a same node join condition.
+ */
+public class SameNodeJoin extends AbstractCondition {
+
+ /**
+ * A score node map with the score nodes from the inner query hits, indexed
+ * by their document number.
+ */
+ private final ScoreNodeMap innerIndex = new ScoreNodeMap();
+
+ /**
+ * The index reader.
+ */
+ private final IndexReader reader;
+
+ /**
+ * Creates a new same node join.
+ *
+ * @param inner the inner query hits.
+ * @param innerSelectorName the selector name for the inner query hits.
+ * @param reader the index reader.
+ * @throws IOException if an error occurs while reading from the index.
+ */
+ public SameNodeJoin(MultiColumnQueryHits inner,
+ Name innerSelectorName,
+ IndexReader reader) throws IOException {
+ super(inner);
+ this.reader = reader;
+ int idx = getIndex(inner, innerSelectorName);
+ ScoreNode[] nodes;
+ while ((nodes = inner.nextScoreNodes()) != null) {
+ Integer docNum = new Integer(nodes[idx].getDoc(reader));
+ innerIndex.addScoreNodes(docNum, nodes);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ScoreNode[][] getMatchingScoreNodes(ScoreNode outer)
+ throws IOException {
+ return innerIndex.getScoreNodes(new Integer(outer.getDoc(reader)));
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoin.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ScoreNodeMap.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ScoreNodeMap.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ScoreNodeMap.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ScoreNodeMap.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,93 @@
+/*
+ * 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.core.query.lucene.join;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ArrayList;
+
+import org.apache.jackrabbit.core.query.lucene.ScoreNode;
+
+/**
+ * <code>ScoreNodeMap</code> implements a simple mapping of an arbitrary key
+ * to an array of <code>ScoreNode[]</code>.
+ */
+public final class ScoreNodeMap {
+
+ /**
+ * The internal map.
+ */
+ private final Map map = new HashMap();
+
+ /**
+ * Adds <code>scoreNodes</code> to this map under the given <code>key</code>.
+ * If there already exists a mapping with the given <code>key</code> the
+ * <code>scoreNodes</code> are added to the existingmapping. The add
+ * operation works as follows:
+ * <ul>
+ * <li>If the existing value for <code>key</code> is a <code>ScoreNode[]</code>,
+ * then the value is turned into a <code>List</code> and the exising value
+ * as well as the new value are added to the <code>List</code>. Finally
+ * the <code>List</code> is uses as the new value for the mapping.
+ * </li>
+ * <li>If the existing value for <code>key</code> is a <code>List</code> the
+ * <code>scoreNodes</code> are simply added to the <code>List</code>.
+ * </li>
+ * </ul>
+ *
+ * @param key the lookup key.
+ * @param nodes the score nodes.
+ */
+ public void addScoreNodes(Object key, ScoreNode[] nodes) {
+ Object existing = map.get(key);
+ if (existing == null) {
+ existing = nodes;
+ map.put(key, existing);
+ } else if (existing instanceof List) {
+ ((List) existing).add(nodes);
+ } else {
+ // ScoreNode[]
+ ArrayList tmp = new ArrayList();
+ tmp.add(existing);
+ tmp.add(nodes);
+ existing = tmp;
+ map.put(key, existing);
+ }
+ }
+
+ /**
+ * Returns an array of <code>ScoreNode[]</code> for the given
+ * <code>key</code>.
+ *
+ * @param key the key.
+ * @return an array of <code>ScoreNode[]</code> that match the given
+ * <code>key</code> or <code>null</code> if there is none.
+ */
+ public ScoreNode[][] getScoreNodes(Object key) {
+ Object sn = map.get(key);
+ if (sn == null) {
+ return null;
+ } else if (sn instanceof List) {
+ List list = (List) sn;
+ return (ScoreNode[][]) list.toArray(new ScoreNode[list.size()][]);
+ } else {
+ // ScoreNode[]
+ return new ScoreNode[][]{(ScoreNode[]) sn};
+ }
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ScoreNodeMap.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/AbstractJoinTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/AbstractJoinTest.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/AbstractJoinTest.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/AbstractJoinTest.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,89 @@
+/*
+ * 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.api.jsr283.query.qom;
+
+import javax.jcr.query.QueryResult;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.spi.commons.query.jsr283.qom.QueryObjectModel;
+import org.apache.jackrabbit.spi.commons.query.jsr283.qom.Constraint;
+import org.apache.jackrabbit.spi.commons.query.jsr283.qom.JoinCondition;
+
+/**
+ * <code>AbstractJoinTest</code> provides utility methods for join related
+ * tests.
+ */
+public abstract class AbstractJoinTest extends AbstractQOMTest {
+
+ /**
+ * Name of the left selector.
+ */
+ protected static final String LEFT = "left";
+
+ /**
+ * Name of the right selector.
+ */
+ protected static final String RIGHT = "right";
+
+ /**
+ * The selector names for the join.
+ */
+ protected static final String[] SELECTOR_NAMES = new String[]{LEFT, RIGHT};
+
+ //--------------------------< utilities >-----------------------------------
+
+ protected void checkResult(QueryResult result, Node[][] nodes)
+ throws RepositoryException {
+ checkResult(result, SELECTOR_NAMES, nodes);
+ }
+
+ protected QueryObjectModel createQuery(int joinType,
+ JoinCondition condition)
+ throws RepositoryException {
+ return createQuery(joinType, condition, null, null);
+ }
+
+ protected QueryObjectModel createQuery(int joinType,
+ JoinCondition condition,
+ Constraint left,
+ Constraint right)
+ throws RepositoryException {
+ // only consider nodes under test root
+ Constraint constraint;
+ if (joinType == JOIN_TYPE_LEFT_OUTER) {
+ constraint = qomFactory.descendantNode(LEFT, testRoot);
+ } else {
+ constraint = qomFactory.descendantNode(RIGHT, testRoot);
+ }
+
+ if (left != null) {
+ constraint = qomFactory.and(constraint, left);
+ }
+ if (right != null) {
+ constraint = qomFactory.and(constraint, right);
+ }
+ return qomFactory.createQuery(
+ qomFactory.join(
+ qomFactory.selector(testNodeType, LEFT),
+ qomFactory.selector(testNodeType, RIGHT),
+ joinType,
+ condition
+ ), constraint, null, null
+ );
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/AbstractJoinTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/AbstractQOMTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/AbstractQOMTest.java?rev=768954&r1=768218&r2=768954&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/AbstractQOMTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/AbstractQOMTest.java Mon Apr 27 12:43:28 2009
@@ -14,7 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.jackrabbit.core.query.qom;
+package org.apache.jackrabbit.api.jsr283.query.qom;
+
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Iterator;
import org.apache.jackrabbit.test.api.query.AbstractQueryTest;
@@ -22,10 +26,14 @@
import org.apache.jackrabbit.spi.commons.query.jsr283.qom.QueryObjectModelConstants;
import org.apache.jackrabbit.core.query.QueryManagerImpl;
import org.apache.jackrabbit.core.query.QueryImpl;
+import org.apache.jackrabbit.api.jsr283.query.Row;
import javax.jcr.query.Query;
+import javax.jcr.query.QueryResult;
+import javax.jcr.query.RowIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
+import javax.jcr.Node;
/**
* <code>AbstractQOMTest</code> is a base class for test cases on the JQOM.
@@ -58,4 +66,64 @@
// TODO: remove cast when bindValue() is available on JSR 283 Query
((QueryImpl) q).bindValue(var, value);
}
+
+ protected void checkResult(QueryResult result,
+ String[] selectorNames,
+ Node[][] nodes)
+ throws RepositoryException {
+ // collect rows
+ Set expectedPaths = new HashSet();
+ log.println("expected:");
+ for (int i = 0; i < nodes.length; i++) {
+ StringBuffer aggregatedPaths = new StringBuffer();
+ for (int j = 0; j < nodes[i].length; j++) {
+ aggregatedPaths.append(getPath(nodes[i][j]));
+ aggregatedPaths.append("|");
+ }
+ expectedPaths.add(aggregatedPaths.toString());
+ log.println(aggregatedPaths.toString());
+ }
+
+ Set resultPaths = new HashSet();
+ log.println("result:");
+ for (RowIterator it = result.getRows(); it.hasNext();) {
+ Row r = (Row) it.nextRow();
+ StringBuffer aggregatedPaths = new StringBuffer();
+ for (int i = 0; i < selectorNames.length; i++) {
+ aggregatedPaths.append(getPath(r.getNode(selectorNames[i])));
+ aggregatedPaths.append("|");
+ }
+ resultPaths.add(aggregatedPaths.toString());
+ log.println(aggregatedPaths.toString());
+ }
+
+ // 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));
+ }
+ }
+
+ /**
+ * Returns the path of the <code>node</code> or an empty string if
+ * <code>node</code> is <code>null</code>.
+ *
+ * @param node a node or <code>null</code>.
+ * @return the path of the node or an empty string if <code>node</code> is
+ * <code>null</code>.
+ * @throws RepositoryException if an error occurs while reading from the
+ * repository.
+ */
+ protected static String getPath(Node node) throws RepositoryException {
+ if (node != null) {
+ return node.getPath();
+ } else {
+ return "";
+ }
+ }
}
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/BindVariableValueTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/BindVariableValueTest.java?rev=768954&r1=768218&r2=768954&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/BindVariableValueTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/BindVariableValueTest.java Mon Apr 27 12:43:28 2009
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.jackrabbit.core.query.qom;
+package org.apache.jackrabbit.api.jsr283.query.qom;
import javax.jcr.RepositoryException;
import javax.jcr.Node;
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/ChildNodeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/ChildNodeTest.java?rev=768954&r1=768218&r2=768954&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/ChildNodeTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/ChildNodeTest.java Mon Apr 27 12:43:28 2009
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.jackrabbit.core.query.qom;
+package org.apache.jackrabbit.api.jsr283.query.qom;
import org.apache.jackrabbit.test.NotExecutableException;