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() {
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 }
|
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 local printer listener thread
100 Thread thr = new Thread(null, new PrinterChangeListener(),
101 "PrinterListener", 0, false);
102 thr.setDaemon(true);
103 thr.start();
104
105 // start the remote printer listener thread
106 Thread remThr = new Thread(null, new RemotePrinterChangeListener(),
107 "RemotePrinterListener", 0, false);
108 remThr.setDaemon(true);
109 remThr.start();
110 } /* else condition ought to never happen! */
111 }
112
113 /* Want the PrintService which is default print service to have
114 * equality of reference with the equivalent in list of print services
115 * This isn't required by the API and there's a risk doing this will
116 * lead people to assume its guaranteed.
117 */
118 public synchronized PrintService[] getPrintServices() {
119 SecurityManager security = System.getSecurityManager();
120 if (security != null) {
121 security.checkPrintJobAccess();
122 }
123 if (printServices == null) {
124 refreshServices();
125 }
126 return printServices;
127 }
128
129 private synchronized void refreshServices() {
305
306 // Not the same as default so proceed to get new PrintService.
307
308 // clear defaultPrintService
309 defaultPrintService = null;
310
311 if (printServices != null) {
312 for (int j=0; j<printServices.length; j++) {
313 if (defaultPrinter.equals(printServices[j].getName())) {
314 defaultPrintService = printServices[j];
315 break;
316 }
317 }
318 }
319
320 if (defaultPrintService == null) {
321 defaultPrintService = new Win32PrintService(defaultPrinter);
322 }
323 return defaultPrintService;
324 }
325 class PrinterChangeListener implements Runnable {
326 long chgObj;
327 PrinterChangeListener() {
328 chgObj = notifyFirstPrinterChange(null);
329 }
330
331 @Override
332 public void run() {
333 if (chgObj != -1) {
334 while (true) {
335 // wait for configuration to change
336 if (notifyPrinterChange(chgObj) != 0) {
337 try {
338 refreshServices();
339 } catch (SecurityException se) {
340 break;
341 }
342 } else {
343 notifyClosePrinterChange(chgObj);
344 break;
345 }
346 }
347 }
348 }
349 }
350
351 /* Windows provides *PrinterChangeNotification* functions that provides
352 information about printer status changes of the local printers but not
353 network printers.
354 Alternatively, Windows provides a way thro' which one can get the
355 network printer status changes by using WMI, RegistryKeyChange combination,
356 which is a slightly complex mechanism.
357 The Windows WMI offers an async and sync method to read thro' registry
358 via the WQL query. The async method is considered dangerous as it leaves
359 open a channel until we close it. But the async method has the advantage of
360 being notified of a change in registry by calling callback without polling for it.
361 The sync method uses the polling mechanism to notify.
362 RegistryValueChange cannot be used in combination with WMI to get registry
363 value change notification because of an error that may be generated because the
364 scope of the query would be too big to handle(at times).
365 Hence an alternative mechanism is choosen via the EnumPrinters by polling for the
366 count of printer status changes(add\remove) and based on it update the printers
367 list.
368 */
369 class RemotePrinterChangeListener implements Runnable {
370 private static final long DELAY = 1000 * 60 * 4; // 4 min pooling
371 private String[] prevRemotePrinters;
372
373 RemotePrinterChangeListener() {
374 prevRemotePrinters = GetRemotePrintersNames();
375 }
376
377 boolean doCompare(String[] str1, String[] str2) {
378 if(str1.length != str2.length) {
379 return true;
380 } else {
381 for(int i = 0;i < str1.length;i++) {
382 for(int j = 0;j < str2.length;j++) {
383 if(!str1[i].equals(str2[j])) {
384 return true;
385 }
386 }
387 }
388 }
389
390 return false;
391 }
392
393 @Override
394 public void run() {
395 while(true) {
396 String[] currentRemotePrinters = GetRemotePrintersNames();
397 if(doCompare(prevRemotePrinters, currentRemotePrinters)) {
398
399 // updated the printers data
400 // printers list now contains both local and network printer data
401 refreshServices();
402
403 // store the current data for next comparison
404 prevRemotePrinters = currentRemotePrinters;
405 }
406
407 try {
408 Thread.sleep(DELAY);
409 } catch (InterruptedException e) {
410 break;
411 }
412 }
413 }
414 }
415
416 private native String getDefaultPrinterName();
417 private native String[] getAllPrinterNames();
418 private native long notifyFirstPrinterChange(String printer);
419 private native void notifyClosePrinterChange(long chgObj);
420 private native int notifyPrinterChange(long chgObj);
421 private native String[] GetRemotePrintersNames();
422 }
|