Path: blob/master/src/java.desktop/share/classes/sun/print/PSStreamPrintJob.java
41153 views
/*1* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.print;2627import java.net.URL;28import java.io.InputStream;29import java.io.IOException;30import java.io.Reader;31import java.util.Vector;3233import javax.print.CancelablePrintJob;34import javax.print.Doc;35import javax.print.DocFlavor;36import javax.print.DocPrintJob;37import javax.print.PrintService;38import javax.print.PrintException;39import javax.print.event.PrintJobEvent;40import javax.print.event.PrintJobListener;41import javax.print.event.PrintJobAttributeListener;4243import javax.print.attribute.Attribute;44import javax.print.attribute.AttributeSet;45import javax.print.attribute.AttributeSetUtilities;46import javax.print.attribute.DocAttributeSet;47import javax.print.attribute.HashPrintJobAttributeSet;48import javax.print.attribute.HashPrintRequestAttributeSet;49import javax.print.attribute.PrintJobAttribute;50import javax.print.attribute.PrintJobAttributeSet;51import javax.print.attribute.PrintRequestAttribute;52import javax.print.attribute.PrintRequestAttributeSet;53import javax.print.attribute.standard.Copies;54import javax.print.attribute.standard.DocumentName;55import javax.print.attribute.standard.Fidelity;56import javax.print.attribute.standard.JobName;57import javax.print.attribute.standard.JobOriginatingUserName;58import javax.print.attribute.standard.Media;59import javax.print.attribute.standard.MediaSize;60import javax.print.attribute.standard.MediaSizeName;61import javax.print.attribute.standard.OrientationRequested;62import javax.print.attribute.standard.RequestingUserName;6364import java.awt.print.*;6566public class PSStreamPrintJob implements CancelablePrintJob {6768private transient Vector<PrintJobListener> jobListeners;69private transient Vector<PrintJobAttributeListener> attrListeners;70private transient Vector<PrintJobAttributeSet> listenedAttributeSets;7172private PSStreamPrintService service;73private boolean fidelity;74private boolean printing = false;75private boolean printReturned = false;76private PrintRequestAttributeSet reqAttrSet = null;77private PrintJobAttributeSet jobAttrSet = null;78private PrinterJob job;79private Doc doc;80/* these variables used globally to store reference to the print81* data retrieved as a stream. On completion these are always closed82* if non-null.83*/84private InputStream instream = null;85private Reader reader = null;8687/* default values overridden by those extracted from the attributes */88private String jobName = "Java Printing";89private int copies = 1;90private MediaSize mediaSize = MediaSize.NA.LETTER;91private OrientationRequested orient = OrientationRequested.PORTRAIT;9293PSStreamPrintJob(PSStreamPrintService service) {94this.service = service;95}9697public PrintService getPrintService() {98return service;99}100101public PrintJobAttributeSet getAttributes() {102synchronized (this) {103if (jobAttrSet == null) {104/* just return an empty set until the job is submitted */105PrintJobAttributeSet jobSet = new HashPrintJobAttributeSet();106return AttributeSetUtilities.unmodifiableView(jobSet);107} else {108return jobAttrSet;109}110}111}112113public void addPrintJobListener(PrintJobListener listener) {114synchronized (this) {115if (listener == null) {116return;117}118if (jobListeners == null) {119jobListeners = new Vector<>();120}121jobListeners.add(listener);122}123}124125public void removePrintJobListener(PrintJobListener listener) {126synchronized (this) {127if (listener == null || jobListeners == null ) {128return;129}130jobListeners.remove(listener);131if (jobListeners.isEmpty()) {132jobListeners = null;133}134}135}136137/* Closes any stream already retrieved for the data.138* We want to avoid unnecessarily asking the Doc to create a stream only139* to get a reference in order to close it because the job failed.140* If the representation class is itself a "stream", this141* closes that stream too.142*/143private void closeDataStreams() {144145if (doc == null) {146return;147}148149Object data = null;150151try {152data = doc.getPrintData();153} catch (IOException e) {154return;155}156157if (instream != null) {158try {159instream.close();160} catch (IOException e) {161} finally {162instream = null;163}164}165else if (reader != null) {166try {167reader.close();168} catch (IOException e) {169} finally {170reader = null;171}172}173else if (data instanceof InputStream) {174try {175((InputStream)data).close();176} catch (IOException e) {177}178}179else if (data instanceof Reader) {180try {181((Reader)data).close();182} catch (IOException e) {183}184}185}186187private void notifyEvent(int reason) {188synchronized (this) {189if (jobListeners != null) {190PrintJobListener listener;191PrintJobEvent event = new PrintJobEvent(this, reason);192for (int i = 0; i < jobListeners.size(); i++) {193listener = jobListeners.elementAt(i);194switch (reason) {195196case PrintJobEvent.JOB_CANCELED :197listener.printJobCanceled(event);198break;199200case PrintJobEvent.JOB_FAILED :201listener.printJobFailed(event);202break;203204case PrintJobEvent.DATA_TRANSFER_COMPLETE :205listener.printDataTransferCompleted(event);206break;207208case PrintJobEvent.NO_MORE_EVENTS :209listener.printJobNoMoreEvents(event);210break;211212case PrintJobEvent.JOB_COMPLETE :213listener.printJobCompleted(event);214break;215216default:217break;218}219}220}221}222}223224public void addPrintJobAttributeListener(225PrintJobAttributeListener listener,226PrintJobAttributeSet attributes) {227synchronized (this) {228if (listener == null) {229return;230}231if (attrListeners == null) {232attrListeners = new Vector<>();233listenedAttributeSets = new Vector<>();234}235attrListeners.add(listener);236if (attributes == null) {237attributes = new HashPrintJobAttributeSet();238}239listenedAttributeSets.add(attributes);240}241}242243public void removePrintJobAttributeListener(244PrintJobAttributeListener listener) {245synchronized (this) {246if (listener == null || attrListeners == null ) {247return;248}249int index = attrListeners.indexOf(listener);250if (index == -1) {251return;252} else {253attrListeners.remove(index);254listenedAttributeSets.remove(index);255if (attrListeners.isEmpty()) {256attrListeners = null;257listenedAttributeSets = null;258}259}260}261}262263public void print(Doc doc, PrintRequestAttributeSet attributes)264throws PrintException {265266synchronized (this) {267if (printing) {268throw new PrintException("already printing");269} else {270printing = true;271}272}273274this.doc = doc;275/* check if the parameters are valid before doing much processing */276DocFlavor flavor = doc.getDocFlavor();277Object data;278279try {280data = doc.getPrintData();281} catch (IOException e) {282notifyEvent(PrintJobEvent.JOB_FAILED);283throw new PrintException("can't get print data: " + e.toString());284}285286if (flavor == null || (!service.isDocFlavorSupported(flavor))) {287notifyEvent(PrintJobEvent.JOB_FAILED);288throw new PrintJobFlavorException("invalid flavor", flavor);289}290291initializeAttributeSets(doc, attributes);292293getAttributeValues(flavor);294295String repClassName = flavor.getRepresentationClassName();296if (flavor.equals(DocFlavor.INPUT_STREAM.GIF) ||297flavor.equals(DocFlavor.INPUT_STREAM.JPEG) ||298flavor.equals(DocFlavor.INPUT_STREAM.PNG) ||299flavor.equals(DocFlavor.BYTE_ARRAY.GIF) ||300flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) ||301flavor.equals(DocFlavor.BYTE_ARRAY.PNG)) {302try {303instream = doc.getStreamForBytes();304printableJob(new ImagePrinter(instream), reqAttrSet);305return;306} catch (ClassCastException cce) {307notifyEvent(PrintJobEvent.JOB_FAILED);308throw new PrintException(cce);309} catch (IOException ioe) {310notifyEvent(PrintJobEvent.JOB_FAILED);311throw new PrintException(ioe);312}313} else if (flavor.equals(DocFlavor.URL.GIF) ||314flavor.equals(DocFlavor.URL.JPEG) ||315flavor.equals(DocFlavor.URL.PNG)) {316try {317printableJob(new ImagePrinter((URL)data), reqAttrSet);318return;319} catch (ClassCastException cce) {320notifyEvent(PrintJobEvent.JOB_FAILED);321throw new PrintException(cce);322}323} else if (repClassName.equals("java.awt.print.Pageable")) {324try {325pageableJob((Pageable)doc.getPrintData(), reqAttrSet);326return;327} catch (ClassCastException cce) {328notifyEvent(PrintJobEvent.JOB_FAILED);329throw new PrintException(cce);330} catch (IOException ioe) {331notifyEvent(PrintJobEvent.JOB_FAILED);332throw new PrintException(ioe);333}334} else if (repClassName.equals("java.awt.print.Printable")) {335try {336printableJob((Printable)doc.getPrintData(), reqAttrSet);337return;338} catch (ClassCastException cce) {339notifyEvent(PrintJobEvent.JOB_FAILED);340throw new PrintException(cce);341} catch (IOException ioe) {342notifyEvent(PrintJobEvent.JOB_FAILED);343throw new PrintException(ioe);344}345} else {346notifyEvent(PrintJobEvent.JOB_FAILED);347throw new PrintException("unrecognized class: "+repClassName);348}349}350351public void printableJob(Printable printable,352PrintRequestAttributeSet attributes)353throws PrintException {354try {355synchronized(this) {356if (job != null) { // shouldn't happen357throw new PrintException("already printing");358} else {359job = new PSPrinterJob();360}361}362job.setPrintService(getPrintService());363PageFormat pf = new PageFormat();364if (mediaSize != null) {365Paper p = new Paper();366p.setSize(mediaSize.getX(MediaSize.INCH)*72.0,367mediaSize.getY(MediaSize.INCH)*72.0);368p.setImageableArea(72.0, 72.0, p.getWidth()-144.0,369p.getHeight()-144.0);370pf.setPaper(p);371}372if (orient == OrientationRequested.REVERSE_LANDSCAPE) {373pf.setOrientation(PageFormat.REVERSE_LANDSCAPE);374} else if (orient == OrientationRequested.LANDSCAPE) {375pf.setOrientation(PageFormat.LANDSCAPE);376}377job.setPrintable(printable, pf);378job.print(attributes);379notifyEvent(PrintJobEvent.JOB_COMPLETE);380return;381} catch (PrinterException pe) {382notifyEvent(PrintJobEvent.JOB_FAILED);383throw new PrintException(pe);384} finally {385printReturned = true;386}387}388389public void pageableJob(Pageable pageable,390PrintRequestAttributeSet attributes)391throws PrintException {392try {393synchronized(this) {394if (job != null) { // shouldn't happen395throw new PrintException("already printing");396} else {397job = new PSPrinterJob();398}399}400job.setPrintService(getPrintService());401job.setPageable(pageable);402job.print(attributes);403notifyEvent(PrintJobEvent.JOB_COMPLETE);404return;405} catch (PrinterException pe) {406notifyEvent(PrintJobEvent.JOB_FAILED);407throw new PrintException(pe);408} finally {409printReturned = true;410}411}412413/* There's some inefficiency here as the job set is created even though414* it may never be requested.415*/416private synchronized void417initializeAttributeSets(Doc doc, PrintRequestAttributeSet reqSet) {418419reqAttrSet = new HashPrintRequestAttributeSet();420jobAttrSet = new HashPrintJobAttributeSet();421422Attribute[] attrs;423if (reqSet != null) {424reqAttrSet.addAll(reqSet);425attrs = reqSet.toArray();426for (int i=0; i<attrs.length; i++) {427if (attrs[i] instanceof PrintJobAttribute) {428jobAttrSet.add(attrs[i]);429}430}431}432433DocAttributeSet docSet = doc.getAttributes();434if (docSet != null) {435attrs = docSet.toArray();436for (int i=0; i<attrs.length; i++) {437if (attrs[i] instanceof PrintRequestAttribute) {438reqAttrSet.add(attrs[i]);439}440if (attrs[i] instanceof PrintJobAttribute) {441jobAttrSet.add(attrs[i]);442}443}444}445446/* add the user name to the job */447String userName = "";448try {449userName = System.getProperty("user.name");450} catch (SecurityException se) {451}452453if (userName == null || userName.isEmpty()) {454RequestingUserName ruName =455(RequestingUserName)reqSet.get(RequestingUserName.class);456if (ruName != null) {457jobAttrSet.add(458new JobOriginatingUserName(ruName.getValue(),459ruName.getLocale()));460} else {461jobAttrSet.add(new JobOriginatingUserName("", null));462}463} else {464jobAttrSet.add(new JobOriginatingUserName(userName, null));465}466467/* if no job name supplied use doc name (if supplied), if none and468* its a URL use that, else finally anything .. */469if (jobAttrSet.get(JobName.class) == null) {470JobName jobName;471if (docSet != null && docSet.get(DocumentName.class) != null) {472DocumentName docName =473(DocumentName)docSet.get(DocumentName.class);474jobName = new JobName(docName.getValue(), docName.getLocale());475jobAttrSet.add(jobName);476} else {477String str = "JPS Job:" + doc;478try {479Object printData = doc.getPrintData();480if (printData instanceof URL) {481str = ((URL)(doc.getPrintData())).toString();482}483} catch (IOException e) {484}485jobName = new JobName(str, null);486jobAttrSet.add(jobName);487}488}489490jobAttrSet = AttributeSetUtilities.unmodifiableView(jobAttrSet);491}492493private void getAttributeValues(DocFlavor flavor) throws PrintException {494495Attribute attr;496Class<? extends Attribute> category;497498if (reqAttrSet.get(Fidelity.class) == Fidelity.FIDELITY_TRUE) {499fidelity = true;500} else {501fidelity = false;502}503504Attribute []attrs = reqAttrSet.toArray();505for (int i=0; i<attrs.length; i++) {506attr = attrs[i];507category = attr.getCategory();508if (fidelity == true) {509if (!service.isAttributeCategorySupported(category)) {510notifyEvent(PrintJobEvent.JOB_FAILED);511throw new PrintJobAttributeException(512"unsupported category: " + category, category, null);513} else if514(!service.isAttributeValueSupported(attr, flavor, null)) {515notifyEvent(PrintJobEvent.JOB_FAILED);516throw new PrintJobAttributeException(517"unsupported attribute: " + attr, null, attr);518}519}520if (category == JobName.class) {521jobName = ((JobName)attr).getValue();522} else if (category == Copies.class) {523copies = ((Copies)attr).getValue();524} else if (category == Media.class) {525if (attr instanceof MediaSizeName &&526service.isAttributeValueSupported(attr, null, null)) {527mediaSize =528MediaSize.getMediaSizeForName((MediaSizeName)attr);529}530} else if (category == OrientationRequested.class) {531orient = (OrientationRequested)attr;532}533}534}535536/* Cancel PrinterJob jobs that haven't yet completed. */537public void cancel() throws PrintException {538synchronized (this) {539if (!printing) {540throw new PrintException("Job is not yet submitted.");541} else if (job != null && !printReturned) {542job.cancel();543notifyEvent(PrintJobEvent.JOB_CANCELED);544return;545} else {546throw new PrintException("Job could not be cancelled.");547}548}549}550551}552553554