What I'm trying to achieve: Custom fault handling action on my fault policies that can publish a file to my file system before any handled fault is delivered to manual intervention on recovery EM area. This way will allow me to alert via platform management tool that an error occurred. Now, I want this flexible enough so I can change file content and location based on different targeted environments during my application promotion.
Now:
package sample.faulthandling.custom.action;
import com.collaxa.cube.engine.fp.BPELFaultRecoveryContextImpl;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Map;
import java.util.Properties;
import oracle.integration.platform.faultpolicy.IFaultRecoveryContext;
import oracle.integration.platform.faultpolicy.IFaultRecoveryJavaClass;
public class logging implements IFaultRecoveryJavaClass {
public void handleRetrySuccess(IFaultRecoveryContext ctx) {
System.out.println("This is for retry success");
handleFault(ctx);
}
public String handleFault(IFaultRecoveryContext ctx) {
System.out.println(" #### EXAMPLE ###### Action context:\n" +
ctx.toString());
// Get BPEL specific context here
BPELFaultRecoveryContextImpl bpelCtx =
(BPELFaultRecoveryContextImpl)ctx;
// Writing an audit entry
bpelCtx.addAuditTrailEntry(" ### SAMPLE Custom Fault Handling Example ### ");
// Getting details
System.out.println("Policy Id: " + ctx.getPolicyId());
System.out.println("Composite Name: " + bpelCtx.getCompositeName());
Map<String, ArrayList> props = ctx.getProperties();
String logFileName = (String)((ArrayList)props.get("logFileName")).get(0);
String logFileDir = (String)((ArrayList)props.get("logFileDir")).get(0);
String message = (String)((ArrayList)props.get("message")).get(0);
String content = message + " - Composite:" + bpelCtx.getCompositeName() + " InstanceID:" + bpelCtx.getCompositeInstanceId()
+ " Activity:" + bpelCtx.getActivityName() + " Fault:" + bpelCtx.getFault();
File file = new File(logFileDir + logFileName);
try {
if (!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(content);
bw.close();
} catch (Exception e) {
}
return "MANUAL";
}
}
Now, deploy to a JAR file using the created deployment profile.
1. Copy the deployed JAR file to the "oracle.soa.ext_11.1.1" directory
Note: You will find this SOA extension in [fmw_home]/Oracle_SOA1/soa/modules/oracle.soa.ext_11.1.1/
2. Update the environment variables running the appropriate domain setDomainEnv.sh
Note: [fmw_home]/user_projects/domains/[your_domain]/bin
Implementation
- Create a generic JDeveloper project leaving the default options.
- Add JAVA technology. Accept the creation of a new project and define the name.
- Define the default package where to create your java classes
- Add the necessary libraries
- BPEL Runtime
- SOA Runtime
Note: Right Click on project and choose Project Properties to access to Libraries and Classpath option.
Now:
- Create a new class (eg. Logging) inside the defined default package
- Copy/Paste the following code to the created class (Note: the package name should match the default package name that you defined)
import com.collaxa.cube.engine.fp.BPELFaultRecoveryContextImpl;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Map;
import java.util.Properties;
import oracle.integration.platform.faultpolicy.IFaultRecoveryContext;
import oracle.integration.platform.faultpolicy.IFaultRecoveryJavaClass;
public class logging implements IFaultRecoveryJavaClass {
public void handleRetrySuccess(IFaultRecoveryContext ctx) {
System.out.println("This is for retry success");
handleFault(ctx);
}
public String handleFault(IFaultRecoveryContext ctx) {
System.out.println(" #### EXAMPLE ###### Action context:\n" +
ctx.toString());
// Get BPEL specific context here
BPELFaultRecoveryContextImpl bpelCtx =
(BPELFaultRecoveryContextImpl)ctx;
// Writing an audit entry
bpelCtx.addAuditTrailEntry(" ### SAMPLE Custom Fault Handling Example ### ");
// Getting details
System.out.println("Policy Id: " + ctx.getPolicyId());
System.out.println("Composite Name: " + bpelCtx.getCompositeName());
Map<String, ArrayList> props = ctx.getProperties();
String logFileName = (String)((ArrayList)props.get("logFileName")).get(0);
String logFileDir = (String)((ArrayList)props.get("logFileDir")).get(0);
String message = (String)((ArrayList)props.get("message")).get(0);
String content = message + " - Composite:" + bpelCtx.getCompositeName() + " InstanceID:" + bpelCtx.getCompositeInstanceId()
+ " Activity:" + bpelCtx.getActivityName() + " Fault:" + bpelCtx.getFault();
File file = new File(logFileDir + logFileName);
try {
if (!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(content);
bw.close();
} catch (Exception e) {
}
return "MANUAL";
}
}
1. Create a new deployment profile to
generate a JAR file (e.g. CustomFaultJavaAction.jar)
Note: Right Click on project and choose Project Properties to access to Deployment Profiles.
Now, deploy to a JAR file using the created deployment profile.
Deployment
1. Copy the deployed JAR file to the "oracle.soa.ext_11.1.1" directory
Note: You will find this SOA extension in [fmw_home]/Oracle_SOA1/soa/modules/oracle.soa.ext_11.1.1/
2. Update the environment variables running the appropriate domain setDomainEnv.sh
Note: [fmw_home]/user_projects/domains/[your_domain]/bin
3. soa.ext build file uses If condition, default ANT installation available on SOA suite is not ready to use If conditions by default. It will be necessary to update both Ant Library and soa.ext build file to be able to incorporate this functionality. So you have to:
- Download ant contrib jar file http://switch.dl.sourceforge.net/project/ant-contrib/ant-contrib/ant-contrib-1.0b2/ant-contrib-1.0b2-bin.zip
- Unzip file and copy lib/ant-contrib.jar to your Ant lib folder
Note: Ant is available on your SOA Suite installations. The location is: [fmw_home]/modules/org.apache.ant_1.7.1 - It is necessary to reference now the Ant Contrib library from the build.xml file used to build the SOA ext. So edit the build.xml file contained on oracle.soa.ext_11.1.1 folder and add the element <taskdef resource="net/sf/antcontrib/antlib.xml"/> after the project element.
4. Run Ant on oracle.soa.ext_11.1.1 folder. Your build target should produce then the following output:
[oracle@soabpm-vm oracle.soa.ext_11.1.1]$ /oracle/fmwhome/modules/org.apache.ant_1.7.1/bin/ant
Buildfile: build.xml
create-manifest-jar:
[echo] Creating oracle.soa.ext at /oracle/fmwhome/Oracle_SOA1/soa/modules/oracle.soa.ext_11.1.1/oracle.soa.ext.jar :/oracle/fmwhome/Oracle_SOA1/soa/modules/oracle.soa.ext_11.1.1/CustomFaultJavaAction.jar:/oracle/fmwhome/Oracle_SOA1/soa/modules/oracle.soa.ext_11.1.1/classes
BUILD SUCCESSFUL
Total time: 0 seconds
Note: Ant is available on your installations of SOA suite in:[fmw_home]/modules/org.apache.ant_1.7.1
5. Now it is time to restart your SOA server. :)
Fault Policy Configuration
1. The following example can be follow to be able to use the implemented custom fault action. Change your fault policy file to include the custom action following the next example:
<?xml version="1.0" encoding="UTF-8"?>
<faultPolicies xmlns="http://schemas.oracle.com/bpel/faultpolicy"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<faultPolicy version="0.0.1" id="FusionMidFaults"
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>
<faultName>
<condition>
<action ref="ora-retry"/>
</condition>
</faultName>
</Conditions>
<Actions>
<Action id="ora-retry">
<retry>
<retryCount>3</retryCount>
<retryInterval>2</retryInterval>
<exponentialBackoff/>
<retryFailureAction ref="my-custom-java"/>
</retry>
</Action>
<Action id="my-custom-java">
<!-- this is user provided class-->
<javaAction className="sample.faulthandling.custom.action.logging"
defaultAction="default-human-intervention"
propertySet="prop-for-my-monitoring">
<returnValue value="MANUAL" ref="default-human-intervention"/>
<returnValue value="ABORT" ref="default-terminate"/>
<returnValue value="RETHROW" ref="default-rethrow-fault"/>
</javaAction>
</Action>
<!-- Generics -->
<Action id="default-terminate">
<abort/>
</Action>
<Action id="default-replay-scope">
<replayScope/>
</Action>
<Action id="default-rethrow-fault">
<rethrowFault/>
</Action>
<Action id="default-human-intervention">
<humanIntervention/>
</Action>
</Actions>
<Properties>
<propertySet name="prop-for-my-monitoring">
<property name="logFileName">my-soa-faults.log</property>
<property name="logFileDir">/home/oracle/logs/</property>
<property name="message">### SAMPLE Custom Fault Handling Example ###</property>
</propertySet>
</Properties>
</faultPolicy>
</faultPolicies>
2. Deploy the policies file (composite or MDS) and test.
Conclusions
This will allow you to manage your properties per fault-policy referencing fault policies files that are available on MDS of the targeted server, managing this way the properties that will influence your fault handling custom actions depending on the environment of your application life cycle.