Showing posts with label BPEL. Show all posts

Implementing Quartz Scheduler in JDeveloper to call BEPL

Image result for jdeveloper logo


We will create a simple a web service proxy component, a scheduler job class that is called by the SOAScheduler and a java class SOASchedulerServlet that initiate the quartz scheduler.

1. To get started, create a new Application in JDeveloper by click CTRL-N, name it SOAScheduler,

2. select “Generic Application”.


3. Create a new Project named "SchedulerProject", select “Java” and “Web Services” as “Project Technologies”.


4. Click "Finish".

5. Create a new Web Service Proxy by click “File/New” or CRTL-N.


6. Click “OK” and “Next”.


7. Select “JAX-WS Style” and click “Next”.


8. Paste the WSDL location into “WSDL Document URL” and click “Next”.


9. Write “sample.oracle.otn.soascheduler.proxy” into “Package Name” and “sample.oracle.otn.soascheduler.proxy.types” into “Root Package for Generated Types” and click “Finish”.

10. In the new HelloWorldProcess_ptClient.java add the Line

System.out.println(helloWorldProcess.process("SOAScheduler"));

public static void main(String [] args)
{
helloworldprocess_client_ep = new Helloworldprocess_client_ep();
HelloWorldProcess helloWorldProcess = helloworldprocess_client_ep.getHelloWorldProcess_pt();
// Add your code to call the desired methods.
System.out.println(helloWorldProcess.process("SOAScheduler"));
}

11. Click on F11 or on the run icon . The composite will be executed by the new generated service proxy.

In the message window you will see the correct output of SOA example composite.


Add Quartz library to the project


1. Click on “Application”  “Project Properties”, “Add JAR/Directory…”.


2. Select in your JDeveloper home “…\jdeveloper\soa\modules\quartz-all-1.6.5.jar”. Click “Select”.


3. Click “OK”.


Creating the Scheduler Job Component


1. Create a new “Java Class” in JDeveloper by click “File/New” or CRTL-N...


2. Click “OK”.


3. Set the Name to “HelloWorldJob” and Package to “sample.oracle.otn.soascheduler.job” and click “OK”.

4. Replace the generated source with the following lines.

package sample.oracle.otn.soascheduler.job;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import sample.oracle.otn.soascheduler.proxy.Helloworldprocess_client_ep;
import sample.oracle.otn.soascheduler.proxy.HelloWorldProcess;
import javax.xml.ws.WebServiceRef;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
public class HelloWorldJob implements Job{
@WebServiceRef
private static Helloworldprocess_client_ep helloworldprocess_client;
public HelloWorldJob() {
helloworldprocess_client = new Helloworldprocess_client_ep();
}
public void execute(JobExecutionContext jobExecutionContext) {
DateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = new Date();
System.out.println("HelloWorldJob started");
try {
helloworldprocess_client = new Helloworldprocess_client_ep();
HelloWorldProcess helloWorldProcess = helloworldprocess_client.getHelloWorldProcess_pt();
// Add your code to call the desired methods.
System.out.println("HelloWorld Response: " + helloWorldProcess.process("SOAScheduler@" + df.format(date)));
} catch (Exception e) {
System.out.println("HelloWorld Process failed: " + e.toString());
e.printStackTrace();
}
}
}

Creating the SOASchedulerServlet java class


1. Create a new Java Class in JDeveloper by click “File/New” or CRTL-N...


2. Set the Name to “SOASchedulerServlet”, Package to “sample.oracle.otn.soascheduler”, Extends “javax.servlet.http.HttpServlet” and click on “OK”.

3. Replace the generated source with the following lines.

