1 /* 2 * Copyright (c) 2001, 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</code> 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</code> 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</code> 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</code> object 76 * @param attributes a <code>DocAttributeSet</code>, which can 77 * be <code>null</code> 78 * @throws IllegalArgumentException if <code>flavor</code> or 79 * <code>printData</code> is <code>null</code>, or the 80 * <code>printData</code> 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</code>. 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 repClass = Class.forName(flavor.getRepresentationClassName()); 95 } catch (Throwable e) { 96 throw new IllegalArgumentException("unknown representation class"); 97 } 98 99 if (!repClass.isInstance(printData)) { 100 throw new IllegalArgumentException("data is not of declared type"); 101 } 102 103 this.flavor = flavor; 104 if (attributes != null) { 105 this.attributes = AttributeSetUtilities.unmodifiableView(attributes); 106 } 107 this.printData = printData; 108 } 109 110 /** 111 * Determines the doc flavor in which this doc object will supply its 112 * piece of print data. 113 * 114 * @return Doc flavor. 115 */ 116 public DocFlavor getDocFlavor() { 117 return flavor; 118 } 119 120 /** 121 * Obtains the set of printing attributes for this doc object. If the 122 * returned attribute set includes an instance of a particular attribute 123 * <I>X,</I> the printer must use that attribute value for this doc, 124 * overriding any value of attribute <I>X</I> in the job's attribute set. 125 * If the returned attribute set does not include an instance 126 * of a particular attribute <I>X</I> or if null is returned, the printer 127 * must consult the job's attribute set to obtain the value for 128 * attribute <I>X,</I> and if not found there, the printer must use an 129 * implementation-dependent default value. The returned attribute set is 130 * unmodifiable. 131 * 132 * @return Unmodifiable set of printing attributes for this doc, or null 133 * to obtain all attribute values from the job's attribute 134 * set. 135 */ 136 public DocAttributeSet getAttributes() { 137 return attributes; 138 } 139 140 /* 141 * Obtains the print data representation object that contains this doc 142 * object's piece of print data in the format corresponding to the 143 * supported doc flavor. 144 * The <CODE>getPrintData()</CODE> method returns an instance of 145 * the representation class whose name is given by 146 * {@link DocFlavor#getRepresentationClassName() getRepresentationClassName}, 147 * and the return value can be cast 148 * from class Object to that representation class. 149 * 150 * @return Print data representation object. 151 * 152 * @exception IOException if the representation class is a stream and 153 * there was an I/O error while constructing the stream. 154 */ 155 public Object getPrintData() throws IOException { 156 return printData; 157 } 158 159 /** 160 * Obtains a reader for extracting character print data from this doc. 161 * The <code>Doc</code> implementation is required to support this 162 * method if the <code>DocFlavor</code> has one of the following print 163 * data representation classes, and return <code>null</code> 164 * otherwise: 165 * <UL> 166 * <LI> <code>char[]</code> 167 * <LI> <code>java.lang.String</code> 168 * <LI> <code>java.io.Reader</code> 169 * </UL> 170 * The doc's print data representation object is used to construct and 171 * return a <code>Reader</code> for reading the print data as a stream 172 * of characters from the print data representation object. 173 * However, if the print data representation object is itself a 174 * <code>Reader</code> then the print data representation object is 175 * simply returned. 176 * <P> 177 * @return a <code>Reader</code> for reading the print data 178 * characters from this doc. 179 * If a reader cannot be provided because this doc does not meet 180 * the criteria stated above, <code>null</code> is returned. 181 * 182 * @exception IOException if there was an I/O error while creating 183 * the reader. 184 */ 185 public Reader getReaderForText() throws IOException { 186 187 if (printData instanceof Reader) { 188 return (Reader)printData; 189 } 190 191 synchronized (this) { 192 if (reader != null) { 193 return reader; 194 } 195 196 if (printData instanceof char[]) { 197 reader = new CharArrayReader((char[])printData); 198 } 199 else if (printData instanceof String) { 200 reader = new StringReader((String)printData); 201 } 202 } 203 return reader; 204 } 205 206 /** 207 * Obtains an input stream for extracting byte print data from 208 * this doc. 209 * The <code>Doc</code> implementation is required to support this 210 * method if the <code>DocFlavor</code> has one of the following print 211 * data representation classes; otherwise this method 212 * returns <code>null</code>: 213 * <UL> 214 * <LI> <code>byte[]</code> 215 * <LI> <code>java.io.InputStream</code> 216 * </UL> 217 * The doc's print data representation object is obtained. Then, an 218 * input stream for reading the print data 219 * from the print data representation object as a stream of bytes is 220 * created and returned. 221 * However, if the print data representation object is itself an 222 * input stream then the print data representation object is simply 223 * returned. 224 * <P> 225 * @return an <code>InputStream</code> for reading the print data 226 * bytes from this doc. If an input stream cannot be 227 * provided because this doc does not meet 228 * the criteria stated above, <code>null</code> is returned. 229 * 230 * @exception IOException 231 * if there was an I/O error while creating the input stream. 232 */ 233 public InputStream getStreamForBytes() throws IOException { 234 235 if (printData instanceof InputStream) { 236 return (InputStream)printData; 237 } 238 239 synchronized (this) { 240 if (inStream != null) { 241 return inStream; 242 } 243 244 if (printData instanceof byte[]) { 245 inStream = new ByteArrayInputStream((byte[])printData); 246 } 247 } 248 return inStream; 249 } 250 251 }