Continuiamo la trattazione di ICEFaces costruendo due pagine web in cui vengono utilizzate due importanti componenti standard: il drag‘n‘drop e l‘output chart. Inoltre il drag‘n‘drop verrà arricchito con l‘utilizzo di effetti grafici dinamici lanciati ogni volta che viene effettuato un drop su un pannello.
Al termine della trattazione dell‘esempio diamo una breve occhiata ai componenti Enterprise di ICEFaces che permettono di arricchire notevolmente i propri siti web.
In questo ultimo articolo della serie dedicata ad ICEFaces continueremo a sviluppare il sito web della scorsa puntata aggiungendo due pagine interattive:
- nella prima pagina implementeremo un semplice shopping cart mediante drag’n’drop ed effetti dinamici;
- nella seconda pagina mostreremo come è possibile disegnare dei grafici senza installare dei plugin nel web browser.
Il progetto
Ecco l’alberatura del progetto “Hello ICEFaces” descritto in questo articolo:
Figura 1 – Alberatura di “Hello ICEFaces”.
Le due nuove pagine da aggiungere al sito saranno accessibili dalla pagina di benvenuto hello.xhtml che adesso si arricchirà di due nuovi bottoni: due commandButton che ci reindirizzano alle due nuove pagine:
partialSubmit="true" action="dragDrop" /> partialSubmit="true" action="axisChart" />
Ecco come compare la nuova pagina hello.xhtml:
Definiamo i flussi di navigazione della pagina nel file faces-config.xml come mostrato in figura:
Figura 3 – I flussi di navigazione nel file faces-config-xml
Il corrispondente codice xml è il seguente:
/WEB-INF/includes/hello.xhtml dragDrop /WEB-INF/includes/dragDrop.xhtml /WEB-INF/includes/hello.xhtml axisChart /WEB-INF/includes/axisOutputChart.xhtml
Adesso siamo pronti a scrivere le due nuove pagine: iniziamo con lo shopping cart.
Shopping cart tramite drag’n’drop
La pagina dello shopping cart simula il comportamento di un carrello virtuale in cui l’utente immette dei prodotti per comprarli. Nella nostra implementazione, l’utente:
- visualizza tutti i prodotti disponibili;
- aggiunge e/o rimuove dei prodotti.
Ecco come apparirà la pagina quando sarà completata:
Figura 4 – Aspetto della pagina Shopping Cart.
La pagina è composta da tre parti:
- Panel Series: è un array di pannelli, ognuno dei quali contiene una immagine (con il nome) del prodotto da ordinare;
- Graphic Image: è una icona (lo shopping cart) su cui è possibile trascinare i prodotti per aggiungerli nel carrello;
- Data Table: è la tabella che contiene tutti i prodotti inseriti nello shopping cart con l’azione di cancellazione per ogni elemento.
Analizziamo singolarmente tutti e tre i nuovi tag da utilizzare.
Panel Series
Il tag ice:panelSeries fornisce un meccanismo per generare dinamicamente una serie di componenti figli in un pannello. Questo componente disegna i suoi figli in modo iterativo (simile al modo in cui si comporta il componente data table) partendo da una lista di dati.
Ecco un estratto del codice usato per visualizzare i prodotti:
value="#{dragDropController.storeInventory.inventory}" var="inventoryItem"> dragListener="#{dragDropController.addShoppingCartItem}" dragValue="#{inventoryItem}" dragOptions="dragGhost" dragMask="dragging,drag_cancel,hover_start,hover_end" dropMask="dragging,drag_cancel,hover_start,hover_end"> url="/images/#{inventoryItem.pictureName}.png" alt="#{inventoryItem.name}" />
Il tag panelSeries utilizza la lista (java.util.List) dragDropController.storeInventory.inventory gestita dal backing bean dragDropController.
All’interno del panelSeries definiamo:
- un panelGroup che contiene una immagine;
- un panelGroup “draggabile” e agganciato alla call back che gestisce il drag;
- un pannello che contiene il nome del prodotto.
Per abilitare il drag a qualsiasi pannello basta definire a “true” l’attributo “draggable” e agganciare l’evento del drag a un listener che ne elaborerà l’evento (nel nostro caso l’evento del drag verrà gestito dal metodo addShoppingCartItem(DragEvent event) definito all’interno del backing bean dragDropController).
Il dragValue definisce l’oggetto che deve essere incapsulato dentro il DragEvent passato al metodo addShoppingCartItem(): in questa maniera nel listener possiamo riprendere il prodotto che è stato messo dall’utente nello shopping trolley.
Graphic Image
Vediamo ora come è stato definito il panelGroup responsabile per la parte drop. Ecco la definizione del pannello che contiene l’icona dello shopping cart su cui occorre draggare gli elementi per aggiungerli al proprio carrello.
style="padding:2px;" dropTarget="true" hoverclass="cartDropTarget"> style="text-align: center;background-color:white;padding:20px;"> alt="#{msgs['page.dragDrop.cartZone.image.label']}" width="55" height="45" />
Lo shopping cart è una icona inclusa in un panelGroup abilitato a ricevere un elemento draggable (dropTarget=”true”). In questa maniera ICEFaces chiamerà il listener addShoppingCartItem() ogni volta che l’utente trascinerà un prodotto sull’icona dello shopping cart.
Si noti come sul panelGroup sia stata utilizzata la classe di stile cartDropTarget per l’evento hoverclass, in questa maniera la cornice dello shopping cart si colorerà di arancione (nel progetto gli stili sono definiti nella directory css) quando l’utente trascinerà con il mouse il prodotto sullo shopping cart
Figura 5 – Trascinamento del prodotto sullo shopping cart.
Data Table
La tabella che abbiamo inserito nella pagina visualizza il contenuto del carrello mediante la variabile dragDropController.shoppingCart.inventory.
Ogni riga della tabella contiene 4 colonne con i seguenti dati:
- l’icona del prodotto scelto;
- il nome del prodotto scelto;
- la quantità di prodotto messo nel carrello;
- un bottone per rimuovere il prodotto o diminuirne la quantità.
Anche il tag della tabella definisce a true il valore del dropTarget: in questa maniera l’utente potrà trascinare il prodotto o sopra l’icona del carrello oppure direttamente sulla tabella: il listener chiamato sarà lo stesso (è definito sull’elemento sorgente del drag):
styleClass="chartContainer backBeanChangeContainer" style="border: none;padding:2px;" hoverclass="cartDropTarget" dropTarget="true" > value="#{dragDropController.shoppingCart.inventory}" var="cartItem" width="100%" style="padding: 0px; margin: 0px;" border="0" cellpadding="2"> ...
Figura 6 – La visualizzazione della tabella di DataTable. Notare anche l’highlight arancione (vedi sotto).
Effetti
Aggiungiamo un effetto grafico alla tabella ogni volta che l’utente rimuove un elemento dallo shopping cart. L’effetto sarà quello di un highlight arancione sul campo delle quantità quando l’utente preme il tasto di rimozione.
Per abilitare un effetto grafico è sufficiente aggiungere un attributo “effect” al panello delle quantità:
La variabile cartItem.changeQuantityEffect è di tipo Highlight, che è una classe figlia di Effect.
Con ICEFaces abbiamo una vasta possibilità di scelta di eventi: basta instanziare un oggetto figlio di Effect (classe astratta) e utilizzare il metodo setFired(boolean) per inviare l’effetto al browser al prossimo refresh.
Figura 7 – La gerarchia della classe Effect.
La variabile changeQuantityEffect è definita come
private Effect changeQuantityEffect;
e istanziata nel costruttore di InventoryItem come highlight arancione:
changeQuantityEffect = new Highlight("#fda505");
Nel metodo di callback decrementQuantity() chiamiamo il metodo setFired(false) in modo tale da inviare l’effetto al browser subito dopo aver rimosso un elemento dal carrello:
public void decrementQuantity() { quantity--; changeQuantityEffect.setFired(false); }
Grafici
ICEFaces definisce il tag outputChart per disegnare grafici. La libreria usata per creare grafici è JChart [7].
Ecco un esempio di definizione di grafico a barre:
type="bar" chartTitle="Bar Chart" yaxisTitle="Problems" xaxisTitle="Years" xaxisLabels="#{axisChartBean.labels}" labels="#{axisChartBean.legendLabels}" colors="#{axisChartBean.paints}" data="#{axisChartBean.data}" />
Il significato degli attributi è immediato: si definisce un grafico a barre (type = “bar”), si definiscono gli assi X ed Y (yaxisTitle, yaxisLabels, xaxisTitle e xaxisLabels), i colori da usare e infine si fornisce la matrice dei dati da utilizzare.
In generale i tipi piu’ importanti di grafici che si possono usare sono:
- grafici a torta (pie outputchart);
- grafici con assi (axis outputChart);
- grafici risultanti dalla combinazione di due o piu’ grafici differenti.
In questo esempio che stiamo scrivendo utilizzeremo solamente dei grafici ad assi.
Axis OutputChart
Ci sono 7 tipi di grafici con assi:
- area;
- areastacked;
- bar;
- barclustered;
- barstacked;
- linee;
- punti.
Ciò che vogliamo implementare è una pagina web in cui vengono visualizzati tutti e 7 i tipi di grafici basandoci su una sola sorgente di dati.
Uno dei 7 tipi di grafico da visualizzare viene scelto dall’utente mediante una combo box che, dinamicamente, cambia il grafico da disegnare.
Definiamo prima di tutto la classe ChartDataSource (il data source del grafico) che fornisce:
- le labels per gli assi X e Y;
- le labels per la leggenda;
- i dati da visualizzare (una matrice di numeri);
- una lista di colori da usare, uno per ogni valore sulle X.
Il grafico da visualizzare è un report calcolato su un bug tracker. In particolare vogliamo visualizzare: il numero di bugs aperti, bugs fissati e miglioramenti per ogni anno di attività.
La classe ChartdataSource fornirà quindi:
- come label dell’asse X: gli anni che vanno dal 2000 al 2006;
- come label dell’asse Y: il numero di bugs aperti/chiusi e miglioramenti registrati;
- come legenda forniremo: “bugs”, “fixed” ed “enanchements”;
- i colori da usare saranno: rosso per i bugs aperti, verde per quelli chiusi e blu per i miglioramenti.
Figura 8 – Grafici: visualizzazione “barstacked”.
Figura 9 – Grafici: visualizzazione “line”.
La pagina conterrà inoltre i seguenti controlli:
- una combo box (ice:selectOneMenu) per scegliere il tipo di grafico ad assi;
- due radio buttons (ice:selectOneRadio) per scegliere il tipo di orientamento (orizzontale o verticale);
- il grafico (ice:outputChart) da visualizzare.
Tutti i valori vengono letti dal backing bean AxisChartBean.
Il grafico da visualizzare viene definito in maniera completamente parametrizzata come segue:
type="#{axisChartBean.type}" chartTitle="#{axisChartBean.type} Chart" yaxisTitle="#{axisChartBean.titleY}" xaxisTitle="#{axisChartBean.titleX}" xaxisLabels="#{axisChartBean.labels}" labels="#{axisChartBean.legendLabels}" colors="#{axisChartBean.paints}" data="#{axisChartBean.data}" actionListener="#{axisChartBean.imageClicked}" renderOnSubmit="#{axisChartBean.newChart}" horizontal="#{axisChartBean.horizontal}" />
In questo modo ogni valore del ice:outputChart può essere modificato dinamicamente mendiante un update parziale della pagina. Per esempio, la combo box usata per cambiare il tipo di grafico è definita come segue:
valueChangeListener="#{axisChartBean.chartChanged}">
Quando l’utente sceglie uno dei sette tipi di grafico nel menu a tendina (axisChartBean.chartList contiene delle stringhe che definiscono i 7 tipi diversi di axis outputchart) viene inviata una richiesta di update parziale della pagina che cambia il tipo di grafico da visualizzare (axisChartBean.type).
Al refresh successivo della pagina il tag ice:outputChart rigenererà un altro grafico in base al nuovo tipo scelto dall’utente.
La seguente immagine mostra la combo box con la lista dei 7 tipi diversi di grafici che si possono scegliere.
Figura 10 – La finestra di selezione dei diversi tipi di grafico.
A questo punto il piccolo sito “Hello World ICEFaces!” è completo, il codice sorgente con il .war corrispondente è incluso nell’allegato di questo articolo (menu a sinistra in alto).
Tutti i componenti del sito sono stati fatti partendo da “pezzi semplici”: per esempio la barra che si trova in basso sul sito di esempio è stata fatta concatenando diversi pannelli (panel group) e text fields.
Tutto sarebbe stato ancora più semplice se avessimo avuto a disposizione un componente complesso già pronto all’uso. Ebbene, ICEFaces fornisce una libreria aggiuntiva per rispondere a questa necessità: è l’Enterprise Pack, che comprende moltissimi componenti, come appunto una status bar (ice-cc:statusBar).
Componenti Enterprise di ICEFaces
ICEFaces viene pubblicato in due edizioni differenti:
- Standard Edition: viene rilasciato con licenza LGPL, è quindi utilizzabile liberamente, e contiene i componenti di base della libreria;
- Enterprise Edition [4]: viene rilasciato a pagamento, contiene più di 30 componenti “complessi” che permettono di arricchire la propria applicazione web in modo semplice e veloce.
La lista di componenti complessi che offre ICEFaces EE è abbastanza ricca [5]:
Componenti di selezione
- Dual List
- Editable List
- Number Spinner
- Date Spinner
- Text Spinner
- Select Partial Checkbox
- Locale Selector
- State/Province Selector
- Select Date Interval
- Slider
Componenti per le tabelle
- Auto-Sort Table
- Easy Data Pager
- Easy Data Pager Info
- Easy Column
- Easy Expandable Table
- Filter Table
- Editable Table
- Rich Data Grid
Componenti di layout
- Round Corners
- Rich Tabs
- Tab View
- Easy Popup
- Dynamic Dialog
Componenti per gli alberi
- Selection Tree
- Tree Table
- Drag and Drop Table
Componenti di processo
- Polling Component
- File Upload Progress
- Asynch Progress
Componenti misti
- Status Bar
- Slide Show
- Schedule Component
Sul sito di ICEFaces c’è uno showcase completo sulla versione Enterprise che permette di avere una idea sul funzionamento di questi componenti avanzati [6].
Per sempio, un componente molto utile da utilizare è la tabella paginata con colonne ordinabili.
Il tag è: ice-cc:autoSortTable.
Figura 11 – Componenti Enterprise: la tabella con colonne ordinabili.
Il tag corrispondente è il seguente:
bean="#{autoSortTableExampleBean.tableBean}" style="width:97%;" showDataPager="#{autoSortTableExampleBean.showDataPager}" showRowControls="#{autoSortTableExampleBean.showRowControls}" columnWidths="60px,100px,100px"> name="firstName" sortable="true"/> name="lastName" sortable="true"/>
Le funzionalità dell’autoSortTable sono:
- può essere usata con ogni lista;
- non bisogna scrivere alcun codice di ordinamento delle righe;
- l’ordinamento viene fatto automaticamente;
- il data page viene incluso automaticamente.
Ecco come usarla:
- creare una istanza di tipo AutoSortTableBean tra i managed bean;
- aggiungere il tag autoSortTable nella pagina;
- aggiungere un tag ice-cc:column per ogni colonna da visualizzare;
- legare il valore di ogni attributo delle colonne ad una proprietà del bean nella lista (tableBean), come la semplice table table, si usa la variabile “row” per la variabile di riga;
- definire per ogni colonna l’attributo da visualizzare, e se la colonna è ordinabile o no.
Altre librerie JSF
Accanto ad ICEFaces, ci sono altre librerie JSF altrettanto valide e ricche di componenti. Vale la pena spendere del tempo per dare loro una occhiata. Una di queste è sicuramente RichFaces (di JBoss) [8]. È completamente free (LGPL), è molto facile da usare e offre una ricca galleria di componenti grafici complessi [9]. Sono particolarmente interessanti i componenti utilizzati per implementare le tabelle (data iteration) e i rich output.
Un’altra libreria interessante è PrimeFaces [10]: ha una ampia galleria di componenti, offre una libreria MVC basata sulle annotazioni che sostituisce completamente il file faces-config.xml; offre una ulteriore libreria per il mobile (Mobile Touch Faces).
In ultimo, richiamiamo Apache MyFaces, che è un contenitore di sotto-progetti che implementano lo standard JSF e alcuni componenti aggiuntivi [11].
Conclusioni
In questo articolo abbiamo completato la scrittura del sito di esempio; abbiamo fatto vedere come ICEFaces permette di utilizzare l’Ajax server push in maniera trasparente, sincronizzare la vista di dati ad ogni aggiornamento automatico da parte del server, utilizzare il drag’n’drop, definire degli effetti grafici, disegnare dei grafici senza ausilio di plugin.
Tutte queste funzionalità sono state implementate per dimostrare come sia possibile sviluppare applicazioni web attraverso un modello di interazione con l’utente più ricco rispetto a ciò che forniscono le applicazioni web standard.
In definitiva ICEFaces è una delle librerie più diffuse e robuste nel mondo JSF; è composta da due parti: la parte SE e la parte EE. La parte Standard fornisce componenti semplici e può essere utilizzata liberamente, mentre la parte EE fornisce componenti complessi che possono tornare utili nella stesura di un sito. Occorre considerare che la parte EE è a pagamento, ma indubbiamente fornisce un valore aggiunto per per velocizzare la scrittura e il test di siti web dinamici.
Riferimenti
[1] Home page di ICEFaces
http://www.icefaces.org/main/home/
[2] Component Show Case di ICEFaces SE
http://component-showcase.icefaces.org/component-showcase/showcase.iface
[3] Online tutorial di ICEFaces SE
http://www.icefaces.org/main/resources/tutorials.iface
[4] Home Page di ICEFaces EE
http://www.icefaces.org/main/ajax-java/icefaces-ee.iface
[5] ICEFaces EE component library
http://www.icefaces.org/main/ajax-java/composite-components.iface
[6] ICEFaces EE component show case
http://composite-component-showcase.icefaces.org/icefaces-composite-comps-showcase/showcase.iface
[7] Libreria Jchart
http://jcharts.sourceforge.net/
[8] RichFaces Home Page
http://www.jboss.org/richfaces
[9] RichFaces Show Case
http://livedemo.exadel.com/richfaces-demo/index.jsp
[10] PrimeFaces
[11] Apache MyFaces