|
|
# **Printer**
|
|
|
|
|
|
## Not interruptible printjobs
|
|
|
As the `javax.print` library has major shortcomings if using the byte stream mode, it currently throws a `NullPointerException` if someone tries to interupt it via java code (the spoolersystem is not affected). To ensure it is not a bug in our system, i investigated this further and looked up the implementation of `javax.print'. I came to the conclusion that the bug is located in the library. I opened a Bug report in the oracle bug database, which confirmed my assumption:
|
|
|
|
|
|
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8230640
|
|
|
|
|
|
It is currently not fixed, and oracle makes no guarantees as when this bug is fixed.
|
|
|
|
|
|
## Eventlistener for printing is missleadingly called
|
|
|
This issue arises also from the same `javax.print` library. I tried to log the current state of the printing job according to the given interface (taken from **PrintDirector **class):
|
|
|
```java
|
|
|
private class PrintJobListener implements javax.print.event.PrintJobListener {
|
|
|
boolean done = false;
|
|
|
|
|
|
@Override
|
|
|
public void printDataTransferCompleted(final PrintJobEvent pje) {
|
|
|
mLogger.info("Data transfer to printer complete");
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void printJobCompleted(final PrintJobEvent pje) {
|
|
|
mLogger.info("Printjob completed");
|
|
|
synchronized (PrintJobListener.this) {
|
|
|
done = true;
|
|
|
PrintJobListener.this.notify();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void printJobFailed(final PrintJobEvent pje) {
|
|
|
mLogger.info("Printjob failed");
|
|
|
synchronized (PrintJobListener.this) {
|
|
|
done = true;
|
|
|
PrintJobListener.this.notify();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void printJobCanceled(final PrintJobEvent pje) {
|
|
|
mLogger.info("Printjob was canceled");
|
|
|
synchronized (PrintJobListener.this) {
|
|
|
done = true;
|
|
|
PrintJobListener.this.notify();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void printJobNoMoreEvents(final PrintJobEvent pje) {
|
|
|
mLogger.info("Printjob has no more events");
|
|
|
synchronized (PrintJobListener.this) {
|
|
|
done = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void printJobRequiresAttention(final PrintJobEvent pje) {
|
|
|
mLogger.info("Printjob requires attention");
|
|
|
PrintJobListener.this.notify();
|
|
|
}
|
|
|
public synchronized void waitForDone() {
|
|
|
try {
|
|
|
// Not busy waiting, sleeping as long as not notified.
|
|
|
while (!done) {
|
|
|
wait();
|
|
|
}
|
|
|
} catch (InterruptedException e) {
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
```
|
|
|
But the events are fired not when you would assume the would. For example the "Data transfer complete" is fired as soon as you make the print call to the library, not when the data transmission to the printer is actually done. The same goes for all the events. Funny enough, the printJobCompleted event is never recieved, even when the printer has printed the document. As the code for the events would need major restruction and refactoring (meaning the `javax.print` code), we can not give further information about the printing state, as we cannot modify the library itself.
|
|
|
|
|
|
## Printjobs on *nix (using CUPS) are split into separate printjobs
|
|
|
|
|
|
This issue only arises when using CUPS for printing. It does not arise for normal printjobs, which is important. The typical size of an printjob via `NORMALPRINT` is in order of bytes, rarely in kilo bytes.
|
|
|
|
|
|
But when using the floatingdot mode, you can expect the printjob will be much bigger, nearly always in the order of kilo bytes. It is especially critically because it just cuts in the middle of a document. For a normal printing mode, this is not a big deal.
|
|
|
But when you cut the floatingdot printjob, you dont append the needed escape sequences to indicate the floatingdot mode, resulting in the printer interpreting the coordinates not as coordinates, but as simple text. This is especially bad if you have ~3000 coordinates, as it rsults in over 200 printjobs.
|
|
|
The current workaround is as follows (taken form the App class):
|
|
|
```java
|
|
|
if (!applyWorkaround) {
|
|
|
printD.print(page);
|
|
|
} else {
|
|
|
mLogger.warn("Currently a workaround is applied for printer communication. Expect a waiting time of up to 100 seconds between document pages. Disable with option -npw");
|
|
|
Thread printingThread = new Thread(() -> {
|
|
|
mLogger.debug("Started printing thread");
|
|
|
printD.print(page);
|
|
|
mLogger.debug("Print call returned");
|
|
|
});
|
|
|
printingThread.start();
|
|
|
while (printingThread.isAlive()) {
|
|
|
final int reduceBusinessWaitingTime = 100;
|
|
|
Thread.sleep(reduceBusinessWaitingTime);
|
|
|
}
|
|
|
mLogger.debug(printingThread.getName() + " has finished.");
|
|
|
try {
|
|
|
final int waitBetweenJobs = 100000;
|
|
|
Thread.sleep(waitBetweenJobs);
|
|
|
} catch (InterruptedException e) {
|
|
|
e.printStackTrace();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
pageNumber++;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
As you can see, we apply bussy waiting in a new thread which handles the printingjob creation. We cannot attach a eventlistener to the printing state (which would be a for more preferred solution) as the firing of these events are missleading (see above issue: Eventlistener for printing is missleadingly called). Therefore, we hope that no printjob will take more thann 100 seconds to finish. |
|
|
\ No newline at end of file |