View Javadoc
1   /*
2    * Copyright (c) 2000, 2007, 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 Provider">
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       * <p>
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      * <p>
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 }