Home > Blogs > VMware Developer Blog


Hello, VMware Objects: Getting Started with the Property Collector

This is the second in series of articles introducing the VMware Management stack. In the first article, I explained how to:

  • Set up a development environment
  • Work with SSL/TLS security in a development environment
  • Connect to a vCenter Server, log in, and get some basic information

In this article, we will build on the previous example. We will look at the VMware object system in the form of Managed Objects and Data Objects, learn more about invoking methods on Managed Objects, and use the Property Collector to start exploring the vCenter inventory.

Object Model, Runtime Environment and Programming Model

To start, let’s explore the VMware Object Model and the runtime environment that supports it. A full description of this environment can be found in the vSphere Web Services SDK Programming Guide. William Lam has also written an excellent description of the Object Model in a pair of blog  posts: Introduction to the vSphere API Part 1 and Introduction to the vSphere API Part 2: Object Model.

The runtime of a vSphere Management application is split between the vCenter Server, and the client application. Communication between these two spaces is handled via SOAP calls using the Java API for XML Web Services (JAX-WS). The BindingProvidercalled VimPortType, is obtained from a VimService instance:

VimService vimService = new VimService();
VimPortType vimPort = vimService.getVimPort();

and the endpoint is set in the Request Context:

Map<String, Object> ctxt = ((BindingProvider) vimPort).getRequestContext();
ctxt.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, url);
ctxt.put(BindingProvider.SESSION_MAINTAIN_PROPERTY, true);

There are two types of objects in the Object Model: Managed Objects and Data Objects. Managed Objects have properties and methods whereas Data Objects just contain data. The distinction between these two becomes important when we consider how they are
represented and used on the client side of the application.

Data Objects are represented as Java classes using the JavaBean pattern. They can be created with new, and properties are accessed using the getter and setter pattern, that is that a property prop is retrieved with getProp and set with setProp.

Managed Objects are not directly represented by Java classes on the client side. Instead, they are represented as Managed Object References, supported by the ManagedObjectReference type. The ManagedObjectReference has two fields: type and value. When passed to the server through a method call or a structure, the server uses this information to identify the specific instance of the Managed Object.

Methods invoked on a Managed Object are handled through the VimPortType. This class has all the methods on all Managed Objects that can be called, which explains why in some of the samples the instance is called “methods”. The first argument handed in to the method is the MangedObjectReference for the object.

In a similar manner, properties of a Managed Object are not directly accessed on the client side. Instead we use another Managed Object called the PropertyCollector to traverse structures on the server side, and pull back a collection of property values.

We have already used several of these ideas in the HelloVWorld example, so let’s look at them in a little more detail. To explore these objects, we will use the vSphere API Reference Guide. This can be found online at VMware vSphere API Reference Guide.  There is also a browsable version of the Reference Guide under the SDK directory.

The root of all access to vSphere Management API is the ServiceInstance. From this Managed Object, we obtain all the inventory and references to access and operate the rest of the system.

If we look in the API Reference Guide, we see that ServiceInstance has some properties, and a hand full of methods.

API Reference Guide Table

API Reference Guide

The first method we want to call is RetrieveServiceContent:

Retrieve Service Content

Retrieve Service Content

We use the following code to make the call:

    // Create a ManagedObjectReference to the singleton "ServiceInstance". This is a special reference that
    // can always be built this way
    ManagedObjectReference serviceInstance = new ManagedObjectReference();
    serviceInstance.setType("ServiceInstance"); 
    serviceInstance.setValue("ServiceInstance");

    // Invoke the RetrieveServiceContent method from the ServiceInstance object.  The method is
    // called from the VimPortType vimPort, with the first argument the object we are calling it with.
    // In Java this would be the equivalent of serviceInstance.retrieveServiceContent()
    ServiceContent serviceContent = vimPort.retrieveServiceContent(serviceInstance);

ServiceContent is a Data Object. Looking at the documentation, we see that it has a number of properties, most of which are Managed Object References to various services. First, we will authenticate ourselves using the login method of the Session Manager found in serviceContent.getSessionManager():

Session Manager

Session Manager

Login Parameters

Login Parameters

 

    // serviceContent.getSessionManager() returns the Managed Object Reference for the Session Manager
    // We are calling the "login" method on it, which takes three parameters: a user name, a password, and
    // an optional locale
    vimPort.login(serviceContent.getSessionManager(), user, password, null);

