Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/classes/sun/print/Win32PrintJob.java
32287 views
/*1* Copyright (c) 2000, 2013, 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.URI;28import java.io.BufferedInputStream;29import java.io.BufferedOutputStream;30import java.io.File;31import java.io.FileOutputStream;32import java.io.InputStream;33import java.io.OutputStream;34import java.io.InputStream;35import java.io.IOException;36import java.io.FileNotFoundException;37import java.io.Reader;38import java.net.URL;39import java.util.Vector;4041import javax.print.CancelablePrintJob;42import javax.print.Doc;43import javax.print.DocFlavor;44import javax.print.DocPrintJob;45import javax.print.PrintService;46import javax.print.PrintException;47import javax.print.event.PrintJobEvent;48import javax.print.event.PrintJobListener;49import javax.print.event.PrintJobAttributeListener;5051import javax.print.attribute.Attribute;52import javax.print.attribute.AttributeSet;53import javax.print.attribute.AttributeSetUtilities;54import javax.print.attribute.DocAttributeSet;55import javax.print.attribute.HashPrintJobAttributeSet;56import javax.print.attribute.HashPrintRequestAttributeSet;57import javax.print.attribute.PrintJobAttribute;58import javax.print.attribute.PrintJobAttributeSet;59import javax.print.attribute.PrintRequestAttribute;60import javax.print.attribute.PrintRequestAttributeSet;61import javax.print.attribute.standard.Copies;62import javax.print.attribute.standard.DocumentName;63import javax.print.attribute.standard.Fidelity;64import javax.print.attribute.standard.JobName;65import javax.print.attribute.standard.JobOriginatingUserName;66import javax.print.attribute.standard.Media;67import javax.print.attribute.standard.MediaSize;68import javax.print.attribute.standard.MediaSizeName;69import javax.print.attribute.standard.OrientationRequested;70import javax.print.attribute.standard.RequestingUserName;71import javax.print.attribute.standard.Destination;72import javax.print.attribute.standard.PrinterIsAcceptingJobs;73import javax.print.attribute.standard.PrinterState;74import javax.print.attribute.standard.PrinterStateReason;75import javax.print.attribute.standard.PrinterStateReasons;7677import java.awt.print.*;7879public class Win32PrintJob implements CancelablePrintJob {8081transient private Vector jobListeners;82transient private Vector attrListeners;83transient private Vector listenedAttributeSets;8485private Win32PrintService service;86private boolean fidelity;87private boolean printing = false;88private boolean printReturned = false;89private PrintRequestAttributeSet reqAttrSet = null;90private PrintJobAttributeSet jobAttrSet = null;91private PrinterJob job;92private Doc doc;93private String mDestination = null;9495/* these variables used globally to store reference to the print96* data retrieved as a stream. On completion these are always closed97* if non-null.98*/99private InputStream instream = null;100private Reader reader = null;101102/* default values overridden by those extracted from the attributes */103private String jobName = "Java Printing";104private int copies = 0;105private MediaSizeName mediaName = null;106private MediaSize mediaSize = null;107private OrientationRequested orient = null;108109/* print job handle used by native code */110private long hPrintJob;111112/* buffer length for printing raw data */113private static final int PRINTBUFFERLEN = 8192;114115Win32PrintJob(Win32PrintService service) {116this.service = service;117}118119public PrintService getPrintService() {120return service;121}122123public PrintJobAttributeSet getAttributes() {124synchronized (this) {125if (jobAttrSet == null) {126/* just return an empty set until the job is submitted */127PrintJobAttributeSet jobSet = new HashPrintJobAttributeSet();128return AttributeSetUtilities.unmodifiableView(jobSet);129} else {130return jobAttrSet;131}132}133}134135public void addPrintJobListener(PrintJobListener listener) {136synchronized (this) {137if (listener == null) {138return;139}140if (jobListeners == null) {141jobListeners = new Vector();142}143jobListeners.add(listener);144}145}146147public void removePrintJobListener(PrintJobListener listener) {148synchronized (this) {149if (listener == null || jobListeners == null ) {150return;151}152jobListeners.remove(listener);153if (jobListeners.isEmpty()) {154jobListeners = null;155}156}157}158159160/* Closes any stream already retrieved for the data.161* We want to avoid unnecessarily asking the Doc to create a stream only162* to get a reference in order to close it because the job failed.163* If the representation class is itself a "stream", this164* closes that stream too.165*/166private void closeDataStreams() {167168if (doc == null) {169return;170}171172Object data = null;173174try {175data = doc.getPrintData();176} catch (IOException e) {177return;178}179180if (instream != null) {181try {182instream.close();183} catch (IOException e) {184} finally {185instream = null;186}187}188else if (reader != null) {189try {190reader.close();191} catch (IOException e) {192} finally {193reader = null;194}195}196else if (data instanceof InputStream) {197try {198((InputStream)data).close();199} catch (IOException e) {200}201}202else if (data instanceof Reader) {203try {204((Reader)data).close();205} catch (IOException e) {206}207}208}209210private void notifyEvent(int reason) {211212/* since this method should always get called, here's where213* we will perform the clean up of any data stream supplied.214*/215switch (reason) {216case PrintJobEvent.DATA_TRANSFER_COMPLETE:217case PrintJobEvent.JOB_CANCELED :218case PrintJobEvent.JOB_FAILED :219case PrintJobEvent.NO_MORE_EVENTS :220case PrintJobEvent.JOB_COMPLETE :221closeDataStreams();222}223224synchronized (this) {225if (jobListeners != null) {226PrintJobListener listener;227PrintJobEvent event = new PrintJobEvent(this, reason);228for (int i = 0; i < jobListeners.size(); i++) {229listener = (PrintJobListener)(jobListeners.elementAt(i));230switch (reason) {231232case PrintJobEvent.JOB_COMPLETE :233listener.printJobCompleted(event);234break;235236case PrintJobEvent.JOB_CANCELED :237listener.printJobCanceled(event);238break;239240case PrintJobEvent.JOB_FAILED :241listener.printJobFailed(event);242break;243244case PrintJobEvent.DATA_TRANSFER_COMPLETE :245listener.printDataTransferCompleted(event);246break;247248case PrintJobEvent.NO_MORE_EVENTS :249listener.printJobNoMoreEvents(event);250break;251252default:253break;254}255}256}257}258}259260public void addPrintJobAttributeListener(261PrintJobAttributeListener listener,262PrintJobAttributeSet attributes) {263synchronized (this) {264if (listener == null) {265return;266}267if (attrListeners == null) {268attrListeners = new Vector();269listenedAttributeSets = new Vector();270}271attrListeners.add(listener);272if (attributes == null) {273attributes = new HashPrintJobAttributeSet();274}275listenedAttributeSets.add(attributes);276}277}278279public void removePrintJobAttributeListener(280PrintJobAttributeListener listener) {281synchronized (this) {282if (listener == null || attrListeners == null ) {283return;284}285int index = attrListeners.indexOf(listener);286if (index == -1) {287return;288} else {289attrListeners.remove(index);290listenedAttributeSets.remove(index);291if (attrListeners.isEmpty()) {292attrListeners = null;293listenedAttributeSets = null;294}295}296}297}298299public void print(Doc doc, PrintRequestAttributeSet attributes)300throws PrintException {301302synchronized (this) {303if (printing) {304throw new PrintException("already printing");305} else {306printing = true;307}308}309310PrinterState prnState = (PrinterState)service.getAttribute(311PrinterState.class);312if (prnState == PrinterState.STOPPED) {313PrinterStateReasons prnStateReasons =314(PrinterStateReasons)service.getAttribute(315PrinterStateReasons.class);316if ((prnStateReasons != null) &&317(prnStateReasons.containsKey(PrinterStateReason.SHUTDOWN)))318{319throw new PrintException("PrintService is no longer available.");320}321}322323if ((PrinterIsAcceptingJobs)(service.getAttribute(324PrinterIsAcceptingJobs.class)) ==325PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS) {326throw new PrintException("Printer is not accepting job.");327}328329330this.doc = doc;331/* check if the parameters are valid before doing much processing */332DocFlavor flavor = doc.getDocFlavor();333Object data;334335try {336data = doc.getPrintData();337} catch (IOException e) {338notifyEvent(PrintJobEvent.JOB_FAILED);339throw new PrintException("can't get print data: " + e.toString());340}341342if (data == null) {343throw new PrintException("Null print data.");344}345346if (flavor == null || (!service.isDocFlavorSupported(flavor))) {347notifyEvent(PrintJobEvent.JOB_FAILED);348throw new PrintJobFlavorException("invalid flavor", flavor);349}350351initializeAttributeSets(doc, attributes);352353getAttributeValues(flavor);354355String repClassName = flavor.getRepresentationClassName();356357if (flavor.equals(DocFlavor.INPUT_STREAM.GIF) ||358flavor.equals(DocFlavor.INPUT_STREAM.JPEG) ||359flavor.equals(DocFlavor.INPUT_STREAM.PNG) ||360flavor.equals(DocFlavor.BYTE_ARRAY.GIF) ||361flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) ||362flavor.equals(DocFlavor.BYTE_ARRAY.PNG)) {363try {364instream = doc.getStreamForBytes();365if (instream == null) {366notifyEvent(PrintJobEvent.JOB_FAILED);367throw new PrintException("No stream for data");368}369printableJob(new ImagePrinter(instream));370service.wakeNotifier();371return;372} catch (ClassCastException cce) {373notifyEvent(PrintJobEvent.JOB_FAILED);374throw new PrintException(cce);375} catch (IOException ioe) {376notifyEvent(PrintJobEvent.JOB_FAILED);377throw new PrintException(ioe);378}379} else if (flavor.equals(DocFlavor.URL.GIF) ||380flavor.equals(DocFlavor.URL.JPEG) ||381flavor.equals(DocFlavor.URL.PNG)) {382try {383printableJob(new ImagePrinter((URL)data));384service.wakeNotifier();385return;386} catch (ClassCastException cce) {387notifyEvent(PrintJobEvent.JOB_FAILED);388throw new PrintException(cce);389}390} else if (repClassName.equals("java.awt.print.Pageable")) {391try {392pageableJob((Pageable)doc.getPrintData());393service.wakeNotifier();394return;395} catch (ClassCastException cce) {396notifyEvent(PrintJobEvent.JOB_FAILED);397throw new PrintException(cce);398} catch (IOException ioe) {399notifyEvent(PrintJobEvent.JOB_FAILED);400throw new PrintException(ioe);401}402} else if (repClassName.equals("java.awt.print.Printable")) {403try {404printableJob((Printable)doc.getPrintData());405service.wakeNotifier();406return;407} catch (ClassCastException cce) {408notifyEvent(PrintJobEvent.JOB_FAILED);409throw new PrintException(cce);410} catch (IOException ioe) {411notifyEvent(PrintJobEvent.JOB_FAILED);412throw new PrintException(ioe);413}414} else if (repClassName.equals("[B") ||415repClassName.equals("java.io.InputStream") ||416repClassName.equals("java.net.URL")) {417418if (repClassName.equals("java.net.URL")) {419URL url = (URL)data;420try {421instream = url.openStream();422} catch (IOException e) {423notifyEvent(PrintJobEvent.JOB_FAILED);424throw new PrintException(e.toString());425}426} else {427try {428instream = doc.getStreamForBytes();429} catch (IOException ioe) {430notifyEvent(PrintJobEvent.JOB_FAILED);431throw new PrintException(ioe.toString());432}433}434435if (instream == null) {436notifyEvent(PrintJobEvent.JOB_FAILED);437throw new PrintException("No stream for data");438}439440if (mDestination != null) { // if destination attribute is set441try {442FileOutputStream fos = new FileOutputStream(mDestination);443byte []buffer = new byte[1024];444int cread;445446while ((cread = instream.read(buffer, 0, buffer.length)) >=0) {447fos.write(buffer, 0, cread);448}449fos.flush();450fos.close();451} catch (FileNotFoundException fnfe) {452notifyEvent(PrintJobEvent.JOB_FAILED);453throw new PrintException(fnfe.toString());454} catch (IOException ioe) {455notifyEvent(PrintJobEvent.JOB_FAILED);456throw new PrintException(ioe.toString());457}458notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);459notifyEvent(PrintJobEvent.JOB_COMPLETE);460service.wakeNotifier();461return;462}463464if (!startPrintRawData(service.getName(), jobName)) {465notifyEvent(PrintJobEvent.JOB_FAILED);466throw new PrintException("Print job failed to start.");467}468BufferedInputStream bin = new BufferedInputStream(instream);469int bread = 0;470try {471byte[] buffer = new byte[PRINTBUFFERLEN];472473while ((bread = bin.read(buffer, 0, PRINTBUFFERLEN)) >=0) {474if (!printRawData(buffer, bread)) {475bin.close();476notifyEvent(PrintJobEvent.JOB_FAILED);477throw new PrintException ("Problem while spooling data");478}479}480bin.close();481if (!endPrintRawData()) {482notifyEvent(PrintJobEvent.JOB_FAILED);483throw new PrintException("Print job failed to close properly.");484}485notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);486} catch (IOException e) {487notifyEvent(PrintJobEvent.JOB_FAILED);488throw new PrintException (e.toString());489} finally {490notifyEvent(PrintJobEvent.NO_MORE_EVENTS);491}492} else {493notifyEvent(PrintJobEvent.JOB_FAILED);494throw new PrintException("unrecognized class: "+repClassName);495}496service.wakeNotifier();497}498499public void printableJob(Printable printable) throws PrintException {500try {501synchronized(this) {502if (job != null) { // shouldn't happen503throw new PrintException("already printing");504} else {505job = new sun.awt.windows.WPrinterJob();506}507}508PrintService svc = getPrintService();509job.setPrintService(svc);510if (copies == 0) {511Copies c = (Copies)svc.getDefaultAttributeValue(Copies.class);512copies = c.getValue();513}514515if (mediaName == null) {516Object media = svc.getDefaultAttributeValue(Media.class);517if (media instanceof MediaSizeName) {518mediaName = (MediaSizeName) media;519mediaSize = MediaSize.getMediaSizeForName(mediaName);520}521}522523if (orient == null) {524orient =525(OrientationRequested)svc.getDefaultAttributeValue(OrientationRequested.class);526}527528job.setCopies(copies);529job.setJobName(jobName);530PageFormat pf = new PageFormat();531if (mediaSize != null) {532Paper p = new Paper();533p.setSize(mediaSize.getX(MediaSize.INCH)*72.0,534mediaSize.getY(MediaSize.INCH)*72.0);535p.setImageableArea(72.0, 72.0, p.getWidth()-144.0,536p.getHeight()-144.0);537pf.setPaper(p);538}539if (orient == OrientationRequested.REVERSE_LANDSCAPE) {540pf.setOrientation(PageFormat.REVERSE_LANDSCAPE);541} else if (orient == OrientationRequested.LANDSCAPE) {542pf.setOrientation(PageFormat.LANDSCAPE);543}544job.setPrintable(printable, pf);545job.print(reqAttrSet);546notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);547return;548} catch (PrinterException pe) {549notifyEvent(PrintJobEvent.JOB_FAILED);550throw new PrintException(pe);551} finally {552printReturned = true;553notifyEvent(PrintJobEvent.NO_MORE_EVENTS);554}555}556557public void pageableJob(Pageable pageable) throws PrintException {558try {559synchronized(this) {560if (job != null) { // shouldn't happen561throw new PrintException("already printing");562} else {563job = new sun.awt.windows.WPrinterJob();564}565}566PrintService svc = getPrintService();567job.setPrintService(svc);568if (copies == 0) {569Copies c = (Copies)svc.getDefaultAttributeValue(Copies.class);570copies = c.getValue();571}572job.setCopies(copies);573job.setJobName(jobName);574job.setPageable(pageable);575job.print(reqAttrSet);576notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);577return;578} catch (PrinterException pe) {579notifyEvent(PrintJobEvent.JOB_FAILED);580throw new PrintException(pe);581} finally {582printReturned = true;583notifyEvent(PrintJobEvent.NO_MORE_EVENTS);584}585}586587/* There's some inefficiency here as the job set is created even though588* it may never be requested.589*/590private synchronized void591initializeAttributeSets(Doc doc, PrintRequestAttributeSet reqSet) {592593reqAttrSet = new HashPrintRequestAttributeSet();594jobAttrSet = new HashPrintJobAttributeSet();595596Attribute[] attrs;597if (reqSet != null) {598reqAttrSet.addAll(reqSet);599attrs = reqSet.toArray();600for (int i=0; i<attrs.length; i++) {601if (attrs[i] instanceof PrintJobAttribute) {602jobAttrSet.add(attrs[i]);603}604}605}606607DocAttributeSet docSet = doc.getAttributes();608if (docSet != null) {609attrs = docSet.toArray();610for (int i=0; i<attrs.length; i++) {611if (attrs[i] instanceof PrintRequestAttribute) {612reqAttrSet.add(attrs[i]);613}614if (attrs[i] instanceof PrintJobAttribute) {615jobAttrSet.add(attrs[i]);616}617}618}619620/* add the user name to the job */621String userName = "";622try {623userName = System.getProperty("user.name");624} catch (SecurityException se) {625}626627if (userName == null || userName.equals("")) {628RequestingUserName ruName =629(RequestingUserName)reqSet.get(RequestingUserName.class);630if (ruName != null) {631jobAttrSet.add(632new JobOriginatingUserName(ruName.getValue(),633ruName.getLocale()));634} else {635jobAttrSet.add(new JobOriginatingUserName("", null));636}637} else {638jobAttrSet.add(new JobOriginatingUserName(userName, null));639}640641/* if no job name supplied use doc name (if supplied), if none and642* its a URL use that, else finally anything .. */643if (jobAttrSet.get(JobName.class) == null) {644JobName jobName;645if (docSet != null && docSet.get(DocumentName.class) != null) {646DocumentName docName =647(DocumentName)docSet.get(DocumentName.class);648jobName = new JobName(docName.getValue(), docName.getLocale());649jobAttrSet.add(jobName);650} else {651String str = "JPS Job:" + doc;652try {653Object printData = doc.getPrintData();654if (printData instanceof URL) {655str = ((URL)(doc.getPrintData())).toString();656}657} catch (IOException e) {658}659jobName = new JobName(str, null);660jobAttrSet.add(jobName);661}662}663664jobAttrSet = AttributeSetUtilities.unmodifiableView(jobAttrSet);665}666667private void getAttributeValues(DocFlavor flavor) throws PrintException {668669if (reqAttrSet.get(Fidelity.class) == Fidelity.FIDELITY_TRUE) {670fidelity = true;671} else {672fidelity = false;673}674675Class category;676Attribute [] attrs = reqAttrSet.toArray();677for (int i=0; i<attrs.length; i++) {678Attribute attr = attrs[i];679category = attr.getCategory();680if (fidelity == true) {681if (!service.isAttributeCategorySupported(category)) {682notifyEvent(PrintJobEvent.JOB_FAILED);683throw new PrintJobAttributeException(684"unsupported category: " + category, category, null);685} else if686(!service.isAttributeValueSupported(attr, flavor, null)) {687notifyEvent(PrintJobEvent.JOB_FAILED);688throw new PrintJobAttributeException(689"unsupported attribute: " + attr, null, attr);690}691}692if (category == Destination.class) {693URI uri = ((Destination)attr).getURI();694if (!"file".equals(uri.getScheme())) {695notifyEvent(PrintJobEvent.JOB_FAILED);696throw new PrintException("Not a file: URI");697} else {698try {699mDestination = (new File(uri)).getPath();700} catch (Exception e) {701throw new PrintException(e);702}703// check write access704SecurityManager security = System.getSecurityManager();705if (security != null) {706try {707security.checkWrite(mDestination);708} catch (SecurityException se) {709notifyEvent(PrintJobEvent.JOB_FAILED);710throw new PrintException(se);711}712}713}714} else if (category == JobName.class) {715jobName = ((JobName)attr).getValue();716} else if (category == Copies.class) {717copies = ((Copies)attr).getValue();718} else if (category == Media.class) {719if (attr instanceof MediaSizeName) {720mediaName = (MediaSizeName)attr;721// If requested MediaSizeName is not supported,722// get the corresponding media size - this will723// be used to create a new PageFormat.724if (!service.isAttributeValueSupported(attr, null, null)) {725mediaSize = MediaSize.getMediaSizeForName(mediaName);726}727}728} else if (category == OrientationRequested.class) {729orient = (OrientationRequested)attr;730}731}732}733734private native boolean startPrintRawData(String printerName,735String jobName);736private native boolean printRawData(byte[] data, int count);737private native boolean endPrintRawData();738739/* Cancel PrinterJob jobs that haven't yet completed. */740public void cancel() throws PrintException {741synchronized (this) {742if (!printing) {743throw new PrintException("Job is not yet submitted.");744} else if (job != null && !printReturned) {745job.cancel();746notifyEvent(PrintJobEvent.JOB_CANCELED);747return;748} else {749throw new PrintException("Job could not be cancelled.");750}751}752}753}754755756