Extending the Data Service with a Data Service Adapter
If the Flex components in your user interface extensions require data that is not available through the vSphere Web Client Data Service, you can extend the Data Service.
You can extend the vSphere Web Client Data Service by creating a Data Service Adapter. A Data Service Adapter is a Java service that integrates with the Data Service, and gives the Data Service the ability to process and respond to Data Service queries for new object types or properties. Data Service Adapters can access data sources within vSphere, or outside data sources.
A Data Service Adapter must implement the same interface and information model of the Data Service. As such, a Data Service Adapter must handle Data Service queries and return information as a result set consisting of objects with associated properties.
Advantages of Providing a Data Service Adapter
Extending the Data Service by creating a Data Service Adapter has several advantages.
The Flex components in your user interface extensions can use the Data Access Manager interface to access the new data. The Data Access Manager provides a consistent data access model throughout the component, easing maintenance and improving code consistency and re-use.
The Data Service automatically routes queries to the appropriate Data Service Adapters. This mechanism removes any distinction between data sources inside or outside of vSphere, and your extension Flex components can access multiple data sources in a single call.
Designing a Data Service Adapter
To create a Data Service Adapter, you must create a Java service that implements one of the adapter interfaces published by the Data Service. The Data Service publishes interfaces for Property Provider Adapters and Data Provider Adapters. The type of Data Service Adapter you must create depends on the information you want to make available through the Data Service.
Property Provider Adapters
You create a Property Provider Adapter to allow the Data Service to access new properties for existing vSphere objects, such as virtual machines or hosts. For example, your vSphere environment may contain custom virtual machines or hosts that provide extra properties not normally available through the Data Service. You can create a Property Provider Adapter to extend the Data Service to fetch these additional properties.
Data Provider Adapters
You can use a Data Provider Adapter to extend the Data Service to fetch entirely new data that is not associated with an existing vSphere object. Typically, you create a Data Service adapter for one of the following purposes.
For example, you might create a Data Service Adapter to handle queries for a new type of vSphere object called a Chassis. You might also use a Data Service Adapter to display data in the vSphere Web Client from an external Web source separate from vCenter Server.
Implementing an Adapter
To implement one of the adapter interfaces, your Java service must import the package com.vmware.vise.data.query from the vSphere Web Client Java SDK.
Once you have created the adapter service, you must add the adapter service to Virgo Server framework and register the adapter with the Data Service. You register an adapter by using the vSphere Web Client SDK DataServiceExtensionRegistry service, typically within your adapter’s constructor method. See Registering a Property Provider Adapter and Registering a Data Provider Adapter.
The registration process declares what types of objects and properties the Data Service Adapter can provide. When the Data Service receives a query for one of the registered object or property types, the Data Service automatically routes the query to the proper Data Service Adapter.
Property Provider Adapters
Queries to a Property Provider Adapter accept one or more specific vSphere objects, and return one or more properties for those objects. A Property Provider Adapter registers with the Data Service to advertise which types of properties it can return. When the Data Service receives a query for one of the registered property types, the Data Service routes the query to the appropriate Property Provider Adapter for processing.
PropertyProviderAdapter Interface
A Property Provider Adapter must implement the PropertyProviderAdapter interface in the com.vmware.vise.data.query Java SDK package. The PropertyProviderAdapter interface publishes a single method named getProperties(). Your Property Provider Adapter service must provide an implementation of this method. The Data Service calls your adapter’s getProperties() method in response to an appropriate query for the properties your adapter is registered to provide.
The method implementation in your service must accept an object of type com.vmware.vise.data.query.PropertyRequestSpec, and must return an object of type com.vmware.vise.data.query.ResultSet.
public ResultSet getProperties(PropertyRequestSpec propertyRequest)
Your service’s implementation of the getProperties() method can retrieve and format data in any way you choose. However, your implementation must return the results as a ResultSet object. You use the PropertyRequestSpec object to obtain the query’s list of target vSphere objects and desired properties. The PropertyRequestSpec object contains an objects array and a properties array, which respectively contain the target vSphere objects and requested properties.
See the Java API reference included in the vSphere Web Client SDK for additional information on ResultSet, PropertyRequestSpec, and other features in the com.vmware.vise.data.query package.
Registering a Property Provider Adapter
You must register your Property Provider Adapter for the adapter to work with the Data Service. You register your Property Provider Adapter with the Data Service by using the DataServiceExtensionRegistry service. The DataServiceExtensionRegistry service contains a method named registerDataAdapter() that you must call to register your Property Provider Adapter.
A best practice for registering your adapter is to pass DataServiceExtensionRegistry as a parameter to your Property Provider Adapter class constructor, and call registerDataAdapter() from within that constructor.
Example Property Provider Adapter
Example: Example Property Provider Adapter Class shows an example of a Property Provider Adapter class. The class constructor method registers the adapter with the Data Service.
Example: Example Property Provider Adapter Class
package com.myAdapter.PropertyProvider;
 
