mercoledì 19 dicembre 2012

Caricare combo da HashMap con JSF 2.0

Per caricare una combo in un componente JSF si possono seguire varie strade.
In questo post vediamo come caricarla a partire da un HashMap.
Di seguito il codice del managed bean:


package org.primefaces.examples.domain;
import java.util.HashMap;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
@ManagedBean(name="myBean")
@ViewScoped
public class CaricaTest {
private Map<String,String> lista=null;
public Map<String, String> getLista() {
 return lista;
}
public void setLista(Map<String, String> lista) {
 this.lista = lista;
}
public CaricaTest(){
 lista=new HashMap<String, String>();
 lista.put("01", "Primo valore");
 lista.put("02", "Secondo valore");
 lista.put("03", "Terzo valore");
}
private String valore;

public String getValore() {
 return valore;
}

public void setValore(String valore) {
 this.valore = valore;
}

}

Adesso vediamo il codice dell'xhtml

<?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">  
<h:outputText value="Lista: " />  
    <h:selectOneMenu value="myBean.valore">
      <f:selectItems value="#{myBean.lista}" />  
    </h:selectOneMenu>
  </h:form>
</h:body>
</html>

Così facendo però abbiamo un comportamento all'apparenza strano.
A video infatti apparirà la seguente schermata:


Guardando al codice HTML generato vediamo che sono "invertiti" chiave e valore della mappa.
Il comportamento è infatti quello di base del componente, voluto così proprio da specifica.
 La logica è che si preferisce  evitare di far vedere all'utente duplicati nel valore mostrato a video e quindi la key della mappa diventa  la descrizione nella combo e viceversa.
Per impostare la visualizzazione che vogliamo occorre modificare il componente f::selectItems  in questo modo:


<f:selectItems  value="#{myBean.lista.entrySet()}" var="entry" 
     itemValue="#{entry.key}" itemLabel="#{entry.value}" 
     itemDescription="#{entry.value}" />  

In questo modo abbiamo il risultato desiderato (si noti che itemDescription è il tooltip del valore):

lunedì 17 dicembre 2012

Generare xsd da xml

Per effettuare questa operazione è possibile utilizzare svariate utility, una delle più comode è TRANG.
Accedendo al link http://www.thaiopensource.com/download/ bisogna scegliere il link evidenziato nella immagine sottostante:
A questo punto bisogna:
  1. Scompattare il contenuto in una directory del file system;
  2. Copiare in questa directory l'xml dal quale vogliamo ottenere l'xsd;
  3. Da shell digitare il comando java -jar trang.jar xmlFile.xml xmlFile.xsd.



giovedì 13 dicembre 2012

Differenza tra ClassNotFoundException e NoClassDefFoundError

Le due eccezioni sono concettualmente simili (manca qualche jar o .class nel classpath) ma è diversa la tipologia di eccezione, la ClassNotFoundException è di tipo checked (che estende dunque da java.lang.Exception e che ha bisogno del try/catch) mentre la NoClassDefFoundError è di tipo Error , quindi unchecked

java.lang.ClassNotFoundException

L' eccezione ClassNotFoundException si verifica quando una applicazione tenta di chiamare una classe utilizzando :

  • Il metodo forName nella classe Class.
  • Il metodo findSystemClass nella classe  ClassLoader .
  • Il metodo loadClass nella classe ClassLoader
Esempio classico:


public static void main(String[] args) throws Exception{
  Class c=Class.forName("classenonEsistente");
  System.out.println(c.getName());
 }


Tale codice produce il seguente risultato:

Exception in thread "main" java.lang.ClassNotFoundException: classenonEsistente
 at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
 at java.lang.Class.forName0(Native Method)
 at java.lang.Class.forName(Class.java:169)
 at ExceptionSample.main(ExceptionSample.java:5)



java.lang.NoClassDefException

