javaprintingappletzkzul

Unable to get default printer name while using applet - ZK Framework


I want to print my file directly from webpage. For that I am using following reference and trying to implement same with ZUL and Composer.

http://tonny-bruckers.blogspot.in/2012/11/printing-files-directly-from-web-page.html

ZUL File :-

<zk>
<applet code = "PrintApplet.class" codebase = "applet/" id="printApplet" width="400px" style="border: 1px" />
<button id="btnClickMe" label="Click Me" sclass="light-btn"/>
</zk>

PrintApplet.class is present inside "WebContent/applet".

public class AppletComposer extends GenericForwardComposer<Window> {
    private Applet printApplet;
    public void doOverrideAfterComposer(Window comp) throws Exception {

    }
    public void onClick$btnClickMe(Event event) throws Exception {
        String Originalstr = "ByteArrayInputStream Example!";
        byte[] Originalbytes = Originalstr.getBytes();
        ByteArrayInputStream bis=new ByteArrayInputStream(Originalbytes);
        printApplet.invoke("print", bis);
    }
}

PrintApplet Class :-

public class PrintApplet extends Applet {
    public void init() 
    {

    }
    public void print(ByteArrayInputStream bis) throws PrintException 
    {
        PrintService service = PrintServiceLookup.lookupDefaultPrintService();
        if (service != null) {
            DocFlavor psFormat = DocFlavor.INPUT_STREAM.PDF;
            PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet();    
            DocPrintJob job = service.createPrintJob();
            Doc pdfDoc = new SimpleDoc(bis,psFormat, null);
            job.print(pdfDoc, attributes);         
        }
    }
}

I am able to invoke PrintApplet with this approach but getting Null as service. PrintApplet is working fine with AppletViewer and with normal Java Application but unable to get default printer service while using the above approach.


Solution

  • First I want to mention that APPLET IS ALWAYS RUN ON CLIENT SIDE and APPLET only communicates to the server which from it is downloaded.

    That’s why we have to specify codebase directory, so that we can download the applet on client browser by then JAVA Platform Environment plugin from browser takes on control, which in turn run on client JRE environment.

    So we have to be very carefully that JDK environment is installed properly. To trace applet log we can use of java applet console tool ‘jconsole’.


    Steps for APPLET to run properly on client browser :

    1. At browser (firefox,chrome,opera) check whether JAVA Platform plugin is there or not, because to run applet from the browser we require that plugin installed and enabled.

      If you are working on linux machine: than it is bit complex, You can find how to enable plugin for LINUX-BROWSER from here:

      http://www.oracle.com/technetwork/java/javase/manual-plugin-install-linux-136395.html

    2. Enable console log for applet, when it executes on client JRE, we can look into it for tracing.

      Path : JDK_DIR/bin/jcontrol

      [JControl Window][1]

      For only development purpose: you can lower the security

    3. We have to clear the cache of applet, every time we build new applet, to reflect the latest change we need to clear the cache first, otherwise it'll load cached applet class.

      To clear we can use 'javaws -viewer'

      Path : JAVA_HOME/bin/javaws -viewer

      [Clear Applet Cache][2]


    As per your code, your server side code (zul and composer) are perfect but the problem is at applet code.

    You are looking for a default printer in print() method, which are one time configuration codes. It has to be in init().

    PrintApplet.java

    public class PrintApplet extends Applet {
    
     private static final long serialVersionUID = 1L;
     private PrintService service;
    
     public void init() 
     {
        JOptionPane.showMessageDialog(null, "Inside INIT()");
        if(null==service){
            service = PrintServiceLookup.lookupDefaultPrintService();
            System.out.println(service.getName());
        } else {
            System.out.println(service.getName());
        }
     }
     public void print(String str) throws PrintException 
     {
        JOptionPane.showMessageDialog(null, "Inside print()");
        JOptionPane.showMessageDialog(null, "String is:::"+str);
        cPrint cP = new cPrint(str, service);
        System.out.println((Integer) AccessController.doPrivileged(cP));
     }
    }
    

    And you need another implementation of AccessController to give access to the default printer locate and print.

    cPrint.java

    class cPrint implements PrivilegedAction<Object> {
     String str;
     PrintService service;
    
     public cPrint(String str, PrintService argPrintService) {
    
        this.str = str;
        this.service = argPrintService;
    
     };
     public Object run() {
        // privileged code goes here
        InputStream is = null;
        try 
        {
            JOptionPane.showMessageDialog(null, "String is:::"+str);
            byte[] Originalbytes = str.getBytes();
            JOptionPane.showMessageDialog(null, "Original bytes:::"+Originalbytes);
            is=new ByteArrayInputStream(Originalbytes);
            FileWriter fstream = new FileWriter("/home/test/out.pdf");  
            BufferedWriter out = new BufferedWriter(fstream);  
            for (Byte b: Originalbytes) {  
                out.write(b);  
            }  
            out.close();
            DocPrintJob printJob = service.createPrintJob();
            Doc doc;
            DocAttributeSet docAttrSet = new HashDocAttributeSet();
            PrintRequestAttributeSet printReqAttr = new HashPrintRequestAttributeSet();
            doc = new SimpleDoc(is, DocFlavor.INPUT_STREAM.AUTOSENSE, docAttrSet);
            PrintJobWatcher pjDone = new PrintJobWatcher(printJob);
            printJob.print(doc, printReqAttr);
            pjDone.waitForDone();
            // It is now safe to close the input stream
            is.close();
         } 
         catch (Exception e) {
            e.printStackTrace();
            System.out.println(e);
            return 1;
         } 
        return 0;
      }
      static class PrintJobWatcher {
        // true iff it is safe to close the print job's input stream
        boolean done = false;
    
        PrintJobWatcher(DocPrintJob job) {
            // Add a listener to the print job
            job.addPrintJobListener(new PrintJobAdapter() {
                public void printJobCanceled(PrintJobEvent pje) {
                    allDone();
                }
                public void printJobCompleted(PrintJobEvent pje) {
                    allDone();
                }
                public void printJobFailed(PrintJobEvent pje) {
                    allDone();
                }
                public void printJobNoMoreEvents(PrintJobEvent pje) {
                    allDone();
                }
                void allDone() {
                    synchronized (PrintJobWatcher.this) {
                        done = true;
                        PrintJobWatcher.this.notify();
                    }
                }
            });
        }
        public synchronized void waitForDone() {
            try {
                while (!done) {
                    wait();
                }
            } catch (InterruptedException e) {
            }
        }
     }
    }
    

    cPrint(str,PrintService)

    Where str can be file name if you want file to be print, or byte array string.

    Here in my example, I expected byte array, so I create pdf file from byte array given by the applet from the composer and then it'll sent to the default printer to the given PrintService.

    So Actual flow for applet in zk to get access for default printer and to print is by this [graph][3].