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