001 /*
002 * Copyright 2000-2002 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package javax.print;
027
028 import java.util.ArrayList;
029 import java.util.Iterator;
030 import java.util.List;
031 import javax.print.attribute.AttributeSet;
032
033 import sun.awt.AppContext;
034 import sun.misc.Service;
035
036 /** Implementations of this class provide lookup services for
037 * print services (typically equivalent to printers) of a particular type.
038 * <p>
039 * Multiple implementations may be installed concurrently.
040 * All implementations must be able to describe the located printers
041 * as instances of a PrintService.
042 * Typically implementations of this service class are located
043 * automatically in JAR files (see the SPI JAR file specification).
044 * These classes must be instantiable using a default constructor.
045 * Alternatively applications may explicitly register instances
046 * at runtime.
047 * <p>
048 * Applications use only the static methods of this abstract class.
049 * The instance methods are implemented by a service provider in a subclass
050 * and the unification of the results from all installed lookup classes
051 * are reported by the static methods of this class when called by
052 * the application.
053 * <p>
054 * A PrintServiceLookup implementor is recommended to check for the
055 * SecurityManager.checkPrintJobAccess() to deny access to untrusted code.
056 * Following this recommended policy means that untrusted code may not
057 * be able to locate any print services. Downloaded applets are the most
058 * common example of untrusted code.
059 * <p>
060 * This check is made on a per lookup service basis to allow flexibility in
061 * the policy to reflect the needs of different lookup services.
062 * <p>
063 * Services which are registered by registerService(PrintService)
064 * will not be included in lookup results if a security manager is
065 * installed and its checkPrintJobAccess() method denies access.
066 */
067
068 public abstract class PrintServiceLookup {
069
070 static class Services {
071 private ArrayList listOfLookupServices = null;
072 private ArrayList registeredServices = null;
073 }
074
075 private static Services getServicesForContext() {
076 Services services = (Services) AppContext.getAppContext().get(
077 Services.class);
078 if (services == null) {
079 services = new Services();
080 AppContext.getAppContext().put(Services.class, services);
081 }
082 return services;
083 }
084
085 private static ArrayList getListOfLookupServices() {
086 return getServicesForContext().listOfLookupServices;
087 }
088
089 private static ArrayList initListOfLookupServices() {
090 ArrayList listOfLookupServices = new ArrayList();
091 getServicesForContext().listOfLookupServices = listOfLookupServices;
092 return listOfLookupServices;
093 }
094
095 private static ArrayList getRegisteredServices() {
096 return getServicesForContext().registeredServices;
097 }
098
099 private static ArrayList initRegisteredServices() {
100 ArrayList registeredServices = new ArrayList();
101 getServicesForContext().registeredServices = registeredServices;
102 return registeredServices;
103 }
104
105 /**
106 * Locates print services capable of printing the specified
107 * {@link DocFlavor}.
108 *
109 * @param flavor the flavor to print. If null, this constraint is not
110 * used.
111 * @param attributes attributes that the print service must support.
112 * If null this constraint is not used.
113 *
114 * @return array of matching <code>PrintService</code> objects
115 * representing print services that support the specified flavor
116 * attributes. If no services match, the array is zero-length.
117 */
118 public static final PrintService[] lookupPrintServices(
119 DocFlavor flavor, AttributeSet attributes) {
120 ArrayList list = getServices(flavor, attributes);
121 return (PrintService[]) (list.toArray(new PrintService[list
122 .size()]));
123 }
124
125 /**
126 * Locates MultiDoc print Services capable of printing MultiDocs
127 * containing all the specified doc flavors.
128 * <P> This method is useful to help locate a service that can print
129 * a <code>MultiDoc</code> in which the elements may be different
130 * flavors. An application could perform this itself by multiple lookups
131 * on each <code>DocFlavor</code> in turn and collating the results,
132 * but the lookup service may be able to do this more efficiently.
133 *
134 * @param flavors the flavors to print. If null or empty this
135 * constraint is not used.
136 * Otherwise return only multidoc print services that can print all
137 * specified doc flavors.
138 * @param attributes attributes that the print service must
139 * support. If null this constraint is not used.
140 *
141 * @return array of matching {@link MultiDocPrintService} objects.
142 * If no services match, the array is zero-length.
143 *
144 */
145 public static final MultiDocPrintService[] lookupMultiDocPrintServices(
146 DocFlavor[] flavors, AttributeSet attributes) {
147 ArrayList list = getMultiDocServices(flavors, attributes);
148 return (MultiDocPrintService[]) list
149 .toArray(new MultiDocPrintService[list.size()]);
150 }
151
152 /**
153 * Locates the default print service for this environment.
154 * This may return null.
155 * If multiple lookup services each specify a default, the
156 * chosen service is not precisely defined, but a
157 * platform native service, rather than an installed service,
158 * is usually returned as the default. If there is no clearly
159 * identifiable
160 * platform native default print service, the default is the first
161 * to be located in an implementation-dependent manner.
162 * <p>
163 * This may include making use of any preferences API that is available
164 * as part of the Java or native platform.
165 * This algorithm may be overridden by a user setting the property
166 * javax.print.defaultPrinter.
167 * A service specified must be discovered to be valid and currently
168 * available to be returned as the default.
169 *
170 * @return the default PrintService.
171 */
172
173 public static final PrintService lookupDefaultPrintService() {
174
175 Iterator psIterator = getAllLookupServices().iterator();
176 while (psIterator.hasNext()) {
177 try {
178 PrintServiceLookup lus = (PrintServiceLookup) psIterator
179 .next();
180 PrintService service = lus.getDefaultPrintService();
181 if (service != null) {
182 return service;
183 }
184 } catch (Exception e) {
185 }
186 }
187 return null;
188 }
189
190 /**
191 * Allows an application to explicitly register a class that
192 * implements lookup services. The registration will not persist
193 * across VM invocations.
194 * This is useful if an application needs to make a new service
195 * available that is not part of the installation.
196 * If the lookup service is already registered, or cannot be registered,
197 * the method returns false.
198 * <p>
199 *
200 * @param sp an implementation of a lookup service.
201 * @return <code>true</code> if the new lookup service is newly
202 * registered; <code>false</code> otherwise.
203 */
204 public static boolean registerServiceProvider(PrintServiceLookup sp) {
205 synchronized (PrintServiceLookup.class) {
206 Iterator psIterator = getAllLookupServices().iterator();
207 while (psIterator.hasNext()) {
208 try {
209 Object lus = psIterator.next();
210 if (lus.getClass() == sp.getClass()) {
211 return false;
212 }
213 } catch (Exception e) {
214 }
215 }
216 getListOfLookupServices().add(sp);
217 return true;
218 }
219
220 }
221
222 /**
223 * Allows an application to directly register an instance of a
224 * class which implements a print service.
225 * The lookup operations for this service will be
226 * performed by the PrintServiceLookup class using the attribute
227 * values and classes reported by the service.
228 * This may be less efficient than a lookup
229 * service tuned for that service.
230 * Therefore registering a <code>PrintServiceLookup</code> instance
231 * instead is recommended.
232 * The method returns true if this service is not previously
233 * registered and is now successfully registered.
234 * This method should not be called with StreamPrintService instances.
235 * They will always fail to register and the method will return false.
236 * @param service an implementation of a print service.
237 * @return <code>true</code> if the service is newly
238 * registered; <code>false</code> otherwise.
239 */
240
241 public static boolean registerService(PrintService service) {
242 synchronized (PrintServiceLookup.class) {
243 if (service instanceof StreamPrintService) {
244 return false;
245 }
246 ArrayList registeredServices = getRegisteredServices();
247 if (registeredServices == null) {
248 registeredServices = initRegisteredServices();
249 } else {
250 if (registeredServices.contains(service)) {
251 return false;
252 }
253 }
254 registeredServices.add(service);
255 return true;
256 }
257 }
258
259 /**
260 * Locates services that can be positively confirmed to support
261 * the combination of attributes and DocFlavors specified.
262 * This method is not called directly by applications.
263 * <p>
264 * Implemented by a service provider, used by the static methods
265 * of this class.
266 * <p>
267 * The results should be the same as obtaining all the PrintServices
268 * and querying each one individually on its support for the
269 * specified attributes and flavors, but the process can be more
270 * efficient by taking advantage of the capabilities of lookup services
271 * for the print services.
272 *
273 * @param flavor of document required. If null it is ignored.
274 * @param attributes required to be supported. If null this
275 * constraint is not used.
276 * @return array of matching PrintServices. If no services match, the
277 * array is zero-length.
278 */
279 public abstract PrintService[] getPrintServices(DocFlavor flavor,
280 AttributeSet attributes);
281
282 /**
283 * Not called directly by applications.
284 * Implemented by a service provider, used by the static methods
285 * of this class.
286 * @return array of all PrintServices known to this lookup service
287 * class. If none are found, the array is zero-length.
288 */
289 public abstract PrintService[] getPrintServices();
290
291 /**
292 * Not called directly by applications.
293 * <p>
294 * Implemented by a service provider, used by the static methods
295 * of this class.
296 * <p>
297 * Locates MultiDoc print services which can be positively confirmed
298 * to support the combination of attributes and DocFlavors specified.
299 * <p>
300 *
301 * @param flavors of documents required. If null or empty it is ignored.
302 * @param attributes required to be supported. If null this
303 * constraint is not used.
304 * @return array of matching PrintServices. If no services match, the
305 * array is zero-length.
306 */
307 public abstract MultiDocPrintService[] getMultiDocPrintServices(
308 DocFlavor[] flavors, AttributeSet attributes);
309
310 /**
311 * Not called directly by applications.
312 * Implemented by a service provider, and called by the print lookup
313 * service
314 * @return the default PrintService for this lookup service.
315 * If there is no default, returns null.
316 */
317 public abstract PrintService getDefaultPrintService();
318
319 private static ArrayList getAllLookupServices() {
320 synchronized (PrintServiceLookup.class) {
321 ArrayList listOfLookupServices = getListOfLookupServices();
322 if (listOfLookupServices != null) {
323 return listOfLookupServices;
324 } else {
325 listOfLookupServices = initListOfLookupServices();
326 }
327 try {
328 java.security.AccessController
329 .doPrivileged(new java.security.PrivilegedExceptionAction() {
330 public Object run() {
331 Iterator iterator = Service
332 .providers(PrintServiceLookup.class);
333 ArrayList los = getListOfLookupServices();
334 while (iterator.hasNext()) {
335 try {
336 PrintServiceLookup lus = (PrintServiceLookup) iterator
337 .next();
338 los.add(lus);
339 } catch (Exception e) {
340 }
341 }
342 return null;
343 }
344 });
345 } catch (java.security.PrivilegedActionException e) {
346 }
347
348 return listOfLookupServices;
349 }
350 }
351
352 private static ArrayList getServices(DocFlavor flavor,
353 AttributeSet attributes) {
354
355 ArrayList listOfServices = new ArrayList();
356 Iterator psIterator = getAllLookupServices().iterator();
357 while (psIterator.hasNext()) {
358 try {
359 PrintServiceLookup lus = (PrintServiceLookup) psIterator
360 .next();
361 PrintService[] services = null;
362 if (flavor == null && attributes == null) {
363 try {
364 services = lus.getPrintServices();
365 } catch (Throwable tr) {
366 }
367 } else {
368 services = lus.getPrintServices(flavor, attributes);
369 }
370 if (services == null) {
371 continue;
372 }
373 for (int i = 0; i < services.length; i++) {
374 listOfServices.add(services[i]);
375 }
376 } catch (Exception e) {
377 }
378 }
379 /* add any directly registered services */
380 ArrayList registeredServices = null;
381 try {
382 SecurityManager security = System.getSecurityManager();
383 if (security != null) {
384 security.checkPrintJobAccess();
385 }
386 registeredServices = getRegisteredServices();
387 } catch (SecurityException se) {
388 }
389 if (registeredServices != null) {
390 PrintService[] services = (PrintService[]) registeredServices
391 .toArray(new PrintService[registeredServices.size()]);
392 for (int i = 0; i < services.length; i++) {
393 if (!listOfServices.contains(services[i])) {
394 if (flavor == null && attributes == null) {
395 listOfServices.add(services[i]);
396 } else if (((flavor != null && services[i]
397 .isDocFlavorSupported(flavor)) || flavor == null)
398 && null == services[i]
399 .getUnsupportedAttributes(flavor,
400 attributes)) {
401 listOfServices.add(services[i]);
402 }
403 }
404 }
405 }
406 return listOfServices;
407 }
408
409 private static ArrayList getMultiDocServices(DocFlavor[] flavors,
410 AttributeSet attributes) {
411
412 ArrayList listOfServices = new ArrayList();
413 Iterator psIterator = getAllLookupServices().iterator();
414 while (psIterator.hasNext()) {
415 try {
416 PrintServiceLookup lus = (PrintServiceLookup) psIterator
417 .next();
418 MultiDocPrintService[] services = lus
419 .getMultiDocPrintServices(flavors, attributes);
420 if (services == null) {
421 continue;
422 }
423 for (int i = 0; i < services.length; i++) {
424 listOfServices.add(services[i]);
425 }
426 } catch (Exception e) {
427 }
428 }
429 /* add any directly registered services */
430 ArrayList registeredServices = null;
431 try {
432 SecurityManager security = System.getSecurityManager();
433 if (security != null) {
434 security.checkPrintJobAccess();
435 }
436 registeredServices = getRegisteredServices();
437 } catch (Exception e) {
438 }
439 if (registeredServices != null) {
440 PrintService[] services = (PrintService[]) registeredServices
441 .toArray(new PrintService[registeredServices.size()]);
442 for (int i = 0; i < services.length; i++) {
443 if (services[i] instanceof MultiDocPrintService
444 && !listOfServices.contains(services[i])) {
445 if (flavors == null || flavors.length == 0) {
446 listOfServices.add(services[i]);
447 } else {
448 boolean supported = true;
449 for (int f = 0; f < flavors.length; f++) {
450 if (services[i]
451 .isDocFlavorSupported(flavors[f])) {
452
453 if (services[i]
454 .getUnsupportedAttributes(
455 flavors[f], attributes) != null) {
456 supported = false;
457 break;
458 }
459 } else {
460 supported = false;
461 break;
462 }
463 }
464 if (supported) {
465 listOfServices.add(services[i]);
466 }
467 }
468 }
469 }
470 }
471 return listOfServices;
472 }
473
474 }
|