MokaByte 93 - Febbraio 2005
Modellare il flusso applicativo sul web tier
Semplifichiamo drasticamente l'utilizzo di MVC Struts
di
Doriano Gallozzi
La robustezza e l'affidabilità di MVC Struts con il rigore e la qualità della modellazione UML. Scopriamo come e perchè è possibile.

Introduzione
Il pattern architetturale Model View Controller (al secolo MVC) è noto per essere semplice ed efficace, e quindi estremamente diffuso e utilizzato (quello che si definisce uno "standard de facto"). L'implementazione Struts di MVC poi, è tanto apprezzata quanto "proven", ossia robusta e matura, come testimoniano numerosi casi di successo. Uno dei principali vantaggi di MVC Struts è proprio il fatto che ciascuno dei suoi elementi svolge un ben preciso compito, per il quale è immediatamente identificabile e di conseguenza manutenibile. Tutta la configurazione è infine basata su file XML, quindi editabili e modificabili a piacere. Ma non è tutto oro quel che luccica, direbbe un noto proverbio, giacchè mettere le mani dentro i file di Struts può non essere così banale, essendo essi numerosi ed essendo l'intervento su insiemi di file XML di grandi dimensioni non proprio immediato. In questo articolo si indaga se sia possibile, mantenendo gli innegabili vantaggi di MVC Struts, approcciarne l'utilizzo in modo differente servendosi del maggiore livello di astrazione che la modellazione offre, e si descrive una possibile soluzione mediante un esempio concreto.

 

Il pattern architetturale MVC
Come è noto (rif.[1]), sia le Servlet sia le JSP risolvono il problema di creare contenuti dinamici sul web. Le JSP nascono in un'epoca successiva alle Servlet, per tentare di eliminarne l'intrinseca complessità e permettere a chi debba occuparsi del solo look & feel di una applicazione J2EE di non avere troppo a che fare con la programmazione Java, giacchè una JSP di Java dovrebbe contenerne piuttosto poco.......purtroppo questo in pratica può non succedere, ed eccoci di fronte a JSP difficili da comprendere perchè piene zeppe di codice Java racchiuso tra quei minacciosi simboli <% e %>.
A titolo di esempio, diamo un'occhiata al frammento di JSP riportato qui sotto. Per un programmatore Java (e non solo, forse....) è abbastanza intuitivo, per un grafico decisamente meno....pensiamo a un nutrito gruppo di JSP piene zeppe di Java e possiamo comprendere il senso di sconforto che può assalire il nostro grafico........


<%@ page import="java.sql.*" %>

<%@
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
{
catch(ClassNotFoundException e);
}%>
<h1> Errore durante il caricamento di un Driver <h1/>
<%}
String url = "jdbs:odbc:PERSONALE";
String user = "sysadmin";
String pass = "sysadmin";
Connection con = null;

try
{
con = DriverManager.getConnection(url,user,pass);
}
{
catch(SQLException e);
}%>
<h1> Errore durante la connessione a un DBMS <h1/>
<hr>

 

Come fare allora?
Qualcuno ha pensato a una soluzione semplice quanto efficace, che consiste nel far lavorare insieme Servlet e JSP, cercando quanto più possibile di separare i loro compiti.
Alle Servlet il compito di elaborare e agire, alle JSP il compito di visualizzare e presentare.
Le Servlet riceveranno richieste dai client e le inoltreranno a opportune componenti (dette Action Class), mentre le JSP avranno il solo compito di costituire la parte GUI della nostra applicazione, con poco o nulla codice Java presente in esse, meglio ancora anzi sostituendolo quasi del tutto con altrettante chiamate a macro scritte una volta per tutte e racchiuse in apposite librerie, dette tag-libraries.
Le Servlet quindi costituiranno la parte di controllo (Controller) della nostra applicazione, responsabile di indirizzare le richieste provenienti dal client verso appropriate componenti e di attivarle di conseguenza.
Queste ultime invocheranno tutte le componenti responsabili di predisporre i dati su cui lavorare (Model).
Le JSP infine costituiranno la parte di Visualizzazione (View), occupandosi esclusivamente o quasi di gestire la visualizzazione delle varie informazioni e l'interfaccia con l'utente.
Quanto abbiamo appena descritto - e cioè l'unione delle tre parti di controllo, modello dati e visualizzazione, esprime l'idea di base del cosiddetto pattern architetturale Model View Controller (MVC nel seguito), schematizzato nella figura 1.


Figura 1
- Il pattern architetturale MVC

