mercoledì 30 maggio 2012

Ottenere .jrxml da .jasper

Per ottenere una "decompilazione" da .jasper a .jrxml non ho trovato utility disponibili.
Per fortuna le classi di Jasper mettono a disposizione le API per farlo.
Di seguito il codice di una semplice classe con il main che dato un .jasper ottiene il jrxml.
Nel classpath bisogna avere i seguenti jar:



  • commons-logging.jar
  • commons-beanutils-1.7.0.jar
  • commons-collections-3.1.jar
  • jasperreports-2.0.1.jar
  • commons-fileupload.jar
  • commons-digester.jar
  • commons-discovery-0.2.jar
  • jasperreports-extensions1.3.1.jar
  • commons-lang-2.3.jar
  • commons-validator.jar
  • commons-httpclient-3.1.jar
  • commons-codec-1.3.jar



  • package test;
    import net.sf.jasperreports.engine.JRException;
    import net.sf.jasperreports.engine.JasperReport;
    import net.sf.jasperreports.engine.util.JRLoader;
    import net.sf.jasperreports.engine.xml.JRXmlWriter;
    public class JasperToJrxml {
       
        public static void main(String[] args) throws JRException {
                String    sourcePath = "out\\questBDM2.jasper";
                String    destinationPath = "out\\questBDM2.jrxml";   
              try
              {
                  JasperReport report = (JasperReport)JRLoader.loadObject(sourcePath);
                  JRXmlWriter.writeReport(report, destinationPath,"UTF-8");
                  System.out.println("Ok");

              }

              catch(JRException e)

              {
                 e.printStackTrace();

              }
            

           }
        }

    lunedì 28 maggio 2012

    File .class con costanti

    Mi è capitato di dover intervenire in fretta e furia su una applicazione deployata  e cercare di fixare un bug senza rilasciare tutto il war ma soltanto i .class necessari.
    In particolare in quest'ultimo caso si trattava di modificare una  query che era stata inserita in modo statico su una interfaccia come Stringa.
    Ho quindi inviato soltanto il .class con l'interfaccia ricompilata ma ovviamente non ha funzionato.
    Questo perchè a compile time Java esplode i valori delle costanti direttamente dentro i .class creati, quindi tutte le classi che utilizzavano quella query continuavano tranquillamente a leggersi il vecchio valore, cablato in fase di compilazione al loro interno.
    Beh ammetto di essere stato poco accorto, comunque questa è una riprova di quanto sia più pulito e corretto inserire i valori costanti mutabili spesso nel corso di  vita di una applicazione (le query) in file xml esterni piuttosto che dentro costanti scolpite nel codice.

    venerdì 18 maggio 2012

    Leggere un file csv utilizzando la classe URL

    Di seguito il codice per leggere un csv disponibile su internet ad un particolare indirizzo web.
    In questo caso vado a leggermi un file csv con i dettagli dei tassi di cambio tra monete disponibile all'URL

    http://uif.bancaditalia.it/UICFEWebroot/QueryOneDateAllCur?lang=ita&rate=1&initMonth={0}&initYear={1}&refCur=euro&R1=csv

    Dove al posto di {0} e {1} vanno inseriti i valori di un mese (da 01 a 12) e di un anno (4 cifre).

    Di seguito il codice:


    package it.moneyBatch;
    import java.net.*;
    import java.io.*;
    import java.text.MessageFormat;
    public class CaricaCsvMonete {
       
        public static final String URL="http://uif.bancaditalia.it/UICFEWebroot/QueryOneDateAllCur?lang=ita&rate=1&initMonth={0}&initYear={1}&refCur=euro&R1=csv";

        /**
         * @param args
         */
        public static void main(String[] args) {
            BufferedReader br = null;
            try
            {
                URL url;
                URLConnection urlConn;
               
                url=new URL(getUrl("2012", "04"));
                urlConn = url.openConnection();
                urlConn.setDoInput(true);
                urlConn.setUseCaches(false);
                String s;
                br=new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
                while ((s = br.readLine()) != null) {
                    s = br.readLine();
                    System.out.println(s);
                }
                br.close();
            }
            catch(Exception ex){
                ex.printStackTrace();
            }

        }
       
        private static String getUrl(String anno,String mese){
            return MessageFormat.format(URL, new Object[]{mese,anno});
        }

    }

    martedì 15 maggio 2012

    Display Table escludere colonne dall'export

    Con display-table è possibile escludere una colonna da un export semplicemente specificando nell'attributo media per quali tipi di export deve essere abilitata (il default è ALL).
    Quindi per escludere una colonna dall'export è sufficiente specificare dentro la colonna media="html".
    E' quindi possibile anche il viceversa, ossia non mostrare una colonna a video ma solo in output, ad esemprio specificando media="pdf excel" la colonna sarà visibile soltanto negli export pdf ed excel e non a video

    lunedì 14 maggio 2012

    Verificare correttezza di una data inserita come Stringa

    Se occorre validare una data inserita dall'utente in formato Stringa può risultare utile un metodo di questo tipo (qui siamo in un contesto di utilizzo con Struts), dove con il SimpleDateFormat prima si verifica che il formato sia corerente con quanto ci aspettiamo (in questo caso dd/MM/yyyy), poi che sia effettivamente come data valida:

    private boolean validaFormatoData(ActionMessages errors){
      boolean retVal=false;
      String formato="dd/MM/yyyy";
      SimpleDateFormat sdf=new SimpleDateFormat(formato);
      try
      {
       // verifichiamo prima la correttezza del formato
       Date date = sdf.parse(data);
       // ora verifichiamo che sia corretta come data
       if (sdf.format(date).equals(data)) {
        retVal = true;
       } else {
        retVal = false;
        errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
          "msg.ER", "Attenzione, la data inserita non è valida"));
       }
      }
      catch(Exception ex){
       errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
         "msg.ER", "Attenzione, la data di nascita deve essere inserita nel formato gg/mm/aaaa"));
           retVal=false;
      }
      return retVal;
     }


    domenica 13 maggio 2012

    Definire Data Source su Tomcat 4.1

    Con Tomcat 4 non è possibile definire i datasource nel file context.xml (dentro la META-INF del war); o quantomeno così facendo sono incappato in errori del tipo "Cannot create JDBC driver of class '' for connect URL 'null'" (in molti hanno avuto questi problemi).
    Seguendo il tutorial presente sul sito sono riuscito a definire un datasource specifico per una web application.
    I passi da seguire sono:
    1. Scaricare il driver per la connessione JDBC e posizionarlo nella directory commons/lib dell'AS;
    2. Modificare il file conf/server.xml definendo il contesto dell'applicazione e il datasource;
    3. Inserire all'interno del web.xml della web application il nodo <resource-ref> (altrimenti si incappa in errori del tipo "JDBC not bound").
     Vediamo in dettaglio i passi 2 e 3 e poi un esempio di chiamata da una servlet per recuperare la connection.
    Il db di test è Mysql

    Punto 2

    All'interno del conf/server.xml, dopo la chiusura dell'ultimo nodo </Context>  e prima della chiusura del nodo </Host>, inserire il seguente xml (NOTA : TestDs è il nome della nostra Web App mentre jdbc/TestDB è il nome del datasource):

    <Context path="/TestDs" docBase="TestDs"
            debug="5" reloadable="true" crossContext="true">

      <Logger className="org.apache.catalina.logger.FileLogger"
                 prefix="localhost_DBTest_log." suffix=".txt"
                 timestamp="true"/>

      <Resource name="jdbc/TestDB"
                   auth="Container"
                   type="javax.sql.DataSource"/>

      <ResourceParams name="jdbc/TestDB">
        <parameter>
          <name>factory</name>
          <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
        </parameter>

        <!-- Maximum number of dB connections in pool. Make sure you
             configure your mysqld max_connections large enough to handle
             all of your db connections. Set to -1 for no limit.
             -->
        <parameter>
          <name>maxActive</name>
          <value>100</value>
        </parameter>

        <!-- Maximum number of idle dB connections to retain in pool.
             Set to 0 for no limit.
             -->
        <parameter>
          <name>maxIdle</name>
          <value>30</value>
        </parameter>

        <!-- Maximum time to wait for a dB connection to become available
             in ms, in this example 10 seconds. An Exception is thrown if
             this timeout is exceeded.  Set to -1 to wait indefinitely.
             -->
        <parameter>
          <name>maxWait</name>
          <value>10000</value>
        </parameter>

        <!-- MySQL dB username and password for dB connections  -->
        <parameter>
         <name>username</name>
         <value>root</value>
        </parameter>
        <parameter>
         <name>password</name>
         <value>root</value>
        </parameter>

        <!-- Class name for mm.mysql JDBC driver -->
        <parameter>
           <name>driverClassName</name>
           <value>org.gjt.mm.mysql.Driver</value>
        </parameter>

        <!-- The JDBC connection url for connecting to your MySQL dB.
             -->
        <parameter>
          <name>url</name>
          <value>jdbc:mysql://localhost:3306/world</value>
        </parameter>
      </ResourceParams>
    </Context>

    Punto 3

    Nel web.xml inserire:

     <resource-ref>
        <description>nome jndi del ds</description>
        <res-ref-name>jdbc/TestDB</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
      </resource-ref>

    Per richiamare il datasource dall'applicazione è sufficiente inserire il seguente codice:

     Context context = new InitialContext();
    javax.sql.DataSource ds =(javax.sql.DataSource)context.lookup("java:comp/env/jdbc/TestDB");
     Connection connection = ds.getConnection();

    NOTA: Con Tomcat 6 e 7 è possibile inserire una notazione più compatta del ds con una serie di attributi che specificano i vari username password url etc. , ho provato anche con tomcat 4.1 ma non mi ha funzionato per cui deduco che non sia possibile

    lunedì 7 maggio 2012

    Jquery caricamento combo dinamiche via ajax


    Prendiamo un esempio classico, quello delle combo Regione-Provincia-Comune da attivarsi in sequenza tramite chiamata Ajax.
    La chiamata Ajax attivata all'onchange della combo regione carica le province di quella regione scelta, mentre quella attivata all'onchange della provincia chiama i comuni di quella provincia.
    Le chiamate Ajax tornano i risultati sotto forma di Xml, e tale xml è poi parsato lato jQuery per aggiornare la combo di interesse.

    Di seguito il codice della jsp utilizzata:

    <%@page import="it.gestore.Regione"%>
    <
    %@page import="java.util.List"%>
    <%@ 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>Insert title here</title>
    <script src="js/jquery-1.5.2.min.js"></script>
    <script>
    $(document).ready(function(){
     $('#ddlRegione').change(function() {
      $.ajax({
             type: "GET",
          url: "CaricaProvince",
          data: "ddlRegione="+document.getElementById('ddlRegione').value,
          dataType: "xml",
          success: function(xml) {
           var select=document.getElementById("ddlProvincia");
           if ( select ){

           while ( select.length > 1  )
           {
             select.remove(1);
             }
        }
           var select2=document.getElementById("ddlComune");
           if ( select2 ){

           while ( select2.length > 1  )
           {
             select2.remove(1);
             }
        }
           $(xml).find('elemento').each(function(){
          
         var value = $(this).find('codice').text();
         var text = $(this).find('descrizione').text();
       
         var select=document.getElementById("ddlProvincia");
        
         var option = document.createElement('option');
        
                    option.text = text;
                    option.value = value;
                  
                    try
                    {
                    
                      select.add(option, null);
                    }
                    catch(ex)
                    {
                   
                      select.add(option);
                    }
         });
     
      }
     });
      })
      $('#ddlProvincia').change(function() {
       $.ajax({
              type: "GET",
           url: "CaricaComuni",
           data: "ddlProvincia="+document.getElementById('ddlProvincia').value,
           dataType: "xml",
           success: function(xml) {
            var select=document.getElementById("ddlComune");
          
            if ( select ){

            while ( select.length > 1  )
            {
              select.remove(1);
              }
         }
            $(xml).find('elemento').each(function(){
           
          var value = $(this).find('codice').text();
          var text = $(this).find('descrizione').text();
        
          var select=document.getElementById("ddlComune");
         
          var option = document.createElement('option');
         
                     option.text = text;
                     option.value = value;
                   
                     try
                     {
                     
                       select.add(option, null); // standards compliant; doesn't work in IE
                     }
                     catch(ex)
                     {
                    
                       select.add(option); // IE only
                     }
          });
      
       }
      });
       })
     
     
     
     
     
      });


    </script>
    </head>
    <body>
    <form action="Carica">
    <table>
    <tr>
    <td>Regioni: </td>
    <td>
    <select name="ddlRegione" id="ddlRegione">
    <option value="">--</option>
    <%
    List<Regione> lista=(List<Regione>)getServletContext().getAttribute("listaRegioni");

    for(int i=0;i<lista.size();i++) {
     Regione r=lista.get(i);
    %>
    <option value="<%=r.getDescrizione()%>"><%=r.getDescrizione() %></option>
    <%} %>

    </select>
    </td>
    </tr>
    <tr>
    <td>Provincia: </td>
    <td><select name="ddlProvincia" id="ddlProvincia">
    <option value="">--</option>
    </td>
    </tr>
    <tr>
    <td>Comune: </td>
    <td><select name="ddlComune" id="ddlComune">
    <option value="">--</option>
    </td>
    </tr>
    </table>
    </form>
    </body>
    </html>



    Lato JQuery sono richiamate delle semplici servlet che interrogano un ejb esterno e restituiscono i dati sotto forma di xml. Di seguito il codice della servlet CaricaProvince (il codice della CaricaComune è analogo)

    package it.servlet;
    import it.gestore.ComuneDao;
    import it.gestore.Provincia;
    import it.gestore.Regione;

    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.Properties;

    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.*;
    /**
     * Servlet implementation class CaricaProvince
     */
    public class CaricaProvince extends HttpServlet {
     private static final long serialVersionUID = 1L;
          
        /**
         * @see HttpServlet#HttpServlet()
         */
        public CaricaProvince() {
            super();
            // TODO Auto-generated constructor stub
        }

     /**
      * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
      */
     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      doPost(request, response);
     }

     /**
      * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
      */
     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      try
      {
       PrintWriter out = response.getWriter();
       String regione=request.getParameter("ddlRegione");
       response.setContentType("text/xml");
       response.setHeader("Cache-Control", "no-cache");
       ComuneDao c=getEjb();
       Regione r=c.getRegioneByName(regione);
       List<Provincia> listaProvince=c.getProvinceByRegione(r);
       out.println( messaggioXml(listaProvince) );
       out.close();
      
      }
      catch(Exception ex){
      
      }
     }
     private String messaggioXml(List<Provincia> province){
      StringBuffer sb=new StringBuffer();
      sb.append("<elementi>");
      for(Provincia p:province){
       sb.append("<elemento>");
       sb.append("<codice>");
       sb.append(p.getIdProvincia());
       sb.append("</codice>");
       sb.append("<descrizione>");
       sb.append(p.getNomeProvincia());
       sb.append("</descrizione>");
       sb.append("</elemento>");
      }
      sb.append("</elementi>");
      return sb.toString();
     }
        private ComuneDao getEjb() throws Exception
        {
         Properties p=new Properties();
            p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
            p.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
            p.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099");
            Context ctx=new InitialContext(p);
            ComuneDao c=(ComuneDao) ctx.lookup("ComuneEjb/remote");
            return c;
        }
    }


    mercoledì 2 maggio 2012

    JQuery utilizzo base DatePicker

    Mi sono trovato ad utilizzare il controllo calendario di Jquery e l’ho trovato veramente comodissimo e di facile utilizzo.
    Dal sito di Jquery occorre scaricare :
    1.  Ultima versione fwk Jquery;
    2.  Ultima versione fwk Jquery-ui (quello che comprende i widget più diffusi);
    3. File javascript di localizzazione per il calendario (da http://jquery-ui.googlecode.com/svn/trunk/ui/i18n/ ).
    Il file del punto 3 va scaricato a parte mentre i primi due, unitamente al css, si trovano nello zip scaricato dal sito (nel mio caso jquery-ui-1.8.20.custom.zip ).
    Ho quindi creato una Web App per testare il calendario, nella jsp ho inserito i link ai js:


    <link type="text/css" href="css/ui-lightness/jquery-ui-1.8.20.custom.css" rel="stylesheet" />
    <script type="text/javascript" src="js/jquery-1.7.2.min.js"></script>
    <script type="text/javascript" src="js/jquery-ui-1.8.20.custom.min.js"></script>
    <script type="text/javascript" src="js/jquery.ui.datepicker-it.js">
    </script>


    Quindi nel codice javascript della jsp ho inserito la funzione che costruisce il calendario :

    <script type="text/javascript">
       $(function(){
        $(".data:input").datepicker({showAnim: 'slide',
          changeMonth: true ,
          changeYear: true,
          maxDate:new Date(),
          showButtonPanel: true,
          showOn: "button",
       buttonImage: "images/calendar.gif",
       buttonImageOnly: true

          }
            
          );
       });
    </script>


    Il selettore $(“.data:input”) specifica che questo codice js sarà applicato a tutti gli elementi di tipo <input type=”text” /> aventi attributo di tipo class denominato “data”.

    All’interno della funzione datePicker ci si può veramente sbizzarrire in quanto esistono innumerevoli proprietà da poter inserire, tra cui animazioni, pulsanti particolari ecc.
    Nel mio caso è stato interessante utilizzare gli attributi:
    • changeMonth e changeYear che settati a true consentono di poter selezionare velocemente da combo anni e mesi;
    • maxDate che consente di limitare la data inserita (in questo caso consente al massimo di inserire la data odierna);
    • showButtonPanel , che settato a true consente di visualizzare sotto il calendario i pulsanti “Oggi” e “chiudi”;
    • showOn buttonImage e buttonImageOnly che con il settaggio su proposto consentono di visualizzare a fianco della text box un bottone al cui click si attiva il calendario.
    Esistono poi una miriade di funzionalità aggiuntive, basta consultare le guide on line disponibili.