Wednesday 21 August 2013

Understanding Dehydration in BPEL

 

Dehydration in Oracle BPEL

Over the life cycle of a BPEL instance, the instance with its current state of execution may be saved in a database. When a BPEL instance is saved to a database, the instance is also known as being dehydrated. The database where the BPEL instance is saved is called a dehydration store.
Once a BPEL instance is dehydrated, Oracle BPEL Server can off load it from the memory of Oracle BPEL Server. When a certain event occurs, such as the arrival of a message or the expiration of a timer, Oracle BPEL Server locates and loads the pertinent BPEL instance from the dehydration store back into the memory of Oracle BPEL Server and resumes the execution of the process instance. Dehydrating BPEL instances offers reliability. If Oracle BPEL Server crashes in the middle of executing a process, the instance can be recovered automatically, programmatically, or manually from the dehydrated states. When Oracle BPEL Server resumes the execution of the process instance, it resumes from the last dehydration point, which is the last state of the instance that Oracle BPEL Server saves to the dehydration store.

Oracle BPEL Process Manager uses the dehydration store database to maintain long-running asynchronous processes and their current state information in a database while they wait for asynchronous callbacks. Storing the process in a database preserves the process and prevents any loss of state or reliability if a system shuts down or a network problem occurs. There are two types of processes in Oracle BPEL Process Manager. These processes impact the dehydration store database in different ways.

Transient vs. durable BPEL processes

 Transient process — Oracle BPEL Server dehydrates the process instance only once at the end of the process. When a host crashes in the middle of running the process instance, the instances are not visible from Oracle BPEL Control.
 Durable process — Oracle BPEL Server dehydrates the process instance in-flight at all midprocess breakpoint and non-idempotent activities, plus the end of the process. When the server crashes, this process instance appears in Oracle BPEL Control up to the last dehydration point (breakpoint activity) once the server restarts. If the server crashes before the process instance reaches the first midprocess breakpoint activity, the instance is not visible in Oracle BPEL Control after the server restarts.
   eg:
  • Receive activity
  • OnMessage branch in a pick activity
  • OnAlarm branch in a pick activity
  • Wait activity

  There are three cases in which dehydration occurs:

1> When the BPEL instance encounters a mid-process breakpoint activity (not including the initial receive)
     That is where an existing BPEL instance must wait for an event, which can be either a timer expiration or message arrival. When the event occurs (the alarm expires or the message arrives), the instance is loaded from the dehydration store and execution is resumed. This type of dehydration occurs only in durable processes, which have mid-process breakpoint activities. A transient process does not have any midprocess breakpoint activities.

2> When the BPEL instance encounters a non-idempotent activity
    When Oracle BPEL Server recovers after a crash, it re tries the activities in the process instance. However, it should only retry the idempotent activities. Therefore, when Oracle BPEL Server encounters a nonidempotent activity, it dehydrates it. This enables Oracle BPEL Server to memorize that this activity was performed once and is not performed again when Oracle BPEL Server recovers from a crash.(check for idempotent activity below)

3>  When the BPEL instance finishes
      At the end of the BPEL process, Oracle BPEL Server saves the process instance to the dehydration store, unless you explicitly configure it not to do so. This happens to both durable and transient processes. For transient processes, the end of the process is the only point where the process instance is saved. This is because a transient process does not have any mid-process breakpoint activities and nonidempotent activities where the in-flight dehydration can occur
.

 Idempotent BPEL Property
A BPEL invoke activity is by default an idempotent activity, meaning that the BPEL process does not dehydrate instances immediately after invoke activities. Therefore, if idempotent is set to true and Oracle BPEL Server fails right after an invoke activity executes, Oracle BPEL Server performs the invoke again after restarting. This is because no record exists that the invoke activity has executed. This property is applicable to both durable and transient processes.
If idempotent is set to false, the invoke activity is dehydrated immediately after execution and recorded in the dehydration store. If Oracle BPEL Server then fails and is restarted, the invoke activity is not repeated, because Oracle BPEL Process Manager sees that the invoke already executed.
When idempotent is set to false, it provides better failover protection, but at the cost of some performance, since the BPEL process accesses the dehydration store much more frequently. This setting can be configured for each partner link in the bpel.xml file.
Setting this parameter to true can significantly improve throughput. However, as mentioned previously, you must ensure that the partner's service can be safely retried in the case of a server failure. Some examples of where this property can be set to true are read-only services (for example, CreditRatingService) or local EJB/WSIF invocations that share the instance's transaction.
Values
This property has the following values:
•false: activity is dehydrated immediately after execution and recorded in the dehydration store
•true (default): If Oracle BPEL Server fails, it performs the activity again after restarting. This is because the server does not dehydrate immediately after the invoke and no record exists that the activity executed.

Dehydration occurs at different times for different BPEL processes.

BPEL processes are mainly two kinds: transient and durable.

Transient process: These are the kind that does not have any break activity or mid receive activity in their design. Dehydration process occurs at the end of the process. If the BPEL process crashes before finishing, then the instance is lost. We will not find the traces of this process in the dehydration store. To java folks, this is very much similar to a transient variable. When explicitly declared as transient the variable will not be persisted with the object state and cannot be serialized.

Durable process: BPEL processes of this kind are dehydrated on the fly when a breakpoint or non-idempotent activity is encountered. In the event of a server crash, the BPEL process restarts from the last dehydration point.

A very important detail is that if a BPEL process fails without reaching a dehydration point then the instance will not show up on the BPEL console. This instance never gets stored to the database.

Dehydration can be forced in several ways
· adding check points
· by setting the idempotent property to false
· adding mid receive activity – if the process needs to wait for an event


Below are the BPEL properties that determine how much to data to be saved to the database during dehydration process.

inMemoryOptimization: only applicable to transient processes. When set to true, the bpel process is only maintained in the memory until finished. Dehydration does not occur on this kind of processes.

completionPersistLevel: controls what type of data is saved after process completion. Property can only be set on transient bpel processes and works when inMemoryOptimization is set to true. When this property is set to “all”, it saves all the final variables, audit data and work item data. This causes the database to increase largely in size. When this property is set to “instanceHeader”, only the instance metadata gets stored to the database.

completionPersistPolicy: controls if and when to persist the instance. When this property is set to “faulted”, only the faulted instances are saved to the database. This setting has a good impact on the database. When set to “on”, all the instances are saved. When set to “off”, nothing is saved. When set to “deferred”, finished instances are saved with a different thread and in another transaction. If server fails, some instances may not be saved.

The above three properties are used together. If used properly, this can reduce the database growth as well as increase the throughput.

Idempotent: applicable to bpel activities. When set to false, the bpel process is dehydrated after this activity. If the server crashes after this, the activity is not executed as it is already recorded in the database as executed.

Comparing XSLT and XQuery


Abstract


XSLT 2.0 and XQuery 1.0 have been developed by two Working Groups in close collaboration, and there is a high degree of overlap in the functionality of the two languages. They share many common concepts, such as the underlying data model, and they both include the whole of XPath 2.0 as a sublanguage, together with its extensive repertoire of data types and the associated function library.
The two languages focus on different needs, and to some extent these needs exist in different user communities. This makes it understandable that many developers have only looked seriously at one of the two languages and have dismissed the other as irrelevant. However, while there are many tasks that both languages can do well, there are some where one of the languages is a far better choice than the other. Any serious XML professional should therefore have a grasp of the capabilities of both, and should know how to choose between them objectively. And the fact that the concepts are so similar actually means that when you have learnt one, the other comes easily.
Those who have looked a little at both languages have in some cases found it hard to decide which one is more suited to their particular requirements. There have been many confusing and conflicting statements made by competing vendors, or by users of one of the two languages, who usually seem to have an unwavering conviction that the grass is greener on their own side of the fence. Sometimes the debate starts to look like a religious war.
This paper will attempt an objective side-by-side comparison of the two languages: not just from the point of view of technical features, but also looking at usability, vendor support, performance, portability, and other decision factors. Is it true, for example, that XQuery is better for data and XSLT is better for documents? Is one or the other language easier to learn depending on your computing background? As well as trying to answer these questions, the paper will also illustrate how the two languages can interoperate, so that each can be used for the parts of an application where it is most appropriate.

