1 /*
   2  * Copyright (c) 2000, 2014, 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 
  27 package javax.print;
  28 
  29 import java.util.ArrayList;
  30 import java.util.Iterator;
  31 import javax.print.attribute.AttributeSet;
  32 
  33 import sun.awt.AppContext;
  34 import java.util.ServiceLoader;
  35 import java.util.ServiceConfigurationError;
  36 
  37 /** Implementations of this class provide lookup services for
  38   * print services (typically equivalent to printers) of a particular type.
  39   * <p>
  40   * Multiple implementations may be installed concurrently.
  41   * All implementations must be able to describe the located printers
  42   * as instances of a PrintService.
  43   * Typically implementations of this service class are located
  44   * automatically in JAR files (see the SPI JAR file specification).
  45   * These classes must be instantiable using a default constructor.
  46   * Alternatively applications may explicitly register instances
  47   * at runtime.
  48   * <p>
  49   * Applications use only the static methods of this abstract class.
  50   * The instance methods are implemented by a service provider in a subclass
  51   * and the unification of the results from all installed lookup classes
  52   * are reported by the static methods of this class when called by
  53   * the application.
  54   * <p>
  55   * A PrintServiceLookup implementor is recommended to check for the
  56   * SecurityManager.checkPrintJobAccess() to deny access to untrusted code.
  57   * Following this recommended policy means that untrusted code may not
  58   * be able to locate any print services. Downloaded applets are the most
  59   * common example of untrusted code.
  60   * <p>
  61   * This check is made on a per lookup service basis to allow flexibility in
  62   * the policy to reflect the needs of different lookup services.
  63   * <p>
  64   * Services which are registered by registerService(PrintService)
  65   * will not be included in lookup results if a security manager is
  66   * installed and its checkPrintJobAccess() method denies access.
  67   */
  68 
  69 public abstract class PrintServiceLookup {
  70 
  71     static class Services {
  72         private ArrayList<PrintServiceLookup> listOfLookupServices = null;
  73         private ArrayList<PrintService> registeredServices = null;
  74     }
  75 
  76     private static Services getServicesForContext() {
  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     private static ArrayList<PrintServiceLookup> getListOfLookupServices() {
  87         return getServicesForContext().listOfLookupServices;
  88     }
  89 
  90     private static ArrayList<PrintServiceLookup> initListOfLookupServices() {
  91         ArrayList<PrintServiceLookup> listOfLookupServices = new ArrayList<>();
  92         getServicesForContext().listOfLookupServices = listOfLookupServices;
  93         return listOfLookupServices;
  94     }
  95 
  96 
  97     private static ArrayList<PrintService> getRegisteredServices() {
  98         return getServicesForContext().registeredServices;
  99     }
 100 
 101     private static ArrayList<PrintService> initRegisteredServices() {
 102         ArrayList<PrintService> registeredServices = new ArrayList<>();
 103         getServicesForContext().registeredServices = registeredServices;
 104         return registeredServices;
 105     }
 106 
 107     /**
 108      * Locates print services capable of printing the specified
 109      * {@link DocFlavor}.
 110      *
 111      * @param flavor the flavor to print. If null, this constraint is not
 112      *        used.
 113      * @param attributes attributes that the print service must support.
 114      * If null this constraint is not used.
 115      *
 116      * @return array of matching {@code PrintService} objects
 117      * representing print services that support the specified flavor
 118      * attributes.  If no services match, the array is zero-length.
 119      */
 120     public static final PrintService[]
 121         lookupPrintServices(DocFlavor flavor,
 122                             AttributeSet attributes) {
 123         ArrayList<PrintService> list = getServices(flavor, attributes);
 124         return list.toArray(new PrintService[list.size()]);
 125     }
 126 
 127 
 128     /**
 129      * Locates MultiDoc print Services capable of printing MultiDocs
 130      * containing all the specified doc flavors.
 131      * <P> This method is useful to help locate a service that can print
 132      * a {@code MultiDoc} in which the elements may be different
 133      * flavors. An application could perform this itself by multiple lookups
 134      * on each {@code DocFlavor} in turn and collating the results,
 135      * but the lookup service may be able to do this more efficiently.
 136      *
 137      * @param flavors the flavors to print. If null or empty this
 138      *        constraint is not used.
 139      * Otherwise return only multidoc print services that can print all
 140      * specified doc flavors.
 141      * @param attributes attributes that the print service must
 142      * support.  If null this constraint is not used.
 143      *
 144      * @return array of matching {@link MultiDocPrintService} objects.
 145      * If no services match, the array is zero-length.
 146      *
 147      */
 148     public static final MultiDocPrintService[]
 149         lookupMultiDocPrintServices(DocFlavor[] flavors,
 150                                     AttributeSet attributes) {
 151         ArrayList<MultiDocPrintService> list = getMultiDocServices(flavors, attributes);
 152         return list.toArray(new MultiDocPrintService[list.size()]);
 153     }
 154 
 155 
 156     /**
 157      * Locates the default print service for this environment.
 158      * This may return null.
 159      * If multiple lookup services each specify a default, the
 160      * chosen service is not precisely defined, but a
 161      * platform native service, rather than an installed service,
 162      * is usually returned as the default.  If there is no clearly
 163      * identifiable
 164      * platform native default print service, the default is the first
 165      * to be located in an implementation-dependent manner.
 166      * <p>
 167      * This may include making use of any preferences API that is available
 168      * as part of the Java or native platform.
 169      * This algorithm may be overridden by a user setting the property
 170      * javax.print.defaultPrinter.
 171      * A service specified must be discovered to be valid and currently
 172      * available to be returned as the default.
 173      *
 174      * @return the default PrintService.
 175      */
 176 
 177     public static final PrintService lookupDefaultPrintService() {
 178 
 179         Iterator<PrintServiceLookup> psIterator = getAllLookupServices().iterator();
 180         while (psIterator.hasNext()) {
 181             try {
 182                 PrintServiceLookup lus = psIterator.next();
 183                 PrintService service = lus.getDefaultPrintService();
 184                 if (service != null) {
 185                     return service;
 186                 }
 187             } catch (Exception e) {
 188             }
 189         }
 190         return null;
 191     }
 192 
 193 
 194     /**
 195      * Allows an application to explicitly register a class that
 196      * implements lookup services. The registration will not persist
 197      * across VM invocations.
 198      * This is useful if an application needs to make a new service
 199      * available that is not part of the installation.
 200      * If the lookup service is already registered, or cannot be registered,
 201      * the method returns false.
 202      *
 203      * @param sp an implementation of a lookup service.
 204      * @return {@code true} if the new lookup service is newly
 205      *         registered; {@code false} otherwise.
 206      */
 207     public static boolean registerServiceProvider(PrintServiceLookup sp) {
 208         synchronized (PrintServiceLookup.class) {
 209             Iterator<PrintServiceLookup> psIterator =
 210                 getAllLookupServices().iterator();
 211             while (psIterator.hasNext()) {
 212                 try {
 213                     Object lus = psIterator.next();
 214                     if (lus.getClass() == sp.getClass()) {
 215                         return false;
 216                     }
 217                 } catch (Exception e) {
 218                 }
 219             }
 220             getListOfLookupServices().add(sp);
 221             return true;
 222         }
 223 
 224     }
 225 
 226 
 227     /**
 228      * Allows an application to directly register an instance of a
 229      * class which implements a print service.
 230      * The lookup operations for this service will be
 231      * performed by the PrintServiceLookup class using the attribute
 232      * values and classes reported by the service.
 233      * This may be less efficient than a lookup
 234      * service tuned for that service.
 235      * Therefore registering a {@code PrintServiceLookup} instance
 236      * instead is recommended.
 237      * The method returns true if this service is not previously
 238      * registered and is now successfully registered.
 239      * This method should not be called with StreamPrintService instances.
 240      * They will always fail to register and the method will return false.
 241      * @param service an implementation of a print service.
 242      * @return {@code true} if the service is newly
 243      *         registered; {@code false} otherwise.
 244      */
 245 
 246     public static boolean registerService(PrintService service) {
 247         synchronized (PrintServiceLookup.class) {
 248             if (service == null || service instanceof StreamPrintService) {
 249                 return false;
 250             }
 251             ArrayList<PrintService> registeredServices = getRegisteredServices();
 252             if (registeredServices == null) {
 253                 registeredServices = initRegisteredServices();
 254             }
 255             else {
 256               if (registeredServices.contains(service)) {
 257                 return false;
 258               }
 259             }
 260             registeredServices.add(service);
 261             return true;
 262         }
 263     }
 264 
 265 
 266    /**
 267     * Locates services that can be positively confirmed to support
 268     * the combination of attributes and DocFlavors specified.
 269     * This method is not called directly by applications.
 270     * <p>
 271     * Implemented by a service provider, used by the static methods
 272     * of this class.
 273     * <p>
 274     * The results should be the same as obtaining all the PrintServices
 275     * and querying each one individually on its support for the
 276     * specified attributes and flavors, but the process can be more
 277     * efficient by taking advantage of the capabilities of lookup services
 278     * for the print services.
 279     *
 280     * @param flavor of document required.  If null it is ignored.
 281     * @param attributes required to be supported. If null this
 282     * constraint is not used.
 283     * @return array of matching PrintServices. If no services match, the
 284     * array is zero-length.
 285     */
 286     public abstract PrintService[] getPrintServices(DocFlavor flavor,
 287                                                     AttributeSet attributes);
 288 
 289     /**
 290      * Not called directly by applications.
 291      * Implemented by a service provider, used by the static methods
 292      * of this class.
 293      * @return array of all PrintServices known to this lookup service
 294      * class. If none are found, the array is zero-length.
 295      */
 296     public abstract PrintService[] getPrintServices() ;
 297 
 298 
 299    /**
 300     * Not called directly by applications.
 301     * <p>
 302     * Implemented by a service provider, used by the static methods
 303     * of this class.
 304     * <p>
 305     * Locates MultiDoc print services which can be positively confirmed
 306     * to support the combination of attributes and DocFlavors specified.
 307     *
 308     * @param flavors of documents required. If null or empty it is ignored.
 309     * @param attributes required to be supported. If null this
 310      * constraint is not used.
 311     * @return array of matching PrintServices. If no services match, the
 312     * array is zero-length.
 313     */
 314     public abstract MultiDocPrintService[]
 315         getMultiDocPrintServices(DocFlavor[] flavors,
 316                                  AttributeSet attributes);
 317 
 318     /**
 319      * Not called directly by applications.
 320      * Implemented by a service provider, and called by the print lookup
 321      * service
 322      * @return the default PrintService for this lookup service.
 323      * If there is no default, returns null.
 324      */
 325     public abstract PrintService getDefaultPrintService();
 326 
 327     private static ArrayList<PrintServiceLookup> getAllLookupServices() {
 328         synchronized (PrintServiceLookup.class) {
 329             ArrayList<PrintServiceLookup> listOfLookupServices = getListOfLookupServices();
 330             if (listOfLookupServices != null) {
 331                 return listOfLookupServices;
 332             } else {
 333                 listOfLookupServices = initListOfLookupServices();
 334             }
 335             try {
 336                 java.security.AccessController.doPrivileged(
 337                      new java.security.PrivilegedExceptionAction<Object>() {
 338                         public Object run() {
 339                             Iterator<PrintServiceLookup> iterator =
 340                                 ServiceLoader.load(PrintServiceLookup.class).
 341                                 iterator();
 342                             ArrayList<PrintServiceLookup> los = getListOfLookupServices();
 343                             while (iterator.hasNext()) {
 344                                 try {
 345                                     los.add(iterator.next());
 346                                 }  catch (ServiceConfigurationError err) {
 347                                     /* In the applet case, we continue */
 348                                     if (System.getSecurityManager() != null) {
 349                                         err.printStackTrace();
 350                                     } else {
 351                                         throw err;
 352                                     }
 353                                 }
 354                             }
 355                             return null;
 356                         }
 357                 });
 358             } catch (java.security.PrivilegedActionException e) {
 359             }
 360 
 361             return listOfLookupServices;
 362         }
 363     }
 364 
 365     private static ArrayList<PrintService> getServices(DocFlavor flavor,
 366                                                        AttributeSet attributes) {
 367 
 368         ArrayList<PrintService> listOfServices = new ArrayList<>();
 369         Iterator<PrintServiceLookup> psIterator = getAllLookupServices().iterator();
 370         while (psIterator.hasNext()) {
 371             try {
 372                 PrintServiceLookup lus = psIterator.next();
 373                 PrintService[] services=null;
 374                 if (flavor == null && attributes == null) {
 375                     try {
 376                     services = lus.getPrintServices();
 377                     } catch (Throwable tr) {
 378                     }
 379                 } else {
 380                     services = lus.getPrintServices(flavor, attributes);
 381                 }
 382                 if (services == null) {
 383                     continue;
 384                 }
 385                 for (int i=0; i<services.length; i++) {
 386                     listOfServices.add(services[i]);
 387                 }
 388             } catch (Exception e) {
 389             }
 390         }
 391         /* add any directly registered services */
 392         ArrayList<PrintService> registeredServices = null;
 393         try {
 394           SecurityManager security = System.getSecurityManager();
 395           if (security != null) {
 396             security.checkPrintJobAccess();
 397           }
 398           registeredServices = getRegisteredServices();
 399         } catch (SecurityException se) {
 400         }
 401         if (registeredServices != null) {
 402             PrintService[] services = registeredServices.toArray(
 403                            new PrintService[registeredServices.size()]);
 404             for (int i=0; i<services.length; i++) {
 405                 if (!listOfServices.contains(services[i])) {
 406                     if (flavor == null && attributes == null) {
 407                         listOfServices.add(services[i]);
 408                     } else if (((flavor != null &&
 409                                  services[i].isDocFlavorSupported(flavor)) ||
 410                                 flavor == null) &&
 411                                null == services[i].getUnsupportedAttributes(
 412                                                       flavor, attributes)) {
 413                         listOfServices.add(services[i]);
 414                     }
 415                 }
 416             }
 417         }
 418         return listOfServices;
 419     }
 420 
 421     private static ArrayList<MultiDocPrintService> getMultiDocServices(DocFlavor[] flavors,
 422                                                                        AttributeSet attributes) {
 423 
 424 
 425         ArrayList<MultiDocPrintService> listOfServices = new ArrayList<>();
 426         Iterator<PrintServiceLookup> psIterator = getAllLookupServices().iterator();
 427         while (psIterator.hasNext()) {
 428             try {
 429                 PrintServiceLookup lus = psIterator.next();
 430                 MultiDocPrintService[] services  =
 431                     lus.getMultiDocPrintServices(flavors, attributes);
 432                 if (services == null) {
 433                     continue;
 434                 }
 435                 for (int i=0; i<services.length; i++) {
 436                     listOfServices.add(services[i]);
 437                 }
 438             } catch (Exception e) {
 439             }
 440         }
 441         /* add any directly registered services */
 442         ArrayList<PrintService> registeredServices = null;
 443         try {
 444           SecurityManager security = System.getSecurityManager();
 445           if (security != null) {
 446             security.checkPrintJobAccess();
 447           }
 448           registeredServices = getRegisteredServices();
 449         } catch (Exception e) {
 450         }
 451         if (registeredServices != null) {
 452             PrintService[] services =
 453                 registeredServices.toArray(new PrintService[registeredServices.size()]);
 454             for (int i=0; i<services.length; i++) {
 455                 if (services[i] instanceof MultiDocPrintService &&
 456                     !listOfServices.contains(services[i])) {
 457                     if (flavors == null || flavors.length == 0) {
 458                         listOfServices.add((MultiDocPrintService)services[i]);
 459                     } else {
 460                         boolean supported = true;
 461                         for (int f=0; f<flavors.length; f++) {
 462                             if (services[i].isDocFlavorSupported(flavors[f])) {
 463 
 464                                 if (services[i].getUnsupportedAttributes(
 465                                      flavors[f], attributes) != null) {
 466                                         supported = false;
 467                                         break;
 468                                 }
 469                             } else {
 470                                 supported = false;
 471                                 break;
 472                             }
 473                         }
 474                         if (supported) {
 475                             listOfServices.add((MultiDocPrintService)services[i]);
 476                         }
 477                     }
 478                 }
 479             }
 480         }
 481         return listOfServices;
 482     }
 483 
 484 }
--- EOF ---