Saturday, 5 March 2011

ErrorHandling in SOA 11g

In SOA 11g we can go for common error handling approach to capture fault at component and composite level.In this test cases I’ve one HelloWorld bpel process ,just prints hello.We cave another parent process,CallHelloWorldComposite that calls Hello process and here we’ll implement the fault policy.

To implement the Error Handler we need fault-policies.xml and fault-bindings.xml file.You can access those files locally from your project folder as well as from MDS or some other places.

image

Here in this case policies files are there in local project folder and in this case you need to just create those file and no entry in composite.xml is required.

But to access fault policy file from other places you need to add below properties in composite.xml,In this case I added policy at composite level.

image

You can give full path of either directory structure or MDS path in those values.

Now we need to design fault-policies.xml file to capture all kind of faults and actions need to be taken if error occurred.You can add your custom java code to perform any additional task like send email notification or enqueing data into custom error queue.Here is my fault-policies.xml file,

*******************************************************************************

<?xml version="1.0" encoding="UTF-8" ?>
<faultPolicies xmlns="http://schemas.oracle.com/bpel/faultpolicy">
  <faultPolicy version="2.0.1" id="commonErrorHandler"
               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 xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
                 name="bpelx:remoteFault">
   
        <condition>
          <action ref="ora-retry"/>
        </condition>
      
     
      </faultName>
      <faultName xmlns:medns="http://schemas.oracle.com/mediator/faults"
                 name="medns:mediatorFault">
        <condition>
          <action ref="ora-cust"/>
        </condition>
      </faultName>
      <faultName xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
                 name="bpelx:bindingFault">
        <condition>
          <action ref="ora-errorQ"/>
        </condition>
      </faultName>
      <faultName xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
                 name="bpelx:runtimeFault">
        <condition>
          <action ref="ora-errorQ"/>
        </condition>
      </faultName>
    </Conditions>
    <Actions>
      <Action id="ora-terminate">
        <abort/>
      </Action>
      <Action id="ora-rethrow-fault">
        <rethrowFault/>
      </Action>
      <Action id="ora-replay-scope">
        <replayScope/>
      </Action>
      <Action id="ora-human-intervention">
        <humanIntervention/>
      </Action>
      <Action id="ora-retry">
        <retry>
          <retryCount>3</retryCount>
          <retryInterval>2</retryInterval>
          <exponentialBackoff/>
          <retryFailureAction ref="send-notification"/>
          <retrySuccessAction ref="ora-errorQ"/>
        </retry>
      </Action>
      <Action id="ora-cust">
        <javaAction className="com.shrik.TestJavaAction"
                    defaultAction="ora-terminate"
                    propertySet="send-notification-properties">
          <returnValue value="REPLAY" ref="ora-terminate"/>
          <returnValue value="RETRHOW" ref="ora-rethrow-fault"/>
          <returnValue value="ABORT" ref="ora-terminate"/>
          <returnValue value="RETRY" ref="ora-retry"/>
          <returnValue value="MANUAL" ref="ora-human-intervention"/>
        </javaAction>
      </Action>
      <Action id="ora-errorQ">
        <javaAction className="com.shrik.ErrorHospitalQueue"
                    defaultAction="ora-terminate"
                    propertySet="enqueue-properties">
          <returnValue value="REPLAY" ref="ora-terminate"/>
          <returnValue value="RETRHOW" ref="ora-rethrow-fault"/>
          <returnValue value="ABORT" ref="ora-terminate"/>
          <returnValue value="RETRY" ref="ora-retry"/>
          <returnValue value="MANUAL" ref="ora-human-intervention"/>
        </javaAction>
      </Action>
      <Action id="send-notification">
        <javaAction className="com.shrik.ErrorHospitalNotification"
                    defaultAction="ora-human-intervention"
                    propertySet="send-notification-properties">
          <returnValue value="MANUAL" ref="ora-human-intervention"/>
        </javaAction>
      </Action>
    </Actions>
    <!-- Property sets used by custom Java actions -->
    <Properties>
      <propertySet name="send-notification-properties">
        <property name="from"><Give from address></property>
        <property name="to"><Give To Address></property>
        <property name="subject">Test Mail</property>
        <property name="text">Environment: TEST</property>
        <property name="host"><smtp host server></property>
        <property name="port"><smtp port></property>
        <property name="username"><user name></property>
        <property name="password"><password></property>
      </propertySet>
      <propertySet name="enqueue-properties">
        <property name="aq.queueconnectionfactory">aqjms/XAQueueConnectionFactory</property>
          <property name="aq.queue">jms/errorQ</property>
      </propertySet>
    </Properties>
  </faultPolicy>
