# Vom Server aus drucken



## inv_zim (7. Jun 2012)

Hallo,

nachdem ich mich jetzt ein paar Monate in die Materie eingearbeitet habe, bin ich gerade vor einer Design-Entscheidung etwas unsicher, und frage euch lieber mal. Im Betrieb baue ich gerade eine Enterprise Anwendung mit Primefaces auf, was auch gut funktioniert. In der Anwendung können diverse Berichte abgerufen werden, welche auf einem Jasper Reports Server als PDF generiert werden, und vom der Anwendung nur noch parametrisiert abgerufen werden sollen. Dazu gehören auch Etiketten für die Produktion.

Ausdrucke aus einer Web Anwendung kann ich ja lediglich an den Browser übergeben, aber wenn ich die Anwender jedes mal noch alles auswählen lasse, vom Drucker bis zur Schublade, dann gehen die mir verständlicherweise an die Gurgel. Optimal wäre eine Lösung, dass einfach der Button "Etiketten drucken" gedrückt wird, und schon kommen die Etiketten aus der richtigen Schublade. 

Erfahrungen im PDF-Druck habe ich bereits, es kommt PDFBox von Apache zum Einsatz, gedruckt wird über die javax.print* Klassen. Duplexdruck, Schubladenwahl, Druckerwahl, ist da ja alles kein Problem (zumindest bisher). Das Drucken möchte ich aber nicht aus der Enterprise Anwendung aus anstoßen, da hier ja ein Zugriff auf Systemebene erfolgen muss, was ich gerne da raus halten möchte, da ja eventuell mal der Server mit den Druckertreibern ein anderer sein kann, als der mit der Glassfish umgebung. Clustering würde so später wahrscheinlich auch nicht mehr funktionieren.

Mein erster Impuls wäre, eine normale Java-Anwendung zu schreiben und zentral auf einem Server auszuführen, welcher die nötigen Drucker und Treiber installiert hat. Diese bekommt dann über JMS die Informationen über einen Drucker, eine Schublade und die URL an der das PDF liegt und antwortet, wenn der Ausdruck erfolgt ist. Die Informationen über die Drucker müssten dann zentral erfasst werden, aber man hätte den Vorteil, für verschiedene Aktionen Standarddrucker zu definieren (z.B. Etiketten welche in Programm x von Benutzer y gedruckt werden, werden in der unteren Schublade im Produktionsgebäude z gedruckt). Darüber hinaus ist noch eine Portierbarkeit gegeben. 

Alternativ könnte ich ein Java-Applet einbinden, dass auf die Drucker des Clients zugreifen darf. Da habe ich aber ein ungutes Gefühl, zum einen finde ich Applets persönlich einfach nicht so sauber, außerdem würde ich mein System dann wieder dezentralisieren. 

Was haltet ihr von der Idee, wie läuft es bei euch? Habt ihr Erfahrungen mit dieser Lösung, oder mit anderen? Oder fallen euch Gründe dafür oder dagegen ein?

Mit freundlichen Grüßen,

Tim


----------



## cljk (10. Jun 2012)

Ich vermute, dass es darum geht, auf den Druckern der einzelnen Arbeitsstationen zu drucken (?) - und das automatisiert. Das nenn ich mal ein ambitioniertes Projekt.

Ich habe in der Firma ein Projekt laufen, wo wir allerdings einen *zentralen* Etikettendrucker verwenden. Daher habe ich einen Nadeldrucker angeschafft, der den ganzen Rotz einfach im Textformat entgegennimmt und ausspuckt. Der hängt an einem Netzwerkdongle und ist auf dem Server (unter Windows) virtuell als LPT eingebunden. Als Verbindung für den Zugriff auf den Drucker nutze ich ein Sun-IO-Framework auf dessen Namen ich gerade nicht komme (wollte das immer mal nativ implementieren... aber die gute Zeit spricht dagegen). Da der betreffende Drucker (OKI microline) ausschließlich Etiketten druckt, brauche ich auch keine Schublade auswählen - der hat nur eine.

Aber für deine Arbeitsplatzlösung wüsste ich auch kein Patentrezept. Das mit dem zentralen Server, der alle Treiber hat finde ich als hakelig vom Bauchgefühl - jedenfalls wenn das mehr als eine handvoll werden. Habt ihr denn überall dieselben Druckertypen? Wie hast du denn vor, mit JAVA die Schublade auszuwählen? Das wäre für mich eins der Hauptprobleme. Rest lässt sich ja beliebig lösen. 

