lunedì 29 aprile 2013

Script Ant per compilazione jasper report con groovy

In una web app con una serie di file jrxml creati con Groovy ecco uno script per la compilazione dei jrxml in modo da avere sempre i .jasper aggiornati.
I report sono stati creati con groovy, nel caso in cui fossero stati realizzati con Java standard allora si averebbe nella jrc come compiler la classe net.sf.jasperreports.engine.design.JRJdtCompiler invece della net.sf.jasperreports.compilers.JRGroovyCompiler.
I jrxml si trovano all'interno di una web app , sotto la directory reports.


 <project name="myProject" basedir="../" >
 <property file="ant/build.properties"/>
<target name="COMPILE-JASPER">
  <echo>Clean file jasper</echo>
  <delete verbose= "true" >
   <fileset dir="${webapp.target}/questionario" includes="*.jasper"/>
  </delete>
  <taskdef name="jrc" classname="net.sf.jasperreports.ant.JRAntCompileTask">
   <classpath refid="compile.classpath"/>
  </taskdef>
  <jrc srcdir ="${webapp.target}/questionario"
          destdir="${webapp.target}/questionario"
          keepjava="false"
          xmlvalidation="true"
          excludes="**/test/*.java,**/Test*.java,*.bak"
       compiler="net.sf.jasperreports.compilers.JRGroovyCompiler">
   <classpath refid="compile.classpath"/>
  </jrc>
 </target>

Lo script iniziale prevede la definizione di un file di properties build.properties dove sono definiti i valori del classpath e delle variabili a cui ci si riferisce nello script.



<?xml version="1.0" encoding="UTF-8"?>
<project>
 <property name="build.dir" value="${basedir}/build" />
 <property name="doc.dir" value="${basedir}/doc" />
 <property name="src" value="${basedir}/src" />
 <property name="test" value="${basedir}/test" />
 <property name="webapp.target" value="${basedir}/WebContent" />
 <property name="webapp.conf" value="${webapp.target}/conf" />
 <property name="webinf.dir" value="${webapp.target}/WEB-INF" />
 <property name="web.lib" value="${webinf.dir}/lib" />
 <property name="lib.lib" value="${basedir}/libProperties" />
 <property name="javac.debug" value="true" />
 <property name="compile.deprecation" value="true" />
 <property name="build.compiler" value="modern" />
 <property name="junit.fork" value="yes" />
 <property name="junit.showoutput" value="true" />
 <property environment="env" />
 <property name="env.COMPUTERNAME" value="${env.HOSTNAME}" />
 <property name="tomcat.home" value="${env.CATALINA_HOME}" />
 <property name="webapp.name" value="gianos-pro" />
 <property name="webapp.war" value="${webapp.name}.war" />
 <property name="webapp.ear" value="${webapp.name}.ear" />
 <property name="compile.jvm" value="1.6" />
 <property name="compile.debug" value="true" />
 <property name="compile.deprecation" value="false" />
 <property name="compile.optimize" value="false" />
 <path id="compile.classpath">
 .... altri jar utili al progetto .....
  <pathelement location="${web.lib}/jasperreports-4.7.0.jar"/>
  <pathelement location="${web.lib}/groovy-all-1.7.5.jar"/>
  <pathelement location="${web.lib}/jdt-compiler-3.1.1.jar"/>
  <pathelement location="${build.dir}/classes"/>
 </path>
</project>

sabato 27 aprile 2013

Windows 7 aggiungere messaggi custom allo start up del pc

Per inserire messaggi personalizzati all'avvio del pc bisogna modificare 2 chiavi nel registro di sistema.
Le chiavi sono :
  • legalnoticecaption;
  • legalnoticetext.