Si è detto che MVC è un pattern architetturale. Un pattern architetturale rappresenta la struttura fondamentale di un sistema software. I pattern architetturali descrivono un insieme di sottosistemi predefiniti, ne specificano le responsabilità e comprendono regole e linee guida per organizzare le relazioni tra questi sottosistemi. Lo scopo primario di questi pattern è quindi quello di fornire la struttura di base per una applicazione.
Tra le varie soluzioni per costruire in modo opportuno le applicazioni di tipo interattivo (tipicamente web), MVC è una di quelle che hanno avuto maggiore successo ("the BluePrints recommended architectural design pattern for interactive applications" dice testualmente Sun Microsystems, si veda sempre rif.[1]): MVC in effetti "segmenta" i compiti che devono essere svolti sul web tier assegnandoli a diverse componenti, scelte e impiegate a seconda delle loro potenzialità.

 

Implementare MVC: Apache Struts
Tra le differenti numerose possibili implementazioni di MVC, quella descritta più sopra con le Servlet, le JSP e l'aggiunta di librerie di tag per rendere ancora più efficiente l'utilizzo delle JSP stesse prende il nome Struts (rif.[2]). Struts è decisamente una delle più note e diffuse implementazioni di MVC, grazie anche al fatto di essere sufficientemente robusta e "matura" da poter essere utilizzata in produzione, come testimoniano numerosi casi di successo.
Struts si serve fondamentalmente di:

  • JSP per implementare la parte View
  • Servlet e particolari classi Java dette Action Class per implementare la parte Controller
  • Particolari classi Java (Form Bean) per la parte Model

A corredo delle JSP è presente in aggiunta un insieme di librerie di tag, estendibili e personalizzabili secondo le esigenze dello sviluppatore.
La Servlet Controller non fa altro che accettare le richieste dal client e inoltrarle alla opportuna Action Class secondo quanto specificato in un apposito file XML, denominato struts-config.xml, che contiene il completo mapping tra le richieste in arrivo e il corrispondente inoltro.


Figura 2
- L'implementazione Struts

A questo punto, abbiamo tutti gli elementi per poter personalizzare a piacimento la parte web di una applicazione J2EE: sappiamo infatti esattamente cosa fanno le varie parti e dove dobbiamo intervenire per ottenere quello che ci serve. Se vogliamo modificare il flusso di navigazione, occorre individuare nel file struts-config.xml l'azione che ci interessa e "dirottarla" verso un altro componente.
Tutto a posto e tutto facile allora? Forse no. A titolo di esempio, può essere interessante dare un'occhiata all'aspetto di un file struts-config.xml.
Eccone uno, tratto da (rif.[2]), e riguardante un semplice workflow di login.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://struts.apache.org/dtds/struts-config_1_2.dtd">
<struts-config>
<form-beans>
<form-bean
name="logonForm"
type="app.LogonForm"/>
</form-beans>
<action-mappings>
<action
path="/Welcome"
forward="/pages/Welcome.jsp"/>
<action
path="/Logon"
forward="/pages/Logon.jsp"/>
<action
path="/LogonSubmit"
type="app.LogonAction"
name="logonForm"
scope="request"
validate="true"
input="/pages/Logon.jsp">
<forward
name="success"
path="/pages/Welcome.jsp"/>
<forward
name="failure"
path="/pages/Logon.jsp"/>
</action>
<action
path="/Logoff"
type="app.LogoffAction">
<forward
name="success"
path="/pages/Logoff.jsp"/>
</action>
</action-mappings>
<message-resources parameter="resources.application"/>

Si può facilmente intuire come tale file, nel caso di applicazioni di una certa dimensione e complessità, divenga molto poco leggibile. Inoltre tale file gestisce il mapping tra le richieste effettuate e le corrispondenti azioni da invocare, e se tali azioni non sono tra quelle già disponibili occorre svilupparle ex-novo. Per non parlare di eventuali interventi di manutenzione.....

Per risolvere questo problema e cercare di rendere l'approccio alla personalizzazione del flusso navigazionale sul web meno problematico, sono già da tempo disponibili diverse soluzioni software, alcune anche free, scaricabili dal web. Una delle più note probabilmente è la Struts Console (rif.[3]), una applicazione Java Swing standalone che permette di esplorare in modo visuale i diversi elementi di configurazione che costituiscono la parte Struts della nostra applicazione, in particolare i vari JSP Tag Library, Struts, Tiles e Validator configuration files. Nella figura seguente, una schermata di StrutsConsole "all'opera" sugli elementi Struts di una semplice applicazione J2EE.


