venerdì 29 marzo 2013

JSF definire e utilizzare PhaseListener

L'interfaccia javax.faces.event.PhaseListener se implementata consente di scrivere codice in ogni punto del ciclo di vita della pagina JSF.
I cicli di vita della pagina sono:
  • RESTORE VIEW
  • APPLY REQUEST VALUES
  • PROCESS VALIDATION
  • UPDATE MODEL VALUE
  • INVOKE APPLICATION
  • RENDER RESPONSE
Si può definire o a livello globale, dichiarandola nel faces-config.xml, oppure sulla singola view in cui è dichiarata (solo dalla versione 1.2 in poi).

Nel primo caso, una volta scritta la classe, è sufficiente dichiarare nel faces-config.xml


<lifecycle>
 <phase-listener>it.events.lifecycleJsf.RegistroEventiPagina</phase-listener>
 </lifecycle>

Nel secondo caso invece dobbiamo:
  1. Definire la classe come proprietà del Managed Bean;
  2. Inserire nella pagina di interesse il tag
    <f:phaseListener binding="#{workflowTabManager.eventListener}" type="it.events.lifecycleJsf.RegistroEventiPagina"/>

La classe RegistroEventiPagina è la seguente:

public class RegistroEventiPagina implements PhaseListener {
 private static final long serialVersionUID = 1L;
 private static Logger log=Logger.getLogger(Costanti.LOG_APPENDER);
 @Override
 public void afterPhase(PhaseEvent pe) {
  if(pe.getPhaseId()==PhaseId.RESTORE_VIEW){
   log.debug("Esco dalla fase di RESTORE_VIEW: "+new Date()+" phaseId-"+pe.getPhaseId().toString());
  }
  else if(pe.getPhaseId()==PhaseId.APPLY_REQUEST_VALUES)
  {
   log.debug("Esco dalla fase di APPLY_REQUEST_VALUES: "+new Date()+" phaseId-"+pe.getPhaseId().toString());
  }
  else if(pe.getPhaseId()==PhaseId.PROCESS_VALIDATIONS)
  {
   log.debug("Esco dalla fase di PROCESS_VALIDATIONS: "+new Date()+" phaseId-"+pe.getPhaseId().toString());
  }
  else if(pe.getPhaseId()==PhaseId.UPDATE_MODEL_VALUES)
  {
   log.debug("Esco dalla fase di UPDATE_MODEL_VALUES: "+new Date()+" phaseId-"+pe.getPhaseId().toString());
  }
  else if(pe.getPhaseId()==PhaseId.INVOKE_APPLICATION)
  {
   log.debug("Esco dalla fase di INVOKE_APPLICATION: "+new Date()+" phaseId-"+pe.getPhaseId().toString());
  }
  else if(pe.getPhaseId()==PhaseId.RENDER_RESPONSE)
  {
   log.debug("Esco dalla fase di RENDER_RESPONSE: "+new Date()+" phaseId-"+pe.getPhaseId().toString());
  }
  
 }
 @Override
 public void beforePhase(PhaseEvent pe) {
  
  if(pe.getPhaseId()==PhaseId.RESTORE_VIEW){
   log.debug("Entro nella fase di RESTORE_VIEW: "+new Date()+" phaseId-"+pe.getPhaseId().toString());
  }
  else if(pe.getPhaseId()==PhaseId.APPLY_REQUEST_VALUES)
  {
   log.debug("Entro nella fase di APPLY_REQUEST_VALUES: "+new Date()+" phaseId-"+pe.getPhaseId().toString());
  }
  else if(pe.getPhaseId()==PhaseId.PROCESS_VALIDATIONS)
  {
   log.debug("Entro nella fase di PROCESS_VALIDATIONS: "+new Date()+" phaseId-"+pe.getPhaseId().toString());
  }
  else if(pe.getPhaseId()==PhaseId.UPDATE_MODEL_VALUES)
  {
   log.debug("Entro nella fase di UPDATE_MODEL_VALUES: "+new Date()+" phaseId-"+pe.getPhaseId().toString());
  }
  else if(pe.getPhaseId()==PhaseId.INVOKE_APPLICATION)
  {
   log.debug("Entro nella fase di INVOKE_APPLICATION: "+new Date()+" phaseId-"+pe.getPhaseId().toString());
  }
  else if(pe.getPhaseId()==PhaseId.RENDER_RESPONSE)
  {
   log.debug("Entro nella fase di RENDER_RESPONSE: "+new Date()+" phaseId-"+pe.getPhaseId().toString());
  }
  
 }

