1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * ident "%Z%%M% %I% %E% SMI" 27 */ 28 29 package com.sun.solaris.domain.pools; 30 31 import java.util.regex.*; 32 33 /** 34 * This class provides the base implementation of an Expression. All 35 * types of Expression must inherit from this class. 36 * 37 * An objective is always specified in terms of an expression. The 38 * only recognized expressions are those known by this class. An 39 * expression is create using the valueOf() factory method, which is 40 * why Expressions must be known to this class. 41 */ 42 abstract class Expression 43 { 44 /** 45 * Expression importance 46 */ 47 private long imp = -1; 48 49 /** 50 * Expression name 51 */ 52 private String name; 53 54 /** 55 * Sole constructor. (For invocation by subclass constructors) 56 */ Expression(long imp, String name)57 protected Expression(long imp, String name) 58 { 59 this.imp = imp; 60 this.name = name; 61 } 62 63 /** 64 * Return the name of the expression. 65 */ getName()66 String getName() 67 { 68 return (this.name); 69 } 70 71 /** 72 * Return the importance of the expression. 73 */ getImportance()74 long getImportance() 75 { 76 return (imp); 77 } 78 79 /** 80 * Returns the supplied string as an expression. 81 * 82 * This utility function attempts to identify the supplied 83 * string as an expression. It tries in turn each of the known 84 * sub-classes until finally, if none can be recognized, an 85 * exception is thrown. This function is not immune to 86 * mistakenly mis-classifying an expression. It is the 87 * responsibility of the concrete Exrpession classes to ensure 88 * that syntactic integrity is maintained with respect to 89 * potential cases of mistaken identity. 90 * 91 * @param raw The candidate expression 92 * @throws IllegalArgumentException If no valid expression can 93 * be found 94 */ valueOf(String raw)95 static Expression valueOf(String raw) throws IllegalArgumentException 96 { 97 Expression exp = null; 98 /* 99 * TODO It would be better if subclasses registered, 100 * but this hard coded list will do until such a time 101 */ 102 if ((exp = KVOpExpression.valueOf(raw)) == null) 103 if ((exp = KVExpression.valueOf(raw)) == null) 104 exp = KExpression.valueOf(raw); 105 if (exp == null) 106 throw new IllegalArgumentException( 107 "unrecognized expression: " + raw); 108 return (exp); 109 } 110 111 /** 112 * Ensure that the supplied importance is a valid value. 113 * 114 * @param imps String representation of the importance. 115 * 116 * @throws IllegalArgumentException if the importance is not 117 * valid. 118 */ validateImportance(String imps)119 protected static long validateImportance(String imps) 120 throws IllegalArgumentException 121 { 122 long imp; 123 124 try { 125 imp = Long.parseLong(imps); 126 } catch (NumberFormatException nfe) { 127 throw new IllegalArgumentException("importance value " + 128 imps + " is not legal"); 129 } 130 131 if (imp < 0) 132 throw new IllegalArgumentException("importance value " + 133 imps + " is not legal (must be positive)"); 134 return (imp); 135 } 136 137 /** 138 * Ensure that the supplied keyword is a member of the 139 * supplied keys. 140 * 141 * @param keys Array of valid key strings. 142 * @param key Key sought. 143 * 144 * @throws IllegalArgumentException if the sought key is not 145 * a member of the keys array. 146 */ validateKeyword(String keys[], String key)147 protected static void validateKeyword(String keys[], String key) 148 throws IllegalArgumentException 149 { 150 for (int i = 0; i < keys.length; i++) { 151 if (keys[i].compareTo(key) == 0) 152 return; 153 } 154 throw new IllegalArgumentException("keyword " + key + 155 " is not recognized"); 156 } 157 158 /** 159 * Return true if the supplied expression "contradicts" this 160 * expression. The definition of contradiction is left down to 161 * each implementing sub-class. 162 * 163 * @param o Expression to examine for contradiction. 164 */ contradicts(Expression o)165 public abstract boolean contradicts(Expression o); 166 } 167 168 /** 169 * This class implements the functionality for a key-value-operator 170 * expression. 171 * 172 * The general form of this expression is defined in the pattern 173 * member. A simplified rendition of which is: 174 * 175 * [[imp]:] <key> <op> <value> 176 * 177 * key is a string which identifies the expression 178 * op is the operator for the expression ( < | > | ~) 179 * value is the value of the expression 180 * 181 * For example: 182 * 183 * 10: utilization < 80 184 */ 185 final class KVOpExpression extends Expression 186 { 187 /** 188 * The operator for this expression. 189 */ 190 private char op; 191 192 /** 193 * The value of this expression. 194 */ 195 private int val; 196 197 /** 198 * The pattern used to recognize this type of expression. 199 */ 200 private static final Pattern pattern = Pattern.compile( 201 "\\s*((\\d+)\\s*:)?\\s*(\\w+)\\s*([~<>])\\s*(\\d+)\\s*"); 202 203 /** 204 * The array of valid keys for this type of expression. 205 */ 206 private static final String keys[] = { "utilization" }; 207 208 /** 209 * A greater than operator. 210 */ 211 static final char GT = '>'; 212 213 /** 214 * A less than operator. 215 */ 216 static final char LT = '<'; 217 218 /** 219 * A near to operator. 220 */ 221 static final char NT = '~'; 222 223 /** 224 * Private constructor used in the valueOf() factory method. 225 * 226 * @param imp The importance of this expression. 227 * @param name The name of this expression. 228 * @param op The operator of this expression. 229 * @param val The value of this expression. 230 */ KVOpExpression(long imp, String name, String op, int val)231 private KVOpExpression(long imp, String name, String op, int val) 232 { 233 super(imp, name); 234 this.op = op.charAt(0); 235 this.val = val; 236 } 237 238 /** 239 * Create and return an expression from the input string. 240 * 241 * Determine if the input string matches the syntax defined by 242 * this expression. If the expression cannot be matched, an 243 * exception will be thrown. 244 * 245 * @param raw Candidate expression string. 246 * 247 * @throws IllegalArgumentExpression if the string is not a 248 * valid expression of this type. 249 */ valueOf(String raw)250 static Expression valueOf(String raw) throws IllegalArgumentException 251 { 252 KVOpExpression exp = null; 253 Matcher m = pattern.matcher(raw); 254 255 if (m.matches()) { 256 long imp = 1; 257 int val = Integer.parseInt(m.group(5)); 258 259 if (m.group(2) != null) 260 imp = validateImportance(m.group(2)); 261 262 validateKeyword(keys, m.group(3)); 263 if (val > 100 || val < 0) 264 throw new IllegalArgumentException( 265 "expression value " + val + 266 " is outside the legal range (0-100)"); 267 exp = new KVOpExpression(imp, m.group(3), 268 m.group(4), val); 269 } 270 return (exp); 271 } 272 273 /** 274 * Return the operator for this expression. 275 */ getOp()276 char getOp() 277 { 278 return (op); 279 } 280 281 /** 282 * Return the value of this expression. 283 */ getValue()284 int getValue() 285 { 286 return (val); 287 } 288 289 /** 290 * Return a string representation of this expresssion. 291 */ toString()292 public String toString() 293 { 294 return ("(" + getImportance() + ", " + getName() + ", '" + op + 295 "', " + val + ")"); 296 } 297 298 /** 299 * Indicates whether some other KVOpExpression is "equal to 300 * this one. 301 * @param o the reference object with which to compare. 302 * @return <code>true</code> if this object is the same as the 303 * o argument; <code>false</code> otherwise. 304 * @see #hashCode() 305 */ equals(Object o)306 public boolean equals(Object o) 307 { 308 if (o == this) 309 return (true); 310 if (!(o instanceof KVOpExpression)) 311 return (false); 312 KVOpExpression other = (KVOpExpression) o; 313 if (getName().compareTo(other.getName()) != 0 || 314 op != other.getOp() || val != other.getValue()) 315 return (false); 316 return (true); 317 } 318 319 /** 320 * Returns a hash code value for the object. This method is 321 * supported for the benefit of hashtables such as those provided by 322 * <code>java.util.Hashtable</code>. 323 * 324 * @return a hash code value for this object. 325 * @see #equals(java.lang.Object) 326 * @see java.util.Hashtable 327 */ hashCode()328 public int hashCode() 329 { 330 return (getName().hashCode() + (int) op + val); 331 } 332 333 /** 334 * Return true if the supplied expression "contradicts" this 335 * expression. If the supplied expression is not of the same 336 * type, then it cannot contradict it. If the names are 337 * different then there can be no contradiction. 338 * 339 * Contradiction occurs if the operator is the same or if they 340 * aren't the same and the operator is < or > and the values 341 * aren't simultanteously achievable. 342 * 343 * @param o Expression to examine for contradiction. 344 */ contradicts(Expression o)345 public boolean contradicts(Expression o) 346 { 347 if (!(o instanceof KVOpExpression)) 348 return (false); 349 KVOpExpression other = (KVOpExpression) o; 350 if (getName().compareTo(other.getName()) != 0) 351 return (false); 352 if (getOp() != other.getOp()) { 353 if (getOp() != NT && other.getOp() != NT) { 354 if (getOp() == GT) { 355 if (getValue() < other.getValue()) 356 return (false); 357 } else { 358 if (getValue() > other.getValue()) 359 return (false); 360 } 361 } else 362 return (false); 363 } 364 return (true); 365 } 366 } 367 368 /** 369 * This class implements the functionality for a key-value expression. 370 * 371 * The general form of this expression is defined in the pattern 372 * member. A simplified rendition of which is: 373 * 374 * [[imp]:] <key> <value> 375 * 376 * key is a string which identifies the expression 377 * value is the value of the expression 378 * 379 * For example: 380 * 381 * 10: locality tight 382 */ 383 final class KVExpression extends Expression 384 { 385 /** 386 * The value of this expression. 387 */ 388 private String val; 389 390 /** 391 * The pattern used to recognize this type of expression. 392 */ 393 private static final Pattern pattern = Pattern.compile( 394 "\\s*((\\d+)\\s*:)?\\s*(\\w+)\\s+(tight|loose|none)\\s*"); 395 396 /** 397 * The array of valid keys for this type of expression. 398 */ 399 private static final String keys[] = { "locality" }; 400 401 /** 402 * Private constructor used in the valueOf() factory method. 403 * 404 * @param imp The importance of this expression. 405 * @param name The name of this expression. 406 * @param val The value of this expression. 407 */ KVExpression(long imp, String name, String val)408 private KVExpression(long imp, String name, String val) 409 { 410 super(imp, name); 411 this.val = val; 412 } 413 414 /** 415 * Create and return an expression from the input string. 416 * 417 * Determine if the input string matches the syntax defined by 418 * this expression. If the expression cannot be matched, an 419 * exception will be thrown. 420 * 421 * @param raw Candidate expression string. 422 * 423 * @throws IllegalArgumentExpression if the string is not a 424 * valid expression of this type. 425 */ valueOf(String raw)426 static Expression valueOf(String raw) throws IllegalArgumentException 427 { 428 KVExpression exp = null; 429 Matcher m = pattern.matcher(raw); 430 431 if (m.matches()) { 432 long imp = 1; 433 434 if (m.group(2) != null) 435 imp = validateImportance(m.group(2)); 436 437 validateKeyword(keys, m.group(3)); 438 exp = new KVExpression(imp, m.group(3), m.group(4)); 439 } 440 return (exp); 441 } 442 443 /** 444 * Return the value of this expression. 445 */ getValue()446 String getValue() 447 { 448 return (val); 449 } 450 451 /** 452 * Return a string representation of this expresssion. 453 */ toString()454 public String toString() 455 { 456 StringBuffer buf = new StringBuffer(); 457 458 buf.append("("); 459 buf.append(getImportance()); 460 buf.append(", "); 461 buf.append(getName()); 462 buf.append(", "); 463 buf.append(val); 464 buf.append(")"); 465 466 return (buf.toString()); 467 } 468 469 /** 470 * Indicates whether some other KVExpression is "equal to 471 * this one. 472 * @param o the reference object with which to compare. 473 * @return <code>true</code> if this object is the same as the 474 * o argument; <code>false</code> otherwise. 475 * @see #hashCode() 476 */ equals(Object o)477 public boolean equals(Object o) 478 { 479 if (o == this) 480 return (true); 481 if (!(o instanceof KVExpression)) 482 return (false); 483 KVExpression other = (KVExpression) o; 484 if (getName().compareTo(other.getName()) != 0 || 485 val.compareTo(other.getValue()) != 0) 486 return (false); 487 return (true); 488 } 489 490 /** 491 * Returns a hash code value for the object. This method is 492 * supported for the benefit of hashtables such as those provided by 493 * <code>java.util.Hashtable</code>. 494 * 495 * @return a hash code value for this object. 496 * @see #equals(java.lang.Object) 497 * @see java.util.Hashtable 498 */ hashCode()499 public int hashCode() 500 { 501 return (getName().hashCode() + val.hashCode()); 502 } 503 504 /** 505 * Return true if the supplied expression "contradicts" this 506 * expression. If the supplied expression is not of the same 507 * type, then it cannot contradict it. If the names are 508 * different then there can be no contradiction. 509 * 510 * Contradiction occurs if the value is different. 511 * 512 * @param o Expression to examine for contradiction. 513 */ contradicts(Expression o)514 public boolean contradicts(Expression o) 515 { 516 if (!(o instanceof KVExpression)) 517 return (false); 518 KVExpression other = (KVExpression) o; 519 if (getName().compareTo(other.getName()) != 0) 520 return (false); 521 if (val.compareTo(other.getValue()) == 0) 522 return (false); 523 return (true); 524 } 525 } 526 527 /** 528 * This class implements the functionality for a key expression. 529 * 530 * The general form of this expression is defined in the pattern 531 * member. A simplified rendition of which is: 532 * 533 * [[imp]:] <key> 534 * 535 * key is a string which identifies the expression 536 * 537 * For example: 538 * 539 * 10: wt-load 540 */ 541 final class KExpression extends Expression 542 { 543 /** 544 * The pattern used to recognize this type of expression. 545 */ 546 private static final Pattern pattern = Pattern.compile( 547 "\\s*((\\d+)\\s*:)?\\s*([\\w-]+)\\s*"); 548 549 /** 550 * The array of valid keys for this type of expression. 551 */ 552 private static final String keys[] = { "wt-load" }; 553 554 /** 555 * Private constructor used in the valueOf() factory method. 556 * 557 * @param imp The importance of this expression. 558 * @param name The name of this expression. 559 */ KExpression(long imp, String name)560 private KExpression(long imp, String name) 561 { 562 super(imp, name); 563 } 564 565 /** 566 * Create and return an expression from the input string. 567 * 568 * Determine if the input string matches the syntax defined by 569 * this expression. If the expression cannot be matched, an 570 * exception will be thrown. 571 * 572 * @param raw Candidate expression string. 573 * 574 * @throws IllegalArgumentExpression if the string is not a 575 * valid expression of this type. 576 */ valueOf(String raw)577 static Expression valueOf(String raw) throws IllegalArgumentException 578 { 579 KExpression exp = null; 580 Matcher m = pattern.matcher(raw); 581 582 if (m.matches()) { 583 long imp = 1; 584 585 if (m.group(2) != null) 586 imp = validateImportance(m.group(2)); 587 588 validateKeyword(keys, m.group(3)); 589 exp = new KExpression(imp, m.group(3)); 590 } 591 return (exp); 592 } 593 594 /** 595 * Return a string representation of this expresssion. 596 */ toString()597 public String toString() 598 { 599 return ("(" + getImportance() + ", " + getName() + ")"); 600 } 601 602 /** 603 * Indicates whether some other KExpression is "equal to 604 * this one. 605 * @param o the reference object with which to compare. 606 * @return <code>true</code> if this object is the same as the 607 * o argument; <code>false</code> otherwise. 608 * @see #hashCode() 609 */ equals(Object o)610 public boolean equals(Object o) 611 { 612 if (o == this) 613 return (true); 614 if (!(o instanceof KExpression)) 615 return (false); 616 KExpression other = (KExpression) o; 617 if (getName().compareTo(other.getName()) != 0) 618 return (false); 619 return (true); 620 } 621 622 /** 623 * Returns a hash code value for the object. This method is 624 * supported for the benefit of hashtables such as those provided by 625 * <code>java.util.Hashtable</code>. 626 * 627 * @return a hash code value for this object. 628 * @see #equals(java.lang.Object) 629 * @see java.util.Hashtable 630 */ hashCode()631 public int hashCode() 632 { 633 return (getName().hashCode()); 634 } 635 636 /** 637 * Return true if the supplied expression "contradicts" this 638 * expression. If the supplied expression is not of the same 639 * type, then it cannot contradict it. If the names are 640 * different then there can be no contradiction. 641 * 642 * @param o Expression to examine for contradiction. 643 */ contradicts(Expression o)644 public boolean contradicts(Expression o) 645 { 646 if (!(o instanceof KExpression)) 647 return (false); 648 KExpression other = (KExpression) o; 649 if (getName().compareTo(other.getName()) != 0) 650 return (false); 651 return (true); 652 } 653 } 654