giovedì 23 maggio 2013

Stampare PDF da AjaxLink

Chi usa Wicket con Internet Explorer 7 o 8 potrà essere incappato nel problema del caching dei link. Questo genera varie problematiche, una delle quali riguarda gli applicativi che permettono di stampare file PDF alla pressione di un link.
Il sistema di cache tende infatti a non far lanciare a Wicket la onClick del link con la conseguenza che eventuali variazioni sui dati avvenuti in seguito, per esempio, ad un filtro su una form, non venissero recepiti dalla funzione di creazione PDF che stampava quindi i vecchi risultati.

La soluzione in questione permette di introdurre il concetto di stampa PDF anche da AjaxLink. Questo risolve la problematica di cui sopra perché l'Ajax Link non viene riconosciuto come componente analogo e quindi non entra nella cache.

Per realizzare questo, basta creare la seguente classe:



import java.io.InputStream;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.AbstractAjaxBehavior;
import org.apache.wicket.request.Response;
import org.apache.wicket.request.handler.resource.ResourceStreamRequestHandler;
import org.apache.wicket.request.http.WebResponse;
import org.apache.wicket.request.resource.ContentDisposition;
import org.apache.wicket.util.resource.AbstractResourceStreamWriter;
import org.apache.wicket.util.resource.IResourceStream;

public class AJAXFileDownload extends AbstractAjaxBehavior
{
 private static final long serialVersionUID = 1L;
 private boolean addAntiCache;
 private String fileName;
 private InputStream is;

    public AJAXFileDownload() {
     this(true);
 }
     
 public AJAXFileDownload(boolean addAntiCache) {
     super();
     this.addAntiCache = addAntiCache;
 }

 /**
  * Call this method to initiate the download.
  */
  public void initiate(AjaxRequestTarget target, String fileName, InputStream is) { 
         this.fileName = fileName; 
         this.is = is; 
         String url = getCallbackUrl().toString(); 

         if (addAntiCache) { 
             url = url + (url.contains("?") ? "&" : "?"); 
             url = url + "antiCache=" + System.currentTimeMillis(); 
         } 

         // the timeout is needed to let Wicket release the channel 
         target.appendJavaScript("setTimeout(\"window.location.href='" + url + "'\", 100);"); 
     } 

 public void onRequest() {
  ResourceStreamRequestHandler handler = new ResourceStreamRequestHandler(getResourceStream(), getFileName());
  handler.setContentDisposition(ContentDisposition.ATTACHMENT);
  getComponent().getRequestCycle().scheduleRequestHandlerAfterCurrent(handler);
 }
 
 protected String getFileName() {
  return this.fileName;
 }

 /**
  * Hook method providing the actual resource stream.
  */
    protected IResourceStream getResourceStream() { 
        return new AbstractResourceStreamWriter() { 
   private static final long serialVersionUID = 1L;
   public void write(Response output) { 
                WebResponse response = (WebResponse)output; 
                byte[] buffer = new byte[256]; 
                try { 

                    int read; 
                    while((read = is.read(buffer)) != -1) { 
                        response.write(buffer, 0, read); 
                        response.flush(); 
                    } 
                    response.close(); 

                } catch (Exception e) { 
                    response.write(e.toString().getBytes()); 
                    response.close(); 
                } 
            } 
        }; 
    } 
}
Usarla è molto semplice.
//Istazione l'oggetto di cui sopra
final AJAXFileDownload fileDownload = new AJAXFileDownload(); 

AjaxLink printLink = new AjaxLink("stampa"){
   public void onClick(AjaxRequestTarget target) {
      
       //operazioni per avere il contenuto del PDF
       final byte[] pdf = creaPDFinQualcheModo();

       fileDownload.initiate(target, "nomefile.pdf", new ByteArrayInputStream(pdf));
   }
};

printLink.add(fileDownload);

add(printLink); //aggiungo il link al componente padre
In questo modo potete generare tutti i PDF che volete.