 @Override
 public PhaseId getPhaseId() {
  
   return PhaseId.ANY_PHASE;
 }

}

PrimeFaces dataTable paginazione e ritorno a pagina selezionata

Utilizzando il componente p:dataTable di primefaces ho avuto necessità di implementare la paginazione (cosa banale) e poi soprattutto, una volta selezionato un elemento della lista, al ritorno sulla lista stessa tornare sulla pagina selezionata e non , come avviene con il comportamento di default, sulla prima pagina.
Stiamo parlando di un caricamento dati classico, non di un LazyLoading.
Per fare questa attività mi è stato molto utile questo link sul forum di primefaces (http://forum.primefaces.org/viewtopic.php?f=3&t=25399 ).

Le attività da compiere sono le seguenti:

1) Definire il bean della tabella come SessionScoped

2) Definire sul bean una proprietà di tipo int (io seguendo l'esempio del forum l'ho denominata first)

3) Inserire sugli attributi del p:dataTable l'attributo first="#{tabellaClienti.first}" dove tabellaClienti è il nome del mio bean di tabella e first la proprietà appena inserita.

4) All'interno della tabella inserire un evento ajax che scatta al cambio di paginazione



<p:ajax event="page" listener="#{tabellaClienti.onPageChange}"/>


Il codice dell'evento è il seguente

public void onPageChange(PageEvent event) {
 log.debug("Clicco sulla pagina "+event.getPage());
 this.setFirst(event.getPage());
}


PrimeFaces aggiungere parametri da processare via ajax

In un form avevo la seguente problematica.
Dopo aver settato un valore di un inplace editor (quindi un inplace associato ad un inputText) viene scatenata una chiamata Ajax che recupera dei dati dalla sessione , fa alcune elaborazioni e quindi rieffettua l'update di un pannello sul form.
Il problema segnalato era che modificando una textarea interna del pannello con l'in place ancora aperto (senza aver cliccato sulla casella di spunta) una volta sottomessa la chiamata Ajax il valore della textArea andava perduto.
Quindi avevo la necessità di portarmi dietro anche il valore della textArea nella chiamata Ajax, in modo che fosse recuperato lato server e non perso.
Con il tag p:ajax questo è molto semplice, basta settare l'attributo "process".
Dalla javadoc di primefaces la descrizione dell'attributo è la seguente:

Component(s) to process in partial request. Defaults to @this.

Quindi basta scrivere nell'atributo process l'id del componente da processare.

Esempio:


<p:inplace id="val_sog" editor="true" 
rendered="#{verificaComplessiva.daModificare 
and verificaComplessiva.stato!='K'}" >  
<p:inputText value="#{verificaComplessiva.punteggio_soggettivo_ope}" immediate="true" />  
<p:ajax event="save" listener="#{workflowTabManager.updateVerificaComplessiva}" 
 process="val_sog txtNote" update="verificaComplessivaPanel"/> 
</p:inplace>                                           

Nel metodo "updateVerificaComplessiva", recuperando dalla sessione il bean, si trova anche il valore della text area, invece prima invece il campo testo era vuoto.


HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
HttpSession session = (HttpSession) request.getSession();
VerificaComplessiva vc = (VerificaComplessiva) session.getAttribute("verificaComplessiva");





lunedì 25 marzo 2013

Configurare web app isolate in JBOSS (versione 5.1)