package sample.oracle.otn.soascheduler;
import sample.oracle.otn.soascheduler.job.HelloWorldJob;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Calendar;
import java.util.GregorianCalendar;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.calendar.AnnualCalendar;
public class SOASchedulerServlet extends HttpServlet {
StdSchedulerFactory schedFact;
Scheduler sched;
public void init(ServletConfig config) throws ServletException {
super.init(config);
try {
schedFact = new StdSchedulerFactory("soa_quartz.properties");
sched = schedFact.getScheduler();
System.out.println(this.getClass().getName() + " started");
/*
// Add the holiday calendar to the schedule
AnnualCalendar holidays = new AnnualCalendar();
// fourth of July (July 4)
Calendar fourthOfJuly = new GregorianCalendar(2011, 7, 4);
holidays.setDayExcluded(fourthOfJuly, true);
// halloween (Oct 31)
Calendar halloween = new GregorianCalendar(2011, 9, 31);
holidays.setDayExcluded(halloween, true);
// christmas (Dec 25)
Calendar christmas = new GregorianCalendar(2011, 11, 25);
holidays.setDayExcluded(christmas, true);
// tell the schedule about our holiday calendar
sched.addCalendar("holidays", holidays, false, false);
*/
sched.start();
JobDetail jd = new JobDetail(JOB_NAME, GROUP_NAME, HelloWorldJob.class);
CronTrigger cronTrigger = new CronTrigger(TRIGGER_NAME, GROUP_NAME);
String cronExpr = null;
// Get the cron Expression as an Init parameter
cronExpr = getInitParameter("cronExpr");
System.out.println(this.getClass().getName() + " Cron Expression for " + JOB_NAME + ":" + cronExpr);
cronTrigger.setCronExpression(cronExpr);
System.out.println(this.getClass().getName() + " Scheduling Job " + JOB_NAME);
sched.scheduleJob(jd, cronTrigger);
System.out.println(this.getClass().getName() + " Job " + JOB_NAME + " scheduled.");
} catch (Exception e) {
System.out.println(this.getClass().getName() + e.getLocalizedMessage());
e.printStackTrace();
}
}
public void destroy() {
try {
if (sched != null) {
sched.unscheduleJob(TRIGGER_NAME, JOB_NAME);
sched.shutdown();
}
} catch (Exception e) {
System.out.println(this.getClass().getName() + " failed to shutdown: " + e.toString());
e.printStackTrace();
}
System.out.println(this.getClass().getName() + " stopped");
}
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
PrintWriter ajax = new PrintWriter(response.getOutputStream());
// logger.warning("get");
String action = request.getParameter("action");
if ("single".equals(action)) {
if (sched != null) {
try {
Trigger trigger =
new SimpleTrigger("SOASingleTrigger", GROUP_NAME, new Date());
trigger.setJobName(JOB_NAME);
trigger.setJobGroup(GROUP_NAME);
// Schedule the trigger
sched.scheduleJob(trigger);
} catch (Exception e) {
System.out.println(this.getClass().getName() + e.getLocalizedMessage());
e.printStackTrace();
}
}
} else if ("start".equals(action)) {
if (sched != null) {
try {
JobDetail jd = new JobDetail(JOB_NAME, GROUP_NAME, HelloWorldJob.class);
CronTrigger cronTrigger = new CronTrigger(TRIGGER_NAME, GROUP_NAME);
// Get the cron Expression as an Init parameter
String cronExpr = getInitParameter("cronExpr");
System.out.println(this.getClass().getName() + " Cron Expression for " + JOB_NAME + ":" + cronExpr);
cronTrigger.setCronExpression(cronExpr);
System.out.println(this.getClass().getName() + " Scheduling Job " + JOB_NAME);
sched.scheduleJob(jd, cronTrigger);
System.out.println(this.getClass().getName() + " Job " + JOB_NAME + " scheduled.");
} catch (Exception e) {
System.out.println(this.getClass().getName() + e.getLocalizedMessage());
e.printStackTrace();
}
}
} else if ("stop".equals(action)) {
if (sched != null) {
try {
sched.unscheduleJob(TRIGGER_NAME, GROUP_NAME);
System.out.println(this.getClass().getName() + " stopped");
} catch (Exception e) {
System.out.println(this.getClass().getName() + " failed to shutdown: " + e.toString());
e.printStackTrace();
}
}
}
ajax.println("<html>");
ajax.println(" <head>");
ajax.println(" <title>SOAScheduler - Web Interface</title>");
ajax.println(" <link rel=\"stylesheet\" type=\"text/css\" href=\"css/mystyle.css\"></link>");
ajax.println(" </head>");
ajax.println(" <body onload='startAjaxPeriodicalUpdater()'>");
ajax.println(" <h2>");
ajax.println(" SOAScheduler @");
ajax.println(" <span class=\"server\">" + System.getProperty("weblogic.Name") + "</span>");
ajax.println(" </h2>");
ajax.println("<table id=\"events_table\" class=\"events_table\" width=\"100%\">");
ajax.println("<tbody>");
String[] jobGroups;
String[] jobsInGroup;
String[] triggerGroups;
Trigger[] jobTriggers;
String[] calendersList;
AnnualCalendar calen;
CronTrigger cronTrigger;
int i, j, k;
try {
jobGroups = sched.getJobGroupNames();
triggerGroups = sched.getTriggerGroupNames();
calendersList = sched.getCalendarNames();
for (i= 0; i < calendersList.length; i++) {
calen = (AnnualCalendar)sched.getCalendar(calendersList[i]);
//System.out.println("Calendar: " + calendersList[i]);
ajax.printf("Calendar: " + calendersList[i]);
}
for (i = 0; i < jobGroups.length; i++) {
// System.out.println("Group: " + jobGroups[i] + " contains the following jobs");
jobsInGroup = sched.getJobNames(jobGroups[i]);
for (j = 0; j < jobsInGroup.length; j++) {
// System.out.println("- " + jobsInGroup[j]);
jobTriggers = sched.getTriggersOfJob(jobsInGroup[j], jobGroups[i]);
for (k = 0; k < jobTriggers.length; k++) {
// System.out.println("- " + triggersInGroup[j]);
if ("org.quartz.CronTrigger".equals(jobTriggers[k].getClass().getName())) {
cronTrigger = (CronTrigger)jobTriggers[k];
ajax.printf("<tr class=\"%s\"><td align=\"left\">Trigger: %s</td><td>Next: %s</td><td>Last: %s</td><td>Cron: %s</td></tr>",
"events", jobTriggers[k].getName(),
jobTriggers[k].getNextFireTime(),
jobTriggers[k].getPreviousFireTime(),
cronTrigger.getCronExpression());
} else {
ajax.printf("<tr class=\"%s\"><td align=\"left\">Trigger: %s</td><td>Next: %s</td></tr>",
"events", jobTriggers[k].getName(),
jobTriggers[k].getNextFireTime());
}
}
}
}
} catch (Exception e) {
System.out.println("SOASchdulerServlet failed: " + e.toString());
e.printStackTrace();
}
ajax.println("</tbody>");
ajax.println("</table>");
ajax.flush();
}
static final String GROUP_NAME = "SOAGroup";
static final String TRIGGER_NAME = "SOATrigger";
static final String JOB_NAME = "SOAJob";
static final String TARGET_PAGE = "index.jsp";
}

