Visualizzazione post con etichetta jsf. Mostra tutti i post
Visualizzazione post con etichetta jsf. Mostra tutti i post

mercoledì 9 marzo 2011

JSF e IllegalMonitorStateException in forwarding

Ci sono casi nei quali il puro uso di JSF non è sufficiente: ad esempio quando si vuole inviare un file o uno stream in download attraverso il browser si deve interagire con la richiesta/risposta della classica HttpServlet. In questo caso potrebbe capitare di ottenere il corretto funzionamento del front-end (ossia del browser) ma di trovare una eccezione IllegalMonitorStateException riferita un doForward(..) sul servlet engine. In sostanza quello che avviene è che la servlet invia un risultato ma poi il sistema JSF (e la relativa servlet), non essendo a conoscenza di questa risposta "on-demand" tenta di inviarne una propria. Il servlet engine si accorge di aver già  mandato una intestazione e dei dati (quelli forniti manualmente) e quindi si scatena l'eccezione di cui sopra. La soluzione è abbastanza semplice: si deve invocare il metodo responseComplete() sul FacesContext corrente una volta che si sia finito di inviare la risposta manualmente.

sabato 29 gennaio 2011

JSF: popolare un menu' programmaticamente

La tag library JSF contiene una serie di elementi, quali ad esempio selectOneMenu, che lavorano su una serie di item da visualizzare in formato lista o menu' a discesa. Il problema di questi item è che non possono essere generati automaticamente nella pagina stessa, come si può invece fare con un foreach della libreria JSP. Per poter generare una lista di item occorre definire in un backing bean un metodo che ritorni un iterable di tipo SelectItem (quindi ad esempio List oppure SelectItem[]) e associare, tramite il tag speciale selectItems, questo elenco al componente stesso.
Il seguente codice mostra un esempio di generazione di un elenco di mesi:

      public final SelectItem[] getMesi(){
        SelectItem months[] = new SelectItem[ 12 ];


        months[ 0 ]     = new SelectItem( 0, "Gennaio" );
        months[ 1 ]     = new SelectItem( 1, "Febbraio" );
        months[ 2 ]     = new SelectItem( 2, "Marzo" );
        months[ 3 ]     = new SelectItem( 3, "Aprile" );
        months[ 4 ]     = new SelectItem( 4, "Maggio" );
        months[ 5 ]     = new SelectItem( 5, "Giugno" );
        months[ 6 ]     = new SelectItem( 6, "Luglio" );
        months[ 7 ]     = new SelectItem( 7, "Agosto" );
        months[ 8 ]     = new SelectItem( 8, "Settembre" );
        months[ 9 ]     = new SelectItem( 9, "Ottobre" );
        months[ 10 ]     = new SelectItem( 10, "Novembre" );
        months[ 11 ]     = new SelectItem( 11, "Dicembre" );

        return months;

    }

e l'associazione con il relativo componente JSF avviene come segue:

<h:selectOneMenu id="selezioneMese" value="#{bean.mesi }" >
  <f:selectItems value="#{bean.mesi }"/>
</h:selectOneMenu>


Con "bean" che rappresenta il nome (id) del backing bean associato alla applicazione JSF.

JSF: propagare le proprieta' di un bean ad un altro bean

Mi sono trovato nella curiosa situazione di avere un bean gestito da una applicazione JSF e di dover usare tale bean per l'inizializzazione di diversi valori di un altro bean gestito dalla stessa applicazione. Non ho trovato nessun modo esplicito di poter collegare in cascata i bean a run-time, e sono quindi ricorso al costruttore del secondo bean per ottenere il primo e usarlo come parametro di inizializzazione per se stesso.
Si ipotizzi di avere il bean A registrato con id beanA e il bean B registrato con id beanB e di dover eseguire su B il metodo B.initFromA( A a ). E' possibile inserire nel costruttore di B il seguente codice:

       public B(){
        super();
       try{
        FacesContext facesContext = FacesContext.getCurrentInstance();

        if( facesContext == null )
            // non sono in contesto JFS?
            return;

        Application webApplication = facesContext.getApplication();
        ValueBinding valueBinding = webApplication.createValueBinding( "#{beanA}" );
        A beanAFromWebApplication = (A) valueBinding.getValue( facesContext );
        initFromA( beanAFromWebApplication );
   
          }catch( Exception e ){
            // esecuzione non in contesto JFS
            // ...
       }
    }


Da notare che vengono gestite eventuali eccezioni di cast (se il bean non viene trovato oppure non e' del tipo corretto) che consentono l'esecuzione di B anche fuori dal contesto JFS (ossia come bean normale).

venerdì 28 gennaio 2011

JSF: istruzioni ECL condizionali

Il tag outputTest della tag lig JSF consente l'utilizzo di istruzioni condizionali, e quindi e' possibile scrivere qualcosa del genere:

<h:outputLabel value="#{ (user.administrator) ?
     'admin' :
     'utente misero' }  " >



Ove si controlla se l'utente e' amministratore e a seconda del relativo livello si stampa un messaggio informativo opportuno.

JSF: associazione programmatica di un managed bean

E' possibile registrare un bean in un contesto JSF programmaticamente (e quindi non solo usando faces-config.xml) con semplici righe di codice:

// ottengo la applicazione web JSF
FacesContext facesContext     = FacesContext.getCurrentInstance();
Application webApplication     = facesContext.getApplication();

String beanValueBindingID =  "#{myBean}";

// creo il binding
ValueBinding valueBinding = w
    ebApplication.createValueBinding( beanValueBindingID );
valueBinding.setValue(facesContext, beanToManage );


Nell'esempio di cui sopra l'oggetto beanToManage viene associato all'applicazione Web con nome mybean e quindi puo' essere usato nelle taglib delle pagine JSP.