</faultPolicies>
****************************************************************************************

and here is my fault-bindings.xml file,

<?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="commonErrorHandler"/>
</faultPolicyBindings>


****************************************************************************************

If HelloWorld endpoint is unreachable then  bpelx:remoteFault will happen and as per fault policy it will execure ora-retry action,will try to retry the endpoint 3 times in 2,4,8 seconds intervals and upon subsequent failure it will invoke com.shrik.ErrorHospitalNotification class with send-notification-properties to notify faults to users.

To write your custom java code,create a new project like,

image

in this project we need to import some jars from <OracleMiddlewareHome>/Oracle_SOA1/soa/modules/oracle.soa.bpel_11.1.1 ,oracle.soa.fabric_11.1.1 directory.

For my case here is the code excerpt ,

For sending email notification from fault policy(ErrorHospitalNotification.java),

****************************************************************************************

package com.shrik;

import com.collaxa.cube.engine.fp.BPELFaultRecoveryContextImpl;


import java.util.ArrayList;
import java.util.Map;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import oracle.integration.platform.faultpolicy.IFaultRecoveryContext;
import oracle.integration.platform.faultpolicy.IFaultRecoveryJavaClass;


public class ErrorHospitalNotification implements IFaultRecoveryJavaClass {
    private String from;
    private String to;
    private String subject;
    private String text;
    private String host;
    private String port;
    private String username;
    private String password;
    private Properties props;

    public ErrorHospitalNotification() {
        super();
    }

