6701498: Change JMX query language to use * and ? as wildcards rather than % and _
authoremcmanus
Thu, 05 Jun 2008 13:40:09 +0200
changeset 686 d0c74839e1bd
parent 685 b4e01579b558
child 687 874e25a9844a
6701498: Change JMX query language to use * and ? as wildcards rather than % and _ Reviewed-by: dfuchs
jdk/src/share/classes/javax/management/MatchQueryExp.java
jdk/src/share/classes/javax/management/ObjectName.java
jdk/src/share/classes/javax/management/Query.java
jdk/src/share/classes/javax/management/QueryNotificationFilter.java
jdk/src/share/classes/javax/management/QueryParser.java
jdk/test/javax/management/query/QueryExpStringTest.java
jdk/test/javax/management/query/QueryParseTest.java
--- a/jdk/src/share/classes/javax/management/MatchQueryExp.java	Thu Jun 05 04:08:41 2008 -0700
+++ b/jdk/src/share/classes/javax/management/MatchQueryExp.java	Thu Jun 05 13:40:09 2008 +0200
@@ -109,36 +109,7 @@
      * Returns the string representing the object
      */
     public String toString()  {
-        return exp + " like " + new StringValueExp(likeTranslate(pattern));
-    }
-
-    private static String likeTranslate(String s) {
-        StringBuilder sb = new StringBuilder();
-        int c;
-        for (int i = 0; i < s.length(); i += Character.charCount(c)) {
-            c = s.codePointAt(i);
-            switch (c) {
-                case '\\':
-                    i += Character.charCount(c);
-                    sb.append('\\');
-                    if (i < s.length()) {
-                        c = s.codePointAt(i);
-                        sb.appendCodePoint(c);
-    }
-                    break;
-                case '*':
-                    sb.append('%'); break;
-                case '?':
-                    sb.append('_'); break;
-                case '%':
-                    sb.append("\\%"); break;
-                case '_':
-                    sb.append("\\_"); break;
-                default:
-                    sb.appendCodePoint(c); break;
-            }
-        }
-        return sb.toString();
+        return exp + " like " + new StringValueExp(pattern);
     }
 
     /*
--- a/jdk/src/share/classes/javax/management/ObjectName.java	Thu Jun 05 04:08:41 2008 -0700
+++ b/jdk/src/share/classes/javax/management/ObjectName.java	Thu Jun 05 13:40:09 2008 +0200
@@ -1781,7 +1781,7 @@
     }
 
     String toQueryString() {
-        return "LIKE " + Query.value(toString());
+        return "like " + Query.value(toString());
     }
 
     /**
--- a/jdk/src/share/classes/javax/management/Query.java	Thu Jun 05 04:08:41 2008 -0700
+++ b/jdk/src/share/classes/javax/management/Query.java	Thu Jun 05 13:40:09 2008 +0200
@@ -108,13 +108,13 @@
  * <dd>Selects MBeans that have a {@code Status} attribute whose value
  *     is one of those three strings.
  *
- * <dt>{@code Message like 'OK: %'}
+ * <dt>{@code Message like 'OK: *'}
  * <dd>Selects MBeans that have a {@code Message} attribute whose value
  *     is a string beginning with {@code "OK: "}.  <b>Notice that the
- *     wildcard characters are SQL's ones.</b>  In the query language,
+ *     wildcard characters are not the ones that SQL uses.</b>  In SQL,
  *     {@code %} means "any sequence of characters" and {@code _}
- *     means "any single character".  In the rest of the JMX API, these
- *     correspond to {@code *} and {@code %} respectively.
+ *     means "any single character".  Here, as in the rest of the JMX API,
+ *     those are represented by {@code *} and {@code ?} respectively.
  *
  * <dt>{@code instanceof 'javax.management.NotificationBroadcaster'}
  * <dd>Selects MBeans that are instances of
@@ -319,11 +319,11 @@
  *
  * <tr><td><i>value</i> <b>LIKE</b> <i>stringLiteral</i>
  *     <td>{@link Query#match Query.match}(<i>q(value)</i>,
- *         <i><a href="#translateWildcards">translateWildcards</a>(q(stringLiteral))</i>)
+ *         <i>q(stringLiteral)</i>)
  *
  * <tr><td><i>value</i> <b>NOT LIKE</b> <i>stringLiteral</i>
  *     <td>{@link Query#not Query.not}({@link Query#match Query.match}(<i>q(value)</i>,
- *         <i><a href="#translateWildcards">translateWildcards</a>(q(stringLiteral))</i>))
+ *         <i>q(stringLiteral)</i>))
  *
  * <tr><td><i>value1</i> <b>+</b> <i>value2</i>
  *     <td>{@link Query#plus Query.plus}(<i>q(value1)</i>, <i>q(value2)</i>)
@@ -360,13 +360,6 @@
  * --><i>floatingPointLiteral</i>))
  * </table>
  *
- * <p id="translateWildcards">Here, <i>translateWildcards</i> 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
- * <b>LIKE</b> 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}.</p>
- *
  * @since 1.5
  */
  public class Query extends Object   {
--- a/jdk/src/share/classes/javax/management/QueryNotificationFilter.java	Thu Jun 05 04:08:41 2008 -0700
+++ b/jdk/src/share/classes/javax/management/QueryNotificationFilter.java	Thu Jun 05 13:40:09 2008 +0200
@@ -43,12 +43,6 @@
  * on both the client and the server in the remote case, so using this class
  * instead is recommended where possible.</p>
  *
- * <!-- <p>Because this class was introduced in version 2.0 of the JMX API,
- * it may not be present on a remote JMX agent that is running an earlier
- * version.  The method {@link JMX#addListenerWithFilter JMX.addListenerWithFilter}
- * can be used when you cannot be sure whether this class is present in the
- * agent you are connecting to.</p> -->
- *
  * <p>This class uses the {@linkplain Query Query API} to specify the
  * filtering logic.  For example, to select only notifications where the
  * {@linkplain Notification#getType() type} is {@code "com.example.mytype"},
--- a/jdk/src/share/classes/javax/management/QueryParser.java	Thu Jun 05 04:08:41 2008 -0700
+++ b/jdk/src/share/classes/javax/management/QueryParser.java	Thu Jun 05 13:40:09 2008 +0200
@@ -490,8 +490,7 @@
                 }
                 AttributeValueExp alhs = (AttributeValueExp) lhs;
                 StringValueExp sve = stringvalue();
-                String s = sve.getValue();
-                q = Query.match(alhs, patternValueExp(s));
+                q = Query.match(alhs, sve);
                 break;
             }
 
@@ -624,40 +623,4 @@
             throw new IllegalArgumentException("Expected string: " + t);
         return Query.value(t.string);
     }