Create a quartz property file


1. Create a new File (General) in JDeveloper by click “File/New” or CRTL-N...


2. Select “File (General)”.


3. Set File Name to “soa_quartz.properties” and Directory to the src directory of your project. Click “OK”.

4. Insert the following lines into the property file.

#
# Configure Main Scheduler Properties
#
org.quartz.scheduler.instanceName = SOASchedulerorg.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
#
# Configure ThreadPool
#
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 4
#
# Configure JobStore
#
org.quartz.jobStore.misfireThreshold = 5000
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

Create a J2EE Deployment Descriptor (web.xml)


1. Create a new web.xml in JDeveloper by click “File/New” or CRTL-N...


2. Select “Java EE Deployment Descriptor”. Click “OK”.


3. Select “web.xml”. Click “Next”.


4. Select “2.5”. Click “Finish”.

5. Select “Servlets” and click on the green “+” (Create Servlet).

Set Name to “SOASchedulerServlet”, Servlet Class to “sample.oracle.otn.soascheduler.SOASchedulerServlet”. Set “Load Servlet on” to “Application Start”.

6. Select “Servlet Mappings” and click on the green “+” (Create “Servlet Mappings”). Add “/soaschedulerservlet” as URL Pattern.

7. Select “Initialization Parameters” and click on the green “+” (Create “Servlet Initialization parameters”). Add “cronExpr” as Name and “0 0,5,10,15,20,25,30,35,40,45,50,55 * * * ?” as Value.


8. Select “Pages” and click on the green “+” (Create “Welcome File”). Add “/soaschedulerservlet”.


9. The Source should look like this…

<?xml version = '1.0' encoding = 'windows-1252'?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5" xmlns="http://java.sun.com/xml/ns/javaee">
<servlet>
<servlet-name>SOASchedulerServlet</servlet-name>
<servlet-class>sample.oracle.otn.soascheduler.SOASchedulerServlet</servlet-class>
<init-param>
<param-name>cronExpr</param-name>
<param-value>0 0,5,10,15,20,25,30,35,40,45,50,55 * * * ?</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SOASchedulerServlet</servlet-name>
<url-pattern>/soaschedulerservlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>/soaschedulerservlet</welcome-file>
</welcome-file-list>
</web-app>

10. Click “Save All”.

11. Attention: The name “cronExpr” is requested in the SOASchedulerServlet.java, and the value means, that the SOA composite bpel-101-helloworld is started every five minutes every day.

Create WAR File (Deployment Profile)

1. Create a new “WAR File” in JDeveloper by click “File/New” or CRTL-N...


2. Click “OK”.


3. Set the Profile Name to “SOAScheduler”. Click “OK”.


