Sun WBEM SDK Developer's Guide

Handling WBEM Query Language Queries

WBEM clients use the execQuery method in the CIMClient class to search for instances that match a set of search criteria. The CIM Object Manager handles client queries for CIM data stored in the CIM Object Manager Repository and it passes to providers queries for CIM data that is served by a particular provider.

All instance providers must imlement the execQuery interface in the com.sun.wbem.provider20 package to handle client queries for the dynamic data they provide. Providers can use the classes and methods in the com.sun.wbem.query package to filter WBEM Query Language (WQL) query strings. Providers with access to an entity that handles indexing can pass the query string to that entity for parsing.

Using the Query APIs to Parse Query Strings

The classes and methods in the com.sun.wbem.query package represent a WBEM Query Language parser and the WQL string to be parsed. The package includes classes that represent clauses within the query string and methods for manipulating the strings within those clauses.

Currently, the only type of WQL expression that can be parsed is the SELECT expression. A SELECT expression contains the following parts:

The WBEM Query Language Expression

The following figure shows the WBEM classes that represent the clauses in a WQL expression.

Figure 5–1 WBEM Classes that Represent the WBEM Query Language Expression

Graphic

WBEM Query Lanuage 

WBEM Query Class 

SELECT attribute_expression

SelectList

FROM table_attribute

FromExp

WHERE conditional_expression

QueryExp

WQL has been adapted to query data that is stored using the CIM data model. In the CIM model, information about objects is stored in CIM classes and CIM instances. CIM instances can contain properties, which have a name, data type, and value. WQL maps the CIM object model to SQL tables, as shown in the following table:

SQL 

WQL 

Table 

CIM class 

Row 

CIM instance 

Column 

CIM property 

In CIM, a WQL expression could be expressed in the following form:


SELECT FROM WHERE CIM property CIM class propertyA = 40

A more realistic example of a WQL expression follows:



SELECT * FROM Solaris_FileSystem WHERE (Name="home" OR Name="files") AND AvailableSpace > 2000000

The SELECT Statement

The SelectExp class represents the SELECT statement.

The SELECT statement is the SQL statement for retrieving information, with a few restrictions and extensions specific to WQL. Although the SQL SELECT statement is typically used in the database environment to retrieve particular columns from tables, the WQL SELECT statement is used to retrieve instances of a single class. WQL does not support queries across multiple classes.

The SELECT expression identifies the search list. The SELECT statement can take one of the following forms:

SELECT Statement 

Selects 

SELECT *

All instances of the specified class and any of its subclasses. 

SELECT attr_exp, attr_exp...attr_exp

Only instances of the specified class and any of its subclasses that contain the specifies identifiers.  

The FROM Clause

The FROM clause is represented by the abstract class, fromExp. Currently NonJoinExp is the only direct subclass of fromExp. The NonJoinExp represents FROM clauses with only one table (CIM class) to which the select operation should be applied.

The FROM clause identifies the class in which to search for instances that match the query string. In SQL terms, the FROM clause identifies a qualified attribute expression, which is the name of a class to search. A qualified attribute expression identifies the table and class. We currently support only non-join expressions, which means that a valid WQL FROM clause includes only a single class.

The WHERE Clause

The QueryExp class is an abstract class whose subclasses represent conditional expressions which return a boolean value when a particular CIMInstance is applied to them.

The WHERE clause narrows the scope of a query. The WHERE clause contains a conditional expression, which can contain a property or key word, an operator, and a constant. All WHERE clauses must specify one of the predefined WQL operators.

The basic syntax for a WHERE clause appended to a SELECT statement follows:

SELECT FROM WHERE CIM instance CIM class conditional_expression

The conditional expression in a WHERE clause takes the following form:

 
property operator constant

The following subclasses of the QueryExp class manipulate particular types of conditional expressions in the WHERE clause:

The conditional expression in the WHERE clause is represented by the QueryExp class. A conditional expression is represented by a tree structure. For example, the conditional expression (a=2 and b=3 or c=4) is represented by the tree structure shown in the following figure:

The QueryExp class returns only the top level of the query expression tree. In the above example, an OR QueryExp. The provider can then use methods within that class to get branches down the query expression tree.

Using the Canonize Methods

