1 /* 2 * Copyright (c) 2000, 2013, 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.OutputStream; 29 30 import java.util.ArrayList; 31 import java.util.Iterator; 32 33 import javax.print.DocFlavor; 34 35 import sun.awt.AppContext; 36 import java.util.ServiceLoader; 37 import java.util.ServiceConfigurationError; 38 39 /** 40 * A <code>StreamPrintServiceFactory</code> is the factory for 41 * {@link StreamPrintService} instances, 42 * which can print to an output stream in a particular 43 * document format described as a mime type. 44 * A typical output document format may be Postscript(TM). 45 * <p> 46 * This class is implemented by a service and located by the 47 * implementation using the 48 * <a href="../../../technotes/guides/jar/jar.html#Service%20Provider"> 49 * SPI JAR File specification</a>. 50 * <p> 51 * Applications locate instances of this class by calling the 52 * {@link #lookupStreamPrintServiceFactories(DocFlavor, String)} method. 53 * <p> 54 * Applications can use a <code>StreamPrintService</code> obtained from a 55 * factory in place of a <code>PrintService</code> which represents a 56 * physical printer device. 57 */ 58 59 public abstract class StreamPrintServiceFactory { 60 61 static class Services { 62 private ArrayList listOfFactories = null; 63 } 64 65 private static Services getServices() { 66 Services services = 67 (Services)AppContext.getAppContext().get(Services.class); 68 if (services == null) { 69 services = new Services(); 70 AppContext.getAppContext().put(Services.class, services); 71 } 72 return services; 73 } 74 75 private static ArrayList getListOfFactories() { 76 return getServices().listOfFactories; 77 } 78 79 private static ArrayList initListOfFactories() { 80 ArrayList listOfFactories = new ArrayList(); 81 getServices().listOfFactories = listOfFactories; 82 return listOfFactories; 83 } 84 85 /** 86 * Locates factories for print services that can be used with 87 * a print job to output a stream of data in the 88 * format specified by {@code outputMimeType}. 89 * <p> 90 * The {@code outputMimeType} parameter describes the document type that 91 * you want to create, whereas the {@code flavor} parameter describes the 92 * format in which the input data will be provided by the application 93 * to the {@code StreamPrintService}. 94 * <p> 95 * Although null is an acceptable value to use in the lookup of stream 96 * printing services, it's typical to search for a particular 97 * desired format, such as Postscript(TM). 98 * 99 * @param flavor of the input document type - null means match all 100 * types. 101 * @param outputMimeType representing the required output format, used to 102 * identify suitable stream printer factories. A value of null means 103 * match all formats. 104 * @return - matching factories for stream print service instance, 105 * empty if no suitable factories could be located. 106 */ 107 public static StreamPrintServiceFactory[] 108 lookupStreamPrintServiceFactories(DocFlavor flavor, 109 String outputMimeType) { 110 111 ArrayList list = getFactories(flavor, outputMimeType); 112 return (StreamPrintServiceFactory[]) 113 (list.toArray(new StreamPrintServiceFactory[list.size()])); 114 } 115 116 /** Queries the factory for the document format that is emitted 117 * by printers obtained from this factory. 118 * 119 * @return the output format described as a mime type. 120 */ 121 public abstract String getOutputFormat(); 122 123 /** 124 * Queries the factory for the document flavors that can be accepted 125 * by printers obtained from this factory. 126 * @return array of supported doc flavors. 127 */ 128 public abstract DocFlavor[] getSupportedDocFlavors(); 129 130 /** 131 * Returns a <code>StreamPrintService</code> that can print to 132 * the specified output stream. 133 * The output stream is created and managed by the application. 134 * It is the application's responsibility to close the stream and 135 * to ensure that this Printer is not reused. 136 * The application should not close this stream until any print job 137 * created from the printer is complete. Doing so earlier may generate 138 * a <code>PrinterException</code> and an event indicating that the 139 * job failed. 140 * <p> 141 * Whereas a <code>PrintService</code> connected to a physical printer 142 * can be reused, 143 * a <code>StreamPrintService</code> connected to a stream cannot. 144 * The underlying <code>StreamPrintService</code> may be disposed by 145 * the print system with 146 * the {@link StreamPrintService#dispose() dispose} method 147 * before returning from the 148 * {@link DocPrintJob#print(Doc, javax.print.attribute.PrintRequestAttributeSet) print} 149 * method of <code>DocPrintJob</code> so that the print system knows 150 * this printer is no longer usable. 151 * This is equivalent to a physical printer going offline - permanently. 152 * Applications may supply a null print stream to create a queryable 153 * service. It is not valid to create a PrintJob for such a stream. 154 * Implementations which allocate resources on construction should examine 155 * the stream and may wish to only allocate resources if the stream is 156 * non-null. 157 * 158 * @param out destination stream for generated output. 159 * @return a PrintService which will generate the format specified by the 160 * DocFlavor supported by this Factory. 161 */ 162 public abstract StreamPrintService getPrintService(OutputStream out); 163 164 165 private static ArrayList getAllFactories() { 166 synchronized (StreamPrintServiceFactory.class) { 167 168 ArrayList listOfFactories = getListOfFactories(); 169 if (listOfFactories != null) { 170 return listOfFactories; 171 } else { 172 listOfFactories = initListOfFactories(); 173 } 174 175 try { 176 java.security.AccessController.doPrivileged( 177 new java.security.PrivilegedExceptionAction() { 178 public Object run() { 179 Iterator<StreamPrintServiceFactory> iterator = 180 ServiceLoader.load 181 (StreamPrintServiceFactory.class).iterator(); 182 ArrayList lof = getListOfFactories(); 183 while (iterator.hasNext()) { 184 try { 185 lof.add(iterator.next()); 186 } catch (ServiceConfigurationError err) { 187 /* In the applet case, we continue */ 188 if (System.getSecurityManager() != null) { 189 err.printStackTrace(); 190 } else { 191 throw err; 192 } 193 } 194 } 195 return null; 196 } 197 }); 198 } catch (java.security.PrivilegedActionException e) { 199 } 200 return listOfFactories; 201 } 202 } 203 204 private static boolean isMember(DocFlavor flavor, DocFlavor[] flavors) { 205 for (int f=0; f<flavors.length; f++ ) { 206 if (flavor.equals(flavors[f])) { 207 return true; 208 } 209 } 210 return false; 211 } 212 213 private static ArrayList getFactories(DocFlavor flavor, String outType) { 214 215 if (flavor == null && outType == null) { 216 return getAllFactories(); 217 } 218 219 ArrayList list = new ArrayList(); 220 Iterator iterator = getAllFactories().iterator(); 221 while (iterator.hasNext()) { 222 StreamPrintServiceFactory factory = 223 (StreamPrintServiceFactory)iterator.next(); 224 if ((outType == null || 225 outType.equalsIgnoreCase(factory.getOutputFormat())) && 226 (flavor == null || 227 isMember(flavor, factory.getSupportedDocFlavors()))) { 228 list.add(factory); 229 } 230 } 231 232 return list; 233 } 234 235 }