-
-    // Convert the SQL pattern syntax, using % and _, to the Query.match
-    // syntax, using * and ?.  The tricky part is recognizing \% and
-    // \_ as literal values, and also not replacing them inside [].
-    // But Query.match does not recognize \ inside [], which makes our
-    // job a tad easier.
-    private StringValueExp patternValueExp(String s) {
-        int c;
-        for (int i = 0; i < s.length(); i += Character.charCount(c)) {
-            c = s.codePointAt(i);
-            switch (c) {
-                case '\\':
-                    i++;  // i += Character.charCount(c), but we know it's 1!
-                    if (i >= s.length())
-                        throw new IllegalArgumentException("\\ at end of pattern");
-                    break;
-                case '[':
-                    i = s.indexOf(']', i);
-                    if (i < 0)
-                        throw new IllegalArgumentException("[ without ]");
-                    break;
-                case '%':
-                    s = s.substring(0, i) + "*" + s.substring(i + 1);
-                    break;
-                case '_':
-                    s = s.substring(0, i) + "?" + s.substring(i + 1);
-                    break;
-                case '*':
-                case '?':
-                    s = s.substring(0, i) + '\\' + (char) c + s.substring(i + 1);
-                    i++;
-                    break;
-            }
-        }
-        return Query.value(s);
-    }
 }
--- a/jdk/test/javax/management/query/QueryExpStringTest.java	Thu Jun 05 04:08:41 2008 -0700
+++ b/jdk/test/javax/management/query/QueryExpStringTest.java	Thu Jun 05 13:40:09 2008 +0200
@@ -121,14 +121,14 @@
         eq, "(12345678) = (2.5)",
         between, "(12345678) between (2.5) and (2.5)",
         match, "attr like 'simpleString'",
-        initial, "attr like 'simpleString%'",
-        initialStar, "attr like '\\*%'",
-        initialPercent, "attr like '\\%%'",
-        any, "attr like '%simpleString%'",
-        anyStar, "attr like '%\\*%'",
-        anyPercent, "attr like '%\\%%'",
-        ffinal, "attr like '%simpleString'",
-        finalMagic, "attr like '%\\?\\*\\[\\\\'",
+        initial, "attr like 'simpleString*'",
+        initialStar, "attr like '\\**'",
+        initialPercent, "attr like '%*'",
+        any, "attr like '*simpleString*'",
+        anyStar, "attr like '*\\**'",
+        anyPercent, "attr like '*%*'",
+        ffinal, "attr like '*simpleString'",
+        finalMagic, "attr like '*\\?\\*\\[\\\\'",
         in, "12345678 in (12345678, 2.5)",
         and, "((12345678) > (2.5)) and ((12345678) < (2.5))",
         or, "((12345678) > (2.5)) or ((12345678) < (2.5))",
@@ -207,7 +207,6 @@
                                     exp + " like " + pat);
             }
             StringValueExp spat = (StringValueExp) pat;
-            spat = Query.value(translateMatch(spat.getValue()));
             return Query.match((AttributeValueExp) exp, spat);
         }
 
