PA165/Cvičení Remoting: Porovnání verzí

Z FI WIKI
Přejít na: navigace, hledání
(JSON-RPC klient)
(JSON-RPC server)
Řádka 213: Řádka 213:
 
import java.io.IOException;
 
import java.io.IOException;
 
import java.net.InetSocketAddress;
 
import java.net.InetSocketAddress;
 +
import java.util.logging.*;
 
import org.simpleframework.http.Request;
 
import org.simpleframework.http.Request;
 
import org.simpleframework.http.Response;
 
import org.simpleframework.http.Response;
Řádka 247: Řádka 248:
 
   
 
   
 
     public static void main(String[] args) throws IOException {
 
     public static void main(String[] args) throws IOException {
         System.out.println("starting server ...");
+
         //enable logging
 +
        Logger log = LogManager.getLogManager().getLogger("");
 +
        log.setLevel(Level.ALL);
 +
        for (Handler h : log.getHandlers()) h.setLevel(Level.FINEST);
 +
        //start server
 +
        Logger.getLogger(SimpleServer.class.getName()).info("starting server");
 
         JsonRpcServer tabule = new JsonRpcServer(new TabuleImpl(), Tabule.class);
 
         JsonRpcServer tabule = new JsonRpcServer(new TabuleImpl(), Tabule.class);
 
         Connection connection = new SocketConnection(new SimpleServer(tabule));
 
         Connection connection = new SocketConnection(new SimpleServer(tabule));
Řádka 255: Řádka 261:
 
}
 
}
 
</java>
 
</java>
 
Pokud chcete vidět přicházející JSON-RPC volání, vytvořte soubor '''src/main/resources/logging.properties''' s obsahem
 
<nowiki>
 
#vypis pujde na konzolu
 
handlers=java.util.logging.ConsoleHandler
 
# handler propusti vsechno od finest
 
java.util.logging.ConsoleHandler.level=FINEST
 
# loggery propusti vsechno od finest
 
.level= FINEST
 
</nowiki>
 
 
a do projektu ''Properties - Run - VM Options'' dejte '''-Djava.util.logging.config.file=logging.properties'''
 
  
 
Spusťte server.
 
Spusťte server.

Verze z 27. 11. 2012, 12:30


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.


