jdk/src/share/classes/javax/management/Query.java
changeset 4156 acaa49a2768a
parent 715 f16baef3a20e
child 5506 202f599c92aa
equal deleted inserted replaced
4155:460e37d40f12 4156:acaa49a2768a
    38  * true when querying a remote MBean Server: a custom implementation of the
    38  * true when querying a remote MBean Server: a custom implementation of the
    39  * {@code QueryExp} interface might not be present in the remote MBean Server,
    39  * {@code QueryExp} interface might not be present in the remote MBean Server,
    40  * but the methods in this class return only standard classes that are
    40  * but the methods in this class return only standard classes that are
    41  * part of the JMX implementation.</p>
    41  * part of the JMX implementation.</p>
    42  *
    42  *
    43  * <p>There are two ways to create {@code QueryExp} objects using the methods
       
    44  * in this class.  The first is to build them by chaining together calls to
       
    45  * the various methods.  The second is to use the Query Language described
       
    46  * <a href="#ql">below</a> and produce the {@code QueryExp} by calling
       
    47  * {@link #fromString Query.fromString}.  The two ways are equivalent:
       
    48  * every {@code QueryExp} returned by {@code fromString} can also be
       
    49  * constructed by chaining method calls.</p>
       
    50  *
       
    51  * <p>As an example, suppose you wanted to find all MBeans where the {@code
    43  * <p>As an example, suppose you wanted to find all MBeans where the {@code
    52  * Enabled} attribute is {@code true} and the {@code Owner} attribute is {@code
    44  * Enabled} attribute is {@code true} and the {@code Owner} attribute is {@code
    53  * "Duke"}. Here is how you could construct the appropriate {@code QueryExp} by
    45  * "Duke"}. Here is how you could construct the appropriate {@code QueryExp} by
    54  * chaining together method calls:</p>
    46  * chaining together method calls:</p>
    55  *
    47  *
    56  * <pre>
    48  * <pre>
    57  * QueryExp query =
    49  * QueryExp query =
    58  *     Query.and(Query.eq(Query.attr("Enabled"), Query.value(true)),
    50  *     Query.and(Query.eq(Query.attr("Enabled"), Query.value(true)),
    59  *               Query.eq(Query.attr("Owner"), Query.value("Duke")));
    51  *               Query.eq(Query.attr("Owner"), Query.value("Duke")));
    60  * </pre>
    52  * </pre>
    61  *
       
    62  * <p>Here is how you could construct the same {@code QueryExp} using the
       
    63  * Query Language:</p>
       
    64  *
       
    65  * <pre>
       
    66  * QueryExp query = Query.fromString("Enabled = true and Owner = 'Duke'");
       
    67  * </pre>
       
    68  *
       
    69  * <p>The principal advantage of the method-chaining approach is that the
       
    70  * compiler will check that the query makes sense.  The principal advantage
       
    71  * of the Query Language approach is that it is easier to write and especially
       
    72  * read.</p>
       
    73  *
       
    74  *
       
    75  * <h4 id="ql">Query Language</h4>
       
    76  *
       
    77  * <p>The query language is closely modeled on the WHERE clause of
       
    78  * SQL SELECT statements. The formal specification of the language
       
    79  * appears <a href="#formal-ql">below</a>, but it is probably easier to
       
    80  * understand it with examples such as the following.</p>
       
    81  *
       
    82  * <dl>
       
    83  * <dt>{@code Message = 'OK'}
       
    84  * <dd>Selects MBeans that have a {@code Message} attribute whose value
       
    85  *     is the string {@code OK}.
       
    86  *
       
    87  * <dt>{@code FreeSpacePercent < 10}
       
    88  * <dd>Selects MBeans that have a {@code FreeSpacePercent} attribute whose
       
    89  *     value is a number less than 10.
       
    90  *
       
    91  * <dt>{@code FreeSpacePercent < 10 and WarningSent = false}
       
    92  * <dd>Selects the same MBeans as the previous example, but they must
       
    93  *     also have a boolean attribute {@code WarningSent} whose value
       
    94  *     is false.
       
    95  *
       
    96  * <dt>{@code SpaceUsed > TotalSpace * (2.0 / 3.0)}
       
    97  * <dd>Selects MBeans that have {@code SpaceUsed} and {@code TotalSpace}
       
    98  *     attributes where the first is more than two-thirds the second.
       
    99  *
       
   100  * <dt>{@code not (FreeSpacePercent between 10 and 90)}
       
   101  * <dd>Selects MBeans that have a {@code FreeSpacePercent} attribute whose
       
   102  *     value is not between 10 and 90, inclusive.
       
   103  *
       
   104  * <dt>{@code FreeSpacePercent not between 10 and 90}
       
   105  * <dd>Another way of writing the previous query.
       
   106  *
       
   107  * <dt>{@code Status in ('STOPPED', 'STARTING', 'STARTED')}
       
   108  * <dd>Selects MBeans that have a {@code Status} attribute whose value
       
   109  *     is one of those three strings.
       
   110  *
       
   111  * <dt>{@code Message like 'OK: *'}
       
   112  * <dd>Selects MBeans that have a {@code Message} attribute whose value
       
   113  *     is a string beginning with {@code "OK: "}.  <b>Notice that the
       
   114  *     wildcard characters are not the ones that SQL uses.</b>  In SQL,
       
   115  *     {@code %} means "any sequence of characters" and {@code _}
       
   116  *     means "any single character".  Here, as in the rest of the JMX API,
       
   117  *     those are represented by {@code *} and {@code ?} respectively.
       
   118  *
       
   119  * <dt>{@code instanceof 'javax.management.NotificationBroadcaster'}
       
   120  * <dd>Selects MBeans that are instances of
       
   121  *     {@link javax.management.NotificationBroadcaster}, as reported by
       
   122  *     {@link javax.management.MBeanServer#isInstanceOf MBeanServer.isInstanceOf}.
       
   123  *
       
   124  * <dt>{@code like 'mydomain:*'}
       
   125  * <dd>Selects MBeans whose {@link ObjectName}s have the domain {@code mydomain}.
       
   126  *
       
   127  * </dl>
       
   128  *
       
   129  * <p>The last two examples do not correspond to valid SQL syntax, but all
       
   130  * the others do.</p>
       
   131  *
       
   132  * <p>The remainder of this description is a formal specification of the
       
   133  * query language.</p>
       
   134  *
       
   135  *
       
   136  * <h4 id="formal-ql">Lexical elements</h4>
       
   137  *
       
   138  * <p>Keywords such as <b>and</b>, <b>like</b>, and <b>between</b> are not
       
   139  * case sensitive.  You can write <b>between</b>, <b>BETWEEN</b>, or
       
   140  * <b>BeTwEeN</b> with the same effect.</p>
       
   141  *
       
   142  * <p>On the other hand, attribute names <i>are</i> case sensitive.  The
       
   143  * attribute {@code Name} is not the same as the attribute {@code name}.</p>
       
   144  *
       
   145  * <p>To access an attribute whose name, ignoring case, is the same as one of
       
   146  * the keywords {@code not}, {@code instanceof}, {@code like}, {@code true},
       
   147  * or {@code false}, you can use double quotes, for example {@code "not"}.
       
   148  * Double quotes can also be used to include non-identifier characters in
       
   149  * the name of an attribute, for example {@code "attribute-name-with-hyphens"}.
       
   150  * To include the double quote character in the attribute name, write it
       
   151  * twice.  {@code "foo""bar""baz"} represents the attribute called
       
   152  * {@code foo"bar"baz}.
       
   153  *
       
   154  * <p>String constants are written with single quotes like {@code 'this'}.  A
       
   155  * single quote within a string constant must be doubled, for example
       
   156  * {@code 'can''t'}.</p>
       
   157  *
       
   158  * <p>Integer constants are written as a sequence of decimal digits,
       
   159  * optionally preceded by a plus or minus sign.  An integer constant must be
       
   160  * a valid input to {@link Long#valueOf(String)}.</p>
       
   161  *
       
   162  * <p>Floating-point constants are written using the Java syntax.  A
       
   163  * floating-point constant must be a valid input to
       
   164  * {@link Double#valueOf(String)}.</p>
       
   165  *
       
   166  * <p>A boolean constant is either {@code true} or {@code false}, ignoring
       
   167  * case.</p>
       
   168  *
       
   169  * <p>Spaces cannot appear inside identifiers (unless written with double
       
   170  * quotes) or keywords or multi-character tokens such as {@code <=}. Spaces can
       
   171  * appear anywhere else, but are not required except to separate tokens. For
       
   172  * example, the query {@code a < b and 5 = c} could also be written {@code a<b
       
   173  * and 5=c}, but no further spaces can be removed.</p>
       
   174  *
       
   175  *
       
   176  * <h4 id="grammar-ql">Grammar</h4>
       
   177  *
       
   178  * <dl>
       
   179  * <dt id="query">query:
       
   180  * <dd><a href="#andquery">andquery</a> [<b>OR</b> <a href="#query">query</a>]
       
   181  *
       
   182  * <dt id="andquery">andquery:
       
   183  * <dd><a href="#predicate">predicate</a> [<b>AND</b> <a href="#andquery">andquery</a>]
       
   184  *
       
   185  * <dt id="predicate">predicate:
       
   186  * <dd><b>(</b> <a href="#query">query</a> <b>)</b> |<br>
       
   187  *     <b>NOT</b> <a href="#predicate">predicate</a> |<br>
       
   188  *     <b>INSTANCEOF</b> <a href="#stringvalue">stringvalue</a> |<br>
       
   189  *     <b>LIKE</b> <a href="#objectnamepattern">objectnamepattern</a> |<br>
       
   190  *     <a href="#value">value</a> <a href="#predrhs">predrhs</a>
       
   191  *
       
   192  * <dt id="predrhs">predrhs:
       
   193  * <dd><a href="#compare">compare</a> <a href="#value">value</a> |<br>
       
   194  *     [<b>NOT</b>] <b>BETWEEN</b> <a href="#value">value</a> <b>AND</b>
       
   195  *         <a href="#value">value</a> |<br>
       
   196  *     [<b>NOT</b>] <b>IN (</b> <a href="#value">value</a>
       
   197  *           <a href="#commavalues">commavalues</a> <b>)</b> |<br>
       
   198  *     [<b>NOT</b>] <b>LIKE</b> <a href="#stringvalue">stringvalue</a>
       
   199  *
       
   200  * <dt id="commavalues">commavalues:
       
   201  * <dd>[ <b>,</b> <a href="#value">value</a> <a href="#commavalues">commavalues</a> ]
       
   202  *
       
   203  * <dt id="compare">compare:
       
   204  * <dd><b>=</b> | <b>&lt;</b> | <b>&gt;</b> |
       
   205  *     <b>&lt;=</b> | <b>&gt;=</b> | <b>&lt;&gt;</b> | <b>!=</b>
       
   206  *
       
   207  * <dt id="value">value:
       
   208  * <dd><a href="#factor">factor</a> [<a href="#plusorminus">plusorminus</a>
       
   209  *     <a href="#value">value</a>]
       
   210  *
       
   211  * <dt id="plusorminus">plusorminus:
       
   212  * <dd><b>+</b> | <b>-</b>
       
   213  *
       
   214  * <dt id="factor">factor:
       
   215  * <dd><a href="#term">term</a> [<a href="#timesordivide">timesordivide</a>
       
   216  *     <a href="#factor">factor</a>]
       
   217  *
       
   218  * <dt id="timesordivide">timesordivide:
       
   219  * <dd><b>*</b> | <b>/</b>
       
   220  *
       
   221  * <dt id="term">term:
       
   222  * <dd><a href="#attr">attr</a> | <a href="#literal">literal</a> |
       
   223  *     <b>(</b> <a href="#value">value</a> <b>)</b>
       
   224  *
       
   225  * <dt id="attr">attr:
       
   226  * <dd><a href="#name">name</a> [<b>#</b> <a href="#name">name</a>]
       
   227  *
       
   228  * <dt id="name">name:
       
   229  * <dd><a href="#identifier">identifier</a> [<b>.</b><a href="#name">name</a>]
       
   230  *
       
   231  * <dt id="identifier">identifier:
       
   232  * <dd><i>Java-identifier</i> | <i>double-quoted-identifier</i>
       
   233  *
       
   234  * <dt id="literal">literal:
       
   235  * <dd><a href="#booleanlit">booleanlit</a> | <i>longlit</i> |
       
   236  *     <i>doublelit</i> | <i>stringlit</i>
       
   237  *
       
   238  * <dt id="booleanlit">booleanlit:
       
   239  * <dd><b>FALSE</b> | <b>TRUE</b>
       
   240  *
       
   241  * <dt id="stringvalue">stringvalue:
       
   242  * <dd><i>stringlit</i>
       
   243  *
       
   244  * <dt id="objectnamepattern">objectnamepattern:
       
   245  * <dd><i>stringlit</i>
       
   246  *
       
   247  * </dl>
       
   248  *
       
   249  *
       
   250  * <h4>Semantics</h4>
       
   251  *
       
   252  * <p>The meaning of the grammar is described in the table below.
       
   253  * This defines a function <i>q</i> that maps a string to a Java object
       
   254  * such as a {@link QueryExp} or a {@link ValueExp}.</p>
       
   255  *
       
   256  * <table border="1" cellpadding="5">
       
   257  * <tr><th>String <i>s</i></th><th><i>q(s)</th></tr>
       
   258  *
       
   259  * <tr><td><i>query1</i> <b>OR</b> <i>query2</i>
       
   260  *     <td>{@link Query#or Query.or}(<i>q(query1)</i>, <i>q(query2)</i>)
       
   261  *
       
   262  * <tr><td><i>query1</i> <b>AND</b> <i>query2</i>
       
   263  *     <td>{@link Query#and Query.and}(<i>q(query1)</i>, <i>q(query2)</i>)
       
   264  *
       
   265  * <tr><td><b>(</b> <i>queryOrValue</i> <b>)</b>
       
   266  *     <td><i>q(queryOrValue)</i>
       
   267  *
       
   268  * <tr><td><b>NOT</b> <i>query</i>
       
   269  *     <td>{@link Query#not Query.not}(<i>q(query)</i>)
       
   270  *
       
   271  * <tr><td><b>INSTANCEOF</b> <i>stringLiteral</i>
       
   272  *     <td>{@link Query#isInstanceOf Query.isInstanceOf}(<!--
       
   273  * -->{@link Query#value(String) Query.value}(<i>q(stringLiteral)</i>))
       
   274  *
       
   275  * <tr><td><b>LIKE</b> <i>stringLiteral</i>
       
   276  *     <td>{@link ObjectName#ObjectName(String) new ObjectName}(<!--
       
   277  * --><i>q(stringLiteral)</i>)
       
   278  *
       
   279  * <tr><td><i>value1</i> <b>=</b> <i>value2</i>
       
   280  *     <td>{@link Query#eq Query.eq}(<i>q(value1)</i>, <i>q(value2)</i>)
       
   281  *
       
   282  * <tr><td><i>value1</i> <b>&lt;</b> <i>value2</i>
       
   283  *     <td>{@link Query#lt Query.lt}(<i>q(value1)</i>, <i>q(value2)</i>)
       
   284  *
       
   285  * <tr><td><i>value1</i> <b>&gt;</b> <i>value2</i>
       
   286  *     <td>{@link Query#gt Query.gt}(<i>q(value1)</i>, <i>q(value2)</i>)
       
   287  *
       
   288  * <tr><td><i>value1</i> <b>&lt;=</b> <i>value2</i>
       
   289  *     <td>{@link Query#leq Query.leq}(<i>q(value1)</i>, <i>q(value2)</i>)
       
   290  *
       
   291  * <tr><td><i>value1</i> <b>&gt;=</b> <i>value2</i>
       
   292  *     <td>{@link Query#geq Query.geq}(<i>q(value1)</i>, <i>q(value2)</i>)
       
   293  *
       
   294  * <tr><td><i>value1</i> <b>&lt;&gt;</b> <i>value2</i>
       
   295  *     <td>{@link Query#not Query.not}({@link Query#eq Query.eq}(<!--
       
   296  * --><i>q(value1)</i>, <i>q(value2)</i>))
       
   297  *
       
   298  * <tr><td><i>value1</i> <b>!=</b> <i>value2</i>
       
   299  *     <td>{@link Query#not Query.not}({@link Query#eq Query.eq}(<!--
       
   300  * --><i>q(value1)</i>, <i>q(value2)</i>))
       
   301  *
       
   302  * <tr><td><i>value1</i> <b>BETWEEN</b> <i>value2</i> AND <i>value3</i>
       
   303  *     <td>{@link Query#between Query.between}(<i>q(value1)</i>,
       
   304  *         <i>q(value2)</i>, <i>q(value3)</i>)
       
   305  *
       
   306  * <tr><td><i>value1</i> <b>NOT BETWEEN</b> <i>value2</i> AND <i>value3</i>
       
   307  *     <td>{@link Query#not Query.not}({@link Query#between Query.between}(<!--
       
   308  * --><i>q(value1)</i>, <i>q(value2)</i>, <i>q(value3)</i>))
       
   309  *
       
   310  * <tr><td><i>value1</i> <b>IN (</b> <i>value2</i>, <i>value3</i> <b>)</b>
       
   311  *     <td>{@link Query#in Query.in}(<i>q(value1)</i>,
       
   312  *         <code>new ValueExp[] {</code>
       
   313  *         <i>q(value2)</i>, <i>q(value3)</i><code>}</code>)
       
   314  *
       
   315  * <tr><td><i>value1</i> <b>NOT IN (</b> <i>value2</i>, <i>value3</i> <b>)</b>
       
   316  *     <td>{@link Query#not Query.not}({@link Query#in Query.in}(<i>q(value1)</i>,
       
   317  *         <code>new ValueExp[] {</code>
       
   318  *         <i>q(value2)</i>, <i>q(value3)</i><code>}</code>))
       
   319  *
       
   320  * <tr><td><i>value</i> <b>LIKE</b> <i>stringLiteral</i>
       
   321  *     <td>{@link Query#match Query.match}(<i>q(value)</i>,
       
   322  *         <i>q(stringLiteral)</i>)
       
   323  *
       
   324  * <tr><td><i>value</i> <b>NOT LIKE</b> <i>stringLiteral</i>
       
   325  *     <td>{@link Query#not Query.not}({@link Query#match Query.match}(<i>q(value)</i>,
       
   326  *         <i>q(stringLiteral)</i>))
       
   327  *
       
   328  * <tr><td><i>value1</i> <b>+</b> <i>value2</i>
       
   329  *     <td>{@link Query#plus Query.plus}(<i>q(value1)</i>, <i>q(value2)</i>)
       
   330  *
       
   331  * <tr><td><i>value1</i> <b>-</b> <i>value2</i>
       
   332  *     <td>{@link Query#minus Query.minus}(<i>q(value1)</i>, <i>q(value2)</i>)
       
   333  *
       
   334  * <tr><td><i>value1</i> <b>*</b> <i>value2</i>
       
   335  *     <td>{@link Query#times Query.times}(<i>q(value1)</i>, <i>q(value2)</i>)
       
   336  *
       
   337  * <tr><td><i>value1</i> <b>/</b> <i>value2</i>
       
   338  *     <td>{@link Query#div Query.div}(<i>q(value1)</i>, <i>q(value2)</i>)
       
   339  *
       
   340  * <tr><td><i>name</i>
       
   341  *     <td>{@link Query#attr(String) Query.attr}(<i>q(name)</i>)
       
   342  *
       
   343  * <tr><td><i>name1<b>#</b>name2</i>
       
   344  *     <td>{@link Query#attr(String,String) Query.attr}(<i>q(name1)</i>,
       
   345  *         <i>q(name2)</i>)
       
   346  *
       
   347  * <tr><td><b>FALSE</b>
       
   348  *     <td>{@link Query#value(boolean) Query.value}(false)
       
   349  *
       
   350  * <tr><td><b>TRUE</b>
       
   351  *     <td>{@link Query#value(boolean) Query.value}(true)
       
   352  *
       
   353  * <tr><td><i>decimalLiteral</i>
       
   354  *     <td>{@link Query#value(long) Query.value}(<!--
       
   355  * -->{@link Long#valueOf(String) Long.valueOf}(<i>decimalLiteral</i>))
       
   356  *
       
   357  * <tr><td><i>floatingPointLiteral</i>
       
   358  *     <td>{@link Query#value(double) Query.value}(<!--
       
   359  * -->{@link Double#valueOf(String) Double.valueOf}(<!--
       
   360  * --><i>floatingPointLiteral</i>))
       
   361  * </table>
       
   362  *
    53  *
   363  * @since 1.5
    54  * @since 1.5
   364  */
    55  */
   365  public class Query extends Object   {
    56  public class Query extends Object   {
   366 
    57 
   598 
   289 
   599      /**
   290      /**
   600       * <p>Returns a new attribute expression.  See {@link AttributeValueExp}
   291       * <p>Returns a new attribute expression.  See {@link AttributeValueExp}
   601       * for a detailed description of the semantics of the expression.</p>
   292       * for a detailed description of the semantics of the expression.</p>
   602       *
   293       *
       
   294       * <p>Evaluating this expression for a given
       
   295       * <code>objectName</code> includes performing {@link
       
   296       * MBeanServer#getAttribute MBeanServer.getAttribute(objectName,
       
   297       * name)}.</p>
       
   298       *
   603       * @param name The name of the attribute.
   299       * @param name The name of the attribute.
   604       *
   300       *
   605       * @return An attribute expression for the attribute named {@code name}.
   301       * @return An attribute expression for the attribute named {@code name}.
   606       */
   302       */
   607      public static AttributeValueExp attr(String name)  {
   303      public static AttributeValueExp attr(String name)  {
   942      public static QueryExp isInstanceOf(StringValueExp classNameValue) {
   638      public static QueryExp isInstanceOf(StringValueExp classNameValue) {
   943         return new InstanceOfQueryExp(classNameValue);
   639         return new InstanceOfQueryExp(classNameValue);
   944      }
   640      }
   945 
   641 
   946      /**
   642      /**
   947       * <p>Return a string representation of the given query.  The string
       
   948       * returned by this method can be converted back into an equivalent
       
   949       * query using {@link #fromString fromString}.</p>
       
   950       *
       
   951       * <p>(Two queries are equivalent if they produce the same result in
       
   952       * all cases.  Equivalent queries are not necessarily identical:
       
   953       * for example the queries {@code Query.lt(Query.attr("A"), Query.attr("B"))}
       
   954       * and {@code Query.not(Query.ge(Query.attr("A"), Query.attr("B")))} are
       
   955       * equivalent but not identical.)</p>
       
   956       *
       
   957       * <p>The string returned by this method is only guaranteed to be converted
       
   958       * back into an equivalent query if {@code query} was constructed, or
       
   959       * could have been constructed, using the methods of this class.
       
   960       * If you make a custom query {@code myQuery} by implementing
       
   961       * {@link QueryExp} yourself then the result of
       
   962       * {@code Query.toString(myQuery)} is unspecified.</p>
       
   963       *
       
   964       * @param query the query to convert.  If it is null, the result will
       
   965       * also be null.
       
   966       * @return the string representation of the query, or null if the
       
   967       * query is null.
       
   968       *
       
   969       * @since 1.7
       
   970       */
       
   971      public static String toString(QueryExp query) {
       
   972          if (query == null)
       
   973              return null;
       
   974 
       
   975          // This is ugly. At one stage we had a non-public class called
       
   976          // ToQueryString with the toQueryString() method, and every class
       
   977          // mentioned here inherited from that class. But that interfered
       
   978          // with serialization of custom subclasses of e.g. QueryEval. Even
       
   979          // though we could make it work by adding a public constructor to this
       
   980          // non-public class, that seemed fragile because according to the
       
   981          // serialization spec it shouldn't work. If only non-public interfaces
       
   982          // could have non-public methods.
       
   983          if (query instanceof ObjectName)
       
   984              return ((ObjectName) query).toQueryString();
       
   985          if (query instanceof QueryEval)
       
   986              return ((QueryEval) query).toQueryString();
       
   987 
       
   988          return query.toString();
       
   989      }
       
   990 
       
   991      /**
       
   992       * <p>Produce a query from the given string.  The query returned
       
   993       * by this method can be converted back into a string using
       
   994       * {@link #toString(QueryExp) toString}.  The resultant string will
       
   995       * not necessarily be equal to {@code s}.</p>
       
   996       *
       
   997       * @param s the string to convert.
       
   998       *
       
   999       * @return a {@code QueryExp} derived by parsing the string, or
       
  1000       * null if the string is null.
       
  1001       *
       
  1002       * @throws IllegalArgumentException if the string is not a valid
       
  1003       * query string.
       
  1004       *
       
  1005       * @since 1.7
       
  1006       */
       
  1007      public static QueryExp fromString(String s) {
       
  1008          if (s == null)
       
  1009              return null;
       
  1010          return new QueryParser(s).parseQuery();
       
  1011      }
       
  1012 
       
  1013      /**
       
  1014       * Utility method to escape strings used with
   643       * Utility method to escape strings used with
  1015       * Query.{initial|any|final}SubString() methods.
   644       * Query.{initial|any|final}SubString() methods.
  1016       */
   645       */
  1017      private static String escapeString(String s) {
   646      private static String escapeString(String s) {
  1018          if (s == null)
   647          if (s == null)