4. On the “General” tab set the “Web Context Root” to “SOAScheduler”.


5. On the Filters subtub of WEB-INF/lib deselect “quartz-all-1.6.5.jar”, because it is already available on the WebLogic Server 10.3.1/2/3. Click “OK”.


6. Click “OK”.


Deploy your application



1. Right click on your Project, select “Deploy” and click on “SOAScheduler”.



2. Select “Deploy to Application Server”. Click “Next”.


3. Select your Application Server, where the Oracle SOA Suite is installed. If you have not your application server already configured. Add a new connection with the green “+”. Click “Next”.


4. Select “AdminServer”. Click “Finish”.

If deployment successful, the message window shows following:


Fault Handling







Fault Handling




After completing this Lesson, you should be able to do the following:




  • List the possible sources of faults  
  • Understand how to throw faults
  • Understand the constructs available for making a process ‘fault tolerant’ - catch, catchAll
  • Understand empty and terminate activities
  • Understand compensation handler
  • Understand Fault Policy Framework




What’s a Fault in BPEL


  • In BPEL, a Fault is a disruption of process execution that results in a signal being sent from the system. Fault Handling is what we do when this happens. 
  • Fault Handling can be thought of as a "mode switch" from the normal processing of the scope or process.
  • Its aim is to undo the partial and unsuccessful work of the scope in which the fault occurred.




Sources of Faults in BPEL process





nFaults in BPEL can be from various sources:



qA fault can be thrown automatically by the BPEL runtime environment, either due to a certain condition in the BPEL process itself (such as a join failure), as a consequence of error conditions in the runtime environment, or related to network communication or other reasons. For such situations, BPEL defines several System faults.


q


qA fault can occur when the BPEL process invokes a Web service operation. The operation might return a fault message, which results in a Business fault.









qA BPEL process can explicitly raise (throw) a custom fault, which is also a kind of Business fault.





When an event occurs that disrupts the normal flow of our business process, this is called a fault. How do we classify these faults? There are lots of ways that organizations classify faults, here is a simple one. Faults can be divided between those generated by our (or by our partner’s) Business Logic and those generated by the system at Runtime, either locally or remotely.Examples:When a fault is thrown, normal processing halts and control is sent to Fault Handler, if one is defined.






Taxonomy of Faults










nBPEL Standard Faults


§Are the faults that come directly from the BPEL Specification






nRuntime faults


§will not be defined by the user, so we need to design parts in the process to handle them. In bpel we will make use of the catch-activity for this. In the catch itself we can invoke our own fault-handling processes or do some other activities (retry etc) which are needed to get a valid situation again.


nBusiness Faults





§Are application specific faults and will occur when we use the “throw”-activity or if we invoke a partnerlink which returns with some fault. It’s up to the “business” to decide what needs to be done when the fault occurs and what activities are needed for handling it.



BPEL Standard Faults





nambiguousReceive


ncompletionConditionFailure


nconflictingReceive


nconflictingRequest


ncorrelationViolation


ninvalidBranchCondition


ninvalidExpressionValue


ninvalidVariables


njoinFailure





nmismatchedAssignmentFailure


nmissingReply


nmissingRequest


nscopeInitializationFailure


nselectionFailure


nsubLanguageExecutionFault


nuninitializedParterRole


nuninitializedVariable


nunsupportedReference


nxsltInvalidSource


nxlstStylesheetNotFound





Runtime Faults = Are generated by the system and includes all standard BPEL faults•invalid variable type used as a parameter (local)•site of the invoked service is temporarily down (remote)








Possible Binding Faults







Possible Remote Faults







Business Faults from partnerlinks





nInvoking synchronous operations on partner –provided Web services may return a WSDL fault message


qWSDL faults are identified in BPEL by their qualified name





nComprised of the WSDL's target namespace and the ncname of the fault












Business Faults = Use the Throw and ReThrow activities•invalid Customer number (local) throws a fault defined in our WSDL•credit check problems (remote) throws a fault defined in our partner’s WSDL Here we see an example of a fault that is thrown when a bad argument is used in a process. Starting at the top in the WSDL file: The portType is “CalculatorPortType”, the Operation is “CalculatorOperation”, and there are both input and output messages, “CalculatorInput” and “CalculatorOutput.” In this example, the fault’s name is “calcFault” and the Fault’s QName is “tns:BadArgumentFault”, which is defined somewhere in one of our other WSDL files.






Business Faults - Signaled (thrown) explicitly





nBPEL provides the <throw> activity


qSyntax <throw faultName="name" />


qBPEL does not require definition of fault names prior to their use in the <throw> activity


