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