giovedì 31 gennaio 2013

Taglib combo date

Ho avuto la necessità di realizzare una combo che date in input 2 date in formato gg/mm/aaaa (data inizio e data fine) mostrasse i dati nel formato MESE-AAAA (es. gennaio-2010...)ordinato dall'inizio alla fine e come valore AAAAMM concatenato.
La taglib è definita così (file tld)

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
  <taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>1.2</jsp-version>
  <short-name>c</short-name>
  <uri>http://gbresci.com</uri>
  <display-name>combo helper</display-name>
  <description>combo helper core library</description>
  <tag>
  <name>combo</name>
  <tag-class>it.gbresci.taglib.ComboDate</tag-class>
  <body-content>empty</body-content>
  <description>Gestione Combo</description>
  <attribute>
  <name>dataDa</name>
  <required>true</required>
  <rtexprvalue>true</rtexprvalue>
  </attribute>
   <attribute>
  <name>dataA</name>
  <required>true</required>
  <rtexprvalue>true</rtexprvalue>
  </attribute>
  <attribute>
  <name>primoVuoto</name>
  <required>false</required>
  <rtexprvalue>true</rtexprvalue>
  </attribute>
  <attribute>
  <name>id</name>
  <required>true</required>
  <rtexprvalue>true</rtexprvalue>
  </attribute>
  </tag>
  </taglib>



Il codice del Tag, che eredita da SimpleTagSupport, è il seguente:

package it.gbresci.taglib;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;

import java.io.IOException;
import java.util.*;

public class ComboDate extends SimpleTagSupport {
	private String id="";
	private String dataDa="";
	private String dataA="";
	private boolean primoVuoto=false;
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public boolean isPrimoVuoto() {
		return primoVuoto;
	}
	public void setPrimoVuoto(boolean primoVuoto) {
		this.primoVuoto = primoVuoto;
	}
	