§This flexible approach can be error-prone, because there is no compile-time checking of fault names. In the case of typos, misspelled faults will not be handled by the designated fault handler.


qFaults can also have an associated variable that contains fault data


qIf such a variable is required, you have to specify it when throwing a fault, by using the optional faultVariable





§<throw faultName="name" faultVariable="variable-name" />





nThe throw activity has three elements: its name, the name of the faultName, and the faultVariable


qThe faultVariable is optional





qIn case a faultVariable is used, it has to be a messageType defined in the WSDL of the process. In other words, it cannot be a simpleType like string.












nThe faults raised with the <throw> activity have to be handled in the BPEL process.


nFaults that are not handled will be returned to the client if the process is synchronous, not otherwise


qIf you want to propagate the faults to the client,


nadd a fault messageType to WSDL, and then specify the <fault …> in operation element.


nIn a synchronous operation, the reply activity can return the fault.





nIn an asynchronous operation, the invoke activity performs this function. This is because in an asynchronous interaction, the client does not wait for a reply. The reply activity is not used to return a fault. Instead, the BPEL process returns a fault using a callback operation on the same port type that normally receives the requested information, with an invoke activity.


Making a fault tolerant process





nUse Fault handler


qUseful to handle standard faults, runtime faults (remote and binding), explicitly raised faults or faults coming from partnerlinks during a scope


qSo, whats left ?....notice the definition says “during a scope”. What if the fault occurs after current scope, say in a subsequent scope


nUse Compensation handler


qUseful if you want to undo a previously completed scope.


qDo I need to do fault handling from scratch, every time.


qNot really.


nUsing Fault Policy Framework

Handle commonly occurring faults in a central way


Handling Faults using Fault Handler





nA Fault handler can be associated with a scope. As the BPEL process can have multiple scopes and scope within scope, every scope can have its own fault handler


n


nWithin a fault handler, the business process defines custom activities that should recover from the fault and possibly reverse the partial (unsuccessful) work of the activity where the fault has occurred.


n


nBPEL Process can complete successfully even when there was a fault


nThis is possible if the fault is caught in a catch block of a scope


n


nOnce a scope receives a fault, normal processing of all nested activities is halted





nscope is considered to have ended abnormally



Designing a Fault Handler





nFault handlers provide a way to separate out normal process logic from error handling logic


nMakes normal processing logic less cluttered and therefore easier to read


nPosition fault handlers strategically





nCatch and handle all exceptions from where you want your process to recover





Now let's step back and look at fault handlers from a higher level. We don’t need Fault Handling, but we should have it. Like airbags and smoke alarms, you don’t need them, but they are highly recommended. Fault Handlers separate normal process logic from fault logic, i.e., the execution of normal activities vs. error handling logic that is in the Fault Handler. You should position your Fault Handlers strategically. By doing this, you don’t have to add fault logic for each individual activity, but rather only for logical units of work. This reduces the overall volume of fault handling code and makes the process less cluttered and much easier to read.
Position Fault Handlers at those points where you would want the process to recover from, or to, depending on how you look at it.






Adding the Fault Handler





nFault handlers can be defined


qFor the process


qFor a scope





qInline for the invoke activity












nTo handle the faults, catch and catchAll are used. These are placed within the FaultHandler












Here is the BPEL Fault Handler syntax.<faultHandlers>?<!-- Note: There must be at least one faultHandler --> <catch faultName="QName"? faultVariable="BPELVariableName"? ( faultMessageType="QName" | faultElement="QName" )? > activity </catch>* <catchAll>? activity </catchAll></faultHandlers>•If we declare a “faultHandlers” section we must have something inside that definition. Therefore, we need to define one or more Catches and/or a catchAll.
•If we define a Catch, it will optionally have a single associated faultName and optionally a single associated faultVariable.
•The faultVariable can also optionally have data that is of the faultMessageType or faultElement type.
•If you notice the “*” character after the closing angle bracket of the Catch, you can see that we can declare as many Catches as are needed.
•The catchAll is optional, and if we declare a catchAll, we can have only one. Both Catches and catchAlls have a primary activity to handle the actual fault recovery's actions.










catch Overview





nEach catch is created to handle a specific fault.


ncatch provides a flexible structure when it comes to matching catch to a fault


●


Type 1: By Fault Name only (which must be a globally unique QName)


Type 2: By FaultName and faultVariable type


Type 3: By faultVariable Type





nFault Variables must be explicitly defined inside the Catch that will handle that particular fault.



Catching a fault that has no variable or a fault that was not defined as such







