La
ActionServlet
La org.apache.struts.action.ActionServlet è la
servlet di controllo di Struts. Come già accennato
nel precedente articolo è la servlet che gestisce
tutte le richieste http che provengono dai client e
indirizza il flusso applicativo in base alla configurazione
presente nel file XML struts-config.xml.
Come è ovvio la ActionServlet estende la javax.servlet.http.HttpServlet;
i suoi metodi doGet() e doPost() chiamano entrambi un
metodo process() che esegue quindi l'elaborazione sia
in caso di richieste di tipo GET che di tipo POST. Di
seguito è riportato il metodo doGet(), il doPost()
è identico:
public
void doGet(HttpServletRequest request, HttpServletresponse
response)
throws
IOException,ServletException {
process(request,response);
}
La
ActionServlet esegue l'elaborazione che schematicamente
comprende i seguenti step:
- I
metodi doGet() e doPost() invocano il metodo process()
della ActionServlet
- Nel
metodo process() la ActionServlet ottiene l'istanza
del RequestProcessor, configurato per l'applicazione
nel tag <controller> dello struts.config.xml,
e ne esegue il metodo process().
- Nel
metodo process() del RequestProcessor viene eseguita
l'elaborazione vera e propria, ed in output al metodo
viene fornito un oggetto ActionForward che consente
alla ActionServlet di inoltrare l'elaborazione in
base alla configurazione presente nello struts-config.xml.
La
ActionServlet viene configurata, come ogni servlet,
nel web.xml. I parametri di inizializzazione sono molti
e per un elenco completo si rimanda al sito ufficiale
di Struts (http://jakarta.apache.org/struts/). Di seguito
è riportato un blocco <servlet> di configurazione
standard della ActionServlet nel quale è settato
ad 1 il parametro <load-on-startup> in base al
quale il container istanzia la ActionServlet allo start-up
della web-application e ne invoca il metodo init().
Inoltre mediante il parametro config è specificata
la posizione del file XML di configurazione dell'applicazione.
Il parametro debug abilita il debugging dell'applicazione.
Mediante il blocco <servlet-mapping> si specifica
che tutte le richieste con path terminante in .do vengono
mappate sulla servlet di controllo di Struts:
<!-Configurazione
standard della Action Servlet -->
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-
Mapping della Action Servlet -->
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
Con
questa configurazione di base è già possibile
utilizzare la ActionServlet come servlet di controllo
della propia applicazione.
Il
Request Processor
Come visto al punto 2) del precedente paragrafo, la
org.apache.struts.action.RequestProcessor è la
classe alla quale la ActionServlet delega l'elaborazione
delle richieste.
Il RequestProcessor viene configurato mediante il tag
<controller> dello struts-config.xml , ed è
possibile utilizzarne uno proprio scrivendo una classe
che estende la org.apache.struts.action.RequestProcessor
e ne implementa i metodi. In particolare è di
uso comune fare l'override del metodo processPreprocess()
che viene eseguito dal RequestProcessor prima dell'elaborazione
di ogni richiesta. Questo metodo è il punto ottimale
per inserire controlli di validità della sessione,
dell'utente o simili.
Il RequestProcessor esegue i seguenti step:
- Legge
il file struts-config.xml per trovate un un elemento
XML <action> corrispondente al path della richiesta.
- Una
volta trovato l'elemento <action> corrispondente
verifica se è presente l'attributo name che
corrisponde al nome dell'ActionForm configurato per
la richiesta in elaborazione. In tal caso provvede
a reperire una istanza dell'ActionForm e a popolarne
gli attributi con i valori presenti nella request
http, facendo una corrispondenza tra nome parametro
e nome attributo.
- Se
nell'elemento <action> è presente l'attributo
validate al valore true chiama il metodo validate()
dell'ActionForm per il controllo dei dati forniti
dalla request.
- Se
il controllo è ok a questo punto il RequestProcessor
chiama il metodo execute() dell'Action configurata
nell'elemento <action> delegandole l'elaborazione
della richiesta.
- Il
metodo execute() dell'Action al termine dell'elaborazione
restituisce un oggetto ActionForward che consente
al RequestProcessor di inoltrare il flusso elaborativo.
Come
visto quindi la ActionServlet delega l'elaborazione
della richiesta al RequestProcessor che a sua volta
, dopo aver popolato con i dati della request l'ActionForm
configurato nell'elemento <action> corrispondente
al path della richiesta, delega l'elaborazione della
singola richiesta alla classe Action corrispondente.
Un esempio di configurazione di una Action nel file
struts-config.xml è il seguente:
<!-definizione
del ActionForm -->
<form-beans>
<form-bean name="startForm" type="it.prove..MenuForm"
/>
</form-beans>
<action-mappings>
<!-definizione del Action -->
<action path="/start"
name="startForm"
scope="request"
type="it.prove.StartAction"
validate="true">
<forward name="ok" path="/pagina1.jsp"/>
<forward name="ko" path="/errorpage.jsp"/>
</action>
</action-mappings>
In
questo esempio al path /start.do viene associato il
form it.prove.StartForm e la Action it.prove.StartAction.
Ciò significa che quando il RequestProcessor
riceverà una richiesta con path /start.do valorizzerà
gli attributi di un oggetto della classe it.prove.StartForm
con i parametri della request e dopo averne validato
i valori la passerà al metodo execute() della
classe it.prove.StartAction che esegue l'elaborazione
prevista.
La
classe Action
Dopo aver esaminato la ActionServlet ed il RequestProcessor
finalmente arriviamo a parlare della classe org.apache.struts.action.Action.
La classe Action è l'elemento fondamentale del
controller di Struts in quanto per ogni funzione realizzata
con Struts bisogna creare una propria classe che la
estende e ne implementa il metodo execute() che è
fatto come segue:
public
ActionForward execute(ActionMapping mapping, ActionForm
form,
HttpServletRequest request, HttpServletResponse response)
throws
Exception{
//codice di esempio
//acquisizione form
MyForm myForm = (MyForm)form;
//acquisizione parametri dal form
String param1 = myForm.getParam1();
//business logic
...
//fine business logic
//inoltro
dell'elaborazione
return mapping.findForward("ok");
}
Il
metodo execute() riceve in input request e response
http, un'istanza dell'oggetto ActionForm prima descritto,
e un oggetto ActionMapping che contiene le infornazioni
configurate nell'elemento <action> tra le quali
i forward, ovvero i percorsi a cui inoltrare in uscita
l'elaborazione. Restituisce un oggetto ActionForward
che contiene il path di inoltro dell'elaborazione.
E' nel metodo execute() della propria Action che lo
sviluppatore inserisce il proprio codice di elaborazione
della richiesta per la funzione specifica.
Bisogna subito sottolineare due aspetti fondamentali
riguardo alle Action:
-
Le Action vengono gestite esattamente come delle servlet.
Ovvero il loro funzionamento è basato sulla
stessa logica multithread delle servlet quindi sono
soggette a tutti i problemi comunemente noti nelle
servlet. Il codice scritto nelle Action deve essere
thread-safe per un corretto funzionamento delle stesse.
- Le
Action fanno parte del Controller e non del Model.
La logica applicativa non deve essere scritta nella
Action, ma questa deve delegare allo strato di Model
l'elaborazione della business-logic.
In
base a quanto detto una Action dovrebbe:
-
Acquisire i dati della request dal form
-
Delegare l'elaborazione della business-logic alle
classi del Model
- Acquisire
i risultati dell'elaborazione e prepararli per la
vista da inviare all'utente mettendoli nello scope
opportuno (se necessario).
- Inoltrare
il flusso elaborativo in base alla logica applicativa.
Le
Action costiuiscono quindi il 'ponte' applicativo tra
lo strato di Controller e di Model di un aapplicazione
scritta con Struts ed hanno un ruolo fondamentale perché
sono le classi che lo sviluppatore scrive continuamente
nello sviluppo di una applicazione Struts.
La
classe ActionForm
Infine concludiamo parlando della classe org.apache.struts.action.ActionForm.
Abbiamo già visto che i form (come sono chiamate
nella terminologia Struts le classi che estendono la
org.apache.struts.action.ActionForm) sono sostanzialmente
dei bean contenenti dati, che il framework popola automaticamente
con i dati della request svincolando lo sviluppatore
dal doverlo fare con proprio codice applicativo. Associando
ad un path un oggetto di una classe che estende la org.apache.struts.action.ActionForm,
definito mediante il tag <form-bean>, è
possibile fornire al metodo execute() della Action un
oggetto contenente tutti i dati inseriti in un FORM
HTML, con la possibilità di validarli prima che
gli stessi giungano alla Action stessa come visto in
precedenza. Ritorneremo comunque a parlare dei form
quando analizzeremo lo strato di View di Struts.
Conclusioni
In questo articolo abbiamo esaminato gli elementi fondamentali
del Controller di Struts per dare un'idea di come venga
elaborata una richiesta dalle classi del framework.
E' ovvio che le classi citate sono molto più
complesse ed articolate di quanto detto quindi per un
esame più approfondito del loro codice si consiglia
di scaricare i sorgenti dal sito di Struts. Lo scopo
dell'articolo era più che altro di illustrare
gli step principali eseguiti dal controller di Struts
ad ogni richiesta per consentire una migliore comprensione
del suo funzionamento.
Bibliografia
[1] Chuck Cavaness - "Programming Jakarta Struts",
O'Reilly, 2003
[2] Rod Johnson - "J2EE Design and Development",
Wrox, 2002
[3] James Goodwill, Richard Hightower - Professional
Jakarta Struts" - Wrox 2004
Alfredo Larotonda, laureato
in Ingegneria Elettronica, lavora da diversi anni nel
settore IT. Dal 1999 si occupa di Java ed in particolare
dello sviluppo di applicazioni web J2EE. Dopo diverse
esperienze di disegno e sviluppo ora si occupa in particolare
di aspetti architetturali per progetti rivolti al mercato
finanziario ed industriale. E' Web Component Developer
certificato SUN per la piattaforma J2EE e Programmer
per la piattaforma Java.
|