How to get a notification from the printer when a physical page / job is complete

I want to be notified from a network printer when it physically finishes printing a page (and / or the entire job). This will be used in an application I am writing to manage web printing and since users are charged per page and the fee should not be lowered until the page is actually completed.

I'm not sure if this requires writing a driver, some kind of plug-in, or if there will be a client application. I am flexible with my platform as my client has not been written yet, so I would love to hear about any suitable solution on Windows or Linux in any programming language / level.

I know there is a difference between a buffer and a printer. I am trying to check at what level the printer can notify the machine via IPP when a page or physical job is complete.

I am currently browsing Java using jspi or cups4j to get notified when an IPP property job-impressions-completed

has changed, or alternatively a poll. I am using the CUPS IPP interface for a local printer. By running a simple tester ( HelloPrint.java

attached below, or CupsTest.java

included in cups4j), I didn't get any attribute changes job-impressions-completed

or list the attribute to assign when polled.

So here are the questions:

  • Do it right? If not, how should I do it?
  • Since this is a CUPS interface for a local printer, it may be that the attribute is job-impressions-completed

    not updated, in particular since it acts as a spooler for the real printer. Assuming a real printer will notify or enumerate this attribute, would this be specific to a specific printer, or should this attribute be available and updated for any IPP-enabled printer?

System Information: Ubuntu 11.10, CUPS 1.5.0, Brother HL-2240D Printer ( PPD available here )

Note. The HL-2240D is not the printer that I will be using for a possible project (in particular, it does not support IPP); I intend to use either the HP HL4250DN or Samsung 3741ND or similar.

Here's a sample app using packages javax.print

and jspi:

HelloPrint.java

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Date;

import javax.print.*;
import javax.print.attribute.*;
import javax.print.attribute.standard.*;
import javax.print.event.*;

import de.lohndirekt.print.IppPrintService;

public class HelloPrint {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // create request attributes
        PrintRequestAttributeSet requestAttributeSet = new HashPrintRequestAttributeSet();
        requestAttributeSet.add(MediaSizeName.ISO_A4);
        requestAttributeSet.add(new Copies(1));
        requestAttributeSet.add(Sides.DUPLEX);

        // find an appropriate service
        // using jspi (http://code.google.com/p/jspi/)
        URI printerURI;
        try {
            printerURI = new URI("ipp://localhost:631/printers/HL2240D-local");
        } catch (URISyntaxException e2) {
            e2.printStackTrace();
            return;
        }
        IppPrintService service = new IppPrintService(printerURI);

        // by enumerating       
        //      PrintService[] services = PrintServiceLookup.lookupPrintServices(
        //              DocFlavor.INPUT_STREAM.PDF, requestAttributeSet);
        //      for (PrintService service1 : services) {
        //          System.out.println(service1);
        //      }
        //      PrintService service = services[0];

        // add listeners to service
        service.addPrintServiceAttributeListener(new PrintServiceAttributeListener() {
            @Override
            public void attributeUpdate(PrintServiceAttributeEvent event) {
                PrintServiceAttributeSet serviceAttributeSet = event
                        .getAttributes();
                StringBuilder s = new StringBuilder();
                s.append("=== PrintServiceAttributeEvent: (" + serviceAttributeSet.size() + " attributes)\n");
                for (Attribute attribute : serviceAttributeSet.toArray()) {
                    PrintServiceAttribute printServiceAttribute = (PrintServiceAttribute) attribute;

                    s.append(printServiceAttribute.getCategory().getName()
                            + "/" + printServiceAttribute.getName() + " = "
                            + printServiceAttribute.toString() + "\n");

                }
                System.out.println(s.toString());
            }
        });

        // add file (blank.pdf is a blank page exported as PDF from LibreOffice
        // Writer)
        FileInputStream inputStream;
        try {
            inputStream = new FileInputStream("blank.pdf");
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return;
        }

        // create a new doc and job
        DocAttributeSet docAttributeSet = new HashDocAttributeSet();
        docAttributeSet.add(MediaSizeName.ISO_A4);
        docAttributeSet.add(Sides.DUPLEX);

        Doc doc = new SimpleDoc(inputStream, DocFlavor.INPUT_STREAM.PDF,
                docAttributeSet);