Catching a fault that carries some data





nTo catch such a fault, we use a variable same in type as that of the fault. We can use the same variable itself or a variable with same type.





nAs discussed earlier, this variable has to of a messageType, that is defined in the WSDL








Catching a Remote Fault





nBPEL run-time faults can be caught as a named BPEL fault.














nWe can access the details of the fault by clicking on the green plus icon to create a fault variable





nUsing this faultVariable (which is of messageType RuntimeFaultMessage), the fault code, fault summary and details of the fault can be accessed.








catchAll Overview






nThe catchAll activity is provided to catch possible faults


nIf you use catchAll, you cannot access the fault variable as BPEL does not provide a method for obtaining additional information about the captured fault.


nUse the getFaultAsString() XPath extension function to obtain additional information.


<catchAll>


<sequence>


<assign>


<copy>


<from expression="ora:getFaultAsString()"/>


<to variable="outputVariable" part="payload"


query="/client:ErrorTesterProcessResponse/client:result"/>


</copy>


</assign>


</sequence>

</catchAll>


Terminate





nThe terminate activity immediately terminates the behavior of a business process instance within which the terminate activity is performed


Unhandled Exception





nIf no catch or catchAll is selected, the fault is not caught by the current scope and is rethrown to the immediately enclosing scope.


nIf the fault occurs in (or is rethrown to) the global process scope, and there is no matching fault handler for the fault at the global level, the process would error out.


nFor synchronous processes, this unhandled fault shall be returned to client


nFor asynchronous processes, an unhandled fault shall not be returned to client. The client will error out due to timeout.





nFor one way processes, the fault is not returned to client



Returning Faults from Sync and Async processes





nIf you want to return errors from synchronous processes that the client can handle,


qRecommended approach is to add fault message to WSDL and use the reply activity. Then add appropriate fault handler in client


qSimply throwing a fault without catching it is also an option, but it is comparatively difficult for the client to handle such an error (as no info is obtained from the WSDL)


nIf you want to return errors from asynchronous process to a client,