Now that we are logged in, we have access to other properties in the serviceContent object. We will look at the about property is contains a Data Object of type AboutInfo. Since this is a Data Object, the property values have been filled in, and to access them we use the getter methods.

    System.out.println(serviceContent.getAbout().getFullName());
    System.out.println("Server type is " + serviceContent.getAbout().getApiType());
    System.out.println("API version is " + serviceContent.getAbout().getVersion());

We will use all these concepts to retrieve property data from Managed Object References.

Simple Use of the Property Collector

The general way we obtain data from Managed Objects on the server is to use the Property Collector. The Property Collector is a Managed Object itself. We get a reference to it from the ServiceContent from the propertyCollector property.

The Property Collector is designed to allow for complex retrieval of properties from the server, and consequently is quite powerful. If you have looked at some of the samples, it can seem quite daunting to use. Before we explore some of the power of the Property Collector, though, let’s look at some simple use.

For the first example, we’ll use the Property Collector to get the name of the root system folder. We’ll start with the HelloVWorld sample from before, and start adding to it. We will be calling this example “HelloPropCollector”. First, let’s create a method collectProperties, and get the Property Collector and Root Folder reference:

private static void collectProperties(VimPortType vimPort, ServiceContent serviceContent) {

    // Get the reference to the PropertyCollector
    ManagedObjectReference propertyCollector = serviceContent.getPropertyCollector();

    // Get the reference to the root folder
    ManagedObjectReference rootFolder = serviceContent.getRootFolder();

}

The method we use to retrieve properties is RetrievePropertiesEx. Looking at this method, we see it takes two parameters: a List of PropertyFilterSpec, and a RetreiveOptions. The RetrieveOptions allows us to limit the number of objects we retrieve, but we will not use it for this example.

Retrieve Properties

Retrieve Properties

The PropertyFilterSpec is a Data Object with two fields: a list of ObjectSpec and a list of PropertySpec. The ObjectSpec specifies the reference to the managed object from which we want to collect the properties, along with some other options, and the PropertySpec specifies what properties from which object types to select. Since all of these are Data Objects, we use new to create them.

    // Create an ObjectSpec to define the beginning of the traversal
    // We are traversing the root folder, so set the obj property to it
    ObjectSpec objectSpec = new ObjectSpec();
    objectSpec.setObj(rootFolder);

    // Create a PropertySpec to specify the properties we want.
    // Each PropertySpec specifies the type of the object we are using, and a list
    // of property names to collect.  In this case the type is the type of the
    // root folder, and the property is "name".  Note that the pathSet list is 
    // automatically initialized by the getPathSet method
    PropertySpec propertySpec = new PropertySpec();
    propertySpec.setType(rootFolder.getType());
    propertySpec.getPathSet().add("name");

    // Create a PropertyFilterSpec and add the ObjectSpec and
    // PropertySpec to it.  As above, the getter methods will automatically
    // initialize the lists
    PropertyFilterSpec propertyFilterSpec = new PropertyFilterSpec();
    propertyFilterSpec.getObjectSet().add(objectSpec);
    propertyFilterSpec.getPropSet().add(propertySpec);

We’re now ready to call RetrievePropertiesEx. As always, this method is on vimPortType, and the first parameter is the Managed Object from which we are making the call, in this case, the Property Collector. The other two parameters are a list of PropertySpec, and a RetrieveOptions. The RetrievePropertiesEx method also throws two exceptions, InvalidPropertyFaultMsg and RuntimeFaultFaultMsg, so we will add a throws clause to collectProperties declaration.

