sabato 16 novembre 2013

Java7 watch service

Una feature molto utile è quella del WatchService, che consente di registrare una directory e notificare ogni evento che viene compiuto su di essa (es. inserimento nuovi file, cancellazioni file,modifiche eccetera).
Si ottiene questo risultato seguendo la seguente serie di passaggi logici:
  1. Ottenere un'istanza del WatchService dalla classe FileSystem;
  2. Registrare la directory di interesse, specificando nei varargs tutti gli eventi per cui si vuole registrarla;
  3. Effettuare un loop infinito dove si attendono gli eventi. Si utilizza il metodo take() per ottenere l'evento appena disponibile. La chiamata a take() è bloccante, se si vuole invece la versione non bloccante bisogna invocare il poll();
  4. Una volta ottenuto l'evento di tipo WatchKey si cicla tra tutti gli eventi disponibili per ottenere quello di interesse;
  5. Una volta processato l'evento si resetta la chiave (key.reset() nel codice), senza questo passaggio soltanto il primo evento nella directory sarà registrato.
Vediamo il codice:

package it.test;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
public class ObserveDirChanges {

 public static void main(String[] args) {
  Path p=Paths.get("c:\\excel");
  WatchService ws=null;
  try
  {
ws=p.getFileSystem().newWatchService();
p.register(ws, StandardWatchEventKinds.ENTRY_CREATE,StandardWatchEventKinds.ENTRY_DELETE,StandardWatchEventKinds.ENTRY_MODIFY,StandardWatchEventKinds.OVERFLOW);
for(;;){
WatchKey key=null;
try
{
key=ws.take();
}
catch(InterruptedException ex){
ex.printStackTrace();
}
for(WatchEvent<?> event:key.pollEvents()){
switch(event.kind().name()){
 case "OVERFLOW":
 System.out.println("Attenzione è andato perduto un evento");
 break;
 case "ENTRY_MODIFY":
 System.out.println("File "+event.context()+" modificato");
 break;
 case "ENTRY_CREATE":
 System.out.println("File "+event.context()+" creato");
 break;
 case "ENTRY_DELETE":
 System.out.println("File "+event.context()+" cancellato");
 break;
 }
 key.reset();
    }
      }
  }
  catch(IOException e){
   e.printStackTrace();
  }

 }

}


JAVA 7 ottenere informazioni su data creazione file

Con le nuove API è possibile ottenere semplicemente molte informazioni sulla natura dei file.
Nel seguente esempio vediamo come ottenere queste informazioni utilizzando l'interfaccia java.nio.file.attribute.BasicFileAttributes.


package it.test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
public class CheckAttributiFile {
 public static void main(String[] args) {
  Path p=Paths.get("c:\\excel\\2_BAHIA.xls");
  try
  {
BasicFileAttributes fileAttributes=Files.readAttributes(p, BasicFileAttributes.class);
System.out.println("Size: "+fileAttributes.size());
System.out.println("Directory: "+fileAttributes.isDirectory());
System.out.println("File normale: "+fileAttributes.isRegularFile());;
System.out.println("Link simbolico: "+fileAttributes.isSymbolicLink());
System.out.println("Ultima modifica: "+fileAttributes.lastModifiedTime());
System.out.println("Ultimo accesso:"+fileAttributes.lastAccessTime());
System.out.println("Data creazione file: "+fileAttributes.creationTime());
  }
  catch (IOException e) {
   e.printStackTrace();
  }
 }
}


 Il risultato è il seguente:

Size: 5120
Directory: false
File normale: true
Link simbolico: false
Ultima modifica: 2013-08-08T09:04:30.744618Z
Ultimo accesso:2013-04-04T06:56:47.668827Z
Data creazione file: 2013-04-04T06:56:47.668827Z

Java 7 classe java.nio.file.Files esempio creazione link simbolico

Con  la classe Files si può fare praticamente di tutto a livello di file system con semplici ed intuitivi metodi.
Vediamo come creare e testare la creazione di un link simbolico:

