1 /* 2 * Copyright (c) 2001, 2014, 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.StringReader; 31 import java.io.InputStream; 32 import java.io.IOException; 33 import java.io.Reader; 34 import javax.print.attribute.AttributeSetUtilities; 35 import javax.print.attribute.DocAttributeSet; 36 37 /** 38 * This class is an implementation of interface {@code Doc} that can 39 * be used in many common printing requests. 40 * It can handle all of the presently defined "pre-defined" doc flavors 41 * defined as static variables in the DocFlavor class. 42 * <p> 43 * In particular this class implements certain required semantics of the 44 * Doc specification as follows: 45 * <ul> 46 * <li>constructs a stream for the service if requested and appropriate. 47 * <li>ensures the same object is returned for each call on a method. 48 * <li>ensures multiple threads can access the Doc 49 * <li>performs some validation of that the data matches the doc flavor. 50 * </ul> 51 * Clients who want to re-use the doc object in other jobs, 52 * or need a MultiDoc will not want to use this class. 53 * <p> 54 * If the print data is a stream, or a print job requests data as a 55 * stream, then {@code SimpleDoc} does not monitor if the service 56 * properly closes the stream after data transfer completion or job 57 * termination. 58 * Clients may prefer to use provide their own implementation of doc that 59 * adds a listener to monitor job completion and to validate that 60 * resources such as streams are freed (ie closed). 61 */ 62 63 public final class SimpleDoc implements Doc { 64 65 private DocFlavor flavor; 66 private DocAttributeSet attributes; 67 private Object printData; 68 private Reader reader; 69 private InputStream inStream; 70 71 /** 72 * Constructs a {@code SimpleDoc} with the specified 73 * print data, doc flavor and doc attribute set. 74 * @param printData the print data object 75 * @param flavor the {@code DocFlavor} object 76 * @param attributes a {@code DocAttributeSet}, which can 77 * be {@code null} 78 * @throws IllegalArgumentException if {@code flavor} or 79 * {@code printData} is {@code null}, or the 80 * {@code printData} does not correspond 81 * to the specified doc flavor--for example, the data is 82 * not of the type specified as the representation in the 83 * {@code DocFlavor}. 84 */ 85 public SimpleDoc(Object printData, 86 DocFlavor flavor, DocAttributeSet attributes) { 87 88 if (flavor == null || printData == null) { 89 throw new IllegalArgumentException("null argument(s)"); 90 } 91 92 Class<?> repClass = null; 93 try { 94 String className = flavor.getRepresentationClassName(); 95 sun.reflect.misc.ReflectUtil.checkPackageAccess(className); 96 repClass = Class.forName(className, false, 97 Thread.currentThread().getContextClassLoader()); 98 } catch (Throwable e) { 99 throw new IllegalArgumentException("unknown representation class"); 100 } 101 102 if (!repClass.isInstance(printData)) { 103 throw new IllegalArgumentException("data is not of declared type"); 104 } 105 106 this.flavor = flavor; 107 if (attributes != null) { 108 this.attributes = AttributeSetUtilities.unmodifiableView(attributes); 109 } 110 this.printData = printData; 111 } 112 113 /** 114 * Determines the doc flavor in which this doc object will supply its 115 * piece of print data. 116 * 117 * @return Doc flavor. 118 */ 119 public DocFlavor getDocFlavor() { 120 return flavor; 121 } 122 123 /** 124 * Obtains the set of printing attributes for this doc object. If the 125 * returned attribute set includes an instance of a particular attribute 126 * <I>X,</I> the printer must use that attribute value for this doc, 127 * overriding any value of attribute <I>X</I> in the job's attribute set. 128 * If the returned attribute set does not include an instance 129 * of a particular attribute <I>X</I> or if null is returned, the printer 130 * must consult the job's attribute set to obtain the value for 131 * attribute <I>X,</I> and if not found there, the printer must use an 132 * implementation-dependent default value. The returned attribute set is 133 * unmodifiable. 134 * 135 * @return Unmodifiable set of printing attributes for this doc, or null 136 * to obtain all attribute values from the job's attribute 137 * set. 138 */ 139 public DocAttributeSet getAttributes() { 140 return attributes; 141 } 142 143 /* 144 * Obtains the print data representation object that contains this doc 145 * object's piece of print data in the format corresponding to the 146 * supported doc flavor. 147 * The {@code getPrintData()} method returns an instance of 148 * the representation class whose name is given by 149 * {@link DocFlavor#getRepresentationClassName() getRepresentationClassName}, 150 * and the return value can be cast 151 * from class Object to that representation class. 152 * 153 * @return Print data representation object. 154 * 155 * @exception IOException if the representation class is a stream and 156 * there was an I/O error while constructing the stream. 157 */ 158 public Object getPrintData() throws IOException { 159 return printData; 160 } 161 162 /** 163 * Obtains a reader for extracting character print data from this doc. 164 * The {@code Doc} implementation is required to support this 165 * method if the {@code DocFlavor} has one of the following print 166 * data representation classes, and return {@code null} 167 * otherwise: 168 * <UL> 169 * <LI> {@code char[]} 170 * <LI> {@code java.lang.String} 171 * <LI> {@code java.io.Reader} 172 * </UL> 173 * The doc's print data representation object is used to construct and 174 * return a {@code Reader} for reading the print data as a stream 175 * of characters from the print data representation object. 176 * However, if the print data representation object is itself a 177 * {@code Reader} then the print data representation object is 178 * simply returned. 179 * 180 * @return a {@code Reader} for reading the print data 181 * characters from this doc. 182 * If a reader cannot be provided because this doc does not meet 183 * the criteria stated above, {@code null} is returned. 184 * 185 * @exception IOException if there was an I/O error while creating 186 * the reader. 187 */ 188 public Reader getReaderForText() throws IOException { 189 190 if (printData instanceof Reader) { 191 return (Reader)printData; 192 } 193 194 synchronized (this) { 195 if (reader != null) { 196 return reader; 197 } 198 199 if (printData instanceof char[]) { 200 reader = new CharArrayReader((char[])printData); 201 } 202 else if (printData instanceof String) { 203 reader = new StringReader((String)printData); 204 } 205 } 206 return reader; 207 } 208 209 /** 210 * Obtains an input stream for extracting byte print data from 211 * this doc. 212 * The {@code Doc} implementation is required to support this 213 * method if the {@code DocFlavor} has one of the following print 214 * data representation classes; otherwise this method 215 * returns {@code null}: 216 * <UL> 217 * <LI> {@code byte[]} 218 * <LI> {@code java.io.InputStream} 219 * </UL> 220 * The doc's print data representation object is obtained. Then, an 221 * input stream for reading the print data 222 * from the print data representation object as a stream of bytes is 223 * created and returned. 224 * However, if the print data representation object is itself an 225 * input stream then the print data representation object is simply 226 * returned. 227 * 228 * @return an {@code InputStream} for reading the print data 229 * bytes from this doc. If an input stream cannot be 230 * provided because this doc does not meet 231 * the criteria stated above, {@code null} is returned. 232 * 233 * @exception IOException 234 * if there was an I/O error while creating the input stream. 235 */ 236 public InputStream getStreamForBytes() throws IOException { 237 238 if (printData instanceof InputStream) { 239 return (InputStream)printData; 240 } 241 242 synchronized (this) { 243 if (inStream != null) { 244 return inStream; 245 } 246 247 if (printData instanceof byte[]) { 248 inStream = new ByteArrayInputStream((byte[])printData); 249 } 250 } 251 return inStream; 252 } 253 254 }