Introduction

How does one compare two languages? The purpose of the comparison is to help potential users decide which language is most appropriate to their needs. For this purpose, a raw comparison of features (language A uses XML syntax, language B does not) is not immensely useful: how does this help anyone decide?
I've tried to structure the comparison under three headings.
Firstly, the feature analysis, but with the emphasis being on the implications of the differences for users. This forms the bulk of the paper.
Secondly, user perceptions: what is it about the two languages that makes people like one and not the other? I haven't tried to be scientific about this, most of what I have to say is anecdotal. But I hope that readers will find it useful all the same, if only as a basis for a more objective assessment.
Thirdly, factors that have more to do with implementations of the languages than with the languages themselves. The point here is that people designing implementations of the two languages have certain ideas about how the languages are likely to be used, and their implementations will tend to to be optimized for some kinds of applications at the expense of others.
I could have included a fourth heading: future directions. To choose a technology, you not only need to understand where it is today, you need to have some kind of idea where it is going in the future. However, my crystal ball has never been very reliable and seems to become less so the more it is used. So I'll avoid speculation.

What do the languages have in common?

The first thing to understand about XSLT and XQuery is that they have more similarities than differences. I emphasize this because most of the paper will be talking about the differences. If the languages weren't so similar, it wouldn't be necessary to compare them so carefully.
(We should always remember when we spend time evaluating two technologies, that the more similar they are, the harder it is to make a decision; yet at the same time, the more similar they are, the less difference it is likely to make which one we choose.)
Here are some of the things that XSLT 2.0 and XQuery 1.0 have in common:
Both languages share the same data model and type system. They both take XML as their input and produce XML as their output, and they model XML in the same way. Both can handle untyped documents (those with no schema) as well as schema-validated documents, and in the case of schema-validated documents, they exploit the type information in essentially the same way. One consequence of the fact that the languages share the same data model is that it's likely that applications written in XSLT will be able to interoperate very easily with those written in XQuery.
Both languages are declarative expression-based languages free of side-effects. This means that many of the concepts to be learnt by new users are the same in both cases, and it also means that when you have learnt one of the languages, you have mastered many of the concepts needed to use the other.
The languages share XPath as a common subset. This means that many expressions can be written in exactly the same way in both XSLT 2.0 and XQuery 1.0: same syntax, same semantics. In addition, the two languages share the same library of built-in functions.
Even beyond the domain of XPath, there are many constructs in each language that have a direct parallel in the other, in many cases using similar syntax. The facilities for creating new elements and attributes, while not identical, have more similarities than differences. Similarly, there are syntactic differences in the way user-written functions are declared in XSLT and XQuery, but no real difference in functional capability. Both languages also allow global and local variables to be declared, using different syntax but quite similar semantics.

Syntax Differences

