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