private static void collectProperties(VimPortType vimPort, ServiceContent serviceContent) 
        throws InvalidPropertyFaultMsg, RuntimeFaultFaultMsg {
    // The RetrievePropertiesEx method takes a list of PropertyFilterSpec, so we need
    // to create a list and add our propertyFilterSpec to it
    List<PropertyFilterSpec> propertyFilterSpecList = new ArrayList<PropertyFilterSpec>();
    propertyFilterSpecList.add(propertyFilterSpec);

    // Although the RetrieveOptions parameter is optional, in Java we must pass
    // something in.  A null will give us an exception, so we must pass in an empty
    // RetrieveOptions object
    RetrieveOptions retrieveOptions = new RetrieveOptions();

    // Finally, make the call and get the results 
    RetrieveResult result = vimPort.retrievePropertiesEx(propertyCollector, propertyFilterSpecList, retrieveOptions);
Data Object Description

Data Object Description

Now that we have the results, we can get the values. The RetrieveResult contains two properties: objects, a list of ObjectContent, and token, a string that is used to continue the retrieval if we had limited the number of objects to return in the RetrieveOptions.

In this example, we want to get the list of DynamicProperty returned in propSet property of ObjectContentEach DynamicProperty has a string name, which is the name of the property and val, an object that is its value. In our example below, the name of the property is “name”, and val will be a string:

    // go through the returned list and print out the data.  We must do a null check on the result
    if (result != null) {
        for (ObjectContent objectContent : result.getObjects()) {
            List<DynamicProperty> properties = objectContent.getPropSet();
            for (DynamicProperty property : properties) {
                System.out.println(property.getName() + ": " + property.getVal());
            }
        }
    }

We now have the entire method:

private static void collectProperties(VimPortType vimPort, ServiceContent serviceContent) 
        throws InvalidPropertyFaultMsg, RuntimeFaultFaultMsg {

    // Get reference to the PropertyCollector
    ManagedObjectReference propertyCollector = serviceContent.getPropertyCollector();

    // Create a new ManagedObjectReference to get
    ManagedObjectReference rootFolder = serviceContent.getRootFolder();

    // Create an ObjectSpec to define the beginning of the traversal
    // We are traversing the root folder, so set the obj property to it
    ObjectSpec objectSpec = new ObjectSpec();
    objectSpec.setObj(rootFolder);

    // Create a PropertySpec to specify the properties we want.
    // Each PropertySpec specifies the type of the object we are using, and a list
    // of property names to collect.  In this case the type is the type of the
    // root folder, and the property is "name".  Note that the pathSet list is 
    // automatically initialized by the getPathSet method
    PropertySpec propertySpec = new PropertySpec();
    propertySpec.setType(rootFolder.getType());
    propertySpec.getPathSet().add("name");

    // Create a PropertyFilterSpec and add the ObjectSpec and
    // PropertySpec to it.  As above, the getter methods will automatically
    // initialize the lists
    PropertyFilterSpec propertyFilterSpec = new PropertyFilterSpec();
    propertyFilterSpec.getObjectSet().add(objectSpec);
    propertyFilterSpec.getPropSet().add(propertySpec);

    // The RetrievePropertiesEx method takes a list of PropertyFilterSpec, so we need
    // to create a list and add our propertyFilterSpec to it
    List<PropertyFilterSpec> propertyFilterSpecList = new ArrayList<PropertyFilterSpec>();
    propertyFilterSpecList.add(propertyFilterSpec);

    // Although the RetrieveOptions parameter is optional, in Java we must pass
    // something in.  A null will give us an exception, so we must pass in an empty
    // RetrieveOptions object
    RetrieveOptions retrieveOptions = new RetrieveOptions();

    // Finally, make the call and get the results 
    RetrieveResult result = vimPort.retrievePropertiesEx(propertyCollector, propertyFilterSpecList, retrieveOptions);

    // go through the returned list and print out the data.  We must do a null check on the result
    if (result != null) {
        for (ObjectContent objectContent : result.getObjects()) {
            List<DynamicProperty> properties = objectContent.getPropSet();
            for (DynamicProperty property : properties) {
                System.out.println(property.getName() + ": " + property.getVal());
            }
        }
    }
}

To call this method, we will call it in main:

    try {
        // Disable all SSL trust security
        DisableSecurity.trustEveryone();

        ServiceContent serviceContent = vimPort
                .retrieveServiceContent(serviceInstance);
        vimPort.login(serviceContent.getSessionManager(), user, password,
                null);

        // Test out all of the code we've been writing
        collectProperties(vimPort, serviceContent);

        vimPort.logout(serviceContent.getSessionManager());
    }
    // many catches...

This will give us the name of the root folder:

name: Datacenters

We can retrieve more than one property from the object by adding additional property names to the PropertySpec. Since we know the type is a Folder, let’s get the childType and childEnity from the root folder:

    PropertySpec propertySpec = new PropertySpec();
    propertySpec.setType(rootFolder.getType());
    propertySpec.getPathSet().add("name");
    // Also get childType and childEntity
    propertySpec.getPathSet().add("childType");
    propertySpec.getPathSet().add("childEntity");

Running this gives us the following:

childEntity: com.vmware.vim25.ArrayOfManagedObjectReference@57b18927
childType: com.vmware.vim25.ArrayOfString@48a38c6b
name: Datacenters

We can also retrieve all the properties of the object by setting all to true, and leaving the pathSet empty:

    // retrieve all the properties
    PropertySpec propertySpec = new PropertySpec();
    propertySpec.setType(rootFolder.getType());
    propertySpec.setAll(true);
alarmActionsEnabled: true
availableField: com.vmware.vim25.ArrayOfCustomFieldDef@3c61e75a
childEntity: com.vmware.vim25.ArrayOfManagedObjectReference@3f9be4ae
childType: com.vmware.vim25.ArrayOfString@13c27c22
configIssue: com.vmware.vim25.ArrayOfEvent@4563a650
configStatus: GRAY
customValue: com.vmware.vim25.ArrayOfCustomFieldValue@113bf1c7
declaredAlarmState: com.vmware.vim25.ArrayOfAlarmState@767e48a7
disabledMethod: com.vmware.vim25.ArrayOfString@5cd408b7
effectiveRole: com.vmware.vim25.ArrayOfInt@648855fd
name: Datacenters
overallStatus: GRAY
permission: com.vmware.vim25.ArrayOfPermission@32c5889b
recentTask: com.vmware.vim25.ArrayOfManagedObjectReference@468b9227
tag: com.vmware.vim25.ArrayOfTag@7528629f
triggeredAlarmState: com.vmware.vim25.ArrayOfAlarmState@2e62f0d0
value: com.vmware.vim25.ArrayOfCustomFieldValue@61afff7a

Let’s return to childEntity. In the documentation, we see that this property is defined as a list of ManagedObjectReferencesIn java, this gets returned as an instance of ArrayOfManagedObjectReference. In general, a list of type Type is return as an instance of ArrayOfType. To obtain the list of objects, we use the getType() getter from this instance. For example, in this case childEntity.getManagedObjectReference(). Similarly, childType is ArrayOfString, so to get the list we use childType.getString().

Now let’s modify the sample to use these. First, let’s only retrieve childType and childEntity:

    PropertySpec propertySpec = new PropertySpec();
    propertySpec.setType(rootFolder.getType());
    propertySpec.getPathSet().add("childType");
    propertySpec.getPathSet().add("childEntity");

Now we modify the print loop so we can print the lists:

    if (result != null) {
        for (ObjectContent objectContent : result.getObjects()) {
            List<DynamicProperty> properties = objectContent.getPropSet();
            for (DynamicProperty property : properties) {
                // Print the property name and value
                System.out.println(property.getName() + ": " + property.getVal());
                if (property.getName().equals("childType")) {
                    System.out.println("childType:");
                    // if this is the childType, the value is ArrayOfString
                    ArrayOfString childType = (ArrayOfString)property.getVal();
                    // get the string list
                    List<String> types = childType.getString();
                    // and print the values
                    for (String s : types) {
                        System.out.println(" -- " + s);
                    }
                }
                if (property.getName().equals("childEntity")) {
                    System.out.println("childEntity:");
                    // if this is the childEntity, the value is ArrayOfManagedObjectReference
                    ArrayOfManagedObjectReference childEngity = (ArrayOfManagedObjectReference)property.getVal();
                    // get the ManagedObjectReference list
                    List<ManagedObjectReference> entities = childEngity.getManagedObjectReference();
                    // Print the type and the value of the ManagedObjectReference
                    for (ManagedObjectReference entity : entities) {
                        System.out.println(" -- " + entity.getType() + " - " + entity.getValue());
                    }
                }
            }
        }
    }

This gives the following result:

childEntity: com.vmware.vim25.ArrayOfManagedObjectReference@6fdd1cc7
childEntity:
 -- Datacenter - datacenter-2
childType: com.vmware.vim25.ArrayOfString@1d8c8631
childType:
 -- Folder
 -- Datacenter

We now have the tools to look at more complicated uses of the Property Collector.

Summary

To summarize, in this article we have

  • Explored the vSphere Object Model
  • Learned about Data Objects, Managed Objects, and Managed Object References
  • Learned how to invoke methods from a Managed Object Reference
  • Learned how to retrieve properties from a Managed Object Reference
  • Learned how properties that return list are mapped in Java

In the next article, we will explore how the Property Collector can be used to traverse the inventory in more useful manner.