Gestion des erreurs avec “BPEL Error Hospital”
Oracle BPEL Error Hospital est un framework qui est apparu avec Oracle SOA Suite 10.1.3.3. Il permet de gérer l’ensemble des erreurs techniques qui ont lieu lors de l’exécution des flux BPEL.
Lorsque vous utilisez BPEL Error Hospital, vous ne gérez plus les erreurs au niveau flux à l’aide de branches catch ou catchAll, mais vous les externalisez dans un composant spécifique sur le serveur. Vous pouvez ainsi définir la même gestion des erreurs pour l’ensemble des flux d’un domaine ou pour un ensemble de flux définis dans une liste. Vous disposerez alors de traitements globaux de gestion des erreurs.
La première application consiste sans doute à récupérer les erreurs intervenant lors de l’appel des services web tiers ou plus généralement une erreur détectée dans une activité Invoke. BPEL Error Hospital va alors pouvoir initialiser un traitement spécifié dans un fichier sur le serveur et, lui même déclencher un large spectre de réponse : interaction humaine via la Console BPEL, relance du flux, exécution d’un code Java, etc.
Comment paramètrer Oracle BPEL Error Hospital ?
Note:
Lorsque vous utilisez BPEL Error Hospital pour gérer les erreurs BPEL, les branches catch et catchAll du flux ne sont plus déclenchées. Il est néanmoins possible de déclencher les directives de gestion des erreurs du flux en relançant les exceptions depuis le framework grace à un “rethrow”.
Mettre en place ce type de gestion des erreurs est très simple. Il faut :
- Modifier le fichier
fault-binding.xmlsur le serveur pour déclarer la configuration de “BPEL Error Hospital” qui doit être utilisée - Créer un fichier qui contient le détail des actions à exécuter en fonction des exceptions capturées
Etape 1: Modifier le fichier fault-binding.xml
Le fichier fault-binding.xml est situé dans le répertoire bpel/domains/default/config, il se base sur le schéma /bpel/system/xmllib/fault-policy-binding.xsd.
Modifiez ce fichier pour spécifier le fichier de traitement des erreurs qui doit être utilisé. On peut spécifier plusieurs fichiers en fonction du flux, du partnerLink, ou du portType déclenchant l’erreur.
<faultPolicyBindings version="2.0.1"
xmlns="http://schemas.oracle.com/bpel/faultpolicy"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- On définit la politique applicable à l'ensemble des processus -->
<process faultPolicy="DefaultPolicy"/>
<!-- On peut cibler plus finement en gérant les erreurs apparaissant
sur des partnerLink précis. Dans ce cas, on appliquera
la politique DBPolicy -->
<partnerLink faultPolicy="DBPolicy">
<portType
xmlns:db="http://xmlns.oracle.com/pcbpel/adapter/db/insert/">
db:insert_plt</portType>
</partnerLink>
</faultPolicyBindings>
Dans ce cas, la politique de traitement des erreurs sera par défaut pour l’ensemble des flux celle définie dans le fichier DefaultPolicy.xml.
En revanche, une politique de traitement des erreurs particulière sera mise en place en ce qui concerne les insertions en base de données. En effet toutes les erreurs apparaissant lors d’une insertion en base de données via le DBAdapter et dont le portType est “db:insert_plt” seront gérées dans le fichier DBPolicy.xml
Etape 2: Créer le fichier de paramètrage de la gestion des erreurs
Il faut ensuite créer un fichier .xml dans le répertoire bpel/domains/default/config/fault-policies. Dans ce fichier, dans notre cas DefaultPolicy.xml, spécifiez l’identifiant (id) de la faultPolicy ainsi que les traitements qui doivent être déclenchés pour chaque type d’erreur. Ces traitements seront exécutés si les erreurs correspondantes sont déclenchées dans les flux, partnerLink, ou portType. Voici un exemple d’un tel fichier qui met en place les actions suivantes :
- ora-retry permet de rejouer le flux ;
- ora-rethrow-fault permet de déclencher la gestion des erreurs du décrit dans les balises “catch” ou “catchAll ” du flux;
- ora-replay-scope permet de rejouer un “scope” du flux en particulier ;
- ora-human-intervention permet de mettre le flux en attente. Pour continuer l’exécution du flux, une personne devra le relancer via l’onglet « Activités » de la BPEL Console par exemple;
- ora-terminate permet d’arrêter et d’abandonner le flux exécuté.
<faultPolicy version="2.0.1" id="DefaultPolicy"
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>
<!-- remoteFault : Faute apparaissant lorsque le service appelé ne répond pas -->
<faultName
xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
name="bpelx:remoteFault">
<condition>
<!-- On exécutera l’activité ora-retry pour
toutes les erreurs remoteFault dont le code est 123-->
<test>$fault.code/code="123"</test>
<action ref="ora-retry"/>
</condition>
</faultName>
<!-- bindingFault : Faute apparaissant si le endpoint n'existe
pas ou ne peut être accédé -->
<faultName
xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
name="bpelx:bindingFault">
<condition>
<action ref="ora-rethrow-fault"/>
</condition>
</faultName>
<faultname
xmlns:flt="http://www.easyteam.fr/AnomalieMiseEnAttente"
name="flt:anomalieMiseEnAttente">
<condition>
<action ref="ora-human-intervention"/>
</condition>
</faultname>
</Conditions>
<Actions>
<!-- Cette action va permettre de rejouer l'appel 8 fois avec des
intervalles de 2, 4, 8, 16, 32, 64, 128, 256 secondes. -->
<Action id="ora-retry">
<retry>
<retryCount>8</retryCount>
<retryInterval>2</retryInterval>
<exponentialBackoff/>
<!-- En cas de succès du retry, la méthode handleRetrySuccess
de la classe spécifiée dans la balise action envoi-mail sera appelée-->
<retrySuccessAction ref="envoi-mail"/>
</retry>
</Action>
<!-- Cette action va permettre de rejouer le scope sur lequel on s'est arrêté-->
<Action id="ora-replay-scope">
<replayScope/>
</Action>
<!-- L'erreur sera relancée dans le flux et pourra éventuellement être attrapée
par les branches catch si elles sont présentes-->
<Action id="ora-rethrow-fault">
<rethrowFault/>
</Action>
<!-- Le flux sera mis "en attente" dans la BPEL Console, une intervention humaine
sera nécessaire pour poursuivre le traitement-->
<Action id="ora-human-intervention">
<humanIntervention/>
</Action>
<!-- Le flux sera avorté et le traitement stoppé -->
<Action id="ora-terminate">
<abort/>
</Action>
</Actions>
</faultPolicy>
Etape 3: Aller plus loin et appeler une classe Java
Vous pouvez aussi faire appel à une classe Java depuis le fichier de paramètrage de BPEL Error Hospital. Pour cela, définissez une action personalisée comme ci-dessous l’action envoi-mail:
<faultPolicy>
...
<faultName
xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
name="bpelx:remoteFault">
<condition>
<action ref="envoi-mail"/>
</condition>
</faultName>
...
</faultPolicy>
Pour les erreurs du type remoteFault, on va exécuter l’action envoi-mail. Il suffit alors de lier cette action à une classe Java. On précise alors le nom de la classe à appeler dans la balise Action:
<faultPolicy>
...
<Actions>
<Action id="envoi-mail">
<javaAction
className="com.easyteam.EnvoiMail"
propertySet="proprietes-envoi-mail"/>
</Action>
</Actions>
...
</faultPolicy>
Ci-dessous, un exemple de définition de propriétés pour la classe d’envoi d’email, ces lignes sont à rajouter en dessous de la balise Actions. Ces propriétés sont en fait éléments qui pourront être récupérés dans la méthode appelée. Il peut s’agir de paramètres techniques tels que le serveur SMTP ou encore d’éléments fonctionnels qui permettront de formater le contenu du mail envoyé.
<faultPolicy>
...
<Actions>
...
</Actions>
<Properties>
<propertySet name="proprietes-envoi-mail">
<property name="from">
hospital@easyteam.fr
</property>
<property name="to">
hospital_receivers@easyteam.fr
</property>
<property name="subject">
Erreur lors d’un appel de WS tiers
</property>
<property name="env">Easyteam.Fabrication</property>
<property name="host">EasyteamSMTP</property>
<property name="port">25</property>
</propertySet>
</Properties>
</faultPolicy>
Pour terminer, il reste à mettre en place votre classe Java implémentant l’interface IFaultRecoveryJavaClass dont voici le squelette :
package com.easyteam;
import com.collaxa.cube.engine.ext.wmp.faultpolicy.FaultRecoveryContext;
import com.oracle.bpel.client.BPELFault;
import com.oracle.bpel.client.config.faultpolicy.IFaultRecoveryContext;
import com.oracle.bpel.client.config.faultpolicy.IFaultRecoveryJavaClass;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
public class EnvoiMail implements IFaultRecoveryJavaClass {
private String from;
private String to;
private String subject;
private String env;
private String host;
private String port;
private Properties myProperties;
public EnvoiMail() {
private void envoiMailAlerte(IFaultRecoveryContext myFaultRecoveryContext, boolean successOrError) {
try {
...
} catch (Exception a_Exception) {
System.out.println("Exception levée lors de l'envoi d'email");
}
}
/**
* Lorsque l'attribut retrySuccessAction pointant sur cette classe est présent dans le bloc d'action Retry
* alors cette méthode est appelée par défaut par Hospital.
*/
public void handleRetrySuccess(IFaultRecoveryContext myFaultRecoveryContext) {
envoiMailAlerte(myFaultRecoveryContext, true);
}
/**
* Il s'agit de la méthode appelée par défaut par Hospital lorsque cette classe est sélectionnée dans
* l'attribut className de la balise javaAction
*/
public String handleBPELFault(IFaultRecoveryContext myFaultRecoveryContext) {
envoiMailAlerte(myFaultRecoveryContext, false);
return "Mail envoyé";
}
}
Cette classe doit être placée dans le répertoire /bpel/system/classes.
N’oubliez pas de redémarrer le serveur à chaque changement de vos classes Java ou des fichiers .xml définissant vos politiques de traitement des erreurs.
Conclusion
Ainsi, comme on l’a vu, l’utilisation de ce framework va grandement simplifier les choses puisqu’il permet de centraliser la gestion des erreurs au sein d’un même référentiel.
La maintenance sera donc plus aisée et les évolutions de gestion des erreurs ne seront plus lourdes puisqu’il suffira de modifier un simple fichier .xml et éventuellement vos classes Java.
Par ailleurs, bien que la gestion des erreurs soit dorénavant unique (plus de catch dans chaque flux), la granularité demeure fine puisqu’il est possible de descendre au niveau du portType pour spécifier un traitement particulier.
Enfin, la possibilité d’appeler des classes Java ouvre de nombreuses possibilités puisqu’il est alors possible d’utiliser les API de BPEL mises à disposition par Oracle et ainsi interagir avec les flux comme bon nous semble.
Si vous voulez en savoir plus, lisez les articles suivants:
- Oracle Fusion Middleware Developer’s Guide for Oracle SOA Suite 11g Release 1 (11.1.1) – 12 Using Fault Handling in a BPEL Process
- Oracle BPEL 10.1.3.3 Fault Policy Management by Eric Elzinga
- Extending the Oracle BPEL Error Hospital with custom Java Actions by Sjoerd Michels
- Documentation Oracle


Part 2 of “Oracle BPEL 10.1.3.3 Fault Policy Management” can be found here, http://eelzinga.wordpress.com/2009/02/14/oracle-bpel-fault-policy-framework-handling-custom-business-faults/ , “Oracle BPEL Fault Policy Framework handling custom business faults”