Qu’est-ce que BPEL ?
BPEL (Business Process Execution Language) est un langage XML pour orchestrer des services web. Il permet de définir des processus métier qui coordonnent plusieurs services web en un workflow complexe.
Concepts clés
Orchestration : Coordination centralisée de services multiples
- Un processus BPEL agit comme chef d’orchestre
- Il appelle différents services web
- Il gère le flux de données entre eux
- Il implémente la logique métier
Structure d’un processus BPEL
<process name="NomDuProcessus"
targetNamespace="http://example.com/process"
xmlns="http://docs.oasis-open.org/wsbpel/2.0/process/executable">
<!-- 1. Déclaration des partenaires -->
<partnerLinks>
<!-- Services externes et clients -->
</partnerLinks>
<!-- 2. Déclaration des variables -->
<variables>
<!-- Données manipulées par le processus -->
</variables>
<!-- 3. Corps du processus -->
<sequence>
<!-- Activités du workflow -->
</sequence>
</process>1. PartnerLinks (Partenaires)
Définit les services externes avec lesquels le processus interagit.
<partnerLinks>
<!-- Le client qui invoque le processus -->
<partnerLink name="client"
partnerLinkType="tns:ClientPLT"
myRole="orderProcessor"/>
<!-- Service externe : vérification de crédit -->
<partnerLink name="creditChecker"
partnerLinkType="tns:CreditPLT"
partnerRole="creditService"/>
<!-- Service externe : gestion des stocks -->
<partnerLink name="inventoryService"
partnerLinkType="tns:InventoryPLT"
partnerRole="inventoryProvider"/>
<!-- Service externe : expédition -->
<partnerLink name="shippingService"
partnerLinkType="tns:ShippingPLT"
partnerRole="shipper"/>
</partnerLinks>Attributs :
name: Nom du partenaire (utilisé dans les activités)partnerLinkType: Type de la relation (défini dans WSDL)myRole: Rôle du processus (quand il reçoit des messages)partnerRole: Rôle du partenaire (quand le processus l’appelle)
2. Variables
Stocke les données échangées et manipulées.
<variables>
<!-- Variable basée sur un type de message WSDL -->
<variable name="orderRequest"
messageType="ord:OrderRequestMessage"/>
<variable name="orderResponse"
messageType="ord:OrderResponseMessage"/>
<!-- Variable basée sur un type XSD -->
<variable name="creditScore"
type="xsd:int"/>
<variable name="totalAmount"
type="xsd:decimal"/>
<!-- Variable basée sur un élément XML -->
<variable name="customerInfo"
element="ord:Customer"/>
<variable name="approved"
type="xsd:boolean"/>
</variables>Types de variables :
messageType: Message WSDL complettype: Type simple XSD (string, int, boolean, etc.)element: Élément XML complexe
3. Activités BPEL
receive : Réception d’un message
Attend un message entrant (début du processus ou message asynchrone).
<!-- Réception initiale qui démarre le processus -->
<receive name="receiveOrder"
partnerLink="client"
operation="submitOrder"
portType="ord:OrderPortType"
variable="orderRequest"
createInstance="yes"/>Attributs :
createInstance="yes": Crée une nouvelle instance du processusvariable: Stocke le message reçu
invoke : Appel d’un service externe
Invoque une opération sur un service externe.
<!-- Appel synchrone (request-response) -->
<invoke name="checkCredit"
partnerLink="creditChecker"
operation="checkCreditScore"
portType="cred:CreditPortType"
inputVariable="creditRequest"
outputVariable="creditResponse"/>
<!-- Appel asynchrone (one-way) -->
<invoke name="sendNotification"
partnerLink="notificationService"
operation="notify"
portType="notif:NotificationPortType"
inputVariable="notificationMessage"/>reply : Envoi d’une réponse
Répond au client (finalise une interaction synchrone).
<reply name="sendOrderConfirmation"
partnerLink="client"
operation="submitOrder"
portType="ord:OrderPortType"
variable="orderResponse"/>assign : Manipulation de données
Copie et transforme des données entre variables.
<assign name="prepareRequest">
<!-- Copie simple -->
<copy>
<from variable="orderRequest" part="customerId"/>
<to variable="creditRequest" part="customerId"/>
</copy>
<!-- Copie avec expression XPath -->
<copy>
<from>$orderRequest/order/totalAmount</from>
<to variable="totalAmount"/>
</copy>
<!-- Assignation d'une valeur littérale -->
<copy>
<from>
<literal>PENDING</literal>
</from>
<to variable="orderStatus"/>
</copy>
<!-- Expression de calcul -->
<copy>
<from>$orderRequest/order/quantity * $orderRequest/order/unitPrice</from>
<to variable="totalAmount"/>
</copy>
</assign>sequence : Exécution séquentielle
Exécute les activités les unes après les autres.
<sequence name="processOrder">
<receive name="receiveOrder" .../>
<assign name="extractData" .../>
<invoke name="checkCredit" .../>
<invoke name="reserveInventory" .../>
<invoke name="scheduleShipping" .../>
<reply name="confirmOrder" .../>
</sequence>flow : Exécution parallèle
Exécute plusieurs activités en parallèle.
<flow name="parallelChecks">
<!-- Ces trois appels s'exécutent simultanément -->
<invoke name="checkCredit"
partnerLink="creditChecker" .../>
<invoke name="checkInventory"
partnerLink="inventoryService" .../>
<invoke name="calculateShipping"
partnerLink="shippingService" .../>
</flow>Avec liens de dépendance :
<flow name="parallelWithDependencies">
<links>
<link name="creditChecked"/>
<link name="inventoryChecked"/>
</links>
<invoke name="checkCredit" ...>
<sources>
<source linkName="creditChecked"/>
</sources>
</invoke>
<invoke name="checkInventory" ...>
<sources>
<source linkName="inventoryChecked"/>
</sources>
</invoke>
<!-- Attend que crédit ET inventaire soient vérifiés -->
<invoke name="processPayment" ...>
<targets>
<target linkName="creditChecked"/>
<target linkName="inventoryChecked"/>
</targets>
</invoke>
</flow>if : Branchement conditionnel
Exécution conditionnelle basée sur une condition.
<if name="checkApproval">
<!-- Condition -->
<condition>$creditScore > 700</condition>
<!-- Si vrai -->
<sequence>
<invoke name="approveOrder" .../>
<assign name="setApproved">
<copy>
<from>true()</from>
<to variable="approved"/>
</copy>
</assign>
</sequence>
<!-- Sinon si -->
<elseif>
<condition>$creditScore > 600 and $orderAmount < 1000</condition>
<invoke name="requestManualApproval" .../>
</elseif>
<!-- Sinon -->
<else>
<sequence>
<invoke name="rejectOrder" .../>
<assign name="setRejected">
<copy>
<from>false()</from>
<to variable="approved"/>
</copy>
</assign>
</sequence>
</else>
</if>Opérateurs de comparaison (en XML) :
<pour <>pour ><=pour ⇐>=pour >==pour ==!=pour !=
while : Boucle
Répète des activités tant qu’une condition est vraie.
<while name="retryLoop">
<condition>$retryCount < 3 and $success = false()</condition>
<sequence>
<invoke name="attemptOperation" .../>
<assign>
<copy>
<from>$retryCount + 1</from>
<to variable="retryCount"/>
</copy>
</assign>
<wait>
<for>'PT10S'</for> <!-- Attendre 10 secondes -->
</wait>
</sequence>
</while>forEach : Itération
Itère sur une collection.
<forEach name="processItems" counterName="itemIndex">
<!-- De 1 à nombre d'items -->
<startCounterValue>1</startCounterValue>
<finalCounterValue>count($orderRequest/items/item)</finalCounterValue>
<scope>
<sequence>
<assign>
<copy>
<from>$orderRequest/items/item[$itemIndex]</from>
<to variable="currentItem"/>
</copy>
</assign>
<invoke name="processItem"
inputVariable="currentItem" .../>
</sequence>
</scope>
</forEach>Avec exécution parallèle :
<forEach name="processItemsParallel"
counterName="itemIndex"
parallel="yes">
<!-- Traite tous les items en parallèle -->
</forEach>pick : Attente d’événements
Attend plusieurs événements possibles (premier arrivé).
<pick name="waitForResponse">
<!-- Événement 1 : Réception d'une approbation -->
<onMessage partnerLink="approver"
operation="approve"
portType="app:ApprovalPortType"
variable="approvalResponse">
<sequence>
<assign>
<copy>
<from>true()</from>
<to variable="approved"/>
</copy>
</assign>
</sequence>
</onMessage>
<!-- Événement 2 : Réception d'un rejet -->
<onMessage partnerLink="approver"
operation="reject"
portType="app:ApprovalPortType"
variable="rejectionResponse">
<sequence>
<assign>
<copy>
<from>false()</from>
<to variable="approved"/>
</copy>
</assign>
</sequence>
</onMessage>
<!-- Événement 3 : Timeout -->
<onAlarm>
<for>'PT1H'</for> <!-- 1 heure -->
<sequence>
<assign>
<copy>
<from>'TIMEOUT'</from>
<to variable="status"/>
</copy>
</assign>
</sequence>
</onAlarm>
</pick>wait : Temporisation
Attend un délai ou jusqu’à une date.
<!-- Attendre 30 secondes -->
<wait name="delay30sec">
<for>'PT30S'</for>
</wait>
<!-- Attendre 2 heures -->
<wait name="delay2hours">
<for>'PT2H'</for>
</wait>
<!-- Attendre jusqu'à une date spécifique -->
<wait name="waitUntilDate">
<until>$scheduledDate</until>
</wait>Format de durée ISO 8601 :
PT30S: 30 secondesPT5M: 5 minutesPT2H: 2 heuresP1D: 1 jour
scope : Portée avec gestion d’erreurs
Définit une portée avec variables locales et gestionnaires d’erreurs.
<scope name="protectedOperation">
<!-- Variables locales au scope -->
<variables>
<variable name="localData" type="xsd:string"/>
</variables>
<!-- Activité principale -->
<sequence>
<invoke name="riskyOperation" .../>
</sequence>
<!-- Gestionnaire d'erreurs -->
<faultHandlers>
<catch faultName="tns:CreditCheckFault">
<sequence>
<invoke name="notifyError" .../>
<reply name="sendErrorResponse" .../>
</sequence>
</catch>
<catchAll>
<invoke name="logUnknownError" .../>
</catchAll>
</faultHandlers>
<!-- Gestionnaire de compensation (annulation) -->
<compensationHandler>
<invoke name="cancelReservation" .../>
</compensationHandler>
</scope>throw : Lever une erreur
<throw name="throwCreditError"
faultName="tns:InsufficientCreditFault"
faultVariable="creditErrorData"/>