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