This chapter describes how to write a provider, including the following topics:
For detailed information on the provider APIs, see the Javadoc reference pages.
Providers are classes that communicate with managed objects 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:
Map the native information format to CIM Java classes
Get information from a device
Pass the information to the CIM Object Manager in the form of CIM Java classes
Map the information from CIM Java classes to native device format
Get the required information from the CIM Java class
Pass the information to the device in native device format
Providers are categorized according to the types of requests they service. The Sun WBEM SDK supports three types of providers:
Instance - Supply dynamic instances of a given class, for example, Solaris packages. Instance providers support one or more of the following operations:
Instance retrieval
Enumeration
Modification
Deletion
Property - Supply dynamic property values, for example, disk space.
Method - Supply methods of one or more classes. A method is a function that describes the behavior of a class. Methods must be implemented by a provider.
A single provider can support both methods and instances, 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.
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 following table describes the provider interfaces. 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.
Providers can communicate with the CIM Object Manager 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.
Table 7-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 |
Interface implemented by method providers, which provide implementation for all methods of CIM classes. |
PropertyProvider |
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. |
The following table describes the methods in the instance provider interface in the Provider package (com.sun.wbem.provider).
These methods each take the op argument, the CIM object path 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
\\myserver\root\cimv2
The default CIM namespace on host myserver.
Solaris_ComputerSystem:Name=mycomputer: CreationClassName=Solaris_ComputerSystem
A specific Solaris Computer System object in the default namespace on host myserver. This Solaris computer system is uniquely identified by two key property values in the format (property=value):
Name=mycomputer
CreationClassName=Solaris_ComputerSystem
Method |
Description |
---|---|
enumInstances |
Enumerates all instances of the class specified in the object path. You can do deep or shallow enumeration, but currently the CIM Object Manager only requests shallow enumeration. |
getInstance |
Returns the instance specified in the object path (op). |
setInstance |
Sets the instance specified in the object path (op). If the instance does not exist, it must be added. |
deleteInstance |
Deletes the instance specified in the object path (op). |
The code segment in Example 7-1, creates a Solaris instance provider class that routes requests for instance data 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 for instances of the Solaris_Package class.
An instance provider must implement all methods in the InstanceProvider interface. The code segment in Example 7-1 shows only two methods:
enumInstances - Calls the appropriate provider to enumerate Solaris packages and patches. This method does a deep enumeration, which returns the class instances and all instances of its subclasses.
getInstances - Calls the appropriate provider to get instances of Solaris packages and patches.
public class Solaris implements InstanceProvider { /** * Top-level provider class routes requests from the CIM * Object Manager to the appropriate provider. */ public void initialize(CIMONHandle, ch) throws CIMException { } public void cleanup() throws CIMException { } /* This class returns a vector of enumerated instances of the specified object in the specified class. If the object is a Solaris package, it calls the Solaris_Package provider to return a list of the Solaris packages on the system. If the object is a Solaris patch, it calls the Solaris_Patch provider to return a list of the Solaris patches on the system. */ public Vector enumInstances(CIMObjectPath op, CIMClient.DEEP, CIMClass cc) throws CIMException { if (op.getObjectName().equalsIgnoreCase("solaris_package")) { Solaris_Package sp = new Solaris_Package(); return sp.enumerateInstances(op); } if (op.getObjectName().equalsIgnoreCase("solaris_patch")) { Solaris_Patch sp = new Solaris_Patch(); return sp.enumerateInstances(op); } return new Vector(); } /* This class returns an instance of the specified object in the specified class. If the object is a Solaris package, it calls the Solaris_Package provider to return the data for the specified Solaris package. If the object is a Solaris patch, it calls the Solaris_Patch provider to return the data for the specified Solaris patch. */ public CIMInstance getInstance(CIMObjectPath op, CIMClass cc) throws CIMException { if (op.getObjectName().equalsIgnoreCase("solaris_package")) { Solaris_Package sp = new Solaris_Package(); return sp.getInstance(op,cc); } if (op.getObjectName().equalsIgnoreCase("solaris_patch")) { Solaris_Patch sp = new Solaris_Patch(); return sp.getInstance(op,cc); } } |
The specialized Solaris instance providers use the API to get and set instances of objects. These providers also declare native methods that call C functions to get Solaris-specific values, such as host name, serial number, release, machine, architecture, and manufacturer.
The code segment in Example 7-2 shows the solaris_package class, which is called in Example 7-1. This code segment implements the getInstance method. This method creates a new instance of the specified class and then fills it with properties returned from native C functions, such as GetPkgArchitecture().
public class Solaris_Package { public CIMInstance getInstance(CIMObjectPath op, CIMClass cc) { String pkgName = ""; for (Enumeration e = op.getKeys().elements(); e.hasMoreElements();) { CIMProperty cp = (CIMProperty)e.nextElement(); if (cp.getName().equalsIgnoreCase("name")) { pkgName = (String) ((CIMValue)(cp.getValue())).getValue(); } } CIMInstance ci = cc.newInstance(); ci.setProperty("Name", new CIMValue(pkgName)); ci.setProperty("TargetOperatingSystem", new CIMValue(new UnsignedInt16(29))); ci.setProperty("Status", new CIMValue(GetPkgStatus(pkgName))); ci.setProperty("Architecture", new CIMValue(GetPkgArchitecture(pkgName))); ci.setProperty("Description", new CIMValue(GetPkgDescription(pkgName))); ci.setProperty("Caption", new CIMValue(GetPkgDescription(pkgName))); ci.setProperty("Manufacturer", new CIMValue(GetPkgVendor(pkgName))); ci.setProperty("Category", new CIMValue(GetPkgCategory(pkgName))); ci.setProperty("Basedir", new CIMValue(GetPkgBasedir(pkgName))); return ci; } native String GetPkgDescription(String pkgName); native String GetPkgArchitecture(String pkgName); native String GetPkgVersion(String pkgName); native String GetPkgVendor(String pkgName); native String GetPkgBasedir(String pkgName); native String GetPkgCategory(String pkgName); native String GetPkgStatus(String pkgName); static { System.loadLibrary("NativeUnix"); } } |
The following table describes the methods in the property provider interface.
Table 7-3 PropertyProvider Interface Methods
Method |
Description |
---|---|
getPropertyValue |
Returns the value of the property for the specified instance. |
setPropertyValue |
Sets the value of the property for the specified instance |
The code segment in Example 7-3 creates a property provider (fruit_prop_provider) class that is registered in Example 7-5. 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.
fruit_prop_provider implements PropertyProvider { public CIMValue getPropertyValue(CIMObjectpath op, string originclass, string PropertyName){ if (PropertyName.euqals("a") return new CIMValue("fooa") else return new CIMValue("foob"); } ... } |
The MethodProvider method takes the following arguments:
op - Object path to the instance whose method must be invoked.
originClass - Name of the class in which this method was originally defined in the class hierarchy. CIM properties are attributes of a CIM class that are inherited from a parent class. A CIM property is uniquely identified within a namespace by its name and origin class. For example, two properties named speed can be distinguished by their respective origin classes DiskDrive and CPU.
inParams - Vector of CIMValues that are the input parameters for the method.
CIMValue - Return value of the method. If the method has no return value, it must return null. A CIM value stores the CIM data type and value of a CIM property. CIM data types (defined in the CIM Specification) are limited to intrinsic data types. The following table provides the WBEM data type name for each CIM data type.
Table 7-4 Sun WBEM SDK and CIM Data Type Names
CIM Data Type |
WBEM Data Type |
Description |
---|---|---|
uint8 |
UnsignedInt8 |
Unsigned 8-bit integer |
sint8 |
Byte |
Signed 8-bit integer |
uint16 |
UnsignedInt16 |
Unsigned 16-bit integer |
sint16 |
Short |
Signed 16-bit integer |
uint32 |
UnsignedInt32 |
Unsigned 32-bit integer |
sint32 |
Integer |
Signed 32-bit integer |
uint64 |
UnsignedInt64 |
Unsigned 64-bit integer |
sint64 |
Long |
Signed 64-bit integer |
string |
String |
UCS-2 string |
boolean |
Boolean |
Boolean |
real32 |
Float |
IEEE 4-byte floating point |
real64 |
Double |
IEEE 8-byte floating point |
datetime |
CIMDateTime |
String containing a date-time |
classname ref |
CIMObjectPath |
Strongly typed reference |
char16 |
Character |
16-bit UCS-2 character |
The following table describes the method in the Method Provider interface.
Table 7-5 MethodProvider Interface Methods
Method |
Description |
---|---|
invokeMethod |
The CIM Object Manager calls this method when the specified method is invoked. |
The code segment in Example 7-4 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:
Reboot a Solaris system
Reboot or shut down a Solaris system
Delete a Solaris serial port
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; } } |
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:
Efficiency - You may want to implement a small portion of time-critical code in a lower-level programming language, such as assembly, and then have your Java application call these functions.
Need to access platform-specific features - The standard Java class library may not support the platform-dependent features needed by your application.
Legacy code - Often, you have legacy code written in some programming language other than Java and want to continue to use the code with a Java provider.
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.
After you write a Provider, you must specify the location of the provider class files and any shared library files.
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:
% setenv LD_LIBRARY_PATH /wbem/provider/ |
For example, using the Borne shell:
% set LD_LIBRARY_PATH = /wbem/provider/ |
Copy the shared library files to the directory specified by the LD_LIBRARY_PATH environment variable. The installation sets this environment variable to /install_dir/opt/SUNWconn/wbem/lib. For example:
% cp libnative.so /install_dir/opt/SUNWconn/wbem/lib % cp native.c /install_dir/opt/SUNWconn/wbem/lib |
Move the provider class files to /install_dir/opt/SUNWconn/wbem/bin.
Set the CLASSPATH variable to the directory that contains the provider class files.
For example, if you put the provider files in:
/install_dir/opt/SUNWconn/wbem/bin/com/mycomp/wbem/provider/
you would set your CLASSPATH variable as follows, using the C shell:
% setenv CLASSPATH com/mycomp/wbem/provider/myprovider |
For the Borne shell, use the following syntax:
$ set CLASSPATH = com/mycomp/wbem/provider/myprovider |
Make sure the CIM Object Manager is running.
The installation starts the CIM Object Manager. If it is not running, see "Restarting the CIM Object Manager".
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. Neither the CIM Object Manager or the provider needs to be running during the registration process.
Create a MOF file defining a CIM class.
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:
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.
[Provider("com.kailee.wbem.providers.provider_name")] Class_name { ... };
Compile the MOF file. For example:
mofcomp class_name
The sample MOF file in Example 7-5 creates a class called Fruit that registers an instance provider (fruit_class_provider), a property provider (fruit_prop_provider), and a method provider (fruit_method_provider).
// Registers fruit_class_provider as the provider for the Fruit class [Provider("com.food.fruitprovider.fruit_class_provider")] Fruit { // fruit_prop_provider is the provider for property a [Provider("com.food.fruitprovider.fruit_class_provider")] - string a; // fruit_prop_provider is also the provider for property b [Provider("com.food.fruitprovider.fruit_class_provider")] string b; // fruit_method_provider is the provider for method b [Provider("com.food.fruitprovider.fruit_class_provider")] int b(); }; |
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.
Edit the provider source file.
Compile the provider source file. For example:
% java MyProvider.java
Become root on your system by typing the following command at the system prompt:
% su |
Type the root password when you are prompted.
Change directories to the location of the init.wbem command by typing the following command:
# cd /etc/init.d/ |
Stop the CIM Object Manager by typing the following command:
# init.wbem -stop |
Restart the CIM Object Manager by typing the following command:
# init.wbem -start |
Chapter 8, Using Sun WBEM SDK Examples explains how to set up and run the Provider examples.