All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.sirix.service.xml.xpath.PipelineBuilder Maven / Gradle / Ivy

/**
 * Copyright (c) 2011, University of Konstanz, Distributed Systems Group All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are permitted
 * provided that the following conditions are met: * Redistributions of source code must retain the
 * above copyright notice, this list of conditions and the following disclaimer. * Redistributions
 * in binary form must reproduce the above copyright notice, this list of conditions and the
 * following disclaimer in the documentation and/or other materials provided with the distribution.
 * * Neither the name of the University of Konstanz nor the names of its contributors may be used to
 * endorse or promote products derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL  BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package io.sirix.service.xml.xpath;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import io.sirix.api.Axis;
import io.sirix.api.Filter;
import io.sirix.api.NodeReadOnlyTrx;
import io.sirix.api.xml.XmlNodeReadOnlyTrx;
import io.sirix.axis.ForAxis;
import io.sirix.service.xml.xpath.filter.DupFilterAxis;
import io.sirix.service.xml.xpath.functions.AbstractFunction;
import io.sirix.service.xml.xpath.functions.FuncDef;
import io.sirix.service.xml.xpath.expr.CastableExpr;
import io.sirix.service.xml.xpath.expr.InstanceOfExpr;
import io.sirix.service.xml.xpath.expr.VariableAxis;
import io.sirix.axis.filter.FilterAxis;
import io.sirix.axis.filter.PredicateFilterAxis;
import io.sirix.exception.SirixXPathException;
import io.sirix.service.xml.xpath.comparators.AbstractComparator;
import io.sirix.service.xml.xpath.comparators.CompKind;
import io.sirix.service.xml.xpath.expr.AndExpr;
import io.sirix.service.xml.xpath.expr.CastExpr;
import io.sirix.service.xml.xpath.expr.EveryExpr;
import io.sirix.service.xml.xpath.expr.ExceptAxis;
import io.sirix.service.xml.xpath.expr.IfAxis;
import io.sirix.service.xml.xpath.expr.IntersectAxis;
import io.sirix.service.xml.xpath.expr.LiteralExpr;
import io.sirix.service.xml.xpath.expr.OrExpr;
import io.sirix.service.xml.xpath.expr.RangeAxis;
import io.sirix.service.xml.xpath.expr.SequenceAxis;
import io.sirix.service.xml.xpath.expr.SomeExpr;
import io.sirix.service.xml.xpath.expr.UnionAxis;
import io.sirix.service.xml.xpath.expr.VarRefExpr;
import io.sirix.service.xml.xpath.operators.AddOpAxis;
import io.sirix.service.xml.xpath.operators.DivOpAxis;
import io.sirix.service.xml.xpath.operators.IDivOpAxis;
import io.sirix.service.xml.xpath.operators.ModOpAxis;
import io.sirix.service.xml.xpath.operators.MulOpAxis;
import io.sirix.service.xml.xpath.operators.SubOpAxis;

/**
 * 

* Builder of a query execution plan in the pipeline manner. *

*/ public final class PipelineBuilder { /** Stack of pipeline builder which stores expressions. */ private final Stack> mExprStack; /** Maps a variable name to the item that the variable holds. */ private final Map mVarRefMap; /** * Constructor. */ public PipelineBuilder() { mExprStack = new Stack>(); mVarRefMap = new HashMap(); } /** * @return the current pipeline stack */ public Stack getPipeStack() { if (mExprStack.size() == 0) { throw new IllegalStateException("No pipe on the stack"); } return mExprStack.peek(); } /** * Adds a new pipeline stack to the stack holding all expressions. */ public void addExpr() { mExprStack.push(new Stack()); } /** * Ends an expression. This means that the currently used pipeline stack will be emptied and the * singleExpressions that were on the stack are combined by a sequence expression, which is lated * added to the next pipeline stack. * * @param mTransaction transaction to operate on * @param mNum number of singleExpressions that will be added to the sequence */ public void finishExpr(final XmlNodeReadOnlyTrx mTransaction, final int mNum) { // all singleExpression that are on the stack will be combined in the // sequence, so the number of singleExpressions in the sequence and the // size // of the stack containing these SingleExpressions have to be the same. if (getPipeStack().size() != mNum) { // this should never happen throw new IllegalStateException("The query has not been processed correctly"); } int no = mNum; Axis[] axis; if (no > 1) { axis = new Axis[no]; // add all SingleExpression to a list while (no-- > 0) { axis[no] = getPipeStack().pop().getExpr(); } if (mExprStack.size() > 1) { assert mExprStack.peek().empty(); mExprStack.pop(); } if (getPipeStack().empty() || getExpression().getSize() != 0) { addExpressionSingle(); } getExpression().add(new SequenceAxis(mTransaction, axis)); } else if (no == 1) { // only one expression does not need to be capsled by a seq axis = new Axis[1]; axis[0] = getPipeStack().pop().getExpr(); if (mExprStack.size() > 1) { assert mExprStack.peek().empty(); mExprStack.pop(); } if (getPipeStack().empty() || getExpression().getSize() != 0) { addExpressionSingle(); } final Axis iAxis; if (mExprStack.size() == 1 && getPipeStack().size() == 1 && getExpression().getSize() == 0) { iAxis = new SequenceAxis(mTransaction, axis); } else { iAxis = axis[0]; } getExpression().add(iAxis); } else { mExprStack.pop(); } } /** * Adds a new single expression to the pipeline. This is done by adding a complete new chain to * the stack because the new single expression has nothing in common with the previous * expressions. */ public void addExpressionSingle() { // A new single expression is completely independent from the previous // expression, therefore a new expression chain is build and added to // the // stack. getPipeStack().push(new ExpressionSingle()); } /** * Returns the current pipeline. If there is no existing pipeline, a new one is generated and * returned. * * @return a reference to the currently used pipeline. */ public ExpressionSingle getExpression() { return getPipeStack().peek(); } /** * Adds a for expression to the pipeline. In case the for expression has more then one for * condition, the for expression is converted to a nested for expression with only one for * condition each, see the following example: for $a in /a, $b in /b, $c in /c return /d is * converted to for $a in /a return for $b in /b return for $c in /c return /d * * @param mForConditionNum Number of all for conditions of the expression */ public void addForExpression(final int mForConditionNum) { assert getPipeStack().size() >= (mForConditionNum + 1); Axis forAxis = (getPipeStack().pop().getExpr()); int num = mForConditionNum; while (num-- > 0) { forAxis = new ForAxis(getPipeStack().pop().getExpr(), forAxis); } if (getPipeStack().empty() || getExpression().getSize() != 0) { addExpressionSingle(); } getExpression().add(forAxis); } /** * Adds a if expression to the pipeline. * * @param mTransaction Transaction to operate with. */ public void addIfExpression(final XmlNodeReadOnlyTrx mTransaction) { assert getPipeStack().size() >= 3; final XmlNodeReadOnlyTrx rtx = mTransaction; final Axis elseExpr = getPipeStack().pop().getExpr(); final Axis thenExpr = getPipeStack().pop().getExpr(); final Axis ifExpr = getPipeStack().pop().getExpr(); if (getPipeStack().empty() || getExpression().getSize() != 0) { addExpressionSingle(); } getExpression().add(new IfAxis(rtx, ifExpr, thenExpr, elseExpr)); } /** * Adds a comparison expression to the pipeline. * * @param mTransaction Transaction to operate with. * @param mComp Comparator type. */ public void addCompExpression(final XmlNodeReadOnlyTrx mTransaction, final String mComp) { assert getPipeStack().size() >= 2; final XmlNodeReadOnlyTrx rtx = mTransaction; final Axis paramOperandTwo = getPipeStack().pop().getExpr(); final Axis paramOperandOne = getPipeStack().pop().getExpr(); final CompKind kind = CompKind.fromString(mComp); final Axis axis = AbstractComparator.getComparator(rtx, paramOperandOne, paramOperandTwo, kind, mComp); // // TODO: use typeswitch of JAVA 7 // if (mComp.equals("eq")) { // // axis = new ValueComp(rtx, paramOperandOne, paramOperandTwo, kind); // } else if (mComp.equals("ne")) { // // axis = new ValueComp(rtx, paramOperandOne, paramOperandTwo, kind); // } else if (mComp.equals("lt")) { // // axis = new ValueComp(rtx, paramOperandOne, paramOperandTwo, kind); // } else if (mComp.equals("le")) { // // axis = new ValueComp(rtx, paramOperandOne, paramOperandTwo, kind); // } else if (mComp.equals("gt")) { // // axis = new ValueComp(rtx, paramOperandOne, paramOperandTwo, kind); // } else if (mComp.equals("ge")) { // // axis = new ValueComp(rtx, paramOperandOne, paramOperandTwo, kind); // // } else if (mComp.equals("=")) { // // axis = new GeneralComp(rtx, paramOperandOne, paramOperandTwo, kind); // } else if (mComp.equals("!=")) { // // axis = new GeneralComp(rtx, paramOperandOne, paramOperandTwo, kind); // } else if (mComp.equals("<")) { // // axis = new GeneralComp(rtx, paramOperandOne, paramOperandTwo, kind); // } else if (mComp.equals("<=")) { // // axis = new GeneralComp(rtx, paramOperandOne, paramOperandTwo, kind); // } else if (mComp.equals(">")) { // // axis = new GeneralComp(rtx, paramOperandOne, paramOperandTwo, kind); // } else if (mComp.equals(">=")) { // // axis = new GeneralComp(rtx, paramOperandOne, paramOperandTwo, kind); // // } else if (mComp.equals("is")) { // // axis = new NodeComp(rtx, paramOperandOne, paramOperandTwo, kind); // } else if (mComp.equals("<<")) { // // axis = new NodeComp(rtx, paramOperandOne, paramOperandTwo, kind); // } else if (mComp.equals(">>")) { // // axis = new NodeComp(rtx, paramOperandOne, paramOperandTwo, kind); // } else { // throw new IllegalStateException(mComp + // " is not a valid comparison."); // // } if (getPipeStack().empty() || getExpression().getSize() != 0) { addExpressionSingle(); } getExpression().add(axis); } /** * Adds an operator expression to the pipeline. * * @param mTransaction Transaction to operate with. * @param mOperator Operator type. */ public void addOperatorExpression(final XmlNodeReadOnlyTrx mTransaction, final String mOperator) { assert getPipeStack().size() >= 1; final XmlNodeReadOnlyTrx rtx = mTransaction; final Axis mOperand2 = getPipeStack().pop().getExpr(); // the unary operation only has one operator final Axis mOperand1 = getPipeStack().pop().getExpr(); if (getPipeStack().empty() || getExpression().getSize() != 0) { addExpressionSingle(); } final Axis axis; // TODO: use typeswitch of JAVA 7 if (mOperator.equals("+")) { axis = new AddOpAxis(rtx, mOperand1, mOperand2); } else if (mOperator.equals("-")) { axis = new SubOpAxis(rtx, mOperand1, mOperand2); } else if (mOperator.equals("*")) { axis = new MulOpAxis(rtx, mOperand1, mOperand2); } else if (mOperator.equals("div")) { axis = new DivOpAxis(rtx, mOperand1, mOperand2); } else if (mOperator.equals("idiv")) { axis = new IDivOpAxis(rtx, mOperand1, mOperand2); } else if (mOperator.equals("mod")) { axis = new ModOpAxis(rtx, mOperand1, mOperand2); } else { // TODO: unary operator throw new IllegalStateException(mOperator + " is not a valid operator."); } getExpression().add(axis); } /** * Adds a union expression to the pipeline. * * @param mTransaction Transaction to operate with. */ public void addUnionExpression(final XmlNodeReadOnlyTrx mTransaction) { assert getPipeStack().size() >= 2; final Axis mOperand2 = getPipeStack().pop().getExpr(); final Axis mOperand1 = getPipeStack().pop().getExpr(); if (getPipeStack().empty() || getExpression().getSize() != 0) { addExpressionSingle(); } getExpression().add( new DupFilterAxis(mTransaction, new UnionAxis(mTransaction, mOperand1, mOperand2))); } /** * Adds a and expression to the pipeline. * * @param mTransaction Transaction to operate with. */ public void addAndExpression(final XmlNodeReadOnlyTrx mTransaction) { assert getPipeStack().size() >= 2; final Axis mOperand2 = getPipeStack().pop().getExpr(); final Axis operand1 = getPipeStack().pop().getExpr(); if (getPipeStack().empty() || getExpression().getSize() != 0) { addExpressionSingle(); } getExpression().add(new AndExpr(mTransaction, operand1, mOperand2)); } /** * Adds a or expression to the pipeline. * * @param mTransaction Transaction to operate with. */ public void addOrExpression(final XmlNodeReadOnlyTrx mTransaction) { assert getPipeStack().size() >= 2; final Axis mOperand2 = getPipeStack().pop().getExpr(); final Axis mOperand1 = getPipeStack().pop().getExpr(); if (getPipeStack().empty() || getExpression().getSize() != 0) { addExpressionSingle(); } getExpression().add(new OrExpr(mTransaction, mOperand1, mOperand2)); } /** * Adds a intersect or a exception expression to the pipeline. * * @param mTransaction Transaction to operate with. * @param mIsIntersect true, if expression is an intersection */ public void addIntExcExpression(final XmlNodeReadOnlyTrx mTransaction, final boolean mIsIntersect) { assert getPipeStack().size() >= 2; final XmlNodeReadOnlyTrx rtx = mTransaction; final Axis mOperand2 = getPipeStack().pop().getExpr(); final Axis mOperand1 = getPipeStack().pop().getExpr(); final Axis axis = mIsIntersect ? new IntersectAxis(rtx, mOperand1, mOperand2) : new ExceptAxis(rtx, mOperand1, mOperand2); if (getPipeStack().empty() || getExpression().getSize() != 0) { addExpressionSingle(); } getExpression().add(axis); } /** * Adds a literal expression to the pipeline. * * @param mTransaction Transaction to operate with. * @param mItemKey key of the literal expression. */ public void addLiteral(final XmlNodeReadOnlyTrx mTransaction, final int mItemKey) { // addExpressionSingle(); getExpression().add(new LiteralExpr(mTransaction, mItemKey)); } /** * Adds a step to the pipeline. * * @param axis the axis step to add to the pipeline. */ public void addStep(final Axis axis) { getExpression().add(axis); } /** * Adds a step to the pipeline. * * @param axis the axis step to add to the pipeline. * @param mFilter the node test to add to the pipeline. */ public void addStep(final Axis axis, final Filter mFilter) { getExpression().add(new FilterAxis(axis, mFilter)); } /** * Returns a queue of all pipelines build so far and empties the pipeline stack. * * @return all build pipelines */ public Axis getPipeline() { assert getPipeStack().size() <= 1; if (getPipeStack().size() == 1 && mExprStack.size() == 1) { return getPipeStack().pop().getExpr(); } else { throw new IllegalStateException("Query was not build correctly."); } } /** * Adds a predicate to the pipeline. * * @param pRtx transaction to operate with */ public void addPredicate(final XmlNodeReadOnlyTrx pRtx) { assert getPipeStack().size() >= 2; final Axis predicate = getPipeStack().pop().getExpr(); if (predicate instanceof LiteralExpr) { predicate.hasNext(); // if is numeric literal -> abbrev for position() final int type = pRtx.getTypeKey(); if (type == pRtx.keyForName("xs:integer") || type == pRtx.keyForName("xs:double") || type == pRtx.keyForName("xs:float") || type == pRtx.keyForName("xs:decimal")) { throw new IllegalStateException("function fn:position() is not implemented yet."); // getExpression().add( // new PosFilter(transaction, (int) // Double.parseDouble(transaction // .getValue()))); // return; // TODO: YES! it is dirty! // AtomicValue pos = // new AtomicValue(mTransaction.getItem().getRawValue(), // mTransaction // .keyForName("xs:integer")); // long position = mTransaction.getItemList().addItem(pos); // mPredicate.reset(mTransaction.getItem().getKey()); // IAxis function = // new FNPosition(mTransaction, new ArrayList(), // FuncDef.POS.getMin(), FuncDef.POS // .getMax(), // mTransaction.keyForName(FuncDef.POS.getReturnType())); // IAxis expectedPos = new LiteralExpr(mTransaction, position); // // mPredicate = new ValueComp(mTransaction, function, // expectedPos, CompKind.EQ); } } getExpression().add(new PredicateFilterAxis(pRtx, predicate)); } /** * Adds a SomeExpression or an EveryExpression to the pipeline, depending on the parameter isSome. * * @param mTransaction Transaction to operate with. * @param mIsSome defines whether a some- or an EveryExpression is used. * @param mVarNum number of binding variables */ public void addQuantifierExpr(final XmlNodeReadOnlyTrx mTransaction, final boolean mIsSome, final int mVarNum) { assert getPipeStack().size() >= (mVarNum + 1); final Axis satisfy = getPipeStack().pop().getExpr(); final List vars = new ArrayList(); int num = mVarNum; while (num-- > 0) { // invert current order of variables to get original variable order vars.add(num, getPipeStack().pop().getExpr()); } final Axis mAxis = mIsSome ? new SomeExpr(mTransaction, vars, satisfy) : new EveryExpr(mTransaction, vars, satisfy); if (getPipeStack().empty() || getExpression().getSize() != 0) { addExpressionSingle(); } getExpression().add(mAxis); } /** * Adds a castable expression to the pipeline. * * @param mTransaction Transaction to operate with. * @param mSingleType single type the context item will be casted to. */ public void addCastableExpr(final XmlNodeReadOnlyTrx mTransaction, final SingleType mSingleType) { assert getPipeStack().size() >= 1; final Axis candidate = getPipeStack().pop().getExpr(); final Axis axis = new CastableExpr(mTransaction, candidate, mSingleType); if (getPipeStack().empty() || getExpression().getSize() != 0) { addExpressionSingle(); } getExpression().add(axis); } /** * Adds a range expression to the pipeline. * * @param mTransaction Transaction to operate with. */ public void addRangeExpr(final XmlNodeReadOnlyTrx mTransaction) { assert getPipeStack().size() >= 2; final Axis mOperand2 = getPipeStack().pop().getExpr(); final Axis mOperand1 = getPipeStack().pop().getExpr(); final Axis axis = new RangeAxis(mTransaction, mOperand1, mOperand2); if (getPipeStack().empty() || getExpression().getSize() != 0) { addExpressionSingle(); } getExpression().add(axis); } /** * Adds a cast expression to the pipeline. * * @param mTransaction Transaction to operate with. * @param mSingleType single type the context item will be casted to. */ public void addCastExpr(final XmlNodeReadOnlyTrx mTransaction, final SingleType mSingleType) { assert getPipeStack().size() >= 1; final Axis candidate = getPipeStack().pop().getExpr(); final Axis axis = new CastExpr(mTransaction, candidate, mSingleType); if (getPipeStack().empty() || getExpression().getSize() != 0) { addExpressionSingle(); } getExpression().add(axis); } /** * Adds a instance of expression to the pipeline. * * @param mTransaction Transaction to operate with. * @param mSequenceType sequence type the context item should match. */ public void addInstanceOfExpr(final XmlNodeReadOnlyTrx mTransaction, final SequenceType mSequenceType) { assert getPipeStack().size() >= 1; final Axis candidate = getPipeStack().pop().getExpr(); final Axis axis = new InstanceOfExpr(mTransaction, candidate, mSequenceType); if (getPipeStack().empty() || getExpression().getSize() != 0) { addExpressionSingle(); } getExpression().add(axis); } /** * Adds a treat as expression to the pipeline. * * @param mTransaction Transaction to operate with. * @param mSequenceType sequence type the context item will be treated as. */ public void addTreatExpr(final NodeReadOnlyTrx mTransaction, final SequenceType mSequenceType) { throw new IllegalStateException("the Treat expression is not supported yet"); } /** * Adds a variable expression to the pipeline. Adds the expression that will evaluate the results * the variable holds. * * @param mTransaction Transaction to operate with. * @param mVarName name of the variable */ public void addVariableExpr(final XmlNodeReadOnlyTrx mTransaction, final String mVarName) { assert getPipeStack().size() >= 1; final Axis bindingSeq = getPipeStack().pop().getExpr(); final Axis axis = new VariableAxis(mTransaction, bindingSeq); mVarRefMap.put(mVarName, axis); if (getPipeStack().empty() || getExpression().getSize() != 0) { addExpressionSingle(); } getExpression().add(axis); } /** * Adds a function to the pipeline. * * @param mTransaction Transaction to operate with. * @param mFuncName The name of the function * @param mNum The number of arguments that are passed to the function * @throws SirixXPathException if function can't be added */ public void addFunction(final XmlNodeReadOnlyTrx mTransaction, final String mFuncName, final int mNum) throws SirixXPathException { assert getPipeStack().size() >= mNum; final List args = new ArrayList(mNum); // arguments are stored on the stack in reverse order -> invert arg // order for (int i = 0; i < mNum; i++) { args.add(getPipeStack().pop().getExpr()); } // get right function type final FuncDef func; try { func = FuncDef.fromString(mFuncName); } catch (final NullPointerException e) { throw EXPathError.XPST0017.getEncapsulatedException(); } // get function class final Class function = func.getFunc(); final Integer min = func.getMin(); final Integer max = func.getMax(); final Integer returnType = mTransaction.keyForName(func.getReturnType()); // parameter types of the function's constructor final Class[] paramTypes = {XmlNodeReadOnlyTrx.class, List.class, Integer.TYPE, Integer.TYPE, Integer.TYPE}; try { // instantiate function class with right constructor final Constructor cons = function.getConstructor(paramTypes); final Axis axis = (Axis) cons.newInstance(mTransaction, args, min, max, returnType); if (getPipeStack().empty() || getExpression().getSize() != 0) { addExpressionSingle(); } getExpression().add(axis); } catch (final NoSuchMethodException e) { throw EXPathError.XPST0017.getEncapsulatedException(); } catch (final IllegalArgumentException e) { throw EXPathError.XPST0017.getEncapsulatedException(); } catch (final InstantiationException e) { throw new IllegalStateException("Function not implemented yet."); } catch (final IllegalAccessException e) { throw EXPathError.XPST0017.getEncapsulatedException(); } catch (final InvocationTargetException e) { throw EXPathError.XPST0017.getEncapsulatedException(); } } /** * Adds a VarRefExpr to the pipeline. This Expression holds a reference to the current context * item of the specified variable. * * @param mTransaction the transaction to operate on. * @param mVarName the name of the variable */ public void addVarRefExpr(final XmlNodeReadOnlyTrx mTransaction, final String mVarName) { final VariableAxis axis = (VariableAxis) mVarRefMap.get(mVarName); if (axis != null) { getExpression().add(new VarRefExpr(mTransaction, axis)); } else { throw new IllegalStateException("Variable " + mVarName + " unkown."); } } /** * {@inheritDoc} */ @Override public String toString() { return new StringBuilder("Expression Stack: ").append(this.mExprStack) .append("\nHashMap: ") .append(this.mVarRefMap) .toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy