Κατανεµηµένα Συστήµατα ΙΙ Μάθηµα Ελεύθερης Επιλογής, Εαρινού Εξαµήνου Τοµέας Εφαρµογών και Θεµελιώσεων Αθανάσιος Κίναλης Πέµπτη, 21 Ιουνίου, 2007 Αίθουσα ΑΠ7 Μελετάµε ένα κατανεµηµένο σύστηµα για την κράτηση αεροπορικών ϑέσεων Εξετάσαµε την αρχιτεκτονική του συστήµατος Επισκόπηση της ϐιβλιοθήκης JDBC για την σύνδεση µε την ϐάση δεδοµένων Επισκόπηση της ϐιβλιοθήκης java.net και την υλοποίηση του συστήµατος µε Sockets Υλοποίηση του συστήµατος µε RMI Υλοποίηση του συστήµατος µε Java Servlets Βασιζόµαστε στο µοντέλο Πελάτη-Εξυπηρέτη ιαχωρίσαµε τον Εξυπηρέτη σε 3 επίπεδα Επίπεδο εδοµένων Βάση εδοµένων Επίπεδο Αντικειµένων Επίπεδο Λογικής Λογική επέκταση του µοντέλου πελάτη-εξυπηρέτη Χωρίζουµε την λειτουργικότητα σε ανεξάρτητα τµήµατα Κάθε τµήµα αναθέτετε σε διαφορετικό εξυπηρέτη (tier) Μια αίτηση µπορεί να απασχολήσει πολλούς εξυπηρέτες Αλυσιδωτές αιτήσεις κατά µήκος των διαφορετικών τµηµάτων Παράδειγµα Multi-tier Συστήµατος ϑα υλοποιήσουµε το σύστηµα µε την χρήση JMS (Java Message Service API) Αφορά την διασύνδεση των δύο υψηλότερων επιπέδων Επίπεδο παρουσίασης (Presentation Tier) Επίπεδο λειτουργιών (Business Logic Tier) Τα χαµηλότερα επίπεδα (και ο τρόπος διασύνδεσης) παραµένουν τα ίδια Επίπεδο αντικειµένων (Object Tier) Επίπεδο δεδοµένων (Data Tier)
Η ανταλλαγή µηνυµάτων είναι µια µέθοδος επικοινωνίας ανάµεσα σε τµήµατα λογισµικού ή εφαρµογών Ενα σύστηµα ανταλλαγής µηνυµάτων παρέχει λειτουργίες µεταξύ οµοτίµων πελατών Κάθε πελάτης µπορεί να λάβει και να στείλει µηνύµατα σε οποιοδήποτε άλλο πελάτη Το σύστηµα παρέχει τις λειτουργίες για τη δηµιουργία, αποστολή, λήψη και ανάγνωση των µηνυµάτων Ασύνδετη επικοινωνία Ο αποστολέας δε χρειάζεται να γνωρίζει τίποτα για τον παραλήπτη και αντίστροφα Ο αποστολέας και ο παραλήπτης δε χρειάζεται να είναι συνδεδεµένοι για να ολοκληρωθεί η αποστολή/λήψη Κοινή µορφή µηνυµάτων Αξιόπιστη επικοινωνία Ασύγχρονη επικοινωνία Ευελιξία στην υλοποίηση Συνδέει ανεξάρτητες συνιστώσες λογισµικού Κάθε συνιστώσα µπορεί να αντικατασταθεί εύκολα Η ανταλλαγή δεδοµένων δε διακόπτει τη ϱοή του προγράµµατος Επιτρέπει τη λειτουργία της εφαρµογής ακόµα και όταν κάποιες συνιστώσες είναι ανενεργές Java Message Service Specification JMS Παροχέας: Ενα σύστηµα ανταλλαγής µηνυµάτων που υλοποιεί τις διεπαφές JMS και παρέχει εργαλεία διαχείρισης και ελέγχου J2EE JBoss WebSphere Πελάτης JMS: Java λογισµικό που παράγει ή καταναλώνει µηνύµατα Μηνύµατα: Αντικείµενα για ανταλλαγή πληροφοριών ανάµεσα στους πελάτες Αντικείµενα ιαχειριστή: Ορίζονται από το διαχειριστή και χρησιµοποιούνται από τους πελάτες Point-to-Point (Message ) Κάθε µήνυµα έχει µόνο έναν παραλήπτη εν υπάρχει συγχρονισµός Ο παραλήπτης επιβεβαιώνει τη λήψη Point-to-Point Επικοινωνία
Publish/Subscribe (Topic) Ενα µήνυµα µπορεί να έχει πολλούς παραλήπτες Ενας πελάτης µπορεί να λάβει µηνύµατα µόνο αφού εγγραφεί στο ϑέµα Publish/Subscribe Επικοινωνία ιαχειριζόµενα Αντικείµενα Βιοµηχανίες Συνδέσεων Προορισµοί ηµιουργούνται µέσω του Sun Application Server Οι προορισµοί δίνουν όνοµα σε ουρές µηνυµάτων ή ϑέµατα (topics) Καταγράφονται στο Java Naming and Directory Interface -- JNDI Connection factory: Χρησιµοποιείται από τους πελάτες για τη σύνδεση µε το παροχέα JMS Context ctx = new InitialContext(); ConnectionFactory connectionfactory = (ConnectionFactory) ctx.lookup("jms/connectionfactory"); Προορισµοί: Ορίζουν τον προορισµό ή την πηγή ενός µηνύµατος Destination mydest = (Destination)ctx.lookup("jms/MyTopic"); my = ()ctx.lookup("jms/my"); Συνδέσεις: Αντιπροσωπεύει τη σύνδεση µε τον παροχέα JMS Connection con = connectionfactory.createconnection(); connection.start(); con.close(); Σύνοδοι: Κρατούν πληροφορία για τη χρήση του JMS παροχέα χρησιµοποιείται για τη δηµιουργία αντικειµένων Παραγωγών Μηνυµάτων Καταναλωτών Μηνυµάτων Μηνυµάτων Session session = connection.createsession(false, Session.AUTO_ACKNOWLEDGE); Παραγωγοί Μηνυµάτων MessageProducer producer = session.createproducer(my); MessageProducer producer = session.createproducer(mytopic); producer.send(message); Καταναλωτές Μηνυµάτων MessageConsumer consumer = session.createconsumer(my); MessageConsumer consumer = session.createconsumer(mytopic); Message m = consumer.receive(); Listener mylistener = new MessageListener() { public void onmessage(message message) {...; consumer.setmessagelistener(mylistener);
Μηνύµατα Επικεφαλίδα Ιδιότητες (Προαιρετικά) Σώµα (Προαιρετικά) TextMessage java.lang.string MapMessage Ζεύγη κλειδιών τιµών BytesMessage υαδικά εδοµένα StreamMessage Μεταφέρει σειριακά τύπους δεδοµένων JAVA ObjectMessage java.io.serializable Message null TextMessage message = session.createtextmessage(); message.settext(msg_text); // msg_text is a String producer.send(message); Υλοποιούµε τρεις συναλλαγές µεταξύ Πελάτη-Εξυπηρέτη (δύο υψηλότερα επίπεδα) Αναζήτηση Πτήσεων επιστρέφει όλες τις πτήσεις που υπάρχουν στη ϐάση δεδοµένων Αναζήτηση Θέσεων επιστρέφει όλες τις κρατήσεις που αφορούν ένα συγκεκριµένο πελάτη Κράτηση ϑέσης υποθέτουµε ότι η πτήση και ο πελάτης υπάρχουν ήδη στους πίνακες της ϐάσης δεδοµένων (για χάριν ευκολίας) Οι υπόλοιπες λειτουργίες υλοποιούνται αντίστοιχα
Οι συνιστώσες λογισµικού για την υλοποίηση σε JMS δεν είναι πολύ διαφορετικές από αυτές που χρησιµοποιούν Sockets, RMI Η ϐασικές διαφορές είναι: Η επικοινωνία είναι ασύγχρονη Πρέπει να ϐρεθεί ο τύπος δεδοµένων που µεταφέρει ένα µήνυµα ηµιουργούµε 2 ουρές µηνυµάτων: µία για αιτήσεις και µία για απαντήσεις Ο πελάτης στέλνει µηνύµατα αιτήσεων και περιµένει να λάβει απαντήσεις Ο εξυπηρέτης περιοδικά ελέγχει την ουρά και περιµένει αιτήσεις Πρέπει να χειριζόµαστε σφάλµατα τύπου JMSException Συνιστώσα Server import java.jms.*; import java.naming.*; import java.sql.*; public Server { Context Factory Receiver Session Factory Session Producer jndicontext = null; recv_queueconfactory = null; recv_queuecon = null; receiver = null; recv_queuesession = null; recv_queue = null; send_queueconfactory = null; send_queuecon = null; send_queuesession = null; send_queue = null; sender = null; Connection theconnection; Συνιστώσα Server -- constructor public Server() { initializedb(); //Get JNDI context jndicontext = new InitialContext(); /* Look up connection factories and queues. If either does not exist, exit.*/ recv_queueconfactory = (Factory) jndicontext.lookup("recvfactory"); recv_queue = () jndicontext.lookup("recv"); send_queueconfactory = (Factory) jndicontext.lookup("sendfactory"); recv_queue = () jndicontext.lookup("send"); catch (NamingException e) { System.err.println("JNDI API lookup failed: " + e.tostring()); System.exit(1); Συνιστώσα Server -- constructor... /* * Create connections. */ recv_queuecon = recv_queueconfactory.create() recv_queuesession = recv_queuecon.createsession(false, Session.AUTO_ACKNOWLEDGE); receiver = recv_queuesession.createreceiver(recv recv_queuecon.start();
Συνιστώσα Server -- listen() public void listen() { while (true) { Message m = receiver.receive(100); if (m!= null) { if (m instanceof TextMessage) { message = (TextMessage) m; if (m.gettext() == "GET_FLIGHTS") { getflights(); else if (...) {... else { continue; Συνιστώσα Server -- getflights() public void getflights() { Flight flights[] = retrieveflightsdb(); Message om = send_queuesession.createobjectmessag om.setobject(flights); sender.send(om); public static void main(string[] args) { Server s = new Server(); s.listen(); Συνιστώσα Client import java.jms.*; import java.naming.*; public Client { Context Factory Producer Session Factory Session Receiver jndicontext = null; query_queueconfactory = null; query_queuecon = null; inquirer = null; query_queuesession = null; query_queue = null; resp_queueconfactory = null; resp_queuecon = null; resp_queuesession = null; resp_queue = null; responder = null; Συνιστώσα Client -- constructor public Client() { initializegui(); //Get JNDI context jndicontext = new InitialContext(); /* Look up connection factories and queues. If eith * not exist, exit.*/ resp_queueconfactory = (Factory) jndicontext.lookup("sendfactory"); resp_queue = () jndicontext.lookup("sendque query_queueconfactory = (Factory) jndicontext.lookup("recvfactory"); query_queue = () jndicontext.lookup("recvqu catch (NamingException e) { System.err.println("JNDI API lookup failed: " + e.tostring()); System.exit(1);
Συνιστώσα Client -- constructor public void retrieveflights() { Flight flights[] = null; /* Message tm = send_queuesession.createtextmessage( * Create connections. tm.settext("get_flights"); */ inquirer.send(tm); Message m = responder.receive(10000); resp_queuecon = if (m!= null) { resp_queueconfactory.create(); if (m instanceof ObjectMessage) { resp_queuesession = message = (ObjectMessage) m; resp_queuecon.createsession(false, flights = (Flights[])m.getObject(); Session.AUTO_ACKNOWLEDGE); else { responder = recv_queuesession.createreceiver(resp_queue); displayerror(); resp_queuecon.start();... Συνιστώσα Client -- getflights() public static void main(string[] args) { Client c = new Client(); c.listen(); Κάναµε µια γρήγορη επισκόπηση των ϐασικών ιδεών των τεχνολογιών Ανταλλαγής Μηνυµάτων Εστιάσαµε στην τεχνολογία JMS Παρουσιάσαµε την υλοποίηση για επιλεγµένες λειτουργίες στον Εξυπηρέτη και Πελάτη