MokaByte 88 - 7mbre 2004 
Sviluppare applicazioni web J2EE
con Jakarta Struts

VIII parte: le action standard
di
Alfredo Larotonda
Nei precedenti articoli della serie abbiamo illustrato l'architettura e i componenti principali di Struts esaminandone pro e contro. Abbiamo esaminato da un punto di vista teorico e concettuale i motivi per i quali utilizzare un framework come Struts nello sviluppo di applicazioni J2EE è consigliato ed opportuno. Avviandoci verso il termine della serie dedicata a Struts, concludiamo con qualche articolo dedicato ad aspetti di taglio maggiormente pratico e forse più utili per un utilizzo giornaliero del framework. Iniziamo col descrivere una serie di Action standard che sono molto usate nello sviluppo concreto di progetti con Struts.

Le Action base standard di Struts
Struts fornisce alcune Action base che arricchiscono il framework di alcune funzionalità rispetto alla Action base standard e che sono utili a diversi scopi . Di seguito forniamo una descrizione di quelle più utilizzate nella pratica.

La DispatchAction
Abbiamo già visto precedentemente che nel funzionamento standard di Struts , il framework esegue il metodo execute() della Action che corrisponde al URL della richiesta effettuata dal client. Il metodo execute() costituisce quindi il punto di ingresso nel framework a fronte di una richiesta dal client. Questo funzionamento si adatta poco alle situazioni nelle quali è necessario eseguire una serie di elaborazioni tra loro logicamente collegate. Tipico è l'esempio di operazioni di inserimento, cancellazione , lettura e aggiornamento su una stessa tabella di un database. Sarebbe abbastanza poco efficiente dover definire una Action per ciascuna singola operazione , in quanto questa tecnica porterebbe ad un proliferare di Action nell'applicazione e quindi ad una difficile gestione della stessa. Struts ci viene incontro fornendo org.apache.struts.actions.DispatchAction.
La DispatchAction è assolutamente analoga ad una Acion base ma fornisce la possibilità di invocare diversi metodi della stessa purchè il client specifichi il metodo da chiamare. In pratica è come una Action che non ha un solo metodo execute() ma ne ha n con nomi diversi. Ognuno di questi metodi deve avere la stessa signature del metodo execute().
Ad esempio una DispatchAction potrebbe avere i seguenti metodi:


public ActionForward inserisci(ActionMapping mapping, ActionForm form,
                               HttpServletRequest req, HttpServletResponse res)
                               throws IOException,ServletException;

public ActionForward aggiorna(ActionMapping mapping, ActionForm form,
                               HttpServletRequest req, HttpServletResponse res)
                               throws IOException,ServletException;

public ActionForward cancella(ActionMapping mapping, ActionForm form,
                               HttpServletRequest req, HttpServletResponse res)
                               throws IOException,ServletException;

public ActionForward leggi(ActionMapping mapping, ActionForm form,
                               HttpServletRequest req, HttpServletResponse res)
                               throws IOException,ServletException;

Affinché il framework sappia a quale metodo delegare l'elaborazione della richiesta, il client deve fornire nella request un parametro contenente il nome del metodo corrispondente. Questo parametro va ovviamente specificato nella definizione della Action nello struts-config.xml nel seguente modo:

<action
path="/gestioneTabella"
type="it.esempio.GestioneTabellaAction"
name="gestioneTabellaForm"
scope="request"
input="/tabella.jsp"
parameter="metodo"/>

Se quindi da una pagina JSP si vuole invocare il metodo inserisci() della Action GestioneTabellaAction sarà sufficiente specificare:

http://servername/context-root/gestioneTabella?metodo=inserisci

Chiaramente il nome del metodo può essere specificato in diversi modi, come un hidden contenuto in un form HTML oppure può essere impostato da una funzione JavaScript prima di eseguire la submit() del form.
L'importante è che è possibile raggruppare logicamente azioni tra di loro correlate in un'unica Action il che porta ad una migliore strutturazione dell'applicazione ed evita duplicazioni inutili di codice. Nella pratica comune la DispatchAction è effettivamente molto utile e a mio parere salvo eccezioni è quella da utilizzare come classe base per le Action della propria applicazione invece della semplice Action standard.

La LookupDispatchAction
La org.apache.struts.actions.LookupDiapatchAction è utile quando la scelta del metodo da eseguire in una Action di tipo 'dispatch' è effettuata mediante i button di un form ma si ha la necessità di avere le label dei button localizzate e non ci si vuole affidare a codice JavaScript per la selezione del metodo da attivare.
La LookupDiapatchAction è quindi del tutto analoga alla DispatchAction per quel che riguarda la sua struttura, quello che cambia è il modo con il quale viene selezionato il metodo da mandare in esecuzione.
In questo caso le label dei button vengono asscociate alle loro key contenute nel resource bundle dell'applicazione, e queste key, che molto probabilmente non sono nomi di metodo validi, vengono mappate dallo sviluppatore ai metodi della Action mediante la definizione di un metodo così fatto:

protected Map getKeyMethodMap(ActionMapping mapping, ActionForm form,
                              HttpServletRequest request) {
  Map map = new HashMap();
  map.put("bottone.leggi", "leggi");
  map.put("bottone.inserisci", "inserisci");
  map.put("bottone.cacnella", "cancella");
  map.put("bottone.modifica", "modifica");
  return map;
}