The following methods are useful for providers that pass the WQL query string to another entity that parses the string:

Writing a Provider that Parses WQL Query Strings

The general procedure for writing a provider that parses WQL queries using the Query APIs follows.

How to Write A Provider that Parses WQL Query Strings
  1. Initialize the WQL parser, for example:


     
        /* Read query string passed to execQuery from the CIM Object 
           Manager into an input data stream. */
        ByteArrayInputStream in = new ByteArrayInputStream(query.getBytes()); 
    
        /* Initialize the parser with the input data stream. */
        WQLParser parser = new WQLParser(in);
           

  2. Create a vector to store the result of the query. For example:


     
        Vector result = new Vector();

  3. Get the select expression from the query. For example:


     
        /* querySpecification returns the WQL expression from the parser.
          (SelectExp)parser casts the WQL expression to a select expression. */
        SelectExp q = (SelectExp)parser.querySpecification();  

  4. Get the select list from the select expression. For example:


     
        /* Use the SelectList method in the SelectExp class
           to return the select list. The select list is the list 
           of attributes, or CIM properties. */
        SelectList attrs = q.getSelectList();     

  5. Get the From clause. For example:


     
        /* Use the getFromClause method in the SelectExp class 
           to return the From clause. Cast the From clause to a 
           Non Join Expression, a table that represents a single 
           CIM class. */
        NonJoinExp from = (NonJoinExp)q.getFromClause();

  6. Use the enumInstances method to return a deep enumeration of the class. For example:


     
       /* Returns all instances, including inherited and local properties, 
          belonging to the specified class (cc). */
        Vector v = new Vector();
        v = enumInstances(op, true, cc, true);
        ...  

  7. Iterate through the instances in the enumeration, matching the query expression and select list to each instance. For example:


     
      /* Test whether the query expression in the WHERE 
    	    clause matches the CIM instance. Apply the select 
         list to the CIM instance and add any instance that 
         matches the select list (list of CIM properties) 
         to the result. */
      for (int i = 0; i < v.size(); i++) {
    	  if ((where == null) || // If there is a WHERE clause
      	    (where.apply((CIMInstance)v.elementAt(i)) == true)) { 
    	         result.addElement(attrs.apply((CIMInstance)v.elementAt(i)));
       ...        

  8. Return the query result. For example:

    return result;

Example — Implementing the execQuery Method

The sample program in Example 5–6 uses the Query APIs to parse the WQL string passed to it by the execQuerymethod. This program parses the Select Expression in the query string, does a deep enumeration of the class, and iterates through the instances in the enumeration, matching the query expression and select list to each instance. Finally, the program returns a vector containing the enumeration of the instances that match the query string.


Example 5–6 Provider that Implements the execQuery Method

/*
     * The execQuery method will support only limited queries 
     * based upon partial key matching. An empty Vector is 
     * returned if no entries are selected by the query.
     *
     * @param	op			The CIM object path of the CIM instance to be returned
     * @param	query	The CIM query expression
     * @param	ql			The CIM query language indicator
     * @param	cc			The CIM class reference
     *
     * @return	A vector of CIM object instances
     *
     * @version    1.19	01/26/00
     * @author	   Sun Microsystems, Inc.
     */
    public Vector execQuery(CIMObjectPath op, 
			    String query, 
			    int ql,
			    CIMClass cc) 
	    throws CIMException {

	ByteArrayInputStream in = new ByteArrayInputStream(query.getBytes());
	WQLParser parser = new WQLParser(in);
	Vector result = new Vector();
	try {
	    SelectExp q = (SelectExp)parser.querySpecification();
	    SelectList attrs = q.getSelectList();
	    NonJoinExp from = (NonJoinExp)q.getFromClause();
	    QueryExp where = q.getWhereClause();

	    Vector v = new Vector();
	    v = enumInstances(op, false, cc, true);

	    // filtering the instances
	    for (int i = 0; i < v.size(); i++) {
		    if ((where == null) || (where.apply((CIMInstance)v.elementAt(i)) == true)) {
		        result.addElement(attrs.apply((CIMInstance)v.elementAt(i)));
		     } 
	    }
	} catch (Exception e) {
	    throw new CIMException(CIMException.CIM_ERR_FAILED, e.toString());
	}
	return result;
    } // execQuery
}