Un problema che spesso si riscontra con JBOSS è che la politica di default nel caricamento delle librerie è quella del PARENT FIRST.
Quindi JBOSS carica nel classpath prima i suoi jar e solo in seguito passa ad analizzare le librerie presenti nella WEB-INF/lib dell'applicazione.
Nel caricamento dei jar nel classpath  vige la regola che il primo caricato è poi quello effettivamente utilizzato.
Da qui tutti gli innumerevoli problemi tra versioni diverse dello stesso jar, per cui il nostro war una volta deployato smette di funzionare per incompatibilità nelle librerie.
In questi casi la soluzione migliore è quella di isolare la nostra applicazione, ossia fare in modo che siano caricati prima i jar della web app e dopo quelli dell'application server.
Su JBOSS 5.1 per ottenere questo risultato bisogna aggiungere un file xml dentro la directory WEB-INF della nostra applicazione, denominato jboss-classloading.xml.

<?xml version="1.0" encoding="UTF-8"?>

         <classloading xmlns="urn:jboss:classloading:1.0"

                       parent-first="false"              

                       domain="DefaultDomain"

                       top-level-classloader="true"

                       parent-domain="Ignored"

                       export-all="NON_EMPTY"

                       import-all="true">

        </classloading>




mercoledì 20 marzo 2013

Tomcat - IOException while loading persisted sessions

Questo errore si verifica quando Tomcat non riesce a ripristinare il valore della sessione.
Tale valore si trova in un file serializzato denominato SESSION.ser all'interno della directory work di Tomcat.
E' necessaria la pulizia della directory work o anche la sola cancellazione del file .ser.


mercoledì 13 marzo 2013

showModalDialog problemi con IE 8

Ho verificato il seguente tipo di problema utilizzando lo showModalDialog soltanto con IE8, mentre tutto funzionava correttamente con Firefox e Chrome.
Il requisito era di aprire in modale una finestra e consentire al suo interno la navigazione mantenendo inibita la possibilità di cliccare sulla finestra padre.
Il problema che si verificava era che al primo click all'interno della finestra modale, invece di proseguire la navigazione normalmente, veniva aperta una nuova finestra , su cui poi si navigava correttamente.
C'era quindi la seguente situazione:
  1. Finestra di partenza, da cui si apre con showModalDialog l'applicazione che si vuole visualizzare in modale;
  2. Finestra dell'applicazione iniziale, sulla quale  clicco per navigare;
  3. Finestra aperta dall'interno della finestra modale.
Insomma  una situazione molto strana ed anomala nonchè, ripeto, esistente soltanto su Internet Explorer.
Navigando su internet ho trovato questo interessante articolo in merito che mi ha aiutato a risolvere il problema: http://jwcooney.com/2011/12/22/showmodaldialog-opens-a-new-window-on-submit-or-location-href/  .

Sintetizzando ci sono due strade da seguire:

  1. Nella pagina che si apre in modale inserire all'interno del tag head il seguente tag: <base target="_self" /> ;
  2. Effettuare il submit del form aperto in maniera modale via javascript utilizzando un tag anchor hidden nel form (<a href=”" id=”goLocation” style=”display:none;”> ).
Con il primo modo non mi ha funzionato, con il secondo invece si.
Quindi via javascript bisogna chiamare un metodo che imposti la proprietà href con l'action desiderata e quindi effettui il click.
Una cosa del tipo:

document.getElementById('goLocation').href = 'myAction.do?par1=x&par2=y';
document.getElementById('goLocation').click();

Si noti come  è necessario passare i parametri desiderati in querystring, per cui nel caso di form con molti campi ci sarà un lavoro pesante di javascript per settare i parametri corretti.

La mia paura a questo punto è stata quella di dover sostituire alla modalità standard di post del form sempre questa via tag anchor e javascript ma non è stato necessario, è bastato fare questa modifica solo nella pagina su cui si apre la finestra in modale, per il resto è rimasto tutto tale e quale.

martedì 12 marzo 2013

Verificare se ci sono errori nel contesto JSF

Per verificare la presenza di SEVERITY_ERROR nel contesto JSF ho usato questo metodo di utilità:


public static boolean isErrorInContext(){
  boolean retVal=false;
  List list=FacesContext.getCurrentInstance().getMessageList();
  for(FacesMessage m:list){
   if(m.getSeverity().equals(FacesMessage.SEVERITY_ERROR))
   {
    retVal=true;
    break;
   }
  }
  return retVal;
 }


Jquery disabilitare tasto backspace con filtro su campi testo

Con il seguente script jquery (testato su IE8 e firefox 19) è possibile fare in modo che sia disabilitato il tasto back space per tutti i componenti tranne che per le input type="text" (in questo caso infatti il backspace ci è utile per cancellare eventuali refusi ortografici):


 $(document).keydown(function(e) {
 if (e.keyCode == 8  && e.target!="[object HTMLInputElement]" ) {
   return false;
  };
           
        };
        
    });


