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 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 PrintServiceLookupProvider 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 PrintServiceLookupProvider win32PrintLUS; 74 75 /* Think carefully before calling this. Preferably don't call it. */ 76 public static PrintServiceLookupProvider 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 PrintServiceLookupProvider() { 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 Thread thr = new Thread(null, new PrinterChangeListener(), 101 "PrinterListener", 0, false); 102 thr.setDaemon(true); 103 thr.start(); 104 } /* else condition ought to never happen! */ 105 } 106 107 /* Want the PrintService which is default print service to have 108 * equality of reference with the equivalent in list of print services 109 * This isn't required by the API and there's a risk doing this will 110 * lead people to assume its guaranteed. 111 */ 112 public synchronized PrintService[] getPrintServices() { 113 SecurityManager security = System.getSecurityManager(); 114 if (security != null) { 115 security.checkPrintJobAccess(); 116 } 117 if (printServices == null) { 118 refreshServices(); 119 } 120 return printServices; 121 } 122 123 private synchronized void refreshServices() { 124 printers = getAllPrinterNames(); 125 if (printers == null) { 126 // In Windows it is safe to assume no default if printers == null so we 127 // don't get the default. 128 printServices = new PrintService[0]; 129 return; 130 } 131 132 PrintService[] newServices = new PrintService[printers.length]; 133 PrintService defService = getDefaultPrintService(); 134 for (int p = 0; p < printers.length; p++) { 135 if (defService != null && 136 printers[p].equals(defService.getName())) { 137 newServices[p] = defService; 138 } else { 139 if (printServices == null) { 140 newServices[p] = new Win32PrintService(printers[p]); 141 } else { 142 int j; 143 for (j = 0; j < printServices.length; j++) { 144 if ((printServices[j]!= null) && 145 (printers[p].equals(printServices[j].getName()))) { 146 newServices[p] = printServices[j]; 147 printServices[j] = null; 148 break; 149 } 150 } 151 if (j == printServices.length) { 152 newServices[p] = new Win32PrintService(printers[p]); 153 } 154 } 155 } 156 } 157 158 // Look for deleted services and invalidate these 159 if (printServices != null) { 160 for (int j=0; j < printServices.length; j++) { 161 if ((printServices[j] instanceof Win32PrintService) && 162 (!printServices[j].equals(defaultPrintService))) { 163 ((Win32PrintService)printServices[j]).invalidateService(); 164 } 165 } 166 } 167 printServices = newServices; 168 } 169 170 171 public synchronized PrintService getPrintServiceByName(String name) { 172 173 if (name == null || name.equals("")) { 174 return null; 175 } else { 176 /* getPrintServices() is now very fast. */ 177 PrintService[] printServices = getPrintServices(); 178 for (int i=0; i<printServices.length; i++) { 179 if (printServices[i].getName().equals(name)) { 180 return printServices[i]; 181 } 182 } 183 return null; 184 } 185 } 186 187 @SuppressWarnings("unchecked") // Cast to Class<PrintServiceAttribute> 188 boolean matchingService(PrintService service, 189 PrintServiceAttributeSet serviceSet) { 190 if (serviceSet != null) { 191 Attribute [] attrs = serviceSet.toArray(); 192 Attribute serviceAttr; 193 for (int i=0; i<attrs.length; i++) { 194 serviceAttr 195 = service.getAttribute((Class<PrintServiceAttribute>)attrs[i].getCategory()); 196 if (serviceAttr == null || !serviceAttr.equals(attrs[i])) { 197 return false; 198 } 199 } 200 } 201 return true; 202 } 203 204 public PrintService[] getPrintServices(DocFlavor flavor, 205 AttributeSet attributes) { 206 207 SecurityManager security = System.getSecurityManager(); 208 if (security != null) { 209 security.checkPrintJobAccess(); 210 } 211 PrintRequestAttributeSet requestSet = null; 212 PrintServiceAttributeSet serviceSet = null; 213 214 if (attributes != null && !attributes.isEmpty()) { 215 216 requestSet = new HashPrintRequestAttributeSet(); 217 serviceSet = new HashPrintServiceAttributeSet(); 218 219 Attribute[] attrs = attributes.toArray(); 220 for (int i=0; i<attrs.length; i++) { 221 if (attrs[i] instanceof PrintRequestAttribute) { 222 requestSet.add(attrs[i]); 223 } else if (attrs[i] instanceof PrintServiceAttribute) { 224 serviceSet.add(attrs[i]); 225 } 226 } 227 } 228 229 /* 230 * Special case: If client is asking for a particular printer 231 * (by name) then we can save time by getting just that service 232 * to check against the rest of the specified attributes. 233 */ 234 PrintService[] services = null; 235 if (serviceSet != null && serviceSet.get(PrinterName.class) != null) { 236 PrinterName name = (PrinterName)serviceSet.get(PrinterName.class); 237 PrintService service = getPrintServiceByName(name.getValue()); 238 if (service == null || !matchingService(service, serviceSet)) { 239 services = new PrintService[0]; 240 } else { 241 services = new PrintService[1]; 242 services[0] = service; 243 } 244 } else { 245 services = getPrintServices(); 246 } 247 248 if (services.length == 0) { 249 return services; 250 } else { 251 ArrayList<PrintService> matchingServices = new ArrayList<>(); 252 for (int i=0; i<services.length; i++) { 253 try { 254 if (services[i]. 255 getUnsupportedAttributes(flavor, requestSet) == null) { 256 matchingServices.add(services[i]); 257 } 258 } catch (IllegalArgumentException e) { 259 } 260 } 261 services = new PrintService[matchingServices.size()]; 262 return matchingServices.toArray(services); 263 } 264 } 265 266 /* 267 * return empty array as don't support multi docs 268 */ 269 public MultiDocPrintService[] 270 getMultiDocPrintServices(DocFlavor[] flavors, 271 AttributeSet attributes) { 272 SecurityManager security = System.getSecurityManager(); 273 if (security != null) { 274 security.checkPrintJobAccess(); 275 } 276 return new MultiDocPrintService[0]; 277 } 278 279 280 public synchronized PrintService getDefaultPrintService() { 281 SecurityManager security = System.getSecurityManager(); 282 if (security != null) { 283 security.checkPrintJobAccess(); 284 } 285 286 287 // Windows does not have notification for a change in default 288 // so we always get the latest. 289 defaultPrinter = getDefaultPrinterName(); 290 if (defaultPrinter == null) { 291 return null; 292 } 293 294 if ((defaultPrintService != null) && 295 defaultPrintService.getName().equals(defaultPrinter)) { 296 297 return defaultPrintService; 298 } 299 300 // Not the same as default so proceed to get new PrintService. 301 302 // clear defaultPrintService 303 defaultPrintService = null; 304 305 if (printServices != null) { 306 for (int j=0; j<printServices.length; j++) { 307 if (defaultPrinter.equals(printServices[j].getName())) { 308 defaultPrintService = printServices[j]; 309 break; 310 } 311 } 312 } 313 314 if (defaultPrintService == null) { 315 defaultPrintService = new Win32PrintService(defaultPrinter); 316 } 317 return defaultPrintService; 318 } 319 320 class PrinterChangeListener implements Runnable { 321 long chgObj; 322 PrinterChangeListener() { 323 chgObj = notifyFirstPrinterChange(null); 324 } 325 326 @Override 327 public void run() { 328 if (chgObj != -1) { 329 while (true) { 330 // wait for configuration to change 331 if (notifyPrinterChange(chgObj) != 0) { 332 try { 333 refreshServices(); 334 } catch (SecurityException se) { 335 break; 336 } 337 } else { 338 notifyClosePrinterChange(chgObj); 339 break; 340 } 341 } 342 } 343 } 344 } 345 346 private native String getDefaultPrinterName(); 347 private native String[] getAllPrinterNames(); 348 private native long notifyFirstPrinterChange(String printer); 349 private native void notifyClosePrinterChange(long chgObj); 350 private native int notifyPrinterChange(long chgObj); 351 }