001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Igor A. Pyankov
019: * @version $Revision: 1.3 $
020: */package org.apache.harmony.x.print.cups;
021:
022: import java.io.IOException;
023: import java.net.URI;
024: import java.net.URISyntaxException;
025: import java.security.AccessController;
026: import java.security.PrivilegedAction;
027: import java.util.ArrayList;
028: import java.util.Vector;
029:
030: import javax.print.DocFlavor;
031: import javax.print.MultiDocPrintService;
032: import javax.print.PrintException;
033: import javax.print.PrintService;
034: import javax.print.PrintServiceLookup;
035: import javax.print.attribute.AttributeSet;
036:
037: import org.apache.harmony.x.print.DefaultPrintService;
038: import org.apache.harmony.x.print.ipp.IppAttribute;
039: import org.apache.harmony.x.print.ipp.IppAttributeGroup;
040: import org.apache.harmony.x.print.ipp.IppClient;
041: import org.apache.harmony.x.print.ipp.IppOperation;
042: import org.apache.harmony.x.print.ipp.IppPrinter;
043: import org.apache.harmony.x.print.ipp.IppRequest;
044: import org.apache.harmony.x.print.ipp.IppResponse;
045:
046: /*
047: * The class extends PrintServiceLookup and is intended for
048: * looking up CUPS/IPP printers
049: *
050: * 1. The class allways looks printers on http://localhost:631
051: * This URL is default URL for default installation of CUPS server
052: * 2. The class accepts two properties:
053: * print.cups.servers - a list of CUPS servers
054: * print.ipp.printers - a list of IPP printers
055: * (note, that CUPS printer is IPP printer too)
056: */
057: public class CUPSPrintServiceProvider extends PrintServiceLookup {
058: private static String cupsdefault = "http://localhost:631";
059: private static ArrayList services = new ArrayList();
060: /*
061: * 0 - no
062: * 1 - more
063: * 2 - more and more
064: * ...
065: */
066: private static int verbose = 0;
067:
068: static {
069: String verbose_property = (String) AccessController
070: .doPrivileged(new PrivilegedAction() {
071: public Object run() {
072: return System.getProperty("print.cups.verbose");
073: }
074: });
075: if (verbose_property != null) {
076: try {
077: Integer v = new Integer(verbose_property);
078: setVerbose(v.intValue());
079: } catch (NumberFormatException e) {
080: setVerbose(0);
081: }
082:
083: }
084: }
085:
086: public CUPSPrintServiceProvider() {
087: super ();
088: }
089:
090: /*
091: * The method returns array of URLs of CUPS servers
092: */
093: private static String[] getCUPSServersByProperty() {
094: ArrayList cupslist = new ArrayList();
095: cupslist.add(cupsdefault);
096:
097: String cupspath = (String) AccessController
098: .doPrivileged(new PrivilegedAction() {
099: public Object run() {
100: return System.getProperty("print.cups.servers");
101: }
102: });
103: String pathsep = ",";
104: if (cupspath != null && !cupspath.equals("")) {
105: String[] cupss = cupspath.split(pathsep);
106: for (int i = 0, ii = cupss.length; i < ii; i++) {
107: if (!cupss[i].equals("")) {
108: try {
109: URI cupsuri = new URI(cupss[i]);
110: cupslist.add(cupsuri.toString());
111: } catch (URISyntaxException e) {
112: if (verbose > 0) {
113: System.err.println("CUPS url: " + cupss[i]);
114: e.printStackTrace();
115: } else {
116: // IGNORE bad URI exception
117: }
118: }
119: }
120: }
121: }
122:
123: return (String[]) cupslist.toArray(new String[0]);
124: }
125:
126: /*
127: * The method returns array of URLs of IPP printers
128: */
129: private static String[] getIppPrintersByProperty() {
130: ArrayList ipplist = new ArrayList();
131:
132: String ipppath = (String) AccessController
133: .doPrivileged(new PrivilegedAction() {
134: public Object run() {
135: return System.getProperty("print.ipp.printers");
136: }
137: });
138: String pathsep = ","; //System.getProperty("path.separator");
139: if (ipppath != null && !ipppath.equals("")) {
140: String[] ipps = ipppath.split(pathsep);
141: for (int i = 0, ii = ipps.length; i < ii; i++) {
142: if (!ipps[i].equals("")) {
143: try {
144: URI cupsuri = new URI(ipps[i]);
145: ipplist.add(cupsuri.toString());
146: } catch (URISyntaxException e) {
147: if (verbose > 0) {
148: System.err.println("IPP url: " + ipps[i]);
149: e.printStackTrace();
150: } else {
151: // IGNORE bad URI exception
152: }
153: }
154: }
155: }
156: }
157:
158: return (String[]) ipplist.toArray(new String[0]);
159: }
160:
161: /*
162: * @see javax.print.PrintServiceLookup#getDefaultPrintService()
163: */
164: public PrintService getDefaultPrintService() {
165: synchronized (this ) {
166: String defaultService = findDefaultPrintService();
167:
168: if (defaultService != null) {
169: PrintService service = getServiceStored(defaultService,
170: services);
171: if (service != null) {
172: return service;
173: }
174:
175: CUPSClient client;
176: try {
177: client = new CUPSClient(defaultService);
178: service = new DefaultPrintService(defaultService,
179: client);
180: services.add(service);
181: return service;
182: } catch (PrintException e) {
183: // just ignore
184: e.printStackTrace();
185: }
186: }
187:
188: if (services.size() == 0) {
189: getPrintServices();
190: }
191: if (services.size() > 0) {
192: return (PrintService) services.get(0);
193: }
194:
195: }
196: return null;
197: }
198:
199: /*
200: * @see javax.print.PrintServiceLookup#getPrintServices()
201: */
202: public PrintService[] getPrintServices() {
203: synchronized (this ) {
204: String[] serviceNames = findPrintServices();
205: if (serviceNames == null || serviceNames.length == 0) {
206: services.clear();
207: return new PrintService[0];
208: }
209:
210: ArrayList newServices = new ArrayList();
211: for (int i = 0; i < serviceNames.length; i++) {
212: PrintService service = getServiceStored(
213: serviceNames[i], services);
214: if (service != null) {
215: newServices.add(service);
216: } else if (getServiceStored(serviceNames[i],
217: newServices) == null) {
218: try {
219: CUPSClient client = new CUPSClient(
220: serviceNames[i]);
221:
222: service = new DefaultPrintService(
223: serviceNames[i], client);
224: newServices.add(service);
225: } catch (PrintException e) {
226: // just ignore
227: e.printStackTrace();
228: }
229: }
230: }
231:
232: services.clear();
233: services = newServices;
234: return (services.size() == 0) ? new PrintService[0]
235: : (PrintService[]) services
236: .toArray(new PrintService[0]);
237: }
238: }
239:
240: /*
241: * find printers on particular CUPS server
242: */
243: private PrintService[] getCUPSPrintServices(String cups) {
244: synchronized (this ) {
245: // just update static field 'services'
246: findPrintServices();
247:
248: // next find services on server 'cups'
249: String[] serviceNames = (String[]) findCUPSPrintServices(
250: cups).toArray(new String[0]);
251: if (serviceNames == null || serviceNames.length == 0) {
252: return new PrintService[0];
253: }
254:
255: // return only those are stored in field 'services'
256: ArrayList newServices = new ArrayList();
257: for (int i = 0; i < serviceNames.length; i++) {
258: PrintService service = getServiceStored(
259: serviceNames[i], services);
260: if (service != null) {
261: newServices.add(service);
262: }
263: }
264:
265: return (newServices.size() == 0) ? new PrintService[0]
266: : (PrintService[]) services
267: .toArray(new PrintService[0]);
268: }
269: }
270:
271: /*
272: * find printers on localhost only
273: */
274: public PrintService[] getPrintServicesOnLocalHost() {
275: return getCUPSPrintServices(cupsdefault);
276: }
277:
278: /*
279: * find service which name is same as serviceName
280: */
281: private PrintService getServiceStored(String serviceName,
282: ArrayList servicesList) {
283: for (int i = 0; i < servicesList.size(); i++) {
284: PrintService service = (PrintService) servicesList.get(i);
285: if (service.getName().equals(serviceName)) {
286: return service;
287: }
288: }
289: return null;
290: }
291:
292: /*
293: * @see javax.print.PrintServiceLookup#getPrintServices(javax.print.DocFlavor
294: * , javax.print.attribute.AttributeSet)
295: */
296: public PrintService[] getPrintServices(DocFlavor flavor,
297: AttributeSet attributes) {
298: PrintService[] cupsservices = getPrintServices();
299: if (flavor == null && attributes == null) {
300: return cupsservices;
301: }
302:
303: ArrayList requestedServices = new ArrayList();
304: for (int i = 0; i < cupsservices.length; i++) {
305: try {
306: AttributeSet unsupportedSet = cupsservices[i]
307: .getUnsupportedAttributes(flavor, attributes);
308: if (unsupportedSet == null) {
309: requestedServices.add(cupsservices[i]);
310: }
311: } catch (IllegalArgumentException iae) {
312: // DocFlavor not supported by service, skiping.
313: }
314: }
315: return (requestedServices.size() == 0) ? new PrintService[0]
316: : (PrintService[]) requestedServices
317: .toArray(new PrintService[0]);
318: }
319:
320: /*
321: * @see javax.print.PrintServiceLookup#getMultiDocPrintServices(javax.print.DocFlavor[]
322: * , javax.print.attribute.AttributeSet)
323: */
324: public MultiDocPrintService[] getMultiDocPrintServices(
325: DocFlavor[] flavors, AttributeSet attributes) {
326: // No multidoc print services available, yet.
327: return new MultiDocPrintService[0];
328: }
329:
330: /*
331: * find all printers
332: */
333: private static String[] findPrintServices() {
334: ArrayList ippservices = new ArrayList();
335:
336: /*
337: * First, find on localhost and servers from print.cups.servers property
338: * and add them to full list
339: */
340: String[] cupses = CUPSPrintServiceProvider
341: .getCUPSServersByProperty();
342: for (int j = 0; j < cupses.length; j++) {
343: ippservices.addAll(findCUPSPrintServices(cupses[j]));
344: }
345:
346: /*
347: * Then, check URLs from print.ipp.printers property and
348: * if is valid ipp printer add them to full list
349: */
350: String[] ippp = CUPSPrintServiceProvider
351: .getIppPrintersByProperty();
352: for (int j = 0; j < ippp.length; j++) {
353: try {
354: URI ippuri = new URI(ippp[j]);
355: IppPrinter printer = new IppPrinter(ippuri);
356: IppResponse response;
357:
358: response = printer.requestPrinterAttributes(
359: "printer-uri-supported", null);
360:
361: Vector gg = response
362: .getGroupVector(IppAttributeGroup.TAG_GET_PRINTER_ATTRIBUTES);
363: if (gg != null) {
364: for (int i = 0, ii = gg.size(); i < ii; i++) {
365: IppAttributeGroup g = (IppAttributeGroup) gg
366: .get(i);
367: int ai = g
368: .findAttribute("printer-uri-supported");
369:
370: if (ai >= 0) {
371: IppAttribute a = (IppAttribute) g.get(ai);
372: Vector v = a.getValue();
373: if (v.size() > 0) {
374: ippservices.add(new String((byte[]) v
375: .get(0)));
376: }
377: }
378: }
379: }
380: } catch (Exception e) {
381: if (verbose > 0) {
382: System.err.println("IPP url: " + ippp[j]);
383: e.printStackTrace();
384: } else {
385: // IGNORE - connection refused due to no server, etc.
386: }
387: }
388: }
389:
390: // return array of printers
391: return (String[]) ippservices.toArray(new String[0]);
392: }
393:
394: /*
395: * find ipp printers on CUPS server 'cups'
396: */
397: public static ArrayList findCUPSPrintServices(String cups) {
398: ArrayList ippservices = new ArrayList();
399:
400: URI cupsuri = null;
401: IppClient c = null;
402: IppRequest request;
403: IppResponse response;
404: IppAttributeGroup agroup;
405: Vector va = new Vector();
406:
407: request = new IppRequest(1, 1,
408: IppOperation.TAG_CUPS_GET_PRINTERS, "utf-8", "en-us");
409: agroup = request
410: .getGroup(IppAttributeGroup.TAG_OPERATION_ATTRIBUTES);
411: va.add("printer-uri-supported".getBytes());
412: agroup.add(new IppAttribute(IppAttribute.TAG_KEYWORD,
413: "requested-attributes", va));
414:
415: try {
416: cupsuri = new URI(cups);
417: c = new IppClient(cupsuri);
418:
419: response = c.request(request.getBytes());
420:
421: Vector gg = response
422: .getGroupVector(IppAttributeGroup.TAG_GET_PRINTER_ATTRIBUTES);
423: if (gg != null) {
424: for (int i = 0, ii = gg.size(); i < ii; i++) {
425: IppAttributeGroup g = (IppAttributeGroup) gg.get(i);
426: int ai = g.findAttribute("printer-uri-supported");
427:
428: if (ai >= 0) {
429: IppAttribute a = (IppAttribute) g.get(ai);
430: Vector v = a.getValue();
431: if (v.size() > 0) {
432: ippservices.add(new String((byte[]) v
433: .get(0)));
434: }
435: }
436: }
437: }
438: } catch (Exception e) {
439: if (verbose > 0) {
440: System.err.println("CUPS url: " + cups);
441: System.err.println("CUPS uri: " + cupsuri);
442: System.err.println("Ipp client: " + c);
443: System.err.println(request.toString());
444: e.printStackTrace();
445: } else {
446: // IGNORE - connection refused due to no server, etc.
447: }
448: }
449:
450: return ippservices;
451: }
452:
453: /*
454: * find default printer
455: * At first, try to find default printer on CUPS servers and return first found
456: * If failed, return first found IPP printer
457: * If failed return null
458: */
459: private static String findDefaultPrintService() {
460: String serviceName = null;
461:
462: String[] cupses = CUPSPrintServiceProvider
463: .getCUPSServersByProperty();
464: for (int i = 0; i < cupses.length; i++) {
465: try {
466: URI cupsuri = new URI(cupses[i]);
467: IppClient c = new IppClient(cupsuri);
468: IppRequest request;
469: IppResponse response;
470: IppAttributeGroup agroup;
471: Vector va = new Vector();
472:
473: request = new IppRequest(1, 1,
474: IppOperation.TAG_CUPS_GET_DEFAULT, "utf-8",
475: "en-us");
476: agroup = request
477: .getGroup(IppAttributeGroup.TAG_OPERATION_ATTRIBUTES);
478: va.add("printer-uri-supported".getBytes());
479: agroup.add(new IppAttribute(IppAttribute.TAG_KEYWORD,
480: "requested-attributes", va));
481:
482: response = c.request(request.getBytes());
483:
484: IppAttributeGroup g = response
485: .getGroup(IppAttributeGroup.TAG_GET_PRINTER_ATTRIBUTES);
486: if (g != null) {
487: int ai = g.findAttribute("printer-uri-supported");
488:
489: if (ai >= 0) {
490: IppAttribute a = (IppAttribute) g.get(ai);
491: Vector v = a.getValue();
492: if (v.size() > 0) {
493: serviceName = new String((byte[]) v.get(0));
494: break;
495: }
496: }
497: }
498: } catch (URISyntaxException e) {
499: //e.printStackTrace();
500: } catch (IOException e) {
501: e.printStackTrace();
502: } catch (Exception e) {
503: //e.printStackTrace();
504: }
505: }
506: if (serviceName != null && !serviceName.equals("")) {
507: return serviceName;
508: }
509:
510: String[] ippp = CUPSPrintServiceProvider
511: .getIppPrintersByProperty();
512: for (int i = 0; i < ippp.length; i++) {
513: try {
514: URI ippuri = new URI(ippp[i]);
515: IppClient c = new IppClient(ippuri);
516: IppRequest request;
517: IppResponse response;
518: IppAttributeGroup agroup;
519: Vector va = new Vector();
520:
521: request = new IppRequest(1, 1,
522: IppOperation.GET_PRINTER_ATTRIBUTES, "utf-8",
523: "en-us");
524: agroup = request
525: .getGroup(IppAttributeGroup.TAG_OPERATION_ATTRIBUTES);
526: va.add("printer-uri-supported".getBytes());
527: agroup.add(new IppAttribute(IppAttribute.TAG_KEYWORD,
528: "requested-attributes", va));
529:
530: response = c.request(request.getBytes());
531:
532: IppAttributeGroup g = response
533: .getGroup(IppAttributeGroup.TAG_GET_PRINTER_ATTRIBUTES);
534: if (g != null) {
535: int ai = g.findAttribute("printer-uri-supported");
536:
537: if (ai >= 0) {
538: IppAttribute a = (IppAttribute) g.get(ai);
539: Vector v = a.getValue();
540: if (v.size() > 0) {
541: serviceName = new String((byte[]) v.get(0));
542: break;
543: }
544: }
545: }
546: } catch (URISyntaxException e) {
547: //e.printStackTrace();
548: } catch (IOException e) {
549: e.printStackTrace();
550: } catch (Exception e) {
551: //e.printStackTrace();
552: }
553: }
554:
555: return serviceName;
556: }
557:
558: public static int isVerbose() {
559: return verbose;
560: }
561:
562: public static void setVerbose(int newverbose) {
563: CUPSPrintServiceProvider.verbose = newverbose;
564: CUPSClient.setVerbose(newverbose);
565: }
566: }
|