root/usr/src/cmd/pools/poold/com/sun/solaris/domain/pools/Expression.java
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 *
 * ident        "%Z%%M% %I%     %E% SMI"
 */

package com.sun.solaris.domain.pools;

import java.util.regex.*;

/**
 * This class provides the base implementation of an Expression. All
 * types of Expression must inherit from this class.
 *
 * An objective is always specified in terms of an expression. The
 * only recognized expressions are those known by this class. An
 * expression is create using the valueOf() factory method, which is
 * why Expressions must be known to this class.
 */
abstract class Expression
{
        /**
         * Expression importance
         */
        private long imp = -1;

        /**
         * Expression name
         */
        private String name;

        /**
         * Sole constructor.  (For invocation by subclass constructors)
         */
        protected Expression(long imp, String name)
        {
                this.imp = imp;
                this.name = name;
        }

        /**
         * Return the name of the expression.
         */
        String getName()
        {
                return (this.name);
        }

        /**
         * Return the importance of the expression.
         */
        long getImportance()
        {
                return (imp);
        }

        /**
         * Returns the supplied string as an expression.
         *
         * This utility function attempts to identify the supplied
         * string as an expression. It tries in turn each of the known
         * sub-classes until finally, if none can be recognized, an
         * exception is thrown. This function is not immune to
         * mistakenly mis-classifying an expression. It is the
         * responsibility of the concrete Exrpession classes to ensure
         * that syntactic integrity is maintained with respect to
         * potential cases of mistaken identity.
         *
         * @param raw The candidate expression
         * @throws IllegalArgumentException If no valid expression can
         * be found
         */
        static Expression valueOf(String raw) throws IllegalArgumentException
        {
                Expression exp = null;
                /*
                 * TODO It would be better if subclasses registered,
                 * but this hard coded list will do until such a time
                 */
                if ((exp = KVOpExpression.valueOf(raw)) == null)
                        if ((exp = KVExpression.valueOf(raw)) == null)
                                exp = KExpression.valueOf(raw);
                if (exp == null)
                        throw new IllegalArgumentException(
                            "unrecognized expression: " + raw);
                return (exp);
        }

        /**
         * Ensure that the supplied importance is a valid value.
         *
         * @param imps String representation of the importance.
         *
         * @throws IllegalArgumentException if the importance is not
         * valid.
         */
        protected static long validateImportance(String imps)
            throws IllegalArgumentException
        {
                long imp;

                try {
                        imp = Long.parseLong(imps);
                } catch (NumberFormatException nfe) {
                        throw new IllegalArgumentException("importance value " +
                            imps + " is not legal");
                }

                if (imp < 0)
                        throw new IllegalArgumentException("importance value " +
                            imps + " is not legal (must be positive)");
                return (imp);
        }

        /**
         * Ensure that the supplied keyword is a member of the
         * supplied keys.
         *
         * @param keys Array of valid key strings.
         * @param key Key sought.
         *
         * @throws IllegalArgumentException if the sought key is not
         * a member of the keys array.
         */
        protected static void validateKeyword(String keys[], String key)
            throws IllegalArgumentException
        {
                for (int i = 0; i < keys.length; i++) {
                        if (keys[i].compareTo(key) == 0)
                                return;
                }
                throw new IllegalArgumentException("keyword " + key +
                    " is not recognized");
        }

        /**
         * Return true if the supplied expression "contradicts" this
         * expression. The definition of contradiction is left down to
         * each implementing sub-class.
         *
         * @param o Expression to examine for contradiction.
         */
        public abstract boolean contradicts(Expression o);
}

/**
 * This class implements the functionality for a key-value-operator
 * expression.
 *
 * The general form of this expression is defined in the pattern
 * member. A simplified rendition of which is:
 *
 * [[imp]:] <key> <op> <value>
 *
 * key is a string which identifies the expression
 * op is the operator for the expression ( < | > | ~)
 * value is the value of the expression
 *
 * For example:
 *
 * 10: utilization < 80
 */
final class KVOpExpression extends Expression
{
        /**
         * The operator for this expression.
         */
        private char op;

        /**
         * The value of this expression.
         */
        private int val;

        /**
         * The pattern used to recognize this type of expression.
         */
        private static final Pattern pattern = Pattern.compile(
            "\\s*((\\d+)\\s*:)?\\s*(\\w+)\\s*([~<>])\\s*(\\d+)\\s*");

        /**
         * The array of valid keys for this type of expression.
         */
        private static final String keys[] = { "utilization" };

        /**
         * A greater than operator.
         */
        static final char GT = '>';

        /**
         * A less than operator.
         */
        static final char LT = '<';

        /**
         * A near to operator.
         */
        static final char NT = '~';

        /**
         * Private constructor used in the valueOf() factory method.
         *
         * @param imp The importance of this expression.
         * @param name The name of this expression.
         * @param op The operator of this expression.
         * @param val The value of this expression.
         */
        private KVOpExpression(long imp, String name, String op, int val)
        {
                super(imp, name);
                this.op = op.charAt(0);
                this.val = val;
        }

