Sun WBEM SDK Developer's Guide

Chapter 5 Writing a Provider Program

This chapter describes how to write a provider, including the following topics:

For detailed information on the provider APIs, see the Javadoc reference pages.

About Providers

Providers are classes that communicate with managed resources to access data. Providers forward this information to the CIM Object Manager for integration and interpretation. When the CIM Object Manager receives a request from a management application for data that is not available from the CIM Object Manager Repository, it forwards the request to a provider.

Object providers must be installed on the same machine as the CIM Object Manager. The CIM Object Manager uses object provider application programming interfaces (APIs) to communicate with locally installed providers.

When an application requests dynamic data from the CIM Object Manager, the CIM Object Manager uses the provider interfaces to pass the request to the provider.

Providers perform the following functions in response to a request from the CIM Object Manager:

Types of Providers

Providers are categorized according to the types of requests they service. The Sun WBEM SDK supports four types of providers:

A single provider can support instances, properties, methods, and associations, which can be convenient.

Most providers are pull providers, which means they maintain their own data, generating it dynamically when necessary. Pull providers have minimal interaction with the CIM Object Manager and the CIM Repository. The data managed by a pull provider typically changes frequently, requiring the provider to either generate the data dynamically or retrieve it from a local cache whenever an application issues a request. A provider can also contact the CIM Object Manager.

A single provider can act simultaneously as a class, instance, and method provider by proper registration and implementation of all relevant methods.

Implementing a Provider Interface

Providers implement a provider interface that supports the type of service specific to their role. In order to implement the interface, a provider class must first declare the interface in an implements clause, and then it must provide an implementation (a body) for all of the abstract methods of the interface.

The CIM Object Manager communicates with providers using the initialize method. The initialize method takes an argument of type CIMOMhandle, which is a reference to the CIM Object Manager. The CIMOMhandle class contains methods that providers can use to transfer data to and from the CIM Object Manager.

The following table describes the provider interfaces in the com.sun.wbem.provider package. Use the InstanceProvider interface in the com.sun.wbem.provider20 package. You can include a method provider, instance provider, and property provider in a single Java class file, or store each provider in a separate file.

Table 5–1 Provider Interfaces

Interface 

Description 

CIMProvider

Base interface implemented by all providers. 

InstanceProvider

Base interface implemented by instance providers. Instance providers serve dynamic instances of classes. 

MethodProvider

Base interface implemented by method providers, which implement all methods of CIM classes. 

PropertyProvider

Base interface implemented by property providers, which are used to retrieve and update dynamic properties. Dynamic data is not stored in the CIM Object Manager Repository. 

AssociatorProvider

Base interface implemented by providers of instances of dynamic associations. 

Authorizable

Marker interface indicates to the CIM Object Manager that the provider handles its own authorization checking. 

The Instance Provider Interface (InstanceProvider)

The following table describes the methods in the instance provider interface in the Provider package (com.sun.wbem.provider20).

These methods each take the op argument, the CIMObjectPath of the specified CIM class or CIM instance. The object path includes the namespace, class name, and keys (if the object is an instance). The namespace is a directory that can contain other namespaces, classes, instances, and qualifier types. A key is a property that uniquely identifies an instance of a class. Key properties have a KEY qualifier.

For example, the following object path has two parts:

\\myserver\root\cimv2\Solaris_ComputerSystem:Name=mycomputer:   CreationClassName=Solaris_ComputerSystem

Table 5–2 InstanceProvider Interface Methods

Method 

Description 

CIMObjectPath createInstance(CIMObjectPath op, CIMInstance ci)

Creates the instance cispecified by op, if it does not exist. If the CIM instance already exists, the provider should throw CIMInstanceException with ID CIM_ERR_ALREADY_EXISTS.Returns the CIMObjectPath of the created instance.

void deleteInstance(CIMObjectPath op)

Deletes the instance specified in the object path (op).

Vector enumInstances(CIMObjectPath path, boolean deep, CIMClass cc)

