Κυριακή 17 Φεβρουαρίου 2008

Easy Web Services XML-Rpc

Ενδιαφέρεσθε να φτιάξετε Web Services; Ειτε ως server είτε ως client; Τότε το ακολουθω σας ενδιαφέρει. Το πλέον σημαντικό όμως πιστεύω οτι ειναι το κομμάτι που ειναι γραμμένο με ITALICS.
Τον τελευταίο καιρό έχω αρχίσει να ασχολούμε με Web Services, λόγω μιας ανάγκης που υπήρξε από έναν πελάτη για να του παρέχουμε την δυνατοτητα να φτιάξει Web Site που να αξιοποιούν το back office της εφαρμογής μας.
Όμως λόγω του μεγάλου πλήθους των λειτουργιών που παρέχει η εφαρμογή, έπρεπε να βρούμε έναν γενικό τρόπο ώστε να κάνουμε αξιοποιήσιμη όλη αυτή την λειτουργικότητα. Επίσης έπρεπε να μην γινει τελειως γενικά, γιατι αυτός που θα χρησιμοποιεί το back office μέσω Web Services θα πρέπει να έχει κάποιους περιορισμους. Οπότε καταλήξαμε στην δημιουργία ενός επιπέδου facade. Δηλαδή κλάσεων που έχουν μεθόδους που κάνουν κάτι το ολοκληρωμένο, πχ αναζήτηση διαθέσιμων ξενοδοχείων, ώστε να χρησιμοποιηθούν για τα Web Services 1:1. Οπότε το μονο που μας χρειαζοτανε ήταν ένας τρόπος να καλούμε αυτές τις μεθόδους.
Αρχικά όλες οι μέθοδοι χρησιμοποιούσαν primitive τύπους, δηλαδή String, Double, Boolean, Date, αλλά αυτό δεν ήταν αρκετό. Χρειαζόμασταν και σύνθετα αντικείμενα που χρησιμοποιούμε στο back office, όπως για παραδειγμα το αντικείμενο Customer. Το οποίο υπήρχαν δύο τρόποι να το παρουμε σε ένα Web Service, ο ένας ήταν να δημιουργήσουμε xsd που να το περιγραφει ως ComplexType, το οποίο θα σήμαινε ότι πολύ δύσκολα θα μπορούσαμε να το αλλάξουμε από την στιγμή που θα το δώσουμε στον πελάτη, ενώ ο άλλος ήταν να το παρουσιάσουμε ως ένα Map όπου το κλειδί θα είναι το ονομα του member και value η τιμή του. Προφανώς η δεύτερη λύση θεωρήθηκε καλύτερη καθώς το μοντέλο που χρησιμοποιούμε ειναι πολύ μεγάλο και υπάρχουν πολλά που δε θα θέλαμε να τα ξέρει καποιος που φτιαχνει Web Services. Αλλά οι ανάγκες για τύπους δε τελειώνουν εδώ. Χρειαστήκε και η υποστήριξη του αντικειμενου List. Για το συγκεκριμένο υπήρχαν δυο εναλλακτικές, ή θα έπρεπε να το αναπαραστίσουμε όντως ως λίστα, ή θα μπορούσαμε να το παραστίσουμε ως ένα Map όπου για κλειδι να είχε την θέση του αντικειμένου στην λίστα και για τιμή την πραγματική του τιμή. Αλλά προτιμίσαμε να μην το μπλέξουμε. Αλλά δε σταματήσαμε εκει, καθώς υπήρξε ανάγκη να στελνουμε ολοκληρες φωτογραφίες, πχ εικονες απο τοπία. Οπότε χρειαστήκαμε ακομα έναν τύπο, το byte[]. Το οποίο ούτε κατα διανοια δε σκεφτήκαμε να το υποκαταστίσουμε με κάτι αλλο.
Οπότε έπρεπε να βρούμε μια τυποποιηση που να υποστηρίζει τους εξείς τύπους: String, Double, Boolean, Date, Map, List, byte[]. Εξεταστηκαν διαφορα αλλά θέλαμε κάτι που να μην ειναι αποκλειστικά Java, να μην έχει WSDL και τυποποιήσεις που σχεδον κανεις δε χρησιμοποιεί αλλά κάτι απλό που ο καθένας μπορεί να αξιοποιήσει, οπότε καταλήξαμε στο XML-RPC, για το οποίο υπάρχει μια υλοποιηση απο την Apache
Το XML-RPC είναι μια τυποποιηση που χρησιμοποιείται στα Web Services απο το 1999, πράγμα που την κάνει απόλυτα συμβατή με κάθε γνωστή γλώσσα προγραμματισμού. Επίσης η υλοποιηση της ειναι τόσο απλή και γενική που διευκολύνει, διοτι σε αφήνει να δημιουργήσεις ότι θέλεις χωρίς να χρειαστεί να χρησιμοποιήσεις ένα τεράστιο και δυσνοητο specification. Όπως συμβαίνει σε άλλα specs, που σου προσφέρουν την δυνατότητα να ειναι πιο κατανοητό το XML που χρησιμοποιείται για την επικοινωνία, αλλά από την άλλη έχει αρκετά περίπλοκο τρόπο να τα χρησιμοποιήσεις, σωστά. Η βασική ιδέα του XML-RPC είναι ότι ένα Web Service δεν ειναι τίποτα περισσότερο από ένα remote call, κάτι σαν αυτό που έκανε παλιά η CORBA και το RMI. Οπότε τα μονα που χρειάζονται είναι:
α) Παραμετροι ειδόσου+Όνομα Μεθοδου=αίτηση προς την υπηρεσία
β) Παραμετροι εξόδου ήΛάθος=απάντηση της υπηρεσίας
Εμεις προκειμένου να το κάνουμε ακόμα πιο εύκολο αποφασίσαμε ότι θα δεχόμαστε μονο μια παράμετρο εισόδου που θα είναι ένα Map, όπου κλειδι θα έχει το όνομα της παραμέτρου και τιμή την τιμή της. Οπότε έτσι καταφέραμε να έχουμε named parameters που σημαίνει ότι δεν υπάρχει θέμα σειράς, που ειναι κάτι που δε μπορείς εύκολα να ελέγχθει στα Web Services. Επίσης αποφασίσαμε, κατα αντιστοιχία, να έχουμε μονο μια παράμετρο εξόδου, πάλι Map.
Οποτε, ουσιαστικά ο τρόπος λειτουργίας είναι "περνάς ένα Map παραμέτρων σε μια μέθοδο που σου επιστρέφει ένα Map παραμέτρων, ή ένα λάθος". Πράγμα που απλοποιεί πάρα πολύ την δουλειά και του client. Οπου για λόγους testing έχει χρειαστει να υλοποιήσω. Αυτή η ύπαρξη του Map ως κυριου τύπου με οδήγησε στο να δημιουργήσω μια κλάση που ονομα "Mapable" όπου πολύ απλά φτιάχνω subclasses αυτής στην μεριά του Client και δημιουργώ εύκολα και γρήγορα το μοντέλο μου, απλά προσθέτω getters και setters που απλά κάνουν get και put σε ένα private Map data, οποτε και προσομοιώνω αυτό που γίνεται γενικότερα στα Beans. Επισης η Mapable έχει δυο μεθόδους, fromMap(Map) που κάνει προσπέλαση ένα ενα τα κλειδια του Map και ελέγχει αν υπάρχουν οι απαραίτητοι getters, κι αν δεν υπάρχουν το τυπώνει στην κονσόλα ώστε ο προγραμματιστής να τους προσθέσει, κι αν οι getters αυτοι επιστρέφουν Mapable τότε πηγαίνει κι ένα επίπεδο πιο μέσα και ελέγχει και το member κ.ο.κ. Επίσης στην περίπτωση που γυρναει λίστα τότε ελέγχεται αν υπάρχει μεθοδος του τύπου getONOMA_MEMBER(int index) ώστε να ελεγχθει αν αυτο που γυρνάει ειναι όντως αυτο που έχει η λίστα.
Βέβαια ακόμα το έχω σε πειραματικό στάδιο, αλλά πιστεύω ότι θα μπορούσε να φανει πολύ χρήσιμο να μην βάζεις private members αλλά να τα κρατας όλα σε ένα private Map.

ΥΓ: Οποιος ενδιαφέρετε ή έχει καποια επιπλέον ιδέα, πολύ ευχαρίστως να μου την γράψει.

To MSN Messenger του Μάκη

Την περασμένη εβδομάδα μου στειλανε ένα πολύ πετυχημένο email με μια εικονα του MSN Messenger του Μάκη!

LinkWithin

Blog Widget by LinkWithin

Mobile edition