Wednesday, March 14, 2012

Coverage Analysis for BPEL Activities

The concept of code coverage in software testing has been around since 1963 according to Wikipedia.  Basically the idea is to ensure that all source code statements have been executed during testing activities.  It occurred to me that source code coverage analysis could be done for BPEL processes in an Oracle Fusion Middleware environment using the data that is exposed by the Fusion Middleware Java API.

In a previous post, I blogged about how to use this API and I wanted to experiment more with it.  I built a small Java program that has this basic flow:
  1. Start the program by supplying the name of the SOA composite application along with the version number and partition which are both optional parameters.
  2. Use the Fusion Java API to retrieve the source code for any BPEL processes defined in the composite and parse the source code to retrieve the names of each  BPEL activity or step.
  3. Use the Fusion Java API to retrieve all instances where this composite has been executed and parse the instance audit trail to retrieve the names of each BPEL activity that has been executed.
  4. Compare these two lists to determine which activities have not yet been tested.  This is technically referred to as "Statement Coverage".
This program turned out to be fairly easy to create and I think will be quite useful in the future for unit testing.  You can download the complete source code here. 

Example

To test the coverage analysis, I created a simple SOA composite named CoverageTest1 with a BPEL process that has an IF activity as shown below.



BPEL source code:

    <if name="If1">
      <condition>1=1</condition>
      <assign name="Assign1">
        <copy>
          <from>"value1"</from>
          <to>$outputVariable.payload/client:result</to>
        </copy>
      </assign>
      <else>
        <assign name="Assign2">
          <copy>
            <from>"value2"</from>
            <to>$outputVariable.payload/client:result</to>
          </copy>
        </assign>
      </else>
    </if>

Note that the condition "1=1" will always return true, so that the ELSE activities will never be executed.

When I run the CoverageAnalyzer.java code from JDeveloper, I get the following response:

Step Assign2 has not been tested
Coverage for composite CoverageTest1 is not complete


Friday, March 9, 2012

Oracle SOA Repository Database vs Java Infrastructure Management API

When you need to get detailed information about the state of your Oracle SOA Suite environment it is tempting to try to extract data from the SOA Repository database.  However, this can be problematic because:
  • Complexity of repository tables and their relationships
  • Many times the "interesting" information is stored in BLOB or CLOB objects which are a pain for data extraction
  • Lack of data or timeliness of data -- I have seen cases where information about the state of a process (e.g., running, faulted, etc.) was not accurate or current.  This is particularly true with synchronous processes which are dehydrated differently than asynchronous processes.
As an alternative, you may want to consider using the Oracle Fusion Middleware Infrastructure Management Java API.  Some of the benefits include:
  • The JAVA API is easy to use, consistent, and navigation is much more straight-forward
  • Lots of interesting data is exposed by the API and it provides some very powerful methods
  • Interacting directly with the SOA infrastructure server is more accurate than querying from the repository database.

The Oracle Fusion Middleware Infrastructure Management Java API is available from the standard documentation library provided on the Oracle Technology Network.  The API for version 11.1.1.4 used in the following examples is located here.  A screen shot of the primary packages is shown below.



The oracle.soa.management.facade package is the main package that is used for getting information about the current state of processes running on your server. 


Library Setup

In order to try the following examples, you will need to add the libraries shown below to your project properties.



Example 1 - Display Basic Information about a Composite

For the first example, I will show you how to get some basic information about the services and components provided by a composite application.  The complete source code is listed below.

import java.util.Hashtable;
import java.util.List;
import javax.naming.Context;
import oracle.soa.management.facade.Component;
import oracle.soa.management.facade.ComponentInstance;
import oracle.soa.management.facade.Composite;
import oracle.soa.management.facade.Locator;
import oracle.soa.management.facade.LocatorFactory;
import oracle.soa.management.facade.Service;
import oracle.soa.management.util.ComponentInstanceFilter;

public class Example1 {
    private Locator locator = null;

    public Example1() {
        super();
    }

    private void initializeLocator() {
        Hashtable jndiProps = new Hashtable();
        jndiProps.put(Context.PROVIDER_URL, "t3://localhost:8001/soa-infra");
        jndiProps.put(Context.INITIAL_CONTEXT_FACTORY,
                      "weblogic.jndi.WLInitialContextFactory");
        jndiProps.put(Context.SECURITY_PRINCIPAL, "weblogic");
        jndiProps.put(Context.SECURITY_CREDENTIALS, "weblogic1");
        jndiProps.put("dedicated.connection", "true");

        // connect to the soa server
        try {
            locator = LocatorFactory.createLocator(jndiProps);
        } catch (Exception e) {
            System.out.println("initializeLocator: " + e.toString());
        }
    }

  

    public Composite getComposite(String partitionName, String compositeName,
                                  String version) throws java.lang.Exception {

        Composite composite =
            locator.lookupComposite(partitionName + "/" + compositeName + "!" +
                                    version);

        return composite;
    }


