aboutsummaryrefslogtreecommitdiff
path: root/src/share/classes/com/sun/org/apache/xpath/internal/axes/PredicatedNodeTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/share/classes/com/sun/org/apache/xpath/internal/axes/PredicatedNodeTest.java')
-rw-r--r--src/share/classes/com/sun/org/apache/xpath/internal/axes/PredicatedNodeTest.java649
1 files changed, 649 insertions, 0 deletions
diff --git a/src/share/classes/com/sun/org/apache/xpath/internal/axes/PredicatedNodeTest.java b/src/share/classes/com/sun/org/apache/xpath/internal/axes/PredicatedNodeTest.java
new file mode 100644
index 0000000..965f3f3
--- /dev/null
+++ b/src/share/classes/com/sun/org/apache/xpath/internal/axes/PredicatedNodeTest.java
@@ -0,0 +1,649 @@
+/*
+ * reserved comment block
+ * DO NOT REMOVE OR ALTER!
+ */
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * 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.
+ */
+/*
+ * $Id: PredicatedNodeTest.java,v 1.2.4.2 2005/09/14 19:45:20 jeffsuttor Exp $
+ */
+package com.sun.org.apache.xpath.internal.axes;
+
+import com.sun.org.apache.xml.internal.dtm.DTM;
+import com.sun.org.apache.xml.internal.dtm.DTMIterator;
+import com.sun.org.apache.xml.internal.utils.PrefixResolver;
+import com.sun.org.apache.xpath.internal.Expression;
+import com.sun.org.apache.xpath.internal.ExpressionOwner;
+import com.sun.org.apache.xpath.internal.XPathContext;
+import com.sun.org.apache.xpath.internal.XPathVisitor;
+import com.sun.org.apache.xpath.internal.compiler.Compiler;
+import com.sun.org.apache.xpath.internal.objects.XObject;
+import com.sun.org.apache.xpath.internal.patterns.NodeTest;
+
+public abstract class PredicatedNodeTest extends NodeTest implements SubContextList
+{
+ static final long serialVersionUID = -6193530757296377351L;
+
+ /**
+ * Construct an AxesWalker using a LocPathIterator.
+ *
+ * @param locPathIterator non-null reference to the parent iterator.
+ */
+ PredicatedNodeTest(LocPathIterator locPathIterator)
+ {
+ m_lpi = locPathIterator;
+ }
+
+ /**
+ * Construct an AxesWalker. The location path iterator will have to be set
+ * before use.
+ */
+ PredicatedNodeTest()
+ {
+ }
+
+ /**
+ * Read the object from a serialization stream.
+ *
+ * @param stream Input stream to read from
+ *
+ * @throws java.io.IOException
+ * @throws javax.xml.transform.TransformerException
+ */
+ private void readObject(java.io.ObjectInputStream stream)
+ throws java.io.IOException, javax.xml.transform.TransformerException
+ {
+ try
+ {
+ stream.defaultReadObject();
+ m_predicateIndex = -1;
+ resetProximityPositions();
+ }
+ catch (ClassNotFoundException cnfe)
+ {
+ throw new javax.xml.transform.TransformerException(cnfe);
+ }
+ }
+
+ /**
+ * Get a cloned PrdicatedNodeTest.
+ *
+ * @return A new PredicatedNodeTest that can be used without mutating this one.
+ *
+ * @throws CloneNotSupportedException
+ */
+ public Object clone() throws CloneNotSupportedException
+ {
+ // Do not access the location path itterator during this operation!
+
+ PredicatedNodeTest clone = (PredicatedNodeTest) super.clone();
+
+ if ((null != this.m_proximityPositions)
+ && (this.m_proximityPositions == clone.m_proximityPositions))
+ {
+ clone.m_proximityPositions = new int[this.m_proximityPositions.length];
+
+ System.arraycopy(this.m_proximityPositions, 0,
+ clone.m_proximityPositions, 0,
+ this.m_proximityPositions.length);
+ }
+
+ if(clone.m_lpi == this)
+ clone.m_lpi = (LocPathIterator)clone;
+
+ return clone;
+ }
+
+ // Only for clones for findLastPos. See bug4638.
+ protected int m_predCount = -1;
+
+ /**
+ * Get the number of predicates that this walker has.
+ *
+ * @return the number of predicates that this walker has.
+ */
+ public int getPredicateCount()
+ {
+ if(-1 == m_predCount)
+ return (null == m_predicates) ? 0 : m_predicates.length;
+ else
+ return m_predCount;
+ }
+
+ /**
+ * Set the number of predicates that this walker has. This does more
+ * that one would think, as it creates a new predicate array of the
+ * size of the count argument, and copies count predicates into the new
+ * one from the old, and then reassigns the predicates value. All this
+ * to keep from having to have a predicate count value.
+ *
+ * @param count The number of predicates, which must be equal or less
+ * than the existing count.
+ */
+ public void setPredicateCount(int count)
+ {
+ if(count > 0)
+ {
+ Expression[] newPredicates = new Expression[count];
+ for (int i = 0; i < count; i++)
+ {
+ newPredicates[i] = m_predicates[i];
+ }
+ m_predicates = newPredicates;
+ }
+ else
+ m_predicates = null;
+
+ }
+
+ /**
+ * Init predicate info.
+ *
+ * @param compiler The Compiler object that has information about this
+ * walker in the op map.
+ * @param opPos The op code position of this location step.
+ *
+ * @throws javax.xml.transform.TransformerException
+ */
+ protected void initPredicateInfo(Compiler compiler, int opPos)
+ throws javax.xml.transform.TransformerException
+ {
+
+ int pos = compiler.getFirstPredicateOpPos(opPos);
+
+ if(pos > 0)
+ {
+ m_predicates = compiler.getCompiledPredicates(pos);
+ if(null != m_predicates)
+ {
+ for(int i = 0; i < m_predicates.length; i++)
+ {
+ m_predicates[i].exprSetParent(this);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get a predicate expression at the given index.
+ *
+ *
+ * @param index Index of the predicate.
+ *
+ * @return A predicate expression.
+ */
+ public Expression getPredicate(int index)
+ {
+ return m_predicates[index];
+ }
+
+ /**
+ * Get the current sub-context position.
+ *
+ * @return The node position of this walker in the sub-context node list.
+ */
+ public int getProximityPosition()
+ {
+
+ // System.out.println("getProximityPosition - m_predicateIndex: "+m_predicateIndex);
+ return getProximityPosition(m_predicateIndex);
+ }
+
+ /**
+ * Get the current sub-context position.
+ *
+ * @param xctxt The XPath runtime context.
+ *
+ * @return The node position of this walker in the sub-context node list.
+ */
+ public int getProximityPosition(XPathContext xctxt)
+ {
+ return getProximityPosition();
+ }
+
+ /**
+ * Get the index of the last node that can be itterated to.
+ *
+ *
+ * @param xctxt XPath runtime context.
+ *
+ * @return the index of the last node that can be itterated to.
+ */
+ public abstract int getLastPos(XPathContext xctxt);
+
+ /**
+ * Get the current sub-context position.
+ *
+ * @param predicateIndex The index of the predicate where the proximity
+ * should be taken from.
+ *
+ * @return The node position of this walker in the sub-context node list.
+ */
+ protected int getProximityPosition(int predicateIndex)
+ {
+ return (predicateIndex >= 0) ? m_proximityPositions[predicateIndex] : 0;
+ }
+
+ /**
+ * Reset the proximity positions counts.
+ */
+ public void resetProximityPositions()
+ {
+ int nPredicates = getPredicateCount();
+ if (nPredicates > 0)
+ {
+ if (null == m_proximityPositions)
+ m_proximityPositions = new int[nPredicates];
+
+ for (int i = 0; i < nPredicates; i++)
+ {
+ try
+ {
+ initProximityPosition(i);
+ }
+ catch(Exception e)
+ {
+ // TODO: Fix this...
+ throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Init the proximity position to zero for a forward axes.
+ *
+ * @param i The index into the m_proximityPositions array.
+ *
+ * @throws javax.xml.transform.TransformerException
+ */
+ public void initProximityPosition(int i) throws javax.xml.transform.TransformerException
+ {
+ m_proximityPositions[i] = 0;
+ }
+
+ /**
+ * Count forward one proximity position.
+ *
+ * @param i The index into the m_proximityPositions array, where the increment
+ * will occur.
+ */
+ protected void countProximityPosition(int i)
+ {
+ // Note that in the case of a UnionChildIterator, this may be a
+ // static object and so m_proximityPositions may indeed be null!
+ int[] pp = m_proximityPositions;
+ if ((null != pp) && (i < pp.length))
+ pp[i]++;
+ }
+
+ /**
+ * Tells if this is a reverse axes.
+ *
+ * @return false, unless a derived class overrides.
+ */
+ public boolean isReverseAxes()
+ {
+ return false;
+ }
+
+ /**
+ * Get which predicate is executing.
+ *
+ * @return The current predicate index, or -1 if no predicate is executing.
+ */
+ public int getPredicateIndex()
+ {
+ return m_predicateIndex;
+ }
+
+ /**
+ * Process the predicates.
+ *
+ * @param context The current context node.
+ * @param xctxt The XPath runtime context.
+ *
+ * @return the result of executing the predicate expressions.
+ *
+ * @throws javax.xml.transform.TransformerException
+ */
+ boolean executePredicates(int context, XPathContext xctxt)
+ throws javax.xml.transform.TransformerException
+ {
+
+ int nPredicates = getPredicateCount();
+ // System.out.println("nPredicates: "+nPredicates);
+ if (nPredicates == 0)
+ return true;
+
+ PrefixResolver savedResolver = xctxt.getNamespaceContext();
+
+ try
+ {
+ m_predicateIndex = 0;
+ xctxt.pushSubContextList(this);
+ xctxt.pushNamespaceContext(m_lpi.getPrefixResolver());
+ xctxt.pushCurrentNode(context);
+
+ for (int i = 0; i < nPredicates; i++)
+ {
+ // System.out.println("Executing predicate expression - waiting count: "+m_lpi.getWaitingCount());
+ XObject pred = m_predicates[i].execute(xctxt);
+ // System.out.println("\nBack from executing predicate expression - waiting count: "+m_lpi.getWaitingCount());
+ // System.out.println("pred.getType(): "+pred.getType());
+ if (XObject.CLASS_NUMBER == pred.getType())
+ {
+ if (DEBUG_PREDICATECOUNTING)
+ {
+ System.out.flush();
+ System.out.println("\n===== start predicate count ========");
+ System.out.println("m_predicateIndex: " + m_predicateIndex);
+ // System.out.println("getProximityPosition(m_predicateIndex): "
+ // + getProximityPosition(m_predicateIndex));
+ System.out.println("pred.num(): " + pred.num());
+ }
+
+ int proxPos = this.getProximityPosition(m_predicateIndex);
+ int predIndex = (int) pred.num();
+ if (proxPos != predIndex)
+ {
+ if (DEBUG_PREDICATECOUNTING)
+ {
+ System.out.println("\nnode context: "+nodeToString(context));
+ System.out.println("index predicate is false: "+proxPos);
+ System.out.println("\n===== end predicate count ========");
+ }
+ return false;
+ }
+ else if (DEBUG_PREDICATECOUNTING)
+ {
+ System.out.println("\nnode context: "+nodeToString(context));
+ System.out.println("index predicate is true: "+proxPos);
+ System.out.println("\n===== end predicate count ========");
+ }
+
+ // If there is a proximity index that will not change during the
+ // course of itteration, then we know there can be no more true
+ // occurances of this predicate, so flag that we're done after
+ // this.
+ //
+ // bugzilla 14365
+ // We can't set m_foundLast = true unless we're sure that -all-
+ // remaining parameters are stable, or else last() fails. Fixed so
+ // only sets m_foundLast if on the last predicate
+ if(m_predicates[i].isStableNumber() && i == nPredicates - 1)
+ {
+ m_foundLast = true;
+ }
+ }
+ else if (!pred.bool())
+ return false;
+
+ countProximityPosition(++m_predicateIndex);
+ }
+ }
+ finally
+ {
+ xctxt.popCurrentNode();
+ xctxt.popNamespaceContext();
+ xctxt.popSubContextList();
+ m_predicateIndex = -1;
+ }
+
+ return true;
+ }
+
+ /**
+ * This function is used to fixup variables from QNames to stack frame
+ * indexes at stylesheet build time.
+ * @param vars List of QNames that correspond to variables. This list
+ * should be searched backwards for the first qualified name that
+ * corresponds to the variable reference qname. The position of the
+ * QName in the vector from the start of the vector will be its position
+ * in the stack frame (but variables above the globalsTop value will need
+ * to be offset to the current stack frame).
+ */
+ public void fixupVariables(java.util.Vector vars, int globalsSize)
+ {
+ super.fixupVariables(vars, globalsSize);
+
+ int nPredicates = getPredicateCount();
+
+ for (int i = 0; i < nPredicates; i++)
+ {
+ m_predicates[i].fixupVariables(vars, globalsSize);
+ }
+ }
+
+
+ /**
+ * Diagnostics.
+ *
+ * @param n Node to give diagnostic information about, or null.
+ *
+ * @return Informative string about the argument.
+ */
+ protected String nodeToString(int n)
+ {
+ if(DTM.NULL != n)
+ {
+ DTM dtm = m_lpi.getXPathContext().getDTM(n);
+ return dtm.getNodeName(n) + "{" + (n+1) + "}";
+ }
+ else
+ {
+ return "null";
+ }
+ }
+
+ //=============== NodeFilter Implementation ===============
+
+ /**
+ * Test whether a specified node is visible in the logical view of a
+ * TreeWalker or NodeIterator. This function will be called by the
+ * implementation of TreeWalker and NodeIterator; it is not intended to
+ * be called directly from user code.
+ * @param n The node to check to see if it passes the filter or not.
+ * @return a constant to determine whether the node is accepted,
+ * rejected, or skipped, as defined above .
+ */
+ public short acceptNode(int n)
+ {
+
+ XPathContext xctxt = m_lpi.getXPathContext();
+
+ try
+ {
+ xctxt.pushCurrentNode(n);
+
+ XObject score = execute(xctxt, n);
+
+ // System.out.println("\n::acceptNode - score: "+score.num()+"::");
+ if (score != NodeTest.SCORE_NONE)
+ {
+ if (getPredicateCount() > 0)
+ {
+ countProximityPosition(0);
+
+ if (!executePredicates(n, xctxt))
+ return DTMIterator.FILTER_SKIP;
+ }
+
+ return DTMIterator.FILTER_ACCEPT;
+ }
+ }
+ catch (javax.xml.transform.TransformerException se)
+ {
+
+ // TODO: Fix this.
+ throw new RuntimeException(se.getMessage());
+ }
+ finally
+ {
+ xctxt.popCurrentNode();
+ }
+
+ return DTMIterator.FILTER_SKIP;
+ }
+
+
+ /**
+ * Get the owning location path iterator.
+ *
+ * @return the owning location path iterator, which should not be null.
+ */
+ public LocPathIterator getLocPathIterator()
+ {
+ return m_lpi;
+ }
+
+ /**
+ * Set the location path iterator owner for this walker. Besides
+ * initialization, this function is called during cloning operations.
+ *
+ * @param li non-null reference to the owning location path iterator.
+ */
+ public void setLocPathIterator(LocPathIterator li)
+ {
+ m_lpi = li;
+ if(this != li)
+ li.exprSetParent(this);
+ }
+
+ /**
+ * Tell if this expression or it's subexpressions can traverse outside
+ * the current subtree.
+ *
+ * @return true if traversal outside the context node's subtree can occur.
+ */
+ public boolean canTraverseOutsideSubtree()
+ {
+ int n = getPredicateCount();
+ for (int i = 0; i < n; i++)
+ {
+ if(getPredicate(i).canTraverseOutsideSubtree())
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * This will traverse the heararchy, calling the visitor for
+ * each member. If the called visitor method returns
+ * false, the subtree should not be called.
+ *
+ * @param visitor The visitor whose appropriate method will be called.
+ */
+ public void callPredicateVisitors(XPathVisitor visitor)
+ {
+ if (null != m_predicates)
+ {
+ int n = m_predicates.length;
+ for (int i = 0; i < n; i++)
+ {
+ ExpressionOwner predOwner = new PredOwner(i);
+ if (visitor.visitPredicate(predOwner, m_predicates[i]))
+ {
+ m_predicates[i].callVisitors(predOwner, visitor);
+ }
+
+ }
+ }
+ }
+
+ /**
+ * @see Expression#deepEquals(Expression)
+ */
+ public boolean deepEquals(Expression expr)
+ {
+ if (!super.deepEquals(expr))
+ return false;
+
+ PredicatedNodeTest pnt = (PredicatedNodeTest) expr;
+ if (null != m_predicates)
+ {
+
+ int n = m_predicates.length;
+ if ((null == pnt.m_predicates) || (pnt.m_predicates.length != n))
+ return false;
+ for (int i = 0; i < n; i++)
+ {
+ if (!m_predicates[i].deepEquals(pnt.m_predicates[i]))
+ return false;
+ }
+ }
+ else if (null != pnt.m_predicates)
+ return false;
+
+ return true;
+ }
+
+ /** This is true if nextNode returns null. */
+ transient protected boolean m_foundLast = false;
+
+ /** The owning location path iterator.
+ * @serial */
+ protected LocPathIterator m_lpi;
+
+ /**
+ * Which predicate we are executing.
+ */
+ transient int m_predicateIndex = -1;
+
+ /** The list of predicate expressions. Is static and does not need
+ * to be deep cloned.
+ * @serial
+ */
+ private Expression[] m_predicates;
+
+ /**
+ * An array of counts that correspond to the number
+ * of predicates the step contains.
+ */
+ transient protected int[] m_proximityPositions;
+
+ /** If true, diagnostic messages about predicate execution will be posted. */
+ static final boolean DEBUG_PREDICATECOUNTING = false;
+
+ class PredOwner implements ExpressionOwner
+ {
+ int m_index;
+
+ PredOwner(int index)
+ {
+ m_index = index;
+ }
+
+ /**
+ * @see ExpressionOwner#getExpression()
+ */
+ public Expression getExpression()
+ {
+ return m_predicates[m_index];
+ }
+
+
+ /**
+ * @see ExpressionOwner#setExpression(Expression)
+ */
+ public void setExpression(Expression exp)
+ {
+ exp.exprSetParent(PredicatedNodeTest.this);
+ m_predicates[m_index] = exp;
+ }
+ }
+
+}