Nel metodo viene definita una HashMap nella quale ad ogni key è associato il nome di un metodo della Action. Questo metodo è usato dal framework per determinare la corrispondenza tra la label localizzata del bottone cliccato ed il metodo della LookupDispatchAction da eseguire.
In base a questo codice la definizione dei bottoni nella pagina JSP sarà del seguente tipo:

<html:form action="/gestioneTabella">
<html:submit property="method">
<bean:message key=" bottone.leggi ">
</html:submit>
<html:submit property="method">
<bean:message key=" bottone.inserisci ">
</html:submit>
<html:submit property="method">
<bean:message key=" bottone.cacnella ">
</html:submit>
<html:submit property="method">
<bean:message key=" bottone.modifica ">
</html:submit>
</html:form>


In questo modo è possibile avere una Action di tipo 'dispatch' i cui metodi sono attivabili da button di un form di una applicazione localizzata semplicemente scrivendo un metodo getKeyMethodMap() come descritto.

La BaseAction
La org.apache.scaffold.http.BaseAction è una Action fornita nei package opzionali denominati Scaffold. E' una Action che fornisce un metodo execute() base fatto come segue:

public ActionForward execute(ActionMapping mapping, ActionForm form,
                             HttpServletRequest req, HttpServletResponse res)
                             throws Exception {

  // Controlla le pre-condizioni all'elaborazione
  preProcess(mapping,form,request,response);
  // ci sono errori va in failure
  if (isErrors(request)) {
    return findFailure(mapping,form,request,response);
  }

  // Esecuzione della logica
  try {
    executeLogic(mapping,form,request,response);
  }
  catch (Exception e) {
    
// Gestione dell'eccezione
    setException(request,e);
    catchException(mapping,form,request,response);
  }
  finally {
    // Elaborazioni finali
    postProcess(mapping,form,request,response);
  }

  // Se ci sono errori va in failure
  if (isErrors(request)) {
    return findFailure(mapping,form,request,response);
  }

  // Otherwise, check for messages and succeed (only 1_0)
  if ((isStruts_1_0()) && (isMessages(request))) {
    saveErrors(request,getMessages(request,false));
  }
}

La BaseAction può essere usata come classe base di tutte le Action dell'applicazione allo scopo di standardizzare la scrittura dei vari metodi execute(). In pratica in questo caso lo sviluppatore dovrà implementare nella propria Action il metodo executeLogic() ed eventualmente uno tra i metodi preProcess() o postProcess(). Il metodo execute() della ActionBase rispecchia le operazioni effettuate in genere da un comune metodo execute() di una Action. Questo approccio può essere comunque usato come spunto per costruirsi una propria Action base se non si vuole utilizzare la BaseAction dei package Scaffold.

 

Le Action standard di Struts per il controllo del flusso
Struts fornisce alcune standard che consentono di controllare il flusso elaborativo.

La ForwardAction
La ForwardAction consente di inoltrare il flusso dell'applicazione ad un'altra risorsa individuata mediante un URI valido, risorsa che può essere una pagina JSP una servlet o altro.
La ForwardAction quindi non fa altro che creare un RequestDispatcher ed effettuare il forward alla risorsa individuata dall'attributo parameter specificato nella definizione della Action nello struts-config.xml.

<action
path="/vaiAllaPagina1"
type="org.apache.struts.actions.ForwardAction"
name="pagina1Form"
scope="request"
input="/pagina0.jsp"
parameter="/pagina1.jsp "/>

La ForwardAction è molto utile quando nell'applicazione si hanno pagine JSP che non richiedono alcuna elaborazione a monte prima di essere visualizzate. Affinché si eviti di effettuare un inoltro alla pagina in questione direttamente da un'altra pagina JSP dell'applicazione si può usare la ForwardAction. In questo modo si resta aderenti al modello di Struts che prevede un controllo centralizzato di tutte le richieste e si predispone l'applicazione a modifiche future. Se un domani infatti la pagina in questione richiedesse invece qualche elaborazione basterà sostituire una Action opportuna al mapping precedentemente corrispondente alla ForwardAction.
Un altro utilizzo della ForwardAction è come elemento di integrazione con altre applicazioni data la sua caratteristica di effettuare un inoltro ad un URI generico.

La IncludeAction
La IncludeAction è la corrispettiva della ForwardAction per l'operazione di include della risposta generata da un'altra risorsa. Consente di aggiungere alla propria elaborazione l'elaborazione effettuata da un'altra risorsa quale ad esempio una servlet. Non è molto utilizzata ma è comunque fornita da Struts qualora potesse servire.

 

Conclusioni
In questo articolo abbiamo esaminato alcune Action fornite da Struts e molto usate nella pratica comune. Sicuramente la DispatchAction è quella maggiormente usata e più utile ai fini di una corretta strutturazione della propria applicazione. In progetti reali è molto facile che le Action della propria applicazione estendano la DispatchAction piuttosto che la Action standard, anche se poi il funzionamento alla base delle due è esattamente lo stesso.

 

Bibliografia
[1] Chuck Cavaness - "Programming Jakarta Struts", O'Reilly, 2003
[2] James Goodwill, Richard Hightower - "Professional Jakarta Struts" - Wrox 2004
[3] Richard Hightower - "Jakarta Struts Live" - SourceBeat 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' in possesso delle certificazioni SCJP (Sun Certified Java Programmer), SCWCD (Sun Certified Web Component Developer) e SCBCD (Sun Certified Business Component Developer).


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