VÝVOJ PODNIKOVÝCH APLIKACÍ NA PLATFORMĚ JAVA - CVIČENÍ Zbyněk Šlajchrt http://java.vse.cz/4it447/HomePage Část 10.
Program Aplikace Fotoalbum Samostatný klient aplikace Využití REST služby pro ruční čištění keše
Kontejner aplikačních klientů (ACC) http://java.sun.com/javaee/6/docs/tutorial/doc/bnabo.html
Struktura EAR Kořen EAR Webový modul EJB modul Klientský modul META-INF/application.xml META-INF/sun-application.xml Webový modul EJB modul Klientský modul WEB-INF/web.xml WEB-INF/sun-web.xml META-INF/ejb-jar.xml META-INF/sun-ejb-jar.xml META-INF/application-client.xml WEB-INF/sun-application-client.xml
Kontejner aplikačních klientů (ACC) Spravuje moduly aplikace určené k běhu na klientském počítači ACC komunikuje přes RMI-IIOP Stará se o Bezpečnost Vytváření kontextu a injektáž prostředků Spouštění klientské aplikace pomocí Java Web Start
Závislosti mezi moduly ear (album-app) web ejb client ejb-client (stub) Klient nezávisí přímo na modulu ejb. Místo toho závisí na speciálním artefaktu ejb-client vygenerovaném z ejb modulu pro potřeby vzdálených klientů. Artefakt ejb-client se vytváří při sestavování ejb modulu a ve fázi install se instaluje do lokálního Maven repository.
Vytvoření klientského modulu Vytvořte v kořenovém adresáři projektu adresář client Vytvořte v něm soubor pom.xml a vložte do něj obsah z poznámek Do pom.xml v kořenu projektu zaregistrujte klientský modul do sekce <modules> <module>client</module> Do pom.xml v modulu ejb přidejte do konfigurace pluginu maven-ejb-plugin položku <generateClient>true</generateClient> <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <parent> <artifactId>album</artifactId> <groupId>cz.vse.javaee</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>client</artifactId> <packaging>jar</packaging> <name>client</name> <version>${parent.version}</version> <dependencies> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>6.0</version> <scope>provided</scope> </dependency> <artifactId>ejb</artifactId> <type>ejb-client</type> <version>${version}</version> </dependencies> <build> <finalName>${artifactId}</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.2</version> <configuration> <archive> <manifest> <mainClass>cz.vse.javaee.album.Main</mainClass> <addClasspath>true</addClasspath> </manifest> </archive> </configuration> </plugin> </plugins> </build> </project>
Úprava závislostí v ear modulu V souboru pom.xml modulu ear přidejte závislost na klientský modul <dependency> <groupId>cz.vse.javaee</groupId> <artifactId>client</artifactId> <type>jar</type> <version>${version}</version> </dependency>
Konfigurace maven-ear-plugin V pom.xml modulu ear je zapotřebí konfigurovat maven-ear-plugin, který provádí sestavení aplikace (EAR) Do sekce modules přidejte položku pro klientský modul <jarModule> <groupId>cz.vse.javaee</groupId> <artifactId>client</artifactId> <bundleDir>/</bundleDir> <includeInApplicationXml>true</includeInApplicationXml> </jarModule> bundleDir – umístění klientského modulu (client.jar) v archivu EAR includeApplicationXml – plugin zapíše informace o klientském modulu do generovaného popisovače application.xml
Vytvoření struktury modulu client Vytvořte adresáře src/main/java src/main/resources/META-INF V META-INF vytvořte soubory application-client.xml – standardní popisovač sun-application-client.xml – proprietární popisovač Obsahy těchto souborů nakopírujte z poznámek Nastavte ve vašem IDE adresář src/main/java jako zdrojový application-client.xml <?xml version="1.0" encoding="UTF-8"?> <application-client version="5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application-client_5.xsd"> <display-name>Album Standalone Client</display-name> </application-client> sun-application-client.xml <!DOCTYPE sun-application-client PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 Application Client 5.0//EN" "http://www.sun.com/software/appserver/dtds/sun-application-client_5_0-0.dtd"> <sun-application-client> </sun-application-client>
Balíček a třída Main Vytvořte balíček cz.vse.javaee.album Vytvořte v něm třídu Main s metodou public static void main(String[] args) { JOptionPane.showMessageDialog(null, "Nazdar!"); }
Build & Deploy V administrátorské konzoli GF otevřete detail aplikace album Zaškrtněte Java Web Start: Enabled Po uložení změny se v řádce s modulem client.jar objeví link Launch Spusťte klientský modul kliknutím na link Launch
Vzdálená volání z klienta Budeme volat metody na AlbumDAO, Některé metody vrací entitu Photo Instance se budou (de)serializovat Entitu Photo učiňte serializovatelnou implements java.io.Serializable
Rozhraní pro vzdálená volání AlbumDAOBean bude implementovat rozhraní pro lokální (v rámci JVM) i vzdálená volání (mezi JVM) Vytvořte rozhraní AlbumDAORemote, které bude pouze rozšiřovat rozhraní AlbumDAO Zařaďte toto rozhraní do seznamu implementovaných rozhraní AlbumDAOBean AlbumDAOBean anotujte @Local(AlbumDAO.class) @Remote(AlbumDAORemote.class)
WORKAROUND Vytvořte vzdálené rozhraní PhotoCacheRemote pro singleton PhotoCache Zařaďte jej do seznamu implementací v singletonu PhotoCache V AlbumDAOBean a CacheSynchronizer změňte typ atributu cache z PhotoCache na PhotoCacheRemote @Remote public interface PhotoCacheRemote { Photo getIconByName(String photoName) throws NoPhotoFoundException; void cleanCache(); } @Remote public interface PhotoCacheRemote { Photo getIconByName(String photoName) throws NoPhotoFoundException; void cleanCache(); }
Úprava třídy Main Výpis seznamu všech fotografií do dialogového okna Stažení vybrané fotografie podle názvu a uložení do souboru -d <název fotky> <soubor> Výpis nápovědy v ostatních případech
Třída Main Nejjednodušší způsob, jak se dostat k referenci na AlbumDAORemote, je použít anotace a injektáž Šlo by použít i vyhledávání v JNDI a globální jméno Použijeme starou známou anotaci @EJB Na rozdíl od serverových komponent, v klientské aplikaci jsou anotované atributy statické! public class Main { @EJB private static AlbumDAORemote albumDAO; public static void main(String[] args) throws NoPhotoFoundException, IOException { try { if (args.length == 1 && "-l".equals(args[0])) { listPhotos(); } else if (args.length == 3 && "-d".equals(args[0])) { download(args); } else { JOptionPane.showMessageDialog(null, "Parameters: (-l | -d photoName file)."); } } catch (Throwable t) { t.printStackTrace(); JOptionPane.showMessageDialog(null, "Error: " + t); private static void download(String[] args) throws NoPhotoFoundException, IOException { String photoName = args[1]; Photo photo = albumDAO.findPhoto(photoName); byte[] bytes = photo.getImage(); File photoFile = new File(args[2]); FileOutputStream fos = new FileOutputStream(photoFile); fos.write(bytes); fos.close(); JOptionPane.showMessageDialog(null, "Downloaded photo " + photoName + " to " + photoFile); private static void listPhotos() { StringBuilder sb = new StringBuilder(); List<Photo> photos = albumDAO.getPhotos(); for (Photo photo : photos) { sb.append(photo.getName()).append('\n'); JOptionPane.showMessageDialog(null, "Fotky\n:" + sb.toString());
Předávání argumentů Před spuštěním aplikace ze serveru je třeba zadat argumenty Na stránce Application Client Launch Page zadejte argumenty ve formátu arg=first&arg=second Argument: -l arg=-l Argumenty: -d foto1 /temp/foto1.png arg=-d&arg=foto1&arg=/temp/foto1.png
REST Architektonický styl distribuovaných systémů REpresentational State Transfer Přenos reprezentace zdroje na klienta Dotazem na zdroj identifikovaný URL nahraje klient reprezentační stav zdroje. Tento stav může obsahovat URL odkazy na další zdroje Dotazem na jiné URL přechází klient do dalšího stavu, který odpovídá reprezentaci odkazovaného zdroje. Dodatečná (post-hoc) interpretace HTTP metod GET, POST, PUT, DELETE
Příklady REST http://myapp/shop/products Zdrojem je zde seznam výrobků Reprezentací může být HTML, XML nebo JSON http://myapp/shop/products/1029 Zdrojem je zde konkrétní výrobek
Omezení na REST architekturu Client-server Stateless – server neudržuje stav klienta Cacheable – klient může kešovat stav Layered – klient neví o přítomnosti mezivrstev Možnost přesunu části kódu serveru na klienta (JavaScript) Jednotné rozhraní pro komunikaci URI ke stavu jsou připojena metadata, např. MIME stav může obsahovat linky na asociované zdroje
Ovládání keše pomocí REST http://localhost:8089/web/rs/cache URL zdroje – keše Metoda GET na tomto zdroji vyčistí keš V modulu web vytvoříme třídu CacheResource @Path("cache") – URL fragment pro tento zdroj @Stateless – chování odpovídá bezstavovému EJB @Produces("text/plain") – MIME reprezentace zdroje Injektáž @EJB PhotoCache photoCache Metoda cleanCache deleguje na PhotoCache @GET – specifikuje, že GET bude směrována sem @Path("cache") @Stateless @Produces("text/plain") public class CacheResource { @EJB private PhotoCache photoCache; @GET public String cleanCache() { photoCache.cleanCache(); return "OK"; }
Úprava WEB-INF/web.xml <servlet> <servlet-name>JerseyWebApplication</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>cz.vse.javaee.album</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <url-pattern>/rs/*</url-pattern> </servlet-mapping>
Domácí úkol
Dodatek: Aplikační vrstva
Dodatek: Prezentační vrstva
Dodatek: Diagram stránek