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 org.treetank.api.INodeReadTrx;
31  import org.treetank.axis.AbsAxis;
32  import org.treetank.exception.TTXPathException;
33  import org.treetank.node.AtomicValue;
34  import org.treetank.node.Type;
35  import org.treetank.service.xml.xpath.XPathError;
36  import org.treetank.service.xml.xpath.XPathError.ErrorType;
37  import org.treetank.utils.NamePageHash;
38  import org.treetank.utils.TypedValue;
39  
40  /**
41   * <h1>DivOpAxis</h1>
42   * <p>
43   * Performs an arithmetic division on two input operators.
44   * </p>
45   */
46  public class DivOpAxis extends AbsObAxis {
47  
48      /**
49       * Constructor. Initializes the internal state.
50       * 
51       * @param rtx
52       *            Exclusive (immutable) trx to iterate with.
53       * @param mOp1
54       *            First value of the operation
55       * @param mOp2
56       *            Second value of the operation
57       */
58      public DivOpAxis(final INodeReadTrx rtx, final AbsAxis mOp1, final AbsAxis mOp2) {
59  
60          super(rtx, mOp1, mOp2);
61      }
62  
63      /**
64       * {@inheritDoc}
65       */
66      @Override
67      public AtomicValue operate(final AtomicValue mOperand1, final AtomicValue mOperand2)
68          throws TTXPathException {
69  
70          final Type returnType = getReturnType(mOperand1.getTypeKey(), mOperand2.getTypeKey());
71          final int typeKey = NamePageHash.generateHashForString(returnType.getStringRepr());
72  
73          final byte[] value;
74  
75          switch (returnType) {
76          case DECIMAL:
77          case FLOAT:
78          case DOUBLE:
79              final double aD = Double.parseDouble(new String(mOperand1.getRawValue()));
80              final double dValue;
81  
82              if (aD == 0.0 || aD == -0.0) {
83                  dValue = Double.NaN;
84              } else {
85                  dValue = aD / Double.parseDouble(new String(mOperand2.getRawValue()));
86              }
87  
88              value = TypedValue.getBytes(dValue);
89              return new AtomicValue(value, typeKey);
90  
91          case INTEGER:
92              try {
93                  final int iValue =
94                      (int)Double.parseDouble(new String(mOperand1.getRawValue()))
95                          / (int)Double.parseDouble(new String(mOperand2.getRawValue()));
96                  value = TypedValue.getBytes(iValue);
97                  return new AtomicValue(value, typeKey);
98              } catch (final ArithmeticException e) {
99                  throw new XPathError(ErrorType.FOAR0001);
100             }
101         case YEAR_MONTH_DURATION:
102         case DAY_TIME_DURATION:
103             throw new IllegalStateException("Add operator is not implemented for the type "
104                 + returnType.getStringRepr() + " yet.");
105         default:
106             throw new XPathError(ErrorType.XPTY0004);
107 
108         }
109 
110     }
111 
112     /**
113      * {@inheritDoc}
114      */
115     @Override
116     protected Type getReturnType(final int mOp1, final int mOp2) throws TTXPathException {
117 
118         Type type1;
119         Type type2;
120         try {
121             type1 = Type.getType(mOp1).getPrimitiveBaseType();
122             type2 = Type.getType(mOp2).getPrimitiveBaseType();
123         } catch (final IllegalStateException e) {
124             throw new XPathError(ErrorType.XPTY0004);
125         }
126 
127         if (type1.isNumericType() && type2.isNumericType()) {
128 
129             // if both have the same numeric type, return it
130             if (type1 == type2) {
131                 return type1;
132             }
133 
134             if (type1 == Type.DOUBLE || type2 == Type.DOUBLE) {
135                 return Type.DOUBLE;
136             } else if (type1 == Type.FLOAT || type2 == Type.FLOAT) {
137                 return Type.FLOAT;
138             } else {
139                 assert (type1 == Type.DECIMAL || type2 == Type.DECIMAL);
140                 return Type.DECIMAL;
141             }
142 
143         } else {
144 
145             switch (type1) {
146 
147             case YEAR_MONTH_DURATION:
148                 if (type2 == Type.YEAR_MONTH_DURATION) {
149                     return Type.DECIMAL;
150                 }
151                 if (type2.isNumericType()) {
152                     return type1;
153                 }
154                 break;
155             case DAY_TIME_DURATION:
156                 if (type2 == Type.DAY_TIME_DURATION) {
157                     return Type.DECIMAL;
158                 }
159                 if (type2.isNumericType()) {
160                     return type1;
161                 }
162                 break;
163             default:
164                 throw new XPathError(ErrorType.XPTY0004);
165             }
166             throw new XPathError(ErrorType.XPTY0004);
167         }
168     }
169 
170 }