        /**
         * Create and return an expression from the input string.
         *
         * Determine if the input string matches the syntax defined by
         * this expression. If the expression cannot be matched, an
         * exception will be thrown.
         *
         * @param raw Candidate expression string.
         *
         * @throws IllegalArgumentExpression if the string is not a
         * valid expression of this type.
         */
        static Expression valueOf(String raw) throws IllegalArgumentException
        {
                KVOpExpression exp = null;
                Matcher m = pattern.matcher(raw);

                if (m.matches()) {
                        long imp = 1;
                        int val = Integer.parseInt(m.group(5));

                        if (m.group(2) != null)
                                imp = validateImportance(m.group(2));

                        validateKeyword(keys, m.group(3));
                        if (val > 100 || val < 0)
                                throw new IllegalArgumentException(
                                    "expression value " + val +
                                    " is outside the legal range (0-100)");
                        exp = new KVOpExpression(imp, m.group(3),
                            m.group(4), val);
                }
                return (exp);
        }

        /**
         * Return the operator for this expression.
         */
        char getOp()
        {
                return (op);
        }

        /**
         * Return the value of this expression.
         */
        int getValue()
        {
                return (val);
        }

        /**
         * Return a string representation of this expresssion.
         */
        public String toString()
        {
                return ("(" + getImportance() + ", " + getName() + ", '" + op +
                    "', " + val + ")");
        }

        /**
         * Indicates whether some other KVOpExpression is "equal to
         * this one.
         * @param o the reference object with which to compare.
         * @return <code>true</code> if this object is the same as the
         * o argument; <code>false</code> otherwise.
         * @see #hashCode()
         */
        public boolean equals(Object o)
        {
                if (o == this)
                        return (true);
                if (!(o instanceof KVOpExpression))
                        return (false);
                KVOpExpression other = (KVOpExpression) o;
                if (getName().compareTo(other.getName()) != 0 ||
                    op != other.getOp() || val != other.getValue())
                        return (false);
                return (true);
        }

        /**
         * Returns a hash code value for the object. This method is
         * supported for the benefit of hashtables such as those provided by
         * <code>java.util.Hashtable</code>.
         *
         * @return a hash code value for this object.
         * @see #equals(java.lang.Object)
         * @see java.util.Hashtable
         */
        public int hashCode()
        {
                return (getName().hashCode() + (int) op + val);
        }

        /**
         * Return true if the supplied expression "contradicts" this
         * expression. If the supplied expression is not of the same
         * type, then it cannot contradict it. If the names are
         * different then there can be no contradiction.
         *
         * Contradiction occurs if the operator is the same or if they
         * aren't the same and the operator is < or > and the values
         * aren't simultanteously achievable.
         *
         * @param o Expression to examine for contradiction.
         */
        public boolean contradicts(Expression o)
        {
                if (!(o instanceof KVOpExpression))
                        return (false);
                KVOpExpression other = (KVOpExpression) o;
                if (getName().compareTo(other.getName()) != 0)
                        return (false);
                if (getOp() != other.getOp()) {
                        if (getOp() != NT && other.getOp() != NT) {
                                if (getOp() == GT) {
                                        if (getValue() < other.getValue())
                                                return (false);
                                } else {
                                        if (getValue() > other.getValue())
                                                return (false);
                                }
                        } else
                                return (false);
                }
                return (true);
        }
}

/**
 * This class implements the functionality for a key-value expression.
 *
 * The general form of this expression is defined in the pattern
 * member. A simplified rendition of which is:
 *
 * [[imp]:] <key> <value>
 *
 * key is a string which identifies the expression
 * value is the value of the expression
 *
 * For example:
 *
 * 10: locality tight
 */
final class KVExpression extends Expression
{
        /**
         * The value of this expression.
         */
        private String val;

        /**
         * The pattern used to recognize this type of expression.
         */
        private static final Pattern pattern = Pattern.compile(
            "\\s*((\\d+)\\s*:)?\\s*(\\w+)\\s+(tight|loose|none)\\s*");

        /**
         * The array of valid keys for this type of expression.
         */
        private static final String keys[] = { "locality" };

        /**
         * Private constructor used in the valueOf() factory method.
         *
         * @param imp The importance of this expression.
         * @param name The name of this expression.
         * @param val The value of this expression.
         */
        private KVExpression(long imp, String name, String val)
        {
                super(imp, name);
                this.val = val;
        }

        /**
         * Create and return an expression from the input string.
         *
         * Determine if the input string matches the syntax defined by
         * this expression. If the expression cannot be matched, an
         * exception will be thrown.
         *
         * @param raw Candidate expression string.
         *
         * @throws IllegalArgumentExpression if the string is not a
         * valid expression of this type.
         */
        static Expression valueOf(String raw) throws IllegalArgumentException
        {
                KVExpression exp = null;
                Matcher m = pattern.matcher(raw);

                if (m.matches()) {
                        long imp = 1;

                        if (m.group(2) != null)
                                imp = validateImportance(m.group(2));

                        validateKeyword(keys, m.group(3));
                        exp = new KVExpression(imp, m.group(3), m.group(4));
                }
                return (exp);
        }

