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