Wednesday, September 15, 2010

Fault handling in Oracle SOA Suite 11g - Part III

Let's pick up the previous posts on fault handling (part I and part II) from where we left off: our custom Java class that handles faults. Remember that our class is supposed to enqueue an event containing the fault’s identifier and return the action to be executed by Oracle SOA Suite’s fault handling framework. Retrieval of the fault information itself is done by the SCA composite that acts as generic fault handler. This composite will be initiated based on the fault event and retrieve the fault information based on its identifier in the event payload using the Oracle SOA Suite API’s. The composite will then initiate a Human Task to notify administrators that there was a fault in one our composite instances.

Note that we enqueue a fault identifier (its ECID) instead of the fault information itself. When executing the Java class, Oracle SOA Suite is still in the middle of the fault handling mechanism. That means the fault and its corresponding information is not yet fully stored and accessible. After the event is published and control is returned from the Java fault handler class, Oracle SOA Suite will complete the fault handling mechanism and all fault information will be accessible using for instance the SOA Suite API’s.

The Java code
The Java class needs to implement the “IFaultRecoveryJavaClass” interface and its handleFault method. This method receives the fault context. The method enqueues an event on an AQ queue containing the fault identifier and returns “ora-terminate” to the fault handling framework. Alternatively you can also use JMS or EDN as queuing infrastructure. The choice depends on requirements, durability, personal flavor, and so on. For an example on publishing events on the Event Delivery Network using Spring you can read this blog by Guido Schmutz.

You will need to import the following libraries and JAR files to make the class compile:

  • SOA Runtime
  • Oracle JDBC
  • Java EE 1.5 API
  • Oracle XML Parser v2
  • SOA Designtime
  • SOA Workflow
  • WebLogic 10.3 Remote-Client


The class roughly looks like this:

package nl.vennster;


public class MyFaultPolicyJavaAction implements IFaultRecoveryJavaClass {

public String handleFault(IFaultRecoveryContext ctx) {
    UUID uuid = UUID.randomUUID();
    enqueueAqEvent(createEventPayload(ctx), uuid);
    return "ora-terminate";
}

}

The helper method to create the AQ event looks like the following:

private String createEventPayload(IFaultRecoveryContext context) {


String eventPayload = " UNKNOWN_ECID";
if (context instanceof RejectedMsgRecoveryContext) {
RejectedMsgRecoveryContext rejectedMessageContext = (RejectedMsgRecoveryContext) context;
String ecid = null;
if (rejectedMessageContext.getRejectedMessage() != null &&
    rejectedMessageContext.getRejectedMessage().getEcid() != null) {
    ecid = rejectedMessageContext.getRejectedMessage().getEcid();
}
else if (rejectedMessageContext.getFault() != null &&
    rejectedMessageContext.getFault().getECID() != null) {
    ecid = rejectedMessageContext.getFault().getECID();
    eventPayload = eventPayload.replace("UNKNOWN_ECID", ecid);
}
else if (context instanceof BPELFaultRecoveryContextImpl) {
    BPELFaultRecoveryContextImpl bpelFaultRecoveryContextImpl = (BPELFaultRecoveryContextImpl) context;
    eventPayload = eventPayload.replace(“UNKNOWN_ECID”, bpelFaultRecoveryContextImpl.getECID());
}

return eventPayload;
}

Finally, the helper method to enqueue the event on AQ:

public void enqueueAqEvent(String input, UUID uuid) throws JMSException, NamingException, IOException {
Session session = null;
MessageProducer publisher = null;
TextMessage message = null;
Context context = new InitialContext();
Properties properties = new Properties();
InputStream is = this.getClass().getClassLoader().getResourceAsStream(“aq.datasource.properties”);
properties.load(is);
QueueConnectionFactory connectionFactory = (QueueConnectionFactory)context.lookup((String) properties.get(“aq.queueconnectionfactory”));
javax.jms.Connection connection = connectionFactory.createConnection();
Queue queue = (Queue) context.lookup((String) properties.get(“aq.queue”));
session = connection.createSession(true, 0);
publisher = session.createProducer(queue);
message = session.createTextMessage(input);
message.setJMSCorrelationID(uuid.toString());
publisher.send(message);
}

I used the following properties file that defines the AQ connection factory and queue itself. You need to make sure these JNDI destinations exist on the Oracle WebLogic Server on which Oracle SOA Suite runs:

aq.queueconnectionfactory = aqjms/XAQueueConnectionFactory
aq.queue = eis/aqjms/ALG_ADMIN_QUEUE

Deploying the Java Fault Handler
You cannot just deploy the resulting JAR file containing the above Java class to Oracle SOA Suite. As documented in the Oracle Fusion Middleware Developer’s Guide for Oracle SOA Suite 11g you need to do the following:
You can add custom classes and JAR files to an SOA composite application. A SOA extension library for adding extension classes and JARs to an SOA composite application is available in the $ORACLE_HOME/soa/modules/oracle.soa.ext_11.1.1 directory. 
To add custom JARs:
  1. Copy the JAR files to this directory or its subdirectory.
  2. Run ant.
  3. Restart Oracle WebLogic Server.
This is required because of library classloading among others.

Read more on fault handling in part IV of this blog series.

No comments:

Post a Comment