/* * Copyright 1999-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package javax.management; /** *
Constructs query object constraints.
* *The MBean Server can be queried for MBeans that meet a particular * condition, using its {@link MBeanServer#queryNames queryNames} or * {@link MBeanServer#queryMBeans queryMBeans} method. The {@link QueryExp} * parameter to the method can be any implementation of the interface * {@code QueryExp}, but it is usually best to obtain the {@code QueryExp} * value by calling the static methods in this class. This is particularly * true when querying a remote MBean Server: a custom implementation of the * {@code QueryExp} interface might not be present in the remote MBean Server, * but the methods in this class return only standard classes that are * part of the JMX implementation.
* *There are two ways to create {@code QueryExp} objects using the methods * in this class. The first is to build them by chaining together calls to * the various methods. The second is to use the Query Language described * below and produce the {@code QueryExp} by calling * {@link #fromString Query.fromString}. The two ways are equivalent: * every {@code QueryExp} returned by {@code fromString} can also be * constructed by chaining method calls.
* *As an example, suppose you wanted to find all MBeans where the {@code * Enabled} attribute is {@code true} and the {@code Owner} attribute is {@code * "Duke"}. Here is how you could construct the appropriate {@code QueryExp} by * chaining together method calls:
* *
* QueryExp query =
* Query.and(Query.eq(Query.attr("Enabled"), Query.value(true)),
* Query.eq(Query.attr("Owner"), Query.value("Duke")));
*
*
* Here is how you could construct the same {@code QueryExp} using the * Query Language:
* *
* QueryExp query = Query.fromString("Enabled = true and Owner = 'Duke'");
*
*
* The principal advantage of the method-chaining approach is that the * compiler will check that the query makes sense. The principal advantage * of the Query Language approach is that it is easier to write and especially * read.
* * *The query language is closely modeled on the WHERE clause of * SQL SELECT statements. The formal specification of the language * appears below, but it is probably easier to * understand it with examples such as the following.
* *The last two examples do not correspond to valid SQL syntax, but all * the others do.
* *The remainder of this description is a formal specification of the * query language.
* * *Keywords such as and, like, and between are not * case sensitive. You can write between, BETWEEN, or * BeTwEeN with the same effect.
* *On the other hand, attribute names are case sensitive. The * attribute {@code Name} is not the same as the attribute {@code name}.
* *To access an attribute whose name, ignoring case, is the same as one of * the keywords {@code not}, {@code instanceof}, {@code like}, {@code true}, * or {@code false}, you can use double quotes, for example {@code "not"}. * Double quotes can also be used to include non-identifier characters in * the name of an attribute, for example {@code "attribute-name-with-hyphens"}. * To include the double quote character in the attribute name, write it * twice. {@code "foo""bar""baz"} represents the attribute called * {@code foo"bar"baz}. * *
String constants are written with single quotes like {@code 'this'}. A * single quote within a string constant must be doubled, for example * {@code 'can''t'}.
* *Integer constants are written as a sequence of decimal digits, * optionally preceded by a plus or minus sign. An integer constant must be * a valid input to {@link Long#valueOf(String)}.
* *Floating-point constants are written using the Java syntax. A * floating-point constant must be a valid input to * {@link Double#valueOf(String)}.
* *A boolean constant is either {@code true} or {@code false}, ignoring * case.
* *Spaces cannot appear inside identifiers (unless written with double
* quotes) or keywords or multi-character tokens such as {@code <=}. Spaces can
* appear anywhere else, but are not required except to separate tokens. For
* example, the query {@code a < b and 5 = c} could also be written {@code a
*
*
* Grammar
*
*
*
*
*
*
* NOT predicate |
* INSTANCEOF stringvalue |
* LIKE objectnamepattern |
* value predrhs
*
*
* [NOT] BETWEEN value AND
* value |
* [NOT] IN ( value
* commavalues ) |
* [NOT] LIKE stringvalue
*
* Semantics
*
*
The meaning of the grammar is described in the table below. * This defines a function q that maps a string to a Java object * such as a {@link QueryExp} or a {@link ValueExp}.
* *| String s | q(s) |
|---|---|
| query1 OR query2 * | {@link Query#or Query.or}(q(query1), q(query2)) * * |
| query1 AND query2 * | {@link Query#and Query.and}(q(query1), q(query2)) * * |
| ( queryOrValue ) * | q(queryOrValue) * * |
| NOT query * | {@link Query#not Query.not}(q(query)) * * |
| INSTANCEOF stringLiteral * | {@link Query#isInstanceOf Query.isInstanceOf}({@link Query#value(String) Query.value}(q(stringLiteral))) * * |
| LIKE stringLiteral * | {@link ObjectName#ObjectName(String) new ObjectName}(q(stringLiteral)) * * |
| value1 = value2 * | {@link Query#eq Query.eq}(q(value1), q(value2)) * * |
| value1 < value2 * | {@link Query#lt Query.lt}(q(value1), q(value2)) * * |
| value1 > value2 * | {@link Query#gt Query.gt}(q(value1), q(value2)) * * |
| value1 <= value2 * | {@link Query#leq Query.leq}(q(value1), q(value2)) * * |
| value1 >= value2 * | {@link Query#geq Query.geq}(q(value1), q(value2)) * * |
| value1 <> value2 * | {@link Query#not Query.not}({@link Query#eq Query.eq}(q(value1), q(value2))) * * |
| value1 != value2 * | {@link Query#not Query.not}({@link Query#eq Query.eq}(q(value1), q(value2))) * * |
| value1 BETWEEN value2 AND value3 * | {@link Query#between Query.between}(q(value1), * q(value2), q(value3)) * * |
| value1 NOT BETWEEN value2 AND value3 * | {@link Query#not Query.not}({@link Query#between Query.between}(q(value1), q(value2), q(value3))) * * |
| value1 IN ( value2, value3 ) * | {@link Query#in Query.in}(q(value1),
* new ValueExp[] {
* q(value2), q(value3)})
*
* |
| value1 NOT IN ( value2, value3 ) * | {@link Query#not Query.not}({@link Query#in Query.in}(q(value1),
* new ValueExp[] {
* q(value2), q(value3)}))
*
* |
| value LIKE stringLiteral * | {@link Query#match Query.match}(q(value), * translateWildcards(q(stringLiteral))) * * |
| value NOT LIKE stringLiteral * | {@link Query#not Query.not}({@link Query#match Query.match}(q(value), * translateWildcards(q(stringLiteral)))) * * |
| value1 + value2 * | {@link Query#plus Query.plus}(q(value1), q(value2)) * * |
| value1 - value2 * | {@link Query#minus Query.minus}(q(value1), q(value2)) * * |
| value1 * value2 * | {@link Query#times Query.times}(q(value1), q(value2)) * * |
| value1 / value2 * | {@link Query#div Query.div}(q(value1), q(value2)) * * |
| name * | {@link Query#attr(String) Query.attr}(q(name)) * * |
| name1#name2 * | {@link Query#attr(String,String) Query.attr}(q(name1), * q(name2)) * * |
| FALSE * | {@link Query#value(boolean) Query.value}(false) * * |
| TRUE * | {@link Query#value(boolean) Query.value}(true) * * |
| decimalLiteral * | {@link Query#value(long) Query.value}({@link Long#valueOf(String) Long.valueOf}(decimalLiteral)) * * |
| floatingPointLiteral * | {@link Query#value(double) Query.value}({@link Double#valueOf(String) Double.valueOf}(floatingPointLiteral)) * |
Here, translateWildcards is a function * that translates from the SQL notation for wildcards, using {@code %} and * {@code _}, to the JMX API notation, using {@code *} and {@code ?}. If the * LIKE string already contains {@code *} or {@code ?}, these characters * have their literal meanings, and will be quoted in the call to * {@link Query#match Query.match}.
* * @since 1.5 */ public class Query extends Object { /** * A code representing the {@link Query#gt} query. This is chiefly * of interest for the serialized form of queries. */ public static final int GT = 0; /** * A code representing the {@link Query#lt} query. This is chiefly * of interest for the serialized form of queries. */ public static final int LT = 1; /** * A code representing the {@link Query#geq} query. This is chiefly * of interest for the serialized form of queries. */ public static final int GE = 2; /** * A code representing the {@link Query#leq} query. This is chiefly * of interest for the serialized form of queries. */ public static final int LE = 3; /** * A code representing the {@link Query#eq} query. This is chiefly * of interest for the serialized form of queries. */ public static final int EQ = 4; /** * A code representing the {@link Query#plus} expression. This * is chiefly of interest for the serialized form of queries. */ public static final int PLUS = 0; /** * A code representing the {@link Query#minus} expression. This * is chiefly of interest for the serialized form of queries. */ public static final int MINUS = 1; /** * A code representing the {@link Query#times} expression. This * is chiefly of interest for the serialized form of queries. */ public static final int TIMES = 2; /** * A code representing the {@link Query#div} expression. This is * chiefly of interest for the serialized form of queries. */ public static final int DIV = 3; /** * Basic constructor. */ public Query() { } /** * Returns a query expression that is the conjunction of two other query * expressions. * * @param q1 A query expression. * @param q2 Another query expression. * * @return The conjunction of the two arguments. The returned object * will be serialized as an instance of the non-public class {@link * * javax.management.AndQueryExp}. */ public static QueryExp and(QueryExp q1, QueryExp q2) { return new AndQueryExp(q1, q2); } /** * Returns a query expression that is the disjunction of two other query * expressions. * * @param q1 A query expression. * @param q2 Another query expression. * * @return The disjunction of the two arguments. The returned object * will be serialized as an instance of the non-public class {@link * * javax.management.OrQueryExp}. */ public static QueryExp or(QueryExp q1, QueryExp q2) { return new OrQueryExp(q1, q2); } /** * Returns a query expression that represents a "greater than" constraint on * two values. * * @param v1 A value expression. * @param v2 Another value expression. * * @return A "greater than" constraint on the arguments. The * returned object will be serialized as an instance of the * non-public class {@link * javax.management.BinaryRelQueryExp} with a {@code relOp} equal * to {@link #GT}. */ public static QueryExp gt(ValueExp v1, ValueExp v2) { return new BinaryRelQueryExp(GT, v1, v2); } /** * Returns a query expression that represents a "greater than or equal * to" constraint on two values. * * @param v1 A value expression. * @param v2 Another value expression. * * @return A "greater than or equal to" constraint on the * arguments. The returned object will be serialized as an * instance of the non-public class {@link * javax.management.BinaryRelQueryExp} with a {@code relOp} equal * to {@link #GE}. */ public static QueryExp geq(ValueExp v1, ValueExp v2) { return new BinaryRelQueryExp(GE, v1, v2); } /** * Returns a query expression that represents a "less than or equal to" * constraint on two values. * * @param v1 A value expression. * @param v2 Another value expression. * * @return A "less than or equal to" constraint on the arguments. * The returned object will be serialized as an instance of the * non-public class {@link * javax.management.BinaryRelQueryExp} with a {@code relOp} equal * to {@link #LE}. */ public static QueryExp leq(ValueExp v1, ValueExp v2) { return new BinaryRelQueryExp(LE, v1, v2); } /** * Returns a query expression that represents a "less than" constraint on * two values. * * @param v1 A value expression. * @param v2 Another value expression. * * @return A "less than" constraint on the arguments. The * returned object will be serialized as an instance of the * non-public class {@link * javax.management.BinaryRelQueryExp} with a {@code relOp} equal * to {@link #LT}. */ public static QueryExp lt(ValueExp v1, ValueExp v2) { return new BinaryRelQueryExp(LT, v1, v2); } /** * Returns a query expression that represents an equality constraint on * two values. * * @param v1 A value expression. * @param v2 Another value expression. * * @return A "equal to" constraint on the arguments. The * returned object will be serialized as an instance of the * non-public class {@link * javax.management.BinaryRelQueryExp} with a {@code relOp} equal * to {@link #EQ}. */ public static QueryExp eq(ValueExp v1, ValueExp v2) { return new BinaryRelQueryExp(EQ, v1, v2); } /** * Returns a query expression that represents the constraint that one * value is between two other values. * * @param v1 A value expression that is "between" v2 and v3. * @param v2 Value expression that represents a boundary of the constraint. * @param v3 Value expression that represents a boundary of the constraint. * * @return The constraint that v1 lies between v2 and v3. The * returned object will be serialized as an instance of the * non-public class {@link * javax.management.BetweenQueryExp}. */ public static QueryExp between(ValueExp v1, ValueExp v2, ValueExp v3) { return new BetweenQueryExp(v1, v2, v3); } /** * Returns a query expression that represents a matching constraint on * a string argument. The matching syntax is consistent with file globbing: * supports "?", "*", "[",
* each of which may be escaped with "\";
* character classes may use "!" for negation and
* "-" for range.
* (* for any character sequence,
* ? for a single arbitrary character,
* [...] for a character sequence).
* For example: a*b?c would match a string starting
* with the character a, followed
* by any number of characters, followed by a b,
* any single character, and a c.
*
* @param a An attribute expression
* @param s A string value expression representing a matching constraint
*
* @return A query expression that represents the matching
* constraint on the string argument. The returned object will
* be serialized as an instance of the non-public class {@link
* javax.management.MatchQueryExp}.
*/
public static QueryExp match(AttributeValueExp a, StringValueExp s) {
return new MatchQueryExp(a, s);
}
/**
* Returns a new attribute expression. See {@link AttributeValueExp} * for a detailed description of the semantics of the expression.
* * @param name The name of the attribute. * * @return An attribute expression for the attribute named {@code name}. */ public static AttributeValueExp attr(String name) { return new AttributeValueExp(name); } /** *Returns a new qualified attribute expression.
* *Evaluating this expression for a given
* objectName includes performing {@link
* MBeanServer#getObjectInstance
* MBeanServer.getObjectInstance(objectName)} and {@link
* MBeanServer#getAttribute MBeanServer.getAttribute(objectName,
* name)}.
Returns a new class attribute expression which can be used in any * Query call that expects a ValueExp.
* *Evaluating this expression for a given
* objectName includes performing {@link
* MBeanServer#getObjectInstance
* MBeanServer.getObjectInstance(objectName)}.
Example: to find MBeans that are instances of * {@link NotificationBroadcaster}, use * {@code Query.isInstanceOf(Query.value(NotificationBroadcaster.class.getName()))}. *
*Evaluating this expression for a given
* objectName includes performing {@link
* MBeanServer#isInstanceOf MBeanServer.isInstanceOf(objectName,
* ((StringValueExp)classNameValue.apply(objectName)).getValue()}.
Return a string representation of the given query. The string * returned by this method can be converted back into an equivalent * query using {@link #fromString fromString}.
* *(Two queries are equivalent if they produce the same result in * all cases. Equivalent queries are not necessarily identical: * for example the queries {@code Query.lt(Query.attr("A"), Query.attr("B"))} * and {@code Query.not(Query.ge(Query.attr("A"), Query.attr("B")))} are * equivalent but not identical.)
* *The string returned by this method is only guaranteed to be converted * back into an equivalent query if {@code query} was constructed, or * could have been constructed, using the methods of this class. * If you make a custom query {@code myQuery} by implementing * {@link QueryExp} yourself then the result of * {@code Query.toString(myQuery)} is unspecified.
* * @param query the query to convert. If it is null, the result will * also be null. * @return the string representation of the query, or null if the * query is null. * * @since 1.7 */ public static String toString(QueryExp query) { if (query == null) return null; if (query instanceof ToQueryString) return ((ToQueryString) query).toQueryString(); return query.toString(); } /** *Produce a query from the given string. The query returned * by this method can be converted back into a string using * {@link #toString(QueryExp) toString}. The resultant string will * not necessarily be equal to {@code s}.
* * @param s the string to convert. * * @return a {@code QueryExp} derived by parsing the string, or * null if the string is null. * * @throws IllegalArgumentException if the string is not a valid * query string. * * @since 1.7 */ public static QueryExp fromString(String s) { if (s == null) return null; return new QueryParser(s).parseQuery(); } /** * Utility method to escape strings used with * Query.{initial|any|final}SubString() methods. */ private static String escapeString(String s) { if (s == null) return null; s = s.replace("\\", "\\\\"); s = s.replace("*", "\\*"); s = s.replace("?", "\\?"); s = s.replace("[", "\\["); return s; } }