001: /*
002: * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.print;
027:
028: import java.io.BufferedReader;
029: import java.io.InputStream;
030: import java.io.InputStreamReader;
031: import java.io.IOException;
032: import java.util.ArrayList;
033: import java.security.AccessController;
034: import java.security.PrivilegedActionException;
035: import java.security.PrivilegedExceptionAction;
036: import javax.print.DocFlavor;
037: import javax.print.MultiDocPrintService;
038: import javax.print.PrintService;
039: import javax.print.PrintServiceLookup;
040: import javax.print.attribute.Attribute;
041: import javax.print.attribute.AttributeSet;
042: import javax.print.attribute.HashPrintRequestAttributeSet;
043: import javax.print.attribute.HashPrintServiceAttributeSet;
044: import javax.print.attribute.PrintRequestAttribute;
045: import javax.print.attribute.PrintRequestAttributeSet;
046: import javax.print.attribute.PrintServiceAttribute;
047: import javax.print.attribute.PrintServiceAttributeSet;
048: import javax.print.attribute.standard.PrinterName;
049:
050: public class Win32PrintServiceLookup extends PrintServiceLookup {
051:
052: private String defaultPrinter;
053: private PrintService defaultPrintService;
054: private String[] printers; /* excludes the default printer */
055: private PrintService[] printServices; /* includes the default printer */
056:
057: static {
058: java.security.AccessController
059: .doPrivileged(new sun.security.action.LoadLibraryAction(
060: "awt"));
061: }
062:
063: /* The singleton win32 print lookup service.
064: * Code that is aware of this field and wants to use it must first
065: * see if its null, and if so instantiate it by calling a method such as
066: * javax.print.PrintServiceLookup.defaultPrintService() so that the
067: * same instance is stored there.
068: */
069: private static Win32PrintServiceLookup win32PrintLUS;
070:
071: /* Think carefully before calling this. Preferably don't call it. */
072: public static Win32PrintServiceLookup getWin32PrintLUS() {
073: if (win32PrintLUS == null) {
074: /* This call is internally synchronized.
075: * When it returns an instance of this class will have
076: * been instantiated - else there's a JDK internal error.
077: */
078: PrintServiceLookup.lookupDefaultPrintService();
079: }
080: return win32PrintLUS;
081: }
082:
083: public Win32PrintServiceLookup() {
084:
085: if (win32PrintLUS == null) {
086: win32PrintLUS = this ;
087:
088: String osName = (String) AccessController
089: .doPrivileged(new sun.security.action.GetPropertyAction(
090: "os.name"));
091: // There's no capability for Win98 to refresh printers.
092: // See "OpenPrinter" for more info.
093: if (osName != null && osName.startsWith("Windows 98")) {
094: return;
095: }
096: // start the printer listener thread
097: PrinterChangeListener thr = new PrinterChangeListener();
098: thr.setDaemon(true);
099: thr.start();
100: } /* else condition ought to never happen! */
101: }
102:
103: /* Want the PrintService which is default print service to have
104: * equality of reference with the equivalent in list of print services
105: * This isn't required by the API and there's a risk doing this will
106: * lead people to assume its guaranteed.
107: */
108: public synchronized PrintService[] getPrintServices() {
109: SecurityManager security = System.getSecurityManager();
110: if (security != null) {
111: security.checkPrintJobAccess();
112: }
113: if (printServices == null) {
114: refreshServices();
115: }
116: return printServices;
117: }
118:
119: private synchronized void refreshServices() {
120: printers = getAllPrinterNames();
121: if (printers == null) {
122: // In Windows it is safe to assume no default if printers == null so we
123: // don't get the default.
124: printServices = new PrintService[0];
125: return;
126: }
127:
128: PrintService[] newServices = new PrintService[printers.length];
129: PrintService defService = getDefaultPrintService();
130: for (int p = 0; p < printers.length; p++) {
131: if (defService != null
132: && printers[p].equals(defService.getName())) {
133: newServices[p] = defService;
134: } else {
135: if (printServices == null) {
136: newServices[p] = new Win32PrintService(printers[p]);
137: } else {
138: int j;
139: for (j = 0; j < printServices.length; j++) {
140: if ((printServices[j] != null)
141: && (printers[p].equals(printServices[j]
142: .getName()))) {
143: newServices[p] = printServices[j];
144: printServices[j] = null;
145: break;
146: }
147: }
148: if (j == printServices.length) {
149: newServices[p] = new Win32PrintService(
150: printers[p]);
151: }
152: }
153: }
154: }
155:
156: // Look for deleted services and invalidate these
157: if (printServices != null) {
158: for (int j = 0; j < printServices.length; j++) {
159: if ((printServices[j] instanceof Win32PrintService)
160: && (!printServices[j]
161: .equals(defaultPrintService))) {
162: ((Win32PrintService) printServices[j])
163: .invalidateService();
164: }
165: }
166: }
167: printServices = newServices;
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: boolean matchingService(PrintService service,
187: PrintServiceAttributeSet serviceSet) {
188: if (serviceSet != null) {
189: Attribute[] attrs = serviceSet.toArray();
190: Attribute serviceAttr;
191: for (int i = 0; i < attrs.length; i++) {
192: serviceAttr = service
193: .getAttribute((Class<PrintServiceAttribute>) attrs[i]
194: .getCategory());
195: if (serviceAttr == null
196: || !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
236: && serviceSet.get(PrinterName.class) != null) {
237: PrinterName name = (PrinterName) serviceSet
238: .get(PrinterName.class);
239: PrintService service = getPrintServiceByName(name
240: .getValue());
241: if (service == null
242: || !matchingService(service, serviceSet)) {
243: services = new PrintService[0];
244: } else {
245: services = new PrintService[1];
246: services[0] = service;
247: }
248: } else {
249: services = getPrintServices();
250: }
251:
252: if (services.length == 0) {
253: return services;
254: } else {
255: ArrayList matchingServices = new ArrayList();
256: for (int i = 0; i < services.length; i++) {
257: try {
258: if (services[i].getUnsupportedAttributes(flavor,
259: requestSet) == null) {
260: matchingServices.add(services[i]);
261: }
262: } catch (IllegalArgumentException e) {
263: }
264: }
265: services = new PrintService[matchingServices.size()];
266: return (PrintService[]) matchingServices.toArray(services);
267: }
268: }
269:
270: /*
271: * return empty array as don't support multi docs
272: */
273: public MultiDocPrintService[] getMultiDocPrintServices(
274: DocFlavor[] flavors, AttributeSet attributes) {
275: SecurityManager security = System.getSecurityManager();
276: if (security != null) {
277: security.checkPrintJobAccess();
278: }
279: return new MultiDocPrintService[0];
280: }
281:
282: public synchronized PrintService getDefaultPrintService() {
283: SecurityManager security = System.getSecurityManager();
284: if (security != null) {
285: security.checkPrintJobAccess();
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 extends Thread {
322: long chgObj;
323:
324: PrinterChangeListener() {
325: chgObj = notifyFirstPrinterChange(null);
326: }
327:
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:
349: private native String[] getAllPrinterNames();
350:
351: private native long notifyFirstPrinterChange(String printer);
352:
353: private native void notifyClosePrinterChange(long chgObj);
354:
355: private native int notifyPrinterChange(long chgObj);
356: }
|