1 /*
2  * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package javax.management;
27 
28 
29 /**
30  * This class is used by the query-building mechanism to represent binary
31  * operations.
32  * @serial include
33  *
34  * @since 1.5
35  */
36 class BinaryOpValueExp extends QueryEval implements ValueExp {
37 
38     /* Serial version */
39     private static final long serialVersionUID = 1216286847881456786L;
40 
41     /**
42      * @serial The operator
43      */
44     private int op;
45 
46     /**
47      * @serial The first value
48      */
49     private ValueExp exp1;
50 
51     /**
52      * @serial The second value
53      */
54     private ValueExp exp2;
55 
56 
57     /**
58      * Basic Constructor.
59      */
BinaryOpValueExp()60     public BinaryOpValueExp() {
61     }
62 
63     /**
64      * Creates a new BinaryOpValueExp using operator o applied on v1 and
65      * v2 values.
66      */
BinaryOpValueExp(int o, ValueExp v1, ValueExp v2)67     public BinaryOpValueExp(int o, ValueExp v1, ValueExp v2) {
68         op   = o;
69         exp1 = v1;
70         exp2 = v2;
71     }
72 
73 
74     /**
75      * Returns the operator of the value expression.
76      */
getOperator()77     public int getOperator()  {
78         return op;
79     }
80 
81     /**
82      * Returns the left value of the value expression.
83      */
getLeftValue()84     public ValueExp getLeftValue()  {
85         return exp1;
86     }
87 
88     /**
89      * Returns the right value of the value expression.
90      */
getRightValue()91     public ValueExp getRightValue()  {
92         return exp2;
93     }
94 
95     /**
96      * Applies the BinaryOpValueExp on a MBean.
97      *
98      * @param name The name of the MBean on which the BinaryOpValueExp will be applied.
99      *
100      * @return  The ValueExp.
101      *
102      * @exception BadStringOperationException
103      * @exception BadBinaryOpValueExpException
104      * @exception BadAttributeValueExpException
105      * @exception InvalidApplicationException
106      */
apply(ObjectName name)107     public ValueExp apply(ObjectName name) throws BadStringOperationException, BadBinaryOpValueExpException,
108         BadAttributeValueExpException, InvalidApplicationException  {
109         ValueExp val1 = exp1.apply(name);
110         ValueExp val2 = exp2.apply(name);
111         String sval1;
112         String sval2;
113         double dval1;
114         double dval2;
115         long   lval1;
116         long   lval2;
117         boolean numeric = val1 instanceof NumericValueExp;
118 
119         if (numeric) {
120             if (((NumericValueExp)val1).isLong()) {
121                 lval1 = ((NumericValueExp)val1).longValue();
122                 lval2 = ((NumericValueExp)val2).longValue();
123 
124                 switch (op) {
125                 case Query.PLUS:
126                     return Query.value(lval1 + lval2);
127                 case Query.TIMES:
128                     return Query.value(lval1 * lval2);
129                 case Query.MINUS:
130                     return Query.value(lval1 - lval2);
131                 case Query.DIV:
132                     return Query.value(lval1 / lval2);
133                 }
134 
135             } else {
136                 dval1 = ((NumericValueExp)val1).doubleValue();
137                 dval2 = ((NumericValueExp)val2).doubleValue();
138 
139                 switch (op) {
140                 case Query.PLUS:
141                     return Query.value(dval1 + dval2);
142                 case Query.TIMES:
143                     return Query.value(dval1 * dval2);
144                 case Query.MINUS:
145                     return Query.value(dval1 - dval2);
146                 case Query.DIV:
147                     return Query.value(dval1 / dval2);
148                 }
149             }
150         } else {
151             sval1 = ((StringValueExp)val1).getValue();
152             sval2 = ((StringValueExp)val2).getValue();
153 
154             switch (op) {
155             case Query.PLUS:
156                 return new StringValueExp(sval1 + sval2);
157             default:
158                 throw new BadStringOperationException(opString());
159             }
160         }
161 
162         throw new BadBinaryOpValueExpException(this);
163     }
164 
165     /**
166      * Returns the string representing the object
167      */
toString()168     public String toString()  {
169         try {
170             return parens(exp1, true) + " " + opString() + " " + parens(exp2, false);
171         } catch (BadBinaryOpValueExpException ex) {
172             return "invalid expression";
173         }
174     }
175 
176     /*
177      * Add parentheses to the given subexpression if necessary to
178      * preserve meaning.  Suppose this BinaryOpValueExp is
179      * Query.times(Query.plus(Query.attr("A"), Query.attr("B")), Query.attr("C")).
180      * Then the original toString() logic would return A + B * C.
181      * We check precedences in order to return (A + B) * C, which is the
182      * meaning of the ValueExp.
183      *
184      * We need to add parentheses if the unparenthesized expression would
185      * be parsed as a different ValueExp from the original.
186      * We cannot omit parentheses even when mathematically
187      * the result would be equivalent, because we do not know whether the
188      * numeric values will be integer or floating-point.  Addition and
189      * multiplication are associative for integers but not always for
190      * floating-point.
191      *
192      * So the rule is that we omit parentheses if the ValueExp
193      * is (A op1 B) op2 C and the precedence of op1 is greater than or
194      * equal to that of op2; or if the ValueExp is A op1 (B op2 C) and
195      * the precedence of op2 is greater than that of op1.  (There are two
196      * precedences: that of * and / is greater than that of + and -.)
197      * The case of (A op1 B) op2 (C op3 D) applies each rule in turn.
198      *
199      * The following examples show the rules in action.  On the left,
200      * the original ValueExp.  On the right, the string representation.
201      *
202      * (A + B) + C     A + B + C
203      * (A * B) + C     A * B + C
204      * (A + B) * C     (A + B) * C
205      * (A * B) * C     A * B * C
206      * A + (B + C)     A + (B + C)
207      * A + (B * C)     A + B * C
208      * A * (B + C)     A * (B + C)
209      * A * (B * C)     A * (B * C)
210      */
parens(ValueExp subexp, boolean left)211     private String parens(ValueExp subexp, boolean left)
212     throws BadBinaryOpValueExpException {
213         boolean omit;
214         if (subexp instanceof BinaryOpValueExp) {
215             int subop = ((BinaryOpValueExp) subexp).op;
216             if (left)
217                 omit = (precedence(subop) >= precedence(op));
218             else
219                 omit = (precedence(subop) > precedence(op));
220         } else
221             omit = true;
222 
223         if (omit)
224             return subexp.toString();
225         else
226             return "(" + subexp + ")";
227     }
228 
precedence(int xop)229     private int precedence(int xop) throws BadBinaryOpValueExpException {
230         switch (xop) {
231             case Query.PLUS: case Query.MINUS: return 0;
232             case Query.TIMES: case Query.DIV: return 1;
233             default:
234                 throw new BadBinaryOpValueExpException(this);
235         }
236     }
237 
opString()238     private String opString() throws BadBinaryOpValueExpException {
239         switch (op) {
240         case Query.PLUS:
241             return "+";
242         case Query.TIMES:
243             return "*";
244         case Query.MINUS:
245             return "-";
246         case Query.DIV:
247             return "/";
248         }
249 
250         throw new BadBinaryOpValueExpException(this);
251     }
252 
253     @Deprecated
setMBeanServer(MBeanServer s)254     public void setMBeanServer(MBeanServer s) {
255         super.setMBeanServer(s);
256      }
257  }
258