420 likes | 561 Views
HTTP , RMI , SOAP a ďalšie akronymy pre výmenu dát medzi počítačmi. Róbert Novotný robert.novotny@upjs.sk. Prečo? Začo? Načo?. výmena dát je takpovediac štandardom medzi ľuďmi medzi človekom a počítačom medzi počítačom a počítačom ak dáta neprúdia, niečo je zle
E N D
HTTP, RMI, SOAP a ďalšie akronymy pre výmenu dát medzi počítačmi Róbert Novotný robert.novotny@upjs.sk
Prečo? Začo? Načo? • výmena dát je takpovediac štandardom • medzi ľuďmi • medzi človekom a počítačom • medzi počítačom a počítačom • ak dáta neprúdia, niečo je zle • klasický príklad: výmena dát medzi prehliadačom • protokol: HTTP • dáta: HTML, čistý text, binárny neporiadok • človek dátam rozumie, čo však počítač? Ako ustanoviť protokoly pre jednoduchú výmenu štruktúrovaných dát medzi dvoma počítačmi?
Filozofia • už od nepamäti (197x): filozofia vzdialeného volania procedúr (remote procedure call, RPC) • viacero špecifikácií: RPC, CORBA, DCOM, SOAP... • cieľ: • jednoduché nastavenie • jazykovo a platformovo nezávislé • zamlženie "lokálne volanie-vzdialené volanie" • podpora prirodzených dátových typov
Prihlasovanie sa na skúšky • jednoduchý príklad prihlasovania sa na skúšku • dohodnime sa na operáciách • zoznam termínov pre daný predmet • prihlásenie sa na daný predmet na daný dátum • operácie budú reprezentované interfejsom public interface ExamRegistration { List<Term> getTerms(String courseCode); boolean signup(Student student, String courseCode, Date date); }
Prečo interfejs? • môžeme vyrobiť viacero implementácií • jednoduchú s napevno danými termínmi • databázovú • integrujúcu sa s AISom • používajúcu vzdialené volania • implementácie môžeme vymieňať a aplikácia bude vyžadovať minimum zmien public class SimpleExamRegistration implements ExamRegistration { ... }
RMI – vzdialené volanie metód • RMI – remote method invocation http://java.sun.com/javase/technologies/core/basic/rmi/index.jsp • transportná vrstva: TCP • serializácia: binárna, prebratá z Javy • interop: len Java vs. Java
RMI – základné pojmy • vzdialený objekt: metódy sú volané klientom. Reprezentovaný service classom. • registry: register objektov, ktoré dokážu obsluhovať vzdialené volania od klientov • server: vykonáva registráciu vzdialených objektov • skeleton: špinavá práca na strane servera – sieťová komunikácia, (de)serializácia objektov • stub: špinavá práca na strane klienta
RMI – ako vyzerá komunikácia? • ako vyzerá typická správa? • binárny neporiadok posielaný cez TCP • objekty sú serializované pomocou Java Serialization • špecifikácia binárneho formátu:http://java.sun.com/javase/6/docs/platform/serialization/spec/serialTOC.html
Postup krokov v klasickom RMI Server: • vytvoriťvzdialený interface s metódami (extends Remote, metódy throws RemoteException) • vytvoriť implementačnú triedu • zaregistrovať triedu v Registry Klient: • získať objekt Registry z daného servera • získať interfejs (za ním je stub) • na ňom volať metódy
Ukážka kódu public interface ExamRegistration extends java.rmi.Remote{ List<Term> getTerms(String courseCode) throws java.rmi.RemoteException; boolean signup(Student student, String courseCode, Date date) throws java.rmi.RemoteException; } • Hádzanie výnimiek musíme dodať aj do implementácie (teda do SimpleExamRegistration) • všetky triedy používané vo volaniach musia implementovať interfejs java.io.Serializable! • public class Student implements Serializable • public class Term implements Serializable
Ukážka kódu servera 1. Vytvoríme inštanciu implementácie ExamService service = new SimpleExamService(); 2. Pretvoríme ju na skeleton, teda vzdialený objekt ExamService skeleton = (ExamService) UnicastRemoteObject.exportObject(service, 0); 3. Získame inštanciu registry Registry registry = LocateRegistry.getRegistry(); 4. Zaregistrujeme skeleton v registry registry.rebind("EXAM", skeleton);
Ukážka kódu klienta 1. získať objekt registry z daného servera Registry registry = LocateRegistry.getRegistry("localhost"); 2. získať interfejs (za ním je stub) ExamService stub = (ExamService) registry.lookup("EXAM"); 3. voláme metódy klasickým spôsobom stub.getTerms("UINF/PAZ1c"); Alternatívne môžeme použiť aj: ExamService stub = java.rmi.Naming.lookup("//localhost/EXAM") stub.getTerms("UINF/PAZ1C");
Výhody a nevýhody + jednoduché použitie, priamo v Jave, žiadne závislosti + v prípade, že sa u klienta nenachádzajú binárky tried, je možné ich dotiahnuť zo servera - pomerne náročná konfigurácia - firewally blokujú komunikáciu + možno tunelovať cez HTTP - náročná konfigurácia Ak nepotrebujeme interop a vieme, že firewally nie sú problémom, je RMI najjednoduchšou cestou.
Caucho Hessian / Burlap • Hessian http://hessian.caucho.com/ • Burlap http://www.caucho.com/resin-3.0/protocols/burlap.xtp • transportná vrstva: HTTP • serializácia: • binárna (Hessian) • XML (Burlap) • interop: • Hessian: implementácie v C++, C#, Python, PHP • Burlap: len Java-Java
Hessian – základné pojmy • HessianServlet (BurlapServlet): na strane servera spracováva HTTP požiadavky, (de)serializuje objekty a priamo volá implementačnú triedu. • interfejs: zodpovedá interfejsu z príkladu. Hessian zaň na strane klienta i serveru dosadí implementáciu podporujúcu vzdialené volania • proxy: na strane klienta rieši HTTP komunikáciu a (de)serializáciu objektov
Hessian / Burlap – ako vyzerá komunikácia? • ako vyzerá typická správa? • Hessian: HTTP POST požiadavka, dáta v binárnej forme • Burlap: HTTP POST požiadavka, dáta v XML POST / HTTP/1.1 Content-Type: text/xml User-Agent: Java/1.5.0_09 Host: 127.0.0.1:8888 Connection: keep-alive Content-Length: 58 <burlap:call> <method>getCurrentDate</method> </burlap:call> HTTP/1.1 200 OK Content-Length: 62 Server: Jetty(6.1.5) <burlap:reply><date>20080311T223714.671Z</date></burlap:reply>
Postup krokov pri použití Servletový kontajner: • vytvoriť inštanciu implementačnej triedy • nakonfigurovať HessianServlet (BurlapServlet) a priradiť mu implementačný objekt Klient: • vytvoriť továreň na proxy volajúcu príslušnú URL adresu • získať z nej interfejs (za ním je stub) • na ňom volať metódy
Ukážka kódu servera (Jetty) 1. Vytvoríme inštanciu implementácie ExamService service = new SimpleExamService(); 2. Nakonfigurujeme HessianServlet, priradíme mu inštanciu HessianServlet hessianServlet = new HessianServlet(); hessianServlet.setHomeAPI(ExamService.class); hessianServlet.setHome(new SimpleExamService()); 3. Nakonfigurujeme servletový kontajner a spustíme ho Server server = new Server(8080); Context context = new Context(server, "/terms"); context.addServlet(new ServletHolder(hessianServlet), "/*"); server.start(); server.join(); Služba bude dostupná na http://localhost:8080/terms
Alternatíva: nasadenie do servlet. kontajnera • HessianServlet je klasický servlet, môžeme ho teda nasadiť do servletového kontajnera (Tomcat, Jetty...) <servlet> <servlet-name>TermsServlet</servlet-name> <servlet-class> com.caucho.hessian.server.HessianServlet </servlet-class> <init-param> <param-name>home-class</param-name> <param-value>sk.novotnyr.SimpleExamService</param-value> </init-param> <init-param> <param-name>home-api</param-name> <param-value>sk.novotnyr.ExamService</param-value> </init-param> </servlet> <servlet-mapping> <url-pattern>/*</url-pattern> <servlet-name>TermsServlet</servlet-name> </servlet-mapping> web.xml Služba bude dostupná na http://localhost:8080/terms
Ukážka kódu klienta 1. vytvoriť továreň na proxy HessianProxyFactory factory = new HessianProxyFactory(); 2. získať interfejs pre danú URL adresu (za ním je proxy) String url = "http://localhost:8080/terms"; TermService proxy = (TermService) factory.create(TermService.class, url); 3. voláme metódy klasickým spôsobom List<Term> terms = proxy.getTerms("UINF/PAZ1c"); BurlapServlet a BurlapProxyFactory fungujú analogicky
Výhody a nevýhody + jednoduché použitie, knižnica je 273 kB JAR, žiadne závislosti + ten je možné ešte zmenšiť (Hessian 83 kB) + jestvuje aj minimalistická verzia aj pre J2ME (mobily) + slušný interop (len Hessian) + čitateľné správy (len Burlap) - vlastný mechanizmus serializácie môže zlyhávať v extrémnych prípadoch Ak potrebujeme interop a RMI robí problémy, je to dobrá alternatíva. Burlap = (Hessian + XML) - interop
Spring HTTP Invoker • Spring HTTP Invoker http://www.springframework.org/ • transportná vrstva: HTTP • serializácia: binárna, prebratá z Javy • interop: len Java-Java
Spring HTTP Invoker – základné pojmy • DispatcherServlet: servlet, cez ktorý idú všetky požiadavky v Spring Frameworku. • HttpInvokerServiceExporter: vie zobrať ľubovoľnú triedu a interfejs a vytvoriť z neho vzdialene volateľný objekt. Obohatí ju o schopnosť (de)serializovať objekty • proxy: na strane klienta rieši HTTP komunikáciu a (de)serializáciu objektov
Spring HTTP Invoker – ako vyzerá komunikácia? • ako vyzerá typická správa? • HTTP POST požiadavka, za ňou dáta v binárnej forme • objekty sú serializované pomocou Java Serialization • posielané inštancie musia implementovať java.io.Serializable
Postup krokov pri použití Servletový kontajner: • nakonfigurovať DispatcherServlet • vytvoriť inštanciu implementačnej triedy • nakonfigurovať HttpInvokerServiceExporter a asociovať s ním implementačnú triedu Klient: • vytvoriť továreň na proxy volajúcu príslušnú URL adresu • získať z nej interfejs (za ním je proxy) • na ňom volať metódy
Ukážka kódu servera (Jetty) 1. Nakonfigurujeme DispatcherServlet DispatcherServlet dispatcher = new DispatcherServlet(); dispatcher.setContextConfigLocation("classpath:ctx.xml"); 2. Nakonfigurujeme springovský aplikačný kontext <bean name="/terms" class="org.springframework.[…].HttpInvokerServiceExporter"> <property name="service"> <beanclass="sk.novotnyr.SimpleExamRegistration" /> </property> <property name="serviceInterface" value="sk.novotnyr.ExamRegistration" /> </property> </bean> ctx.xml 3. Nakonfigurujeme servletový kontajner a spustíme ho (viď príklad z konfigurácie Hessianu)
Ukážka kódu klienta 1. vytvoriť továreň na proxy HttpInvokerProxyFactoryBean factory = new HttpInvokerProxyFactoryBean(); 2. nastaviťobslužný interfejs a URL (za ňou je proxy) factory.setServiceInterface(ExamRegistration.class); factory.setServiceUrl("http://localhost:8080/"); factory.afterPropertiesSet(); 3. voláme metódy klasickým spôsobom List<Term> terms = proxy.getTerms("UINF/PAZ1c");
Výhody a nevýhody Spring HTTP Invoker + ponecháva výhody RMI, odstraňuje jeho neduhy + možno exportnúť ľubovoľný interfejs v RMI sme museli dediť od Remote a hádzať výnimky - žiadny interop - pomerne veľký JAR so závislosťami (1,7 MB), keďže používame Spring Framework Ak používame Spring Framework, Spring HTTP Invoker je veľmi užitočným vylepšením RMI.
SOAP / Web Services • Web Services – webové služby http://www.w3.org/2002/ws/ • SOAP – protokol pre výmenu XML správ • transportná vrstva: HTTP, SMTP (maily), JMS (Java Messaging), Jabber, JavaVM (v rámci virtuálneho stroja) • serializácia: XML • interop: univerzálny Posielame XML dáta z bodu A do bodu B.
Web Services – základné pojmy • endpoint: spracováva SOAP správy a odpovedá na ne, rieši (de)serializáciu • operácia: vzdialene volateľná metóda • port: logická množina operácii. Analógia interfejsu z OOP • služba: logická množina portov • binding: určuje formát správ a používaný transport • popis služby: metadáta o službe – zoznamslužieb, portov, operácií, dátové typy, návratové hodnoty, špecifikácia transportného protokolu. Popis služieb pomocou XML jazyka WSDL.
SOAP – ako vyzerá komunikácia? [HTTP POST hlavička] [XML hlavička] <SOAP-ENV:Envelope> <SOAP-ENV:Body> <ns1:doubleAnInteger <param1 xsi:type="xsd:int">123</param1> </ns1:doubleAnInteger> </SOAP-ENV:Body> </SOAP-ENV:Envelope> Otázka i odpoveď vyzerajú na prvý pohľad ešte horšie, toto je zjednodušená verzia... [hlavička HTTP odpovede] [XML hlavička] <SOAP-ENV:Envelope <SOAP-ENV:Body> <ns1:doubleAnIntegerResponse <return xsi:type="xsd:int">246</return> </ns1:doubleAnIntegerResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
SOAP a implementácie v Jave • SOAP je všeobecný, jestvuje viacero Java implementácií • Apache Axis 2http://ws.apache.org/axis2/ • Apache CXF (zlúčenie CodeHaus XFire + ObjectWeb Celtix) http://incubator.apache.org/cxf • každý aplikačný server poskytuje svoju implementáciu (JBoss, IBM WebSphere) • v Jave existuje štandardizovaná sada interfejsov a tried: JAX-WS(http://java.sun.com/webservices/technologies) • pre jednoduchosť ukážeme: CXF nad HTTP transportom
Postup krokov v SOAP – zdola nahor Server: • začneme od metadát – vytvoríme WSDL • vygenerujeme triedy pre serverovskú časť • dodáme implementáciu • zverejníme WSDL a adresu koncového bodu Výhodné, ak máme v úmysle interop Klient: • získame WSDL • vygenerujeme klientské triedy
Postup krokov v SOAP – zhora nadol Server: • vezmeme interfejs a oanotujeme ho • zverejníme ho (metadáta sa vytvoria automaticky) Výhodné, ak chceme rýchlo niečo spustiť. Klient: • získame WSDL • vygenerujeme klientské triedy • alebo vezmeme továreň, ktorá vráti proxy
Postup krokov v SOAP – zhora nadol s JAX-WS Server: • vezmeme interfejs a oanotujeme ho @WebService public interface ExamRegistration { List<Term> getTerms(String courseCode); boolean signup(Student student, String courseCode, Date date); } • zverejníme ho (metadáta sa vytvoria automaticky) import javax.xml.ws.Endpoint; Endpoint.publish("http://localhost:8080/terms", new SimpleExamRegistration());
Postup krokov v SOAP – zhora nadol s JAX-WS Endpoint.publish("http://localhost:8080/terms", new SimpleExamRegistration()); • automaticky sa vytvorí endpoint na danej adrese • vytvorí sa: • služba ExamRegistrationService • port ExamRegistration • operácie getTerms() a signup() • automatické mapovanie tried Student a Term na XML reprezentácie a späť • binding pre HTTP protokol • spustí sa HTTP server • metadáta sa zverejnia na http://localhost:8080/terms?wsdl
Ukážka kódu pre klienta s JAX-WS 1. získame adresu WSDL metadát 2. spustíme generovanie tried pre klienta wsdl2java.bat -d d:\bezadis\src -p sk.novotnyr.client http://localhost:8080/terms?wsdl 2. vygeneruje sa množstvo tried do balíčka sk.novotnyr ExamRegistrationService, GetTerms, GetTermsResponse,... 3. vytvoríme inštanciu služby a z nej získame inštanciu proxy ExamRegistrationService service = new ExamRegistrationService() ExamService proxy = service.getPort(ExamService.class); 4. na proxy voláme metódy ExamRegistrationService sa vytvorí nad adresou prebratou zo servera a nad príslušným WSDL
Výhody a nevýhody SOAP + buzzword + maximálna flexibilita + možno zvoliť ľubovoľný transport + neobmedzený interop + bezpečnosť - podpisovanie správ, šifrovanie, timestamping, garantované doručenie... - často zložitá konfigurácia - nutnosť uvážiť výkon (konverzia na XML reprezentáciu je náročná) - pre samostatnú serverovskú aplikáciu treba často kopu JARov (CXF: 17MB!) + od Javy 6 je k dispozícii priama podpora pre SOAP Ak vieme, že interop je prioritou, nemáme inú možnosť. Všeobecnosť a komplexnosť = širšie a komplexnejšie problémy