we must use a invoke activity. We need not have a separate porttype defined. The BPEL process returns a fault using a callback operation on the same port type that normally receives the requested information, with an invoke activity. (See http://download.oracle.com/docs/cd/B31017_01/integrate.1013/b28981/faults.htm#BABIBAFC). The client should have a pick activity to deal with different messages


No-op





nThere is often a need to use an activity that does nothing.


nAn example is when a fault must be caught and suppressed





nYou can use the empty activity to insert a no-op instruction into a business process



Interesting scenario





nA travel portal wants to offer a service TravelFlow that can book airline, car, hotel and tourism booking in one go. If any of the bookings cannot be done, nothing should get booked







Using Fault Handlers









A better approach would be….









….. Compensation






nThe fault-handling concept in BPEL is similar to exception-handling in Java and other programming languages. However, business processes require additional error- handling steps. When intermediate results are made persistent, they must be reversed explicitly. Let's now take a closer look at such compensation steps



Compensation Handler





nlet you specify compensation logic to undo successfully completed activities in the case of a fault.


nA compensation handler specifically defines how to reverse the result of the particular unit it's associated with.


nThe unit of compensation is, in its simplest form, one activity.





nIt can also be a BPEL scope that forms a logical unit of work consisting of several activities and therefore needs to be compensated as such.



When will it work





nDuring runtime processing, compensation handlers become active once the corresponding invoke activity or scope has completed successfully.





nA compensation handler never becomes active for an invoke activity or scope that terminated abnormally (for example, by means of a fault). If an invoke activity fails, BPEL presumes that no compensation is needed for the invoked service. In the case where a scope terminated abnormally, its fault handler must have taken care of compensating its nested activities already.



How will it work





nA snapshot of the data accessible to the invoke activity or scope at that point in time is taken.





nThis ensures that the compensation activity will ultimately have access to the same data that was current upon invocation of the original activity, so it can reverse what the original activity did.


How to trigger it





nIf you don't specify a fault handler or compensation handler for your activity or scope, there will be a default implementation


nDefault implementation - all active compensation handlers of activities enclosed by that scope are triggered


nBPEL also provides a special activity, the compensate activity, to explicitly trigger compensation handlers


nThis construct can only be used from within a fault handler or compensation handler.


nIt's applicable to immediately enclosed invoke activities and scopes only.





nUsing the scope attribute of the compensate activity, you select the unit to be compensated—that is, the name of the scope or invoke activity.


Fault Policy Management Framework





nThis framework gives us the opportunity to handle all the business and runtime faults for an “invoke” activity. With the framework we can define one policy for every bpel domain.


qSo, using this, you can say –


§ Whenever there is fault X, do this..





nThe framework cannot completely replace Fault Handlers or Compensation as it can only handle faults that are returned from partnerlinks


How to Implement





nDefine a bindings file in the composite fault-bindings.xml


nDefine a policy file in the composite fault-policies.xml


Both files are placed at same level as the composite.xml.


That’s it



If you want to use java actions,


nDeploy the java code onto the server, and then refer to it from the policy file.





n


Default available actions





nora-retry ( retry the activity )


nora-replay-scope ( replay the scope in which the fault occurred )


nora-rethrow-fault ( system will throw the fault to the bpel fault handlers )


nora-human-intervention ( the current activity will freeze. In the console the user will be able to take several actions on this


ninstance )


nora-terminate ( terminate instance )





nora-java ( execute custom java )



Dealing with Faults - Summary





Here are some of your options for dealing with faults


nUse a terminate activity to stop the execution of a process or an activity altogether so that somebody can step in and make the necessary repairs.


nUse a reply activity with a fault name associated with it so that it will respond with a fault.


nUse a throw activity to signal an internal fault.


nUse a fault handler to catch a fault and attempt to deal with it.


nUse compensation to rollback or "undo" a process that has failed after committing either itself as a whole (a microflow) or at least one of its activities (a long-running process).

For handling faults when invoking a partnerlink, one can use fault policy framework.



Challenge Exercise





nCreate a process that reads PO Data. PO Data contains header and lines. The process delivers two files – header.txt and lines.txt. If there is any issue in delivering lines.txt, header.txt should also be not delivered.


nHint: You should create two scopes, delivering one file in each scope, and add the compensation logic for the first scope.





nNote: You can attempt this exercise after we have discussed File adapters.






nCreate a process that inserts data into a database. After deploying the process, delete the table. So when you invoke the process it will error out. Use a fault policy framework to retry the error after 5 minutes. During this 5 minutes, create the table again. So that in next try, data will be inserted.





nFind out what happens when – in a flow activity containing two branches, one of the branches error out and the error goes unhandled in the branch, but is handled in a higher scope. If we have inserted a row in a table in the other branch, will it stay, or rollback.






nPlace the fault policy and binding files in MDS and use them in two composites.

Doing things Parallely Doing things Conditionally Doing things in a Loop Pick and OnAlarm




Doing things Parallely
Doing things Conditionally
Doing things in a Loop
Pick and
OnAlarm




Lesson Objectives

nAfter completing this Lesson, you should be able to do the following:
qAdd parallel flows using the Flow activity
qAdd conditional logic using Switch activity
qExecute loops using While activity
qCreating a web service bottom up
qUnderstand the use cases for Events
qHandle events using pick activity
qUsing a wait activity

qAdding OnAlarm branch to a scope


Processing with Parallel Flows

nA parallel flow:
qIs implemented in a BPEL <flow> structure
qContains one or more activity sequences processed concurrently (in parallel)
qEnables synchronization of dependencies between activities

qCompletes when all sequences in the flow are finished



Parallel flows implement processing of concurrent sequences of activities. In BPEL the <flow> element implements the flow structure. The <flow> element may contain one or more activities to be processed simultaneously, that is, in parallel.
Typically, a sequence of activities are processed in parallel. Sequences of concurrent processing are enabled by nesting one or more activities within a <sequence> element, each of which are contained within the flow.Synchronization of activities is realized because the flow does not complete until all activities or sequences of activities are finished processing.

Parallel Flow Example


nCreate a process that takes in a string and returns its translation in French, German and Russian languages.

qFor example, if input is Hello (English), then output is Bonjour in French, Hallo in German
nIt uses a translation service to do the job
n

nHowever, as each of the translations are independent, this can be done parallely


Parallel Flow ExampleCreate a process that takes in a string and returns its translation in French, German and Russian languages.For example, if input is Hello (English), then output is Bonjour in French, Hallo in German and .. in Russian


Creating the Translation Service

nWe want to create a simple web service that takes a string and translates it into another language. 
nThe web service internally uses Google APIs to get the work done.
nThis is an example of creating a web service bottom up – create the implementation first and then generate the WSDL file
nCreate the java file
nThen use New > BusinessTier > Web Services > Java Web Services to create the web service

nDeploy to Application server

Adding a Parallel Flow to the Process

Drag a Flow activity from the Component Palette and drop it into your process

nNote: The flow initially contains two concurrent sequences.




Adding a Parallel Flow to the ProcessThe Component Palette contains a Flow activity. To add and configure a parallel flow in your process:1.  Drag a Flow activity and drop it into the Diagram View. For example drop the flow after the AssignRating activity.2.  Double-click the Flow activity to configure it. In the General tab, change the Name to GetPriceQuote. Click OK.Note: The flow is initially created with two branches. Each branch represents a sequence of activities to be processed in parallel. If you click the blue down-arrow icon, on the left of the diamond shape representing the flow, you can add additional branch sequences to the flow.


Conditional Branching with Switch

nIn BPEL a conditional branch:
qIs implemented by a <switch> element
qConsists of one or more ordered <case> branches, which
nSpecify a condition to be evaluated
nAre processed in their order of appearance, and the first branch with a true condition is processed
nContain a sequence of activities
qMay have one <otherwise> branch, which
nIs processed if all <case> conditions are false
nIs optional

nContains a sequence of activities


Conditional Branching with SwitchA conditional branch is structure used to take different processing paths based on some condition determined by the data values passed between activities in the process.BPEL implements conditional branching with the <switch> element, represented by the Switch activity in the Component Palette. A <switch> element can contain:One or more ordered <case> branches, each with a condition to be evaluated. The first <case> branch returning a true result is processed.Optionally, a <otherwise> branch, which is processed if no <case> branch is processed. If omitted the BPEL logic assumes an empty activity exists for the otherwise branch.In JDeveloper, when you drag a Switch activity from the Component Palette and drop it into the Diagram View the following two conditional branches are created:One <case> branch
An <otherwise> branchYou may add additional <case> branches as needed. Double-clicking the <case> branch allows you to specify a comment and a Boolean expression to be evaluated for the branch. All conditional branches contain a sequence of activities that can be processed when the branch is select for execution.


Adding Conditional Branching Logic



Using While for looping

nDrag a while activity into the process

nSpecify a condition.  As long as condition is true, loop will continue.

Use cases

nI call a process, and expect it to return different kinds of responses
nI call a DocumentService, that can return me either a PurchaseOrder or an Invoice or a Receipt
nI want multiple kinds of messages to be able to initiate my BPEL process.
nI call a asynchronous process, but do not want to wait indefinitely. 

nI want to wait only for a certain amount of time (say 5 minutes)

Hmm..so whats the common pattern?

nRealize that the first two scenarios can be dealt with if I have an option to do different things depending upon the message I receive
nThe third scenario is also similar if I perceive the indication the system sends me when a particular amount of time has passed as a message

nThe common pattern, hence, is event driven processing


Taxonomy of Events

BPEL supports two types of events:
nMessage events are triggered by incoming messages

nAlarm events are time-related and are triggered either after a certain duration or at a specific time.

Pick Activity


nThe Pick activity is an excellent technique to use to implement a Receive activity (wait for a message) with a timeout. This is accomplished by using both of the following:
nAn onMessage branch to receive a specific message from an operation exposed by a service through a PartnerLink
nAn onAlarm branch that implements a wait time
nThe Pick activity terminates when a message or an alarm event occurs, whichever occurs first.

nPick activity can be configured with multiple onMessage and onAlarm branches


Suspending a Process with a Wait Activity



nThe Wait activity pauses for a specified amount of time or until a specified time period.
nWaiting for specified amount of time
q<wait name="Wait_1" for="'PT2M'"/>
qP1Y2M3DT4H5M6S – Wait for 1 year, 2 months, 3 days, 4 hours, 5 minutes and 6 seconds
nWaiting until a certain time

q<wait name="Wait_2" until="'2007-02-28T12:43:59'"/>


Raise the alarm, but still keep waiting



nWhile I want to raise an alarm if the process doesn’t return after certain interval, I still want to wait for the response
nUse the On Alarm branch available to a scope.

nIf any activity in a scope has to wait for more than the time configured in the On Alarm branch, an alarm is raised.

Pick vs OnAlarm

nPick is a activity, OnAlarm is a branch that can be added to any scope

nIn Pick, after the alarm, one of the paths will be chosen.  In OnAlarm, after the alarm, just an alarm is raised, but no other action is done.

Notes

The Oracle BPEL Process Manager uses the open source Quartz Scheduler Library to implement the schedule expiration events for the wait and onAlarm branch of pick activities

About This Site

Howdy! My name is Suersh Rohan and I am the developer and maintainer of this blog. It mainly consists of my thoughts and opinions on the technologies I learn,use and develop with.
Powered by Blogger.

- Copyright © My Code Snapshots -Metrominimalist- Powered by Blogger - Designed by Suresh Rohan -