Architecture soa (architecture orientée services)( Télécharger le fichier original )par Virginie ELIAS CNAM Nantes - Pays de la Loire - Ingénieur en Informatique 2009 |
Exemples de grandeurs mesurables et unités associées
PROCEDURE Demande_Extraction ( P$Table in Varchar2, -- Table a extraire P$Fichier in Varchar2, -- Fichier de sortie P$Repertoire in Varchar2, -- Répertoire de sortie P$Separateur in Varchar2 Default ',', -- Séparateut Csv P$Entetes in Varchar2 Default 'O', -- Entete des colonnes P$Date in Varchar2 Default 'DD/MM/YYYY', -- Format date P$Where in Varchar2 Default Null, -- Clause Where P$Order in Varchar2 Default Null -- Clause Order by ) IS F$Fichier UTL_FILE.FILE_TYPE ; L$Ligne Varchar2(32767) ; L$I Integer ; L$Date Varchar2(40) := '''' || P$Date || '''' ; XmlFic Utl_File.File_Type; XmlData CLOB; Fin BOOLEAN := TRUE; qryCtx DBMS_XMLGEN.ctxHandle; TYPE REFCUR1 IS REF CURSOR ; cur REFCUR1; -- Colonnes de la table -- CURSOR C_COLTAB ( P$Tab IN VARCHAR2 ) IS SELECT COLUMN_NAME, DATA_TYPE FROM USER_TAB_COLUMNS WHERE TABLE_NAME = P$Tab AND DATA_TYPE IN ('CHAR','VARCHAR2','NUMBER','DATE','FLOAT') ; L$Separateur Varchar2(2) := P$Separateur ; L$Requete Varchar2(10000) ; L$Desc Varchar2(10000) ; L$SQLW VARCHAR2(10000):= 'SELECT '; L$Col VARCHAR2(256); ----------------------------------------- -- Ouverture d'un fichier d'extraction -- ----------------------------------------- FUNCTION Ouvrir_fichier ( P$Dir in Varchar2, P$Nom_Fichier in Varchar2 ) RETURN UTL_FILE.FILE_TYPE IS Fichier UTL_FILE.FILE_TYPE ; L$Msg Varchar2(256); Begin Fichier := UTL_FILE.FOPEN( P$Dir, P$Nom_Fichier, 'W', 32764 ) ; If not UTL_FILE.IS_OPEN( Fichier ) Then L$Msg := 'Erreur ouverture du fichier (' || P$Dir || ') ' || P$Nom_Fichier ; RAISE_APPLICATION_ERROR( -20100, L$Msg ) ; End if ; Return( Fichier ) ; Exception When UTL_FILE.INVALID_PATH Then L$Msg := P$Dir || P$Nom_Fichier || ' : ' || 'File location is invalid.'; RAISE_APPLICATION_ERROR( -20070, L$Msg ) ; When UTL_FILE.INVALID_MODE Then L$Msg := P$Dir || P$Nom_Fichier || ' : ' || 'The open_mode parameter in FOPEN is invalid.'; RAISE_APPLICATION_ERROR( -20070, L$Msg ) ; When UTL_FILE.INVALID_FILEHANDLE Then L$Msg := P$Dir || P$Nom_Fichier || ' : ' || 'File handle is invalid.'; RAISE_APPLICATION_ERROR( -20070, L$Msg ) ; When UTL_FILE.INVALID_OPERATION Then L$Msg := P$Dir || P$Nom_Fichier || ' : ' || 'File could not be opened or operated on as requested.'; RAISE_APPLICATION_ERROR( -20070, L$Msg ) ; When UTL_FILE.READ_ERROR Then L$Msg := P$Dir || P$Nom_Fichier || ' : ' || 'Operating system error occurred during the read operation.'; RAISE_APPLICATION_ERROR( -20070, L$Msg ) ; When UTL_FILE.WRITE_ERROR Then L$Msg := P$Dir || P$Nom_Fichier || ' : ' || 'Operating system error occurred during the write operation.'; RAISE_APPLICATION_ERROR( -20070, L$Msg ) ; When UTL_FILE.INTERNAL_ERROR then L$Msg := P$Dir || P$Nom_Fichier || ' : ' || 'Unspecified PL/SQL error'; RAISE_APPLICATION_ERROR( -20070, L$Msg ) ; When UTL_FILE.CHARSETMISMATCH Then L$Msg := P$Dir || P$Nom_Fichier || ' : ' || 'A file is opened using FOPEN_NCHAR,' || ' but later I/O operations use nonchar functions such as PUTF or GET_LINE.'; RAISE_APPLICATION_ERROR( -20070, L$Msg ) ; When UTL_FILE.FILE_OPEN Then L$Msg := P$Dir || P$Nom_Fichier || ' : ' || 'The requested operation failed because the file is open.'; RAISE_APPLICATION_ERROR( -20070, L$Msg ) ; When UTL_FILE.INVALID_MAXLINESIZE Then L$Msg := P$Dir || P$Nom_Fichier || ' : ' || 'The MAX_LINESIZE value for FOPEN() is invalid;' || ' it should be within the range 1 to 32767.'; RAISE_APPLICATION_ERROR( -20070, L$Msg ) ; When UTL_FILE.INVALID_FILENAME Then L$Msg := P$Dir || P$Nom_Fichier || ' : ' || 'The filename parameter is invalid.'; RAISE_APPLICATION_ERROR( -20070, L$Msg ) ; When UTL_FILE.ACCESS_DENIED Then L$Msg := P$Dir || P$Nom_Fichier || ' : ' || 'Permission to access to the file location is denied.'; RAISE_APPLICATION_ERROR( -20070, L$Msg ) ; When UTL_FILE.INVALID_OFFSET Then L$Msg := P$Dir || P$Nom_Fichier || ' : ' || 'The ABSOLUTE_OFFSET parameter for FSEEK() is invalid;' ||' it should be greater than 0 and less than the total number of bytes in the file.'; RAISE_APPLICATION_ERROR( -20070, L$Msg ) ; When UTL_FILE.DELETE_FAILED Then L$Msg := P$Dir || P$Nom_Fichier || ' : ' || 'The requested file delete operation failed.'; RAISE_APPLICATION_ERROR( -20070, L$Msg ) ; When UTL_FILE.RENAME_FAILED Then L$Msg := P$Dir || P$Nom_Fichier || ' : ' || 'The requested file rename operation failed.'; RAISE_APPLICATION_ERROR( -20070, L$Msg ) ; When others Then L$Msg := 'Erreur : ' || To_char( SQLCODE ) || ' sur ouverture du fichier (' || P$Dir || ') ' || P$Nom_Fichier ; RAISE_APPLICATION_ERROR( -20070, L$Msg ) ; End Ouvrir_fichier ; Begin -- Ouverture du fichier -- F$Fichier := Ouvrir_fichier( P$Repertoire, P$Fichier||'.txt' ) ; -- Affichage des entetes de colonne ? -- If Upper(P$Entetes) = 'O' Then L$I := 1 ; For COLS IN C_COLTAB( P$Table ) Loop If L$I = 1 Then L$Ligne := L$Ligne || COLS.COLUMN_NAME ; Else L$Ligne := L$Ligne || L$Separateur || COLS.COLUMN_NAME ; End if ; L$I := L$I + 1 ; End loop ; -- Ecriture ligne entetes -- UTL_FILE.PUT_LINE( F$Fichier, L$Ligne ) ; ElsIf Upper(P$Entetes) = 'I' Then L$Separateur := ',' ; L$Desc := 'INSERT INTO ' || P$Table || ' (' ; L$I := 1 ; For COLS IN C_COLTAB( P$Table ) Loop If L$I = 1 Then L$Desc := L$Desc || COLS.COLUMN_NAME ; Else L$Desc := L$Desc || L$Separateur || COLS.COLUMN_NAME ; End if ; L$I := L$I + 1 ; End loop ; L$Desc := L$Desc || ' ) VALUES (' ; End if ; -- Réenvoyer un résultat lisible d'un browser dans le cas où l'invocation est faite par HTTP htp.htmlopen;htp.bodyopen;htp.line; htp.tableopen('border'); htp.tablecaption(P$Table,'center'); htp.tablerowopen; -- htp.tableheader(L$Ligne); ---- -- Génération de la requete -- L$I := 1 ; FOR COLS IN C_COLTAB( P$Table ) LOOP IF L$I > 1 THEN L$SQLW := L$SQLW || '||' ; END IF ; If COLS.DATA_TYPE IN ('NUMBER','FLOAT') Then L$Col := 'Decode(' || COLS.COLUMN_NAME || ',NULL, ''NULL'',To_char("' || COLS.COLUMN_NAME || '"))' ; ElsIf COLS.DATA_TYPE = 'DATE' Then If Upper(P$Entetes) = 'I' Then L$Col := 'Decode(' || COLS.COLUMN_NAME || ',NULL,''NULL'',''to_date(''''''||' || 'To_char("' || COLS.COLUMN_NAME || '",'|| L$Date ||')' || '||'''''','''|| L$Date||''')'')' ; Else L$Col := 'To_char("'|| COLS.COLUMN_NAME || '",'|| L$Date ||')' ; End if ; Else If Upper(P$Entetes) = 'I' Then L$Col := 'Decode(' || COLS.COLUMN_NAME || ',NULL, ''NULL'',' || '''''''''' || '|| REPLACE("'|| COLS.COLUMN_NAME || '",CHR(39),CHR(39)||CHR(39))' || '||' || ''''''''')' ; Else L$Col := '"'|| COLS.COLUMN_NAME || '"' ; End if ; End if ; IF L$I = 1 THEN L$SQLW := L$SQLW || L$Col ; ELSE L$SQLW := L$SQLW || '''' || L$Separateur || '''' || '||' || L$Col ; END IF ; L$I := L$I + 1 ; END LOOP ; L$Requete := L$SQLW || ' FROM ' || P$Table ; If P$Where is not null Then -- ajout de la clause WHERE -- L$Requete := L$Requete || ' WHERE ' || P$Where ; End if ; If P$Order is not null Then -- ajout de la clause ORDER BY -- L$Requete := L$Requete || ' ORDER BY ' || P$Order ; End if ; --F_TRACE( L$Requete, 'T' ) ;
htp.tableRowClose; htp.tablerowopen;
-- Extraction des lignes -- Open cur For L$Requete ; Loop Fetch cur Into L$Ligne ; Exit when cur%NOTFOUND ; -- htp.tablerowopen; htp.tabledata(L$Ligne); htp.tablerowclose; -- -- Ecriture du fichier de sortie -- If Upper(P$Entetes) = 'I' Then UTL_FILE.PUT_LINE( F$Fichier, L$Desc || L$Ligne || ' );' ) ; Else UTL_FILE.PUT_LINE( F$Fichier, L$Ligne ) ; End if ; End loop ; -- htp.tablerowclose; htp.tableclose; htp.bodyclose; htp.htmlclose; -- Close cur ; -- Fermeture fichier -- UTL_FILE.FCLOSE( F$Fichier ) ; if P$Where is null then qryCtx := dbms_xmlgen.newContext ('select * FROM '|| P$Table || ''); else qryCtx := dbms_xmlgen.newContext ('select * FROM '|| P$Table || ' where ' || P$Where || ''); end if;
DBMS_XMLGEN.setRowsettag(qryCtx, ''); DBMS_XMLGEN.setRowTag(qryCtx, P$Table); DBMS_XMLGEN.setMaxRows(qryCtx, 1); -- Créer des données au format XML à partir d'une requête : XmlData :=DBMS_XMLGEN.getXML(qryCtx); -- Copie les données au format XML dans un fichier : XmlFic := sys.Utl_File.FOpen (P$Repertoire, P$Table||'.xml', 'W'); WHILE FIN LOOP -- Assigner le XML Schema
xmldata := REPLACE(Xmldata,'<'||P$Table||'>', '<'||P$Table||'_PIVOT:'||P$Table||' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:'||P$Table||'_PIVOT="http://xml.netbeans.org/schema/'||P$Table||'" xsi:schemaLocation="http://xml.netbeans.org/schema/'||P$Table||' '||P$Table||'.xsd">'); xmldata := REPLACE(Xmldata,'</'||P$Table||'>','</'||P$Table||'_PIVOT:'||P$Table||'>'); Utl_File.Put (XmlFic, SUBSTR (XmlData,1,32767)); Utl_File.FFlush(XmlFic); IF LENGTH (XmlData) > 32767 THEN XmlData := SUBSTR (XmlData, 32768); ELSE FIN := FALSE; DBMS_OUTPUT.PUT_LINE ('FIN'); END IF; END LOOP; Utl_File.FClose (XmlFic); Illustration de la flexibilité apportée par le concept de service Pseudo Code L3G : Début de saisie d'un devis pour un tiers (client, produit, quantite, date_livraison) select * from Client where nomduClient='client' Si Client n'existe pas Alors Saisir information du client insert into Client... values... Fin select * from Produit where nomduProduit = `produit' Si Produit.quantitestock - quantite_reservee < quantite Alors select Produit.delais from Produit where nomduProduit = `produit' si Date_jour + Produit.delais > date_livraison Alors Message «Devis refusé car stock indisponible dans délais imparti» Exit Fin Fin Update produit set quantite_reservee = quantite_reservee + quantite Insert into devis ... values ... Fin de Saisie de devis Constats : Constat :
Pseudo Code d'appel de services : Début de saisie d'un devis pour un tiers (client, produit, quantite, date_livraison) Client = ObtenirleClient(client) Si AnalyserStockProduit(produit, quantite) = rupture_stock Alors Si AnalyserDelaisProduit(produit,date_livraison) = date_impossible Alors Message «Devis refusé car stock indisponible dans délais imparti» Exit Fin Fin MettreajourStockreserve(produit, quantite) CreerleDevis(Client, produit, quantite,date_livraison) Fin de Saisie de devis Constats :
MettreajourStockreserve(produit, quantite) lors de la livraison du produit, ObtenirleClient(client) dans le cas d'une saisie de commande sans devis préalable. Annuaire de Services : Début ObtenirleClient(client) select * from Client where nomduClient=client Si n'existe pas Alors Saisir information du client insert into Client... values... Fin Retourner Client Fin ObtenirleClient Début CreerleDevis(Client, produit, quantite, date_livraison) insert into Devis... values... Fin CreerleDevis Début AnalyserStockProduit(produit,quantite) select quantitestock + quantite_reservee from Produit where nomduProduit = produit Si quantitestock + quantite_reservee < quantite Alors Retourne rupture_stock Sinon Retourne ok Fin Fin AnalyseStockProduit Début AnalyserDelaisProduit(produit,date_livraison) select delais Produit where nomduProduit = produit Si date_jour + delais < date_livraison Alors Retourne date_impossible Sinon Retourne ok Fin Fin AnalyseDelaisProduit Début MettreajourStockreserve(produit, quantite) Update produit set quantite_reservee = quantite_reservee + quantite Fin CreerleDevis Illustration de l'interopérabilité (traduction d'une source IBM162(*)) 1) Le diagramme de classe (outil Rose) ci dessous représente le processus d'approbation de prêt (demande de crédit, évaluation du risque, approbation, erreur) : Illustration 146 : Classe sous Rose 2) Proposition IBM de diagramme d'activité : Illustration 147 : la "Demande de Prêt" Les activités sont nommées (exemple : invokeAssessor) via des rectangles aux coins arrondis. Les actions devant être exécutées selon des conditions d'entrée à l'activité se trouvent dans le cartouche de l'activité. Par exemple, riskAssessment (une variable) est mis à jour selon le résultat du service de contrôle. Les Acteurs sont représentés dans des cadres encapsulant les activités pour lesquelles un message de réception ou d'émission leur est attribué. Une activité sans cadre (sans Acteur) signifie quelle est gérée par le processus lui-même sans besoin de service particulier. Les flèches quant à elles, indiquent le sens du processus. Ici, l'activité « Reply » renvoie une réponse au client, achevant l'exécution du processus. 3) Un export XMI163(*) du diagramme d'activités est effectué : 4) Sous Eclipse, un projet Java est créé pour importer le fichier XMI. Puis la génération BPEL est déclenchée (fonction standard). Enfin, après avoir appuyé sur « Finish », un certain nombre de fichiers apparaissent dans le projet, dont les fichiers BPEL et WSDL (Service Web).
Tableau 11 : Mapping UML / BPEL <process name="loanApprovalProcess" ...> <variables> <variable name="request" messageType="loandef:creditInformationMessage"/> <variable name="riskAssessment" messageType="asns:riskAssessmentMessage"/> ... </variables> ... <flow> <receive name="receive1" partner="customer" portType="apns:loanApprovalPT" operation="approve" variable="request" createInstance="yes"> <source linkName="receive-to-assess" transitionCondition= "bpws:getVariableData('request', 'amount')<10000"/> <source linkName="receive-to-approval" transitionCondition= "bpws:getVariableData('request', 'amount')>=10000"/> </receive> <invoke name="invokeAssessor" partner="assessor" portType="asns:riskAssessmentPT" operation="check" inputVariable="request" outputVariable="riskAssessment"> <target linkName="receive-to-assess"/> <source linkName="assess-to-setMessage" transitionCondition= "bpws:getVariableData('riskAssessment', 'risk')='low'"/> <source linkName="assess-to-approval" transitionCondition= "bpws:getVariableData('riskAssessment', 'risk')!='low'"/> </invoke> <assign name="assign"> <target linkName="assess-to-setMessage"/> <source linkName="setMessage-to-reply"/> <copy> <from expression="'yes'"/> <to variable="approvalInfo" part="accept"/> </copy> </assign> ... <reply name="reply" partner="customer" portType="apns:loanApprovalPT" operation="approve" variable="approvalInfo"> <target linkName="setMessage-to-reply"/> <target linkName="approval-to-reply"/> </reply> </flow> </process> Illustration 149 : Extrait de la traduction BPEL 5) Enfin, pour tester le résultat, il faut déployer les fichiers générés via un serveur TOMCAT par exemple ou sous WebSphere Application Server. Illustration 150 : Déploiement du Processus Après avoir cliqué sur "Continue Deployment", insérer les fichiers requis pour les différents rôles. Dans cet exemple, il y en a deux : LoanAssessor and LoanApprover. Illustration 151 : Déploiement des services Une fois le Processus déployé, le lancer en invoquant le script LoanApprovalSample : LoanApprovalSample [soap-address] first-name last-name amount. Par exemple : LoanApprovalSample http://localhost:80/bpws4j/soaprpcrouter Joe Black 10 Structures : Tiers, RIB et Adresses * 162 http://www.ibm.com/developerworks/webservices/library/ws-uml2bpel * 163 XMI (XML Metadata Interchange) : définit un format d'échange standard entre ateliers logiciels. |
|