Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/print/PrintServiceLookup.java
38829 views
/*1* Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/242526package javax.print;2728import java.util.ArrayList;29import java.util.Iterator;30import javax.print.attribute.AttributeSet;3132import sun.awt.AppContext;33import java.util.ServiceLoader;34import java.util.ServiceConfigurationError;3536/** Implementations of this class provide lookup services for37* print services (typically equivalent to printers) of a particular type.38* <p>39* Multiple implementations may be installed concurrently.40* All implementations must be able to describe the located printers41* as instances of a PrintService.42* Typically implementations of this service class are located43* automatically in JAR files (see the SPI JAR file specification).44* These classes must be instantiable using a default constructor.45* Alternatively applications may explicitly register instances46* at runtime.47* <p>48* Applications use only the static methods of this abstract class.49* The instance methods are implemented by a service provider in a subclass50* and the unification of the results from all installed lookup classes51* are reported by the static methods of this class when called by52* the application.53* <p>54* A PrintServiceLookup implementor is recommended to check for the55* SecurityManager.checkPrintJobAccess() to deny access to untrusted code.56* Following this recommended policy means that untrusted code may not57* be able to locate any print services. Downloaded applets are the most58* common example of untrusted code.59* <p>60* This check is made on a per lookup service basis to allow flexibility in61* the policy to reflect the needs of different lookup services.62* <p>63* Services which are registered by registerService(PrintService)64* will not be included in lookup results if a security manager is65* installed and its checkPrintJobAccess() method denies access.66*/6768public abstract class PrintServiceLookup {6970static class Services {71private ArrayList listOfLookupServices = null;72private ArrayList registeredServices = null;73}7475private static Services getServicesForContext() {76Services services =77(Services)AppContext.getAppContext().get(Services.class);78if (services == null) {79services = new Services();80AppContext.getAppContext().put(Services.class, services);81}82return services;83}8485private static ArrayList getListOfLookupServices() {86return getServicesForContext().listOfLookupServices;87}8889private static ArrayList initListOfLookupServices() {90ArrayList listOfLookupServices = new ArrayList();91getServicesForContext().listOfLookupServices = listOfLookupServices;92return listOfLookupServices;93}949596private static ArrayList getRegisteredServices() {97return getServicesForContext().registeredServices;98}99100private static ArrayList initRegisteredServices() {101ArrayList registeredServices = new ArrayList();102getServicesForContext().registeredServices = registeredServices;103return registeredServices;104}105106/**107* Locates print services capable of printing the specified108* {@link DocFlavor}.109*110* @param flavor the flavor to print. If null, this constraint is not111* used.112* @param attributes attributes that the print service must support.113* If null this constraint is not used.114*115* @return array of matching <code>PrintService</code> objects116* representing print services that support the specified flavor117* attributes. If no services match, the array is zero-length.118*/119public static final PrintService[]120lookupPrintServices(DocFlavor flavor,121AttributeSet attributes) {122ArrayList list = getServices(flavor, attributes);123return (PrintService[])(list.toArray(new PrintService[list.size()]));124}125126127/**128* Locates MultiDoc print Services capable of printing MultiDocs129* containing all the specified doc flavors.130* <P> This method is useful to help locate a service that can print131* a <code>MultiDoc</code> in which the elements may be different132* flavors. An application could perform this itself by multiple lookups133* on each <code>DocFlavor</code> in turn and collating the results,134* but the lookup service may be able to do this more efficiently.135*136* @param flavors the flavors to print. If null or empty this137* constraint is not used.138* Otherwise return only multidoc print services that can print all139* specified doc flavors.140* @param attributes attributes that the print service must141* support. If null this constraint is not used.142*143* @return array of matching {@link MultiDocPrintService} objects.144* If no services match, the array is zero-length.145*146*/147public static final MultiDocPrintService[]148lookupMultiDocPrintServices(DocFlavor[] flavors,149AttributeSet attributes) {150ArrayList list = getMultiDocServices(flavors, attributes);151return (MultiDocPrintService[])152list.toArray(new MultiDocPrintService[list.size()]);153}154155156/**157* Locates the default print service for this environment.158* This may return null.159* If multiple lookup services each specify a default, the160* chosen service is not precisely defined, but a161* platform native service, rather than an installed service,162* is usually returned as the default. If there is no clearly163* identifiable164* platform native default print service, the default is the first165* to be located in an implementation-dependent manner.166* <p>167* This may include making use of any preferences API that is available168* as part of the Java or native platform.169* This algorithm may be overridden by a user setting the property170* javax.print.defaultPrinter.171* A service specified must be discovered to be valid and currently172* available to be returned as the default.173*174* @return the default PrintService.175*/176177public static final PrintService lookupDefaultPrintService() {178179Iterator psIterator = getAllLookupServices().iterator();180while (psIterator.hasNext()) {181try {182PrintServiceLookup lus = (PrintServiceLookup)psIterator.next();183PrintService service = lus.getDefaultPrintService();184if (service != null) {185return service;186}187} catch (Exception e) {188}189}190return null;191}192193194/**195* Allows an application to explicitly register a class that196* implements lookup services. The registration will not persist197* across VM invocations.198* This is useful if an application needs to make a new service199* 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* <p>203*204* @param sp an implementation of a lookup service.205* @return <code>true</code> if the new lookup service is newly206* registered; <code>false</code> otherwise.207*/208public static boolean registerServiceProvider(PrintServiceLookup sp) {209synchronized (PrintServiceLookup.class) {210Iterator psIterator = getAllLookupServices().iterator();211while (psIterator.hasNext()) {212try {213Object lus = psIterator.next();214if (lus.getClass() == sp.getClass()) {215return false;216}217} catch (Exception e) {218}219}220getListOfLookupServices().add(sp);221return true;222}223224}225226227/**228* Allows an application to directly register an instance of a229* class which implements a print service.230* The lookup operations for this service will be231* performed by the PrintServiceLookup class using the attribute232* values and classes reported by the service.233* This may be less efficient than a lookup234* service tuned for that service.235* Therefore registering a <code>PrintServiceLookup</code> instance236* instead is recommended.237* The method returns true if this service is not previously238* 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</code> if the service is newly243* registered; <code>false</code> otherwise.244*/245246public static boolean registerService(PrintService service) {247synchronized (PrintServiceLookup.class) {248if (service instanceof StreamPrintService) {249return false;250}251ArrayList registeredServices = getRegisteredServices();252if (registeredServices == null) {253registeredServices = initRegisteredServices();254}255else {256if (registeredServices.contains(service)) {257return false;258}259}260registeredServices.add(service);261return true;262}263}264265266/**267* Locates services that can be positively confirmed to support268* 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 methods272* of this class.273* <p>274* The results should be the same as obtaining all the PrintServices275* and querying each one individually on its support for the276* specified attributes and flavors, but the process can be more277* efficient by taking advantage of the capabilities of lookup services278* 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 this282* constraint is not used.283* @return array of matching PrintServices. If no services match, the284* array is zero-length.285*/286public abstract PrintService[] getPrintServices(DocFlavor flavor,287AttributeSet attributes);288289/**290* Not called directly by applications.291* Implemented by a service provider, used by the static methods292* of this class.293* @return array of all PrintServices known to this lookup service294* class. If none are found, the array is zero-length.295*/296public abstract PrintService[] getPrintServices() ;297298299/**300* Not called directly by applications.301* <p>302* Implemented by a service provider, used by the static methods303* of this class.304* <p>305* Locates MultiDoc print services which can be positively confirmed306* to support the combination of attributes and DocFlavors specified.307* <p>308*309* @param flavors of documents required. If null or empty it is ignored.310* @param attributes required to be supported. If null this311* constraint is not used.312* @return array of matching PrintServices. If no services match, the313* array is zero-length.314*/315public abstract MultiDocPrintService[]316getMultiDocPrintServices(DocFlavor[] flavors,317AttributeSet attributes);318319/**320* Not called directly by applications.321* Implemented by a service provider, and called by the print lookup322* service323* @return the default PrintService for this lookup service.324* If there is no default, returns null.325*/326public abstract PrintService getDefaultPrintService();327328private static ArrayList getAllLookupServices() {329synchronized (PrintServiceLookup.class) {330ArrayList listOfLookupServices = getListOfLookupServices();331if (listOfLookupServices != null) {332return listOfLookupServices;333} else {334listOfLookupServices = initListOfLookupServices();335}336try {337java.security.AccessController.doPrivileged(338new java.security.PrivilegedExceptionAction() {339public Object run() {340Iterator<PrintServiceLookup> iterator =341ServiceLoader.load(PrintServiceLookup.class).342iterator();343ArrayList los = getListOfLookupServices();344while (iterator.hasNext()) {345try {346los.add(iterator.next());347} catch (ServiceConfigurationError err) {348/* In the applet case, we continue */349if (System.getSecurityManager() != null) {350err.printStackTrace();351} else {352throw err;353}354}355}356return null;357}358});359} catch (java.security.PrivilegedActionException e) {360}361362return listOfLookupServices;363}364}365366private static ArrayList getServices(DocFlavor flavor,367AttributeSet attributes) {368369ArrayList listOfServices = new ArrayList();370Iterator psIterator = getAllLookupServices().iterator();371while (psIterator.hasNext()) {372try {373PrintServiceLookup lus = (PrintServiceLookup)psIterator.next();374PrintService[] services=null;375if (flavor == null && attributes == null) {376try {377services = lus.getPrintServices();378} catch (Throwable tr) {379}380} else {381services = lus.getPrintServices(flavor, attributes);382}383if (services == null) {384continue;385}386for (int i=0; i<services.length; i++) {387listOfServices.add(services[i]);388}389} catch (Exception e) {390}391}392/* add any directly registered services */393ArrayList registeredServices = null;394try {395SecurityManager security = System.getSecurityManager();396if (security != null) {397security.checkPrintJobAccess();398}399registeredServices = getRegisteredServices();400} catch (SecurityException se) {401}402if (registeredServices != null) {403PrintService[] services = (PrintService[])404registeredServices.toArray(405new PrintService[registeredServices.size()]);406for (int i=0; i<services.length; i++) {407if (!listOfServices.contains(services[i])) {408if (flavor == null && attributes == null) {409listOfServices.add(services[i]);410} else if (((flavor != null &&411services[i].isDocFlavorSupported(flavor)) ||412flavor == null) &&413null == services[i].getUnsupportedAttributes(414flavor, attributes)) {415listOfServices.add(services[i]);416}417}418}419}420return listOfServices;421}422423private static ArrayList getMultiDocServices(DocFlavor[] flavors,424AttributeSet attributes) {425426427ArrayList listOfServices = new ArrayList();428Iterator psIterator = getAllLookupServices().iterator();429while (psIterator.hasNext()) {430try {431PrintServiceLookup lus = (PrintServiceLookup)psIterator.next();432MultiDocPrintService[] services =433lus.getMultiDocPrintServices(flavors, attributes);434if (services == null) {435continue;436}437for (int i=0; i<services.length; i++) {438listOfServices.add(services[i]);439}440} catch (Exception e) {441}442}443/* add any directly registered services */444ArrayList registeredServices = null;445try {446SecurityManager security = System.getSecurityManager();447if (security != null) {448security.checkPrintJobAccess();449}450registeredServices = getRegisteredServices();451} catch (Exception e) {452}453if (registeredServices != null) {454PrintService[] services = (PrintService[])455registeredServices.toArray(456new PrintService[registeredServices.size()]);457for (int i=0; i<services.length; i++) {458if (services[i] instanceof MultiDocPrintService &&459!listOfServices.contains(services[i])) {460if (flavors == null || flavors.length == 0) {461listOfServices.add(services[i]);462} else {463boolean supported = true;464for (int f=0; f<flavors.length; f++) {465if (services[i].isDocFlavorSupported(flavors[f])) {466467if (services[i].getUnsupportedAttributes(468flavors[f], attributes) != null) {469supported = false;470break;471}472} else {473supported = false;474break;475}476}477if (supported) {478listOfServices.add(services[i]);479}480}481}482}483}484return listOfServices;485}486487}488489490