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.