    public void showBasicInfo(String partitionName, String compositeName,
                              String version) {

        try {

            Composite composite =
                getComposite(partitionName, compositeName, version);
            if (composite == null) {
                System.out.println("Composite not found");
            } else {           

                // get list of services
                List<Service> serviceList = composite.getServices();
                for (Service aService : serviceList) {
                    System.out.println("Service name: " + aService.getName());
                    System.out.println("CompositeDN: " +
                                       aService.getCompositeDN());
                }

                // get list of components
                List<Component> componentList = composite.getComponents();
                for (Component aComponent : componentList) {
                    System.out.println("Component name: " +
                                       aComponent.getName());
                    System.out.println("Implementation type: " +
                                       aComponent.getImplementationType());
                    //System.out.println("Source: " + aComponent.getDefinition());
                }
            }
        } catch (Exception e) {
            System.out.println("showBasicInfo: " + e.toString());
        }
    }

    public static void main(String[] args) {
        Example1 example = new Example1();

        example.initializeLocator();
        example.showBasicInfo("default", "Composite1", "1.0");
       
    }
}


The first thing to notice is that we need to create a Locator object.  In order to do this, a Hashtable is created and various key/value parameters are inserted.  For example, the server URL and login information is provided here. 

        Hashtable jndiProps = new Hashtable();
        jndiProps.put(Context.PROVIDER_URL, "t3://localhost:8001/soa-infra");
        jndiProps.put(Context.INITIAL_CONTEXT_FACTORY,
                      "weblogic.jndi.WLInitialContextFactory");
        jndiProps.put(Context.SECURITY_PRINCIPAL, "weblogic");
        jndiProps.put(Context.SECURITY_CREDENTIALS, "weblogic1");
        jndiProps.put("dedicated.connection", "true");

Then the Locator object is created by calling the LocatorFactory and passing the Hashtable values.

          locator = LocatorFactory.createLocator(jndiProps);

Next, the Locator object is asked to lookup a particular composite.  The lookup method expects a fully qualified name (also called a distinguished name) which consists of the partition name, the composite name, and the version.  Here's the snippet of code that performs this task:

Composite composite =
            locator.lookupComposite(partitionName + "/" + compositeName + "!" +
                                    version);


Once the Composite object is obtained, you can navigate further down the hierarchy as desired.  For example, to get basic information about the components of a composite application, you could execute this code:

                // get list of components
                List<Component> componentList = composite.getComponents();
                for (Component aComponent : componentList) {
                    System.out.println("Component name: " +
                                       aComponent.getName());
                    System.out.println("Implementation type: " +
                                       aComponent.getImplementationType());
                }


If you wanted to obtain the source code for a composite you could execute:

                    aComponent.getDefinition();


Example 2 - Display Composite Instance Information


Here is another example that prints out all the instances that have been created for a particular composite application.  The complete source code is shown below and uses the same structure as Example 1.


import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import javax.naming.Context;
import oracle.soa.management.facade.Component;
import oracle.soa.management.facade.ComponentInstance;
import oracle.soa.management.facade.Composite;
import oracle.soa.management.facade.Locator;
import oracle.soa.management.facade.LocatorFactory;
import oracle.soa.management.facade.Service;
import oracle.soa.management.util.ComponentInstanceFilter;

public class Example2 {
    private Locator locator = null;

    public Example2() {
        super();
    }

    private void initializeLocator() {
        Hashtable jndiProps = new Hashtable();
        jndiProps.put(Context.PROVIDER_URL, "t3://localhost:8001/soa-infra");
        jndiProps.put(Context.INITIAL_CONTEXT_FACTORY,
                      "weblogic.jndi.WLInitialContextFactory");
        jndiProps.put(Context.SECURITY_PRINCIPAL, "weblogic");
        jndiProps.put(Context.SECURITY_CREDENTIALS, "weblogic1");
        jndiProps.put("dedicated.connection", "true");

        // connect to the soa server
        try {
            locator = LocatorFactory.createLocator(jndiProps);
        } catch (Exception e) {
            System.out.println("initializeLocator: " + e.toString());
        }
    }

    public void showInstances(String compositeName) {

        ComponentInstanceFilter componentInstanceFilter =
            new ComponentInstanceFilter();
        componentInstanceFilter.setCompositeName(compositeName);

        try {
            List<ComponentInstance> componentInstanceList =
                locator.getComponentInstances(componentInstanceFilter);

            for (ComponentInstance aComponentInstance :
                 componentInstanceList) {
                System.out.println("Component: " +
                                   aComponentInstance.getComponentName());
                System.out.println("Instance ID: " +
                                   aComponentInstance.getCompositeInstanceId());
            }
        } catch (Exception e) {
            System.out.println("Error getting component instances for composite " +
                               compositeName);
        }
    }

    public static void main(String[] args) {
        Example2 example = new Example2();

        example.initializeLocator();
        example.showInstances("Composite");
    }
}


In this example, the Locator object will be asked retrieve all the instances that match a particular filter. 

List<ComponentInstance> componentInstanceList =
                locator.getComponentInstances(componentInstanceFilter);


Then a for loop iterates through the list and prints out information that is of interest.

for (ComponentInstance aComponentInstance : componentInstanceList) {
                System.out.println("Component: " +
                                   aComponentInstance.getComponentName());
                System.out.println("Instance ID: " +
                                   aComponentInstance.getCompositeInstanceId());
}