Nell‘articolo pubblicato il mese scorso abbiamo fatto una breve introduzione a BlazeDS e a Flex 3. In questa seconda parte vedremo degli esempi pratici di integrazione tra applicativi Flex e Java. In particolare vedremo i passi da seguire per integrare un front end in Flex con un‘applicazione Java-based su server JBoss.
Introduzione
Nel precedente articolo abbiamo visto le novità di Flex 3 e abbiamo introdotto il BlazeDS, un componente che facilita l’integrazione tra Flex e Java. Vedremo ora quali sono i passi per eseguire tale integrazione. Creeremo una semplice applicazione Flex di esempio che effettuerà una RPC per prelevare dal server le informazioni da inserire in una DataGrid. Per creare il frontend in Flex utilizzeremo il Flex Builder 3 (è possibile scaricare una versione trial sul sito di Adobe [1]), mentre per la parte server creeremo un progetto con Eclipse. È possibile creare il frontend anche utilizzando il compilatore a linea di comando mxml, oppure usando i task Ant direttamente da Eclipse, prelevabile (opensource) dal sito di Adobe. Faremo due esempi: nel primo utilizzeremo una chiamata ad un metodo di una classe POJO, mentre nel secondo, faremo interagire il client con un server basato su EJB. Ricordiamo solamente che, sebbene Java e AS3 siano molto simili, il mapping tra gli oggetti AS3 e Java non è ottimale. È possibile aggiungere comunque il supporto per nuovi tipi di dati. Gli esempi sono scaricabili a partire dal menu dell’articolo in alto a sinistra.
Esempio 1: RPC verso POJO
Supponiamo di avere già un’applicazione server in Java e di voler creare un frontend in Flex. Partiamo innanzitutto con il download dell’ultima versione di BlazeDS dall’indirizzo
http://opensource.adobe.com/wiki/display/blazeds/BlazeDS
Qui è possibile scegliere se scaricare solo i binari, la versione con i sorgenti, oppure la versione Turnkey, contenente anche un web server Tomcat, all’interno del quale il deploy di BlazeDS è già stato fatto corretamente, e dove sono anche presenti diverse applicazioni di esempio.
Per i nostri scopi effettuiamo il download dei binari, disponibili come unico file ZIP. All’interno di questo pacchetto troviamo il file “blazeds.war”. Scompattiamo il file blazeds.war e copiamo i file presenti in “WEB-INF/lib e WEB-INF/flex” nelle rispettive cartelle del nostro progetto Java.
A questo punto configuriamo la servlet “message broker”, che si occupa di gestire tutte le comunicazioni e le invocazioni dei servizi. Nel file “web.xml” della nostra applicazione aggiungiamo:
flex.messaging.HttpFlexSession MessageBrokerServlet MessageBrokerServlet flex.messaging.MessageBrokerServlet services.configuration.file /WEB-INF/flex/services-config.xml 1 MessageBrokerServlet /messagebroker/*
Come possiamo vedere, viene specificato il file di configurazione, che per default viene chiamato “service-config.xml”, che contiene la configurazione di tutti gli aspetti comuni a tutti i sevizi (logging, sicurezza, definizione dei canali, etc…).
Stiamo supponendo di avere già un’applicazione server, vediamo quindi in cosa consiste. I dati che verranno inviati al client sono dei prodotti rappresentati da una semplice classe Java con una serie di proprietà e dei metodi accessor getter e setter:
package flex.samples.product; import java.io.Serializable; public class Product implements Serializable { private int productId; private String name; private String description; private String image; private String category; private double price; private int qtyInStock; public String getCategory() { return category; } public void setCategory(String category) { this.category = category; } ...
A prelevare questi dati dal DB ci pensa un’altra semplice classe Java (POJO) con il metodo getProducts(). Questo metodo sarà invocato da Flex:
package flex.samples.product; import java.util.ArrayList; ... public class ProductService { public List getProducts() throws DAOException { List list = new ArrayList(); Connection c = null; try { c = ConnectionHelper.getConnection(); Statement s = c.createStatement(); ResultSet rs = s.executeQuery("SELECT * FROM product ORDER BY name"); while (rs.next()) { list.add(new Product(rs.getInt("product_id"), rs.getString("name"), rs.getString("description"), rs.getString("image"), rs.getString("category"), rs.getDouble("price"), rs.getInt("qty_in_stock"))); } } catch (SQLException e) { e.printStackTrace(); throw new DAOException(e); } finally { ConnectionHelper.close(c); } return list; } ...
Configuriamo adesso il file “remoting-config.xml” creando la destinazione product:
class="flex.messaging.services.RemotingService"> class="flex.messaging.services.remoting.adapters.JavaAdapter" default="true"/> flex.samples.product.ProductService
L’adattatore e il canale di default che useremo sono quelli preconfigurati nella distribuione BlazeDS. L’unica parte di codice aggiunta è quella che definisce una nuova destinazione. Tale configurazione mappa un nome logico ad una classe, e questo permetterà di invocare i metodi di tale classe referenziando il nome logico con un oggetto RemoteObject. È possibile impostare ulteriori parametri per gli adattatori o configurare un diverso canale di default. Ad esempio è possibile impostare per la destinazione la proprietà scope che può assumere 3 valori: Application, Session e Request. Gli oggetti remoti con scope Application sono disponibili durante il tempo in cui è disponibile l’intera applicazione. Gli oggetti con scope Session sono relativi ad una conversazione tra server e client, mentre gli oggetti con scope request vengono ricreati dopo ogni richiesta fatta dal client.
Front End
La situazione che abbiamo pensato è quella di creare una nuova interfaccia ad un’applicazione server già esistente. Iniziamo col creare un nuovo Flex Project, inseriamo il nome del progetto, e assicuriamoci di settare il campo “Application Server Type” a None.
Figura 1 – Finestra iniziale per la creazione di un nuovo progetto Flex.
Quando si usa il server JBoss, siamo costretti a impostaree questo campo a “None” perche’ altrimenti nel passaggio successivo verrà chiesto di inserire la directory dove verrà messa l’applicazione dopo il deploy sul server. Utilizzando Tomcat, non si hanno problemi perche’ dopo il deploy tutti i WAR vengono scompattati sempre nello stesso punto (dentro la cartella “webapps”), ma nel caso di JBoss, questo non è vero (i WAR vengono scompattati ad ogni deploy in cartelle temporanee diverse). Settando questo campo al valore J2EE avremmo avuto, nel passaggio successivo, la possibilità di specificare i seguenti 2 argomenti:
- Services: il path del file di configurazione del Data Service (BlazeDS)
- Context-root: il context-root dell’applicazione
Nel nostro caso, i due valori li setteremo durante la compilazione del progetto Flex specificandoli come argomenti del compilatore. Apriamo dal menu la finestra delle proprietà
Project ->Properties ->Flex Compiler
E aggiungiamo nel campo “Additional compiler arguments”:
-services "path del services-config.xml dell'applicativo server" -context-root "/context"
Nel mio caso ho inserito
-services "C:/Programmi/Java/eclipse-galileo-j2ee/workspace /JFProject/Web/public/WEB-INF/flex /services-config.xml" -context-root "/JFProject"
Figura 2 – Argomenti passati al compilatore Flex.
Completiamo il wizard senza modificare i valori di default proposti. Apriamo il file “mxml” principale, che riporta lo stesso nome del progetto e inseriamo il seguente codice
Compiliamo l’applicazione e copiamo tutti i file generati (.swf, .html, .js) nell’applicazione server (devono essere risorse accessibili, quindi li mettiamo nel punto in cui risiede il file “index.html”).
Possiamo ora provare l’applicazione sul server JBoss effettuando prima il deploy e successivamente richiamandola con il browser, di solito all’indirizzo:
http://localhost:8080/JFProject/JFProject.html
Esempio 2: RPC verso EJB
Nel secondo esempio faremo qualcosa di più interessante. Considereremo il caso in cui la business logic sia implementata attraverso degli EJB, in particolare dei session bean, e quindi faremo in modo che il front end in Flex dialoghi con uno di questi session bean. La logica dell’applicativo server rimane la stessa: faremo solamente diventare un session bean il POJO che si occupava di recuperare dal DB i dati e li restituiva in una lista.
BlazeDS permette di istanziare semplici classi Java (POJO) senza nessun problema tuttavia non possiamo dire la stessa cosa quando abbiamo a che fare con EJB. Questo è anche naturale dal momento che questi bean non sono istanziabili direttamente, ma sono oggetti gestiti dal container in cui risiedono. Per poter richiamare i metodi di un EJB è necessario utilizzare un meccanismo a factory che si occupa di effettuare il lookup degli oggetti e li rende successivamente disponibili. Per i nostri scopi non è necessario implementare una custom factory, ma possiamo utilizzare direttamente una libreria free [2], che permette di interagire sia con EJB remoti che locali. Effettuiamo allora il download di questa libreria, FlexEJBFactory.jar, e copiamola nella cartella $JBOSS_HOME/server/default/lib.
Nell’esempio precedente, avevamo copiato tutti i JAR presenti nel file blazeds.war dentro la cartella WEB-INF/lib dell’applicativo server. Questa volta, occorre mettere anche queste librerie nella cartella $JBOSS_HOME/server/default/lib.
Copiamo i file di configurazione, presenti in WEB-INF/flex del blazeds.war, nella rispettiva cartella del nostro progetto Java (come nell’esempio precedente).
Il nuovo server farà le stesse cose di prima ma attraverso un EJB. Modifichiamo allora il POJO dell’esempio precedente e facciamolo diventare un EJB, creando l’opportuna interfaccia (local o remote);
package flex.samples.model; import java.util.ArrayList; ... @Stateless(name="Product") @LocalBinding(jndiBinding=ProductLocal.JNDI_NAME) public class ProductBean implements ProductLocal{ public List getProducts() throws DAOException { List list = new ArrayList(); Connection c = null; try { c = ConnectionHelper.getConnection(); Statement s = c.createStatement(); ResultSet rs = s.executeQuery("SELECT * FROM product ORDER BY name"); while (rs.next()) { list.add(new Product(rs.getInt("product_id"), rs.getString("name"), rs.getString("description"), rs.getString("image"), rs.getString("category"), rs.getDouble("price"), rs.getInt("qty_in_stock"))); } } catch (SQLException e) { e.printStackTrace(); throw new DAOException(e); } finally { ConnectionHelper.close(c); } return list; } ... package flex.samples.common.interfaces; import java.util.List; ... @Local public interface ProductLocal { public static final String JNDI_NAME="Product/local"; public List getProducts(); }
Questa volta, il risultato della compilazione non sarà un file WAR ma bensì un EAR (occorrerà creare un nuovo build Ant).
Partendo dai file di configurazione Flex presenti con la distribuzione BlazeDS, occorre effettuare le seguenti modifiche:
1. Aggiungiamo il factory nel file service-config.xml:
2. Aggiungiamo la nuova destinazione nel file remoting-config.xml:
ejb3 Product/local application
Notiamo le differenze con l’esempio precedente. La destinazione contiene il nodo factory per indicare l’uso dell’ EJB3Factory dichiarato nel “services-config.xml”, e il nodo source questa volta contiene il riferimento JNDI del bean.
Per la parte client possiamo riusare il progetto Flex del primo esempio avendo cura di modificare i parametri del compilatore Flex per puntare alla nuova applicazione server (prima di ricompilare). Poi copiamo i file SWG, HTML, JS nell’applicativo server (come nel caso precedente), e creiamo il file .ear.
Siamo pronti a effettuare il deploy e a provare la nostra applicazione.
Conclusioni
In questo articolo abbiamo visto degli esempi pratici di integrazione che ci aprono le porte verso la creazione di nuove interfacce RIA. Nel panorama attualmente molto vivo degli strumenti che consentono di creare Rich Internet Application per Java, BlazeDS ci permette di considerare Flex come una alternativa di sicuro valore.
Riferimenti
[1] Flex Builder 3
http://www.adobe.com/cfusion/entitlement/index.cfm?e=flexbuilder3
[2] Peter Martin’s EJB factory with EJB3 Support for both local and remote EJBs
http://www.adobe.com/cfusion/exchange/index.cfm?event=extensionDetail&extid=1089970#
[3] S. Tiwari, J. Herrington, E. Elrom, J. Mostafa, “AdvancED Flex 3”, FriendsOfED, 2008
http://www.friendsofed.com/book.html?isbn=1430210273