package it.test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class FilesExample {
 public static void main(String[] args) throws IOException{
  Path p3=Paths.get("C:\\lav\\testFile\\simbolicLink.txt");
  Path p4=Paths.get("C:\\lav\\testFile\\fileReale.txt");
  System.out.println(Files.createFile(p4));
  Files.createSymbolicLink(p3, p4);
  System.out.println(Files.isSymbolicLink(p3));
  
 }
 
}


Andando sulla directory del filesystem via dos vedremo quindi:

JAVA NIO package interfaccia Path

Con java 7 abbiamo un package java.nio.file con interessanti feature per lo scandagliamento del file System.
Una di queste è rappresentato dall'interfaccia java.nio.Path che consente di ottenere molte informazioni con metodi semplici ed intuitivi.
Si crea una implementazione di tale interfaccia chiamando il metodo statico get sulla classe Paths.
Esempio:

package it.test;
import java.nio.file.Path;
import java.nio.file.Paths;
public class PathExample {
public static void main(String[] args) {
  Path p=Paths.get("c:\\lav\\trash\\prof");
  System.out.println(p.getFileName());
        System.out.println(p.getRoot());
        System.out.println(p.getParent());
        for(Path element:p){
         System.out.println(element.toString());
        }
 }

}



Ci fornisce l'output seguente:

prof
c:\
c:\lav\trash
lav
trash
prof

In questo altro esempio ho preso il path relativo al progetto Java di test, utilizzando anche ulteriori metodi dell'interfaccia come il toAbsolutePath() o il toUri().

package it.test;
import java.io.IOException;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
public class PathExample {
public static void main(String[] args) throws IOException {
  Path p=Paths.get("src");
  System.out.println("File name: "+p.getFileName());
        System.out.println("Root: "+p.getRoot());
        System.out.println("Parent: "+p.getParent());
        for(Path element:p){
         System.out.println(element.toString());
        }
        System.out.println("Absolute path: "+p.toAbsolutePath());
        System.out.println("Uri: "+p.toUri());
        System.out.println("Path normalized:"+p.normalize().toString());
        System.out.println("Real path: "+p.toRealPath(LinkOption.NOFOLLOW_LINKS));
        
 }

}


Risultato:

File name: src
Root: null
Parent: null
src
Absolute path: C:\lav\workspace\wsTest\Java7Cert\src
Uri: file:///C:/lav/workspace/wsTest/Java7Cert/src/
Path normalized:src
Real path: C:\lav\workspace\wsTest\Java7Cert\src