import com.vmware.vise.data.query;
import com.vmware.vise.data.query.PropertyProviderAdapter;
import com.vmware.vise.data.query.ResultSet;
import com.vmware.vise.data.query.type;
 
public class MyAdapter implements PropertyProviderAdapter {
 
public MyAdapter(DataServiceExtensionRegistry extensionRegistry) {
TypeInfo vmTypeInfo = new TypeInfo();
vmTypeInfo.type = "VirtualMachine";
vmTypeInfo.properties = new String[] { "myVMdata" };
TypeInfo[] providerTypes = new TypeInfo[] {vmTypeInfo};
 
extensionRegistry.registerDataAdapter(this, providerTypes);
}
 
@Override
public ResultSet getProperties(PropertyRequestSpec propertyRequest) {
// Logic to retrieve properties and return as result set
}
...
}
 
In Example: Example Property Provider Adapter Class, the class constructor method MyAdapter() constructs an array of property types that the adapter can supply to the Data Service in the array named providerTypes. The constructor then calls the Data Service Extension Registry method named registerDataAdapter to register the Property Provider Adapter with the Data Service.
The Data Service calls the override method getProperties() when the Data Service receives a query for the kinds of properties that were specified at registration. The getProperties() method must retrieve the necessary properties, format them as a ResultSet object, and return that ResultSet.
Data Provider Adapters
A Data Provider Adapter is responsible for all aspects of data retrieval, including parsing a query, computing the results of access operations, finding the matching objects or properties, and formatting results into responses compatible with the Data Service. You can use a Data Provider Adapter to retrieve almost any data, including data agnostic to vSphere, provided that you can format it as a set of objects and related properties.
Typically, you use a Data Provider Adapter to retrieve data on custom objects that you have added to your vSphere environment. The specific implementation of the Data Provider Adapter’s data access depends on the data source for your custom object. Your Data Provider Adapter might query a database for configuration data, or retrieve operational data directly from a particular device.
When designing a Data Provider Adapter, consider the following requirements:
DataProviderAdapter Interface
A Data Provider Adapter must implement the DataProviderAdapter interface in the com.vmware.vise.data.query Java SDK package. The DataProviderAdapter interface publishes a single method named getData(). Your Data Provider Adapter service must provide an implementation of this method. The Data Service calls your adapter’s getData() method in response to the queries your adapter is registered to process.
Your implementation of the getData() method must accept an object of type com.vmware.vise.data.query.RequestSpec as a parameter, and must return an object of type com.vmware.vise.data.query.Response.
public Response getData(RequestSpec request)
The RequestSpec object parameter to the getData() method contains an array of Data Service query objects. Each query contains a target object and one or more constraints that define the information that the client requests, as well as the expected format for results.
Your getData() method determines what information it must fetch by processing each Data Service query and handling the included constraints. The getData() method must then retrieve that information, through whatever means your data source provides, such as a database query or a remote device method.
YourgetData() method must format the retrieved information as a specific result type for each query, and then return those results an array, packaged in a Response object.
Processing Data Service Queries
Data Service queries are passed to your Data Service Adapter through the com.vmware.data.query.RequestSpec object parameter. A RequestSpec object consists of an array of objects of type com.vmware.data.query.QuerySpec, each of which represents an individual query.
Each QuerySpec object defines the query target, the query constraints, and the expected formatting for the query results.
Query Target Object
The query target is the object for which your getData() method must retrieve information. In the QuerySpec object, the target is represented as an object of type com.vmware.data.query.ResourceSpec
Your getData() method can determine what information it must retrieve by using the values in the ResourceSpec object. The ResourceSpec object specifies the target object as a String type, which contains a URI for the target object. The requested properties are contained in an object of type com.vmware.data.query.PropertySpec.
Handling Constraints
Within the QuerySpec object, The query constraints are represented as an object of type com.vmware.data.query.Constraint. A query can specify the following types of constraints, each of which is a subclass of the base Constraint class.
ObjectIdentityConstraint. Queries based on this constraint retrieve the properties of a known target object. For example, a query could retrieve the powered-on state of a given virtual machine. The object identifier can be any type that implements the IResourceReference interface.
PropertyConstraint. Queries based on this constraint retrieve all objects with a given property value. For example, a query could retrieve all virtual machine objects with a power state of ‘on’. This constraint accepts the property name and comparator as strings, and the property value as an Object. PropertyConstraint is roughly analogous to a SELECT statement in a database query.
RelationalConstraint. Queries based on this constraint retrieve all objects that match the specified relationship with a given object. For example, a query could retrieve all virtual machine objects related to a given host object. RelationalConstraint is roughly analogous to a JOIN statement in a database query.
CompositeConstraint. Composite queries allow the combination of multiple constraints using the “and” or “or” operator (passed as a string). The combined sub-constraints in CompositeConstraint are contained in an array of Constraint objects.
When processing constraints, a best practice is to read the entire set of constraints and then determine the most efficient processing order. For example, you can process relational constraints first to retrieve a smaller number of objects that meet any included property constraints.
Specifying Result Sets
Within the QuerySpec object, the expected formatting for the query results are included in an object of type com.vmware.data.query.ResultSpec. The properties of the ResultSpec object specify a maximum number of results for the query to return, provide an offset into the returned results, and set ordering for the returned results. Your getData() method must use the values of the ResultSpec properties to format the information it has retrieved.
Resolving the Target Object
The target object for a query is identified by a Uniform Resource Identifiers (URI) string, which is a unique identifier for a specific custom objects. In your Data Provider Adapter, you must resolve the URI for a query target object to the correct custom object type.
Implementing a Resource Type Resolver
A best practice is to use a Resource Type Resolver to automatically resolve a URI to the correct custom object type. To use a Resource Type Resolver, you must create a Java class that implements the interface com.vmware.vise.data.uri.ResourceTypeResolver.
The class you create to implement ResourceTypeResolver must support the following methods.
String getResourceType(URI uri)
The getResourceType() method must parse a given URI and return a String containing the type of custom object to which the URI pertains. For example, for a URI that referred to a given custom Chassis object, the getResourceType() method must return the String “samples:Chassis”.
String getServerGuid(URI uri)
The getServerGuid() method must parse a given URI and return a String containing the server global unique identifier for the URI target object, if any.
Registering a Resource Type Resolver
To use your Resource Type Resolver, you must register the resolver with the Data Service. You typically register the Resource Type Resolver in your Data Provider Adapter class constructor by using the Resource Type Resolver Registry service, an OSGI service included with the vSphere Web Client. You must use the vSphere Web Client Spring framework to pass the Resource Type Resolver Registry OSGI service as an argument to your class constructor method. See Passing Arguments to Your Class Constructor.
Example: Example Data Provider Adapter Class, shows an example of how to register a Resource Type Resolver.
Registering a Data Provider Adapter
You must register your Data Provider Adapter for the adapter to work with the Data Service. You can register an adapter automatically by declaring the Java service as an OSGI bundle, or you can register an adapter explicitly by using the Data Service Extension Registry service.
Registering Automatically
You can register your Data Provider Adapter automatically when you add the adapter to the Virgo server framework. To use automatic registration, you must declare the Java service that implements your Data Provider Adapter as an OSGI bundle when you add the service to the Virgo server framework. The vSphere Web Client detects new OSGI bundles as they are added and automatically registers Data Provider Adapters with the Data Service. You must also annotate the adapter class with the object types that the adapter supports.
Declaring the Service as an OSGI Bundle
To declare the service as an OSGI bundle, you must define your adapter’s Java service as a Java Bean in the bundle-context.xml file. You can find the bundle-context.xml file your plug-in module’s src/main/resources/META-INF/spring folder.
To define the Java Bean, you must add the following XML element to the bundle-context.xml file.
<bean name=”MyDataProviderImpl” class=”com.example.MyDataProviderAdapter”> </bean>
The name attribute is an identifier that you choose for the Java Bean. You must set the value of the class attribute to the fully-qualified class name of the Java class you have created that implements the DataProviderAdapter interface.
Once you have defined your Data Provider Adapter as a Java Bean, you must modify the bundle-context-osgi.xml file to include the Java Bean as an OSGI service. You can find the bundle-context-osgi.xml file your plug-in module’s src/main/resources/META-INF/spring folder.
You must add the following XML element to the bundle-context-osgi.xml file.
<osgi:service id=”MyDataProvider” ref=”MyDataProviderImpl” interface=”com.vmware.vise.data.query.DataProviderAdapter” />
The id attribute is an identifier that you choose for the Data Provider Adapter. You must set the value of the ref attribute to the same value as the name attribute that you defined when declaring your Java Bean. The interface attribute must be set to the fully qualified class name of the DataProviderAdapter interface.
You must update the src/main/resources/META-INF/MANIFEST.MF file to reflect any Java packages from the vSphere Web Client SDK that your Data Provider Adapter imports. You add the imported packages to the import-packages section of the MANIFEST.MF file.
In Example: Example Data Provider Adapter Class, the example Data Provider Adapter imports the packages com.vmware.vise.data.uri and com.vmware.data.query. For the example, the MANIFEST.MF file must list those packages in the import-package section.
Import-Package: org.apache.commons.logging,
com.vmware.vise.data,
com.vmware.vise.data.query,
com.vmware.vise.data.uri
Annotating the Adapter Class
You must annotate your Data Provider Adapter class with the object types for which the adapter processes queries. The vSphere Web Client uses these annotations to route queries for the specific types to the correct adapters. You use the @type tag to create the necessary annotation.
@type(“samples:Chassis”) // declares the supported object types
public class MyAdapter implements DataProviderAdapter {
...
Passing Arguments to Your Class Constructor
Most Data Provider Adapters make use of other OSGI services that are provided by the vSphere Web Client SDK. These services include the base Data Service itself, the Resource Type Resolver Registry, and the vSphere Object Reference Service. You can pass these OSGI services to your Data Provider Adapter as arguments to the Data Provider Adapter class constructor method.
All Data Provider Adapters can include the vSphere Web Client Data Service. To include the Data Service as an argument to your Data Provider Adapter class constructor, you add the following element to your service’s bundle-context-osgi.xml file.
<osgi:reference id=”dataService” interface=”com.vmware.vise.data.query.DataService” />
If your Data Provider Adapter handles queries for multiple custom object types, you must include the Resource Type Resolver Registry OSGI service and register a Resource Type Resolver. To include the Resource Type Resolver Registry OSGI service as an argument to your Data Provider Adapter class constructor, you add the following element to your service’s bundle-context-osgi.xml file.
<osgi:reference id=”uriRefTypeAdapter” interface=”com.vmware.vise.data.uri.ResourceTypeResolverRegistry” />
If your Data Provider Adapter handles queries for built-in vSphere object types, such as Hosts or Virtual Machines, you can include the VimObjectReferenceService. To pass the VimObjectReferenceService as an argument to your Data Provider Adapter class constructor, you add the following element to your service’s bundle-context-osgi.xml file.
<osgi:reference id=”vimObjectReferenceService” interface=”com.vmware.vise.vim.data.VimObjectReferenceService” />
Your Data Provider Adapter can use the User Session Service to get information about the current user session. To pass the User Session Service as an argument to your Data Provider Adapter class constructor, you add the following element to your service’s bundle-context-osgi.xml file.
<osgi: reference id=”userSessionService” interface=”com.vmware.vise.usersession.UserSessionService” />
If you choose to pass any OSGI service to your Data Provider Adapter’s class constructor, you must include those constructor arguments when you declare your Data Provider Adapter as a JavaBean in the bundle-context.xml file. See Declaring the Service as an OSGI Bundle.
For each service your Data Provider Adapter includes, you must add a <constructor-arg> element to your adapter’s Bean defnition. In each <constructor-arg> element, you set the ref attribute to the same value as the id attribute in the <osgi:reference> element in the bundle-context-osgi.xml file.
If your Data Provider Adapter made use of the Data Service, VimObjectReferenceService, Resource Type Resolver Registry, and User Session Service, the Bean definition might appear as follows.
<bean name=”MyDataProviderImpl” class=”com.example.MyDataProviderAdapter”>
<constructor-arg ref=”dataService”/>
<constructor-arg ref=”uriRefTypeAdapter”/>
<constructor-arg ref=”vimObjectReferenceService”/>
<constructor-arg ref=”userSessionService”/>
</bean>
Registering Explicitly
You can register your Data Provider Adapter with the Data Service by using the DataServiceExtensionRegistry service. DataServiceExtensionRegistry contains a registerDataAdapter() method that you must call to register your Data Provider Adapter.
A common way to register your adapter is to pass DataServiceExtensionRegistry as a parameter to your Data Provider Adapter class constructor, and call registerDataAdapter() from within that constructor.
Data Provider Adapter Example
Example: Example Data Provider Adapter Class presents an example of a Data Provider Adapter class. In the example, the class constructor method registers a Resource Type Resolver. The example assumes that the Data Provider Adapter is registered automatically by registering the service as an OSGI bundle. The Data Service and Resource Type Resolver Registry services are passed as arguments to the class constructor.
As a best practice, you can initalize the other services that your Data Provider Adapter requires in yourr Data Provider Adapter class constructor. These might include the vSphere Web Client Data Service, the Resource Type Resolver Registry if your adapter handles multiple custom object types, and the VimObjectReferenceService if your adapter requires data from regular vSphere objects.
In Example: Example Data Provider Adapter Class, the Data Provider Adapter class constructor initializes the class member variables for the Data Service and registers the Resource Type Resolver Registry, and registers a Resource Type Resolver.
For more complete examples of Data Provider Adapters, see the sample extensions included in the vSphere Web Client SDK download.
Example: Example Data Provider Adapter Class
package com.MyAdapter.DataProvider;
 
import java.net.URI;
 
import com.vmware.vise.data.uri.ResourceTypeResolverRegistry;
import com.vmware.vise.data.query.DataProviderAdapter;
import com.vmware.vise.data.query.QuerySpec;
import com.vmware.vise.data.query.RequestSpec;
import com.vmware.vise.data.query.Response;
import com.vmware.vise.data.query.type;
 
@type(“samples:Chassis”) // type that the adapter supports
public class MyAdapter implements DataProviderAdapter {
 
private final DataService _dataService;
 
// Resource resolver, used to resolve the URIs of objects serviced by this adapter
private static final ModelObjectUriResolver RESOURCE_RESOLVER = new ModelObjectUriResolver();
 
public MyAdapter { // constructor method
DataService dataService,
ResourceTypeResolverRegistry typeResolverRegistry ) {
 
if ( dataService = null || typeResolverRegistry == null ) {
throw new IllegalArgumentException(“MyAdapter constructor arguments must be non-null.”);
)
_dataService = dataService;
try {
// Register the Resource Type resolver for multiple custom object types
typeResolverRegistry.registerSchemeResolver(
ModelObjectUriResolver.SCHEME,
RESOURCE_RESOLVER);
} catch (UnsupportedOperationException e) {
_logger.warn(“ModelObjectUriResolver registration failed.”, e);
}
 
@Override
// All query requests for the types supported by this adapter are routed here by the vSphere
// Web Client Data Service; this method is the starting point for processing constraints,
// discovering objects and properties, and returning results
public Response getData(RequestSpec request) {
// Query Processing logic, constraint processing, object discovery, and result set return
}
 
The getData() method is called by the vSphere Web Client Data Service when it has received a query for one of the objects or properties specified at registration. Within the getData() method, your Data Provider Adapter must parse the query, compute the results, and return that result data as a Response object.