    private void sendMail() {
        props = new Properties();
        props.put("mail.smtp.host", getHost());
        props.put("mail.smtp.port", getPort());
        props.put("mail.transport.protocol", "smtp");
        props.setProperty("mail.smtps.quitwait", "false");
        props.put("mail.smtp.auth", "true");
        Authenticator auth = new javax.mail.Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(getUsername(),
                                                  getPassword());
            }
        };
        Session mailSession = Session.getDefaultInstance(props, auth);
        Message simpleMessage = new MimeMessage(mailSession);
        try {
            InternetAddress fromAddress = new InternetAddress(from);
            simpleMessage.setFrom(fromAddress);
            String toAddresses[] = to.split(";");
            if (toAddresses != null && toAddresses.length > 0) {
                InternetAddress toInternetAddresses[] =
                    new InternetAddress[toAddresses.length];
                for (int i = 0; i < toAddresses.length; i++)
                    toInternetAddresses[i] =
                            new InternetAddress(toAddresses[i]);

                simpleMessage.setRecipients(javax.mail.Message.RecipientType.TO,
                                            toInternetAddresses);
            }
            simpleMessage.setSubject(subject);
            simpleMessage.setText(text);
            Transport.send(simpleMessage);
        } catch (AddressException e) {
            System.out.println("Error formatting Internet Email Address: " +
                               e.getMessage().toString());
            e.printStackTrace();
        } catch (MessagingException e) {
            System.out.println("Error sending email: " +
                               e.getMessage().toString());
            e.printStackTrace();
        }
    }

    private String getParameterValue(ArrayList parameterList) {
        String value = null;
        if (parameterList != null && parameterList.size() > 0)
            value = (String)parameterList.get(0);
        return value;
    }

    public void handleRetrySuccess(IFaultRecoveryContext iFaultRecoveryContext) {
        BPELFaultRecoveryContextImpl bpelCtx =
            (BPELFaultRecoveryContextImpl)iFaultRecoveryContext;
        Map properties = iFaultRecoveryContext.getProperties();
        if (properties != null && properties.size() == 8) {
            setFrom(getParameterValue((ArrayList)properties.get("from")));
            setTo(getParameterValue((ArrayList)properties.get("to")));
            setSubject(getParameterValue((ArrayList)properties.get("subject")) +
                       " " + "Retry Success");
            setText("The exception that occurred when processing " +
                    bpelCtx.getTitle() + " was successfully retried.\n" +
                    "This message was automatically generated, please do not reply to it.");
            setHost(getParameterValue((ArrayList)properties.get("host")));
            setPort(getParameterValue((ArrayList)properties.get("port")));
            setUsername(getParameterValue((ArrayList)properties.get("username")));
            setPassword(getParameterValue((ArrayList)properties.get("password")));
            sendMail();
        }
    }


    public String handleFault(IFaultRecoveryContext iFaultRecoveryContext) {
        Map properties = iFaultRecoveryContext.getProperties();

        BPELFaultRecoveryContextImpl bpelCtx =
            (BPELFaultRecoveryContextImpl)iFaultRecoveryContext;

        if (properties != null && properties.size() == 8) {
            setFrom(getParameterValue((ArrayList)properties.get("from")));
            setTo(getParameterValue((ArrayList)properties.get("to")));
            setSubject(getParameterValue((ArrayList)properties.get("subject")) +
                       bpelCtx.getTitle());
            setText(getParameterValue((ArrayList)properties.get("text")) +
                    "BPEL Process Instance: " + bpelCtx.getInstanceId() +
                    " needs intervention to recover from a technical exception: " +
                    bpelCtx.getFault().getMessage() +
                    "Check the Activities tab in the BPEL Management Console in order to resolve the error as soon as possible. This message was automatically generated, please do not reply to it.");
            setHost(getParameterValue((ArrayList)properties.get("host")));
            setPort(getParameterValue((ArrayList)properties.get("port")));
            setUsername(getParameterValue((ArrayList)properties.get("username")));
            setPassword(getParameterValue((ArrayList)properties.get("password")));
            bpelCtx.addAuditTrailEntry("Sending Email...");
            sendMail();
        }

        return "MANUAL";
    }


    public void setFrom(String from) {
        this.from = from;
    }

    public String getFrom() {
        return from;
    }

    public void setTo(String to) {
        this.to = to;
    }

    public String getTo() {
        return to;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getSubject() {
        return subject;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public String getHost() {
        return host;
    }

    public void setPort(String port) {
        this.port = port;
    }

    public String getPort() {
        return port;
    }

    public void setProps(Properties props) {
        this.props = props;
    }

    public Properties getProps() {
        return props;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getUsername() {
        return username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPassword() {
        return password;
    }

}

****************************************************************************************

Now your custom java code should be referenced by weblogic server,For that,

  1. Create a jar file containing all your custom java code.
  2. Place the jar file in <OracleMiddlewareHome>/Oracle_SOA1/soa/modules/oracle.soa.ext_11.1.1 directory.
  3. Make sure ANT/bin is set in your classpath.
  4. and just run ant from that directory and eventually it will generate oracle.soa.ext.jar file.
  5. Start the weblogic server.

Now deploy the HelloWorld and caller process and turn helloworld endpoint off from em.

Now when you run CallHelloWorldComposite then definitely it will throw remote fault and parse your fault policy file.

After retrying it will send notification and go to manual intervention for recovery.

You can extend your Error Handling Framework as per your project need.

15 comments:

vivek said...

Hi,Excellent Article..
Can we call a webService/BPEL Process from the Java Action ?
What’s the Trade-off in terms of performance?
I want to invoke a BPEL Service,when mediator results in a Fault.

Thanks
Vivek

shrikworld said...

Hi, thanks for your complement.Here are your answers,
Can we call a webService/BPEL Process from the Java Action --> Yes its possible.For that you have write code for invoking soap service.
What’s the Trade-off in terms of performance --> If there is complex code definitely custom java action degrade the perfomance although its very negligible, because your classes would be loaded during the startup of weblogic server.

I want to invoke a BPEL Service,when mediator results in a Fault--> yes its feasible , will post one blog on that.

Yatan said...

I am your fan after reading your blocks, nice work dude.

Anonymous said...

Hi Shrik,

Great article! I have a requirement where I need to perform the following steps when a remote/binding/run-time fault occurs:

1. Log the fault details into the DB (performed in the catch block)
2. Email the fault details to the Admin (performed in the catch block)
3. Recover the process manually in the EM console by performing a

Hence, I would assume I would need to re-throw the fault first to the catch block first and then manually intervene:










I also reversed the order to manually intervene first and then re-throw the fault but that too isn't working.

But it does not perform both these actions. At any given point, only one action is performed for a given condition. How do I achieve both a re-throw and a manual intervention actions for the same fault condition?

Raju said...

hi shirik

i also have the same requirement as the above post .could you please reply on that

regards
siva

Raju said...

hi shirik

i have the same requirement as above please reply'

Regards
raju

pavan4s said...

Hi Shirik,

Can we pass parameters dynamically?


Here i want to pass from-address from bpel process or is there any chance of getting invoke variable name and data(invoke where we got the fault)

Regards

PavanKumar M

pavan4s said...

Hi Shirik,

Can we pass parameters dynamically?


Here i want to pass from-address from bpel process or is there any chance of getting invoke variable name and data(invoke where we got the fault)

Regards

PavanKumar M

Raju said...

hi shrik
Is it possible to send the variable data into the property section of fault policies.if yes could you tell me how to do it . TIA

Regards
Raju

Rajashekar Reddy said...

nice explanation....

Shreekanta Roy Chowdhury , i could not see the ErrorHosiptalQueue.java.
whihc is used to insert the error log to DB.could please mail me?

Unknown said...

Can u plz tellme diff between application server and weblogic server


Regards
Ram

Daniela Valadez said...

Thanks for writing this up, your Java class helped me out in implementing my own :) Just a question though, is it possible to reference the classname from the MDS repository? I haven't found any documention for doing so... Thanks again!

Unknown said...

Hi,

As mentioned by vivek ,i have a requirement to call a webService/BPEL Process from the Java Action

If anyone already implemented...Could you please share the code.

Regards,
Raju.

Souvik said...

Hi Shirik,
I am not getting email notification.I have done all the steps as you mentioned and also successfully tested the Email part from em console-->soa-infra-->notification management

I am using your same java code and include it to oracle.soa.ext_11.1.1 directory.

My Fault-policy is little different than yours.





















/SAN/oracle/Middleware/user_projects/applications/my_domain/Error
rejmsg_Build_%ID%_%TIMESTAMP%.xml




3
2






















Email:macot@abc.com
Email:PalSO@abc.com
SOAEXCEPTION
Environment:TEST
mail.abc.com.sa
25
weblogic
password





1>For BuildRawMaterialPull fault ,message is moved to /SAN/oracle/Middleware/user_projects/applications/my_domain/Error directory as per fault-policies.xml

2> For ConsumeRawMaterialPull fault, there is no notification as it should call and then

Please suggest.

Anonymous said...

A secret web hosting solution of the business-boosting!!!!!!! Thanks for sharing your golden information, I like this blog posting and I say that get amazing web hosting solutions.
UK VPS Server Hosting