Thursday, January 29, 2015

Oracle SOA Suite 12c: SOA instance purging with the Java API in multiple threads

Let's tackle a single topic at a time in this blog post ;) SOA Suite 12c provides a Java API to perform operations on the SOA infrastructure and things running there such as composites and instances. There are several blog posts available on how to do this in SOA Suite 10g and 11g. However since 12c is relatively new, I decided to try if I could easily access the Java API in 12c and if the API was still similar to 11g or had undergone major changes. As a usecase I decided I wanted to purge instances. This is usually done by database scripts on the SOA infra database. If however you do not have direct access to the database, this can be used as an alternative. I could of course have done the same by using WLST. I found that purging instances by using the Java API was slow so I decided I would like to try this using multiple threads working in parallel. The resulting code is provided in this post.

Implementation

In order to separate the different topics which will be discussed in this blog post I split the implementation in three parts. JDeveloper 12c, Purging composites and Multithreading.

JDeveloper 12c. Using the SOA Suite Java API

In JDeveloper 11g I would have to add the required libraries in the project properties and I could create a Java class which could access the Java API. In JDeveloper 11g I would have to add the following library references: WebLogic 10.3 Remote-Client, SOA Runtime, JRF API. I decided to try the same in JDeveloper 12c. When adding the SOA Runtime however, JDeveloper 12c decided I would want to develop a composite and 'refactored' my project to allow development of composites. This wasn't what I wanted however. In order to avoid this issue/feature I decided to add a single JAR to my 12c project containing required classes instead of using the SOA Runtime library reference. I added oracle.soa.wlstman.jar from my ORACLE_HOME/soa/soa/oracle.soa.fabric.11.1.1 folder (yes, the 11.1.1 folder is still there in 12.1.3). I of course also needed to add Weblogic 12.1 Remote-Client and JRF API to get it working.

Purging composites

Purging composites can be done in several ways. By using WLST, by using DB scripts and by using the Java API. If you want to use the Java API, 12c and 11g are very similar in available classes. First you should obtain an instance of oracle.soa.management.facade.Locator. You can obtain this locator from the context (oracle.soa.management.facade.LocatorFactory.createLocator()) if you're executing your Java code from for example a Spring component or BPEL Java embedding activity. You can also create this Locator remotely by using JNDI properties (connection information) and provide that to the createLocator method. For example;

 public Locator getLocator(String providerURL,String  
 user,String pass) throws Exception {  
     Hashtable jndiProps = new Hashtable();  
     jndiProps.put(Context.PROVIDER_URL,providerURL);  
     jndiProps.put(Context.INITIAL_CONTEXT_FACTORY,  
            "weblogic.jndi.WLInitialContextFactory");  
     jndiProps.put(Context.SECURITY_PRINCIPAL, user);  
     jndiProps.put(Context.SECURITY_CREDENTIALS, pass);  
     jndiProps.put("dedicated.connection", "true");  
     return LocatorFactory.createLocator(jndiProps);  
   }  

When you have the Locator, you can do all kinds of interesting things like querying for composites;

   public List<Composite> getComposites(Locator myLocator)  
 throws Exception {  
     CompositeFilter filter = new CompositeFilter();  
     return myLocator.getComposites(filter);  
   }  

You can use the CompositeFilter class to query for specific composites. Once you have obtained the Composite, you can query for instances of a specific state by using the CompositeInstanceFilter.

   public CompositeInstanceFilter getCompositeInstanceFilter() {  
     CompositeInstanceFilter filter = new CompositeInstanceFilter();  
     int[] states = { CompositeInstance.STATE_COMPLETED_SUCCESSFULLY,  
               CompositeInstance.STATE_FAULTED,  
               CompositeInstance.STATE_STALE,  
               CompositeInstance.STATE_SUSPENDED,  
               CompositeInstance.STATE_TERMINATED_BY_USER,  
               CompositeInstance.STATE_UNKNOWN };  
     filter.setStates( states );  
     Date daysAgo = new DateTime(new Date()).minusDays(1).toDate();  
     filter.setMaxCreationDate(daysAgo);  
     return filter;  
   }  

In this case I do not want to delete running instances (BPM/ACM processes) and I only want to delete instances older then a day.

Then you can call purgeInstances(getCompositeInstanceFilter()) on an instance of the composite.

The API is pretty straightforward and provides a lot of useful methods and classes. In my opinion, every senior SOA developer should be able to use this API!

Multithreading

At first I looped over the instances separately and checked if it needed to be deleted. This was very slow. Then I found the CompositeInstanceFilter and the purgeInstances method on the composite instance. Using these, the job could be done a lot faster. However I still did not get the performance I wanted since the purgeInstances method call worked synchronously. I decided I wanted to call this method asynchronously on multiple composites at once.

In order to create multithreaded Java applications, the following article by Lars Vogel provides a very nice introduction/overview: http://www.vogella.com/tutorials/JavaConcurrency/article.html.

I used two classes. A class implementing the Runnable interface which did the actual purging and a class doing the rest. In order to maintain a constant thread pool with running threads, I used the java.util.concurrent.ExecutorService class. The end result was that I first obtained the composites, created the class which executes the purgeInstances method with the correct filter and then gave this class to the ExecutorService which makes sure I only have a specified number of threads running simultaneously. Since I'm not interested in the result of the purging, I can use the Runnable interface and do not need the Callable interface with additional result processing code.

Conclusion

I have not seen major differences between 11g and 12c in Java API usage. This is a good thing. Most likely migrating from 11g to 12c requires little effort on the Java API part of things. Also developers are not required to get used to a new API.

Purging instances can be done more effectively with the Java API by using multiple threads. In this blog post I have provided an example for this. Be careful though; the SOA Suite doesn't like it when you're hammering it with a lot of threads with complicated requests.

You can download the JDeveloper 12c workspace with the code here

No comments:

Post a Comment