ΕΘΝΙΚΟ ΚΑΙ ΚΑΠΟΔΙΣΤΡΙΑΚΟ ΠΑΝΕΠΙΣΤΗΜΙΟ ΑΘΗΝΩΝ ΣΧΟΛΗ ΘΕΤΙΚΩΝ ΕΠΙΣΤΗΜΩΝ ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ ΚΑΙ ΤΗΛΕΠΙΚΟΙΝΩΝΙΩΝ ΠΡΟΓΡΑΜΜΑ ΜΕΤΑΠΤΥΧΙΑΚΩΝ ΣΠΟΥΔΩΝ Τεχνολογία Διοίκησης Επιχειρησιακών Διαδικασιών Οδηγός Εργαστηρίου: Χρήση REST υπηρεσιών σε BPEL Διεργασίες ΓΕΩΡΓΙΟΣ Χ. ΑΘΑΝΑΣΟΠΟΥΛΟΣ
1 Εισαγωγή Στόχος του συγκεκριμένου οδηγού είναι η εξοικείωση με την δημιουργία «εικονικών» περιγραφών REST υπηρεσιών με την χρήση της WSDL, που επιτρέπουν την διασύνδεση των συγκεκριμένων υπηρεσιών από μια διαδικασία BPEL. Ο οδηγός αυτός συνοδεύεται από σχετικό κώδικα ο οποίος υλοποιήθηκε στα πλαίσια του εργαστηρίου του μαθήματος. Ο κώδικας είναι διαθέσιμος από την σελίδα του μαθήματος στην πλατφόρμα του e-class. Θα πρέπει να τονιστεί ότι στην περίπτωση όπου κανείς επιθυμεί την εκτέλεση των παραδειγμάτων του εργαστηρίου στο τοπικό του σύστημα θα πρέπει να αλλάξει την διεύθυνση του εξυπηρετητή που χρησιμοποιείται στο κώδικα του παραδείγματος, πχ. από chloe.di.uoa.gr:8080 σε localhost:8080. 2 REST υπηρεσίες Τα χαρακτηριστικά και οι μέθοδοι ανάπτυξης REST υπηρεσιών παρουσιάστηκαν σε προηγούμενο εργαστήριο του μαθήματος. Ωστόσο, κάποια σημαντικά στοιχεία που πρέπει να αναφερθούν στα πλαίσια του παρόντος εργαστηρίου είναι: Η χρήση του πρωτοκόλλου HTTP ως δομικό στοιχείο για την κλήση των υπηρεσιών Η δυνατότητα των REST υπηρεσιών να προσφέρουν τα αποτελέσματα τους σε διάφορες μορφές, π.χ. XML και JSON Η έλλειψη μιας κοινώς αποδεκτής περιγραφής Παρόλα αυτά, για την χρήση μιας REST υπηρεσίας από μια επιχειρησιακή διαδικασία περιεγραμμένη σε BPEL κρίνεται απαραίτητο: να υπάρχει κατάλληλη περιγραφή της υπηρεσίας σε WSDL, να ανταλλάσσει μηνύματα σε XML, και να μπορεί να κληθεί η συγκεκριμένη υπηρεσία χρησιμοποιώντας του τυπικούς μηχανισμούς που προσφέρει μια μηχανή εκτέλεσης διαδικασιών. Από τις απαιτήσεις αυτές, την μεν πρώτη θα την ικανοποιήσουμε κατασκευάζοντας μια περιγραφή σε γλώσσα WSDL, την δεύτερη θα πρέπει να την επιβάλουμε στον κατασκευαστή της υπηρεσίας ενώ την δε τρίτη θα μας την καλύψει η προσφερόμενη υλοποίηση του ODE. Για να είναι δυνατή η χρήση μιας REST υπηρεσίας από μια BPEL διαδικασία, η υπηρεσία θα πρέπει να ανταλλάσσει XML μηνύματα και να χρησιμοποιεί το πρωτόκολλο HTTP για την ανταλλαγή των μηνυμάτων. Επιπλέον, η συγκεκριμένη πληροφορία θα πρέπει να αποτελεί μέρος της περιγραφής μιας υπηρεσίας. Η κατασκευή της WSDL περιγραφής για μια REST υπηρεσία αποτελεί το στόχο των επόμενων βημάτων μας.
3 Περιγραφή REST υπηρεσιών 3.1 Abstract part Ξεκινώντας με τη περιγραφή μιας REST υπηρεσίας με την χρήση WSDL, το πρώτο στοιχείο που πρέπει να προσέξει κάνεις έχει να κάνει με την περιγραφή των μηνυμάτων που ανταλλάσσονται. Εάν τα μηνύματα που ανταλλάσσονται με μια υπηρεσία είναι σύνθετα θα πρέπει να κατασκευαστούν περιγραφές των σχετικών τύπων οι οποίες θα προστεθούν είτε στο types στοιχείο μιας WSDL περιγραφής είστε σε ξεχωριστά schema documents. Στην περίπτωση λειτουργιών (operations) που περιλαμβάνουν ορίσματα απλών τύπων αυτά είναι καλύτερο να προσδιορίζονται ως ξεχωριστά τμήματα (parts) του μηνύματος εισόδου, για να είναι ευκολότερη η αντιστοίχιση τους στο σχετικό binding που θα καθοριστεί. Για παράδειγμα για μια REST υπηρεσία ελέγχου πιστοληπτικής ικανότητας το abstract τμήμα του WSDL που αναπτύχθηκε παρουσιάζεται στην κάτωθι εικόνα. <types> <xsd:schema targetnamespace="http://j2ee.netbeans.org/wsdl/restservice/restservice"> <xsd:complextype name="customertype"> <xsd:sequence> <xsd:element name="addressline1" type="xsd:string" minoccurs="0"></xsd:element> <xsd:element name="addressline2" type="xsd:string" minoccurs="0"></xsd:element> <xsd:element name="city" type="xsd:string" minoccurs="0"></xsd:element> <xsd:element name="creditlimit" type="xsd:integer" minoccurs="1"></xsd:element> <xsd:element name="customerid" type="xsd:integer" minoccurs="1"></xsd:element> <xsd:element name="email" type="xsd:string" minoccurs="1"></xsd:element> <xsd:element name="fax" type="xsd:string" minoccurs="1"></xsd:element> <xsd:element name="name" type="xsd:string" minoccurs="1"></xsd:element> <xsd:element name="phone" type="xsd:string" minoccurs="1"></xsd:element> <xsd:element name="state" type="xsd:string" minoccurs="1"></xsd:element> </xsd:sequence> </xsd:complextype> </xsd:schema> </types> <message name="findrequest"> <part name="id" type="xsd:string"/> </message> <message name="findresponse"> <part name="customer" type="tns:customertype"/> </message> <porttype name="customerpt"> <operation name="find"> <input name="input1" message="tns:findrequest"/> <output name="output1" message="tns:findresponse"/> </operation> </porttype>
Στην παραπάνω εικόνα μπορεί εύκολα να αναγνωρίσει κανείς τον τύπο customertype που έχει δημιουργηθεί για την περιγραφή των στοιχείων του πελάτη που ανταλλάσσει η προσφερόμενη υπηρεσία με τους χρήστες της. Σημαντικό στοιχείο που πρέπει να προσεχθεί ιδιαίτερα, για την ορθή λειτουργία του μηχανισμού κλήσης REST υπηρεσιών, είναι το target namespace κάτω από το οποίο έχει οριστεί ο συγκεκριμένο τύπος. Θα πρέπει το συγκεκριμένο namespace να συμφωνεί με αυτό που χρησιμοποιεί η REST υπηρεσία. Για να επιτευχθεί ο συγκεκριμένο στόχος θα πρέπει στην class (Customer) που έχει δημιουργηθεί στο NetBeans project (RestService) το οποίο περιέχει τον κώδικα της REST υπηρεσίας να βεβαιωθούμε ότι το namespace attribute στο σχετικό annotation (@XMLRootElement) της κλάσης Customer έχει την ίδια τιμή με αυτή του τύπου στο schema (δες την κάτωθι εικόνα). Σημειώνουμε ότι στο PortType που θα περιέχει τις λειτουργίες που υποστηρίζει η συγκεκριμένη υπηρεσία, μπορούμε να ορίσουμε τόσες λειτουργίες (operations) όσα και τα resources x λειτουργίες της REST υπηρεσίας (ή και λιγότερες εφόσον το επιθυμούμε). Στο WSDL του παραδείγματος που προσφέρεται έχουμε ορίσει ένα operation που αντιστοιχεί στην ανάκτηση του resource Customer με την χρήση της λειτουργίας GET. Στην περίπτωση που επιθυμούσαμε την υποστήριξη και άλλων λειτουργιών, π.χ. POST, DELETE, ή και άλλων resources, π.χ. Order, θα έπρεπε να προσθέσουμε αντίστοιχες λειτουργίες στο PortType του συγκεκριμένου WSDL. 3.2 Concrete Part Το τελικό στοιχείο, για να μπορέσει να υποστηριχθεί η κλήση REST υπηρεσιών με την χρήση μιας WSDL περιγραφής, είναι ο καθορισμός του απαραίτητου binding και του concrete part του WSDL κειμένου. Το WSDL έχει επεκταθεί κατάλληλα έτσι ώστε να μπορεί να υποστηρίζει και plain HTTP bindings
(http://www.w3.org/tr/wsdl#_http). Σημειώνουμε ότι από specification ορίζεται ότι οι HTTP λειτουργίες που μπορούν να υποστηριχθούν είναι οι GET & POST οπότε για την REST υπηρεσία την οποία θα προσφέρουμε είναι απαραίτητο να ακολουθήσουμε την low-rest προσέγγιση ανάπτυξης. Ένας απλός και χρήσιμος οδηγός για το πώς μπορεί κανείς να καθορίσει τις διάφορες μορφές του HTTP binding που μπορούν να χρησιμοποιηθούν είναι διαθέσιμος από το εξής link: http://docs.oracle.com/cd/e19509-01/821-0015/cnfg_http-bc-get-post-processing_r/index.html. Εάν και οι δυνατοί συνδυασμοί ως προς το τελικό binding που μπορούμε να έχουμε είναι πολλοί θα πρέπει πάντοτε αυτοί να βρίσκονται εντός των περιορισμών που ορίζονται από την μηχανή εκτέλεσης, π.χ. ODE (https://ode.apache.org/wsdl-11-http-bindingsupport.html). Οι επεκτάσεις της WSDL που έχουν οριστεί για την κατασκευή HTTP bindings περιλαμβάνουν: Το <http:binding> που καθορίζει το είδος της HTTP λειτουργίας που θα χρησιμοποιηθεί από το συγκεκριμένο binding, π.χ. GET. Το <http:operation> που καθορίζει την σχετική διεύθυνση της κάθε λειτουργίας. Το συγκεκριμένο στοιχείο καθορίζει την διεύθυνση μιας λειτουργίας σχετικά ως προς την τιμή του <http:address> που καθορίζεται στο αντίστοιχο port. Τα <http:urlencoded> και <http:urlreplacement> που ορίζουν πως τα σχετικά τμήματα (parts) του μηνύματος εισόδου μιας λειτουργίας κωδικοποιούνται και μεταφέρονται από το σχετικό HTTP request. Στα πλαίσια του παραδείγματος του εργαστηρίου, έχει καθοριστεί συγκεκριμένο binding (HttpBinding) από το οποίο γίνεται κλήση με βάση το HTTP GET operation. Επιπλέον για την μεταφορά των παραμέτρων κλήσης αντιγράφουμε (urlreplacement) τις τιμές των τμημάτων (parts) του μηνύματος εισόδου της κάθε λειτουργίας (operation) στην σχετική διεύθυνση που χρησιμοποιεί η κάθε μια εξ αυτών.
<binding name="httpbinding" type="tns:customerpt"> <http:binding verb="get"/> <operation name="find"> <http:operation location="gr.uoa.rest.customer/(id)"/> <input name="input1"> <http:urlreplacement/> </input> <output name="output1"> <mime:content part="customer" type="application/xml"/> </output> </operation> </binding> <service name="restservice"> <port name="restservicehttpport" binding="tns:httpbinding"> <http:address location="http://chloe.di.uoa.gr:8080/restservice/webresources"/> </port> </service> Με βάση το επιλεγμένο encoding (urlreplacement) για την λειτουργία find η τιμή του part με όνομα id χρησιμοποιείται στον σχηματισμό της τελική διεύθυνσης (URL) που θα κληθεί για την εκτέλεση της συγκεκριμένης λειτουργίας. Συγκεκριμένα για την αναζήτηση των στοιχείων του πελάτη με id=3 το URL που σχηματιστεί είναι : http://chloe.di.uoa.gr:8080/restservice/webresources/gr.uoa.rest.customer/3 Όπως μπορεί εύκολα κανείς να αναγνωρίσει, στο καθορισμένο binding έχει οριστεί ότι το αποτέλεσμα της κλήσης και συγκεκριμένα η τιμή του part customer θα είναι της μορφής xml κειμένου. Η δήλωση αυτή είναι απαραίτητη για να μπορέσει να γίνει η αναγνώριση του αποτελέσματος κατά την εκτέλεση διαδικασίας που χρησιμοποιεί το αποτέλεσμα της συγκεκριμένης λειτουργίας. Θα πρέπει εδώ να τονίσουμε ότι αντί της συγκεκριμένης μορφής κλήσεων θα μπορούσε κάλλιστα η τιμές των παραμέτρων κλήσης να μεταφερθούν ως urlencoded, δλδ ως name=value ζεύγη τα οποία διαχωρίζονται μεταξύ τους με την χρήση του & και με την διεύθυνση της υπηρεσίας με την χρήση του?. Σε κάθε περίπτωση όμως, δεδομένου ότι το αποτέλεσμα της κλήσης θα θέλαμε να γίνει αποδεκτό από διαδικασίες οι οποίες θα εκτελούνται από το ODE, αυτό θα πρέπει είναι φορμαρισμένο ως XML μήνυμα.