        /**
         * Return the value of this expression.
         */
        String getValue()
        {
                return (val);
        }

        /**
         * Return a string representation of this expresssion.
         */
        public String toString()
        {
                StringBuffer buf = new StringBuffer();

                buf.append("(");
                buf.append(getImportance());
                buf.append(", ");
                buf.append(getName());
                buf.append(", ");
                buf.append(val);
                buf.append(")");

                return (buf.toString());
        }

        /**
         * Indicates whether some other KVExpression is "equal to
         * this one.
         * @param o the reference object with which to compare.
         * @return <code>true</code> if this object is the same as the
         * o argument; <code>false</code> otherwise.
         * @see #hashCode()
         */
        public boolean equals(Object o)
        {
                if (o == this)
                        return (true);
                if (!(o instanceof KVExpression))
                        return (false);
                KVExpression other = (KVExpression) o;
                if (getName().compareTo(other.getName()) != 0 ||
                    val.compareTo(other.getValue()) != 0)
                        return (false);
                return (true);
        }

        /**
         * Returns a hash code value for the object. This method is
         * supported for the benefit of hashtables such as those provided by
         * <code>java.util.Hashtable</code>.
         *
         * @return a hash code value for this object.
         * @see #equals(java.lang.Object)
         * @see java.util.Hashtable
         */
        public int hashCode()
        {
                return (getName().hashCode() + val.hashCode());
        }

        /**
         * Return true if the supplied expression "contradicts" this
         * expression. If the supplied expression is not of the same
         * type, then it cannot contradict it. If the names are
         * different then there can be no contradiction.
         *
         * Contradiction occurs if the value is different.
         *
         * @param o Expression to examine for contradiction.
         */
        public boolean contradicts(Expression o)
        {
                if (!(o instanceof KVExpression))
                        return (false);
                KVExpression other = (KVExpression) o;
                if (getName().compareTo(other.getName()) != 0)
                        return (false);
                if (val.compareTo(other.getValue()) == 0)
                        return (false);
                return (true);
        }
}

/**
 * This class implements the functionality for a key expression.
 *
 * The general form of this expression is defined in the pattern
 * member. A simplified rendition of which is:
 *
 * [[imp]:] <key>
 *
 * key is a string which identifies the expression
 *
 * For example:
 *
 * 10: wt-load
 */
final class KExpression extends Expression
{
        /**
         * The pattern used to recognize this type of expression.
         */
        private static final Pattern pattern = Pattern.compile(
            "\\s*((\\d+)\\s*:)?\\s*([\\w-]+)\\s*");

        /**
         * The array of valid keys for this type of expression.
         */
        private static final String keys[] = { "wt-load" };

        /**
         * Private constructor used in the valueOf() factory method.
         *
         * @param imp The importance of this expression.
         * @param name The name of this expression.
         */
        private KExpression(long imp, String name)
        {
                super(imp, name);
        }

        /**
         * Create and return an expression from the input string.
         *
         * Determine if the input string matches the syntax defined by
         * this expression. If the expression cannot be matched, an
         * exception will be thrown.
         *
         * @param raw Candidate expression string.
         *
         * @throws IllegalArgumentExpression if the string is not a
         * valid expression of this type.
         */
        static Expression valueOf(String raw) throws IllegalArgumentException
        {
                KExpression exp = null;
                Matcher m = pattern.matcher(raw);

                if (m.matches()) {
                        long imp = 1;

                        if (m.group(2) != null)
                                imp = validateImportance(m.group(2));

                        validateKeyword(keys, m.group(3));
                        exp = new KExpression(imp, m.group(3));
                }
                return (exp);
        }

        /**
         * Return a string representation of this expresssion.
         */
        public String toString()
        {
                return ("(" + getImportance() + ", " + getName() + ")");
        }

        /**
         * Indicates whether some other KExpression is "equal to
         * this one.
         * @param o the reference object with which to compare.
         * @return <code>true</code> if this object is the same as the
         * o argument; <code>false</code> otherwise.
         * @see #hashCode()
         */
        public boolean equals(Object o)
        {
                if (o == this)
                        return (true);
                if (!(o instanceof KExpression))
                        return (false);
                KExpression other = (KExpression) o;
                if (getName().compareTo(other.getName()) != 0)
                        return (false);
                return (true);
        }

        /**
         * Returns a hash code value for the object. This method is
         * supported for the benefit of hashtables such as those provided by
         * <code>java.util.Hashtable</code>.
         *
         * @return a hash code value for this object.
         * @see #equals(java.lang.Object)
         * @see java.util.Hashtable
         */
        public int hashCode()
        {
                return (getName().hashCode());
        }

        /**
         * Return true if the supplied expression "contradicts" this
         * expression. If the supplied expression is not of the same
         * type, then it cannot contradict it. If the names are
         * different then there can be no contradiction.
         *
         * @param o Expression to examine for contradiction.
         */
        public boolean contradicts(Expression o)
        {
                if (!(o instanceof KExpression))
                        return (false);
                KExpression other = (KExpression) o;
                if (getName().compareTo(other.getName()) != 0)
                        return (false);
                return (true);
        }
}