Returns the names of the instances for the class specified in path. If deepis true, returns the names of all instances of the specified class and all classes derived from the class. Otherwise, returns only the names of instances belonging to the specified class.

Providers that do not want to create instances from scratch can create a template for the new instance by calling the newInstance() method for the class to which the instance belongs (cc).

Vector enumInstances(CIMObjectPath path, boolean deep, CIMClass cc, boolean localOnly)

Returns the instances (the entire instance not just the name of the instance) for the class specified in path.

Providers that do not want to create instances from scratch can create a template for the new instance by calling the newInstance() method for the class to which the instance belongs (cc).

If localOnly is true, returns the local (non-inherited) properties in the enumerated instances. Otherwise, returns all inherited and local properties.

Vector execQuery (CIMObjectPath op, String query, int ql, CIMClass cc

Executes a query to retrieve CIM objects. This method returns a vector of CIM instances of the specified CIM class (cc)that match the specified query string.

CIMInstance getInstance(CIMObjectPath op, CIMClass cc, boolean localOnly)

Returns the instance specified in the object path (op).

Providers that do not want to create instances from scratch can create a template for the new instance by calling the newInstance() method for the class to which the instance belongs (cc).

If localOnly is true, only the local (non-inherited) properties are returned. Otherwise, returns all inherited and local properties.

void setInstance(CIMInstance ci)

Updates the specified CIM instance if it exists. If the instance does not exist, throws a CIMInstanceException with ID CIM_ERR_NOT_FOUND.

Example — Implementing an Instance Provider

The following example shows the Java source code for an instance provider, SimpleInstanceProvider, that implements the enumInstances and getInstance interfaces for the Ex_SimpleInstanceProvider class. For brevity, this example implements the deleteInstance, createInstance, setInstance, and execQuery interfaces by throwing a CIMException. In practice, an instance provider must implement all InstanceProvider interfaces.


Example 5–1 SimpleInstanceProvider Instance Provider

/*
 * "@(#)SimpleInstanceProvider.java"
 */
import com.sun.wbem.cim.*;
import com.sun.wbem.client.*;
import com.sun.wbem.provider.CIMProvider;
import com.sun.wbem.provider20.InstanceProvider;
import com.sun.wbem.provider.MethodProvider;
import java.util.*;
import java.io.*;

public class SimpleInstanceProvider implements InstanceProvider{
     static int loop = 0;
     public void initialize(CIMOMHandle cimom) throws CIMException {
     }
     public void cleanup() throws CIMException {
     }
     public Vector enumInstances(CIMObjectPath op, boolean deep, CIMClass cc,
            boolean localOnly) throws CIMException {
                return null;
     }
     /*
      * enumInstances:
      * The entire instances and not just the names are returned.
      * Deep or shallow enumeration is possible, however
      * currently the CIMOM only asks for shallow enumeration.
      */
     public Vector enumInstances(CIMObjectPath op, boolean deep, CIMClass cc)
             throws CIMException {
         if (op.getObjectName().equalsIgnoreCase("Ex_SimpleInstanceProvider")) 
             {
             Vector instances = new Vector();
             CIMObjectPath cop = new CIMObjectPath(op.getObjectName(),
                     op.getNameSpace());
                 if (loop == 0){
                     cop.addKey("First", new CIMValue("red"));
                     cop.addKey("Last", new CIMValue("apple"));
                     // To delete this class, comment this following 
	                    // line and compile it.
                     instances.addElement(cop);
                     loop += 1;
                 } else {
                     cop.addKey("First", new CIMValue("red"));
                     cop.addKey("Last", new CIMValue("apple"));
                     // To delete this class, comment this following 
                     // line and compile it.
                     instances.addElement(cop);
                     cop = new CIMObjectPath(op.getObjectName(),
                             op.getNameSpace());
                     cop.addKey("First", new CIMValue("green"));
                     cop.addKey("Last", new CIMValue("apple"));
                     // To delete this class, comment this following 
                     // line and compile it.
                     instances.addElement(cop);
                 }
             return instances;
             }
         return new Vector();
     }

     public CIMInstance getInstance(CIMObjectPath op, 
             CIMClass cc, boolean localOnly) throws CIMException {
             if (op.getObjectName().equalsIgnoreCase("Ex_SimpleInstanceProvider"))
             {
                 CIMInstance ci = cc.newInstance();
                 ci.setProperty("First", new CIMValue("yellow"));
                 ci.setProperty("Last", new CIMValue("apple"));
                 return ci;
             }
            return new CIMInstance();
      }

     public Vector execQuery(CIMObjectPath op, String query, int ql, CIMClass cc)
             throws CIMException {
                 throw(new CIMException(CIMException.CIM_ERR_NOT_SUPPORTED));
    }

     public void setInstance(CIMObjectPath op, CIMInstance ci)
             throws CIMException {
                 throw(new CIMException(CIMException.CIM_ERR_NOT_SUPPORTED));
    }

     public CIMObjectPath createInstance(CIMObjectPath op, CIMInstance ci)
              throws CIMException {
                 throw(new CIMException(CIMException.CIM_ERR_NOT_SUPPORTED));
    }

     public void deleteInstance(CIMObjectPath cp) throws CIMException {
         throw(new CIMException(CIMException.CIM_ERR_NOT_SUPPORTED));
     }
 }


The Property Provider Interface (PropertyProvider)

The following table describes the methods in the property provider interface.

Table 5–3 PropertyProvider Interface Methods

Method 

Description 

CIMValue getPropertyValue(CIMObjectPath op, String originClass, String propertyName)

Returns a CIMValue containing the value of the property specified by propertyName for the instance specified in op. The originClass contains the name of the class in the class hierarchy that originally defined this property.

void setPropertyValue(CIMObjectPath op, String originClass, String propertyName, CIMValue cv)

Sets the value of the property specified by propertyName for the instance specified in op to the CIMValue cv. The originClass contains the name of the class in the class hierarchy that originally defined this property.

Example — Implementing a Property Provider

The code segment in Example 5–2 creates a property provider (fruit_prop_provider) class that is registered in Example 5–2. The fruit_prop_provider implements the PropertyProvider interface.

This sample property provider illustrates the getPropertyValue method, which returns a property value for the specified class, parent class, and property name. A CIM property is defined by its name and origin class. Two or more properties can have the same name, but the origin class uniquely identifies the property.


Example 5–2 Implementing a Property Provider

...

public class SimplePropertyProvider implements PropertyProvider{
    public void initialize(CIMOMHandle cimom) 
    throws CIMException {
    }

    public void cleanup() 
    throws CIMException {
    }
    
    public CIMValue getPropertyValue(CIMObjectpath op, string originclass, 
	           string PropertyName){
		    if (PropertyName.equals("A")
		        return new CIMValue("ValueA")
  		  else
			      return new CIMValue("ValueB");
    }
    ...
}
 


The Method Provider Interface (MethodProvider)

The following table describes the method in the Method Provider interface.

Table 5–4 MethodProvider Interface Methods

Method 

Description 

CIMValue invokeMethod(CIMObjectPath op, String methodName, Vector inParams, Vector outParams)

The CIM Object Manager calls this method when methodName in the instance referred to by op is invoked..

inParams is a vector of CIMValues that are input parameters to the invoked method. outParams is a vector of CIMValues that are output parameters from the invoked method.

Example — Implementing a Method Provider

The code segment in Example 5–3 creates a Solaris provider class that routes requests to execute methods from the CIM Object Manager to one or more specialized providers. These specialized providers service requests for dynamic data for a particular type of Solaris object. For example, the Solaris_Package provider services requests to execute methods in the Solaris_Package class.

The method provider in this example implements a single method invokeMethod that calls the appropriate provider to perform one of following operations:


Example 5–3 Implementing a Method Provider

...
public class Solaris implements MethodProvider {
    public void initialize(CIMONHandle, ch) throws CIMException {
    }
    public void cleanup() throws CIMException {
    }
    public CIMValue invokeMethod(CIMObjectPath op, String methodName, 
            Vector inParams, Vector outParams) throws CIMException {
        if (op.getObjectName().equalsIgnoreCase("solaris_computersystem")) {
            Solaris_ComputerSystem sp = new Solaris_ComputerSystem();
            if (methodName.equalsIgnoreCase("reboot")) {
                return new CIMValue (sp.Reboot());
            }
        }
        if (op.getObjectName().equalsIgnoreCase("solaris_operatingsystem")) {
            Solaris_OperatingSystem sos = new Solaris_OperatingSystem();
            if (methodName.equalsIgnoreCase("reboot")) {
                return new CIMValue (sos.Reboot());
            }
            if (methodName.equalsIgnoreCase("shutdown")) {
                return new CIMValue (sos.Shutdown());
            }
        }
        if (op.getObjectName().equalsIgnoreCase("solaris_serialport")) {
            Solaris_SerialPort ser = new Solaris_SerialPort();
            if (methodName.equalsIgnoreCase("disableportservice")) {
                return new CIMValue (ser.DeletePort(op));
            }
        }
        return null;
    }
}
...
 


The Associator Provider Interface (AssociatorProvider)

The following table describes the methods in the AssociatorProvider interface. For detailed information about the arguments these methods take, see The Association Methods.

Table 5–5 AssociatorProvider Interface Methods

Method 

Description 

Vector associators(CIMObjectPath assocName, CIMObjectPath objectName, String role, String resultRole, boolean includeQualifiers, boolean includeClassOrigin, String[] propertyList)

Returns a vector of CIM instances that are associated to the instance specified by objectName.

Vector associatorNames(CIMObjectPath assocName, CIMObjectPath objectName, String role, String resultRole)

Returns a vector of the names of CIM instances that are associated to the CIM instance specified by objectName.

Vector references(CIMObjectPath assocName, CIMObjectPath objectName, String role, boolean includeQualifiers, boolean includeClassOrigin, String[] propertyList)

Returns a vector of associations in which the CIM instance specified by objectName participates.

Vector referenceNames(CIMObjectPath assocName, CIMObjectPath objectName, String role)

Returns a vector of the names of associations in which the CIM instance specified by objectName participates.

Example — Implementing an Association Provider

A complete association provider must implement all AssociatorProvider methods. For brevity, the code segment in the following example implements only the associators method. The CIM Object Manager passes values for assocName, objectName, role, resultRole, includeQualifiers, includeClassOrigin, and propertyList to the association provider.

Example 5–4 prints the name of a CIM association class and the CIM class or instance whose associated objects are to be returned. This provider handles instances of example_teacher and example_student classes.


Example 5–4 Implementing an Association Provider

public Vector associators(CIMObjectPath assocName,
        CIMObjectPath objectName, String role,
				 String resultRole, boolean includeQualifiers,
				 boolean includeClassOrigin, String propertyList[]) throws CIMException {
    System.out.println("Associators "+assocName+" "+objectName);
	   if (objectName.getObjectName()equalsIgnoreCase("example_teacher")) {
		     Vector v = new Vector();
		     if ((role != null)  &&
		         (!role.equalsIgnoreCase("teaches"))) {
		          // Teachers only play the teaches role.
		          return v;
		     }
		 // Get the associators of a teacher
		 CIMProperty nameProp = (CIMProperty)objectName.getKeys().elementAt(0);
		 String name = (String)nameProp.getValue().getValue();
		 // Get the student class
		 CIMObjectPath tempOp = new CIMObjectPath("example_student");
		 tempOp.setNameSpace(assocName.getNameSpace());
		 CIMClass cc = cimom.getClass(tempOp, false);
    // Test the instance name passed by objectName
    // and return the associated instances of the student class.
  	 if(name.equals("teacher1")) {
		     // Get students for teacher1
		     CIMInstance ci = cc.newInstance();
		     ci.setProperty("name", new CIMValue("student1"));
		     v.addElement(ci.filterProperties(propertyList,
			           includeQualifiers, includeClassOrigin));
		     ci = cc.newInstance();
		     ci.setProperty("name", new CIMValue("student2"));
		     v.addElement(ci.filterProperties(propertyList,
			           includeQualifiers, includeClassOrigin));
		     return v;
		  }
}

Writing a Native Provider

Providers get and set information on managed devices. A native provider is a machine-specific program written to run on a managed device. For example, a provider that accesses data on a Solaris system will most likely include C functions to query the Solaris system. Two common reasons for writing a native provider are:

The Java Native Interface is the native programming interface for Java that is part of the JDK. By writing programs using the JNI, you ensure that your code is completely portable across all platforms. The JNI allows Java code that runs within a Java Virtual Machine (VM) to operate with applications and libraries written in other languages, such as C, C++, and assembly.

For more information on writing and integrating Java programs with native methods, visit the Java web site at http://www.javasoft.com/docs/books/tutorial/native1.1/index.html.

Installing a Provider

After you write a Provider, you must specify the location of the provider class files and any shared library files and then stop and restart the CIM Object Manager.

How to Install a Provider
  1. Specify the location of shared library files in one of the following ways:

    • Set the LD_LIBRARY_PATH environment variable to the location of the shared library files. For example, using the C shell:


      Note –

      If you set the LD_LIBRARY_PATH environment variable in a shell, you must stop and restart the CIM Object Manager in the same shell for this new value to be recognized.



      % setenv LD_LIBRARY_PATH /wbem/provider/
      

      For example, using the Bourne shell:


      % LD_LIBRARY_PATH = /wbem/provider/
      

    • Copy the shared library files to one of the directories specified by the LD_LIBRARY_PATH environment variable. The installation sets this environment variable to /usr/sadm/lib/wbem and /usr/snadm/lib. For example:

      % cp libnative.so /usr/sadm/lib/wbem% cp native.c /usr/sadm/lib/wbem
      

  2. Move the provider class files to /usr/sadm/lib/wbem.

    Move the provider class files to the same path as the package in which they are defined. For example, if the provider is packaged as com.sun.providers.myprovider.*, move the provider class files to /usr/sadm/lib/wbem/com/sun/providers/myprovider/.

  3. Set the Solaris Provider CLASSPATH variable to the directory that contains the provider class files as described in To Set the Provider CLASSPATH.

  4. Stop the CIM Object Manager by typing the following command:


    Note –

    If you set the LD_LIBRARY_PATH environment variable in a shell, you must stop and restart the CIM Object Manager in the same shell for this new value to be recognized.



    # /etc/init.d/init.wbem -stop
    

  5. Restart the CIM Object Manager by typing the following command:


    # /etc/init.d/init.wbem -start
    

Setting the Solaris Provider CLASSPATH

To set the Solaris provider's CLASSPATH, use the client APIs to create an instance of the Solaris_ProviderPath class and set its pathurl property to the location of your provider class files. The Solaris_ProviderPath class is stored in the \root\system namespace.

You can also set the provider CLASSPATH to the location of your provider class files. You can set the class path to the jar file or to any directory that contains the classes. Use the standard URL format that Java uses for setting the CLASSPATH.

Provider CLASSPATH

Syntax 

Absolute path to directory 

file:///a/b/c/

Relative path to directory from which the CIM Object Manager was started (/). .

file://a/b/c

To Set the Provider CLASSPATH
  1. Create an instance of the Solaris_ProviderPath class. For example:

    /* Create a namespace object initialized with root\system  
    (name of namespace) on the local host. */   
    CIMNameSpace cns = new CIMNameSpace("", "root\system"); 
    
    // Connect to the root\system namespace as root. 
    cc = new CIMClient(cns, "root", "root_password");
    
    // Get the Solaris_ProviderPath class 
    cimclass = cc.getClass(new CIMObjectPath("Solaris_ProviderPath");
    
    // Create a new instance of Solaris_ProviderPath. 
    class ci = cimclass.newInstance();

  2. Set the pathurl property to the location of your provider class files. For example:

    ...
    /* Set the provider CLASSPATH to //com/mycomp/myproviders/.*/
    ci.setProperty("pathurl", new CIMValue(new String("//com/mycomp/myproviders/")); 
    ...

  3. Update the instance. For example:

    // Pass the updated instance to the CIM Object Manager 
    cc.setInstance(new CIMObjectPath(), ci);  

Registering a Provider

Providers register with the CIM Object Manager to publish information about the data and operations they support and their physical implementation. The CIM Object Manager uses this information to load and initialize the provider and to determine the right provider for a particular client request. All types of providers follow the same procedure for registration.

How To Register a Provider
  1. Create a MOF file defining a CIM class.

  2. Assign the provider qualifier to the class. Assign a provider name to the provider qualifier.

    The provider name identifies the Java class to serve as the provider for this class. You must specify the complete class name. For example:

    [Provider("com.kailee.wbem.providers.provider_name")]
    Class_name {
    …
    };


    Note –

    We recommend following Java class and package naming conventions for providers so that provider names are unique. The prefix of a unique package name is always written in all-lowercase ASCII letters and should be one of the top-level domain names, currently com, edu, gov, mil, net, org, or one of the English two-letter codes identifying countries as specified in ISO Standards 3166, 1981.

    Subsequent components of the package name vary according to an organizations own internal naming conventions. Such conventions might specify that certain directory name components be division, department, project, machine, or login names, for example, com.mycompany.wbem.myprovider.


  3. Compile the MOF file. For example:


    % mofcomp class_name
    

For more information on using the Managed Object Format (MOF) Compiler to compile a MOF file, see the Solaris WBEM Services Administrator's Guide.

Changing a MOF File

If you change a class definition in a MOF file that was previously compiled, you must delete the class from the CIM Object Manager Repository before recompiling the MOF file. Otherwise, you will get an error that the class already exists and the new information will not propagate to the CIM Object Manager. You can use the CIM WorkShop to delete a class as described in Deleting Classes and Their Attributes.

Example — Registering a Provider

The following example shows the MOF file that declares to the CIM Object Manager the Ex_SimpleInstanceProvider class that is served by the SimpleInstanceProvider (shown in Example 5–1). Provider and class names in a valid MOF file follow these rules:


Example 5–5 SimpleInstanceProvider MOF File

// ===================================================================
// Title:       SimpleInstanceProvider
// Filename:    SimpleInstanceProvider.mof
// Description:
// ===================================================================

// ==================================================================
// Pragmas
// ==================================================================
#pragma Locale ("en-US")

// ==================================================================
//   SimpleInstanceProvider
// ==================================================================
[Provider("SimpleInstanceProvider")]
class Ex_SimpleInstanceProvider
{
   // Properties
      [Key, Description("First Name of the User")]
   string First;
      [Description("Last Name of the User")]
   string Last;
};


Modifying a Provider

You can make changes to a Provider class while the CIM Object Manager and provider are running. But you must stop and restart the CIM Object Manager to make the changes take effect.

How To Modify a Provider
  1. Edit the provider source file.

  2. Compile the provider source file. For example:


    % javac MyProvider.java
    

  3. Become root on your system by typing the following command at the system prompt:


    % su
    

  4. Type the root password when you are prompted.

  5. Change directories to the location of the init.wbem command by typing the following command:


    # cd /etc/init.d/
    

  6. Stop the CIM Object Manager by typing the following command:


    # init.wbem -stop
    

  7. Restart the CIM Object Manager by typing the following command:


    # init.wbem -start
    

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
}