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