The most obvious difference in the syntactic style of the two languages is that an XSLT 2.0 stylesheet is an XML document, while an XQuery query is not. The XQuery syntax mimics XML in many ways, and many queries encountered in practice are in fact well-formed XML documents, but that's more by accident than by design. It's possible in XQuery to write things that XML does not allow, for example (note the nested quotes):
<a href="{concat("file:///", $filename)}"/> and conversely, there are things that XML allows that you can't do in XQuery, for example you can't replace the "<" operator by an "&lt;" entity reference in an expression such as person[salary < 10000].
What are the practical implications of this difference between XSLT and XQuery?
It is often remarked that the use of XML syntax makes XSLT very verbose. The greater expressiveness of XPath 2.0, and the introduction of user-written functions, makes this less true in XSLT 2.0 than was the case in 1.0, but it remains a valid observation.
XQuery is fully composable: any expression can be nested inside any other. By contrast, XSLT is a two-language system: XPath expressions can be nested inside XSLT instructions, but not vice versa. You can get around this in XSLT 2.0 using function calls (there was also a limited workaround in XSLT 1.0 using variables) but it still means that you need to write a function call when you want to make a callback from XPath into XSLT, for example when computing a sort key.
The fact that an XSLT stylesheet is a well-formed XML document has a number of advantages, however:
Stylesheets can be used as the input or output of a transformation (this is surprisingly common in practice)
XSLT can be embedded in other XML-based languages, and can in turn have other XML-based languages embedded within it. For example, this enables XSLT to support embedded schemas (a schema embedded within a stylesheet) in a way that XQuery can not. Similarly, XSLT can be easily embedded in pipeline processing languages such as Orbeon's XPL.
Because XSLT is XML, rather than merely mimicking XML, the same parser technology can be reused, the whole range of XML techniques can be used when writing stylesheets (for example, use of external entities and CDATA sections) and there are no surprises in store for a user who knows the rules of XML.
Theoretically, another benefit is that it enables a stylesheet to be developed by first creating an XHTML mockup of the required output page, and then replacing elements in the XHTML selectively by instructions that compute those parts of the output that depend on the input. In practice, I haven't seen very much evidence that stylesheet developers work this way, and it doesn't necessarily produce good XSLT code.
Another benefit I have seen from using XML syntax is that it makes the grammar of XSLT much more easily extensible than that of XQuery. Because it tries to make do without any reserved words, and because it mixes a number of different syntactic styles, the grammar of XQuery is a delicate creature. Adding new features like a full-text search capability requires very careful analysis to ensure that no grammatical ambiguities are introduced. By contrast, it's very easy to extend XSLT with new instructions or new attributes, without any risk of ambiguities or backwards incompatibilities. This means that it's quite possible for such extensions to be implemented by vendors (or even by third parties) as well as by the XSL Working Group itself.
It is by no means always true that an XSLT stylesheet (whether 1.0 or 2.0) is longer than the equivalent in XQuery. Consider the simple task: create a copy of a document that is identical to the original except that all NOTE attributes are omitted. Here is an XSLT stylesheet that does the job. It's a simple variation on the standard identity template that forms part of every XSLT developer's repertoire:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="*"> <xsl:copy> <xsl:copy-of select="@* except @NOTE"/> <xsl:apply-templates/> </xsl:copy> </xsl:template> </xsl:stylesheet> In XQuery, lacking an apply-templates instruction and built-in template rules, the recursive descent has to be programmed by hand:
xquery version 1.0; declare function local:copy($node as element()) { element {node-name($node)} { (@* except @NOTE, for $c in child::node return typeswitch($c) case $e as element() return local:copy($a) case $t as text() return $t case $c as comment() return $c case $p as processing-instruction return $p } }; local:copy(/*) That's 9 lines for XSLT, 13 for XQuery. More significant that the difference in length, however, is that the XQuery solution is wrong; it loses unused namespace declarations. There appears to be no way in XQuery 1.0 to copy an element along with all its in-scope namespaces unless the contents of the element are also copied exactly.
Apart from the use of true XML versus merely XML-like syntax, the main difference between the two languages at the syntactic level is probably the way that modularity is handled. XSLT has an include/import mechanism whose detailed semantics discourage independent compilation of modules (an imported module doesn't even need to be a valid standalone stylesheet, for example it can contain references to global variables declared by its caller). By contrast, the import module feature in XQuery is designed to allow library modules to be compiled independently of each other and linked at run-time. On the other hand, the XSLT approach, with its use of import precedence to select the templates and functions that are invoked at run-time, provides a mechanism for polymorphism (and thus, customization of stylesheets) that is entirely missing from XQuery.
Do these differences in syntactic style make a real difference to the effectiveness of the languages? I suspect the answer is, not as much as you might expect. Both styles have advantages and disadvantages, and if you discount the psychological factors, all of the disadvantages have practical workarounds.

Differences in Functionality

In this section I will try to answer the question, what functionality is there in XSLT 2.0 that has no direct equivalent in XQuery, and vice versa?
In nearly all cases, the absence of certain functionality from one of the languages can be worked around. However, the workarounds may be very inconvenient, so these differences can have a real impact on the cost, or even the viability, of writing certain applications.
I'll structure this by looking at the facilities present in one language that are absent from the other, and discuss the workarounds available.

XQuery facilities missing from XSLT

FLWOR expressions

The most obvious XQuery feature with no direct analogue in XSLT is the FLWOR expression.
In fact, with one small exception, nearly every FLWOR expression can be translated fairly mechanically into equivalent XSLT constructs. The mapping is shown in the table below:
Parts of a FLWOR expression, and their XSLT equivalents
Construct XSLT equivalent
for $var in SEQ <xsl:for-each select="SEQ"> <xsl:variable name="var" select="."/>
let $var := SEQ <xsl:variable name="var" select="SEQ"/>
where CONDITION <xsl:if test="CONDITION">
order by $X/VALUE <xsl:sort select="VALUE"/>
Table 1
Thus nearly every FLWOR expression has a direct equivalent in XSLT. For example, to take a query from the XMark benchmark:
for $b in doc("auction.xml")/site/regions//item let $k := $b/name order by $k return <item name="{$k}">{ $b/location } </item> is equivalent to the XSLT code:
<xsl:for-each select="doc('auction.xml')/site/regions//item"> <xsl:sort select="name"/> <item name="{name}" <xsl:value-of select="location"/> </item> </xsl:for-each> In the above example, the variables that appear in the FLWOR expression have been eliminated entirely from the XSLT version, since everything can be handled using the implicit variable "." (the context item) that's available within <xsl:for-each>.
Here's another more complex example from the XMark benchmark. The query is:
for $p in doc("auction.xml")/site/people/person let $a := for $t in doc("auction.xml")/site/closed_auctions/closed_auction let $n := for $t2 in doc("auction.xml")/site/regions/europe/item where $t/itemref/@item = $t2/@id return $t2 where $p/@id = $t/buyer/@person return <item> {$n/name} </item> return <person name="{$p/name}">{ $a }</person>and here is the XSLT 2.0 equivalent.
<xsl:for-each select="doc('auction.xml')/site/people/person"> <xsl:variable name="p" select="."/> <xsl:variable name="a" as="element(item)*"> <xsl:for-each select="doc('auction.xml')/site/closed_auctions/closed_auction"> <xsl:variable name="t" select="."/> <xsl:variable name="n" select="doc('auction.xml')/site/regions/europe/item [$t/itemref/@item = @id]"/> <xsl:if test="$p/@id = $t/buyer/person"> <item><xsl:copy-of select="$n/name"/></item> </xsl:if> </xsl:variable> <person name="{$p/name}"> <xsl:copy-of select="$a"/> </person> </xsl:for-each> The translation here isn't purely mechanical, but it shows that it can be done: I've avoided declaring extra variables in XSLT where they aren't needed. The simplification of the evaluation of $n by replacing a FLWOR expression with a simple path expression could have been done equally well in the XQuery original. (There seems to be a tendency among XQuery programmers, especially those from a SQL background, to use complex FLWOR expressions in cases where a simple path expression with a predicate would suffice.)
There is one feature of FLWOR expressions that doesn't have any direct equivalent in XSLT. In fact, I believe it's the only feature of XQuery that has no functional equivalent in XSLT. This is the ability in the order by clause to refer to variables from any of the containing for clauses. This means that a FLWOR expression containing more than one for clause is not directly equivalent to a set of nested for loops. I have to say that I have found no application that requires this feature. The feature greatly complicates the semantic definition of FLWOR expressions, by requiring the introduction of a concept of tuples that doesn't appear in the user-visible data model. My feeling is that this is an alien import from the relational world. In the XML world, tuples are not needed because element nodes provide quite enough structuring capability.
The fact that FLWOR expressions can in nearly every case (and in all practical cases that I've come across) be rewritten using equivalent XSLT constructs doesn't mean that the distinction is purely cosmetic. There's no doubt that FLWOR expressions make it easier to write complex queries involving multiple joins across different sets of nodes (loosely, "tables"). It could also be argued that the XSLT for-each construct makes it easier to navigate the implicit hierarchic relationships in the XML structure: by using a singular context item to identify position, rather than multiple range variables, it is optimizing for hierarchic navigation rather than joins. It can thus be seen as a usability trade-off, perhaps an example of how XSLT is biased towards document-oriented XML while XQuery is biassed towards data-oriented XML.
Does the difference matter as far as optimizability is concerned? I'm prepared to be proved wrong, but I don't think it does. I think an optimizer can recognize and optimize the join constructs in the XSLT version of the code just as easily as it can in the XQuery version. XSLT optimizability starts to suffer when you make extensive use of template rules, because they are so dynamic in their nature; but if you confine yourself to the subset of the language that maps directly to XQuery, then it's just as optimizable. (Which is not to say I would recommend doing this: there is more to life than performance.)
For users with a SQL background, and for users doing data-intensive tasks, the FLWOR expression is certainly more concise and more expressive than its XSLT expansion. But I think this amounts to a psychological difference, not one that has measurable benefits in the cost of developing applications.

Other XQuery Facilities

Having looked at FLWOR, are there any other XQuery facilities that have no direct equivalent in XSLT?
Static typing is one. Static typing (which I prefer to call pessimistic static typing) requires a query to be written in a way that ensures that all type errors can be detected at compile time. For example, under static typing it's an error to write book[author eq 'Kay'] if the schema allows a book to have more than one author. The construct is permitted, however, if books can have no author, because the eq operator doesn't make it a type error if one of the operands is an empty sequence.
Static typing is optional for XQuery implementations, and it remains to be seen how many implementations will offer it. I've steered clear of it in Saxon, because I find that for many applications - those where the schema is reasonably liberal - it causes the compiler to produce more spurious errors than real coding errors. I've preferred to implement "optimistic static typing" instead: the compiler gives errors only for constructs that are bound to fail at run-time (like adding an integer to a string), not for constructs that might succeed or might fail.
The relationship of XSLT to static typing has been left somewhat ambiguous. It's possible in theory for an XSLT implementor to provide static type checking, but the specification doesn't attempt to define all the detailed inference rules that they would need to apply.
For these reasons, I think the question of static typing should be considered more as a difference between implementations, rather than a difference between the XSLT and XQuery languages as such.
Another XQuery capability which I have already mentioned is not available in XSLT is independent compilation of modules. Again this is to some extent a product feature rather than a language feature. However, it's certainly true that the XQuery module design makes this much easier to achieve than the XSLT design.
XQuery has a typeswitch construct that has no XSLT equivalent. However, it can be emulated with an xsl:choose instruction and a series of instance of tests; or more probably, using xsl:apply-templates. In fact, typeswitch can be regarded as a poor man's substitute for XSLT's template rules, as the example earlier in this paper demonstrates.
One interesting difference between XSLT and XQuery is that the result of an XSLT transformation is always a set of one or more XML documents. By contrast, an XQuery query can produce a result of any type allowed by the data model: for example, the result of the query count(//person) is a number. In XSLT, the result of such an expression needs to be wrapped in an XML document. This can make XQuery more convenient to integrate into host languages in the way that SQL is often integrated. However, it's not really a substantive difference, since the XML wrapper that's needed in XSLT is easily stripped off by the application.
And that, I think, is that. As far as I can tell, every other construct in the XQuery language has a direct equivalent in XSLT 2.0. Now let's look at some of the things in XSLT 2.0 that are not present in XQuery.

XSLT 2.0 facilities missing from XQuery

I will try to cover each of these quite briefly.

Template Rules

I'll take this first because it is the most obvious XSLT feature that has no direct equivalent in XQuery.
Template rules, and the xsl:apply-templates instruction, are the distinguishing characteristic of most XSLT stylesheets. You don't have to use this style of programming, but most of the experts recommend it, especially when handling document-oriented as distinct from data-oriented XML input. The benefit of writing your code this way is that it's much easier to make your code resilient to variations in the structure of input documents: a template rule says what should be done with a <loc> element, for example, independently of where that element is found in the source document.
Template rules make life really difficult for an optimizer. The very flexibility, the independence of the stylesheet structure from the schema structure, makes it almost impossible for an XSLT compiler to know the circumstances in which particular template rules will be activated, or the conditions that will apply when they fire. Optimization is important when dealing with a few megabytes of data, but when the volumes reach gigabytes and terabytes, you can't survive without it: and that's why XQuery offers no equivalent feature.
What this seems to tell us is that XSLT is designed primarily for handling modest volumes of document-oriented (semi-structured) XML, while XQuery is designed primarily for handling vast volumes of data-oriented (predictably-structured) XML. Neither language is exclusively confined to that territory, but that's where they are most at home.

Formatting Capabilities

XSLT 2.0 includes facilities to format numbers, dates, and times. For example, the number 1127 can be converted to the string 1.127,00 while the date 2005-04-18 can be displayed as Montag: Achtzehnte April.
The inclusion of such facilities in XSLT reflects its original primary role in rendering XML data for human consumption. XQuery has no corresponding facilities. This suggests a general rule: if the primary purpose of the application is to render data for display to human readers, XSLT might be a better choice than XQuery.

Regular Expression Handling

Both XSLT and XQuery have access to the standard functions matches(), replace(), and tokenize(), which between them provide a great deal of string-handling functionality using regular expressions. The matches() function tests whether a string matches a regular expression; the replace() function replaces substrings that match a regular expression with a replacement string, and the tokenize() function splits a string into substring by detecting separators that match a regular expression.
In addition to these facilities XSLT 2.0 offers an instruction xsl:analyze-string that has no equivalent in XQuery. Unlike any of the functions listed in the previous paragraph, this allows generalized processing of each matched or non-matched portion of an input string, where the processing can include, for example, creation of new element nodes. The following code, for example, replaces the text see [Kay, 93] with see <citation><author>Kay</author><year>93</year></citation>.
<xsl:analyze-string select="$input" regex="\[(.*),(.*)\]"> <xsl:matching-substring> <citation> <author><xsl:value-of select="regex-group(1)"/></author> <year><xsl:value-of select="regex-group(2)"/></year> </citation> </xsl:matching-substring> <xsl:non-matching-substring> <xsl:value-of select="."/> </xsl:non-matching-substring> </xsl:analyze-string> The only way of achieving this transformation using XQuery 1.0 is to write some fairly convoluted recursive functions.
The xsl:analyze-string instruction is often particularly useful in up-conversion applications, where the task is to generate XML markup by recognizing textual patterns in an input file. As such it is often used in conjunction with XSLT's unparsed-text() function, which reads a non-XML input file. Again, this has no XQuery equivalent, though it could easily be added as a vendor extension function.

Grouping

Grouping is one of the more difficult tasks to accomplish with XSLT 1.0, but this will become history with the adoption of XSLT 2.0 and its xsl:for-each-group instruction.
Grouping can be defined as identifying implicitly-related sets of nodes in a source tree and making their relationship explicit by adding a hierarchic level to the markup. Often the implicit relationship is that the nodes in a group share a common value for a grouping key: for example, a group might consist of all employees based at the same location, or all employees in the same age bracket. Such examples of grouping are similar to the applications of the GROUP BY construct in SQL, except that SQL does not deal in hierarchies, so its GROUP BY cannot actually create a hierarchic level, all it can do is to compute some aggregate over the members of the group, such as their average salary.
Another difference between XML grouping and relational grouping is that in XML, order is significant, and the implicit relationship used to identify a group often takes order into account. A common example is from XHTML, where there is an implicit relationship between an h2 element and the p and other sibling elements that follow it, up to the next h2. The xsl:for-each-group instruction handles this situation with a group-starting-with option. Positional groups can also be identified by matching the last element in the group, and positional and value-based grouping can be combined with the group-adjacent feature, which recognizes a group as comprising a set of items that (a) are adjacent, and (b) share a common value for a grouping key.
The classic circumvention to the absence of a grouping capability in XSLT 1.0 is the technique known as Muenchian grouping, after Steve Muench of Oracle who invented it. It relies heavily on keys - another feature that is missing from XQuery. All is not lost for XQuery users, however, because there is a new function distinct-values(). Like most other grouping techniques, Muenchian grouping essentially involves two nested loops: an outer loop which identifies and iterates over the distinct values of the grouping key, and an inner loop that locates and processes every item from the input that has that value as its grouping key. In XQuery 1.0, the outer loop can be implemented using the distinct-values() function, and the inner loop using an XPath filter expression (or a FLWOR expression if you prefer) that selects the items having that value. The challenge for an implementation is to detect this coding pattern and implement it with better than O(n2) performance. (Muenchian grouping will generally be O(n log n), and the same can be expected of XSLT 2.0's xsl:for-each-group).
For positional grouping problems, XQuery 1.0 users will have to fall back on the same techniques used by XSLT 1.0: basically a recursive head-tail traversal of the input sequence, passing whatever parameters are needed to recognize the pattern that defines the grouping criterion. (Users unlucky enough to find that their XQuery implementation has no support for the following-sibling axis, which is optional according to the XQuery specification, will really have a challenge on their hands.)
Grouping arises in two main ways. Firstly, it arises in up-conversion applications where the true structure of the data is not explicit in the markup. Converting XHTML to a structure with a nested section hierarchy can be seen as an example of this. Secondly, grouping arises in reporting applications, where the groups are not really intrinsic to the structure of the data, but rather a way of presenting the data for human consumption. For both up-conversion and reporting applications, XSLT 2.0 appears to offer many advantages over XQuery 1.0, of which grouping is just one example.

Keys

XSLT 1.0 users will be aware that one of the most powerful mechanisms for tuning the performance of stylesheets is by means of keys. The xsl:key function allows you, in effect, to declare an index, while the key() function allows you to select nodes by using the index.
Keys can give dramatic performance benefits: I once improved the execution time of a stylesheet running over a 40Mbyte input file from 90 minutes to 45 seconds, and the improvement was all due to keys.
There is no equivalent facility in the XQuery language. However, there may well be equivalent facilities in the better XQuery implementations. The absence of this feature reflects the fact that XQuery is rooted in database thinking. In a database system, indexes are persistent: they are a property of the data, not a property of an individual query. Any XML database with XQuery support is likely to offer some kind of physical database design tool that allows you to define indexes on your data. Another part of the database tradition, at least since SQL appeared on the scene, is that indexes should be exploited automatically when the optimizer finds a query predicate that can take advantage of them; it shouldn't be the job of the query author to say when indexes should and should not be used.
This rather leaves open the question as to what non-database XQuery implementations will do. What if that stylesheet of mine, with a 40Mb input file, had been a query? The answer is that it depends on the vendor. Saxon (whose XQuery implementation operates on in-memory documents only) has provided a vendor extension similar in capability to XSLT's keys, and other products may do the same. However, the resulting queries will not be portable across implementations.

User Perceptions

In the previous section I attempted an objective analysis of the functionality of the XSLT and XQuery languages, with some attempt to analyze the impact of the differences on the cost and viability of projects.
In practice, technologies are often chosen on less objective criteria, and it would be a mistake to dismiss the softer factors as irrelevant. In practice, users don't choose one language over another because they have measured scientifically that it has a shorter learning curve, but they may well choose it because they have heard anecdotally that this is the case, or because they have been persuaded of this by a product salesperson, or because they decide that this is likely to be the case after an hour or a day struggling with the concepts. Perceptions in this area matter as much as reality.
XSLT has been around for six years or so, while XQuery is still very new. It's therefore quite difficult to compare the way people react to the two languages. Even for XSLT, it's very hard to get a coherent picture. There seems to be some polarization: people either love it or hate it. By and large it's probably true that the people who love it use it, and those who hate it don't. This might seem obvious, but there are plenty of technologies that people use despite disliking them intensely, because they feel they have no choice.
What is it about XSLT that some people don't like? I think there are probably three main areas where one encounters resistence. Firsly, people are put off by the verbosity of the XML-based syntax. Secondly, people struggle with the fact that XSLT is a non-procedural language: they find it difficult to learn to express their transformations in a declarative way rather than in the form of a procedural algorithm. Thirdly, some people find the concept of rule-based programming difficult to master. There are some other conceptual hurdles in XSLT as in any language, of course (namespaces and whitespace handling come to mind), but I think these three are probably the biggest ones.
XSLT 2.0 has done a lot to address the first of these problems: complex logic in XSLT 2.0 can be expressed much more concisely. But the reputation will probably stick. Mark Fussel's famous blog explaining Microsoft's decision to drop XSLT in favour of XQuery, used syntax as its major selling point, and fudged any difference between the 1.0 and 2.0 versions of the language, showing eloquently how it's perceptions that matter.
How much does syntax really matter? Probably more than it should. Just as we form our first impressions of other people from the first eye contact, so we quickly make an assessment of a programming language from the first piece of code we see in that language. If that code looks ugly, the language has an uphill struggle.
As for the other conceptual hurdles, the fact that XQuery doesn't have template rules, and therefore looks and feels a lot more like SQL, is probably attractive to many people (especially, of course, SQL users). Among database query language afficionados XSLT has little credibility simply because it doesn't look and feel like a database query language (which is not surprising, given that its origins are much more founded in functional programming languages such as Scheme). These are all issues of perception, I think, but they will ensure that there is a community that likes XQuery and doesn't like XSLT, regardless of functionality.
Among many experienced XSLT users one can sense a similar distaste for XQuery. There are a number of reasons for this. One is sheer incomprehension: why should anyone be interested in a language that has so little functionality compared to XSLT? To some people, it feels as if W3C has spent five years taking a giant step backwards. Another is a feeling of resentment that XQuery has hijacked the future direction of XPath, overturning some of the design principles in XPath 1.0 such as weak typing and avoidance of dynamic errors. Associated with this is a feeling by old-timers that XML was designed for documents and that its increasing use for structured data is compromising the design principles.
Programming languages have always attracted an emotional response, so the existence of such a range of reactions should not be surprising. For the user evaluating technologies and trying to make an informed choice, the difficulty is to separate the emotion (whether it comes from your own developers or from vendor salespeople) from the reality. A healthy dose of scepticism is appropriate.

Implementation Factors

In choosing a language, you can't make a decision based solely on the features of the language itself: you also have to consider features of the language implementations. The product implementations define many important factors that are outside the scope of the W3C specifications: performance, product maturity and support, APIs and integration with other technologies, configurability, diagnostics, instrumentation.
I'm not concerned here with the virtues of one XSLT processor over another, or one XQuery implementation over another. I'm more interested in asking whether there are general characteristics of XSLT implementations that differ from the characteristics of XQuery implementations.
There are at least three reasons that such differences might exist:
The languages have inherent characteristics that constrain implementations.
The languages are aimed at different markets, and implementors optimize their products for the requirements of those markets.
XQuery implementors use other XQuery implementations as their benchmark, while XSLT implementors measure themselves against other XSLT implementations. The two therefore drift in different directions, with different metrics being considered important.
I think there are probably two qualities that are most important to users: product maturity (implying reliability, availability of support and training, availability of skilled developers, and so on) and performance.
On the maturity side, XSLT clearly has a head start, having been around for six years or so already. It's easy to verify that there are more XSLT developers, more training courses, more books, more active internet forums, and all the rest. Saxon alone has had a quarter of a million downloads, and is bundled with packages that ship in many times that quantity. The numbers put XSLT into the same kind of league as Perl, Python, or PHP as mainstream web programming languages. It's much too early to collect comparable data for XQuery.
Interestingly, there are a lot more XQuery 1.0 implementations than XSLT 2.0 implementations (until very recently Saxon had the field to itself among XSLT 2.0 processors). Perhaps this is itself an indicator of maturity: a mature market moves forward with less haste, and the number of vendors in the race tends to drop with time rather than increasing.
Of course another factor that matters to many users is which vendors are supporting which language. For some people, the fact of Microsoft stopping support for Java or XSLT is enough reason to abandon the language. Many other users, however, welcome the opportunity to reduce their dependence on one supplier.
Performance is a big open question. I don't know of any serious studies so far to compare XSLT and XQuery performance. It would be quite hard to set the rules for such a race: how much would one be allowed to optimize the way the code is written to take best advantage of each language? I suspect that for a transformation-style workload (documents in, documents out) there wouldn't be a decisive win for either, and that the variations between products would be greater than any differences between the two languages.
The big area where XQuery should win is in handling queries on XML databases. In fact, in that area, it's probably a no-contest: no-one is building XSLT engines to tackle that job. It's in this area that query optimization is absolutely vital, and all the restrictions in XQuery functionality compared with XSLT can be seen as having one aim in life: to make it possible to optimize queries against large databases. I've heard people argue that XSLT could be optimized just as well, but I don't think the point will ever be tested, because I don't think anyone will seriously try to do it.

Summary and Conclusions

Let's try to draw some conclusions.
Firstly, in functionality alone, there is no doubt that XSLT 2.0 wins over XQuery 1.0. There are many jobs that XSLT 2.0 can do easily that are really difficult in XQuery 1.0. Many of these fall into the categories of up-conversion applications or rendition applications, but there are plenty of others. The example given earlier, of a stylesheet/query that copies a document except for the NOTE attributes, illustrates the point.
Secondly, it's probably true at present that XSLT is better at manipulating documents, and XQuery is better at manipulating data. Both languages should be able to do both jobs, but they seem to be better at some aspects of the job than others.
The extra verbosity of XSLT (which still applies although to a lesser extent with XSLT 2.0) is probably most noticeable with very simple queries ("count how many employees will retire this month"). I find myself increasingly using XQuery for such one-liners in preference to XSLT. This applies whether it's an ad-hoc throwaway query, or something built into a Java application. In many such cases, in fact, all one needs is an XPath expression, and of course XPath is a pure subset of XQuery.
If you are building XML databases, whether "native" XML databases or XML-over-relational databases, XQuery is certainly the language of choice. If you are transforming XML documents in filestore or in memory, I think it's much harder to justify preferring XQuery over XSLT at this stage of the game. In a year's time, perhaps there will be more data to justify making this choice especially for data-oriented applications, but my feeling is that anyone who does so today is probably attaching rather too much weight to subjective criteria.
I would actually encourage any serious XML developer to have both tools in their kitbag. Once you have learnt one, it's easy enough to learn the other. I think that with time, there will be a good level of interoperation between XSLT and XQuery products, so using one language for one task doesn't get in the way of using the other language for another part of the same application. XQuery clearly wins for the database access, XSLT for the presentation side of the application; there are other bits, such as the business logic, where in many cases either language will do the job and it becomes a matter of personal preference.
Slogans can be simplistic, but I think a one-line conclusion is not too far out: XQuery is for query, XSLT is for transformation.

Tuesday 20 August 2013

Change DB JNDI dynamically in SOA 11g

  Lets take one simple example , we want to retrieve data from employees table of HR schema based on employee_id.For that I created a datasource and outbound connection factory in database adapter.I passed on the newly created JNDI name in adapter .jca file accordingly and deployed.It ran successfully.
But my requirement is to pass on the JNDI name dynamically from descriptor, means if the destination database change then user can change the JNDI name from soa preference of deployed process, no need for redeployment. Here are some simple steps to achieve that,
Say like below you created your composite,
image
In composite.xml for the BPEL process I created one preference say,jndiVar like,
image
Here is my BPEL flow outline,
image
At setJNDI I’m assigning preference value to a process variable,
image
Then after creating the adapter go to the BPEL source and add
<bpelx:inputProperty name="jca.jndi" variable="jndiVar"/> as below,
image
Then deploy the process and change your preference value accordingly to point to right JNDI as below,
Farm_soa_domain > Weblogic Domain > soa_domain > right mouseclick and select ‘System MBean Browser’.
image
Navigate to Application Defined MBeans > oracle.soa.config > Server : soa_server1 > SCAComposite > your_project > SCAComposite.SCAComponent > your bpel_process.
Select the Attribute ‘Properties’.
image
Change the value of our preference,set JNDI accordingly and click apply.
image
Thats all your adapter will retrieve the data using new JNDI, obviously that JNDI should be defined in weblogic.

How to Undeploy Composite Manually

  Sometime I noticed that you can’t undeploy the composite from SOA EM console.It is little bit irritating and can be of various reason like not deployed properly , database reference is null etc. But I figured out undeployment procedure of SOA composite manually apart from wizard based.It worked fine for me.Here are the steps,
Login to EM console and go to mds configuration,
image
Export metadata,
image
soa-infra_metadata.zip file will be downloaded.Unzip the same and you will find deployed-composites folder and underneath deployed-composites.xml like below,
image
Delete the entry of whatever the composite you want to undeploy.You can delete the respective composite from your partition folder. Then zip it again and import the MDS from EM.
You need to restart the server and after that your composite will be gone !!!

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.

****************************************************************************************
<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>
<propertySet name="enqueue-properties">
        <property name="aq.queueconnectionfactory">jms/shrikCF</property>
          <property name="aq.queue">jms/shrikQueue</property>
      </propertySet>
So first of all you need to create a jms queue and connection factory in weblogic server , in my case it is shrikQueue and shrikCF and change the enqueue-properties value accordingly.
Here is the code excerpts that help you to enqueue data into shrikQueue,
package com.shrik;

import com.collaxa.cube.engine.fp.BPELFaultRecoveryContextImpl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
import java.util.UUID;
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.QueueConnectionFactory;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import oracle.integration.platform.faulthandling.recovery.RejectedMsgRecoveryContext;
import oracle.integration.platform.faultpolicy.IFaultRecoveryContext;
import oracle.integration.platform.faultpolicy.IFaultRecoveryJavaClass;
public class ErrorHospitalQueue implements IFaultRecoveryJavaClass {
    private String queueCF;
    private String queueName;
    public ErrorHospitalQueue() {
        super();
    }

    public String handleFault(IFaultRecoveryContext iFaultRecoveryContext) {
        BPELFaultRecoveryContextImpl ctx =
            (BPELFaultRecoveryContextImpl)iFaultRecoveryContext;
        Map properties = iFaultRecoveryContext.getProperties();
        UUID uuid = UUID.randomUUID();
        ctx.addAuditTrailEntry("Enqueueing Data into shrikQueue...");
        ctx.addAuditTrailEntry(createEventPayload(ctx));
        ctx.addAuditTrailEntry((String)getParameterValue((ArrayList)properties.get("aq.queueconnectionfactory")));
        ctx.addAuditTrailEntry((String)getParameterValue((ArrayList)properties.get("aq.queue")));
        try {
            enqueueAqEvent(createEventPayload(ctx), uuid, properties, ctx);
        } catch (JMSException e) {
            e.printStackTrace();
        } catch (NamingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "ora-terminate";
    }
    private String createEventPayload(IFaultRecoveryContext context) {
        String eventPayload =
            "<AdminFault xmlns=\"http://www.shrik.com/\">\n" +
            " <ecid>UNKNOWN_ECID</ecid>\n" +
            "</AdminFault>";
        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;
    }

    public void enqueueAqEvent(String input, UUID uuid, Map props,
                               BPELFaultRecoveryContextImpl ctx) throws JMSException,
                                                                        NamingException,
                                                                        IOException {
        Session session = null;
        MessageProducer publisher = null;
        TextMessage message = null;
        Context context = new InitialContext();
        QueueConnectionFactory connectionFactory =
            (QueueConnectionFactory)context.lookup((String)getParameterValue((ArrayList)props.get("aq.queueconnectionfactory")));
        Connection connection =
            (Connection)connectionFactory.createConnection();
        Queue errQueue =
            (Queue)context.lookup((String)getParameterValue((ArrayList)props.get("aq.queue")));
        session =
                (Session)connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        publisher = session.createProducer(errQueue);
        message = session.createTextMessage(input);
        message.setJMSCorrelationID(uuid.toString());
        connection.start();
        publisher.send(message);
        connection.stop();
        connection.close();

    }
    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) {
        System.out.println("This is for retry success");
        handleFault(iFaultRecoveryContext);
    }
    public void setQueueCF(String queueCF) {
        this.queueCF = queueCF;
    }
    public String getQueueCF() {
        return queueCF;
    }
    public void setQueueName(String queueName) {
        this.queueName = queueName;
    }
    public String getQueueName() {
        return queueName;
    }
}
After updating the jar you will be able to see message with ecid got enqueued on error scenario, here is the sample message structure,
<AdminFault xmlns="http://www.shrik.com/">
<ecid>11d1def534ea1be0:-918321b:12f07773909:-8000-0000000000000c0d</ecid>
</AdminFault>
You can customize the message as per your need

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

Error Handling in SOA 11g :Introducing Error Report: Part 3

 In previous blog I discussed how to enqueue ECID to your JMS queue from fault policy on any error.So instead of only enqueueing ECID we can also put Fault complete metadata like fault details, composite id etc.You need to modify your custom java code little bit, here is the modified code,
package com.shrik.world.fault;
import com.collaxa.cube.engine.fp.BPELFaultRecoveryContextImpl;
import java.util.Map;
import java.util.UUID;
import oracle.integration.platform.faultpolicy.IFaultRecoveryContext;
import oracle.integration.platform.faultpolicy.IFaultRecoveryJavaClass;
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.QueueConnectionFactory;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import oracle.integration.platform.faulthandling.recovery.RejectedMsgRecoveryContext;
public class CustomFaultHandler implements IFaultRecoveryJavaClass {
  
    Map props;
    public CustomFaultHandler() {
        super();
    }
    public void handleRetrySuccess(IFaultRecoveryContext iFaultRecoveryContext) {
        System.out.println("Retry Success");
        handleFault(iFaultRecoveryContext);
    }
    public String handleFault(IFaultRecoveryContext iFaultRecoveryContext) {
        //Print Fault Meta Data to Console
        System.out.println("****************Fault Metadata********************************");
        System.out.println("Fault policy id: " +
                           iFaultRecoveryContext.getPolicyId());
        System.out.println("Fault type: " + iFaultRecoveryContext.getType());
        System.out.println("Partnerlink: " +
                           iFaultRecoveryContext.getReferenceName());
        System.out.println("Port type: " +
                           iFaultRecoveryContext.getPortType());
        System.out.println("**************************************************************");
        //print all properties defined in the fault-policy file
        System.out.println("Properties Set for the Fault");
        props = iFaultRecoveryContext.getProperties();
        for (Object key : props.keySet()) {
            System.out.println("Key : " + key.toString() + " Value : " +
                               props.get(key).toString());
        }
        //Print Fault Details to Console if it exists
        System.out.println("****************Fault Details********************************");
        BPELFaultRecoveryContextImpl bpelCtx =
            (BPELFaultRecoveryContextImpl)iFaultRecoveryContext;
        if (iFaultRecoveryContext instanceof BPELFaultRecoveryContextImpl) {
            System.out.println("Fault: " + bpelCtx.getFault());
            System.out.println("Activity: " + bpelCtx.getActivityName());
            System.out.println("Composite Instance: " +
                               bpelCtx.getCompositeInstanceId());
            System.out.println("Composite Name: " +
                               bpelCtx.getCompositeName());
            System.out.println("***********************************************************");
        }
        //enqueueing Error Details
        System.out.println("Enqueueing Data into ErrorQ.....");
        try {
            enqueueAqEvent(iFaultRecoveryContext);
        } catch (JMSException e) {
            e.printStackTrace();
        } catch (NamingException e) {
            e.printStackTrace();
        }
        return bpelCtx.getFault().getMessage().contains("env:Server") ? "Terminate":"Manual";
       
    }
    private void enqueueAqEvent(IFaultRecoveryContext iFaultRecoveryContext) throws NamingException,
                                                                                    JMSException {
      
        UUID uuid = UUID.randomUUID();
        Session session = null;
        MessageProducer publisher = null;
        TextMessage message = null;
        InitialContext context = new InitialContext();
        QueueConnectionFactory connectionFactory =(QueueConnectionFactory)context.lookup("error.qcf");
        Connection connection =connectionFactory.createConnection();
        Queue errQueue =(Queue)context.lookup("error.q");
        session =connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        publisher = session.createProducer(errQueue);
        message =session.createTextMessage(createEventPayload(iFaultRecoveryContext));
        message.setJMSCorrelationID(uuid.toString());
        connection.start();
        publisher.send(message);
        connection.stop();
        connection.close();
    }
    private String createEventPayload(IFaultRecoveryContext iFaultRecoveryContext) {
        String eventPayload =
            "<SOAFault xmlns=\"http://www.shrik.world.com/\">\n" +
            " <ecid>UNKNOWN_ECID</ecid>\n" +
            " <policyID>"+ iFaultRecoveryContext.getPolicyId() + "</policyID>\n" +
            " <type>"+ iFaultRecoveryContext.getType() + "</type>\n" +
            " <partnerLink>"+ iFaultRecoveryContext.getReferenceName() + "</partnerLink>\n" +
            " <port>"+ iFaultRecoveryContext.getPortType() + "</port>\n" +
            " <faultDetails>UNKNOWN_FAULT_DETAILS</faultDetails>\n" +
            " <activity>UNKNOWN_ACTIVITY</activity>\n" +
            " <compositeID>UNKNOWN_INSTANCE_ID</compositeID>\n" +
            " <compositeName>UNKNOWN_COMPOSITE_NAME</compositeName>\n" +
            " <compositeName>UNKNOWN_COMPONENT_NAME</compositeName>\n" +
            "</SOAFault>";
        if (iFaultRecoveryContext instanceof RejectedMsgRecoveryContext) {
            RejectedMsgRecoveryContext rejectedMessageContext =
                (RejectedMsgRecoveryContext)iFaultRecoveryContext;
            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 (iFaultRecoveryContext instanceof
                   BPELFaultRecoveryContextImpl) {
            BPELFaultRecoveryContextImpl bpelFaultRecoveryContextImpl =
                (BPELFaultRecoveryContextImpl)iFaultRecoveryContext;
       
            eventPayload =eventPayload.replace("UNKNOWN_ECID", bpelFaultRecoveryContextImpl.getECID());
            eventPayload =eventPayload.replace("UNKNOWN_FAULT_DETAILS", bpelFaultRecoveryContextImpl.getFault().getMessage());
            eventPayload =eventPayload.replace("UNKNOWN_ACTIVITY", bpelFaultRecoveryContextImpl.getActivityName());
            eventPayload =eventPayload.replace("UNKNOWN_INSTANCE_ID", bpelFaultRecoveryContextImpl.getComponentInstanceId());
            eventPayload =eventPayload.replace("UNKNOWN_COMPOSITE_NAME", bpelFaultRecoveryContextImpl.getCompositeName());
            eventPayload =eventPayload.replace("UNKNOWN_COMPONENT_NAME", bpelFaultRecoveryContextImpl.getComponentName());
        }
        System.out.println(eventPayload);
        return eventPayload;
    }
}
So whenever any error occur at composite the below message will be put into the queue
image
<SOAFault xmlns="http://www.shrik.world.com/">
<ecid>11d1def534ea1be0:1ba57489:13197ef8107:-8000-0000000000000347</ecid>
<policyID>CompositeFaultPolicy</policyID>
<type>bpel</type>
<partnerLink>Service1</partnerLink>
<port>{
http://xmlns.oracle.com/ErrorHandlingApp/HelloWorld/sayHello}sayHello</port>
<faultDetails>faultName: {{
http://schemas.oracle.com/bpel/extension}remoteFault}
messageType: {{http://schemas.oracle.com/bpel/extension}RuntimeFaultMessage}
parts: {{
summary=<summary>Message Router for shrik/HelloWorld!1.0*soa_a94e595b-965e-48d9-8b15-6735c29a2805 is not able to process messages. The composite state is set to "off".  The composite can be turned "on" by using the administrative consoles.</summary>
,detail=<detail>&lt;exception>Message Router for shrik/HelloWorld!1.0*soa_a94e595b-965e-48d9-8b15-6735c29a2805 is not able to process messages. The composite state is set to "off".  The composite can be turned "on" by using the administrative consoles.&lt;/exception>
</detail>
,code=<code>env:Server</code>}
</faultDetails>
<activity>Invoke1</activity>
<compositeID>bpel:260001</compositeID>
<compositeName>CallHelloWorld</compositeName>
<compositeName>BPELProcess1</compositeName>
</SOAFault>

Now we can have a composite say SOAErrorNotificationProcess to dequeue the data from this error queue and send notification to concerned group along with auditing the same.Here is the design of that composite,
image
Its pretty simple and for auditing purpose I created below table in soainfra.database to store the error details,here is the DDL and sample data,
CREATE TABLE "DEV_SOAINFRA"."XX_COMPOSITE_ERRORS"
  (
    "ECID"           VARCHAR2(1000 BYTE) NOT NULL ENABLE,
    "POLICY_ID"      VARCHAR2(100 BYTE),
    "TYPE"           VARCHAR2(20 BYTE),
    "PARTNERLINK"    VARCHAR2(50 BYTE),
    "PORT"           VARCHAR2(500 BYTE),
    "FAULT_SUMMARY"  VARCHAR2(1000 BYTE),
    "FAULT_DETAILS"  VARCHAR2(1000 BYTE),
    "FAULT_CODE"     VARCHAR2(100 BYTE),
    "ACTIVITY"       VARCHAR2(20 BYTE),
    "COMPOSITE_ID"   VARCHAR2(100 BYTE),
    "COMPOSITE_NAME" VARCHAR2(1000 BYTE),
    "ERROR_TIME" DATE,
    CONSTRAINT "XX_COMPOSITE_ERRORS_PK" PRIMARY KEY ("ECID") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "DEV_SOAINFRA" ENABLE
  )
  SEGMENT CREATION IMMEDIATE PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE
  (
    INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT
  )
  TABLESPACE "DEV_SOAINFRA" ;

Make the routing parallel in mediator so that u can incorporate your custom fault policy there,
image
I’m not going into more details of this composite.Now just make one process faulted and our custom framework will do the following things sequentially,
1.It parse the custom policy file.2.It retrieves the fault metadata and details from em 3.It enqueue all the details to error queue. 4.SOAErrorNotificationProcess will keep on polling that queue and as soon as a data comes into error queue it retrieves that.5.It audit all the error details into a table as well as send email to a group with all fault details.
Now what's next? you can see all the faulted instances for manual recovery.Now can’t we have a report by which we can see all the error details , all the recoverable instance and retry or abort from there itself instead of going to em.Even that report would be useful for business users to get a bird’s eye view.
I used ADF here for creating the report.To get started create a view(using entity) based on the error table that you created in soainfra like below,
image
Register you vo to am to make it accessible to your report as a datasource.Create a page and drag drop your data source as a ADF Query panel. Here is the UI of mine,
image
In the menu I just incorporated print page and export as a excel functionality,
There is a button Instance Statistics in toolbar which bound to adf popup. Data source for popup is different and sql query based,here is the query
SELECT (CASE WHEN STATE=1 THEN 'OPEN AND RUNNING'
WHEN STATE=2 THEN 'OPEN AND SUSPENDED'
WHEN STATE=3 THEN 'OPEN AND FAULTED'
WHEN STATE=4 THEN 'CLOSED AND PENDING'
WHEN STATE=5 THEN 'CLOSED AND COMPLETED'
WHEN STATE=6 THEN 'CLOSED AND FAUTED'
WHEN STATE=7 THEN 'CLOSED AND CANCELLED'
WHEN STATE=8 THEN 'CLOSED AND ABORTED'
WHEN STATE=9 THEN 'CLOSED AND STALE'
WHEN STATE=10 THEN 'NON-RECOVERABLE'
ELSE STATE || ''
END) AS STATE, COUNT(*) AS NUM_OF_CUBE_INST FROM CUBE_INSTANCE GROUP BY STATE

image
Register your view to am.Now create a popup and bind the popup id to your command button popup behaviour.
image
Now create a pie chart based on SOAInstancesV as below in your popup,
image
Now just run the page to check the added functionality,Run the query and click on command button on toolbar.
image
image
Now we need to build left hand navigation.There are two links with popup behaviour, RetryInstances and SOAErrorByDay.
In RetryInstances it will popup all the recoverable instances from soa mbean that went to manual intervention in em and there would be option for retry or terminate instances without login into em.     The underlying datasource for retryinstances is based on Java bean.First create below classes in your model,
FaultDetails.java it basically contains all the getter and setter method that will be used later as a table.
package com.shrik.world.model.bean;
public class FaultDetails {
    private String compositeDN;
    private String compositeInstanceID;
    private String componentName;
    private String componentInstanceID;
    private String activityName;
    private String faultID;
    private String faultName;
    private boolean recoverableFlag;
    private String faultMessage;
    public FaultDetails() {
        super();
    }
    public FaultDetails(String compositeDN, String compositeInstanceID, String componentName, String componentInstanceID,
                 String activityName, String faultID, String faultName,boolean recoverableFlag,String faultMessage) {
        this.compositeDN=compositeDN;
        this.compositeInstanceID=compositeInstanceID;
        this.componentName=componentName;
        this.componentInstanceID=componentInstanceID;
        this.activityName=activityName;
        this.faultID=faultID;
        this.faultName=faultName;
        this.recoverableFlag=recoverableFlag;
        this.faultMessage=faultMessage;
    }

    public void setCompositeDN(String compositeDN) {
        this.compositeDN = compositeDN;
    }
    public String getCompositeDN() {
        return compositeDN;
    }
    public void setCompositeInstanceID(String compositeInstanceID) {
        this.compositeInstanceID = compositeInstanceID;
    }
    public String getCompositeInstanceID() {
        return compositeInstanceID;
    }
    public void setComponentName(String componentName) {
        this.componentName = componentName;
    }
    public String getComponentName() {
        return componentName;
    }
    public void setComponentInstanceID(String componentInstanceID) {
        this.componentInstanceID = componentInstanceID;
    }
    public String getComponentInstanceID() {
        return componentInstanceID;
    }
    public void setActivityName(String activityName) {
        this.activityName = activityName;
    }
    public String getActivityName() {
        return activityName;
    }
    public void setFaultID(String faultID) {
        this.faultID = faultID;
    }
    public String getFaultID() {
        return faultID;
    }
    public void setFaultName(String faultName) {
        this.faultName = faultName;
    }
    public String getFaultName() {
        return faultName;
    }
  
    public void setFaultMessage(String faultMessage) {
        this.faultMessage = faultMessage;
    }
    public String getFaultMessage() {
        return faultMessage;
    }
    public void setRecoverableFlag(boolean recoverableFlag) {
        this.recoverableFlag = recoverableFlag;
    }
    public boolean isRecoverableFlag() {
        return recoverableFlag;
    }
}
FaultReport.java that populates FaultDetails with all required information,
package com.shrik.world.model.bean;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import javax.naming.Context;
import oracle.soa.management.facade.Fault;
import oracle.soa.management.facade.FaultRecoveryActionTypeConstants;
import oracle.soa.management.facade.Locator;
import oracle.soa.management.facade.LocatorFactory;
import oracle.soa.management.facade.bpel.BPELServiceEngine;
import oracle.soa.management.util.FaultFilter;
public class FaultReport {
    private Locator locator = null;
    private BPELServiceEngine mBPELServiceEngine;
    private List<Fault> faultList;
    private List<FaultDetails> myfaults = new ArrayList();
    public List<FaultDetails> findAllRecoverableFaults() {
        return myfaults;
    }
    public FaultReport() {
        locator = this.getLocator();
        try {
            mBPELServiceEngine = (BPELServiceEngine)locator.getServiceEngine(Locator.SE_BPEL);
            FaultFilter filter = new FaultFilter();
            filter.setFaultName("{http://schemas.oracle.com/bpel/extension}remoteFault");
            filter.setRecoverable(true);
            //Get faults using defined filter
            faultList = mBPELServiceEngine.getFaults(filter);
            for (Fault fault : faultList) {
                myfaults.add(new FaultDetails(
                                                fault.getCompositeDN().getStringDN(),
                                                fault.getCompositeInstanceId(),
                                                fault.getComponentName(),
                                                fault.getComponentInstanceId(),
                                                fault.getLabel(),
                                                fault.getId(),
                                                fault.getName().toString(),
                                                fault.isRecoverable(),
                                                fault.getMessage().toString()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Locator getLocator() {
        try {
            return LocatorFactory.createLocator(getJndiProps());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    public Hashtable getJndiProps() {
        Hashtable jndiProps = new Hashtable();
        jndiProps.put(Context.PROVIDER_URL, "t3://localhost:8001/soa-infra");
        jndiProps.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
        jndiProps.put(Context.SECURITY_PRINCIPAL, "weblogic");
        jndiProps.put(Context.SECURITY_CREDENTIALS, "welcome1");
        jndiProps.put("dedicated.connection", "true");
        return jndiProps;
    }
   
    public void retryRecoverableInstances(){
        try {
            mBPELServiceEngine.recoverFaults(faultList.toArray(new Fault[faultList.size()]), FaultRecoveryActionTypeConstants.ACTION_RETRY);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
   
    public void terminateRecoverableInstances(){
        try {
            mBPELServiceEngine.recoverFaults(faultList.toArray(new Fault[faultList.size()]), FaultRecoveryActionTypeConstants.ACTION_ABORT);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Here you can retrieve the server properties from external file as well instead of hardcoding.
Now right click on FaultReport and generate the data source.After sometime you should be able to see the datasource,
image
Now in the popup drag drop that datasource in a panel collection as below,
image
In the menu I added two options,Retry and Abort and here is the action listener binding
image
image
Methods are written as below,
package com.shrik.world.bean;
import  com.shrik.world.model.bean.FaultReport;
import javax.faces.event.ActionEvent;
public class Reconcile {
    public Reconcile() {
    }
    public void RetrySOARecoverable(ActionEvent actionEvent) {
       new FaultReport().retryRecoverableInstances();
      
    }
    public void TerminateSOAInstances(ActionEvent actionEvent) {
        new FaultReport().terminateRecoverableInstances();
    }
   
}
Now to get error details per day just create a SQL query based vo and register to am as below,
image
Now create a bar chart in popup window as below,
image
Now run the page and click on RetryInstances in left navigator,check the Retry and Abort functionality and verify the same from em console.
image
Now click on SOAErrorByDay and a bar chart would popup as below,
image
Now you can wrap up the whole code into a EAR and deploy that to em.You can customize your GUI as per your need.