Questa eccezione è sollevata dalla JVM quando cerca di caricare una classe a runtime e non la trova.
E' una sottoclasse di java.lang.LinkageError, il problema è che la classe che stiamo chiamando ne utilizza un'altra a runtime non presente.
Il classico esempio si ha quando proviamo ad invocare da console una classe java dimenticandoci il nome completo del package (il classico Hello World che all'inizio non funziona mai).
Esempio:
Supponiamo di utilizzare la libreria jmimemagic (descritta in un precedente post) e di usarla dimenticandoci di aggiungere al classpath la libreria commons-logging.jar.
Il codice compila correttamente, in quanto la nostra classe richiama esclusivamente la classe MagicMatcher che fa parte della libreria jmimemagic e che è inclusa nel classpath.

A  Runtime abbiamo una NoClassDefException .


public static void main(String[] args)  {
  try
  {
  Magic m=new Magic();
  byte[] lb=FileUtil.load(new File("file/WS.png"));
  MagicMatch match = m.getMagicMatch(lb);
  System.out.println(match.getMimeType());
  }
  catch (Exception e) {
   System.out.println("Eccezione!!!");
   e.printStackTrace();
  }
 }


Eseguendo il codice non si passa per il catch (si ricordi che l'eccezione è sottoclasse di LinkageError e quindi di Throwable, non di Exception) e in console sarà stampata direttamente la NoClassDefException, nel cui stacktrace troviamo anche l'origine dell'errore, che è una eccezione di tipo ClassNotFoundException per l'appunto.

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
 at net.sf.jmimemagic.Magic.(Magic.java:46)
 at MatchMagic.main(MatchMagic.java:21)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory
 at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
 ... 2 more


mercoledì 12 dicembre 2012

Itext per generare tabella rtf

In questo esempio vediamo come generare un RTF con IText in cui posizioniamo una tabella generata dinamicamente, passando al metodo di creazione :
  • un array di Stringhe che rappresentano gli header di colonne;
  • una lista di Stringhe che rappresentano i valori , e che devono essere un multiplo della size dell'array di header, esempio con 4 colonne di intestazione per avere 2 righe la size di questa lista deve essere di 8.
Il vantaggio di avere questa tabella è che Itext (a differenza di Jasper Report o meglio del Jasper report che ho usato io qualche anno fa, non so le ultime versioni) genera tabelle facilmente modificabili, mentre Jasper mette dei place holders tipo caselle di testo che rendono molto difficoltoso modificare il file.

Sotto posto il codice:

package chart.example;
import java.awt.Color;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import com.lowagie.text.Cell;
import com.lowagie.text.Document;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Table;
import com.lowagie.text.rtf.RtfWriter2;

public class TableCreator {
 
 public static void main(String[] args) throws Exception
 {
  FileOutputStream fos = new FileOutputStream("file/executive_summary.rtf");
  Document d=new Document();
  RtfWriter2.getInstance(d, fos );
     d.open();
     String[] lista=new String[]{"Lunedi","Martedi","Mercoledi","Giovedi"};
     List<String> valTot=new ArrayList<String>();
     valTot.add("12");
     valTot.add("15");
     valTot.add("16");
     valTot.add("98");
     valTot.add("12");
     valTot.add("15");
     valTot.add("16");
     valTot.add("98");
     valTot.add("dsfddsdsf");
     valTot.add("baiaffa");
     valTot.add("16");
     valTot.add("98");
     valTot.add("ssssss");
     valTot.add("baiaffone");
     valTot.add("13");
     valTot.add("983");
     valTot.add("dsdsdsdsds");
     valTot.add("baiaffone");
     valTot.add("13");
     valTot.add("983");
     d.add(getSimpleTable(lista, valTot));
     d.close();
    
 }
 
 public static int myFontStyle = Font.UNDEFINED;
 public static Font baseFont = new Font ( myFontStyle, 12, Font.NORMAL );
 public static Font baseFontTabelleHeader=new Font ( myFontStyle, 10, Font.NORMAL );
 public static Table getSimpleTable( String[] header_cells, List<String> column_cells ) throws Exception
 {
  Table table = new Table( header_cells.length );
        if(column_cells.size()%header_cells.length!=0){
        throw new IllegalArgumentException("Attenzione il numero di valori " +
           "deve essere un multiplo del numero di colonne, " +
           "quindi di "+header_cells.length+" " +
             "il valore risulta invece "+column_cells.size());
        }
  table.setBorderWidth(1);
  table.setPadding(2);
        table.setSpacing(0);

        for ( int i = 0 ; i < header_cells.length ; i++ )
        {
         table.addCell( getHeaderCell( header_cells[i], baseFontTabelleHeader ) );
        }
       
        for ( int i = 0 ; i < column_cells.size() ;  )
        {
         for(int k=0;k<header_cells.length;k++){
          table.addCell( getCell( column_cells.get(i), baseFont ) );
          i++;
         }
        }

  return table;
 }

 public static Cell getHeaderCell( String text, Font font ) throws Exception
 {
  Font f = new Font( font );
  f.setStyle(Font.BOLD);
  Cell cell = new Cell( new Paragraph( text, f ) );
        cell.setHeader(true);
        cell.setBackgroundColor( new Color(0xE1E1E1) );
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        return cell;
 }

 public static Cell getCell( String text, Font font ) throws Exception
 {
  Cell cell = new Cell( new Paragraph( text, font ) );
  cell.setHeader(false);
        cell.setHorizontalAlignment(Element.ALIGN_LEFT);
        return cell;
 }

 public static Cell getCenteredCell( String text, Font font ) throws Exception
 {
  Cell cell = new Cell( new Paragraph( text, font ) );
  cell.setHeader(false);
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        return cell;
 }
}



sabato 8 dicembre 2012

JFreeChart, esempi realizzazione grafici

In questo posto vediamo come generare 4 tipologie di grafici con JFreeChart, in particolare:

  • Tachimetro (grafico a lancetta);
  • Torta;
  • Istogramma semplice;
  • Istogramma multiplo.
Ho creato un semplice Java Project includendo le seguenti librerie nel classpath:

  • jfreechart-1.0.9.jar;
  • jcommon-1.0.12.jar;
  • iText-2.0.8.jar.
Di seguito incollo la classe main principale, con dei metodi statici che generano delle immagini png per ciascun tipo grafico definito:


package chart.example;
import java.awt.BasicStroke;
import java.awt.Color;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.labels.PieSectionLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.DialShape;
import org.jfree.chart.plot.MeterInterval;
import org.jfree.chart.plot.MeterPlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.Range;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.DefaultValueDataset;
import org.jfree.ui.TextAnchor;
import com.lowagie.text.Font;
public class ChartCreator {
 public static int myFontStyle = Font.UNDEFINED;
 public static Font baseFont = new Font ( myFontStyle, 12, Font.NORMAL );
 public static void main(String[] args) throws Exception {
   creaGraficoATorta();
        creaIstogrammaMultiplo();
        creaTachimetro();
        creaIstogrammaSemplice();
 }
 private static void creaGraficoATorta() throws Exception{
  OutputStream fos=new FileOutputStream(new File("out/torta.png"));
  String[] componenti=new String[]{"Inter","Milan","Rubentus"};
  double[] valori=new double[]{18.0,18.0,28.0};
  JFreeChart chart=creaGraficoATorta(componenti, valori, false);
  ChartUtilities.writeChartAsPNG(fos, chart, 500, 300);
 }
 private static void creaIstogrammaMultiplo() throws Exception{
  OutputStream fos=new FileOutputStream(new File("out/istoMul.png"));
  double[] valori=new double[9];
  valori[0]=20.0;
  valori[1]=65.0;
  valori[2]=15.0;
  valori[3]=30.0;
  valori[4]=50.0;
  valori[5]=20.0;
  valori[6]=25.0;
  valori[7]=60.0;
  valori[8]=15.0;
  String[] componenti=new String[3];
  componenti[0]="Lazio";
  componenti[1]="Lombardia";
  componenti[2]="Toscana";
  String[] sottocomponenti=new String[3];
  sottocomponenti[0]="Ricchi";
  sottocomponenti[1]="Classe Media";
  sottocomponenti[2]="Poveri";
  JFreeChart chart=creaIstogramma(componenti,sottocomponenti, valori, "Ripartizione classi sociali", "Regioni", "Percentuali");
   ChartUtilities.writeChartAsPNG(fos, chart, 500, 300);
 }
 
 private static void creaIstogrammaSemplice() throws Exception
 {
  OutputStream fos=new FileOutputStream(new File("out/isto.png"));
  String[] componenti=new String[]{"Alto","Medio","Basso"};
  double[] valori=new double[]{85.5,75.12,45.56};
  JFreeChart chart=creaIstogramma(componenti, valori, "Andamenti", "", "");
  ChartUtilities.writeChartAsPNG(fos, chart, 500, 300);
 }
 private static void creaTachimetro() throws Exception{
  OutputStream fos=new FileOutputStream(new File("out/tachimetro.png"));
  BigDecimal a=new BigDecimal(37.0);
  BigDecimal b=new BigDecimal(49.0);
  BigDecimal res=a.divide(b,2,RoundingMode.HALF_UP);
  double v=res.doubleValue()*(double)100;
  JFreeChart chart=creaTachimetro(new Double(v), "Esempio", "", Color.WHITE);
  ChartUtilities.writeChartAsPNG(fos, chart, 500, 300);
 }

 public static JFreeChart creaTachimetro(Double valore, String titolo, String sottotitolo, Color bgcolor)
 {
  DefaultValueDataset ds = new DefaultValueDataset();
  ds.setValue(valore);
  MeterPlot plot = new MeterPlot(ds);
  plot.setUnits("%");
  plot.setRange(new Range(0, 100));
  plot.setMeterAngle(210);
  plot.addInterval(new MeterInterval("Intervallo1", new Range(90.0, 100.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(255, 0, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo2", new Range(80.0, 90.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(255, 51, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo3", new Range(70.0, 80.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(255, 102, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo4", new Range(60.0, 70.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(255, 153, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo5", new Range(50.0, 60.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(255, 204, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo6", new Range(40.0, 50.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(255, 255, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo7", new Range(30.0, 40.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(192, 255, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo8", new Range(20.0, 30.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(128, 255, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo9", new Range(10.0, 20.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(64, 255, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo10", new Range(0.0, 10.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(0, 255, 0, 200)));
  plot.setBackgroundPaint(bgcolor);
  plot.setNeedlePaint(Color.BLACK);
  plot.setDialBackgroundPaint(bgcolor);
  plot.setDialOutlinePaint(bgcolor);
  plot.setDialShape(DialShape.CIRCLE);
  plot.setTickLabelsVisible(false);
  plot.setTickSize(100.0);
  plot.setTickPaint(Color.GRAY);
  plot.setValueFont(new java.awt.Font("Dialog", Font.BOLD, 14));
  plot.setValuePaint(Color.BLACK);
  JFreeChart chart = new JFreeChart(null, null, plot, false);
  chart.setBackgroundPaint(bgcolor);
  if (!titolo.equals("")) {
   TextTitle title = new TextTitle(titolo);
   title.setFont(new java.awt.Font("Verdana", Font.BOLD, 12));
   title.setPaint(new Color(0x2684B3));
   chart.setTitle(title);
  }
  if (!sottotitolo.equals("")) {
   TextTitle subtitle = new TextTitle(sottotitolo);
   subtitle.setFont(new java.awt.Font("Verdana", java.awt.Font.ITALIC, 11));
   subtitle.setPaint(new Color(0x2684B3));
   chart.addSubtitle(subtitle);
  }
  return chart;
 }
 public static JFreeChart creaIstogramma(String[] componenti,String[] sottocomponenti,double[] valori,String titolo,String ascissa,String ordinata){
  DefaultCategoryDataset cds=new DefaultCategoryDataset();
  int j=0;
  int cambioComponente=sottocomponenti.length;
  String comp=componenti[j];
  int sottoComp=0;
        for(int i=0;i 1) {
   for (int i = 0; i < componenti.length; i++) {
    renderer.setSeriesItemLabelsVisible(i, true);
    renderer.setSeriesItemLabelGenerator(i, new SeriesLabelGenerator());
   }
  } else {
   renderer.setSeriesItemLabelsVisible(0, true);
   renderer.setSeriesItemLabelGenerator(0, new LabelGenerator(null));
  }
      return chart;
 }
 public static JFreeChart creaIstogramma(String[] componenti,double[] valori,String titolo,String ascissa,String ordinata){
  DefaultCategoryDataset cds=new DefaultCategoryDataset();
        for(int i=0;i

Nel codice sono utilizzate due classi (LabelGenerator e SeriesLabelGenerator) che servono a mostrare nei grafici a torta e a istogramma semplice (LabelGenerator) e nel grafico a istogramma multiplo (SeriesLabelGenerator) i valori con le percentuali.

LabelGenerator


package chart.example;
import java.text.NumberFormat;
import org.jfree.chart.labels.AbstractCategoryItemLabelGenerator;
import org.jfree.chart.labels.CategoryItemLabelGenerator;
import org.jfree.data.category.CategoryDataset;
public class LabelGenerator extends AbstractCategoryItemLabelGenerator implements CategoryItemLabelGenerator {

 private static final long serialVersionUID = 7389531138610633787L;
 private Integer category;
 private NumberFormat formatter = NumberFormat.getPercentInstance();
 public LabelGenerator(int category) {
  this(new Integer(category));
 }
 public LabelGenerator(Integer category) {
  super("", NumberFormat.getInstance());
 this.category = category;
 }
 public String generateLabel(CategoryDataset dataset, int series, int category ) {
  String result = null;
  double base = 0.0;
  if (this.category != null) {
   final Number b = dataset.getValue(series, this.category.intValue());
   base = b.doubleValue();
  }
  else {
   base = calculateSeriesTotal(dataset, series);
  }
  Number value = dataset.getValue(series, category);
  if (value != null) {
   final double v = value.doubleValue();
   //  you could apply some formatting here
   result = "     "+ value.toString() + " (" + this.formatter.format(v / base) + ")";
  }
  return result;
 }
 private double calculateSeriesTotal(CategoryDataset dataset, int series) {
  double result = 0.0;
  for (int i = 0; i < dataset.getColumnCount(); i++) {
   Number value = dataset.getValue(series, i);
   if (value != null) {
    result = result + value.doubleValue();
    }
  }
  return result;
 }
}



SeriesLabelGenerator



package chart.example;
import java.text.NumberFormat;
import org.jfree.chart.labels.AbstractCategoryItemLabelGenerator;
import org.jfree.chart.labels.CategoryItemLabelGenerator;
import org.jfree.data.category.CategoryDataset;
public class SeriesLabelGenerator extends AbstractCategoryItemLabelGenerator implements CategoryItemLabelGenerator {
 private static final long serialVersionUID = 7389531138610633787L;
 private NumberFormat formatter = NumberFormat.getPercentInstance();
 public SeriesLabelGenerator() {
  super("", NumberFormat.getInstance());
 }
 public String generateLabel(CategoryDataset dataset, int series, int category ) {
  String result = null;
  double base = 0.0;
  base = calculateCategoryTotal(dataset, category);
  Number value = dataset.getValue(series, category);
  if (value != null) {
   final double v = value.doubleValue();
   result = "     "+ value.toString() + " (" + this.formatter.format(v / base) + ")";
  }
  return result;
 }
 private double calculateCategoryTotal(CategoryDataset dataset, int category) {
  double result = 0.0;
  for (int i = 0; i < dataset.getRowCount(); i++) {
   Number value = dataset.getValue(i,category);
   if (value != null) {
    result = result + value.doubleValue();
    }
  }
  return result;
 }
}



Il risultato del codice è la generazione delle seguenti immagini:

Torta





Istogramma semplice


Istogramma multiplo


Grafico a lancetta




martedì 4 dicembre 2012

Calcolare il giorno della settimana di un determinato anno

Si può applicare questa formula per calcolare il giorno della settimana dalla data:

x = N + (q)(N - 1) : 4 - (q)(N - 1) : 100 + (q)(N - 1) : 400 + t

Dove
N = anno corrente
q =  resto della divisione
t =  numero giorni trascorsi dall'inizio dell'anno in questione alla data presa in considerazione

Questa formula vale per qualsiasi data successiva al 15/10/1582.
Sotto una veloce implementazione in una classe Java:


import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
public class GetGiornoSettimana {

	/**
	 * x = N + (q)(N - 1) : 4 - (q)(N - 1) : 100 + (q)(N - 1) : 400 + t
	 * @param args
	 */
	public static void main(String[] args) {
		GetGiornoSettimana g=new GetGiornoSettimana();
		System.out.println(g.getGiornoSettimana(new Date()));
        System.out.println(g.getGiornoSettimana(20, 4, 1978));
       
	}
	private boolean isLeapYear(int anno){
		GregorianCalendar gc=new GregorianCalendar();
		return gc.isLeapYear(anno);
	}
	public String getGiornoSettimana(int giorno,int mese,int anno){
		return getGiornoSettimana(creaData(giorno, mese, anno));
	}
    public  String getGiornoSettimana(Date data){
    	String retVal="";
    	int anno=getAnnoDaData(data);
    	int val1=anno+getPrimoElemento(anno);
    	int giorniTrascorsi=getGiorniFromInizioAnno(data);
    	int r=val1+giorniTrascorsi;
    	int resto=r%7;
    	switch(resto){
    	case 0:
    		retVal="sabato";
    		break;
    	case 1:
    		retVal="domenica";
    		break;
    	case 2:
    		retVal="lunedi";
    		break;
    	case 3:
    		retVal="martedi";
    		break;
    	case 4:
    		retVal="mercoledi";
    		break;
    	case 5:
    		retVal="giovedi";
    		break;
    	case 6:
    		retVal="venerdi";
    		break;
    		
    	}
    	return retVal;
    }
    private int getPrimoElemento(int anno){
    	return getElemento(anno-1, 4)-getElemento(anno-1, 100)+getElemento(anno-1, 400);
    }
    private int getElemento(int anno,int div){
    	int r=(int)Math.floor((double)anno/(double)div);
    	System.out.println(r);
    	return r;
    }
    private int getGiorniFromInizioAnno(Date d){
    	int anno=getAnnoDaData(d);
    	boolean bisestile=isLeapYear(anno)?true:false;
    	int retVal=0;
    	int mese=getMeseDaData(d);
    	int giorno=getGiornoDaData(d);
    	for(int i=1;i<mese;i++){
    		switch(i){
    		case 2:
    			retVal+=bisestile?29:28;
    		 break;
    		case 4:
    		case 6:
    		case 9:
    		case 11:
    			retVal+=30;
    		 break;
    		default:
    			retVal+=31;
    		 break;
    		}
    	}
    	retVal+=giorno;
    	return retVal;
    }
    private int getAnnoDaData(Date data){
    	Calendar c=Calendar.getInstance();
    	c.setTime(data);
    	return c.get(Calendar.YEAR);
    }
    private int getMeseDaData(Date data){
    	Calendar c=Calendar.getInstance();
    	c.setTime(data);
    	return c.get(Calendar.MONTH)+1;
    }
    private int getGiornoDaData(Date data){
    	Calendar c=Calendar.getInstance();
    	c.setTime(data);
    	return c.get(Calendar.DAY_OF_MONTH);
    }
    private Date creaData(int giorno,int mese,int anno){
        Calendar c=Calendar.getInstance();
        c.set(Calendar.YEAR, anno);
        c.set(Calendar.MONTH, mese-1);
        c.set(Calendar.DAY_OF_MONTH, giorno);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    } 
   
}




domenica 2 dicembre 2012

JSF 2.0 bean validation con Tomcat

Con il meccanismo di tipo bean validation è possibile, senza specificare per ogni campo la tipologia di validazione necessaria, magari richiamando un metodo del managed bean ogni volta, definire una tipologia generica di validazione a livello di managed bean con una annotazione customizzata, in modo che i metodi di validazione siano richiamati ogni volta che si effettua la validazione del managed bean.
Poichè Tomcat non ha nelle sue librerie quelle del package javax.validation.* occorre per prima cosa scaricare i jar corretti e metterli nella lib del progetto Web.
Ho scaricato l'implementazione hibernate validator 4.3.1 dal sito.
Attenzione, non basta scaricare soltanto la libreria della jsr validation-api-1.0.0.jar, questa infatti è solo un'interfaccia, e peraltro per qualche strano motivo che non ho capito se si inserisce nel classpath soltanto la libreria della JSR non si incappa in nessun errore, ma semplicemente i validatori posti come annotation a livello di managed bean sono ignorati.
Le librerie nella lib del progetto sono quindi le seguenti:
  • hibernate-validator-4.3.1.Final.jar;
  • hibernate-validator-annotation-processor-4.3.1.Final.jar;
  • jboss-logging-3.1.0.CR2.jar;
  • validation-api-1.0.0.GA.jar.
Oltre all'implementazione di JSF 2.0 (ho usato Mojarra):

  • javax.faces-2.1.14.jar;
  • jstl-1.2.jar.

Ho inserito il seguente validatore per il campo tipo mail:



package com.jsfcompref.annotation;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class EmailConstraintValidator implements ConstraintValidator {
 private static final String EMAIL_PATTERN = 
  "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@"
  + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
 @Override
 public void initialize(Email parameters) {
  // TODO Auto-generated method stub
  
 }

 @Override
 public boolean isValid(String value, ConstraintValidatorContext arg1) {
  Pattern pattern = Pattern.compile(EMAIL_PATTERN);
  Matcher matcher=pattern.matcher(value);
  return matcher.matches();
 }

}
L'annotation chiamata Email è così definita:

package com.jsfcompref.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.*;
import javax.validation.Constraint;
@Documented
@Constraint(validatedBy=EmailConstraintValidator.class)
@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Email {
String message() default "{validator.email})";
Class[] groups() default{};
Class[] payload() default{};
}


Quindi basta annotare il managed bean in questo modo:

.....

@Email(message="Attenzione email non valida")
 private String email;
// getter e setter
E poi sulla facelet definire semplicemente il campo mail così:

<h:inputText label="Email" id="email" value="#{userBean.email}" required="true"/>


Nel caso di errori nel campo mail comparirà quindi il messaggio specificato nell'annotation (di default cerca il messaggio nel file di properties).

venerdì 30 novembre 2012

Display tag decorator export e autosize colonne excel

Visualizzando una lista avevo 2 necessità:

  1. Decodificare dei valori in visualizzazione (es. a fronte di alcuni codici dare la relativa descrizione);
  2. Esportare questi valori in excel in modo da avere le colonne excel già adattate alla descrizione, senza doverlo fare a mano.
Per il punto 1 sono ricorso ad un decorator, solo che nell'export excel ancora avevo il campo codice invece della descrizione.
Infatti nella tabella bisogna specificare questo:

<display:setproperty name="decorator.media.excel" value="org.decorator.MyDecorator">



In modo da forzare ad utilizzare il decorator anche nell'export, quindi non basta definirlo soltanto a livello di tabella con l'attributo decorator.

Per quanto riguarda invece il punto 2 nel file displaytable.properties occorre dichiarare la seguente proprietà:



export.excel.class=org.displaytag.export.excel.ExcelHssfView

In questo modo tale modifica vale per tutte le tabelle dell'applicazione.
Per fare questa modifica premetto che occorre avere la versione 1.2 della libreria assieme al displaytag-export-poi-1.2.jar.
Nel mio caso poi, avendo l'applicazione la libreria POI-3.5 a Runtime avevo un errore di questo tipo:


java.lang.NoSuchMethodError: org.apache.poi.hssf.usermodel.HSSFRow.createCell(I)Lorg/apache/poi/hssf/usermodel

Evidentemente serviva una versione più recente della libreria ma essendo questa utilizzata in altri modi nell'applicazione ho deciso di ridefinirmi l'exporter nel file displaytag.properties facendolo puntare ad una mia classe.
Quindi ho decompilato la classe ExcelHssfView (che si trova dentro displaytag-export-poi-1.2.jar) e corretto manualmente gli errori trovati.
In particolare nel metodo doExport ho dovuto fare questa modifica:


                HSSFCellStyle headerStyle = wb.createCellStyle();
         headerStyle.setFillPattern((short)2);
         headerStyle.setFillBackgroundColor((short)54);
         HSSFFont bold = wb.createFont();
         bold.setBoldweight((short)700);
         bold.setColor((short)9);
         headerStyle.setFont(bold);

Inserendo il cast a short per i valori numerici.
Mentre invece nel costruttore della classe statica  ExcelGenerationException ho dovuto commentare il costruttore:


super(Messages.getString("ExcelView.errorexporting"), cause);

In quanto non definito nella libreria displaytag-1.2.jar (!?...) sostituendolo con

super(ExcelGenerationException.class,Messages.getString("ExcelView.errorexporting"));

Adesso tutto funziona come volevo.

giovedì 22 novembre 2012

Java generare random password

Metodo statico di utilità

public static String generateRandomPassword(int lunghezza){
  char[] caratteri={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p'
 ,'q','r','s','t','u','v','w','x','y','z','è','ì','ò','ù','é','\'','&','(',')','?','!','/'};
  char[] maiuscole={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P'
    ,'Q','R','S','T','U','V','W','X','Y','Z'};
         char[] numeri={'0','1','2','3','4','5','6','7','8','9'};
  int lunghezzaChar=caratteri.length;
  int lunghezzaMaiuscole=maiuscole.length;
  int lunghezzaNumeri=numeri.length;
  StringBuffer sb=new StringBuffer();
  List<String> composizionePwd=new LinkedList<String>();
  for(int i=0;i<lunghezza;i++){
   int x = (int)(Math.random() * 10);
   if(x<=3){
    composizionePwd.add("C");
   }
   else if(x>3 && x<=6){
    composizionePwd.add("M");
   }
   else
   {
    composizionePwd.add("N");
   }
  }
  for(int i=0;i<lunghezza;i++){
   int elementoArray=0;
   if(composizionePwd.get(i).equals("M")){
    elementoArray= (int)(Math.random()*lunghezzaMaiuscole);
    sb.append(maiuscole[elementoArray]);
   }
   else if(composizionePwd.get(i).equals("C"))
   {
    elementoArray=(int)(Math.random()*lunghezzaChar);
    sb.append(caratteri[elementoArray]);
   }
   else
   {
    elementoArray=(int)(Math.random()*lunghezzaNumeri);
    sb.append(numeri[elementoArray]);
   }
  }
  return sb.toString();
 }



mercoledì 21 novembre 2012

Javascript inibire scrittura in text area al combo change

Questa operazione apparentemente banale nasconde una piccola insidia con Internet
Explorer.
La scelta migliore rimane quella di utilizzare un framework Javascript come Jquery ma se tale scelta non fosse possibile....
Con Firefox e Chrome si può usare il costrutto:

 document.getElementById("idCampo").setAttribute("readonly","readonly");



Con Internet Explorer tale istruzione non funziona, e bisogna utilizzare

document.getElementById("idCampo").readOnly=true;

Di seguito il codice di un esempio, abbiamo una combo al cui evento onchange per un particolare codice si inibisce la scrittura nella textbox sottostante.


<html>

<head>

<script>
function disabilitaAbilita(){
if(document.getElementById("test").value=="1")
{
document.getElementById("firstName").value="Scrittura inibita!!!!";
//document.getElementById("firstName").setAttribute("readonly","readonly");
document.getElementById("firstName").readOnly=true;
}
else
{
document.getElementById("firstName").value="";
//document.getElementById("firstName").removeAttribute("readonly");
document.getElementById("firstName").readOnly=false;
}
}
</script>
</head>
<body onload="disabilitaAbilita()">

<form > Scelta

<SELECT name="example" id="test" onchange="disabilitaAbilita()">

<OPTION selected value="1">UNO </OPTION>

<OPTION  value="2">DUE</OPTION>

<OPTION value="3">TRE</OPTION>

<OPTION value="4">QUATTRO</OPTION>

</SELECT>

<br>

Testo<textarea type="text" name="firstname" id="firstName">

</form>

</body>

</html>
Ecco l'esempio renderizzato:
Scelta

Testo

Java ottenere MimeType da bytes[]

Esiste una comoda libreria che consente , dato l'array di byte, di determinare il mime type del file.
La libreria si chiama jmimemagic-0.1.0.jar ( si può scaricare qui ).
Richiede come dipendenza i 2 seguenti jar:
  • commons-logging.jar;
  • jakarta-oro.jar.
Vediamo un esempio su un progetto Java, in cui ho incluso nel classpath i 3 jar.


Magic m=new Magic();
byte[] lb=FileUtil.load(new File("file/WS.png"));
MagicMatch match = m.getMagicMatch(lb);
System.out.println(match.getMimeType());

L'array di byte dal file è stato ottenuto  con il seguente metodo statico di una classe denominata FileUtil di cui incollo il codice:

import java.io.*;
public class FileUtil {

  public final static byte[] load(String fileName)
   {
     try { 
       FileInputStream fin=new FileInputStream(fileName);
       return load(fin);
     }
     catch (Exception e) {
  
       return new byte[0];
     }
   }

   public final static byte[] load(File file)
   {
     try { 
       FileInputStream fin=new FileInputStream(file);
       return load(fin);
     }
     catch (Exception e) {
      
       return new byte[0];
     }
   }

   public final static byte[] load(FileInputStream fin)
   {
     byte readBuf[] = new byte[512*1024];
   
     try { 
       ByteArrayOutputStream bout = new ByteArrayOutputStream();
     
       int readCnt = fin.read(readBuf);
       while (0 < readCnt) {
         bout.write(readBuf, 0, readCnt);
         readCnt = fin.read(readBuf);
       }
       
       fin.close();
       
       return bout.toByteArray();
     }
     catch (Exception e) {
      
       return new byte[0];
     }
   }
}


mercoledì 14 novembre 2012

Problemi di visualizzazione in Internet Explorer 8

Mi è capitato un problema apparentemente molto strano.
Praticamente la stessa applicazione web aveva una resa grafica diversa (disallineamenti nei div nei bottoni ecc.) a seconda se veniva testata tramite localhost oppure tramite nome server.
Mettendo localhost tutto si vedeva correttamente, invece con il nome server si verificavano i disallineamenti.
Inutile dire che con tutti gli altri browser (Firefox,Chrome etc.) si vedeva sempre correttamente.
Tornando al problema era dovuto ad una impostazione di Inetrnet Explorer, la Visualizzazione Compatibilità, che serve a rendere migliore la resa grafica per siti web progettati per IE 6 e 7.
Dal menu Strumenti/Impostazione Visualizzazione Compatibilità avevo questa situazione:

Il problema si è risolto deselezionando la scelta "Visualizza siti Intranet in Visualizzazione Compatibilità".
In generale è anche possibile escludere o rimuovere dalla visualizzazione anche un solo sito.
L'applicazione infatti era realizzata con PrimeFaces 3.4 che è compatibile con IE 8 e superiori, non con 7 e 6, forzando la visualizzazione compatibilità a quanto ho capito era come forzare la visualizzazione ad Internet Explorer 7.


martedì 6 novembre 2012

Web Service Rest

In questo post vediamo come realizzare un semplice servizio Web Rest e deployarlo come una Web App sotto Tomcat 7.
Innanzitutto qui possiamo trovare le basi teoriche dei servizi Web Rest.
Tra i vantaggi dell'utilizzo di un servizio Web Rest c'è l'eliminazione del payload soap e quindi una maggiore velocità di fruizione.
Tra gli svantaggi per adesso sicuramente c'è quello di non avere un sistema built-in di security integrato (tipo WS-Security per i Web Service SOAP).
Sviluppare l'esempio di per se è stato molto semplice, l'unico problema è quello di avere le giuste dipendenze nel classpath.
Ho utilizzato le librerie di Jersey per costruire il servizio.
In particolare dentro la WEB-INF /lib ho i seguenti jar:
  • asm-3.3.1.jar;
  • jaxrs-api.jar;
  • jersey-core-1.1.5.1.jar;
  • jersey-server-1.1.5.1.jar;
  • jsr311-api-1.1.jar.
Le librerie di Jersey si trovano sul sito, la jsr311 l'ho scaricata da internet direttamente.
Nel web.xml dobbiamo configurare la servlet di Jersey per esporre il servizio.

<servlet>
    <servlet-name>RestfulContainer</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>com.sun.jersey.config.property.packages</param-name>
      <param-value>it.test</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>RestfulContainer</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping> 

Si noti che il param-value rappresenta il nome del package in cui abbiamo deployato il servizio.

La classe che implementa il servizio Web è la seguente:

package it.test;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
// The Java class will be hosted at the URI path "/helloworld"
@Path("/helloworld")
public class RestTest {
    
  // This method is called if TEXT_PLAIN is request
   @GET
   @Produces(MediaType.TEXT_PLAIN)
   public String sayPlainTextHello() {
     return "Hello Jersey";
   }

   // This method is called if XML is request
   @GET
   @Produces(MediaType.TEXT_XML)
   public String sayXMLHello() {
     return "" + "<hello> Hello Jersey" + "</hello>";
   }

   // This method is called if HTML is request
   @GET
   @Produces(MediaType.TEXT_HTML)
   public String sayHtmlHello() {
     return "<html> " + "<title>" + "Hello Jersey" + "</title>"
         + "<body><h1>
<b>" + "Hello Gino" + "<b></b></b></h1>
</body></html></code></pre>
" + " ";
   }
   @GET
   @Path("/greetings/{test}")
    @Produces(MediaType.TEXT_PLAIN)
   public String saluta(@PathParam("test") String t){
    return "Ciao "+t;
   }
  
}  

Sono servizi in get molto semplici, con l'annotazione @Produces si specifica il tipo di output che sarà prodotto mentre con @PathParam si indica un parametro da passare in input al servizio (è il caso del metodo saluta).

Una volta fatto partire il server possiamo verificare che il servizio risponda digitando

http://localhost:8080/TestRest/rest/helloworld

Dovrebbe apparire una pagina bianca con scritto "Hello Gino".
 Poichè nei servizi rest una risorsa è indentificata dal suo URI aggiungendo al path della web app +path servlet il nome specificato nell'annotazione @Path della classe.

Scrivere un client Java al servizio

Ho creato un semplice java project inserendo le seguenti librerie nel classpath:

  • asm-3.3.1.jar;
  • jaxrs-api.jar;
  • jersey-bundle-1.9.1.jar.
Il codice del client è il seguente

package it.client;
import java.net.URI;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
public class ClientTest {
 public static void main(String[] args) {
      ClientConfig config = new DefaultClientConfig();
      Client client = Client.create(config);
      WebResource service = client.resource(getBaseURI());
      // Fluent interfaces
      System.out.println(service.path("rest").path("helloworld").accept(MediaType.TEXT_PLAIN).get(ClientResponse.class).toString());
      // Get plain text
      System.out.println(service.path("rest").path("helloworld").accept(MediaType.TEXT_PLAIN).get(String.class));
      // Get XML
      System.out.println(service.path("rest").path("helloworld").accept(MediaType.TEXT_XML).get(String.class));
      // The HTML
      System.out.println(service.path("rest").path("helloworld").accept(MediaType.TEXT_HTML).get(String.class));
     System.out.println(service.path("rest").path("helloworld/greetings/kjasdkjasd").type(MediaType.TEXT_PLAIN).get(String.class)); 

 }
  private static URI getBaseURI() {
      return UriBuilder.fromUri("http://localhost:8080/TestRest").build();
    }
}

L'output prodotto a console è il seguente:

GET http://localhost:8080/TestRest/rest/helloworld returned a response status of 200 OK
Hello Jersey
<hello> Hello Jersey</hello>
<html> <title>Hello Jersey</title><body><h1>
<b>Hello Gino<b></b></b></h1>
</body></html>
Ciao kjasdkjasd

Tomcat 7 : [org.apache.xml.resolver.tools.ResolvingXMLReader]

Sono incappato nel seguente errore allo start up di Tomcat 7 (jdk 1.7 di riferimento).


Unable to load class [org.apache.xml.resolver.tools.ResolvingXMLReader] 
to check against the @HandlesTypes annotation of one or more ServletContentInitializers. 
java.lang.ClassNotFoundException: org.apache.xml.resolver.tools.ResolvingXMLReader

L'errore si ripeteva in continuazione e di fatto il war che stavo provando (un web service) non veniva deployato.
Il web.xml era versione 3.0.
La soluzione del problema è mettere il seguente attributo dentro il nodo web-app del web.xml:

metadata-complete="true"

Questo attributo dice al server di non scansionare tutta la directory web-inf/lib alla ricerca di annotazioni compatibili con il modello di servlet 3.0.
Un vantaggio di questo attributo inoltre è che migliora di molto la velocità dell'application server allo start up.

lunedì 5 novembre 2012

Verificare versione JAX-B installata

Quando capita di incappare in errori del tipo

com.sun.xml.bind.v2.runtime.JAXBContextImpl
cannot be cast to com.sun.xml.internal.bind.api.JAXBRIContext


Occorre verificarela versione di JAX-B presente nella JDK.
Il problema può essere dovuto al class loader, ossia al caricamento nel classpath di una libreria diversa.
Questo può accadere ad esempio se nella nostra web-app nella directory WEB-INF/lib carichiamo una libreria di JAX-B con versione diversa.
Per verificare la versione della nostra jdk posizionarsi da terminale nella directory bin della jdk e digitare il comando xjc -version.


C:\Programmi\Java\jdk1.6.0_35\bin>xjc -version
xjc version "JAXB 2.1.10 in JDK 6"
JavaTM Architecture for XML Binding(JAXB) Reference Implementation, (build JAXB
2.1.10 in JDK 6)




giovedì 1 novembre 2012

Installare Tomcat 7 come servizio windows rinominandolo

Per installare Tomcat 7 come servizio occorre andare da command sulla bin del server e digitare

>> service.bat install
Per installarlo mentre per disinstallarlo


>> service.bat uninstall
Se vogliamo rinominarlo possiamo editare il file service.bat oppure farne una copia, quindi inserire nelle linee


rem Set default Service name
set SERVICE_NAME=Tomcat7
set PR_DISPLAYNAME=Apache Tomcat 7

Il SERVICE_NAME e il PR_DISPLAYNAME che si desidera.
Il  PR_DISPLAYNAME è quello che si vedrà andando sulla lista dei servizi di windows

mercoledì 31 ottobre 2012

Elencare tutti i db presenti

Per trovare tutti i db presenti su un Sql Server


SELECT name 
    FROM master..sysdatabases 
    ORDER BY name

martedì 23 ottobre 2012

Java ottenere il content-type di un file

Un metodo Java per ottenere il content-type di un file dato il nome.
Esiste una funzione ad hoc nella jdk, nella classe astratta java.net.URLConnection, denominata guessContentTypeFromName che prende in input una Stringa.
Solo che non funziona con alcuni tipi (es .doc,.xls) anche abbastanza comuni.

public static String getContentTypeFromFileName(String s){
  String retVal="";
  if(!(s==null || s.trim().equals(""))){
   
  int punto=s.indexOf(".");
  String extension=s.substring(punto);
  if(".pdf".equals(extension)){
   retVal="application/pdf";
  }
  else if(".doc".equals(extension)){
   retVal="application/msword";
  }
  else if(".docx".equals(extension)){
   retVal="application/vnd.openxmlformats-officedocument.wordprocessingml.document";
  }
  else if(".csv".equals(extension)){
   retVal="text/csv";
  }
  else if(".xls".equals(extension)){
   retVal="application/vnd.ms-excel";
  }
  else if(".xlsx".equals(extension)){
   retVal="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
  }
  else if(".ppt".equals(extension)){
   retVal="application/vnd.ms-powerpoint";
  }
  else if(".pptx".equals(extension)){
   retVal="application/vnd.openxmlformats-officedocument.presentationml.presentation";
  }
  else
  {
   if("".equals(retVal)){
    retVal=URLConnection.guessContentTypeFromName(s);
   }
  }
  }
  return retVal;
 }


giovedì 18 ottobre 2012

Hash MD5 con Sql Server

In sql server esiste la funzione HashBytes che prende in input 2 parametri:
  • L'algoritmo usato;
  • La Stringa di cui calcolare l'hash.
Per cui scrivendo

select HashBytes('MD5','carlo')
>> 0x6E6BC4E49DD477EBC98EF4046C067B5F

Abbiamo il risultato in bytes, per ottenere invece il valore in varchar non funziona il classico metodo CONVERT dell'sql  ma bisogna utilizzare la funzione fn_varbintohexstr definita nel master.


select SUBSTRING(master.dbo.fn_varbintohexstr(HashBytes('MD5', 'ciao')), 3, 32);
>> 6e6bc4e49dd477ebc98ef4046c067b5f

Si noti che è fondamentale il passaggio per la funzione fn_varbintohexstr altrimenti il substring si applicherebbe a dei bytes e non a delle stringhe con risultati errati.
Esempio:


select substring(HashBytes('MD5','ciao'),3,32); 
>> 0xC4E49DD477EBC98EF4046C067B5F


mercoledì 17 ottobre 2012

Configurare filtro ISAPI su IIS 7.5 per Tomcat 7.0

L'operazione di configurazione del filtro isapi  consente di avere IIS come Web Server e di delegare l'esecuzione di codice Java Server Side (servlet,jsp, etc.) direttamente a Tomcat.
Le  entità necessarie per questa configurazione sono:
  • isapi_redirect.dll  plug in per iis (scaricabili qui ) prestando attenzione alle versioni a 64 bit o 32 bit a seconda del sistema operativo;
  • workers.properties , file dove si indicano host e porte usate dai cosiddetti "workers";
  • uriworkermap.properties, file che effettua la mappatura URL-workers;
  • isapi_redirect.properties,  file che definisce la locazione dei file uriworkermap e workers così come il percorso del file di log e i livelli di log
Si noti che in versioni precedenti di IIS non esisteva la possibilità di specificare il file isapi_redirect.properties e era necessario inserire chiavi di registro sul S.O.

Esempio di file .reg per il registro di Windows


REGEDIT4
[HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0]
"server_root"="C:\\connettore\\"
"extension_uri"="/jakarta/isapi_redirector.dll"
"worker_file"="c:\\connettore\\conf\\workers.properties"
"log_file"="c:\\connettore\\logs\\isapi_redirect.log" 
"worker_mount_file"="c:\\connettore\\conf\\uriworkermap.properties"
"log_level"="DEBUG"


Tale opzione è ancora possibile ma sconsigliata in quanto il meccanismo del file di properties è più flessibile.
La isapi_redirect.dll può essere messa in una qualsiasi directory del server.
In questo esempio si trova sotto c:\connettore e il sistema operativo è windows Server 2008 a 64 bit.

isapi_redirect.properties

extension_uri=/jakarta/isapi_redirect.dll
log_file=c:\connettore\logs\isapi.log
log_level=debug
worker_file=c:\connettore\conf\workers.properties
worker_mount_file=c:\connettore\conf\uriworkermap.properties

L' extension_uri indica il path all'extension dell'isapi redirect, il nome jakarta in questo caso dovrà essere il nome della directory virtuale definita sotto IIS.
Da IIS infatti, nel Web Site scelto, si crea tale directory virtuale e quindi si aggiunge il filtro isapi che punta al percorso del file system dove si trova la isapi_redirect.dll ( vedi qui per ulteriori dettagli).

workers.properties


worker.list=myWorker
worker.myWorker.port=8009
worker.myWorker.host=localhost
worker.myWorker.type=ajp13
Questi dati si riferiscono alla configurazione del Tomcat che vogliamo esporre.
La porta utilizzata è la porta del connettore AJP di Tomcat. Tale configurazione si trova nel file server.xml dentro la directory conf di Tomcat. Il valore 8009 è quello di default.

uriworkermap.properties


/myApp=myWorker
/myApp/*=myWorker

Dove myApp sarà il nome del nostro war dentro Tomcat.


A questo punto se tutto è andato a buon fine digitando http://NOME_SERVER/myApp si verrà ridirezionati direttamente alla porta 8080 di Tomcat (http://NOME_SERVER:8080/myApp ), ovviamente l'indicazione ella porta non comparirà più nell'url perchè il raccordo tra indirizzo e applicazione deployata sotto Tomcat è fatto dal  filtro ISAPI


sabato 6 ottobre 2012

Autocomplete con Jquery


In questo post vediamo come effettuare un autocompletamento utilizzando jquery e con la chiamata Ajax ad una classe Java per il recupero delle occorrenze.
La pagina html si compone di un form con 2 text box nome e cognome, digitando il cognome dal secondo carattere in poi parte la chiamata Ajax che suggerisce sotto la lista dei nominativi che iniziano con quelle lettere.
I nominativi proposti sono sotto forma di cognome/nome, alla selezione di ognuno di essi è invocato un metodo javascript che splitta la stringa e inserisce il nome nella casella di testo del nome e il cognome in quella del cognome.

Ho utilizzato jquery versione 1.3.2.

Il metodo autocomplete è il seguente:

 $("#cognome").autocomplete("data.jsp",{minChars: 2,onItemSelect: function(item) {
                var text = item.innerHTML;
                var splitResult=text.split("  ");
                var nom=splitResult[1];
                var cog=splitResult[0];
                document.getElementById("nome").value=nom;
                document.getElementById("cognome").value=cog;
                $("#testoProva").html(text);
            }});


Data.jsp è la pagina java che torna i dati in formato stringa, tra parentesi graffe si possono specificare varie proprietà del metodo, in questo caso la minLength che indica dopo quante lettere si dovrà effettuare la chiamata e l' onItemSelect che ci dice cosa fare una volta che dalla lista di proposte di nominativi se ne sceglie uno.

Di seguito incollo il codice

index.jsp
<html>
<head>
    <link href="css/jquery.autocomplete.css" rel="stylesheet" type="text/css"></link>
    <script src="js/jquery_1.3.2_min.js" type="text/javascript"></script>
    <script src="js/jquery.autocomplete.js"></script> 
    <style>
        input {
            font-size: 120%;
        }
    </style>
</head>
<body>

 <h3>
Nome</h3>
<input id="nome" name="nome" type="text" />
    <h3>
Cognome</h3>
<input id="cognome" name="cognome" type="text" />
     <div id="testoProva">
     
     </div>
<script>
       
            $("#cognome").autocomplete("data.jsp",{minChars: 2,onItemSelect: function(item) {
                var text = item.innerHTML;
                var splitResult=text.split("  ");
                var nom=splitResult[1];
                var cog=splitResult[0];
                document.getElementById("nome").value=nom;
                document.getElementById("cognome").value=cog;
                $("#testoProva").html(text);
            }});

        
       
    </script>
</body>
</html>


data.jsp

<%@page import="it.db.Caricamento"%>
<%@page import="java.util.Iterator"%>
<%@page import="java.util.List"%>

<%
    
    Caricamento db = new Caricamento();
    
    String query = request.getParameter("q");
    
    List<String> nomi = db.getData(query);
   
    Iterator<String> iterator = nomi.iterator();
    while(iterator.hasNext()) {
        String nome = (String)iterator.next();
        out.println(nome);
    }
%>


Caricamento.java (classe che simula accesso al db)
 
package it.db;
import java.util.*;
public class Caricamento {
  private int totale;
     private String nomi = "Zegna  Mario Alberto,Zorro  Marco,Abate  Matteo,Abatino  Carlo,Sgarbi  Vittorio,Selvaggio  Mario";
     private List<String> nomiL;
     public Caricamento() {
         nomiL= new ArrayList<String>();
         StringTokenizer st = new StringTokenizer(nomi, ",");
          
         while(st.hasMoreTokens()) {
             nomiL.add(st.nextToken().trim());
         }
         totale = nomiL.size();
     }
      
     public List<String> getData(String query) {
         String nom= null;
         query = query.toLowerCase();
         List<String> matched = new ArrayList<String>();
         for(int i=0; i<totale; i++) {
             nom= countries.get(i).toLowerCase();
             if(nom.startsWith(query)) {
                 matched.add(nomiL.get(i));
             }
         }
         return matched;
     }
}

domenica 23 settembre 2012

Jpa mappare Primary Key

La primary key è l'identità di un entity bean.
L'annotazione  @javax.persistence.Id identifica la proprietà che funge da primarìy key.
La chiave primaria può essere autogenerata dal provider, in questo caso si utilizza l'annotazione
@javax.persistence.GeneratedValue con le seguenti strategie (attributo strategy):
  • TABLE;
  • SEQUENCE;
  • IDENTITY;
  • AUTO.
AUTO

E'  la strategia di default  che utilizza le colonne autoincrementali presenti in molti database come MySql o Sql Server.

IDENTITY

Con questa strategia si obbliga il provider ad utilizzare i campi autoincrementali del db (esempio in mysql AUTO_INCREMENT e in Sql Server IDENTITY ) Per adottare questa strategia basta fare così:
....
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
public long getId(){
.....
}

TABLE

Con questa strategia si definisce una tabella utilizzata come "serbatoio" per fornire le chiavi primarie.
La struttura di questa tabella è la seguente:

create table GENERATOR_TABLE
{
     PRIMARY_KEY_COLUMN VARCHAR not null,
     VALUE_COLUMN long not null
}

Bisogna utilizzare una altra annotazione @TableGenerator dove si specifica il generatore con il nome della tabella creata etc etc.

Esempio

@TableGenerator(name="myGenerator",table="GENERATOR_TABLE",pkColumnName="PRIMARY_KEY_COLUMN",
valueColumnName="VALUE_COLUMN",pkColumnValue="CUST_ID",allocationsize=10)
@Id
@GeneratedValue(strategy=GenerationType.TABLE,generator="myGenerator")
public long getId(){...}

SEQUENCE

Alcuni RDBMS come Oracle hanno un meccanismo built in per la generazione delle primary key, definito appunto SEQUENCE.
In questi casi a livello di classe va definito il sequence generator utilizzato e referenziato dall'attributo generator dell'annotazione @GeneratedValue.
Esempio:

@Entity
@Table(name="CUSTOMER_TABLE")
@SequenceGenerator(name="CUSTOMER_SEQUENCE",sequenceName="CUST_SEQ")
public class Customer implements Serializable{

.....
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="CUSTOMER_SEQUENCE")
public long getId(){...}
....
}

lunedì 10 settembre 2012

Jsf implementazione Mojarra problemi DOCTYPE

Ho riscontrato un problema utilizzando il motore di JSF 2.0 di Mojarra (versione 2.1.12).
Nel passaggio da una pagina all'altra ho notato che si perdeva il font del carattere.
Il font è impostato da un css personalizzato, siccome come librerie stiamo utilizzando PrimeFaces 3.1 secondo le specifiche della libreria abbiamo messo nello stylesheet:

.ui-widget,        
.ui-widget .ui-widget {
        font-size: 10px;      
               }


In questo modo si ridefinisce il font per tutti i form. Il codice del css è inline nella pagina, in modo da essere sicuri che vada in overrride rispetto a quello di default della libreria di PrimeFaces.
Il motivo della perdita del font è dovuto alla mancata valorizzazione del DOCTYPE nella pagina html generata, nonostante questo sia presente correttamente nell' xhtml della pagina.
Sembra essere proprio un bug di queste ultime versioni(http://java.net/jira/browse/JAVASERVERFACES-2453?page=com.atlassian.jira.plugin.system.issuetabpanels%3Aall-tabpanel) anche se nella descrizione riportata si fa riferimento a questo problema solo se sono presenti degli <ui:include sulla pagina e nel nostro caso gli ui:include ci sono sempre, sia nella pagina che si vede correttamente sia nell'altra.
Per risolvere il problema ho preso l'ultima installazione di MyFaces come implementazion; stesso risultato ho avuto prendendo la versione 2.1.1 di Mojarra.


venerdì 7 settembre 2012

JSF stampare i valori in request

Snippet per stampare a video tutti i valori presenti nella request in JSF

Map<String, String> parameterMap = (Map<String, String>) FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
Set<String> ss=  parameterMap.keySet();
 for(String s:ss){

           log.debug("Chiave: "+s+" Valore: "+parameterMap.get(s));
       }

mercoledì 5 settembre 2012

Prime Faces lista esportabile

Con Prime Faces , ottima libreria di componenti per jsf 2, sono incappato in un problema per gestire l'export in excel.
Questo perchè la libreria si appoggia alle Apache POI.

Utilizzando primefaces 3.3.1 ho dovuto aggiungere nella lib i jar di Apache POI 3.7 (con qualsiasi altra versione andava in errore).
La lista totale dei jar nella WEB-INF/lib è la seguente
  •  primefaces-3.3.1.jar
  •  itext-1.4.8.jar
  •  log4j-1.2.13.jar
  •  commons-logging-1.1.jar
  • junit-3.8.1.jar
  •  javax.faces-2.1.12.jar
  • poi-scratchpad-3.7-20101029.jar
  •  poi-examples-3.7-20101029.jar
  •  poi-ooxml-3.7-20101029.jar
  •  poi-3.7-20101029.jar
  •  poi-ooxml-schemas-3.7-20101029.jar
Il testo della porzione di .xhtml è reperibile qui sul sito di Prime Faces.

Ho notato che dentro le p:column se invece di fare come scritto sul sito ossia così:

  <p:column> 
        <f:facet name="header"> 
            <h:outputText value="Model" /> 
        </f:facet> 
        <h:outputText value="#{car.model}" /> 
    </p:column>
 


Si fa

  <p:column> 
       #{car.model}
    </p:column>  


Il dato non è stampato correttamente sull'excel/pdf.
Allo stesso modo se non si inserisce la facet con l'header non si visualizzano le intestazioni di colonna.




sabato 1 settembre 2012

Collisione di Persistence Context

Interessante questo post trovato su Javaranch (http://www.coderanch.com/t/431474/java-EJB-SCBCD/certification/PersistenceContext-Collision ) .

Se uno stateless session bean chiama un metodo di un ejb a cui è associato un Persistence Context EXTENDED ( ossia gli oggetti restano sincronizzati anche dopo la chiamata ai singoli metodi), poichè c'è collisione tra i persistence context si verifica un errore.

Si ricordi che il Persistence Context EXTENDED non può mai essere associato agli Ejb Stateless.

martedì 28 agosto 2012

Offuscare codice Java con PROGUARD

Utilizzando PROGUARD è possibile effettuare un efficace offuscamento del codice e anche comprimere nel caso sia necessario ottimizzare spazio.
Si utilizza da riga di comando.
Per usarlo ho per prima cosa scritto un progetto di prova, un semplice java project che effettua una criptazione utilizzando l'algoritmo AES con chiave a 16 bit.

Testato il programma ho creato il jar.
Quindi ho esportato il jar dentro la cartella lib di PROGUARD.
Ho inserito sempre qui sotto la lib di PROGUARD anche il jar commons-codec-1.3.jar che è utilizzato dal mio codice.
Quindi ho creato (sempre sotto la lib) un file denominato parametri.pro così definito

-injars  cipher.jar
-outjars cipher_obs.jar

-libraryjars C:\Programmi\Java\jdk1.6.0_29\jre\lib\rt.jar;C:\Programmi\Java\jdk1.6.0_29\jre\lib\jce.jar;commons-codec-1.3.jar

-keep public class it.oasi.cipher.Cypher {
    public static void main(java.lang.String[]);
}




injars e outjars rappresentano rispettivamente il jar da offuscare e il jar prodotto dall'offuscamento

libraryjars indica tutte le librerie (comprese quelle generali della jdk come si può vedere) utilizzate dal jar. Si noti che ho onserito anche il jce.jar per avere il supporto della classe javax.crypto.Cipher

keep serve a mantenere l'entry point del codice (in questo caso il codice main)

Per generare il jar offuscato posizionarsi via shell sulla directory lib e digitare il seguente comando

 java -jar proguard.jar @parametri.pro


Il risultato è il seguente

Classe originale

import java.io.IOException;
import java.security.Key;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

public class Cypher
{
  private static Cypher istanza;


public static Cypher getInstance(){
      if(istanza==null){
          istanza=new Cypher();
      }
      return istanza;
  }

  private  Key getKey()
  {
    Date data = getDateForKey();
    SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
    String chiave = sdf.format(data) + "abcdre";
   
    byte[] rawdata = chiave.getBytes();
   
    SecretKeySpec skeySpec = new SecretKeySpec(rawdata, "AES");
    return skeySpec; }

  private  Date getDateForKey() {
    Calendar c = Calendar.getInstance();
    c.set(1, 1978);
    c.set(2, 3);
    c.set(5, 20);
    return c.getTime(); }

  private  byte[] encrypt(String valore) throws Exception {
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(1, getKey());
    return cipher.doFinal(valore.getBytes());
  }

  private  byte[] decrypt(byte[] valore) throws Exception {
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(2, getKey());
    return cipher.doFinal(valore);
  }

  public  String cifra(String valore) throws Exception {
    return toBase64(encrypt(valore));
  }

  public  String decifra(String valore) throws Exception {
        return new String(decrypt(fromBase64(valore)));
      }
  private  String toBase64(byte[] valore)
  {
    return new String(new Base64().encode(valore));
  }

  private  byte[] fromBase64(String valore)
    throws IOException
  {
    return new Base64().decode(valore.getBytes());
  }

  public static void main(String[] args)
    throws Exception
  {
      Cypher c=Cypher.getInstance();
     
   String cifratoB64 = c.cifra("abilitatoDrillDown");
   String decifrato = c.decifra(cifratoB64);
    System.out.println("Cifrato: " + cifratoB64);
    System.out.println("Decifrato: " + decifrato);
  }
}


Se provo a decompilare il jar offuscato ottengo qualcosa di vagamente incomprensibile:


import java.io.PrintStream;
import java.security.Key;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class Cypher
{
  private static Cypher a;

  private Key a()
  {
    (localObject = Calendar.getInstance()).set(1, 1978);
    ((Calendar)localObject).set(2, 3);
    ((Calendar)localObject).set(5, 20);
    Object localObject = ((Calendar)localObject).getTime();
    SimpleDateFormat localSimpleDateFormat = new SimpleDateFormat("dd-MM-yyyy");
    localObject = (localObject = localSimpleDateFormat.format((Date)localObject) + "abcdre").getBytes();
    return (Key)(localObject = new SecretKeySpec(localObject, "AES"));
  }

  public static void main(String[] paramArrayOfString)
  {
    if (a == null)
      a = new Cypher();
    Object localObject2 = "abilitatoDrillDown";
    localObject2 = localObject2;
    Object localObject1 = localObject1 = paramArrayOfString = a;
    Cipher localCipher;
    (localCipher = Cipher.getInstance("AES")).init(1, ((Cypher)localObject1).a());
    localObject1 = localCipher.doFinal(((String)localObject2).getBytes());
    String str = new String(new Base64().encode(localObject1));
    localObject2 = str;
    localObject1 = paramArrayOfString;
    localObject1 = localObject2;
    localObject2 = new Base64().decode(((String)localObject1).getBytes());
    localObject1 = localObject1;
    (localCipher = Cipher.getInstance("AES")).init(2, ((Cypher)localObject1).a());
    paramArrayOfString = new String(localCipher.doFinal(localObject2));
    System.out.println("Cifrato: " + str);
    System.out.println("Decifrato: " + paramArrayOfString);
  }
}


NB: in questo caso anche importando il jar su un  nostro progetto sarà visibile solo il metodo main, per fare in modo che lo siano anche altri metodi occorre specificarli qui.

Esempio:

-keep public class it.oasi.cipher.Cypher {
    public static void main(java.lang.String[]);
    public static it.oasi.cipher.Cypher getInstance();
    public java.lang.String decifra(java.lang.String );
}


Da notare come le variabili di input non vanno specificati così come i tipi, se disgraziatamente doveste farlo (ad esempio nel decifra dopo il tipo di input definire la variabile valore) si incappa nel seguente messaggio di errore

Error: Expecting separating ',' or closing ')' before 'valore' in line 8 of file
 'parametri.pro',
  included from argument number 1

lunedì 20 agosto 2012

Sql Server select cast

Con Sql server per ottenere valori decimali si può utilizzare la sintassi

select cast([numero] as decimal(5,2))


Se facciamo così però:

select cast(3/5 as decimal(5,2))


Otteniamo 0, un modo veloce per ottenere il risultato corretto è quello di anteporre 1. * all'espressione, in questo caso il risultato è 0.6 correttamente

Facendo

select cast(1.*3/5 as decimal(5,2))



martedì 14 agosto 2012

Web Service con WS-Security seconda parte (CLIENT)

Per generare un client di un Web Service messo in sicurezza come visto nel precedente post occorre per prima cosa tramite l'utility wsimport (vedi qui ) generare le classi del client e dopo aggiungere l'handler che si occuperà in questo caso di scrivere username e password nell'header soap.

Ho scritto 2 classi una è l'implementazione dell'HandlerResolver usati in JAX-WS 2.0 proprio per "prendere il controllo" della eventuale catena di Handler presenti (in questo caso sarà soltanto uno).

Poi invece bisogna scrivere l'handler specifico che implementerà al solito l'interfaccia SOAPHandler.


MyHandler

import java.util.ArrayList;
import java.util.List;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.HandlerResolver;
import javax.xml.ws.handler.PortInfo;
import javax.xml.ws.handler.soap.SOAPHandler;
public class MyHandler implements HandlerResolver {

    @Override
    public List<Handler> getHandlerChain(PortInfo portInfo) {
        List<Handler> handlerList = new ArrayList<Handler>();
        SOAPHandler handler =  new WSSecurityHandler();
        handlerList.add(handler);
        return handlerList;
    }

}

WsSecurityHandler

package it.handler;

import java.io.IOException;
import java.util.Set;
import java.util.TreeSet;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPHeader;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
/**
 * Handler che gestisce il passaggio <br>
 * di username e password nell'header soap
 * @author
 *
 */
public class WSSecurityHandler implements SOAPHandler {
    private boolean scriviOutputSuConsole=true;
    /**
     * INSERIRE LO USERNAME
     */
    public static final String USER_NAME="pippo";
    /**
     * INSERIRE LA PWD 
     */
    public static final String PWD="pluto";
    @Override
    public void close(MessageContext arg0) {
        if(scriviOutputSuConsole) System.out.println("CLOSE");
    }

    @Override
    public boolean handleFault(MessageContext context1) {
        SOAPMessageContext context = (SOAPMessageContext)context1;
        try {
            if(scriviOutputSuConsole)context.getMessage().writeTo(System.out);
        } catch (SOAPException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return false;
    }

    @Override
 
    public boolean handleMessage(MessageContext context1) {
        SOAPMessageContext context = (SOAPMessageContext)context1;
        Boolean outbound = (Boolean)context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (outbound.booleanValue())
        {
            try {
                SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope();
                SOAPFactory factory = SOAPFactory.newInstance();
                String prefix = "wsse";
                String uri = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
                SOAPElement securityElement = factory.createElement("Security", prefix, uri);
                QName nameMust = new QName(envelope.getPrefix()+":mustUnderstand");
                securityElement.addAttribute(nameMust, "1");
                securityElement.addNamespaceDeclaration("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
                SOAPElement tokenElement = factory.createElement("UsernameToken", prefix, uri);
                QName nameWSU = new QName("wsu:Id");
                tokenElement.addAttribute(nameWSU, "token-1-1236072936329-25515818");
                SOAPElement username = factory.createElement("Username", prefix, uri);
                username.addTextNode(USER_NAME);
                SOAPElement pwd = factory.createElement("Password", prefix, uri);
                pwd.addTextNode(PWD);
                tokenElement.addChildElement(username);
                tokenElement.addChildElement(pwd);
                securityElement.addChildElement(tokenElement);
                SOAPHeader header = envelope.addHeader();
                header.addChildElement(securityElement);
                if(scriviOutputSuConsole) context.getMessage().writeTo(System.out);
               
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        else
        {
        }
        return true;
    }

    @Override
    public Set getHeaders() {
        return new TreeSet();
    }
}



A questo punto dal nostro client Java dobbiamo scrivere il seguente codice (supponiamo di aver messo in sicurezza il Web Service visto in questo post )

FattorialeDaoImplService f=new FattorialeDaoImplService();
CalcoloWs port=f.getCalcoloWsPort();
HandlerResolver resolver = new MyHandler();
f.setHandlerResolver(resolver);    
         
long fatt=port.getFattoriale(5);                 
System.out.println(fatt);