In particolare:
  • toUri() ritorna un path che può essere aperto da un browser ;
  • toAbsolutePath() ritorna il path assoluto dato un path relativo;
  • normalize() rimuove simboli non necessari (es. "." e "..");
  • toRealPath() ritona il path assoluto e normalizzato e può risolvere anche i symbolic link (nel caso in esame usando l'opzione NOFOLLOWLINKS è stato scelto di non considerare i link simbolici. A differenza degli altri metodi esposti però se il file non esiste fisicamente lancia una eccezione tipo IOException.
E' possibile anche effettuare delle comparazioni tra path, ed esistono 2 metodi:
  • compareTo che effettua un confronto puramente lessicografico e torna 0 se i path sono uguali;
  • equals() che effettua un confronto reale tra i path (ma bisogna accertarsi che i percorsi di entrambi i path siano percorsi assoluti).
Esempio:

 // comparing paths
        Path p2=Paths.get("C:\\lav\\workspace\\wsTest\\Java7Cert\\src");
        System.out.println(p.compareTo(p2)==0?"OK":"KO");
        System.out.println(p.equals(p2));
        System.out.println(p.toAbsolutePath().equals(p2));

In questo caso ci torna prima KO, poi false e poi true (quando si confrontano i path entrambi assoluti).

mercoledì 13 novembre 2013

Primefaces p:dialog problemi nel submit ajax

Utilizzando primefaces 3.5 ho avuto il seguente problema.
Avevo un form principale che richiamava un p:dialog.
Il p:dialog si vedeva sempre con i campi in grigetto e non riuscivo quindi ad effettuare l'update.
Ho usato quindi la proprietà appendToBody="true" che effettivamente consentiva la visualizzazione corretta del form ma i valori dei campi non passavano in request (il bean aveva scope di tipo view).
A questo punto per risolvere il tutto ho messo tutto il p:dialog all'interno di un form separato e fuori dal form principale (occhio che definire form innestati provoca problemi in alcuni browser) e a questo punto tutto ho potuto rimettere il valore di default appendToBody e tutto ha funzionato correttmaente.
Incollo sotto l'xhtml del p:dialog:

<ui:composition 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:form id="ghersi">
    <p:dialog id="parametrizzazioneGi" widgetVar="par020WidgetVar" appendToBody="false"
       closable="true" resizable="true" draggable="true" modal="true" 
                width="600" height="250" header = "#{msg['paramGi']}" dynamic="true">
              <table>
              <tr><td>#{msg['codInt']}</td>
              <td> 
              <p:inputText id="codiceInterno" value="#{par020.codiceInterno}" maxlength="5" size="10"></p:inputText>
              </td>
              </tr>
              <tr><td>#{msg['codOgg']}</td>
              <td> 
              <p:inputText id="codiceOggetto" value="#{par020.codiceOggetto}" maxlength="30" size="40"></p:inputText>
              </td>
              </tr>
               <tr><td>#{msg['dtUltElabor']}</td>
              <td> 
              <p:inputText id="dtUltElab" value="#{par020.dataUltimaElaborazione}" maxlength="9" size="18"></p:inputText>
              </td>
              </tr>
               <tr><td>#{msg['schedPar']}</td>
              <td> 
              <p:inputText id="schedaParam" value="#{par020.schedaParametro}" maxlength="80" size="45"></p:inputText>
              </td>
              </tr>
              <tr>
              <td colspan="2">
              <p:commandButton id="insertParam" value="Inserimento" icon="ui-icon-arrowreturnthick-1-w"  
          actionListener="#{par020.insert}"   
             style="margin-top:15px;margin-right:5px;color:white;background:#868686;"
             update=":mainForm:parametri :mainForm:messages " oncomplete="par020WidgetVar.hide()" /> 
              </td>
              </tr>
              </table>
              
  </p:dialog>
    </h:form>
    </ui:composition>


lunedì 11 novembre 2013

Internet Explorer evitare messaggio sul window.close()

Con questo javascript si riesce ad evitare che richiamando il window.close() sia chiesta conferma all'utente della volontà di chiudere la finestra.
Il messaggio di conferma viene richiesto perchè c'è solo una finestra di tipo parent, per cui si avvisa in quanto chiuderla significa praticamente chiudere il browser.
Per evitare il problema ho trovato qui un trucco utile.
La funzione window.open ha la seguente firma:
window.open(URL,name,specs,replace)
I valori di name possono essere:
    _blank - Il caricamento dell'URL avviene in una nuova finestra
    _parent - Il caricamento dell'URL avviene nel frame parent
    _self - Il caricamento dell'url rimpiazza l'url corrente
    _top - Il caricamento dell'url rimpiazza qualsiasi frameset caricato
    name - il nome della finestra
Si imbroglia IE aprendo una pagina vuota superiore nella stessa pagina e quindi richiudendola.
Il valore true nel parametro replace indica che sostituisce il valore nella history.
Il parametro specs, qui lasciato vuoto, serve a specificare eventuali caratteristiche grafiche della finestra.
Così:

var win=window.open("","_top","","true");
win.opener=true;
win.close(); 


giovedì 7 novembre 2013

Determinare data creazione di un file

Dalla versione JDK 7 ci sono le API apposite di java.nio.
Con la jdk 1.6 si può procedere così (funziona in sistemi windows non l'ho testato su linux):


File f=new File("c:\\lav\\popso.txt");
SimpleDateFormat sdf=new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
Date d=new Date(f.lastModified());
System.out.println(sdf.format(d));