PA165/Cvičení Remoting
Obsah
JavaRMI
Nejdřív si předvedeme JavaRMI.
Na tabule.jar je JAR soubor s následující definicí:
package cz.muni.fi.pa165.rmi; import java.rmi.Remote; import java.rmi.RemoteException; public interface Tabule extends Remote { void zverejni(String text) throws RemoteException; }
Klient
Vytvořte si projekt, přidejte k němu JAR s rozhraním a vytvořte klienta:
package cz.muni.fi.pa165.rmi; import java.rmi.registry.Registry; import java.rmi.registry.LocateRegistry; import java.rmi.RemoteException; import java.rmi.NotBoundException; public class Pisalek { public static void main(String[] args) throws RemoteException, NotBoundException { if(args.length!=2) { System.out.println("Usage: java "+Pisalek.class.getName()+" host text"); System.exit(1); } String host = args[0]; String text = args[1]; Registry remregistry = LocateRegistry.getRegistry(host); Tabule tabule = (Tabule) remregistry.lookup("tabule"); tabule.zverejni(text); } }
Klienta spusťte vůči serveru cvičícího na nymfe31.fi.muni.cz.
Server
Utvořte dvojice se sousedem a vyzkoušejte komunikaci s jeho serverem.
Na straně serveru je třeba spustit na pozadí program
rmiregistry &
mít implementaci serveru:
package cz.muni.fi.pa165.rmi; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.server.ServerNotActiveException; import java.rmi.server.UnicastRemoteObject; public class TabuleImpl implements Tabule { synchronized public void zverejni(String text) throws RemoteException { try { System.out.println(UnicastRemoteObject.getClientHost() + ": " + text); } catch (ServerNotActiveException e) { e.printStackTrace(); } } public static void main(String[] args) throws RemoteException { System.out.println("startuji Tabuli"); Tabule stub = (Tabule) UnicastRemoteObject.exportObject(new TabuleImpl(), 0); LocateRegistry.getRegistry().rebind("tabule", stub); } }
která musí být spuštěna se správnými parametry:
java -Djava.rmi.server.codebase=http://acrab.ics.muni.cz/~makub/rmi/tabule.jar -cp tabule.jar:. cz.muni.fi.pa165.rmi.TabuleImpl
Metoda v rozhraní Tabule nepřijímá žádné třídy, které by JVM na straně serveru neznal. Pokud by tomu tak bylo, i klient by musel vystavit takové třídy někde na webu a musel by být spuštěn s parametrem -Djava.rmi.server.codebase
, aby si server mohl třídy stáhnout.
SOAP/WSDL Web Services
Ukážeme si web services pomocí Apache CXF.
Spusťte si IntelliJ:
module add jdk-1.6.0_16 idea-8.1 maven-2.0.9 idea.sh
SOAP server
Vytvořte si nový projekt typu Maven zvaný třeba soap-cxf-server. Do pom.xml připište:
<properties> <cxf.version>2.2.4</cxf.version> </properties> <dependencies> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>${cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>${cxf.version}</version> </dependency> <!-- Jetty is needed if you're are not using the CXFServlet --> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http-jetty</artifactId> <version>${cxf.version}</version> </dependency> </dependencies> <build> <plugins> <!-- nastaveni verze zdrojaku --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>6</source> <target>6</target> </configuration> </plugin> </plugins> </build>
Vytvořte package cz.muni.fi.pa165.soap a v něm tyto třídy:
package cz.muni.fi.pa165.soap; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.ws.WebFault; @WebFault(name = "Vyjimka") @XmlAccessorType(XmlAccessType.FIELD) public class Vyjimka extends RuntimeException { String duvod; public Vyjimka(String message,String duvod) { super(message); this.duvod = duvod; } }
package cz.muni.fi.pa165.soap; import javax.jws.WebService; import javax.jws.WebParam; @WebService public interface Tabule { void zverejni(@WebParam(name = "text")String text) throws Vyjimka; }
package cz.muni.fi.pa165.soap; import javax.annotation.Resource; import javax.jws.WebService; import javax.servlet.http.HttpServletRequest; import javax.xml.ws.WebServiceContext; import javax.xml.ws.handler.MessageContext; @WebService(endpointInterface = "cz.muni.fi.pa165.soap.Tabule", serviceName = "Tabule") public class TabuleImpl implements Tabule { @Resource WebServiceContext wsCtx; public void zverejni(String text) throws Vyjimka { if (text == null || text.isEmpty()) throw new Vyjimka("empty text", "retezec prazdny"); System.out.println(getClient() + ":" + text); } private String getClient() { MessageContext msgCtx = wsCtx.getMessageContext(); HttpServletRequest req = (HttpServletRequest) msgCtx.get(MessageContext.SERVLET_REQUEST); return req.getRemoteHost(); } }
package cz.muni.fi.pa165.soap; import javax.xml.ws.Endpoint; public class Server { public static void main(String[] args) throws InterruptedException { String address = "http://localhost:9000/tabule"; Endpoint.publish(address, new TabuleImpl()); System.out.println("Server ready..."); } }
Spusťte třídu cz.muni.fi.pa165.soap.Server a navštivte URL http://localhost:9000/tabule?wsdl.
SOAP klient
Aniž uzavřete předchozí projekt, vytvořte nový projekt zvaný třeba soap-cxf-klient. Děláme to tak proto, abychom viděli, že jediným pojítkem mezi serverem a klientem je WSDL popis služby.
Do pom.xml připište
<properties> <cxf.version>2.2.4</cxf.version> </properties> <dependencies> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>${cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>${cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http-jetty</artifactId> <version>${cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-common-utilities</artifactId> <version>${cxf.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.cxf</groupId> <artifactId>cxf-codegen-plugin</artifactId> <version>${cxf.version}</version> <executions> <execution> <id>generate-sources</id> <configuration> <wsdlOptions> <wsdlOption> <wsdl>http://localhost:9000/tabule?wsdl</wsdl> </wsdlOption> </wsdlOptions> </configuration> <goals> <goal>wsdl2java</goal> </goals> </execution> </executions> </plugin> <!-- nastaveni verze zdrojaku --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>6</source> <target>6</target> </configuration> </plugin> <!-- zavislosti na JARech --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <configuration> <outputDirectory> ${project.build.directory} </outputDirectory> </configuration> </plugin> </plugins> </build>
Spusťte Maven goal mvn generate-sources a pak přidejte třídu:
package cz.muni.fi.pa165.soap; public class Klient { public static void main(String[] args) { Tabule tabule = new Tabule_Service().getTabuleImplPort(); try { tabule.zverejni("ahoj"); tabule.zverejni(""); } catch (Vyjimka_Exception e) { e.printStackTrace(); System.out.println(e.getFaultInfo().getDuvod()); } } }
Spusťte třídu Klient.
Pro kopii všech potřebných knihoven zadejte příkaz mvn dependency:copy-dependencies.
URL na službu se bere z WSDL popisu služby. Pokud ho potřebujete změnit, lze to udělat takto:
((BindingProvider) tabule).getRequestContext() .put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, "http://nymfe41.fi.muni.cz:9000/tabule");
AJAX a JSON
viz Cvičení AJAX.