0001: /*
0002: * Copyright 2000-2004 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package sun.print;
0027:
0028: import java.net.URI;
0029: import java.net.URL;
0030: import java.io.BufferedInputStream;
0031: import java.io.BufferedOutputStream;
0032: import java.io.BufferedReader;
0033: import java.io.BufferedWriter;
0034: import java.io.File;
0035: import java.io.FileOutputStream;
0036: import java.io.InputStream;
0037: import java.io.InputStreamReader;
0038: import java.io.OutputStream;
0039: import java.io.OutputStreamWriter;
0040: import java.io.IOException;
0041: import java.io.Reader;
0042: import java.io.UnsupportedEncodingException;
0043: import java.util.Vector;
0044:
0045: import javax.print.CancelablePrintJob;
0046: import javax.print.Doc;
0047: import javax.print.DocFlavor;
0048: import javax.print.DocPrintJob;
0049: import javax.print.PrintService;
0050: import javax.print.PrintException;
0051: import javax.print.event.PrintJobEvent;
0052: import javax.print.event.PrintJobListener;
0053: import javax.print.event.PrintJobAttributeListener;
0054:
0055: import javax.print.attribute.Attribute;
0056: import javax.print.attribute.AttributeSet;
0057: import javax.print.attribute.AttributeSetUtilities;
0058: import javax.print.attribute.DocAttributeSet;
0059: import javax.print.attribute.HashPrintJobAttributeSet;
0060: import javax.print.attribute.HashPrintRequestAttributeSet;
0061: import javax.print.attribute.PrintJobAttribute;
0062: import javax.print.attribute.PrintJobAttributeSet;
0063: import javax.print.attribute.PrintRequestAttribute;
0064: import javax.print.attribute.PrintRequestAttributeSet;
0065: import javax.print.attribute.standard.Copies;
0066: import javax.print.attribute.standard.Destination;
0067: import javax.print.attribute.standard.DocumentName;
0068: import javax.print.attribute.standard.Fidelity;
0069: import javax.print.attribute.standard.JobName;
0070: import javax.print.attribute.standard.JobOriginatingUserName;
0071: import javax.print.attribute.standard.JobSheets;
0072: import javax.print.attribute.standard.Media;
0073: import javax.print.attribute.standard.MediaSize;
0074: import javax.print.attribute.standard.MediaSizeName;
0075: import javax.print.attribute.standard.OrientationRequested;
0076: import javax.print.attribute.standard.RequestingUserName;
0077: import javax.print.attribute.standard.NumberUp;
0078: import javax.print.attribute.standard.Sides;
0079: import javax.print.attribute.standard.PrinterIsAcceptingJobs;
0080:
0081: import java.awt.print.*;
0082:
0083: public class UnixPrintJob implements CancelablePrintJob {
0084: private static String debugPrefix = "UnixPrintJob>> ";
0085:
0086: transient private Vector jobListeners;
0087: transient private Vector attrListeners;
0088: transient private Vector listenedAttributeSets;
0089:
0090: private PrintService service;
0091: private boolean fidelity;
0092: private boolean printing = false;
0093: private boolean printReturned = false;
0094: private PrintRequestAttributeSet reqAttrSet = null;
0095: private PrintJobAttributeSet jobAttrSet = null;
0096: private PrinterJob job;
0097: private Doc doc;
0098: /* these variables used globally to store reference to the print
0099: * data retrieved as a stream. On completion these are always closed
0100: * if non-null.
0101: */
0102: private InputStream instream = null;
0103: private Reader reader = null;
0104:
0105: /* default values overridden by those extracted from the attributes */
0106: private String jobName = "Java Printing";
0107: private int copies = 1;
0108: private MediaSizeName mediaName = MediaSizeName.NA_LETTER;
0109: private MediaSize mediaSize = MediaSize.NA.LETTER;
0110: private CustomMediaTray customTray = null;
0111: private OrientationRequested orient = OrientationRequested.PORTRAIT;
0112: private NumberUp nUp = null;
0113: private Sides sides = null;
0114:
0115: UnixPrintJob(PrintService service) {
0116: this .service = service;
0117: mDestination = service.getName();
0118: mDestType = UnixPrintJob.DESTPRINTER;
0119: }
0120:
0121: public PrintService getPrintService() {
0122: return service;
0123: }
0124:
0125: public PrintJobAttributeSet getAttributes() {
0126: synchronized (this ) {
0127: if (jobAttrSet == null) {
0128: /* just return an empty set until the job is submitted */
0129: PrintJobAttributeSet jobSet = new HashPrintJobAttributeSet();
0130: return AttributeSetUtilities.unmodifiableView(jobSet);
0131: } else {
0132: return jobAttrSet;
0133: }
0134: }
0135: }
0136:
0137: public void addPrintJobListener(PrintJobListener listener) {
0138: synchronized (this ) {
0139: if (listener == null) {
0140: return;
0141: }
0142: if (jobListeners == null) {
0143: jobListeners = new Vector();
0144: }
0145: jobListeners.add(listener);
0146: }
0147: }
0148:
0149: public void removePrintJobListener(PrintJobListener listener) {
0150: synchronized (this ) {
0151: if (listener == null || jobListeners == null) {
0152: return;
0153: }
0154: jobListeners.remove(listener);
0155: if (jobListeners.isEmpty()) {
0156: jobListeners = null;
0157: }
0158: }
0159: }
0160:
0161: /* Closes any stream already retrieved for the data.
0162: * We want to avoid unnecessarily asking the Doc to create a stream only
0163: * to get a reference in order to close it because the job failed.
0164: * If the representation class is itself a "stream", this
0165: * closes that stream too.
0166: */
0167: private void closeDataStreams() {
0168:
0169: if (doc == null) {
0170: return;
0171: }
0172:
0173: Object data = null;
0174:
0175: try {
0176: data = doc.getPrintData();
0177: } catch (IOException e) {
0178: return;
0179: }
0180:
0181: if (instream != null) {
0182: try {
0183: instream.close();
0184: } catch (IOException e) {
0185: } finally {
0186: instream = null;
0187: }
0188: } else if (reader != null) {
0189: try {
0190: reader.close();
0191: } catch (IOException e) {
0192: } finally {
0193: reader = null;
0194: }
0195: } else if (data instanceof InputStream) {
0196: try {
0197: ((InputStream) data).close();
0198: } catch (IOException e) {
0199: }
0200: } else if (data instanceof Reader) {
0201: try {
0202: ((Reader) data).close();
0203: } catch (IOException e) {
0204: }
0205: }
0206: }
0207:
0208: private void notifyEvent(int reason) {
0209:
0210: /* since this method should always get called, here's where
0211: * we will perform the clean up of any data stream supplied.
0212: */
0213: switch (reason) {
0214: case PrintJobEvent.DATA_TRANSFER_COMPLETE:
0215: case PrintJobEvent.JOB_CANCELED:
0216: case PrintJobEvent.JOB_FAILED:
0217: case PrintJobEvent.NO_MORE_EVENTS:
0218: case PrintJobEvent.JOB_COMPLETE:
0219: closeDataStreams();
0220: }
0221:
0222: synchronized (this ) {
0223: if (jobListeners != null) {
0224: PrintJobListener listener;
0225: PrintJobEvent event = new PrintJobEvent(this , reason);
0226: for (int i = 0; i < jobListeners.size(); i++) {
0227: listener = (PrintJobListener) (jobListeners
0228: .elementAt(i));
0229: switch (reason) {
0230:
0231: case PrintJobEvent.JOB_CANCELED:
0232: listener.printJobCanceled(event);
0233: break;
0234:
0235: case PrintJobEvent.JOB_FAILED:
0236: listener.printJobFailed(event);
0237: break;
0238:
0239: case PrintJobEvent.DATA_TRANSFER_COMPLETE:
0240: listener.printDataTransferCompleted(event);
0241: break;
0242:
0243: case PrintJobEvent.NO_MORE_EVENTS:
0244: listener.printJobNoMoreEvents(event);
0245: break;
0246:
0247: default:
0248: break;
0249: }
0250: }
0251: }
0252: }
0253: }
0254:
0255: public void addPrintJobAttributeListener(
0256: PrintJobAttributeListener listener,
0257: PrintJobAttributeSet attributes) {
0258: synchronized (this ) {
0259: if (listener == null) {
0260: return;
0261: }
0262: if (attrListeners == null) {
0263: attrListeners = new Vector();
0264: listenedAttributeSets = new Vector();
0265: }
0266: attrListeners.add(listener);
0267: if (attributes == null) {
0268: attributes = new HashPrintJobAttributeSet();
0269: }
0270: listenedAttributeSets.add(attributes);
0271: }
0272: }
0273:
0274: public void removePrintJobAttributeListener(
0275: PrintJobAttributeListener listener) {
0276: synchronized (this ) {
0277: if (listener == null || attrListeners == null) {
0278: return;
0279: }
0280: int index = attrListeners.indexOf(listener);
0281: if (index == -1) {
0282: return;
0283: } else {
0284: attrListeners.remove(index);
0285: listenedAttributeSets.remove(index);
0286: if (attrListeners.isEmpty()) {
0287: attrListeners = null;
0288: listenedAttributeSets = null;
0289: }
0290: }
0291: }
0292: }
0293:
0294: public void print(Doc doc, PrintRequestAttributeSet attributes)
0295: throws PrintException {
0296:
0297: synchronized (this ) {
0298: if (printing) {
0299: throw new PrintException("already printing");
0300: } else {
0301: printing = true;
0302: }
0303: }
0304:
0305: if ((PrinterIsAcceptingJobs) (service
0306: .getAttribute(PrinterIsAcceptingJobs.class)) == PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS) {
0307: throw new PrintException("Printer is not accepting job.");
0308: }
0309:
0310: this .doc = doc;
0311: /* check if the parameters are valid before doing much processing */
0312: DocFlavor flavor = doc.getDocFlavor();
0313:
0314: Object data;
0315:
0316: try {
0317: data = doc.getPrintData();
0318: } catch (IOException e) {
0319: notifyEvent(PrintJobEvent.JOB_FAILED);
0320: throw new PrintException("can't get print data: "
0321: + e.toString());
0322: }
0323:
0324: if (flavor == null || (!service.isDocFlavorSupported(flavor))) {
0325: notifyEvent(PrintJobEvent.JOB_FAILED);
0326: throw new PrintJobFlavorException("invalid flavor", flavor);
0327: }
0328:
0329: initializeAttributeSets(doc, attributes);
0330:
0331: getAttributeValues(flavor);
0332:
0333: // set up mOptions
0334: if ((service instanceof IPPPrintService)
0335: && CUPSPrinter.isCupsRunning()) {
0336:
0337: IPPPrintService.debug_println(debugPrefix
0338: + "instanceof IPPPrintService");
0339:
0340: if (mediaName != null) {
0341: CustomMediaSizeName customMedia = ((IPPPrintService) service)
0342: .findCustomMedia(mediaName);
0343: if (customMedia != null) {
0344: mOptions = " media=" + customMedia.getChoiceName();
0345: }
0346: }
0347:
0348: if (customTray != null
0349: && customTray instanceof CustomMediaTray) {
0350: String choice = customTray.getChoiceName();
0351: if (choice != null) {
0352: mOptions += " media=" + choice;
0353: }
0354: }
0355:
0356: if (nUp != null) {
0357: mOptions += " number-up=" + nUp.getValue();
0358: }
0359:
0360: if (orient == OrientationRequested.LANDSCAPE
0361: && (flavor != null)
0362: && !flavor
0363: .equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE)) {
0364: mOptions += " landscape";
0365: }
0366:
0367: if (sides != null) {
0368: mOptions += " sides=" + sides;
0369: }
0370:
0371: }
0372:
0373: IPPPrintService.debug_println(debugPrefix + "mOptions "
0374: + mOptions);
0375: String repClassName = flavor.getRepresentationClassName();
0376: String val = flavor.getParameter("charset");
0377: String encoding = "us-ascii";
0378: if (val != null && !val.equals("")) {
0379: encoding = val;
0380: }
0381:
0382: if (flavor.equals(DocFlavor.INPUT_STREAM.GIF)
0383: || flavor.equals(DocFlavor.INPUT_STREAM.JPEG)
0384: || flavor.equals(DocFlavor.INPUT_STREAM.PNG)
0385: || flavor.equals(DocFlavor.BYTE_ARRAY.GIF)
0386: || flavor.equals(DocFlavor.BYTE_ARRAY.JPEG)
0387: || flavor.equals(DocFlavor.BYTE_ARRAY.PNG)) {
0388: try {
0389: instream = doc.getStreamForBytes();
0390: if (instream == null) {
0391: notifyEvent(PrintJobEvent.JOB_FAILED);
0392: throw new PrintException("No stream for data");
0393: }
0394: if (!(service instanceof IPPPrintService && ((IPPPrintService) service)
0395: .isIPPSupportedImages(flavor.getMimeType()))) {
0396: printableJob(new ImagePrinter(instream));
0397: ((UnixPrintService) service).wakeNotifier();
0398: return;
0399: }
0400: } catch (ClassCastException cce) {
0401: notifyEvent(PrintJobEvent.JOB_FAILED);
0402: throw new PrintException(cce);
0403: } catch (IOException ioe) {
0404: notifyEvent(PrintJobEvent.JOB_FAILED);
0405: throw new PrintException(ioe);
0406: }
0407: } else if (flavor.equals(DocFlavor.URL.GIF)
0408: || flavor.equals(DocFlavor.URL.JPEG)
0409: || flavor.equals(DocFlavor.URL.PNG)) {
0410: try {
0411: URL url = (URL) data;
0412: if ((service instanceof IPPPrintService)
0413: && ((IPPPrintService) service)
0414: .isIPPSupportedImages(flavor
0415: .getMimeType())) {
0416: instream = url.openStream();
0417: } else {
0418: printableJob(new ImagePrinter(url));
0419: ((UnixPrintService) service).wakeNotifier();
0420: return;
0421: }
0422: } catch (ClassCastException cce) {
0423: notifyEvent(PrintJobEvent.JOB_FAILED);
0424: throw new PrintException(cce);
0425: } catch (IOException e) {
0426: notifyEvent(PrintJobEvent.JOB_FAILED);
0427: throw new PrintException(e.toString());
0428: }
0429: } else if (flavor.equals(DocFlavor.CHAR_ARRAY.TEXT_PLAIN)
0430: || flavor.equals(DocFlavor.READER.TEXT_PLAIN)
0431: || flavor.equals(DocFlavor.STRING.TEXT_PLAIN)) {
0432: try {
0433: reader = doc.getReaderForText();
0434: if (reader == null) {
0435: notifyEvent(PrintJobEvent.JOB_FAILED);
0436: throw new PrintException("No reader for data");
0437: }
0438: } catch (IOException ioe) {
0439: notifyEvent(PrintJobEvent.JOB_FAILED);
0440: throw new PrintException(ioe.toString());
0441: }
0442: } else if (repClassName.equals("[B")
0443: || repClassName.equals("java.io.InputStream")) {
0444: try {
0445: instream = doc.getStreamForBytes();
0446: if (instream == null) {
0447: notifyEvent(PrintJobEvent.JOB_FAILED);
0448: throw new PrintException("No stream for data");
0449: }
0450: } catch (IOException ioe) {
0451: notifyEvent(PrintJobEvent.JOB_FAILED);
0452: throw new PrintException(ioe.toString());
0453: }
0454: } else if (repClassName.equals("java.net.URL")) {
0455: /*
0456: * This extracts the data from the URL and passes it the content
0457: * directly to the print service as a file.
0458: * This is appropriate for the current implementation where lp or
0459: * lpr is always used to spool the data. We expect to revise the
0460: * implementation to provide more complete IPP support (ie not just
0461: * CUPS) and at that time the job will be spooled via IPP
0462: * and the URL
0463: * itself should be sent to the IPP print service not the content.
0464: */
0465: URL url = (URL) data;
0466: try {
0467: instream = url.openStream();
0468: } catch (IOException e) {
0469: notifyEvent(PrintJobEvent.JOB_FAILED);
0470: throw new PrintException(e.toString());
0471: }
0472: } else if (repClassName.equals("java.awt.print.Pageable")) {
0473: try {
0474: pageableJob((Pageable) doc.getPrintData());
0475: if (service instanceof IPPPrintService) {
0476: ((IPPPrintService) service).wakeNotifier();
0477: } else {
0478: ((UnixPrintService) service).wakeNotifier();
0479: }
0480: return;
0481: } catch (ClassCastException cce) {
0482: notifyEvent(PrintJobEvent.JOB_FAILED);
0483: throw new PrintException(cce);
0484: } catch (IOException ioe) {
0485: notifyEvent(PrintJobEvent.JOB_FAILED);
0486: throw new PrintException(ioe);
0487: }
0488: } else if (repClassName.equals("java.awt.print.Printable")) {
0489: try {
0490: printableJob((Printable) doc.getPrintData());
0491: if (service instanceof IPPPrintService) {
0492: ((IPPPrintService) service).wakeNotifier();
0493: } else {
0494: ((UnixPrintService) service).wakeNotifier();
0495: }
0496: return;
0497: } catch (ClassCastException cce) {
0498: notifyEvent(PrintJobEvent.JOB_FAILED);
0499: throw new PrintException(cce);
0500: } catch (IOException ioe) {
0501: notifyEvent(PrintJobEvent.JOB_FAILED);
0502: throw new PrintException(ioe);
0503: }
0504: } else {
0505: notifyEvent(PrintJobEvent.JOB_FAILED);
0506: throw new PrintException("unrecognized class: "
0507: + repClassName);
0508: }
0509:
0510: // now spool the print data.
0511: PrinterOpener po = new PrinterOpener();
0512: java.security.AccessController.doPrivileged(po);
0513: if (po.pex != null) {
0514: throw po.pex;
0515: }
0516: OutputStream output = po.result;
0517:
0518: /* There are three cases:
0519: * 1) Text data from a Reader, just pass through.
0520: * 2) Text data from an input stream which we must read using the
0521: * correct encoding
0522: * 3) Raw byte data from an InputStream we don't interpret as text,
0523: * just pass through: eg postscript.
0524: */
0525:
0526: BufferedWriter bw = null;
0527: if ((instream == null && reader != null)) {
0528: BufferedReader br = new BufferedReader(reader);
0529: OutputStreamWriter osw = new OutputStreamWriter(output);
0530: bw = new BufferedWriter(osw);
0531: char[] buffer = new char[1024];
0532: int cread;
0533:
0534: try {
0535: while ((cread = br.read(buffer, 0, buffer.length)) >= 0) {
0536: bw.write(buffer, 0, cread);
0537: }
0538: br.close();
0539: bw.flush();
0540: bw.close();
0541: } catch (IOException e) {
0542: notifyEvent(PrintJobEvent.JOB_FAILED);
0543: throw new PrintException(e);
0544: }
0545: } else if (instream != null
0546: && flavor.getMediaType().equalsIgnoreCase("text")) {
0547: try {
0548:
0549: InputStreamReader isr = new InputStreamReader(instream,
0550: encoding);
0551: BufferedReader br = new BufferedReader(isr);
0552: OutputStreamWriter osw = new OutputStreamWriter(output);
0553: bw = new BufferedWriter(osw);
0554: char[] buffer = new char[1024];
0555: int cread;
0556:
0557: while ((cread = br.read(buffer, 0, buffer.length)) >= 0) {
0558: bw.write(buffer, 0, cread);
0559: }
0560: bw.flush();
0561: } catch (IOException e) {
0562: notifyEvent(PrintJobEvent.JOB_FAILED);
0563: throw new PrintException(e);
0564: } finally {
0565: try {
0566: if (bw != null) {
0567: bw.close();
0568: }
0569: } catch (IOException e) {
0570: }
0571: }
0572: } else if (instream != null) {
0573: BufferedInputStream bin = new BufferedInputStream(instream);
0574: BufferedOutputStream bout = new BufferedOutputStream(output);
0575: byte[] buffer = new byte[1024];
0576: int bread = 0;
0577:
0578: try {
0579: while ((bread = bin.read(buffer)) >= 0) {
0580: bout.write(buffer, 0, bread);
0581: }
0582: bin.close();
0583: bout.flush();
0584: bout.close();
0585: } catch (IOException e) {
0586: notifyEvent(PrintJobEvent.JOB_FAILED);
0587: throw new PrintException(e);
0588: }
0589: }
0590: notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);
0591:
0592: if (mDestType == UnixPrintJob.DESTPRINTER) {
0593: PrinterSpooler spooler = new PrinterSpooler();
0594: java.security.AccessController.doPrivileged(spooler);
0595: if (spooler.pex != null) {
0596: throw spooler.pex;
0597: }
0598: }
0599: notifyEvent(PrintJobEvent.NO_MORE_EVENTS);
0600: if (service instanceof IPPPrintService) {
0601: ((IPPPrintService) service).wakeNotifier();
0602: } else {
0603: ((UnixPrintService) service).wakeNotifier();
0604: }
0605: }
0606:
0607: public void printableJob(Printable printable) throws PrintException {
0608: try {
0609: synchronized (this ) {
0610: if (job != null) { // shouldn't happen
0611: throw new PrintException("already printing");
0612: } else {
0613: job = new PSPrinterJob();
0614: }
0615: }
0616: job.setPrintService(getPrintService());
0617: job.setCopies(copies);
0618: job.setJobName(jobName);
0619: PageFormat pf = new PageFormat();
0620: if (mediaSize != null) {
0621: Paper p = new Paper();
0622: p.setSize(mediaSize.getX(MediaSize.INCH) * 72.0,
0623: mediaSize.getY(MediaSize.INCH) * 72.0);
0624: p.setImageableArea(72.0, 72.0, p.getWidth() - 144.0, p
0625: .getHeight() - 144.0);
0626: pf.setPaper(p);
0627: }
0628: if (orient == OrientationRequested.REVERSE_LANDSCAPE) {
0629: pf.setOrientation(PageFormat.REVERSE_LANDSCAPE);
0630: } else if (orient == OrientationRequested.LANDSCAPE) {
0631: pf.setOrientation(PageFormat.LANDSCAPE);
0632: }
0633: job.setPrintable(printable, pf);
0634: job.print(reqAttrSet);
0635: notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);
0636: return;
0637: } catch (PrinterException pe) {
0638: notifyEvent(PrintJobEvent.JOB_FAILED);
0639: throw new PrintException(pe);
0640: } finally {
0641: printReturned = true;
0642: notifyEvent(PrintJobEvent.NO_MORE_EVENTS);
0643: }
0644: }
0645:
0646: public void pageableJob(Pageable pageable) throws PrintException {
0647: try {
0648: synchronized (this ) {
0649: if (job != null) { // shouldn't happen
0650: throw new PrintException("already printing");
0651: } else {
0652: job = new PSPrinterJob();
0653: }
0654: }
0655: job.setPrintService(getPrintService());
0656: job.setCopies(copies);
0657: job.setJobName(jobName);
0658: job.setPageable(pageable);
0659: job.print(reqAttrSet);
0660: notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);
0661: return;
0662: } catch (PrinterException pe) {
0663: notifyEvent(PrintJobEvent.JOB_FAILED);
0664: throw new PrintException(pe);
0665: } finally {
0666: printReturned = true;
0667: notifyEvent(PrintJobEvent.NO_MORE_EVENTS);
0668: }
0669: }
0670:
0671: /* There's some inefficiency here as the job set is created even though
0672: * it may never be requested.
0673: */
0674: private synchronized void initializeAttributeSets(Doc doc,
0675: PrintRequestAttributeSet reqSet) {
0676:
0677: reqAttrSet = new HashPrintRequestAttributeSet();
0678: jobAttrSet = new HashPrintJobAttributeSet();
0679:
0680: Attribute[] attrs;
0681: if (reqSet != null) {
0682: reqAttrSet.addAll(reqSet);
0683: attrs = reqSet.toArray();
0684: for (int i = 0; i < attrs.length; i++) {
0685: if (attrs[i] instanceof PrintJobAttribute) {
0686: jobAttrSet.add(attrs[i]);
0687: }
0688: }
0689: }
0690:
0691: DocAttributeSet docSet = doc.getAttributes();
0692: if (docSet != null) {
0693: attrs = docSet.toArray();
0694: for (int i = 0; i < attrs.length; i++) {
0695: if (attrs[i] instanceof PrintRequestAttribute) {
0696: reqAttrSet.add(attrs[i]);
0697: }
0698: if (attrs[i] instanceof PrintJobAttribute) {
0699: jobAttrSet.add(attrs[i]);
0700: }
0701: }
0702: }
0703:
0704: /* add the user name to the job */
0705: String userName = "";
0706: try {
0707: userName = System.getProperty("user.name");
0708: } catch (SecurityException se) {
0709: }
0710:
0711: if (userName == null || userName.equals("")) {
0712: RequestingUserName ruName = (RequestingUserName) reqSet
0713: .get(RequestingUserName.class);
0714: if (ruName != null) {
0715: jobAttrSet.add(new JobOriginatingUserName(ruName
0716: .getValue(), ruName.getLocale()));
0717: } else {
0718: jobAttrSet.add(new JobOriginatingUserName("", null));
0719: }
0720: } else {
0721: jobAttrSet.add(new JobOriginatingUserName(userName, null));
0722: }
0723:
0724: /* if no job name supplied use doc name (if supplied), if none and
0725: * its a URL use that, else finally anything .. */
0726: if (jobAttrSet.get(JobName.class) == null) {
0727: JobName jobName;
0728: if (docSet != null
0729: && docSet.get(DocumentName.class) != null) {
0730: DocumentName docName = (DocumentName) docSet
0731: .get(DocumentName.class);
0732: jobName = new JobName(docName.getValue(), docName
0733: .getLocale());
0734: jobAttrSet.add(jobName);
0735: } else {
0736: String str = "JPS Job:" + doc;
0737: try {
0738: Object printData = doc.getPrintData();
0739: if (printData instanceof URL) {
0740: str = ((URL) (doc.getPrintData())).toString();
0741: }
0742: } catch (IOException e) {
0743: }
0744: jobName = new JobName(str, null);
0745: jobAttrSet.add(jobName);
0746: }
0747: }
0748:
0749: jobAttrSet = AttributeSetUtilities.unmodifiableView(jobAttrSet);
0750: }
0751:
0752: private void getAttributeValues(DocFlavor flavor)
0753: throws PrintException {
0754: Attribute attr;
0755: Class category;
0756:
0757: if (reqAttrSet.get(Fidelity.class) == Fidelity.FIDELITY_TRUE) {
0758: fidelity = true;
0759: } else {
0760: fidelity = false;
0761: }
0762:
0763: Attribute[] attrs = reqAttrSet.toArray();
0764: for (int i = 0; i < attrs.length; i++) {
0765: attr = attrs[i];
0766: category = attr.getCategory();
0767: if (fidelity == true) {
0768: if (!service.isAttributeCategorySupported(category)) {
0769: notifyEvent(PrintJobEvent.JOB_FAILED);
0770: throw new PrintJobAttributeException(
0771: "unsupported category: " + category,
0772: category, null);
0773: } else if (!service.isAttributeValueSupported(attr,
0774: flavor, null)) {
0775: notifyEvent(PrintJobEvent.JOB_FAILED);
0776: throw new PrintJobAttributeException(
0777: "unsupported attribute: " + attr, null,
0778: attr);
0779: }
0780: }
0781: if (category == Destination.class) {
0782: URI uri = ((Destination) attr).getURI();
0783: if (!"file".equals(uri.getScheme())) {
0784: notifyEvent(PrintJobEvent.JOB_FAILED);
0785: throw new PrintException("Not a file: URI");
0786: } else {
0787: try {
0788: mDestType = DESTFILE;
0789: mDestination = (new File(uri)).getPath();
0790: } catch (Exception e) {
0791: throw new PrintException(e);
0792: }
0793: // check write access
0794: SecurityManager security = System
0795: .getSecurityManager();
0796: if (security != null) {
0797: try {
0798: security.checkWrite(mDestination);
0799: } catch (SecurityException se) {
0800: notifyEvent(PrintJobEvent.JOB_FAILED);
0801: throw new PrintException(se);
0802: }
0803: }
0804: }
0805: } else if (category == JobSheets.class) {
0806: if ((JobSheets) attr == JobSheets.NONE) {
0807: mNoJobSheet = true;
0808: }
0809: } else if (category == JobName.class) {
0810: jobName = ((JobName) attr).getValue();
0811: } else if (category == Copies.class) {
0812: copies = ((Copies) attr).getValue();
0813: } else if (category == Media.class) {
0814: if (attr instanceof MediaSizeName) {
0815: mediaName = (MediaSizeName) attr;
0816: IPPPrintService.debug_println(debugPrefix
0817: + "mediaName " + mediaName);
0818: if (!service.isAttributeValueSupported(attr, null,
0819: null)) {
0820: mediaSize = MediaSize
0821: .getMediaSizeForName(mediaName);
0822: }
0823: } else if (attr instanceof CustomMediaTray) {
0824: customTray = (CustomMediaTray) attr;
0825: }
0826: } else if (category == OrientationRequested.class) {
0827: orient = (OrientationRequested) attr;
0828: } else if (category == NumberUp.class) {
0829: nUp = (NumberUp) attr;
0830: } else if (category == Sides.class) {
0831: sides = (Sides) attr;
0832: }
0833: }
0834: }
0835:
0836: private String[] printExecCmd(String printer, String options,
0837: boolean noJobSheet, String banner, int copies,
0838: String spoolFile) {
0839: int PRINTER = 0x1;
0840: int OPTIONS = 0x2;
0841: int BANNER = 0x4;
0842: int COPIES = 0x8;
0843: int NOSHEET = 0x10;
0844: int pFlags = 0;
0845: String execCmd[];
0846: int ncomps = 2; // minimum number of print args
0847: int n = 0;
0848:
0849: // conveniently "lp" is the default destination for both lp and lpr.
0850: if (printer != null && !printer.equals("")
0851: && !printer.equals("lp")) {
0852: pFlags |= PRINTER;
0853: ncomps += 1;
0854: }
0855: if (options != null && !options.equals("")) {
0856: pFlags |= OPTIONS;
0857: ncomps += 1;
0858: }
0859: if (banner != null && !banner.equals("")) {
0860: pFlags |= BANNER;
0861: ncomps += 1;
0862: }
0863: if (copies > 1) {
0864: pFlags |= COPIES;
0865: ncomps += 1;
0866: }
0867: if (noJobSheet) {
0868: pFlags |= NOSHEET;
0869: ncomps += 1;
0870: }
0871: if (UnixPrintServiceLookup.osname.equals("SunOS")) {
0872: ncomps += 1; // lp uses 1 more arg than lpr (make a copy)
0873: execCmd = new String[ncomps];
0874: execCmd[n++] = "/usr/bin/lp";
0875: execCmd[n++] = "-c"; // make a copy of the spool file
0876: if ((pFlags & PRINTER) != 0) {
0877: execCmd[n++] = new String("-d" + printer);
0878: }
0879: if ((pFlags & BANNER) != 0) {
0880: String quoteChar = "\"";
0881: execCmd[n++] = new String("-t " + quoteChar + banner
0882: + quoteChar);
0883: }
0884: if ((pFlags & COPIES) != 0) {
0885: execCmd[n++] = new String("-n "
0886: + new Integer(copies).toString());
0887: }
0888: if ((pFlags & NOSHEET) != 0) {
0889: execCmd[n++] = new String("-o nobanner");
0890: }
0891: if ((pFlags & OPTIONS) != 0) {
0892: execCmd[n++] = new String("-o " + options);
0893: }
0894: } else {
0895: execCmd = new String[ncomps];
0896: execCmd[n++] = "/usr/bin/lpr";
0897: if ((pFlags & PRINTER) != 0) {
0898: execCmd[n++] = new String("-P" + printer);
0899: }
0900: if ((pFlags & BANNER) != 0) {
0901: execCmd[n++] = new String("-J " + banner);
0902: }
0903: if ((pFlags & COPIES) != 0) {
0904: execCmd[n++] = new String("-#"
0905: + new Integer(copies).toString());
0906: }
0907: if ((pFlags & NOSHEET) != 0) {
0908: execCmd[n++] = new String("-h");
0909: }
0910: if ((pFlags & OPTIONS) != 0) {
0911: execCmd[n++] = new String("-o" + options);
0912: }
0913: }
0914: execCmd[n++] = spoolFile;
0915: if (IPPPrintService.debugPrint) {
0916: System.out.println("UnixPrintJob>> execCmd");
0917: for (int i = 0; i < execCmd.length; i++) {
0918: System.out.print(" " + execCmd[i]);
0919: }
0920: System.out.println();
0921: }
0922: return execCmd;
0923: }
0924:
0925: private static int DESTPRINTER = 1;
0926: private static int DESTFILE = 2;
0927: private int mDestType = DESTPRINTER;
0928:
0929: private File spoolFile;
0930: private String mDestination, mOptions = "";
0931: private boolean mNoJobSheet = false;
0932:
0933: // Inner class to run "privileged" to open the printer output stream.
0934:
0935: private class PrinterOpener implements
0936: java.security.PrivilegedAction {
0937: PrintException pex;
0938: OutputStream result;
0939:
0940: public Object run() {
0941: try {
0942: if (mDestType == UnixPrintJob.DESTFILE) {
0943: spoolFile = new File(mDestination);
0944: } else {
0945: /* Write to a temporary file which will be spooled to
0946: * the printer then deleted. In the case that the file
0947: * is not removed for some reason, request that it is
0948: * removed when the VM exits.
0949: */
0950: spoolFile = File.createTempFile("javaprint", ".ps",
0951: null);
0952: spoolFile.deleteOnExit();
0953: }
0954: result = new FileOutputStream(spoolFile);
0955: return result;
0956: } catch (IOException ex) {
0957: // If there is an IOError we subvert it to a PrinterException.
0958: notifyEvent(PrintJobEvent.JOB_FAILED);
0959: pex = new PrintException(ex);
0960: }
0961: return null;
0962: }
0963: }
0964:
0965: // Inner class to run "privileged" to invoke the system print command
0966:
0967: private class PrinterSpooler implements
0968: java.security.PrivilegedAction {
0969: PrintException pex;
0970:
0971: public Object run() {
0972: try {
0973: /**
0974: * Spool to the printer.
0975: */
0976: if (spoolFile == null || !spoolFile.exists()) {
0977: pex = new PrintException("No spool file");
0978: notifyEvent(PrintJobEvent.JOB_FAILED);
0979: return null;
0980: }
0981: String fileName = spoolFile.getAbsolutePath();
0982: String execCmd[] = printExecCmd(mDestination, mOptions,
0983: mNoJobSheet, jobName, copies, fileName);
0984:
0985: Process process = Runtime.getRuntime().exec(execCmd);
0986: process.waitFor();
0987: spoolFile.delete();
0988: notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);
0989: } catch (IOException ex) {
0990: notifyEvent(PrintJobEvent.JOB_FAILED);
0991: // REMIND : 2d printing throws PrinterException
0992: pex = new PrintException(ex);
0993: } catch (InterruptedException ie) {
0994: notifyEvent(PrintJobEvent.JOB_FAILED);
0995: pex = new PrintException(ie);
0996: } finally {
0997: notifyEvent(PrintJobEvent.NO_MORE_EVENTS);
0998: }
0999: return null;
1000: }
1001: }
1002:
1003: public void cancel() throws PrintException {
1004: synchronized (this ) {
1005: if (!printing) {
1006: throw new PrintException("Job is not yet submitted.");
1007: } else if (job != null && !printReturned) {
1008: job.cancel();
1009: notifyEvent(PrintJobEvent.JOB_CANCELED);
1010: return;
1011: } else {
1012: throw new PrintException("Job could not be cancelled.");
1013: }
1014: }
1015: }
1016: }
|