jdk/src/java.desktop/windows/classes/sun/print/Win32PrintServiceLookup.java
changeset 27324 f54441c74373
parent 27323 babdaa819add
parent 27315 00f085d0f75c
child 27325 948cceef81ba
equal deleted inserted replaced
27323:babdaa819add 27324:f54441c74373
     1 /*
       
     2  * Copyright (c) 2000, 2012, 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 sun.print;
       
    27 
       
    28 import java.io.BufferedReader;
       
    29 import java.io.InputStream;
       
    30 import java.io.InputStreamReader;
       
    31 import java.io.IOException;
       
    32 import java.util.ArrayList;
       
    33 import java.security.AccessController;
       
    34 import java.security.PrivilegedActionException;
       
    35 import java.security.PrivilegedExceptionAction;
       
    36 import javax.print.DocFlavor;
       
    37 import javax.print.MultiDocPrintService;
       
    38 import javax.print.PrintService;
       
    39 import javax.print.PrintServiceLookup;
       
    40 import javax.print.attribute.Attribute;
       
    41 import javax.print.attribute.AttributeSet;
       
    42 import javax.print.attribute.HashPrintRequestAttributeSet;
       
    43 import javax.print.attribute.HashPrintServiceAttributeSet;
       
    44 import javax.print.attribute.PrintRequestAttribute;
       
    45 import javax.print.attribute.PrintRequestAttributeSet;
       
    46 import javax.print.attribute.PrintServiceAttribute;
       
    47 import javax.print.attribute.PrintServiceAttributeSet;
       
    48 import javax.print.attribute.standard.PrinterName;
       
    49 
       
    50 public class Win32PrintServiceLookup extends PrintServiceLookup {
       
    51 
       
    52     private String defaultPrinter;
       
    53     private PrintService defaultPrintService;
       
    54     private String[] printers; /* excludes the default printer */
       
    55     private PrintService[] printServices; /* includes the default printer */
       
    56 
       
    57     static {
       
    58         java.security.AccessController.doPrivileged(
       
    59             new java.security.PrivilegedAction<Void>() {
       
    60                 public Void run() {
       
    61                     System.loadLibrary("awt");
       
    62                     return null;
       
    63                 }
       
    64             });
       
    65     }
       
    66 
       
    67     /* The singleton win32 print lookup service.
       
    68      * Code that is aware of this field and wants to use it must first
       
    69      * see if its null, and if so instantiate it by calling a method such as
       
    70      * javax.print.PrintServiceLookup.defaultPrintService() so that the
       
    71      * same instance is stored there.
       
    72      */
       
    73     private static Win32PrintServiceLookup win32PrintLUS;
       
    74 
       
    75     /* Think carefully before calling this. Preferably don't call it. */
       
    76     public static Win32PrintServiceLookup getWin32PrintLUS() {
       
    77         if (win32PrintLUS == null) {
       
    78             /* This call is internally synchronized.
       
    79              * When it returns an instance of this class will have
       
    80              * been instantiated - else there's a JDK internal error.
       
    81              */
       
    82             PrintServiceLookup.lookupDefaultPrintService();
       
    83         }
       
    84         return win32PrintLUS;
       
    85     }
       
    86 
       
    87     public Win32PrintServiceLookup() {
       
    88 
       
    89         if (win32PrintLUS == null) {
       
    90             win32PrintLUS = this;
       
    91 
       
    92             String osName = AccessController.doPrivileged(
       
    93                 new sun.security.action.GetPropertyAction("os.name"));
       
    94             // There's no capability for Win98 to refresh printers.
       
    95             // See "OpenPrinter" for more info.
       
    96             if (osName != null && osName.startsWith("Windows 98")) {
       
    97                 return;
       
    98             }
       
    99             // start the printer listener thread
       
   100             PrinterChangeListener thr = new PrinterChangeListener();
       
   101             thr.setDaemon(true);
       
   102             thr.start();
       
   103         } /* else condition ought to never happen! */
       
   104     }
       
   105 
       
   106     /* Want the PrintService which is default print service to have
       
   107      * equality of reference with the equivalent in list of print services
       
   108      * This isn't required by the API and there's a risk doing this will
       
   109      * lead people to assume its guaranteed.
       
   110      */
       
   111     public synchronized PrintService[] getPrintServices() {
       
   112         SecurityManager security = System.getSecurityManager();
       
   113         if (security != null) {
       
   114             security.checkPrintJobAccess();
       
   115         }
       
   116         if (printServices == null) {
       
   117             refreshServices();
       
   118         }
       
   119         return printServices;
       
   120     }
       
   121 
       
   122     private synchronized void refreshServices() {
       
   123         printers = getAllPrinterNames();
       
   124         if (printers == null) {
       
   125             // In Windows it is safe to assume no default if printers == null so we
       
   126             // don't get the default.
       
   127             printServices = new PrintService[0];
       
   128             return;
       
   129         }
       
   130 
       
   131         PrintService[] newServices = new PrintService[printers.length];
       
   132         PrintService defService = getDefaultPrintService();
       
   133         for (int p = 0; p < printers.length; p++) {
       
   134             if (defService != null &&
       
   135                 printers[p].equals(defService.getName())) {
       
   136                 newServices[p] = defService;
       
   137             } else {
       
   138                 if (printServices == null) {
       
   139                     newServices[p] = new Win32PrintService(printers[p]);
       
   140                 } else {
       
   141                     int j;
       
   142                     for (j = 0; j < printServices.length; j++) {
       
   143                         if ((printServices[j]!= null) &&
       
   144                             (printers[p].equals(printServices[j].getName()))) {
       
   145                             newServices[p] = printServices[j];
       
   146                             printServices[j] = null;
       
   147                             break;
       
   148                         }
       
   149                     }
       
   150                     if (j == printServices.length) {
       
   151                         newServices[p] = new Win32PrintService(printers[p]);
       
   152                     }
       
   153                 }
       
   154             }
       
   155         }
       
   156 
       
   157         // Look for deleted services and invalidate these
       
   158         if (printServices != null) {
       
   159             for (int j=0; j < printServices.length; j++) {
       
   160                 if ((printServices[j] instanceof Win32PrintService) &&
       
   161                     (!printServices[j].equals(defaultPrintService))) {
       
   162                     ((Win32PrintService)printServices[j]).invalidateService();
       
   163                 }
       
   164             }
       
   165         }
       
   166         printServices = newServices;
       
   167     }
       
   168 
       
   169 
       
   170     public synchronized PrintService getPrintServiceByName(String name) {
       
   171 
       
   172         if (name == null || name.equals("")) {
       
   173             return null;
       
   174         } else {
       
   175             /* getPrintServices() is now very fast. */
       
   176             PrintService[] printServices = getPrintServices();
       
   177             for (int i=0; i<printServices.length; i++) {
       
   178                 if (printServices[i].getName().equals(name)) {
       
   179                     return printServices[i];
       
   180                 }
       
   181             }
       
   182             return null;
       
   183         }
       
   184     }
       
   185 
       
   186     @SuppressWarnings("unchecked") // Cast to Class<PrintServiceAttribute>
       
   187     boolean matchingService(PrintService service,
       
   188                             PrintServiceAttributeSet serviceSet) {
       
   189         if (serviceSet != null) {
       
   190             Attribute [] attrs =  serviceSet.toArray();
       
   191             Attribute serviceAttr;
       
   192             for (int i=0; i<attrs.length; i++) {
       
   193                 serviceAttr
       
   194                     = service.getAttribute((Class<PrintServiceAttribute>)attrs[i].getCategory());
       
   195                 if (serviceAttr == null || !serviceAttr.equals(attrs[i])) {
       
   196                     return false;
       
   197                 }
       
   198             }
       
   199         }
       
   200         return true;
       
   201     }
       
   202 
       
   203     public PrintService[] getPrintServices(DocFlavor flavor,
       
   204                                            AttributeSet attributes) {
       
   205 
       
   206         SecurityManager security = System.getSecurityManager();
       
   207         if (security != null) {
       
   208           security.checkPrintJobAccess();
       
   209         }
       
   210         PrintRequestAttributeSet requestSet = null;
       
   211         PrintServiceAttributeSet serviceSet = null;
       
   212 
       
   213         if (attributes != null && !attributes.isEmpty()) {
       
   214 
       
   215             requestSet = new HashPrintRequestAttributeSet();
       
   216             serviceSet = new HashPrintServiceAttributeSet();
       
   217 
       
   218             Attribute[] attrs = attributes.toArray();
       
   219             for (int i=0; i<attrs.length; i++) {
       
   220                 if (attrs[i] instanceof PrintRequestAttribute) {
       
   221                     requestSet.add(attrs[i]);
       
   222                 } else if (attrs[i] instanceof PrintServiceAttribute) {
       
   223                     serviceSet.add(attrs[i]);
       
   224                 }
       
   225             }
       
   226         }
       
   227 
       
   228         /*
       
   229          * Special case: If client is asking for a particular printer
       
   230          * (by name) then we can save time by getting just that service
       
   231          * to check against the rest of the specified attributes.
       
   232          */
       
   233         PrintService[] services = null;
       
   234         if (serviceSet != null && serviceSet.get(PrinterName.class) != null) {
       
   235             PrinterName name = (PrinterName)serviceSet.get(PrinterName.class);
       
   236             PrintService service = getPrintServiceByName(name.getValue());
       
   237             if (service == null || !matchingService(service, serviceSet)) {
       
   238                 services = new PrintService[0];
       
   239             } else {
       
   240                 services = new PrintService[1];
       
   241                 services[0] = service;
       
   242             }
       
   243         } else {
       
   244             services = getPrintServices();
       
   245         }
       
   246 
       
   247         if (services.length == 0) {
       
   248             return services;
       
   249         } else {
       
   250             ArrayList<PrintService> matchingServices = new ArrayList<>();
       
   251             for (int i=0; i<services.length; i++) {
       
   252                 try {
       
   253                     if (services[i].
       
   254                         getUnsupportedAttributes(flavor, requestSet) == null) {
       
   255                         matchingServices.add(services[i]);
       
   256                     }
       
   257                 } catch (IllegalArgumentException e) {
       
   258                 }
       
   259             }
       
   260             services = new PrintService[matchingServices.size()];
       
   261             return matchingServices.toArray(services);
       
   262         }
       
   263     }
       
   264 
       
   265     /*
       
   266      * return empty array as don't support multi docs
       
   267      */
       
   268     public MultiDocPrintService[]
       
   269         getMultiDocPrintServices(DocFlavor[] flavors,
       
   270                                  AttributeSet attributes) {
       
   271         SecurityManager security = System.getSecurityManager();
       
   272         if (security != null) {
       
   273           security.checkPrintJobAccess();
       
   274         }
       
   275         return new MultiDocPrintService[0];
       
   276     }
       
   277 
       
   278 
       
   279     public synchronized PrintService getDefaultPrintService() {
       
   280         SecurityManager security = System.getSecurityManager();
       
   281         if (security != null) {
       
   282           security.checkPrintJobAccess();
       
   283         }
       
   284 
       
   285 
       
   286         // Windows does not have notification for a change in default
       
   287         // so we always get the latest.
       
   288         defaultPrinter = getDefaultPrinterName();
       
   289         if (defaultPrinter == null) {
       
   290             return null;
       
   291         }
       
   292 
       
   293         if ((defaultPrintService != null) &&
       
   294             defaultPrintService.getName().equals(defaultPrinter)) {
       
   295 
       
   296             return defaultPrintService;
       
   297         }
       
   298 
       
   299          // Not the same as default so proceed to get new PrintService.
       
   300 
       
   301         // clear defaultPrintService
       
   302         defaultPrintService = null;
       
   303 
       
   304         if (printServices != null) {
       
   305             for (int j=0; j<printServices.length; j++) {
       
   306                 if (defaultPrinter.equals(printServices[j].getName())) {
       
   307                     defaultPrintService = printServices[j];
       
   308                     break;
       
   309                 }
       
   310             }
       
   311         }
       
   312 
       
   313         if (defaultPrintService == null) {
       
   314             defaultPrintService = new Win32PrintService(defaultPrinter);
       
   315         }
       
   316         return defaultPrintService;
       
   317     }
       
   318 
       
   319     class PrinterChangeListener extends Thread {
       
   320         long chgObj;
       
   321         PrinterChangeListener() {
       
   322             chgObj = notifyFirstPrinterChange(null);
       
   323         }
       
   324 
       
   325         public void run() {
       
   326             if (chgObj != -1) {
       
   327                 while (true) {
       
   328                     // wait for configuration to change
       
   329                     if (notifyPrinterChange(chgObj) != 0) {
       
   330                         try {
       
   331                             refreshServices();
       
   332                         } catch (SecurityException se) {
       
   333                             break;
       
   334                         }
       
   335                     } else {
       
   336                         notifyClosePrinterChange(chgObj);
       
   337                         break;
       
   338                     }
       
   339                 }
       
   340             }
       
   341         }
       
   342     }
       
   343 
       
   344     private native String getDefaultPrinterName();
       
   345     private native String[] getAllPrinterNames();
       
   346     private native long notifyFirstPrinterChange(String printer);
       
   347     private native void notifyClosePrinterChange(long chgObj);
       
   348     private native int notifyPrinterChange(long chgObj);
       
   349 }