1 /* 2 * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.print; 27 28 import java.io.ByteArrayInputStream; 29 import java.io.CharArrayReader; 30 import java.io.IOException; 31 import java.io.InputStream; 32 import java.io.Reader; 33 import java.io.StringReader; 34 35 import javax.print.attribute.AttributeSetUtilities; 36 import javax.print.attribute.DocAttributeSet; 37 38 /** 39 * This class is an implementation of interface {@code Doc} that can be used in 40 * many common printing requests. It can handle all of the presently defined 41 * "pre-defined" doc flavors defined as static variables in the 42 * {@code DocFlavor} class. 43 * <p> 44 * In particular this class implements certain required semantics of the 45 * {@code Doc} specification as follows: 46 * <ul> 47 * <li>constructs a stream for the service if requested and appropriate. 48 * <li>ensures the same object is returned for each call on a method. 49 * <li>ensures multiple threads can access the {@code Doc} 50 * <li>performs some validation of that the data matches the doc flavor. 51 * </ul> 52 * Clients who want to re-use the doc object in other jobs, or need a 53 * {@code MultiDoc} will not want to use this class. 54 * <p> 55 * If the print data is a stream, or a print job requests data as a stream, then 56 * {@code SimpleDoc} does not monitor if the service properly closes the stream 57 * after data transfer completion or job termination. Clients may prefer to use 58 * provide their own implementation of doc that adds a listener to monitor job 59 * completion and to validate that resources such as streams are freed (ie 60 * closed). 61 */ 62 public final class SimpleDoc implements Doc { 63 64 /** 65 * The doc flavor in which this doc will supply its piece of print data. 66 */ 67 private DocFlavor flavor; 68 69 /** 70 * The set of printing attributes for this doc. 71 */ 72 private DocAttributeSet attributes; 73 74 /** 75 * The print data. 76 */ 77 private Object printData; 78 79 /** 80 * The reader for extracting character print data from this doc. 81 */ 82 private Reader reader; 83 84 /** 85 * The input stream for extracting byte print data from this doc. 86 */ 87 private InputStream inStream; 88 89 /** 90 * Constructs a {@code SimpleDoc} with the specified print data, doc flavor 91 * and doc attribute set. 92 * 93 * @param printData the print data object 94 * @param flavor the {@code DocFlavor} object 95 * @param attributes a {@code DocAttributeSet}, which can be {@code null} 96 * @throws IllegalArgumentException if {@code flavor} or {@code printData} 97 * is {@code null}, or the {@code printData} does not correspond to 98 * the specified doc flavor--for example, the data is not of the 99 * type specified as the representation in the {@code DocFlavor} 100 */ 101 public SimpleDoc(Object printData, 102 DocFlavor flavor, DocAttributeSet attributes) { 103 104 if (flavor == null || printData == null) { 105 throw new IllegalArgumentException("null argument(s)"); 106 } 107 108 Class<?> repClass = null; 109 try { 110 String className = flavor.getRepresentationClassName(); 111 sun.reflect.misc.ReflectUtil.checkPackageAccess(className); 112 repClass = Class.forName(className, false, 113 Thread.currentThread().getContextClassLoader()); 114 } catch (Throwable e) { 115 throw new IllegalArgumentException("unknown representation class"); 116 } 117 118 if (!repClass.isInstance(printData)) { 119 throw new IllegalArgumentException("data is not of declared type"); 120 } 121 122 this.flavor = flavor; 123 if (attributes != null) { 124 this.attributes = AttributeSetUtilities.unmodifiableView(attributes); 125 } 126 this.printData = printData; 127 } 128 129 /** 130 * Determines the doc flavor in which this doc object will supply its piece 131 * of print data. 132 * 133 * @return doc flavor 134 */ 135 public DocFlavor getDocFlavor() { 136 return flavor; 137 } 138 139 /** 140 * Obtains the set of printing attributes for this doc object. If the 141 * returned attribute set includes an instance of a particular attribute 142 * <i>X,</i> the printer must use that attribute value for this doc, 143 * overriding any value of attribute <i>X</i> in the job's attribute set. If 144 * the returned attribute set does not include an instance of a particular 145 * attribute <i>X</i> or if {@code null} is returned, the printer must 146 * consult the job's attribute set to obtain the value for attribute 147 * <i>X,</i> and if not found there, the printer must use an 148 * implementation-dependent default value. The returned attribute set is 149 * unmodifiable. 150 * 151 * @return unmodifiable set of printing attributes for this doc, or 152 * {@code null} to obtain all attribute values from the job's 153 * attribute set 154 */ 155 public DocAttributeSet getAttributes() { 156 return attributes; 157 } 158 159 /** 160 * Obtains the print data representation object that contains this doc 161 * object's piece of print data in the format corresponding to the supported 162 * doc flavor. The {@code getPrintData()} method returns an instance of the 163 * representation class whose name is given by {@link #getDocFlavor() 164 * getDocFlavor()}.{@link DocFlavor#getRepresentationClassName() 165 * getRepresentationClassName()}, and the return value can be cast from 166 * class {@code Object} to that representation class. 167 * 168 * @return print data representation object 169 * @throws IOException if the representation class is a stream and there was 170 * an I/O error while constructing the stream 171 */ 172 public Object getPrintData() throws IOException { 173 return printData; 174 } 175 176 /** 177 * Obtains a reader for extracting character print data from this doc. The 178 * {@code Doc} implementation is required to support this method if the 179 * {@code DocFlavor} has one of the following print data representation 180 * classes, and return {@code null} otherwise: 181 * <ul> 182 * <li>{@code char[]} 183 * <li>{@code java.lang.String} 184 * <li>{@code java.io.Reader} 185 * </ul> 186 * The doc's print data representation object is used to construct and 187 * return a {@code Reader} for reading the print data as a stream of 188 * characters from the print data representation object. However, if the 189 * print data representation object is itself a {@code Reader} then the 190 * print data representation object is simply returned. 191 * 192 * @return a {@code Reader} for reading the print data characters from this 193 * doc. If a reader cannot be provided because this doc does not 194 * meet the criteria stated above, {@code null} is returned. 195 * @throws IOException if there was an I/O error while creating the reader 196 */ 197 public Reader getReaderForText() throws IOException { 198 199 if (printData instanceof Reader) { 200 return (Reader)printData; 201 } 202 203 synchronized (this) { 204 if (reader != null) { 205 return reader; 206 } 207 208 if (printData instanceof char[]) { 209 reader = new CharArrayReader((char[])printData); 210 } 211 else if (printData instanceof String) { 212 reader = new StringReader((String)printData); 213 } 214 } 215 return reader; 216 } 217 218 /** 219 * Obtains an input stream for extracting byte print data from this doc. The 220 * {@code Doc} implementation is required to support this method if the 221 * {@code DocFlavor} has one of the following print data representation 222 * classes; otherwise this method returns {@code null}: 223 * <ul> 224 * <li>{@code byte[]} 225 * <li>{@code java.io.InputStream} 226 * </ul> 227 * The doc's print data representation object is obtained. Then, an input 228 * stream for reading the print data from the print data representation 229 * object as a stream of bytes is created and returned. However, if the 230 * print data representation object is itself an input stream then the print 231 * data representation object is simply returned. 232 * 233 * @return an {@code InputStream} for reading the print data bytes from this 234 * doc. If an input stream cannot be provided because this doc does 235 * not meet the criteria stated above, {@code null} is returned. 236 * @throws IOException if there was an I/O error while creating the input 237 * stream 238 */ 239 public InputStream getStreamForBytes() throws IOException { 240 241 if (printData instanceof InputStream) { 242 return (InputStream)printData; 243 } 244 245 synchronized (this) { 246 if (inStream != null) { 247 return inStream; 248 } 249 250 if (printData instanceof byte[]) { 251 inStream = new ByteArrayInputStream((byte[])printData); 252 } 253 } 254 return inStream; 255 } 256 }