Da start digitare regedit quindi andare su HKEY_LOCAL_MACHINE/SOFTWARE/MICROSOFT/WINDOWS/CurrentVersion/Policies/System
Qui si trovano le due voci che si possono customizzare, la prima rappresenta l'intestazione dell'alert, la seconda il testo.
Saranno quindi sempre visibili al riavvio del sistema. Per rimuoverli è sufficiente cancellare il testo oppure cancellare direttamente le voci dal registro (per farlo è necessario essere amministratori del pc).


venerdì 26 aprile 2013

Web Service Rest con RestEasy

Resteasy è un framework realizzato da JBoss per realizzare servizi Rest (http://www.jboss.org/resteasy).
L'ho scaricato e testato su Tomcat 7, jdk 6 di riferimento.
Per realizzarlo ho creato una Web App, mettendo nella lib tutte le librerie del pacchetto tranne la el-api-1.0.jar, poichè andava in conflitto con le librerie di Tomcat 7 (linkage error).
Nel Web xml bisogna dichiarare la servlet di riferimento, in questo caso facciamo in modo che tutte le richieste che dopo il nome della web app hanno il suffisso /rest siano intercettate dalla servlet


<!-- Auto scan REST service -->
 <context-param>
  <param-name>resteasy.scan</param-name>
  <param-value>true</param-value>
 </context-param>
 
 <!-- this need same with resteasy servlet url-pattern -->
 <context-param>
  <param-name>resteasy.servlet.mapping.prefix</param-name>
  <param-value>/rest</param-value>
 </context-param>
 
 <listener>
  <listener-class>
   org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
  </listener-class>
 </listener>
 
 <servlet>
  <servlet-name>resteasy-servlet</servlet-name>
  <servlet-class>
   org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
  </servlet-class>
 </servlet>
 
 <servlet-mapping>
  <servlet-name>resteasy-servlet</servlet-name>
  <url-pattern>/rest/*</url-pattern>
 </servlet-mapping>
 

A questo punto dobbiamo scrivere il servizio Web.
Il servizio prende in input un intero e torna la lista dei numeri di Fibonacci fino a quell'intero assegnato.

Di seguito il codice


package it.test;
import java.util.ArrayList;
import java.util.List;
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;
import javax.ws.rs.core.Response;
@Path("/calculator")
public class MessageService {
 @GET
 @Path("/{param}")
 public Response printMessage(@PathParam("param") int val) {
        List<Integer> fibNumbers=fib(val);
  return Response.status(200).entity(listaNumeri(fibNumbers)).build();
 }
 @GET
 @Path("lista/{param}")
 @Produces(MediaType.TEXT_PLAIN)
 public String getListaNumeri(@PathParam("param")int val){
   List<Integer> fibNumbers=fib(val);
   return listaNumeri(fibNumbers);
 }
 private String listaNumeri(List<Integer> lista){
  StringBuffer sb=new StringBuffer();
  sb.append("[ ");
  for(int i=0;i<lista.size();i++){
   sb.append(lista.get(i));
   if(i<lista.size()-1)
   sb.append(",");
  }
  sb.append(" ]");
  return sb.toString();
 }
 private  List<Integer> fib(int n) {
  List<Integer> retList=new ArrayList<Integer>();
        int prev1=0, prev2=1;
        for(int i=0; i<n; i++) {
            int savePrev1 = prev1;
            retList.add(savePrev1);
            prev1 = prev2;
            prev2 = savePrev1 + prev2;
        }
        return retList;
}
 
}



Gli url per ragiungere i 2 servizi sono:
  • http://localhost:8080/restfacile/rest/calculator/15 (richiama il metodo printMessage);
  • http://localhost:8080/restfacile/rest/calculator/lista/15 (richiama il metodo getListaNumeri).

Si può testare il servizio sia da url direttamente che con un client Java.
Per realizzare il client Java ho creato un progetto java normale, mettendo nelle dipendenze le classi di resteasy + il jar commons-logging-1.1.1.jar (altrimenti avevo errore di ClassNotFoundException).

Di seguito il client:


package start;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import org.jboss.resteasy.client.ClientRequest;
import org.jboss.resteasy.client.ClientResponse;
public class RestEasyClient {
 public static void main(String[] args) throws Exception {
   
  ClientRequest request = new ClientRequest(
    "http://localhost:8080/restfacile/rest/calculator/lista/15");
  ClientResponse<String> risposta=request.get(String.class);
  if (risposta.getStatus() != 200) {
   throw new RuntimeException("Errore di tipo : "
    + risposta.getStatus());
  }
  BufferedReader br = new BufferedReader(new InputStreamReader(
   new ByteArrayInputStream(risposta.getEntity().getBytes())));
  String output;
  System.out.println("Output ottenuto .... \n");
  while ((output = br.readLine()) != null) {
   System.out.println(output);
  }
 }

}


Sql Server creare un database da file .bak

Con Sql Server 2008 per ripristinare su una istanza di db il back up di un back up (file con estensione .bak) si procede in questo modo:
Per prima cosa dal nodo database con il tasto destro del mouse selezionare l'opzione "Ripristina file e datagroup".

Dalla schermata che appare specificare il nome del db di destinazione (può essere già esistente o meno, nel caso non lo sia sarà generato da sql server).

Una volta specificato il database di destinazione, il dispositivo di origine (il file .bak) e selezionata la check box in basso, prima di procedere al back up occorre abilitare le impostazioni di sovrascrittura cliccando sulla sinistra in opzioni e quindi selezionando "Sovrascrivi il database esistente /WITH REPLACE)


Nel caso in cui non si avesse questa accortezza il back up andrà in errore dandoci un messaggio del tipo: "Il set di backup include un backup di un database diverso dal "nome_db" esistente"

giovedì 25 aprile 2013

Web Service name,portName e serviceName

Tramite annotation è possibile specificare e personalizzare il wsdl.
In particolare l'annotazione @javax.jws.WebService consente di impostare:
  • serviceName - il nome del servizio Web, per capirci quello che si trova come attributo del nodo padre "definitions";
  • name - l'attributo name del nodo portType (sezione contenente i dettagli generali delle operation esposte);
  • portName - l'attributo name del nodo binding (sezione contenente i dettagli specifici delle operation esposte).

mercoledì 24 aprile 2013

Sql Server express impostare la porta 1433 come default TCP/IP

Per poter raggiungere Sql Server tramite TCP/IP bisogna abilitare la funzionalità da Sql Server Configuration Manager.


Questo tuttavia non basta, di default infatti il server prende una porta casuale per cui si può incappare in problemi di connessione quando si prova a connettersi tramite datasource esterno (nel mio caso datasource definito su Tomcat).
E' necessario quindi andare con il tasto destro su TCP/IP poi su proprietà e quindi sul tab "Indirizzi IP" e quindi settare la porta nella sezione denominata "IP ALL".
A questo punto si può restartare il db e modificare il datasource in questo modo:



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

<Context>

  <Resource name="jdbc/gianospro"
  auth="Container"
  type="javax.sql.DataSource"
  factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
  testWhileIdle="true"
  testOnBorrow="true"
  testOnReturn="false"
  validationQuery="SELECT 1"
  validationInterval="30000"
  timeBetweenEvictionRunsMillis="30000"
  maxActive="100"
  minIdle="10"
  maxWait="10000"
  initialSize="10"
  removeAbandonedTimeout="60"
  removeAbandoned="true"
  logAbandoned="true"
  minEvictableIdleTimeMillis="30000"
  jmxEnabled="true"
  jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"
  username="root"
  password="admin"
  driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
  url="jdbc:sqlserver://127.0.0.1:1433;databaseName=nome_db"/>

</Context>



Abilitare telnet su Windows 7

Di default non è abilitato il servizio di telnet in Windows 7.
Per abilitarlo occorre andare in Pannello di controllo / Programmi /Attivazione/Disattivazione funzioni di Windows.
Nel dettaglio:




mercoledì 17 aprile 2013

Salvare un file in percorso temporaneo

Per utilizzare un percorso temporaneo è molto utile la variabile java.io.tmpdir, definita così

"java.io.tmpdir is a standard Java system property which is used by the disk-based storage policies. It determines where the JVM writes temporary files, including those written by these storage policies (see Section 4 and Appendix A.6). The default value is typically "/tmp" on Unix-like platforms."

 L'unica piccola seccatura è che a seconda del sistema operativo o anche della singola distribuzione nel mondo Linux il percorso può avere o non avere lo slash finale.

Di solito uso questo metodo per ottenere il percorso di un file temporaneo:


private static String getFileTempName(String nomeFile){
 StringBuffer sb=new StringBuffer();
 String td=System.getProperty("java.io.tmpdir");
 sb.append(System.getProperty("java.io.tmpdir"));
 if ( !(td.endsWith("/") || td.endsWith("\\")) ){
  sb.append(File.separator);
 }
 sb.append(nomeFile);
 log.debug("File temporaneo di salvataggio: "+sb.toString());
 return sb.toString();
 }

venerdì 12 aprile 2013

Web Service gestire zip file

Sotto il codice di realizzazione di un Web Service con un operation che, data in input una directory torna lo zip di tutti i file presenti dentro la directory stessa.
Tralasciando il codice di definizione del Web Service (si tratta di annotare una classe con @WebService e utilizzare @MTOM per ottimizzare il passaggio dati) il metodo è il seguente:

public DataHandler provaDownloadAllegati(String dir) throws Exception
 {
  
 File f=new File(dir);
 File filezip=new File(dir+File.separator+"result.zip");
 ZipOutputStream out = new ZipOutputStream(new FileOutputStream(filezip));
 if(f.isDirectory()){
   String[] fileNames=f.list();
   for(String s: fileNames)
   {
    log.debug("Zippo file "+s);
    if("result.zip".equals(s)){
     continue;
    }
    byte[] b=FileUtil.load(dir+File.separator+s);
    ZipEntry ze=new ZipEntry(s);
    out.putNextEntry(ze);
    out.write(b);
    out.closeEntry();
    
   }
   out.close();
   DataHandler retVal= new DataHandler(new FileDataSource(new File(dir+File.separator+"result.zip")));
   return retVal;
 }
 else
 {
   throw new Exception("Specificare path corretto directory");
 }
  
 }



Ho provato anche ad evitarmi il salvataggio su File System, tornando quindi solo lo stream, ma, pur tornandomi il dato con la size corretta, purtroppo lo stream risulta sempre corrotto, quindi non riesco ad aprirlo.
Posto il codice, non si sa mai se qualcuno ci sia riuscito


......
 ByteArrayOutputStream bos = new ByteArrayOutputStream();
 ZipOutputStream out = new ZipOutputStream(bos);
for(String s:fileNames){
         byte[] allegatoBytes=getBytesFromFileName(dir+file.separator+s);
         out.putNextEntry(new ZipEntry(s));
         out.write(allegatoBytes);
            out.closeEntry();
         }
  return bos.toByteArray();
......

Il metodo getBytesFromFileName è il seguente:


.....
 FileInputStream fin=new FileInputStream(new File(name));
 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 ex ){
.....gestire eccezione......
}


mercoledì 3 aprile 2013

Ant errore "com.sun.tools.javac.Main is not on the classpath. Perhaps JAVA_HOME does not point to the JDK."

Sono incappato in questo errore configurando un nuovo pc.
L'errore avveniva in fase di compilazione del build.xml di ant.
Per risolvere il problema da Eclipse  (trattasi di encoding non riconosciuto) occorre inserire l'opzione
-Dfile.encoding=Cp1252
Nel tab JRE , sezione VM arguments dell' "External Tool Configurations" dell'ant.