View Javadoc

1   /**
2    * Copyright (c) 2011, University of Konstanz, Distributed Systems Group
3    * All rights reserved.
4    * 
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions are met:
7    * * Redistributions of source code must retain the above copyright
8    * notice, this list of conditions and the following disclaimer.
9    * * Redistributions in binary form must reproduce the above copyright
10   * notice, this list of conditions and the following disclaimer in the
11   * documentation and/or other materials provided with the distribution.
12   * * Neither the name of the University of Konstanz nor the
13   * names of its contributors may be used to endorse or promote products
14   * derived from this software without specific prior written permission.
15   * 
16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19   * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20   * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   */
27  
28  package org.treetank.service.xml.xpath.operators;
29  
30  import static org.treetank.service.xml.xpath.XPathAxis.XPATH_10_COMP;
31  
32  import org.treetank.api.INodeReadTrx;
33  import org.treetank.axis.AbsAxis;
34  import org.treetank.exception.TTXPathException;
35  import org.treetank.node.AtomicValue;
36  import org.treetank.node.Type;
37  import org.treetank.node.interfaces.IValNode;
38  import org.treetank.service.xml.xpath.expr.LiteralExpr;
39  import org.treetank.utils.NamePageHash;
40  
41  /**
42   * <h1>AbstractOpAxis</h1>
43   * <p>
44   * Abstract axis for all operators performing an arithmetic operation.
45   * </p>
46   */
47  public abstract class AbsObAxis extends AbsAxis {
48  
49      /** First arithmetic operand. */
50      private final AbsAxis mOperand1;
51  
52      /** Second arithmetic operand. */
53      private final AbsAxis mOperand2;
54  
55      /** True, if axis has not been evaluated yet. */
56      private boolean mIsFirst;
57  
58      /**
59       * Constructor. Initializes the internal state.
60       * 
61       * @param rtx
62       *            Exclusive (immutable) trx to iterate with.
63       * @param mOp1
64       *            First value of the operation
65       * @param mOp2
66       *            Second value of the operation
67       */
68      public AbsObAxis(final INodeReadTrx rtx, final AbsAxis mOp1, final AbsAxis mOp2) {
69  
70          super(rtx);
71          mOperand1 = mOp1;
72          mOperand2 = mOp2;
73          mIsFirst = true;
74  
75      }
76  
77      /**
78       * {@inheritDoc}
79       */
80      @Override
81      public final void reset(final long mNodeKey) {
82  
83          super.reset(mNodeKey);
84          mIsFirst = true;
85          if (mOperand1 != null) {
86              mOperand1.reset(mNodeKey);
87          }
88  
89          if (mOperand2 != null) {
90              mOperand2.reset(mNodeKey);
91          }
92      }
93  
94      /**
95       * {@inheritDoc}
96       */
97      @Override
98      public boolean hasNext() {
99  
100         resetToLastKey();
101 
102         if (mIsFirst) {
103             mIsFirst = false;
104             try {
105 
106                 AtomicValue mItem1 = null;
107                 if (mOperand1 instanceof LiteralExpr) {
108                     mItem1 = ((LiteralExpr)mOperand1).evaluate();
109                 } else if (mOperand1.hasNext()) {
110                     // atomize operand
111                     mItem1 = atomize(mOperand1);
112 
113                 }
114 
115                 if (mItem1 != null) {
116 
117                     AtomicValue mItem2 = null;
118                     if (mOperand2 instanceof LiteralExpr) {
119                         mItem2 = ((LiteralExpr)mOperand2).evaluate();
120                     } else if (mOperand2.hasNext()) {
121                         // atomize operand
122                         mItem2 = atomize(mOperand2);
123                     }
124 
125                     if (mItem2 != null) {
126                         final AtomicValue result = operate(mItem1, mItem2);
127                         // add retrieved AtomicValue to item list
128                         final int itemKey = getItemList().addItem(result);
129                         moveTo(itemKey);
130                         return true;
131 
132                     }
133                 }
134             } catch (TTXPathException e) {
135                 throw new RuntimeException(e);
136             }
137         }
138         // either not the first call, or empty sequence
139         resetToStartKey();
140         return false;
141 
142     }
143 
144     /**
145      * Atomizes an operand according to the rules specified in the XPath
146      * specification.
147      * 
148      * @param mOperand
149      *            the operand to atomize
150      * @return the atomized operand. (always an atomic value)
151      */
152     private AtomicValue atomize(final AbsAxis mOperand) {
153 
154         int type = getNode().getTypeKey();
155         AtomicValue atom;
156 
157         if (XPATH_10_COMP) {
158 
159             atom = new AtomicValue(((IValNode)getNode()).getRawValue(), getNode().getTypeKey());
160         } else {
161             // unatomicType is cast to double
162             if (type == NamePageHash.generateHashForString("xs:untypedAtomic")) {
163                 type = NamePageHash.generateHashForString("xs:double");
164                 // TODO: throw error, of cast fails
165             }
166 
167             atom = new AtomicValue(((IValNode)getNode()).getRawValue(), getNode().getTypeKey());
168         }
169 
170         // if (!XPATH_10_COMP && operand.hasNext()) {
171         // throw new XPathError(ErrorType.XPTY0004);
172         // }
173 
174         return atom;
175     }
176 
177     /**
178      * Performs the operation on the two input operands. First checks if the
179      * types of the operands are a valid combination for the operation and if so
180      * computed the result. Otherwise an XPathError is thrown.
181      * 
182      * @param mOperand1
183      *            first input operand
184      * @param mOperand2
185      *            second input operand
186      * @return result of the operation
187      * @throws TTXPathException
188      *             if the operations fails
189      */
190     protected abstract AtomicValue operate(final AtomicValue mOperand1, final AtomicValue mOperand2)
191         throws TTXPathException;
192 
193     /**
194      * Checks if the types of the operands are a valid combination for the
195      * operation and if so returns the corresponding result type. Otherwise an
196      * XPathError is thrown. This typed check is done according to the <a
197      * href="http://www.w3.org/TR/xpath20/#mapping">Operator Mapping</a>.
198      * 
199      * @param mOp1
200      *            first operand's type key
201      * @param mOp2
202      *            second operand's type key
203      * @return return type of the arithmetic function according to the operand
204      *         type combination.
205      * @throws TTXPathException
206      *             if type is not specified
207      */
208     protected abstract Type getReturnType(final int mOp1, final int mOp2) throws TTXPathException;
209 
210 }