Figura 3
- Struts Console
(clicca sull'immagine per ingrandire)

Tuttavia, si tratta sempre e comunque di una soluzione parziale, perchè Struts Console ci permette sostanzialmente di gestire in un unico ambiente dotato di accattivante interfaccia i diversi file di configurazione di Struts, ma nulla di più. Esiste un modo per fare davvero un significativo passo in avanti?

 

Modellare ci aiuta!
Proviamo a pensare in termini di modellazione. Una possibile soluzione molto efficiente consiste nell'impiegare per lo sviluppo della nostra applicazione la Model Driven Architecture (MDA nel seguito), metodologia messa a punto da Object Management Group (rif.[4]).

MDA prevede la definizione e costruzione di:

  • un modello di business (detto Platform Independent Model o semplicemente PIM e specificato tramite formalismo UML);
  • una serie di modelli applicativi derivati dal PIM. Essi, detti Platform Specific Model o PSM, sono tanti quanti ciascuna delle tecnologie scelte per implementare la applicazione; nel caso di applicazione J2EE 3-tier avremo quindi un modello per il livello EIS, un modello per EJB, uno per Web, per ciascuno dei quali viene definita una serie di stereotipi UML (nel nostro caso si avrebbe un EIS Model, un EJB Model, un Web Model);
  • un Code model, ossia un repository contenente tutti i componenti di codice sviluppati a partire dai modelli precedenti (vedere figura 4).


Figura 4
- Model Driven Architecure

Ecco la nostra soluzione: utilizzare in modo opportuno gli elementi messi a disposizione nel Web model.

 

Un esempio pratico
Vediamo da vicino un esempio concreto per illustrare meglio il tutto. Ci serviremo dello strumento Compuware OptimalJ (rif.[5]), ambiente di sviluppo per applicazioni J2EE completamente conforme alla metodologia MDA.
La chiave di volta della nostra soluzione consiste nello sfruttare gli elementi presenti nel Web model. In pratica, si tratta di elementi che mappano quanto poi, nel sottostante Code model, verrà tradotto in elementi del framework Struts (fig. 5).


Figura 5
- Modellare gli elementi di Struts

Servendosi di tali elementi è possibile modellare tutti gli aspetti del proprio flusso navigazionale sul web tier. La traduzione di tali elementi nei corrispondenti elementi di Struts avviene a cura del tool, evitandoci di intervenire direttamente sui file di Struts. Senza contare che nel nostro caso non avremo soltanto come risultato un adattamento immediato del flusso navigazionale secondo le nostre esigenze, ma anche la costruzione automatica - sempre a partire da quanto modellato - di tutte le "web actions" necessarie, ossia la costruzione di Action Class e Form Bean relativi, con in più anche le eventuali Helper Class del caso.
Utilizziamo ora tutto questo in pratica nel nostro esempio.
La nostra applicazione è un semplice sistema CRM in cui vengono gestiti i dati di una serie di clienti (Customer) e le relative chiamate effettuate al sistema (Call), tenendo conto del Livello di Servizio con cui ciascun cliente è registrato nel sistema (ServiceAgreement).
In figura 6 il Class Diagram della applicazione in questione.


Figura 6
- Class Diagram della Applicazione CRM

Ci proponiamo di creare sul web tier un flusso applicativo cosiddetto CRUD, che ci permetta cioè di realizzare una per una tutte le diverse azioni applicative di base, le classiche Create, Update, Read e Delete. A tale scopo, sul web tier definiamo un nuovo web component (figura 7)


Figura 7
- Creazione di un web component

Espandiamo il componente appena creato e notiamo che uno degli elementi che lo compongono è un elemento di tipo web flow, punto di partenza per definire il flusso di navigazione del nostro nuovo componente sul web tier. Attiviamo quindi il Webflow Diagram (figura 8).

 


Figura 8
- Webflow Diagram Workbench

Abbiamo a disposizione un ambiente grafico estremamente semplice e intuitivo da utilizzare che ci permette di disegnare il flusso navigazionale così come lo desideriamo, aggiungendo tutto quanto serve (web action, web page etc, si veda la parte racchiusa dal cerchio rosso in figura 8) e comprese le varie interconnessioni.
Il risultato sarà molto simile a un UML Activity Diagram, ma molto più leggibile e ricco di informazioni. Esso inoltre conterrà, in modo estremamente efficace e comprensibile, tutti gli ingredienti e i requisiti necessari a definire il nostro flusso navigazionale.


Figura 9
- Flusso navigazionale del web component

Il successivo passo di generazione del codice costruirà tutto quanto occorre sul web tier, creando i diversi elementi necessari (Action Class, Form Bean etc) e aggiornando in modo opportuno il file struts-config.xml. Apportiamo infine un veloce tocco di personalizzazione grafica, utilizzando il Web User Interface Designer per personalizzare il look & feel dell'applicazione, come illustrato nelle figure 10 e 11.


Figura 10
- Invocazione del Web User Interface Designer
(clicca sull'immagine per ingrandire)

 


Figura 11
- Definizione del Layout della Pagina

Non resta che compilare l'applicazione ed eseguirla per verificare il risultato "navigandola" come da specifiche iniziali. A titolo di esempio, e tenendo presente la "mappa" di quanto modellato (figura 9), si veda in figura 12 il risultato della action "retrieveAction", che produce la webpage "customerList"


Figura 12
- customerList in seguito a retrieveAction
(clicca sull'immagine per ingrandire)

Nella successiva figura 13 si ha il risultato che si ottiene facendo clic sul bottone "new", cosa che equivale (vedere sempre figura 9) a "navigare", partendo dalla webPage "customerList", l'evento "new"; ciò provoca l'invocazione della action "newAction" e la visualizzazione della webpage "customerForm" ; quest'ultima, inseriti i dati, permette, con clic sul bottone "submit", l'invocazione della action "updateAction".


Figura 13
- Creazione di un nuovo customer
(clicca sull'immagine per ingrandire)


Conclusioni
MVC Struts può essere paragonato a una efficientissima ma molto fitta rete di strade, con veicoli e vigili per dirigere il traffico. Non è immediato, per chi arriva in una città sconosciuta o anche per chi deve costruire una città ex-novo, avere il pieno controllo su tutto ciò, anche se ciascuno degli elementi coinvolti esegue esattamente il proprio compito, definito con esattezza a priori. Un utile passo in avanti è senz'altro messo a disposizione da strumenti quali Struts Console, che sono paragonabili a una mappa della città, e che quindi permettono una visualizzazione completa di tutta la struttura, ma purtroppo nulla di più. In questo articolo si è cercato di mettere in evidenza che tipo di vantaggi possa fornire un approccio di tipo radicalmente diverso, basato sulla modellazione. E' sufficiente individuare quanto ci occorre e modellarlo, salvo lasciare ad opportuni tool il compito di realizzare completamente la struttura sottostante, secondo quanto da noi specificato. Quasi come avere a disposizione un meccanismo automatico per richiedere l'aggiunta di strade, veicoli e vigili costruiti secondo le nostre esigenze....e un navigatore satellitare per percorrere il tutto, quasi ad occhi chiusi....!

 

Bibliografia
[1] Eric Armstrong, Jennifer Ball, Stephanie Bodoff et. al, "The J2EEtm Tutorial for Sun Java System Application Server" Online copy on http://java.sun.com/j2ee/1.4/docs/tutorial/doc/index.html[2] Apache Jakarta Struts - http://struts.apache.org [3] Struts Console - http://www.jamesholmes.com/struts/console/ [4] Mokabyte - "Uso della Model Driven Architecture nello Sviluppo di Applicazioni J2EE", parte 1 http://www.mokabyte.it/2004/07/mda-1.htm e parte 2 http://www.mokabyte.it/2004/09/mda-2.htm)
[5] Compuware Lab "OptimalJ Community" - http://javacentral.compuware.com

 

Doriano Gallozzi è nato a Roma nel 1964 e si è laureato in Ingegneria Elettronica (indirizzo Informatica) nel 1989. Da sempre interessato a problematiche di analisi, progettazione e sviluppo di Sistemi Informativi, ha lavorato per diversi anni in aziende del settore informatico italiano (gruppo ENI, gruppo Telecom Italia), dove ha acquisito diverse esperienze tanto nel campo della progettazione e sviluppo del software (in ambiente M/F come in ambiente distribuito) quanto nel campo dei RDBMS (DBA su diversi progetti per clienti finali quali Telecom Italia). Da gennaio 2000 lavora nella Divisione Prevendita di Compuware Italia. La sua attività verte principalmente sulla piattaforma J2EE e tecnologie correlate, ma anche su ambiti tecnologici quali l'Enterprise Application Integration, i Portali Web, gli strumenti di Business Process Modeling.

MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it