giovedì 7 marzo 2013

Apache POI impostare pagina orizzontale

Con queste semplici istruzioni su apache po 3.9 è possibile impostare il foglio in modo che sia tutto presente su una pagina e impostato orizzontale .
La proprietà per l'impostazione pagina orizzontale è la setLandScape(true) sull'interfaccia org.apache.poi.ss.usermodel.PrintSetup

Esempio:


HSSFSheet sheet = wb.createSheet(nome);
sheet.setAutobreaks(true);
PrintSetup ps = sheet.getPrintSetup();
ps.setLandscape(true);
ps.setFitHeight((short)1);
ps.setFitWidth((short)1);


Sql Server select con WHEN e ALIAS

Ci sono due modi di utilizzo delle select con la clausola WHEN.
Si può scrivere qualcosa di questo tipo:

....,
case TIPO_SOGGETTO
WHEN 'PF' then 'Persona Fisica'
WHEN 'PG' then 'Persona Giuridica'
end ,
.....


In questo caso nella esecuzione dell'sql si avrà come intestazione di colonna proprio il campo TIPO_SOGGETTO.
Nel caso in cui si vogliano invece avere degli alias occorre modificare leggermente la sintassi.
Supponiamo ad esempio di applicare per due volte la stessa condizione vista sopra per esporre risultati  diversi,volendo evitare la ripetizione del nome colonna:

......,
case 
WHEN TIPO_SOGGETTO='PF' then 'Persona Fisica'
WHEN TIPO_SOGGETTO='PG' then 'Persona Giuridica'
end as TIPOLOGIA,
case 
WHEN TIPO_SOGGETTO='PF' then (LTRIM(RTRIM(s.nome))+ ' '+LTRIM(RTRIM(s.cognome))) 
WHEN TIPO_SOGGETTO='PG' then (LTRIM(RTRIM(s.denominazione))) 
end as DENOMINAZIONE_SOGGETTO ,
.......

martedì 5 marzo 2013

Jquery show hide div


Con Jquery sono disponibili due comode funzione che si occupano di realizzare lo show/hide dinamico di un div:
  • La funzione toggle;
  • La funzione slideToggle che da un effetto "slide" all'animazione.
Di seguito un esempio

Codice javascript



function toggleDiv(divId) {
   $("#"+divId).slideToggle("slow");
   var v=$("#linkGuida").text();
  
   if(v=="Guida on-line"){
    $("#linkGuida").html("Nascondi guida on-line");
    }
   else
    {
    $("#linkGuida").html("Guida on-line");
    }
}



Codice html


<br/>
<a href="javascript:toggleDiv('qwerty');"   ><span id="linkGuida">Guida on-line</span></a>
<br/>
<div id="qwerty" style="display:none">
<fieldset>
<legend>
Nomenclatura 
</legend>
<ul>
  <li><b>BOT:</b> Buono ordinario del tesoro</li>
  <li><b>BTP:</b> Buono del tesoro pluriennale</li>
  <li><b>CTZ:</b> Obbligazione del tipo Zero Coupon (solo maxicedola finale)</li>
</ul>
</fieldset>

</div>
 

Vediamo l'esempio all'opera (cliccare sul link 'Guida on line')

Guida on-line