Oracle SOA suite comes with fault handling framework which is a collection of sub modules to automate handling of faults .
For introduction of fault handling in composites, please visit Oracle's FMW Developer's Guide for Oracle SOA Suite
Two important files in fault framework are
<Action id="ora-custom-java">
For introduction of fault handling in composites, please visit Oracle's FMW Developer's Guide for Oracle SOA Suite
Two important files in fault framework are
fault-policies.xml
fault-bindings.xml
fault-policies.xml: Talks about what kind of faults it can handle and how. Fault policy file defines fault conditions and their corresponding fault recovery actions.
fault-bindings.xml: Talks about binding of fault-policies with composite and its components or scope of fault-policies.
As part of fault-policies.xml, we can mention various types of recovery actions like retry,re-throw,human-intervention,replay,terminate and many more.Java action is one of them.
Fault-poloicies.xml
<?xml version="1.0" encoding="UTF-8" ?>
<faultPolicies xmlns="http://schemas.oracle.com/bpel/faultpolicy">
<faultPolicy version="2.0.1"
id="ProcessingFaults"
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.oracle.com/bpel/faultpolicy"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Conditions>
<!-- remote fault processing starts here: -->
<faultName xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
name="bpelx:remoteFault">
<condition>
<action ref="ora-retry"/>
</condition>
</faultName>
<!-- binding fault processing starts here: -->
<faultName xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
name="bpelx:bindingFault">
<condition>
<action ref="ora-retry"/>
</condition>
</faultName>
</Conditions>
<!-- Above two conditions indicates perform retry actions for binding and remote faults -->
<Actions>
<!-- RetryInterval is in seconds. This action handles our retry requirement and in case retry also failed then that chains to custom java action -->
<Action id="ora-retry">
<retry>
<retryCount>3</retryCount>
<retryInterval>5</retryInterval>
<exponentialBackoff/>
<retryFailureAction ref="ora-custom-java"/>
<!--in case retry also failed then that chains control to java action-->
</retry>
</Action>
<Action id="ora-custom-java">
<!-- this is user provided custom java class. This action handles notification requirement -->
<javaAction className="
com.fault.handler.
JavaFaultHandler
"
defaultAction="ora-human-intervention" propertySet="notification-properties">
<returnValue value="RETRHOW" ref="ora-rethrow-fault"/>
<!-- If java class returns
RETRHOW then action
"ora-rethrow-fault"
is invoked -->
<returnValue value="MANUAL" ref="ora-human-intervention"/>
<!-- If java class returns
MANUAL
then action
"
ora-human-intervention
"
is invoked -->
</javaAction>
</Action>
<!-- This action re throws fault back to BPEL Catch/CatchAll-->
<Action id="ora-rethrow-fault">
<
rethrowFault/>
<
/Action
>
<!-- Human Intervention. This action handles human intervention part-->
<Action id="ora-human-intervention">
<humanIntervention/>
</Action>
</Actions>
<!-- Below properties are read from java class-->
<Properties>
<propertySet name="notification-properties">
<property name="email_to">team1@gmail.com</property>
<property name="email_cc">team2@gmail.com</property>
<property name="commonErrorHandlingProcess">CommonErrorHandlingBPEL</property>
<property name="domain">default</property>
</propertySet>
</Properties>
</faultPolicy>
</faultPolicies>
fault-bindings.xml
<?xml version="1.0" encoding="UTF-8" ?>
<faultPolicyBindings version="2.0.1"
xmlns="http://schemas.oracle.com/bpel/faultpolicy"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<composite faultPolicy="ProcessingFaults"/>
</faultPolicyBindings>
This bindings file binds fault recovery actions to composite level.i.e all components with in composite.xml
Now let's see how we can write a custom java class plugged into fault handling mechanism.
Co-locate both xml files with composite.xml.
Please create a java project in Jdev and add following libraries to project class-path.
BPEL Runtime
Oracle.soa.fabric.jar
Custom Java action class
package com.fault.handler;
import com.fault.handler.Exception;
import com.collaxa.cube.engine.fp.BPELFaultRecoveryContextImpl;
import oracle.integration.platform.faultpolicy.IFaultRecoveryContext;
import oracle.integration.platform.faultpolicy.IFaultRecoveryJavaClass;
oracle.integration.platform.faulthandling.recovery.RejectedMsgRecoveryContext;
import java.util.Map;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import java.io.StringWriter;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
public class JavaFaultHandler implements IFaultRecoveryJavaClass {
public void handleRetrySuccess(IFaultRecoveryContext iFaultRecoveryContext) {
System.out.println("Retry Success Happend...");
// handleFault(iFaultRecoveryContext);
}
private String nodeToString(Node node) {
StringWriter sw = new StringWriter();
try {
Transformer t = TransformerFactory.newInstance().newTransformer();
t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
t.transform(new DOMSource(node), new StreamResult(sw));
} catch (TransformerException te) {
System.out.println("nodeToString Transformer Exception");
}
return sw.toString();
}
//Below method will be invoked by fault handling mechanism when there is a fault.
public String handleFault(IFaultRecoveryContext iFaultRecoveryContext) {
try{
Exception excObj = new Exception();
if(iFaultRecoveryContext instanceof BPELFaultRecoveryContextImpl){
// Get BPEL specific context here
BPELFaultRecoveryContextImpl bpelCtx =
(BPELFaultRecoveryContextImpl)iFaultRecoveryContext;
// bit of log statements for debug purpose
System.out.println("*** BPEL Context + getComponentInstanceId ***: " +
bpelCtx.getComponentInstanceId());
System.out.println("*** BPEL Context + getFault ***: " +
bpelCtx.getFault());
System.out.println("*** BPEL Context+ getInstanceId ***: " +
bpelCtx.getInstanceId());
System.out.println("*** BPEL Context + getCompositeTitle ***: " +
bpelCtx.getTitle());
System.out.println("*** BPEL Context + FaultedProcess Revision ***:"+
bpelCtx.getProcessDN().getRevision());
try{
// This code assumes all BPELs will have a variable called-
faultHandlerVariable
which is defined on canonical xsd containing generic error data
Element root =(Element) bpelCtx.getVariableData
("faultHandlerVariable", "payload", "/");
Node exception = root.getFirstChild();
String errorDataStr = nodeToString(
exception
);
//Setting business payload data
excObj.setBusinessPayload(errorDataStr);
} catch (Exception e){
//Ignore this exception; because setting this business payload data is optional for my requirement
;
}
//Setting BPEL specific error data
excObj.setErrorCode((bpelCtx.getFault().getFaultName().toString().contains("remoteFault"))?"remoteFault":"bindingFault");
excObj.setErrorMessage(bpelCtx.getFault().getMessage().toString());
excObj.setErrorInstanceId(bpelCtx.getInstanceId());
excObj.setErrorProcessId( bpelCtx.getCompositeName());
excObj.setErrorProcessVersion(bpelCtx.getProcessDN().getRevision());
} else if (iFaultRecoveryContext instanceof RejectedMsgRecoveryContext) {
//Get Rejected messages context here
System.out.println("*** iFaultRecoveryContext is an instanceof RejectedMsgRecoveryContext ***");
System.out.println("==========================================================");
} else{
//Get Non-BPEL context here, if error is raised from other than BPEL component
System.out.println("*** iFaultRecoveryContext is neither instanceof BPELFaultRecoveryContextImpl nor RejectedMsgRecoveryContext***");
System.out.println("====================================");
}
//Setting Email error data
excObj.steEmailTo(props.get("email_to").toString().substring(1, props.get("email_to").toString().length()-1));
excObj.setEmailCC(props.get("email_cc").toString().substring(1, props.get("email_cc").toString().length()-1));
excObj.setDomainId(props.get("domain").toString().substring(1, props.get("domain").toString().length()-1));
//Setting CommonStatusLogger Process invocation context data
excObj.setCommonEHProcessName(props.get("commonEH_process").toString().substring(1, props.get("commonEH_process").toString().length()-1));
//
CommonStatusLoggerDirectBinding
direct binding Invocation
Please refer to SOA direct binding API This call invokes a composite which sends email.I am passing all error related data and email notification details as an object.
CommonStatusLoggerDirectBinding ceh =new
CommonStatusLoggerDirectBinding
();
String status = ceh.invokeCommonErrorStatusDirect(excObj);
if (status == "S")
return "MANUAL";
else
return "RETRHOW";
}
catch(Exception e){
System.out.println("***JavaFaultHandler Exception******\n"+ e.getMessage());
e.printStackTrace();
return "RETRHOW";
}
}
}
Bean Utility class
package com.fault.handler;
import java.util.Date;
//This BEAN class represents all the common attributes any fault handler requires.
public class
Exception
{
protected String errorCode;
protected String errorMessage;
protected Date errorTime= new Date();
protected String domainId="default";
protected String errorProcessId;
protected String errorProcessVer;
protected String errorProcessURL;
protected Long errorInstanceId;
protected String fileName;
protected String payload;
protected String fileDate;
protected String sourceSystem;
protected String reference;
protected String emailTo="team1@gmail.com";
protected String emailCC;
protected String errorPartnerLink;
protected String subject="Runtime Error: ";
protected String providerURL;
protected String initialContext="weblogic.jndi.WLInitialContextFactory";
protected String securityCredential;
protected String securityPrinciple;
protected String commonEHProcessName="CommonErrorHandlerProcess";
protected String commonEHProcessVer="1.0";
protected String commonEHURL;
protected String errorPayload;
protected String businessPayload;
public Exception() {
super();
}
//Setter methods
public void setErrorCode (String errorCode ){
this.errorCode = errorCode;
}
public void setErrorMessage (String errorMessage){
this.errorMessage = errorMessage;
}
public void setErrorTime (Date errorTime){
this.errorTime = errorTime;
}
public void setDomainId (String domainId){
this.domainId = domainId;
}
public void setErrorProcessId (String errorProcessId){
this.errorProcessId = errorProcessId;
}
public void setErrorProcessVersion (String errorProcessVersion){
this.errorProcessVer = errorProcessVersion;
}
public void setErrorProcessURL (String errorProcessURL){
this.errorProcessURL = errorProcessURL;
}
public void setErrorInstanceId (Long errorInstanceId){
this.errorInstanceId = errorInstanceId;
}
public void setFileName (String fileName){
this.fileName = fileName;
}
public void setPayload (String payload){
this.payload = payload;
}
public void setFileDate (String fileDate){
this.fileDate = fileDate;
}
public void setSourceSystem (String sourceSystem){
this.sourceSystem = sourceSystem;
}
public void setReference (String reference){
this.reference = reference;
}
public void steEmailTo (String emailTo){
this.emailTo = emailTo;
}
public void setEmailCC (String emailCC){
this.emailCC = emailCC;
}
public void setErrorPartnerLink (String errorPartnerLink){
this.errorPartnerLink = errorPartnerLink;
}
public void setSubject (String subject){
this.subject = subject;
}
public void setProviderURL (String providerURL){
this.providerURL = providerURL;
}
public void setInitalContext (String initialContext){
this.initialContext = initialContext;
}
public void setSecurityCredential (String securityCredential){
this.securityCredential = securityCredential;
}
public void setSecurityPrinciple (String securityPrinciple){
this.securityPrinciple = securityPrinciple;
}
public void setCommonEHProcessName (String commonEHProcessName){
this.commonEHProcessName = commonEHProcessName;
}
public void setCommonEHProcessVer (String commonEHProcessVer){
this.commonEHProcessVer = commonEHProcessVer;
}
public void setCommonEHURL (String commonEHURL){
this.commonEHURL = commonEHURL;
}
public void setBusinessPayload (String businessPayload){
this.businessPayload = businessPayload;
}
//Getter methods
public String getErrorCode ( ){
return this.errorCode;
}
public String getErrorMessage (){
return this.errorMessage;
}
public Date getErrorTime (){
return this.errorTime ;
}
public String getDomainId (){
return this.domainId ;
}
public String getErrorProcessId (){
return this.errorProcessId ;
}
public String getErrorProcessVersion (){
return this.errorProcessVer ;
}
public String getErrorProcessURL (){
return this.errorProcessURL ;
}
public Long getErrorInstanceId (){
return this.errorInstanceId ;
}
public String getFileName (){
return this.fileName ;
}
public String getPayload (){
return this.payload ;
}
public String getFileDate (){
return this.fileDate ;
}
public String getSourceSystem (){
return this.sourceSystem ;
}
public String getReference (){
return this.reference ;
}
public String getEmailTo (){
return this.emailTo ;
}
public String getEmailCC (){
return this.emailCC ;
}
public String getErrorPartnerLink (){
return this.errorPartnerLink ;
}
public String getSubject (){
return this.subject;
}
public String getProviderURL (){
return this.providerURL;
}
public String getInitialContext (){
return this.initialContext;
}
public String getSecurityCredential (){
return this.securityCredential;
}
public String getSecurityPrinciple (){
return this.securityPrinciple;
}
public String getCommonEHProcessName (){
return this.commonEHProcessName ;
}
public String getCommonEHProcessVer (){
return this.commonEHProcessVer;
}
public String getCommonEHURL (){
return this.commonEHURL;
}
public String getBusinessPayload (){
return this.businessPayload;
}
public String toString(){
errorPayload =
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
"
<
BPELException xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
"xsi:schemaLocation=\"http://www.example.net/BPELException CommonErrorHandlerProcessInput.xsd\"\n" +
" xmlns=\"http://www.example.net/BPELException\">\n" +
"
<
ErrorCode>"+getErrorCode()+"
<
/ErrorCode>\n" +
"
<
ErrorMessage>"+getErrorMessage()+"
<
/ErrorMessage
>
\n" +
"
<
ErrorTime>"+getErrorTime()+"
<
/ErrorTime
>
\n" +
"
<
DomainId>"+getDomainId()+"
<
/DomainId
>
\n" +
"
<
ProcessId>"+getErrorProcessId()+"
<
/ProcessId
>
\n" +
"
<
ProcessVersion>"+getErrorProcessVersion()+"
<
/ProcessVersion
>
\n" +
"
<
ProcessURL>"+getErrorProcessURL()+"
<
/ProcessURL
>
\n" +
"
<I
nstanceId>"+getErrorInstanceId()+"
<
/InstanceId
>
\n" +
"
<
FileName>"+getFileName()+"
<
/FileName
>
\n" +
"
<
payload>"+getBusinessPayload()+"
<
/payload
>
\n" +
"
<
FileDate>"+getFileDate()+"
<
/FileDate
>
\n" +
"
<
SourceSystem>"+getSourceSystem()+"
<
/SourceSystem
>
\n" +
"
<
Reference>"+getReference()+"
<
/Reference
>
+
"
<
EmailTo>"+getEmailTo()+"
<
/EmailTo
>
\n" +
"
<
EmailCC>"+getEmailCC()+"
<
/EmailCC
>
\n" +
"
<
/BPELException
>
\n" ;
return this.errorPayload;
}
}
Configuring Java class
Pack above classes into jar
stop WLS server
Place them in $ORACLE_HOME/soa/modules/oracle.soa.ext_11.1.1
run ant from same location
Restart Oracle WebLogic Server
Now code is ready for testing.
In a nutshell what we are trying to implement is, whenever there is either remote or binding fault in HellowWorld1 composite, then email notification should be sent out to configured users and human intervention should be waiting for someone to log in and correct payload and resubmit.
How to test
Create HelloWorld1 and HelloWorld2 composites.
HelloWorld1 invokes HelloWorld2.
Place fault-policies.xml and fault-bindings.xml into HellowWorld1 project and deploy both.Now retire HellowWorld2.Initiate HellowWorld1