	public String getDataDa() {
		return dataDa;
	}
	public void setDataDa(String dataDa) {
		this.dataDa = dataDa;
	}
	public String getDataA() {
		return dataA;
	}
	public void setDataA(String dataA) {
		this.dataA = dataA;
	}
	private boolean validate()
	{
		boolean retVal=true;
		if(this.dataDa!= null && this.dataDa.length()==10 
			&& this.dataA!=null && this.dataA.length()==10){
			try
			{
				Date data1=getDateFromString(dataDa);
				Date data2=getDateFromString(dataA);
				if(data2.getTime()<data1.getTime()){
					retVal=false;
				}
				
			}
			catch(Exception ex){
				//log
				retVal=false;
			}
		}
		return retVal;
	}
	public void doTag() throws JspException {

		PageContext pageContext = (PageContext) getJspContext();
		JspWriter out = pageContext.getOut();
		StringBuffer sb = new StringBuffer();
        if(validate()){
		try {
			
			sb.append("<select id=\"");
			sb.append(this.id);
			sb.append("\" name=\"");
			sb.append(this.id);
			sb.append("\"");
			sb.append(">");
			if(primoVuoto){
				sb.append("<option value=\"\"> </option>");
			}
			Map<String,String> myMap=getMappaValori();
			Set<String> chiavi=myMap.keySet();
			for(String s:chiavi){
				sb.append("<option value=\"");
				sb.append(s);
				sb.append("\">");
				sb.append(myMap.get(s));
				sb.append("</option>");
				
			}
			sb.append("</select>");
			out.println(sb.toString());

		} catch (Exception e) {
			e.printStackTrace();
		}
        }
        else
        {
        	try {
				out.println("<h1><b>Attenzione errore nel popolamanto controllo, controllare gli estremi delle date!!</b></h1>");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        }

	}
	private Map<String,String> getMappaValori(){
		Map<String,String> myMap=new LinkedHashMap<String, String>();
		Date dataDatag=getDateFromString(dataDa);
		Date dataAtag=getDateFromString(dataA);
		Date dataTempTag=dataDatag;
		do
		{
			myMap.put(getChiaveFromDate(dataTempTag), getValoreFromDate(dataTempTag));
			Calendar c=Calendar.getInstance();
			c.setTime(dataTempTag);
			c.add(Calendar.MONTH, 1);
			dataTempTag=c.getTime();
		}
		while(dataTempTag.getTime()<dataAtag.getTime());
		return myMap;
	}
	private Date getDateFromString(String d){
		Calendar c=Calendar.getInstance();
		String giorno=d.substring(0, 2);
		String mese=d.substring(3, 5);
		String anno=d.substring(6);
		c.set(Calendar.DAY_OF_MONTH,Integer.parseInt(giorno));
		c.set(Calendar.MONTH, Integer.parseInt(mese)-1);
		c.set(Calendar.YEAR, Integer.parseInt(anno));
		return c.getTime();
	}
	private String getChiaveFromDate(Date d){
		Calendar c=Calendar.getInstance();
		c.setTime(d);
		int anno=c.get(Calendar.YEAR);
		int mese=c.get(Calendar.MONTH)+1;
		StringBuffer sb=new StringBuffer();
		sb.append(anno);
		String mes=String.valueOf(mese);
		if(mes.length()==1){
			sb.append("0");
		}
		sb.append(mes);
		return sb.toString();
	}
	private String getValoreFromDate(Date d){
		Calendar c=Calendar.getInstance();
		c.setTime(d);
		int anno=c.get(Calendar.YEAR);
		int mese=c.get(Calendar.MONTH);
		StringBuffer sb=new StringBuffer();
		switch(mese){
		case 0:
			sb.append("GENNAIO-");
			break;
		case 1:
			sb.append("FEBBRAIO-");
			break;
		case 2:
			sb.append("MARZO-");
			break;
		case 3:
			sb.append("APRILE-");
			break;
		case 4:
			sb.append("MAGGIO-");
			break;
		case 5:
			sb.append("GIUGNO-");
			break;
		case 6:
			sb.append("LUGLIO-");
			break;
		case 7:
			sb.append("AGOSTO-");
			break;
		case 8:
			sb.append("SETTEMBRE-");
			break;
		case 9:
			sb.append("OTTOBRE-");
			break;
		case 10:
			sb.append("NOVEMBRE-");
			break;
		case 11:
			sb.append("DICEMBRE-");
			break;
		
			
		}
		sb.append(anno);
		return sb.toString();
	}

}



Sulla jsp avremo infine l'importazione e definizione della taglib:

<%@ taglib prefix="x" uri="http://gbresci.com" %>
......
Data Test: <x:combo dataA="31/12/2012" dataDa="01/01/2009" id="qwerty"/> 

Si ricorda che :
  • Il file .tld deve essere salvato dentro la directory WEB-INF;
  • Il campo URI definito nel tld deve essere uguale a quello definito sulla jsp e NON è necessario che punti ad una vera url, si tratta soltanto di un nome logico;
  • Settando nella taglib il valore RTEXPRVALUE a true si rende possibile inserire all'interno del campo sulla jsp anche del codice java che interpeti il valore a runtime.

lunedì 28 gennaio 2013

Tomcat 7 installato come servizio modificare heap size

Per modificare e/o monitorare la quantità di memoria allocata dal servizio sotto Windows si utilizza l'utility tomcat7w.exe in questo modo:
  1. Prendere nota del nome del servizio;
  2. Posizionarsi via shell sotto la directory bin;
  3. Digitare il comando tomcat7w.exe  //ES//[NOME_SERVIZIO].

Appare la seguente schermata:



Quindi selezionare il tab JAVA e modificare i valori minimi e massimi del pool di memoria


Per tenere sempre sotto monitoraggio il servizio ed accedervi successivamente sempre da shell digitiamo:

tomcat7w.exe  //MS//[NOME_SERVIZIO]

A questo punto accedendo al server in basso si potrà notare l'icona di Tomcat e con un semplice doppio click si riesce ad accedere al pannello di controllo del servizio sopra mostrato.

sabato 26 gennaio 2013

Calendario con visualizzazione solo dei mesi

Ho avuto questa richiesta da parte di un cliente.
Visualizzare una coppia di date (Data da e Data a) sotto forma di calendario con la possibilità di scegliere esclusivamente il mese.
Oltre a questo il requisito prevedeva anche di impostare per il campo Data da il primo giorno del mese mentre per il campo Data a la fine del mese.
Speravo e credevo di trovare molte librerie javascript che facessero al caso mio e invece ne ho trovata soltanto una, la

jQuery.mtz.monthpicker

