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