| /* |
| * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package sun.print; |
| |
| import java.net.URI; |
| import java.net.URL; |
| import java.io.BufferedInputStream; |
| import java.io.BufferedOutputStream; |
| import java.io.BufferedReader; |
| import java.io.BufferedWriter; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.OutputStream; |
| import java.io.OutputStreamWriter; |
| import java.io.IOException; |
| import java.io.PrintWriter; |
| import java.io.Reader; |
| import java.io.StringWriter; |
| import java.io.UnsupportedEncodingException; |
| import java.util.Vector; |
| |
| import javax.print.CancelablePrintJob; |
| import javax.print.Doc; |
| import javax.print.DocFlavor; |
| import javax.print.DocPrintJob; |
| import javax.print.PrintService; |
| import javax.print.PrintException; |
| import javax.print.event.PrintJobEvent; |
| import javax.print.event.PrintJobListener; |
| import javax.print.event.PrintJobAttributeListener; |
| |
| import javax.print.attribute.Attribute; |
| import javax.print.attribute.AttributeSet; |
| import javax.print.attribute.AttributeSetUtilities; |
| import javax.print.attribute.DocAttributeSet; |
| import javax.print.attribute.HashPrintJobAttributeSet; |
| import javax.print.attribute.HashPrintRequestAttributeSet; |
| import javax.print.attribute.PrintJobAttribute; |
| import javax.print.attribute.PrintJobAttributeSet; |
| import javax.print.attribute.PrintRequestAttribute; |
| import javax.print.attribute.PrintRequestAttributeSet; |
| import javax.print.attribute.standard.Copies; |
| import javax.print.attribute.standard.Destination; |
| import javax.print.attribute.standard.DocumentName; |
| import javax.print.attribute.standard.Fidelity; |
| import javax.print.attribute.standard.JobName; |
| import javax.print.attribute.standard.JobOriginatingUserName; |
| import javax.print.attribute.standard.JobSheets; |
| import javax.print.attribute.standard.Media; |
| import javax.print.attribute.standard.MediaSize; |
| import javax.print.attribute.standard.MediaSizeName; |
| import javax.print.attribute.standard.OrientationRequested; |
| import javax.print.attribute.standard.RequestingUserName; |
| import javax.print.attribute.standard.NumberUp; |
| import javax.print.attribute.standard.Sides; |
| import javax.print.attribute.standard.PrinterIsAcceptingJobs; |
| |
| import java.awt.print.*; |
| |
| |
| |
| public class UnixPrintJob implements CancelablePrintJob { |
| private static String debugPrefix = "UnixPrintJob>> "; |
| |
| transient private Vector jobListeners; |
| transient private Vector attrListeners; |
| transient private Vector listenedAttributeSets; |
| |
| private PrintService service; |
| private boolean fidelity; |
| private boolean printing = false; |
| private boolean printReturned = false; |
| private PrintRequestAttributeSet reqAttrSet = null; |
| private PrintJobAttributeSet jobAttrSet = null; |
| private PrinterJob job; |
| private Doc doc; |
| /* these variables used globally to store reference to the print |
| * data retrieved as a stream. On completion these are always closed |
| * if non-null. |
| */ |
| private InputStream instream = null; |
| private Reader reader = null; |
| |
| /* default values overridden by those extracted from the attributes */ |
| private String jobName = "Java Printing"; |
| private int copies = 1; |
| private MediaSizeName mediaName = MediaSizeName.NA_LETTER; |
| private MediaSize mediaSize = MediaSize.NA.LETTER; |
| private CustomMediaTray customTray = null; |
| private OrientationRequested orient = OrientationRequested.PORTRAIT; |
| private NumberUp nUp = null; |
| private Sides sides = null; |
| |
| UnixPrintJob(PrintService service) { |
| this.service = service; |
| mDestination = service.getName(); |
| mDestType = UnixPrintJob.DESTPRINTER; |
| } |
| |
| public PrintService getPrintService() { |
| return service; |
| } |
| |
| public PrintJobAttributeSet getAttributes() { |
| synchronized (this) { |
| if (jobAttrSet == null) { |
| /* just return an empty set until the job is submitted */ |
| PrintJobAttributeSet jobSet = new HashPrintJobAttributeSet(); |
| return AttributeSetUtilities.unmodifiableView(jobSet); |
| } else { |
| return jobAttrSet; |
| } |
| } |
| } |
| |
| public void addPrintJobListener(PrintJobListener listener) { |
| synchronized (this) { |
| if (listener == null) { |
| return; |
| } |
| if (jobListeners == null) { |
| jobListeners = new Vector(); |
| } |
| jobListeners.add(listener); |
| } |
| } |
| |
| public void removePrintJobListener(PrintJobListener listener) { |
| synchronized (this) { |
| if (listener == null || jobListeners == null ) { |
| return; |
| } |
| jobListeners.remove(listener); |
| if (jobListeners.isEmpty()) { |
| jobListeners = null; |
| } |
| } |
| } |
| |
| |
| /* Closes any stream already retrieved for the data. |
| * We want to avoid unnecessarily asking the Doc to create a stream only |
| * to get a reference in order to close it because the job failed. |
| * If the representation class is itself a "stream", this |
| * closes that stream too. |
| */ |
| private void closeDataStreams() { |
| |
| if (doc == null) { |
| return; |
| } |
| |
| Object data = null; |
| |
| try { |
| data = doc.getPrintData(); |
| } catch (IOException e) { |
| return; |
| } |
| |
| if (instream != null) { |
| try { |
| instream.close(); |
| } catch (IOException e) { |
| } finally { |
| instream = null; |
| } |
| } |
| else if (reader != null) { |
| try { |
| reader.close(); |
| } catch (IOException e) { |
| } finally { |
| reader = null; |
| } |
| } |
| else if (data instanceof InputStream) { |
| try { |
| ((InputStream)data).close(); |
| } catch (IOException e) { |
| } |
| } |
| else if (data instanceof Reader) { |
| try { |
| ((Reader)data).close(); |
| } catch (IOException e) { |
| } |
| } |
| } |
| |
| private void notifyEvent(int reason) { |
| |
| /* since this method should always get called, here's where |
| * we will perform the clean up of any data stream supplied. |
| */ |
| switch (reason) { |
| case PrintJobEvent.DATA_TRANSFER_COMPLETE: |
| case PrintJobEvent.JOB_CANCELED : |
| case PrintJobEvent.JOB_FAILED : |
| case PrintJobEvent.NO_MORE_EVENTS : |
| case PrintJobEvent.JOB_COMPLETE : |
| closeDataStreams(); |
| } |
| |
| synchronized (this) { |
| if (jobListeners != null) { |
| PrintJobListener listener; |
| PrintJobEvent event = new PrintJobEvent(this, reason); |
| for (int i = 0; i < jobListeners.size(); i++) { |
| listener = (PrintJobListener)(jobListeners.elementAt(i)); |
| switch (reason) { |
| |
| case PrintJobEvent.JOB_CANCELED : |
| listener.printJobCanceled(event); |
| break; |
| |
| case PrintJobEvent.JOB_FAILED : |
| listener.printJobFailed(event); |
| break; |
| |
| case PrintJobEvent.DATA_TRANSFER_COMPLETE : |
| listener.printDataTransferCompleted(event); |
| break; |
| |
| case PrintJobEvent.NO_MORE_EVENTS : |
| listener.printJobNoMoreEvents(event); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| public void addPrintJobAttributeListener( |
| PrintJobAttributeListener listener, |
| PrintJobAttributeSet attributes) { |
| synchronized (this) { |
| if (listener == null) { |
| return; |
| } |
| if (attrListeners == null) { |
| attrListeners = new Vector(); |
| listenedAttributeSets = new Vector(); |
| } |
| attrListeners.add(listener); |
| if (attributes == null) { |
| attributes = new HashPrintJobAttributeSet(); |
| } |
| listenedAttributeSets.add(attributes); |
| } |
| } |
| |
| public void removePrintJobAttributeListener( |
| PrintJobAttributeListener listener) { |
| synchronized (this) { |
| if (listener == null || attrListeners == null ) { |
| return; |
| } |
| int index = attrListeners.indexOf(listener); |
| if (index == -1) { |
| return; |
| } else { |
| attrListeners.remove(index); |
| listenedAttributeSets.remove(index); |
| if (attrListeners.isEmpty()) { |
| attrListeners = null; |
| listenedAttributeSets = null; |
| } |
| } |
| } |
| } |
| |
| public void print(Doc doc, PrintRequestAttributeSet attributes) |
| throws PrintException { |
| |
| synchronized (this) { |
| if (printing) { |
| throw new PrintException("already printing"); |
| } else { |
| printing = true; |
| } |
| } |
| |
| if ((PrinterIsAcceptingJobs)(service.getAttribute( |
| PrinterIsAcceptingJobs.class)) == |
| PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS) { |
| throw new PrintException("Printer is not accepting job."); |
| } |
| |
| this.doc = doc; |
| /* check if the parameters are valid before doing much processing */ |
| DocFlavor flavor = doc.getDocFlavor(); |
| |
| Object data; |
| |
| try { |
| data = doc.getPrintData(); |
| } catch (IOException e) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException("can't get print data: " + e.toString()); |
| } |
| |
| if (flavor == null || (!service.isDocFlavorSupported(flavor))) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintJobFlavorException("invalid flavor", flavor); |
| } |
| |
| initializeAttributeSets(doc, attributes); |
| |
| getAttributeValues(flavor); |
| |
| // set up mOptions |
| if ((service instanceof IPPPrintService) && |
| CUPSPrinter.isCupsRunning()) { |
| |
| IPPPrintService.debug_println(debugPrefix+ |
| "instanceof IPPPrintService"); |
| |
| if (mediaName != null) { |
| CustomMediaSizeName customMedia = |
| ((IPPPrintService)service).findCustomMedia(mediaName); |
| if (customMedia != null) { |
| mOptions = " media="+ customMedia.getChoiceName(); |
| } |
| } |
| |
| if (customTray != null && |
| customTray instanceof CustomMediaTray) { |
| String choice = customTray.getChoiceName(); |
| if (choice != null) { |
| mOptions += " media="+choice; |
| } |
| } |
| |
| if (nUp != null) { |
| mOptions += " number-up="+nUp.getValue(); |
| } |
| |
| if (orient != OrientationRequested.PORTRAIT && |
| (flavor != null) && |
| !flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE)) { |
| mOptions += " orientation-requested="+orient.getValue(); |
| } |
| |
| if (sides != null) { |
| mOptions += " sides="+sides; |
| } |
| |
| } |
| |
| IPPPrintService.debug_println(debugPrefix+"mOptions "+mOptions); |
| String repClassName = flavor.getRepresentationClassName(); |
| String val = flavor.getParameter("charset"); |
| String encoding = "us-ascii"; |
| if (val != null && !val.equals("")) { |
| encoding = val; |
| } |
| |
| if (flavor.equals(DocFlavor.INPUT_STREAM.GIF) || |
| flavor.equals(DocFlavor.INPUT_STREAM.JPEG) || |
| flavor.equals(DocFlavor.INPUT_STREAM.PNG) || |
| flavor.equals(DocFlavor.BYTE_ARRAY.GIF) || |
| flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) || |
| flavor.equals(DocFlavor.BYTE_ARRAY.PNG)) { |
| try { |
| instream = doc.getStreamForBytes(); |
| if (instream == null) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException("No stream for data"); |
| } |
| if (!(service instanceof IPPPrintService && |
| ((IPPPrintService)service).isIPPSupportedImages( |
| flavor.getMimeType()))) { |
| printableJob(new ImagePrinter(instream)); |
| ((UnixPrintService)service).wakeNotifier(); |
| return; |
| } |
| } catch (ClassCastException cce) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException(cce); |
| } catch (IOException ioe) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException(ioe); |
| } |
| } else if (flavor.equals(DocFlavor.URL.GIF) || |
| flavor.equals(DocFlavor.URL.JPEG) || |
| flavor.equals(DocFlavor.URL.PNG)) { |
| try { |
| URL url = (URL)data; |
| if ((service instanceof IPPPrintService) && |
| ((IPPPrintService)service).isIPPSupportedImages( |
| flavor.getMimeType())) { |
| instream = url.openStream(); |
| } else { |
| printableJob(new ImagePrinter(url)); |
| ((UnixPrintService)service).wakeNotifier(); |
| return; |
| } |
| } catch (ClassCastException cce) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException(cce); |
| } catch (IOException e) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException(e.toString()); |
| } |
| } else if (flavor.equals(DocFlavor.CHAR_ARRAY.TEXT_PLAIN) || |
| flavor.equals(DocFlavor.READER.TEXT_PLAIN) || |
| flavor.equals(DocFlavor.STRING.TEXT_PLAIN)) { |
| try { |
| reader = doc.getReaderForText(); |
| if (reader == null) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException("No reader for data"); |
| } |
| } catch (IOException ioe) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException(ioe.toString()); |
| } |
| } else if (repClassName.equals("[B") || |
| repClassName.equals("java.io.InputStream")) { |
| try { |
| instream = doc.getStreamForBytes(); |
| if (instream == null) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException("No stream for data"); |
| } |
| } catch (IOException ioe) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException(ioe.toString()); |
| } |
| } else if (repClassName.equals("java.net.URL")) { |
| /* |
| * This extracts the data from the URL and passes it the content |
| * directly to the print service as a file. |
| * This is appropriate for the current implementation where lp or |
| * lpr is always used to spool the data. We expect to revise the |
| * implementation to provide more complete IPP support (ie not just |
| * CUPS) and at that time the job will be spooled via IPP |
| * and the URL |
| * itself should be sent to the IPP print service not the content. |
| */ |
| URL url = (URL)data; |
| try { |
| instream = url.openStream(); |
| } catch (IOException e) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException(e.toString()); |
| } |
| } else if (repClassName.equals("java.awt.print.Pageable")) { |
| try { |
| pageableJob((Pageable)doc.getPrintData()); |
| if (service instanceof IPPPrintService) { |
| ((IPPPrintService)service).wakeNotifier(); |
| } else { |
| ((UnixPrintService)service).wakeNotifier(); |
| } |
| return; |
| } catch (ClassCastException cce) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException(cce); |
| } catch (IOException ioe) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException(ioe); |
| } |
| } else if (repClassName.equals("java.awt.print.Printable")) { |
| try { |
| printableJob((Printable)doc.getPrintData()); |
| if (service instanceof IPPPrintService) { |
| ((IPPPrintService)service).wakeNotifier(); |
| } else { |
| ((UnixPrintService)service).wakeNotifier(); |
| } |
| return; |
| } catch (ClassCastException cce) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException(cce); |
| } catch (IOException ioe) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException(ioe); |
| } |
| } else { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException("unrecognized class: "+repClassName); |
| } |
| |
| // now spool the print data. |
| PrinterOpener po = new PrinterOpener(); |
| java.security.AccessController.doPrivileged(po); |
| if (po.pex != null) { |
| throw po.pex; |
| } |
| OutputStream output = po.result; |
| |
| /* There are three cases: |
| * 1) Text data from a Reader, just pass through. |
| * 2) Text data from an input stream which we must read using the |
| * correct encoding |
| * 3) Raw byte data from an InputStream we don't interpret as text, |
| * just pass through: eg postscript. |
| */ |
| |
| BufferedWriter bw = null; |
| if ((instream == null && reader != null)) { |
| BufferedReader br = new BufferedReader(reader); |
| OutputStreamWriter osw = new OutputStreamWriter(output); |
| bw = new BufferedWriter(osw); |
| char []buffer = new char[1024]; |
| int cread; |
| |
| try { |
| while ((cread = br.read(buffer, 0, buffer.length)) >=0) { |
| bw.write(buffer, 0, cread); |
| } |
| br.close(); |
| bw.flush(); |
| bw.close(); |
| } catch (IOException e) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException (e); |
| } |
| } else if (instream != null && |
| flavor.getMediaType().equalsIgnoreCase("text")) { |
| try { |
| |
| InputStreamReader isr = new InputStreamReader(instream, |
| encoding); |
| BufferedReader br = new BufferedReader(isr); |
| OutputStreamWriter osw = new OutputStreamWriter(output); |
| bw = new BufferedWriter(osw); |
| char []buffer = new char[1024]; |
| int cread; |
| |
| while ((cread = br.read(buffer, 0, buffer.length)) >=0) { |
| bw.write(buffer, 0, cread); |
| } |
| bw.flush(); |
| } catch (IOException e) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException (e); |
| } finally { |
| try { |
| if (bw != null) { |
| bw.close(); |
| } |
| } catch (IOException e) { |
| } |
| } |
| } else if (instream != null) { |
| BufferedInputStream bin = new BufferedInputStream(instream); |
| BufferedOutputStream bout = new BufferedOutputStream(output); |
| byte[] buffer = new byte[1024]; |
| int bread = 0; |
| |
| try { |
| while ((bread = bin.read(buffer)) >= 0) { |
| bout.write(buffer, 0, bread); |
| } |
| bin.close(); |
| bout.flush(); |
| bout.close(); |
| } catch (IOException e) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException (e); |
| } |
| } |
| notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE); |
| |
| if (mDestType == UnixPrintJob.DESTPRINTER) { |
| PrinterSpooler spooler = new PrinterSpooler(); |
| java.security.AccessController.doPrivileged(spooler); |
| if (spooler.pex != null) { |
| throw spooler.pex; |
| } |
| } |
| notifyEvent(PrintJobEvent.NO_MORE_EVENTS); |
| if (service instanceof IPPPrintService) { |
| ((IPPPrintService)service).wakeNotifier(); |
| } else { |
| ((UnixPrintService)service).wakeNotifier(); |
| } |
| } |
| |
| public void printableJob(Printable printable) throws PrintException { |
| try { |
| synchronized(this) { |
| if (job != null) { // shouldn't happen |
| throw new PrintException("already printing"); |
| } else { |
| job = new PSPrinterJob(); |
| } |
| } |
| job.setPrintService(getPrintService()); |
| job.setCopies(copies); |
| job.setJobName(jobName); |
| PageFormat pf = new PageFormat(); |
| if (mediaSize != null) { |
| Paper p = new Paper(); |
| p.setSize(mediaSize.getX(MediaSize.INCH)*72.0, |
| mediaSize.getY(MediaSize.INCH)*72.0); |
| p.setImageableArea(72.0, 72.0, p.getWidth()-144.0, |
| p.getHeight()-144.0); |
| pf.setPaper(p); |
| } |
| if (orient == OrientationRequested.REVERSE_LANDSCAPE) { |
| pf.setOrientation(PageFormat.REVERSE_LANDSCAPE); |
| } else if (orient == OrientationRequested.LANDSCAPE) { |
| pf.setOrientation(PageFormat.LANDSCAPE); |
| } |
| job.setPrintable(printable, pf); |
| job.print(reqAttrSet); |
| notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE); |
| return; |
| } catch (PrinterException pe) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException(pe); |
| } finally { |
| printReturned = true; |
| notifyEvent(PrintJobEvent.NO_MORE_EVENTS); |
| } |
| } |
| |
| public void pageableJob(Pageable pageable) throws PrintException { |
| try { |
| synchronized(this) { |
| if (job != null) { // shouldn't happen |
| throw new PrintException("already printing"); |
| } else { |
| job = new PSPrinterJob(); |
| } |
| } |
| job.setPrintService(getPrintService()); |
| job.setCopies(copies); |
| job.setJobName(jobName); |
| job.setPageable(pageable); |
| job.print(reqAttrSet); |
| notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE); |
| return; |
| } catch (PrinterException pe) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException(pe); |
| } finally { |
| printReturned = true; |
| notifyEvent(PrintJobEvent.NO_MORE_EVENTS); |
| } |
| } |
| /* There's some inefficiency here as the job set is created even though |
| * it may never be requested. |
| */ |
| private synchronized void |
| initializeAttributeSets(Doc doc, PrintRequestAttributeSet reqSet) { |
| |
| reqAttrSet = new HashPrintRequestAttributeSet(); |
| jobAttrSet = new HashPrintJobAttributeSet(); |
| |
| Attribute[] attrs; |
| if (reqSet != null) { |
| reqAttrSet.addAll(reqSet); |
| attrs = reqSet.toArray(); |
| for (int i=0; i<attrs.length; i++) { |
| if (attrs[i] instanceof PrintJobAttribute) { |
| jobAttrSet.add(attrs[i]); |
| } |
| } |
| } |
| |
| DocAttributeSet docSet = doc.getAttributes(); |
| if (docSet != null) { |
| attrs = docSet.toArray(); |
| for (int i=0; i<attrs.length; i++) { |
| if (attrs[i] instanceof PrintRequestAttribute) { |
| reqAttrSet.add(attrs[i]); |
| } |
| if (attrs[i] instanceof PrintJobAttribute) { |
| jobAttrSet.add(attrs[i]); |
| } |
| } |
| } |
| |
| /* add the user name to the job */ |
| String userName = ""; |
| try { |
| userName = System.getProperty("user.name"); |
| } catch (SecurityException se) { |
| } |
| |
| if (userName == null || userName.equals("")) { |
| RequestingUserName ruName = |
| (RequestingUserName)reqSet.get(RequestingUserName.class); |
| if (ruName != null) { |
| jobAttrSet.add( |
| new JobOriginatingUserName(ruName.getValue(), |
| ruName.getLocale())); |
| } else { |
| jobAttrSet.add(new JobOriginatingUserName("", null)); |
| } |
| } else { |
| jobAttrSet.add(new JobOriginatingUserName(userName, null)); |
| } |
| |
| /* if no job name supplied use doc name (if supplied), if none and |
| * its a URL use that, else finally anything .. */ |
| if (jobAttrSet.get(JobName.class) == null) { |
| JobName jobName; |
| if (docSet != null && docSet.get(DocumentName.class) != null) { |
| DocumentName docName = |
| (DocumentName)docSet.get(DocumentName.class); |
| jobName = new JobName(docName.getValue(), docName.getLocale()); |
| jobAttrSet.add(jobName); |
| } else { |
| String str = "JPS Job:" + doc; |
| try { |
| Object printData = doc.getPrintData(); |
| if (printData instanceof URL) { |
| str = ((URL)(doc.getPrintData())).toString(); |
| } |
| } catch (IOException e) { |
| } |
| jobName = new JobName(str, null); |
| jobAttrSet.add(jobName); |
| } |
| } |
| |
| jobAttrSet = AttributeSetUtilities.unmodifiableView(jobAttrSet); |
| } |
| |
| private void getAttributeValues(DocFlavor flavor) throws PrintException { |
| Attribute attr; |
| Class category; |
| |
| if (reqAttrSet.get(Fidelity.class) == Fidelity.FIDELITY_TRUE) { |
| fidelity = true; |
| } else { |
| fidelity = false; |
| } |
| |
| Attribute []attrs = reqAttrSet.toArray(); |
| for (int i=0; i<attrs.length; i++) { |
| attr = attrs[i]; |
| category = attr.getCategory(); |
| if (fidelity == true) { |
| if (!service.isAttributeCategorySupported(category)) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintJobAttributeException( |
| "unsupported category: " + category, category, null); |
| } else if |
| (!service.isAttributeValueSupported(attr, flavor, null)) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintJobAttributeException( |
| "unsupported attribute: " + attr, null, attr); |
| } |
| } |
| if (category == Destination.class) { |
| URI uri = ((Destination)attr).getURI(); |
| if (!"file".equals(uri.getScheme())) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException("Not a file: URI"); |
| } else { |
| try { |
| mDestType = DESTFILE; |
| mDestination = (new File(uri)).getPath(); |
| } catch (Exception e) { |
| throw new PrintException(e); |
| } |
| // check write access |
| SecurityManager security = System.getSecurityManager(); |
| if (security != null) { |
| try { |
| security.checkWrite(mDestination); |
| } catch (SecurityException se) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| throw new PrintException(se); |
| } |
| } |
| } |
| } else if (category == JobSheets.class) { |
| if ((JobSheets)attr == JobSheets.NONE) { |
| mNoJobSheet = true; |
| } |
| } else if (category == JobName.class) { |
| jobName = ((JobName)attr).getValue(); |
| } else if (category == Copies.class) { |
| copies = ((Copies)attr).getValue(); |
| } else if (category == Media.class) { |
| if (attr instanceof MediaSizeName) { |
| mediaName = (MediaSizeName)attr; |
| IPPPrintService.debug_println(debugPrefix+ |
| "mediaName "+mediaName); |
| if (!service.isAttributeValueSupported(attr, null, null)) { |
| mediaSize = MediaSize.getMediaSizeForName(mediaName); |
| } |
| } else if (attr instanceof CustomMediaTray) { |
| customTray = (CustomMediaTray)attr; |
| } |
| } else if (category == OrientationRequested.class) { |
| orient = (OrientationRequested)attr; |
| } else if (category == NumberUp.class) { |
| nUp = (NumberUp)attr; |
| } else if (category == Sides.class) { |
| sides = (Sides)attr; |
| } |
| } |
| } |
| |
| private String[] printExecCmd(String printer, String options, |
| boolean noJobSheet, |
| String banner, int copies, String spoolFile) { |
| int PRINTER = 0x1; |
| int OPTIONS = 0x2; |
| int BANNER = 0x4; |
| int COPIES = 0x8; |
| int NOSHEET = 0x10; |
| int pFlags = 0; |
| String execCmd[]; |
| int ncomps = 2; // minimum number of print args |
| int n = 0; |
| |
| // conveniently "lp" is the default destination for both lp and lpr. |
| if (printer != null && !printer.equals("") && !printer.equals("lp")) { |
| pFlags |= PRINTER; |
| ncomps+=1; |
| } |
| if (options != null && !options.equals("")) { |
| pFlags |= OPTIONS; |
| ncomps+=1; |
| } |
| if (banner != null && !banner.equals("")) { |
| pFlags |= BANNER; |
| ncomps+=1; |
| } |
| if (copies > 1) { |
| pFlags |= COPIES; |
| ncomps+=1; |
| } |
| if (noJobSheet) { |
| pFlags |= NOSHEET; |
| ncomps+=1; |
| } |
| if (UnixPrintServiceLookup.osname.equals("SunOS")) { |
| ncomps+=1; // lp uses 1 more arg than lpr (make a copy) |
| execCmd = new String[ncomps]; |
| execCmd[n++] = "/usr/bin/lp"; |
| execCmd[n++] = "-c"; // make a copy of the spool file |
| if ((pFlags & PRINTER) != 0) { |
| execCmd[n++] = "-d" + printer; |
| } |
| if ((pFlags & BANNER) != 0) { |
| String quoteChar = "\""; |
| execCmd[n++] = "-t " + quoteChar+banner+quoteChar; |
| } |
| if ((pFlags & COPIES) != 0) { |
| execCmd[n++] = "-n " + copies; |
| } |
| if ((pFlags & NOSHEET) != 0) { |
| execCmd[n++] = "-o nobanner"; |
| } |
| if ((pFlags & OPTIONS) != 0) { |
| execCmd[n++] = "-o " + options; |
| } |
| } else { |
| execCmd = new String[ncomps]; |
| execCmd[n++] = "/usr/bin/lpr"; |
| if ((pFlags & PRINTER) != 0) { |
| execCmd[n++] = "-P" + printer; |
| } |
| if ((pFlags & BANNER) != 0) { |
| execCmd[n++] = "-J " + banner; |
| } |
| if ((pFlags & COPIES) != 0) { |
| execCmd[n++] = "-#" + copies; |
| } |
| if ((pFlags & NOSHEET) != 0) { |
| execCmd[n++] = "-h"; |
| } |
| if ((pFlags & OPTIONS) != 0) { |
| execCmd[n++] = "-o" + options; |
| } |
| } |
| execCmd[n++] = spoolFile; |
| if (IPPPrintService.debugPrint) { |
| System.out.println("UnixPrintJob>> execCmd"); |
| for (int i=0; i<execCmd.length; i++) { |
| System.out.print(" "+execCmd[i]); |
| } |
| System.out.println(); |
| } |
| return execCmd; |
| } |
| |
| private static int DESTPRINTER = 1; |
| private static int DESTFILE = 2; |
| private int mDestType = DESTPRINTER; |
| |
| private File spoolFile; |
| private String mDestination, mOptions=""; |
| private boolean mNoJobSheet = false; |
| |
| // Inner class to run "privileged" to open the printer output stream. |
| |
| private class PrinterOpener implements java.security.PrivilegedAction { |
| PrintException pex; |
| OutputStream result; |
| |
| public Object run() { |
| try { |
| if (mDestType == UnixPrintJob.DESTFILE) { |
| spoolFile = new File(mDestination); |
| } else { |
| /* Write to a temporary file which will be spooled to |
| * the printer then deleted. In the case that the file |
| * is not removed for some reason, request that it is |
| * removed when the VM exits. |
| */ |
| spoolFile = File.createTempFile("javaprint", ".ps", null); |
| spoolFile.deleteOnExit(); |
| } |
| result = new FileOutputStream(spoolFile); |
| return result; |
| } catch (IOException ex) { |
| // If there is an IOError we subvert it to a PrinterException. |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| pex = new PrintException(ex); |
| } |
| return null; |
| } |
| } |
| |
| // Inner class to run "privileged" to invoke the system print command |
| |
| private class PrinterSpooler implements java.security.PrivilegedAction { |
| PrintException pex; |
| |
| private void handleProcessFailure(final Process failedProcess, |
| final String[] execCmd, final int result) throws IOException { |
| try (StringWriter sw = new StringWriter(); |
| PrintWriter pw = new PrintWriter(sw)) { |
| pw.append("error=").append(Integer.toString(result)); |
| pw.append(" running:"); |
| for (String arg: execCmd) { |
| pw.append(" '").append(arg).append("'"); |
| } |
| try (InputStream is = failedProcess.getErrorStream(); |
| InputStreamReader isr = new InputStreamReader(is); |
| BufferedReader br = new BufferedReader(isr)) { |
| while (br.ready()) { |
| pw.println(); |
| pw.append("\t\t").append(br.readLine()); |
| } |
| } finally { |
| pw.flush(); |
| throw new IOException(sw.toString()); |
| } |
| } |
| } |
| |
| public Object run() { |
| if (spoolFile == null || !spoolFile.exists()) { |
| pex = new PrintException("No spool file"); |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| return null; |
| } |
| try { |
| /** |
| * Spool to the printer. |
| */ |
| String fileName = spoolFile.getAbsolutePath(); |
| String execCmd[] = printExecCmd(mDestination, mOptions, |
| mNoJobSheet, jobName, copies, fileName); |
| |
| Process process = Runtime.getRuntime().exec(execCmd); |
| process.waitFor(); |
| final int result = process.exitValue(); |
| if (0 != result) { |
| handleProcessFailure(process, execCmd, result); |
| } |
| notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE); |
| } catch (IOException ex) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| // REMIND : 2d printing throws PrinterException |
| pex = new PrintException(ex); |
| } catch (InterruptedException ie) { |
| notifyEvent(PrintJobEvent.JOB_FAILED); |
| pex = new PrintException(ie); |
| } finally { |
| spoolFile.delete(); |
| notifyEvent(PrintJobEvent.NO_MORE_EVENTS); |
| } |
| return null; |
| } |
| } |
| |
| public void cancel() throws PrintException { |
| synchronized (this) { |
| if (!printing) { |
| throw new PrintException("Job is not yet submitted."); |
| } else if (job != null && !printReturned) { |
| job.cancel(); |
| notifyEvent(PrintJobEvent.JOB_CANCELED); |
| return; |
| } else { |
| throw new PrintException("Job could not be cancelled."); |
| } |
| } |
| } |
| } |