        DocPrintJob job = service.createPrintJob();

        // listen to print job attribute change events
        // attribute set is null, means this means to listen on all dynamic
        // attributes that the job supports.
        job.addPrintJobAttributeListener(new PrintJobAttributeListener() {
            @Override
            public void attributeUpdate(PrintJobAttributeEvent event) {
                PrintJobAttributeSet jobAttributeSet = event.getAttributes();
                StringBuilder s = new StringBuilder();
                s.append("=== PrintJobAttributeEvent: (" + jobAttributeSet.size() + " attributes)\n");
                for (Attribute attribute : jobAttributeSet.toArray()) {
                    PrintJobAttribute jobAttribute = (PrintJobAttribute) attribute;

                    s.append(jobAttribute.getCategory().getName() + "/"
                            + jobAttribute.getName() + " = "
                            + jobAttribute.toString() + "\n");

                }
                System.out.println(s.toString());

            }
        }, null);

        // listen to print job events
        job.addPrintJobListener(new PrintJobListener() {

            @Override
            public void printJobRequiresAttention(PrintJobEvent pje) {
                System.out.println("=== PrintJobEvent: printJobRequiresAttention");
            }

            @Override
            public void printJobNoMoreEvents(PrintJobEvent pje) {
                // TODO Auto-generated method stub
                System.out.println("=== PrintJobEvent: printJobNoMoreEvents");
                System.out.println(pje.getPrintEventType());
                System.out.println(pje.toString());
            }

            @Override
            public void printJobFailed(PrintJobEvent pje) {
                // TODO Auto-generated method stub
                System.out.println("=== PrintJobEvent: printJobFailed");
                System.out.println(pje.getPrintEventType());
                System.out.println(pje.toString());
            }

            @Override
            public void printJobCompleted(PrintJobEvent pje) {
                // TODO Auto-generated method stub
                System.out.println("=== PrintJobEvent: printJobCompleted");
                System.out.println(pje.getPrintEventType());
                System.out.println(pje.toString());
            }

            @Override
            public void printJobCanceled(PrintJobEvent pje) {
                // TODO Auto-generated method stub
                System.out.println("=== PrintJobEvent: printJobCanceled");
                System.out.println(pje.getPrintEventType());
                System.out.println(pje.toString());
            }

            @Override
            public void printDataTransferCompleted(PrintJobEvent pje) {
                System.out.println("=== PrintJobEvent: printDataTransferCompleted");
                System.out.println(pje.getPrintEventType());
                System.out.println(pje.toString());
            }
        });

        // print
        try {
            job.print(doc, requestAttributeSet);
        } catch (PrintException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
            return;
        }

        // try polling
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                return;
            }

            System.out.println("=== Polling: I'm alive and it " + new Date());
            System.out.println("Job attributes");
            for (Attribute attribute : job.getAttributes().toArray()) {
                System.out.println((attribute.getCategory().getName() + "/"
                        + attribute.getName() + " = " + attribute.toString()));
            }
            System.out.println("Service attributes");
            for (Attribute attribute : service.getAttributes().toArray()) {
                System.out.println((attribute.getCategory().getName() + "/"
                        + attribute.getName() + " = " + attribute.toString()));
            }
        }
    }

}

      

+3


source to share


1 answer


In the end, it all depends on the printer firmware. The IPP specifies the attribute display job - complete as optional . This means that if the printer cannot determine which page was printed, you cannot read it - regardless of whether you program correctly.

Vendors usually declare support for IPP, but do not document very well the additional components they might (or might not) implement.

Before doing any programming, I suggest reading all the available assignments using the ones ipptool

available from CUPS:



#!/usr/bin/env ipptool -tv -d job=482 ipp://192.168.2.113/ipp
{
OPERATION Get-Job-Attributes
GROUP operation-attributes-tag
ATTR charset attributes-charset utf-8
ATTR language attributes-natural-language en
ATTR uri printer-uri $uri
ATTR integer job-id $job
}

      

job-state

attribute is mandatory and some time must reach the final state: completed

, aborted

, or canceled

. It might be good enough if you can get the number of working pages elsewhere :-)

+2


source







All Articles