@@ -226,28 +225,6 @@
         throw new Exception("Expected in or like after expression");
     }
 
-    private static String translateMatch(String s) {
-        StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < s.length(); i++) {  // logic not correct for wide chars
-            char c = s.charAt(i);
-            switch (c) {
-                case '\\':
-                    sb.append(c).append(s.charAt(++i)); break;
-                case '%':
-                    sb.append('*'); break;
-                case '_':
-                    sb.append('?'); break;
-                case '*':
-                    sb.append("\\*"); break;
-                case '?':
-                    sb.append("\\?"); break;
-                default:
-                    sb.append(c); break;
-            }
-        }
-        return sb.toString();
-    }
-
     private static QueryExp parseQueryAfterParen(String[] ss)
             throws Exception {
         /* This is very ugly.  We might have "(q1) and (q2)" here, or
--- a/jdk/test/javax/management/query/QueryParseTest.java	Thu Jun 05 04:08:41 2008 -0700
+++ b/jdk/test/javax/management/query/QueryParseTest.java	Thu Jun 05 13:40:09 2008 +0200
@@ -347,30 +347,30 @@
 
         // LIKE
 
-        "A like 'b%m'",
+        "A like 'b*m'",
         expectTrue("blim"), expectTrue("bm"),
         expectFalse(""), expectFalse("blimmo"), expectFalse("mmm"),
 
-        "A not like 'b%m'",
+        "A not like 'b*m'",
         expectFalse("blim"), expectFalse("bm"),
         expectTrue(""), expectTrue("blimmo"), expectTrue("mmm"),
 
-        "A like 'b_m'",
+        "A like 'b?m'",
         expectTrue("bim"), expectFalse("blim"),
 
-        "A like '%can''t%'",
+        "A like '*can''t*'",
         expectTrue("can't"),
         expectTrue("I'm sorry Dave, I'm afraid I can't do that"),
         expectFalse("cant"), expectFalse("can''t"),
 
-        "A like '\\%%\\%'",
-        expectTrue("%blim%"), expectTrue("%%"),
-        expectFalse("blim"), expectFalse("%asdf"), expectFalse("asdf%"),
+        "A like '\\**\\*'",
+        expectTrue("*blim*"), expectTrue("**"),
+        expectFalse("blim"), expectFalse("*asdf"), expectFalse("asdf*"),
 
-        "A LIKE '*%?_'",
-        expectTrue("*blim?!"), expectTrue("*?_"),
-        expectFalse("blim"), expectFalse("blim?"),
-        expectFalse("?*"), expectFalse("??"), expectFalse(""), expectFalse("?"),
+        "A LIKE '%*_?'",
+        expectTrue("%blim_?"), expectTrue("%_?"), expectTrue("%blim_!"),
+        expectFalse("blim"), expectFalse("blim_"),
+        expectFalse("_%"), expectFalse("??"), expectFalse(""), expectFalse("?"),
 
         Query.toString(
                 Query.initialSubString(Query.attr("A"), Query.value("*?%_"))),
@@ -483,7 +483,7 @@
         // note the little {} at the end which means this is a subclass
         // and therefore QualifiedAttributeValue should return false.
 
-        MBeanServerDelegate.class.getName() + "#SpecificationName LIKE '%'",
+        MBeanServerDelegate.class.getName() + "#SpecificationName LIKE '*'",
         new Wrapped(new MBeanServerDelegate(), true),
         new Tester(new String[] {"SpecificationName"}, new Object[] {"JMX"}, false),
 
@@ -497,7 +497,7 @@
         "A.class.name = 'java.lang.String'",
         expectTrue("blim"), expectFalse(95), expectFalse((Object) null),
 
-        "A.canonicalName like 'JMImpl%:%'",
+        "A.canonicalName like 'JMImpl*:*'",
         expectTrue(MBeanServerDelegate.DELEGATE_NAME),
         expectFalse(ObjectName.WILDCARD),
 
@@ -544,12 +544,15 @@
         "a in b, c", "a in 23", "a in (2, 3", "a in (2, 3x)",
         "a like \"foo\"", "a like b", "a like 23",
         "like \"foo\"", "like b", "like 23", "like 'a:b'",
-        "5 like 'a'", "'a' like '%'",
+        "5 like 'a'", "'a' like '*'",
         "a not= b", "a not = b", "a not b", "a not b c",
         "a = +b", "a = +'b'", "a = +true", "a = -b", "a = -'b'",
         "a#5 = b", "a#'b' = c",
         "a instanceof b", "a instanceof 17", "a instanceof",
-        "a like 'oops\\'", "a like '[oops'",
+        // "a like 'oops\\'", "a like '[oops'",
+        // We don't check the above because Query.match doesn't.  If LIKE
+        // rejected bad patterns then there would be some QueryExp values
+        // that could not be converted to a string and back.
 
         // Check that -Long.MIN_VALUE is an illegal constant.  This is one more
         // than Long.MAX_VALUE and, like the Java language, we only allow it