  disponibile qui
Un grazie all'autore, Luciano Costa!!

La libreria si appoggia a jquery, ed importa i 3 seguenti js (tutte scaricabili dall'url sopra linkata):

  •  jquery.min.js (versione 1.7.2);
  • jquery-ui.min.js (versione 1.8.18);
  • jquery.mtz.monthpicker.js .

Occorre anche importare una libreria di css, il jqueri-ui css framework 1.8.18.

Ho dovuto soltanto modificare lievemente la libreria jquery.mtz.monthpicker.js , per aggiungere una validazione che scrivesse la data da e data a secondo quanto richiesto. La versione di default infatti si limita  a scrivere mm/aaaa, a me invece serviva la data per esteso.
Ho aggiunto la mia funzione (chiamata checkData()) di formattazione nel metodo della libreria associato al click sull'elemento del calendario.

container.find('.mtz-monthpicker-month').bind('click', function () {
             
                var m = parseInt($(this).data('month'));
                if ($.inArray(m, settings.disabledMonths) < 0 ) {
                    settings.selectedMonth = $(this).data('month');
                    settings.selectedMonthName = $(this).text();
                    monthpicker.trigger('monthpicker-click-month', $(this).data('month'));
                    checkData();
                }
            });


La funzione checkData è la seguente:

function checkData(){
     var dataDa=document.getElementById("dataDa").value;
     if(dataDa.length==7){
     var dataDaFormattata="01/"+dataDa.substring(0);
     document.getElementById("dataDa").value=dataDaFormattata;
     }
     else
     {
      document.getElementById("dataDa").value="01"+dataDa.substring(2);
     }
     var dataA=document.getElementById("dataA").value;
     var mese="01";
     var anno="0000";
    if (dataA.length == 7) {
   mese = dataA.substring(0, 2);
   anno = dataA.substring(3, 7);
  } else {
    mese=dataA.substring(3,5);
    anno=dataA.substring(6,10);
  }
     var giorno='01';
     if(mese=='04' || mese=='06' || mese=='09' || mese=='11'){
      
      giorno='30';
     }
     else if(mese=='02'){
      if(isleap(anno)==true){
       giorno='29';
      }
      else
       {
      giorno='28';
       }
     }
     else
      {
        giorno='31';
      }
     
     document.getElementById("dataA").value=giorno+"/"+mese+"/"+anno;
    }

    function isleap(year)
    {
     var yr=year;
     if ((parseInt(yr)%4) == 0)
     {
      if (parseInt(yr)%100 == 0)
      {
        if (parseInt(yr)%400 != 0)
        {
      
        return false;
        }
        if (parseInt(yr)%400 == 0)
        {
       
        return true;
        }
      }
      if (parseInt(yr)%100 != 0)
      {
      
        return true;
      }
     }
     if ((parseInt(yr)%4) != 0)
     {
       
        return false;
     } 
    }


Un'ultima particolarità è che le due date devono essere precaricate con un valore che gli arriva dalla sessione e quindi ogni data ha una sua lista di caricamento diversa.
Ecco la jsp:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Test sulle date</title>
  <script src='js/jquery.min.js'></script> 
    <script src='js/jquery-ui.min.js'></script>
    <script type="text/javascript" src="js/jquery.mtz.monthpicker.js"></script>
    <link rel='stylesheet' href='css/jquery-ui.css'>
</head>

  <style type="text/css">
      td.mtz-monthpicker-month {
        text-align:center;
      }
      select.mtz-monthpicker:focus {
        outline: none;
      }
    </style>
<body>
<%
   String dataDa=(String)request.getSession().getAttribute("DATA_DA");
   String dataA=(String)request.getSession().getAttribute("DATA_A");
%>
<table align="center">
<tr>
<td>
Data da:
</td>
<td>
<input id="dataDa" class="mtz-monthpicker-widgetcontainer" value="<%=dataDa %>" readonly="readonly" type="text">
<img border="0"  src="images/calendar.gif" onclick="javascript:document.getElementById('dataDa').focus();" >
</td>
<td>Data a: </td>
<td>
<input id="dataA" class="mtz-monthpicker-widgetcontainer" value="<%=dataA%>" readonly="readonly" type="text">
<img border="0"  src="images/calendar.gif" onclick="javascript:document.getElementById('dataA').focus();">
</td>
</tr>
</table>

<script>
optionsDa = {
    pattern: 'mm/yyyy', 
    selectedYear: <%=Integer.parseInt((String)request.getSession().getAttribute("ANNO_DA"))%>,
    startYear: 2008,
    finalYear: 2050,
    monthNames: ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic']
};
optionsA = {
     pattern: 'mm/yyyy', 
     selectedYear: <%=Integer.parseInt((String)request.getSession().getAttribute("ANNO_A"))%>,
     startYear: 2008,
     finalYear: 2050,
     monthNames: ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic']
 };
$('#dataDa').monthpicker(optionsDa);
$('#dataA').monthpicker(optionsA);
</script>
</body>
</html>


martedì 22 gennaio 2013

Display Table, decorator per singola colonna

Con Display Table è possibile creare una classe che faccia da decoratore a tutti i dati della collection rappresentata a video, ma in molti casi questa operazione risulta ripetitiva.
Un caso tipico è quello della formattazione di date, valute etc. che ci arrivano in formati diversi dal db.
In tali casi è possibile utilizzare dei decoratori sulle singole colonne, quindi si definisce una classe per la formattazione e in tutte le colonne in cui se ne ha bisogno si aggancia il decoratore.
Tale decoratore implementa l'interfaccia DisplaytagColumnDecorator, che dalla versione 1.1 sostituisce la precedente ColumnDecorator, ora deprecata.
Vediamo un esempio, ottenuto con la libreria display-tag-1.2.

La classe decoratore è definita così:


import javax.servlet.jsp.PageContext;
import org.displaytag.decorator.DisplaytagColumnDecorator;
import org.displaytag.exception.DecoratorException;
import org.displaytag.properties.MediaTypeEnum;
public class DateColumnDecorator implements DisplaytagColumnDecorator {
public Object decorate(Object colonna, PageContext arg1, MediaTypeEnum arg2)
   throws DecoratorException {
   StringBuffer sb=new StringBuffer();
   String data=(String)colonna;
   if(data !=null && data.length()==8){
   String anno=data.substring(0,4);
   String mese=data.substring(4, 6);
   String giorno=data.substring(6,8);
   sb.append(giorno);
   sb.append("/");
   sb.append(mese);
   sb.append("/");
   sb.append(anno);
   }
   else
   {
    sb.append(data);
   }
  return sb.toString();
 }
}


Lo scopo è quello di formattare date che arrivano nel formato AAAAMMGG in GG/MM/AAAA.

Il frammento di display table in cui si richiama il decoratore è il seguente:


<display:column property="dt_reg" title="Data Immissione Verifica"  decorator="org.gianos.form.decorator.DateColumnDecorator"  sortable="true"/>


sabato 19 gennaio 2013

Lettura di un WSDL

Gli elementi descrittivi di un wsdl sono contenuti all'interno del tag definitions.
Vediamoli applicati ad un semplice servizio Web che implementa un solo metodo , il classico hello world.
Di seguito l'estratto del codice Java di generazione del servizio:

@WebService(name="salutatore")
public class Ciao {
 @WebMethod(operationName="helloWorld")
 public String saluta(String nome){
 return "Ciao "+nome;
 }

}


Il WSDL generato è il seguente:

<?xml version='1.0' encoding='UTF-8'?><!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.7-b01  svn-revision#${svn.Last.Changed.Rev}. --><!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.7-b01  svn-revision#${svn.Last.Changed.Rev}. --><definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://ws.it/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://ws.it/" name="CiaoService">
<types>
<xsd:schema>
<xsd:import namespace="http://ws.it/" schemaLocation="http://localhost:8080/WsWebServiceTest/Ciao?xsd=1"/>
</xsd:schema>
</types>
<message name="helloWorld">
<part name="parameters" element="tns:helloWorld"/>
</message>
<message name="helloWorldResponse">
<part name="parameters" element="tns:helloWorldResponse"/>
</message>
<portType name="salutatore">
<operation name="helloWorld">
<input wsam:Action="http://ws.it/salutatore/helloWorldRequest" message="tns:helloWorld"/>
<output wsam:Action="http://ws.it/salutatore/helloWorldResponse" message="tns:helloWorldResponse"/>
</operation>
</portType>
<binding name="salutatorePortBinding" type="tns:salutatore">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="helloWorld">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="CiaoService">
<port name="salutatorePort" binding="tns:salutatorePortBinding">
<soap:address location="http://localhost:8080/WsWebServiceTest/Ciao"/>
</port>
</service>
</definitions>

Le sezioni di cui si compone sono le seguenti:

TYPES

Opzionale, definisce i tipi di dato utilizzati.
I dati possono essere tipi semplici (xsd:string etc.) oppure xsd .
La sezione types può contenere direttamente gli xsd oppure puntare ad xsd esterni.
In questo caso l'xsd è linkato:


<xsd:schema><xsd:import namespace="http://ws.it/" 
schemaLocation="http://localhost:8080/WsWebServiceTest/Ciao?xsd=1"/></xsd:schema>


Accedendo all'url si può vedere l'xsd del tipo dato utilizzato.

<?xml version='1.0' encoding='UTF-8'?><!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.7-b01  svn-revision#${svn.Last.Changed.Rev}. --><xs:schema xmlns:tns="http://ws.it/" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0" targetNamespace="http://ws.it/">
<xs:element name="helloWorld" type="tns:helloWorld"/>
<xs:element name="helloWorldResponse" type="tns:helloWorldResponse"/>
<xs:complexType name="helloWorld">
<xs:sequence>
<xs:element name="arg0" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="helloWorldResponse">
<xs:sequence>
<xs:element name="return" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>


MESSAGES

Sono associati ai tipi e rappresentano per così dire i parametri di ingresso e di uscita delle operazioni dei servizi web (che sono quindi 2, vedi xsd sopra definito).

<message name="helloWorld">
<part name="parameters" element="tns:helloWorld"/>
</message>
<message name="helloWorldResponse">
<part name="parameters" element="tns:helloWorldResponse"/>
</message>


PORTTYPE 

Il PortType rappresenta l'interfaccia del metodo richiamato, si noti come il nome del port type sia il name del servizio Web mentre nel nodo operation abbiamo il censimento dell'unica operazione ad esso associata, denominata helloworld.

BINDING

Questa sezione, sempre utilizzando una sintassi "javista" rappresenta l'implementazione del servizio o dei servizi definiti nella sezione PORTTYPE.
 In particolare fornisce informazioni su:
  • Il protocollo di trasporto utilizzato, che può essere di tipo HTTP o SMTP. Dall'attributo transport si evince in questo caso che il protocollo utilizzato è HTTP;
  • Lo style del servizio, che può essere di tipo RPC oppure DOCUMENT (document è il default);
  • Il formato dati utilizzato nel messaggio SOAP,  anche qui ci sono due possibilità, literal (come in questo caso, si tratta  puro e semplice xml) oppure encoded (messaggio xml conforme a regole esterne). Si noti che il  formato encoded non è WS-I compliant.
SERVICE

La sezione service direttamente l'endpoint dove è disponibile il servizio.
 

Accedere ad un parametro del web.xml in un Web Service

Dato un Web Service realizzato usando jax-ws 2.0 (vedi esempio qui) per accedere ad un parametro definito nel web.xml come un context-param si utilizza l'interfaccia javax.xml.ws.WebServiceContext.
Di seguito l'esempio di inejction sulla classe che implementa il Web Service:


@Resource
private WebServiceContext context;

Per accedere al parametro invece:

ServletContext ctx=(ServletContext)context.getMessageContext().get(MessageContext.SERVLET_CONTEXT);
String param=ctx.getInitParameter("STAGE");



venerdì 18 gennaio 2013

Primefaces 3.4.2 problemi con p:selectOneMenu

Sono incappato in un problema con la versione 3.4.2 del framework, al momento l'ultima release stabile.
Il problema si verifica quando , in una coppia di combo legate via ajax si seleziona la prima combo e parte l'evento di caricamento sulla seconda.
Se la selezione avviene dopo aver digitato un valore sulla combo l'evento onchange javascript non scatta, quindi il caricamento delle combo collegata non avviene.
Il bug è descritto nel forum di primefaces (http://forum.primefaces.org/viewtopic.php?f=3&t=28035&p=88388#p88388 ) e si risolve sostituendo alla versione 3.4.2 la versione 3.4.5 al momento in versione SNAPSHOT.
Per verificare il problema ho preso l'esempio dallo showcase di primefaces. Colgo l'occasione per postare il codice del progetto.

JAR

Sono sufficienti 2 soli jar
  • L'ultima versione di Mojarra (http://javaserverfaces.java.net/download.html), nel mio caso la 2.1.17;
  • L'ultima versione di PrimeFaces (http://www.primefaces.org/downloads.html), nel mio caso la 3.4.2
WEB.XML

Qui bisogna configurare la servlet di JSF + gli url pattern necessari. E' opzionale (ma è meglio farlo) inserire anche il parametro relativo all'environment (production,test, etc.) .
Di seguito l'estratto del web.xml


<servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.jsf</url-pattern>
  </servlet-mapping>
  <context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Production</param-value>
  </context-param>
 
Con JSF 2.0 èopzionale l'utilizzo del faces-config.xml, in quanto si possono usare le annotation sui bean.

Per il codice ho preso tutto dall'esempio di primefaces che si trova qui.

MANAGED BEAN


package it.showcase;
import java.io.Serializable;  
import java.util.HashMap;  
import java.util.Map;  
import javax.faces.application.FacesMessage;  
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;  
@ManagedBean(name="pprBean")
@ViewScoped
public class PPRBean implements Serializable {  
 private static final long serialVersionUID = 1L;

 private String city;  
  
    private String suburb;  
      
    private Map cities = new HashMap();  
  
    private Map> suburbsData = new HashMap>();  
      
    private Map suburbs = new HashMap();  
  
    public PPRBean() {  
        cities.put("Istanbul", "Istanbul");  
        cities.put("Ankara", "Ankara");  
        cities.put("Izmir", "Izmir");  
          
        Map suburbsIstanbul = new HashMap();  
        suburbsIstanbul.put("Kadikoy", "Kadikoy");  
        suburbsIstanbul.put("Levent", "Levent");  
        suburbsIstanbul.put("Cengelkoy", "Cengelkoy");  
          
        Map suburbsAnkara = new HashMap();  
        suburbsAnkara.put("Kecioren", "Kecioren");  
        suburbsAnkara.put("Cankaya", "Cankaya");  
        suburbsAnkara.put("Yenimahalle", "Yenimahalle");  
          
        Map suburbsIzmir = new HashMap();  
        suburbsIzmir.put("Cesme", "Cesme");  
        suburbsIzmir.put("Gumuldur", "Gumuldur");  
        suburbsIzmir.put("Foca", "Foca");  
          
        suburbsData.put("Istanbul", suburbsIstanbul);  
        suburbsData.put("Ankara", suburbsAnkara);  
        suburbsData.put("Izmir", suburbsIzmir);  
    }  
      
    public String getCity() {  
        return city;  
    }  
  
    public void setCity(String city) {  
        this.city = city;  
    }  
  
    public String getSuburb() {  
        return suburb;  
    }  
  
    public void setSuburb(String suburb) {  
        this.suburb = suburb;  
    }  
  
    public Map getCities() {  
        return cities;  
    }  
  
    public void setCities(Map cities) {  
        this.cities = cities;  
    }  
      
    public Map> getSuburbsData() {  
        return suburbsData;  
    }  
  
    public void setSuburbsData(Map> suburbsData) {  
        this.suburbsData = suburbsData;  
    }  
      
    public Map getSuburbs() {  
        return suburbs;  
    }  
  
    public void setSuburbs(Map suburbs) {  
        this.suburbs = suburbs;  
    }  
      
    public void handleCityChange() {  
        if(city !=null && !city.equals(""))  
            suburbs = suburbsData.get(city);  
        else  
            suburbs = new HashMap();  
    }  
  
    public void displayLocation() {  
        FacesMessage msg = new FacesMessage("Selected", "City:" + city + ", Suburb: " + suburb);  
  
        FacesContext.getCurrentInstance().addMessage(null, msg);  
    }  
}  


La pagina xhtml è la seguente:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"  
    xmlns:h="http://java.sun.com/jsf/html"  
    xmlns:f="http://java.sun.com/jsf/core"  
    xmlns:p="http://primefaces.org/ui"
    xmlns:ui="http://java.sun.com/jsf/facelets">  
   <h:head>
   </h:head>
<h:body> 
    <h:form id="form">  
      
        <p:growl id="msgs" showDetail="true"/>  
                      
        <p:panel header="Double Combo" style="margin-bottom:10px;">  
            <h:panelGrid columns="2" cellpadding="5">  
                <p:selectOneMenu id="city" value="#{pprBean.city}">  
                    <f:selectItem itemLabel="Select City" itemValue="" />  
                    <f:selectItems value="#{pprBean.cities}" />  
                    <p:ajax update="suburbs"  
                            listener="#{pprBean.handleCityChange}" />  
                </p:selectOneMenu>  
      
                <p:selectOneMenu id="suburbs" value="#{pprBean.suburb}">  
                    <f:selectItem itemLabel="Select Suburb" itemValue="" />  
                    <f:selectItems value="#{pprBean.suburbs}" />  
                </p:selectOneMenu>  
                
                <h:selectOneMenu id="city2" value="#{pprBean.city}">  
                    <f:selectItem itemLabel="Select City" itemValue="" />  
                    <f:selectItems value="#{pprBean.cities}" />  
                    <p:ajax update="suburbs2"  
                            listener="#{pprBean.handleCityChange}" />  
                </h:selectOneMenu>  
      
                <p:selectOneMenu id="suburbs2" value="#{pprBean.suburb}">  
                    <f:selectItem itemLabel="Select Suburb" itemValue="" />  
                    <f:selectItems value="#{pprBean.suburbs}" />  
                </p:selectOneMenu>  
                
                
            </h:panelGrid>  
      
            <p:separator />  
              
            <p:commandButton value="Submit" update="msgs" actionListener="#{pprBean.displayLocation}" id="btnSubmit"/>  
      
        </p:panel>  
      
    </h:form>  
</h:body>
</html>


Si noti che ho inserito oltre alle 2 combo base dell'esempio un'altra coppia sostituendo il componente jsf standard (h:selectOneMenu invece di p:selectOneMenu).
In questo modo si può verificare l'errato comportamento del p:selectOneMenu.
Se si accede alla pagina, si scrive ad esempio la lettera I nella combo e poi si seleziona Istanbul la combo"Suburb" non viene popolata.
Se si effettua lo stesso test nella coppia di combo sottostanti invece funziona correttamente.
Inserendo la versione 3.5 SNAPSHOT di PrimeFaces tutto funziona correttamente.

venerdì 11 gennaio 2013

Conoscere il prossimo contatore identity inserito

Con Sql Server per conoscere il prossimo id che verrà generato nel caso dei campi identity occorre eseguire la seguente query:

SELECT IDENT_CURRENT ('NOME_TABELLA')+ IDENT_INCR('NOME_TABELLA')


N.B.: non usare mai la select max(id) +1 from tabella in quanto nel caso di campi identity potrebbero esserci dei buchi nella numerazione (dovuti ad esempio a delle delete) o la tabella potrebbe essere stata definita con un passo di incremento >1. Da qui la necessità di usare l'accoppiata IDENT_CURRENT e IDENT_INCR