(Pro ty, kdo neumí zkompilovat a spustit javovou třídu, tak z příkazového řádku se to udělá takto:

 
  mkdir rmicviceni
  cd rmicviceni
  wget http://acrab.ics.muni.cz/~makub/rmi/tabule.jar
  mkdir -p cz/muni/fi/pa165/rmi
  vi cz/muni/fi/pa165/rmi/Pisalek.java
  javac -cp tabule.jar:. cz/muni/fi/pa165/rmi/Pisalek.java
  java -cp tabule.jar:. cz.muni.fi.pa165.rmi.Pisalek nymfe31 'neco chytreho'
  

nebo v NetBeans si vytvoříte nový projekt pomocí File - New Project - Categories: Java - Projects: Java Application, v dialogu 'Create Main Class zadat cz.muni.fi.pa165.rmi.Pisalek, pak v Libraries zvolit Add JAR/Folder, přidat soubor tabule.jar, přepsat třídu Pisalek, na projektu pak zvolit Properties - Run - Arguments a do políčka napsat nymfe31 'neco chytreho' . Pak spustit projekt. Z příkazové řádky je to jednodušší, že. )

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 zkompilována

javac -cp tabule.jar:. cz/muni/fi/pa165/rmi/TabuleImpl.java

a 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.

JSON-RPC

Ukážeme si vzdálené volání procedur (RPC) pomocí protokolu JSON-RPC 2.0. K implementaci použijeme knihovnu jsonrpc4j.


Rozhraní služby

Stáhněte si Mavenový projekt tabule-json-rpc.zip, rozzipujte, a nainstalujte, bud pomocí mvn install nebo otevřením v NetBeans a zvolením Build.

Projekt obsahuje definici rozhraní a vyjímky:

Tabule.java

 
package cz.muni.fi.pa165.jsonrpc;
 
public interface Tabule {
    void zverejni(String text) throws Vyjimka;
}

Vyjimka.java

 
package cz.muni.fi.pa165.jsonrpc;
 
public class Vyjimka extends Exception {
 
    public Vyjimka(String message) {
        super(message);
    }
 
}

JSON-RPC server

Vytvořte si nový projekt typu Maven s názvem tabule-json-rpc-server a do pom.xml připište závislost na projektu tabule-json-rpc a knihovnách pro JSON-RPC:

 
    <name>tabule-json-rpc-server</name>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    
    <repositories>
        <repository>
            <id>jsonrpc4j-webdav-maven-repo</id>
            <name>jsonrpc4j maven repository</name>
            <url>http://jsonrpc4j.googlecode.com/svn/maven/repo/</url>
            <layout>default</layout>
        </repository>
    </repositories>
    <dependencies>
        <dependency>
            <groupId>cz.muni.fi.pa165</groupId>
            <artifactId>tabule-json-rpc</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>com.googlecode</groupId>
            <artifactId>jsonrpc4j</artifactId>
            <version>0.25</version>
        </dependency>
        <dependency>
            <groupId>javax.portlet</groupId>
            <artifactId>portlet-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-servlet-api</artifactId>
            <version>7.0.27</version>
        </dependency>
        <dependency>
            <groupId>org.simpleframework</groupId>
            <artifactId>simple</artifactId>
            <version>4.1.21</version>
        </dependency>
    </dependencies>

Vytvořte následující třídy v balíku cz.muni.fi.pa165.jsonrpc:

TabuleImpl.java

 
package cz.muni.fi.pa165.jsonrpc;
 
public class TabuleImpl implements Tabule {
 
    @Override
    public void zverejni(String text) throws Vyjimka {
        if (text == null || text.isEmpty()) throw new Vyjimka("text je prázdný");
        System.out.println(SimpleServer.getClient()+": " + text);
    }
}

SimpleServer.java

 
package cz.muni.fi.pa165.jsonrpc;
 
import com.googlecode.jsonrpc4j.JsonRpcServer;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.logging.*;
import org.simpleframework.http.Request;
import org.simpleframework.http.Response;
import org.simpleframework.http.core.Container;
import org.simpleframework.transport.connect.Connection;
import org.simpleframework.transport.connect.SocketConnection;
 
public class SimpleServer implements Container {
 
    private JsonRpcServer jsonRpcServer;
    
    public SimpleServer(JsonRpcServer jsonRpcServer) {
        this.jsonRpcServer = jsonRpcServer;
    }
 
    private static ThreadLocal<String> client = new ThreadLocal<String>();
    
    static String getClient() {
        return client.get();
    }
 
    @Override
    public void handle(Request request, Response response) {
        try {
            if ("POST".equals(request.getMethod())) {
                response.set("Content-Type", "application/json");
                client.set(request.getClientAddress().getHostName());
                jsonRpcServer.handle(request.getInputStream(), response.getOutputStream());
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
 
    public static void main(String[] args) throws IOException {
        //enable logging
        Logger log = LogManager.getLogManager().getLogger("");
        log.setLevel(Level.ALL);
        for (Handler h : log.getHandlers()) h.setLevel(Level.FINEST);
        //start server
        Logger.getLogger(SimpleServer.class.getName()).info("starting server");
        JsonRpcServer tabule = new JsonRpcServer(new TabuleImpl(), Tabule.class);
        Connection connection = new SocketConnection(new SimpleServer(tabule));
        connection.connect(new InetSocketAddress(1420));
    }
 
}

Spusťte server.

JSON-RPC klient

Vytvořte nový projekt typu Maven jménem tabule-json-rpc-klient a do pom.xml připište:

 
     <repositories>
        <repository>
            <id>jsonrpc4j-webdav-maven-repo</id>
            <name>jsonrpc4j maven repository</name>
            <url>http://jsonrpc4j.googlecode.com/svn/maven/repo/</url>
            <layout>default</layout>
        </repository>
    </repositories>
    <dependencies>
        <dependency>
            <groupId>cz.muni.fi.pa165</groupId>
            <artifactId>tabule-json-rpc</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>com.googlecode</groupId>
            <artifactId>jsonrpc4j</artifactId>
            <version>0.25</version>
        </dependency>
    </dependencies>

Vytvořte třídu

SimpleClient.java

 
package cz.muni.fi.pa165.jsonrpc;
 
import com.googlecode.jsonrpc4j.JsonRpcHttpClient;
import com.googlecode.jsonrpc4j.ProxyUtil;
 
import java.net.MalformedURLException;
import java.net.URL;
 
public class SimpleClient {
 
    public static void main(String[] args) throws MalformedURLException, Vyjimka {
 
        JsonRpcHttpClient client = new JsonRpcHttpClient(new URL("http://localhost:1420/"));
        Tabule tabule = ProxyUtil.createClientProxy(SimpleClient.class.getClassLoader(), Tabule.class, client);
 
        tabule.zverejni("ahoj");
        //tabule.zverejni(null);
    }
}

Spusťte klienta.

SOAP/WSDL Web Services

Ukážeme si web services pomocí Apache CXF.


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>

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());
        }
    }
}

Klikněte pravým tlačítkem a vyberte Maven - Update folders. Alternativně můžete z příkazového řádku spustit mvn generate-sources a mvn package.

Spusťte třídu Klient.

Pro kopii všech knihoven potřebných pro spuštění z příkazového řádku 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://nymfe31.fi.muni.cz:9000/tabule");