Ich habe nur nicht recht verstanden, ob die Drucker Teil der Arbeitsstationen sind oder irgendwo anders sind und zentrale Einheiten sind - ob das die gleichen Typen oder unterschiedliche sind. Ob die immer verfügbar sind (24h-Betrieb) oder ggf. nur wenn die Arbeitsstationen an sind.


----------



## inv_zim (13. Jun 2012)

Hi cljk,

erst einmal danke für deine Antwort! Es sind nicht wirklich Drucker der Workstations. Örtlich gesehen schon (bzw. werden sie auch so benutzt), aber generell sind es erst einmal Netzwerkdrucker, das heisst sie sind durchgehend erreichbar. Es geht mir auch nicht um alle Drucker, sondern hauptsächlich erst einmal um die Etikettendrucker in den verschiedenen Produktionsgebäuden, im Lager, in der Logistik. Um die zu zählen dürften zwei Hände gerade so noch reichen. 
Es handelt sich nicht um exakt die selben Drucker, aber die betreffenden Modelle sind alle von Kyocera und das wird sich auch in Zukunft erst mal so schnell nicht ändern. 

Meine erste Implementierung steht mittlerweile:
Wie schon geplant, sende ich von meiner JEE Anwendung aus eine Nachricht in eine JMS-Queue mit den Informationen Drucker(name), Schublade, Papierformat, Kopien und Pfad zum PDF. Zur Anwendung gehört ebenfalls ein JEE Application Client, welcher die Nachrichten aus dem JMS abruft, die PDFs (mit PDFBox) in ein druckbares Format wandelt und mit der Java Print API an den entsprechenden Drucker weiterleitet. Dieser läuft ein mal zentral.

Das ganze sieht dann (beispielhaft) so aus:


```
PDDocument pageable = PDDocument.load(new URL(auftrag.getPdfPfad()));
PrintService[] services = PrinterJob.lookupPrintServices();
PrintService service = null;
for (int i = 0; i < services.length; i++) {
  PrintService printService = services[i];
  if (printService.getName().equals(auftrag.getDruckerName())) {
    service = printService;
    break;
  }
}
PrinterJob printJob = PrinterJob.getPrinterJob();
printJob.setPrintService(service);
printJob.setPageable(pageable);

HashPrintRequestAttributeSet attrSet = new HashPrintRequestAttributeSet();
attrSet.add(MediaSizeName.ISO_A5);
attrSet.add(MediaTray.BOTTOM);
attrSet.add(new Copies(1);                   

                    
try {
  printJob.print(attrSet);
} catch (PrinterException ex) {
  Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
}
```

Das hier sagt dem Drucker, er soll aus der unteren Schublade auf A5 Papier 1 Kopie drucken. Natürlich vorausgesetzt, es existiert eine untere Schublade und darin befindet sich auch wirklich A5 Papier. Auf den Druckern mit denen ich teste funktioniert diese Lösung, auch wenn die Java Print API meiner Meinung nach einfach ein Krampf ist. Ich bin gespannt, ob die anderen Drucker da auch mit sich reden lassen, vorsichtshalber habe ich die JMS Nachricht extra als XML gepackt, um eventuell den Druckclient noch in einer anderen Sprache zu implementieren. 

So viel Aufwand zum Drucken :noe:


----------



## cljk (13. Jun 2012)

Hätt ich jetzt gar nicht gewusst, dass man so "einfach" die Schublade etc. auswählen kann - wieder was gelernt.
Aber sonst sieht deine Architektur doch top aus: Anwendung, die die Druckjobs generiert und in eine Queue schiebt, dort wird sie von einer Gegenstelle abgearbeitet, wüsste nicht, was man da noch besser machen könnte. Das einzige wäre ggf. das PDF mit in die JMS zu schieben statt auf Datenträger - aber sonst Respekt!


----------



## inv_zim (13. Jun 2012)

Hi,

vielen Dank für die Zustimmung, dann wird das so umgesetzt 
Nur noch als Nachtrag: Das PDF liegt nicht auf dem Datenträger, das wird von einem Reporting-Server generiert. Der Jasper Reports Server läuft in einer Tomcat Instanz und ich kann auf das PDF via HTTP zugreifen und sogar noch Parameter mitgeben. Auf den Zugriff hin wird der Report erstellt und "ausgeliefert".

Gruß und danke nochmal,

Tim


----------

