1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73:
74: import ;
75: import ;
76: import ;
77: import ;
78: import ;
79: import ;
80: import ;
81: import ;
82: import ;
83: import ;
84: import ;
85: import ;
86:
87: import ;
88: import ;
89: import ;
90: import ;
91: import ;
92: import ;
93: import ;
94: import ;
95: import ;
96: import ;
97: import ;
98: import ;
99: import ;
100: import ;
101: import ;
102: import ;
103: import ;
104: import ;
105: import ;
106: import ;
107: import ;
108: import ;
109: import ;
110: import ;
111: import ;
112: import ;
113: import ;
114: import ;
115: import ;
116: import ;
117: import ;
118: import ;
119: import ;
120: import ;
121: import ;
122: import ;
123: import ;
124: import ;
125: import ;
126: import ;
127: import ;
128:
129:
130:
136: public class IppPrintService implements PrintService
137: {
138:
146: private Map printerAttr;
147:
148:
149: private HashSet printServiceAttributeListener;
150:
151:
152: private transient String user;
153:
154:
155: private transient String passwd;
156:
157:
158: private String name;
159:
160:
161: private List flavors;
162:
163:
164: private PrinterURI printerUri;
165:
166:
167: private ArrayList printerUris;
168:
169:
173: static final Logger logger = SystemLogger.SYSTEM;
174:
175:
178: public static final RequestingUserName REQUESTING_USER_NAME;
179:
180:
183: public static final JobName JOB_NAME;
184:
185: static
186: {
187: JOB_NAME = new JobName("Java Printing", null);
188: REQUESTING_USER_NAME = new RequestingUserName(
189: SystemProperties.getProperty("user.name", ""), null);
190: }
191:
192:
193:
194:
203: public IppPrintService(URI uri, String username, String password)
204: throws IppException
205: {
206: printerUri = new PrinterURI(uri);
207: user = username;
208: passwd = password;
209:
210: printServiceAttributeListener = new HashSet();
211:
212: printerAttr = getPrinterAttributes();
213: processResponse();
214: }
215:
216:
222: private Map getPrinterAttributes() throws IppException
223: {
224: IppResponse response = null;
225:
226: try
227: {
228: IppRequest request = new IppRequest(printerUri.getURI(), user, passwd);
229:
230: int operation = OperationsSupported.GET_PRINTER_ATTRIBUTES.getValue();
231: request.setOperationID((short) operation);
232: request.setOperationAttributeDefaults();
233: request.addOperationAttribute(printerUri);
234:
235: response = request.send();
236: }
237: catch (IOException e)
238: {
239: throw new IppException("IOException in IPP request/response.", e);
240: }
241:
242: return (Map) response.getPrinterAttributes().get(0);
243: }
244:
245:
252: private Set getPrinterAttributeSet(Class attributeClass)
253: {
254: return (Set) printerAttr.get(attributeClass);
255: }
256:
257:
267: private Attribute getPrinterDefaultAttribute(Class attributeClass)
268: {
269: Set set = (Set) printerAttr.get(attributeClass);
270: return ((DefaultValueAttribute) set.toArray()[0]).getAssociatedAttribute();
271: }
272:
273:
276: private void processResponse()
277: {
278:
279: PrinterName[] tmp = (PrinterName[]) getPrinterAttributeSet(
280: PrinterName.class).toArray(new PrinterName[1]);
281: name = tmp[0].getValue();
282:
283:
284:
285:
286:
287:
288: flavors = new ArrayList();
289: Set flavorAttributes = getPrinterAttributeSet(DocumentFormatSupported.class);
290: if (flavorAttributes != null)
291: {
292: for (Iterator it = flavorAttributes.iterator(); it.hasNext();)
293: {
294: String mimeType = ((DocumentFormatSupported) it.next()).getValue();
295:
296: if (mimeType.equals("text/plain"))
297: {
298: flavors.add(DocFlavor.CHAR_ARRAY.TEXT_PLAIN);
299: flavors.add(DocFlavor.READER.TEXT_PLAIN);
300: flavors.add(DocFlavor.STRING.TEXT_PLAIN);
301:
302:
303: mimeType = mimeType + "; charset=utf-8";
304: }
305: else if (mimeType.equals("text/html"))
306: {
307: flavors.add(DocFlavor.CHAR_ARRAY.TEXT_HTML);
308: flavors.add(DocFlavor.READER.TEXT_HTML);
309: flavors.add(DocFlavor.STRING.TEXT_HTML);
310:
311:
312: mimeType = mimeType + "; charset=utf-8";
313: }
314:
315:
316:
317:
318: boolean changed = false;
319: try
320: {
321: Class[] clazzes = new Class[] { DocFlavor.BYTE_ARRAY.class,
322: DocFlavor.INPUT_STREAM.class,
323: DocFlavor.URL.class };
324:
325: for (int j = 0; j < clazzes.length; j++)
326: {
327: Field[] fields = clazzes[j].getDeclaredFields();
328: for (int i = 0; i < fields.length; i++)
329: {
330: if (fields[i].getType().equals(clazzes[j]))
331: {
332: DocFlavor flavor = (DocFlavor) fields[i].get(null);
333: if (flavor.getMimeType().equals(mimeType))
334: changed = flavors.add(flavor);
335: }
336: }
337: }
338: if (!changed)
339: {
340:
341: flavors.add(new DocFlavor(mimeType, "[B"));
342: flavors.add(new DocFlavor(mimeType, "java.io.InputStream"));
343: flavors.add(new DocFlavor(mimeType, "java.net.URL"));
344: }
345: }
346: catch (SecurityException e)
347: {
348:
349: }
350: catch (IllegalArgumentException e)
351: {
352:
353: }
354: catch (IllegalAccessException e)
355: {
356:
357: }
358: }
359:
360: if (this.getClass()
361: .isAssignableFrom(gnu.javax.print.CupsPrintService.class))
362: {
363:
364:
365: flavors.add(DocFlavor.SERVICE_FORMATTED.PAGEABLE);
366: flavors.add(DocFlavor.SERVICE_FORMATTED.PRINTABLE);
367: }
368: }
369:
370:
371: Set uris = getPrinterAttributeSet(PrinterUriSupported.class);
372: printerUris = new ArrayList(uris.size());
373: Iterator it = uris.iterator();
374: while (it.hasNext())
375: {
376: PrinterUriSupported uri = (PrinterUriSupported) it.next();
377: printerUris.add( new PrinterURI(uri.getURI()));
378: }
379: }
380:
381:
386: public DocPrintJob createPrintJob()
387: {
388: return new DocPrintJobImpl(this, user, passwd);
389: }
390:
391:
392:
395: public PrintServiceAttribute getAttribute(Class category)
396: {
397: if (category == null)
398: throw new NullPointerException("category may not be null");
399:
400: if (! PrintServiceAttribute.class.isAssignableFrom(category))
401: throw new IllegalArgumentException(
402: "category must be of type PrintServiceAttribute");
403:
404: Set set = getPrinterAttributeSet(category);
405: if (set != null && set.size() > 0)
406: return (PrintServiceAttribute) set.toArray()[0];
407:
408: return null;
409: }
410:
411:
414: public PrintServiceAttributeSet getAttributes()
415: {
416: PrintServiceAttributeSet set = new HashPrintServiceAttributeSet();
417:
418: Iterator it = printerAttr.values().iterator();
419: while (it.hasNext())
420: {
421: Iterator it2 = ((Set) it.next()).iterator();
422: while (it2.hasNext())
423: {
424: Attribute attr = (Attribute) it2.next();
425: if (attr instanceof PrintServiceAttribute)
426: set.add(attr);
427: }
428: }
429:
430: return AttributeSetUtilities.unmodifiableView(set);
431: }
432:
433:
436: public Object getDefaultAttributeValue(Class category)
437: {
438:
439: if (category.equals(Fidelity.class))
440: return Fidelity.FIDELITY_FALSE;
441: if (category.equals(JobName.class))
442: return JOB_NAME;
443: if (category.equals(RequestingUserName.class))
444: return REQUESTING_USER_NAME;
445:
446:
447: if (category.equals(JobPriority.class)
448: && printerAttr.containsKey(JobPriorityDefault.class))
449: return getPrinterDefaultAttribute(JobPriorityDefault.class);
450: if (category.equals(JobHoldUntil.class)
451: && printerAttr.containsKey(JobHoldUntilDefault.class))
452: return getPrinterDefaultAttribute(JobHoldUntilDefault.class);
453: if (category.equals(JobSheets.class)
454: && printerAttr.containsKey(JobSheetsDefault.class))
455: return getPrinterDefaultAttribute(JobSheetsDefault .class);
456: if (category.equals(MultipleDocumentHandling.class)
457: && printerAttr.containsKey(MultipleDocumentHandlingDefault.class))
458: return getPrinterDefaultAttribute(MultipleDocumentHandlingDefault.class);
459: if (category.equals(Copies.class)
460: && printerAttr.containsKey(CopiesDefault.class))
461: return getPrinterDefaultAttribute(CopiesDefault.class);
462: if (category.equals(Finishings.class)
463: && printerAttr.containsKey(FinishingsDefault.class))
464: return getPrinterDefaultAttribute(FinishingsDefault.class);
465: if (category.equals(Sides.class)
466: && printerAttr.containsKey(SidesDefault.class))
467: return getPrinterDefaultAttribute(SidesDefault.class);
468: if (category.equals(NumberUp.class)
469: && printerAttr.containsKey(NumberUpDefault.class))
470: return getPrinterDefaultAttribute(NumberUpDefault.class);
471: if (category.equals(OrientationRequested.class)
472: && printerAttr.containsKey(OrientationRequestedDefault.class))
473: return getPrinterDefaultAttribute(OrientationRequestedDefault.class);
474: if (category.equals(Media.class)
475: && printerAttr.containsKey(MediaDefault.class))
476: return getPrinterDefaultAttribute(MediaDefault.class);
477: if (category.equals(PrinterResolution.class)
478: && printerAttr.containsKey(PrinterResolutionDefault.class))
479: return getPrinterDefaultAttribute(PrinterResolutionDefault.class);
480: if (category.equals(PrintQuality.class)
481: && printerAttr.containsKey(PrintQualityDefault.class))
482: return getPrinterDefaultAttribute(PrintQualityDefault.class);
483: if (category.equals(Compression.class)
484: && printerAttr.containsKey(CompressionSupported.class))
485: return Compression.NONE;
486: if (category.equals(PageRanges.class))
487: return new PageRanges(1, Integer.MAX_VALUE);
488:
489: return null;
490: }
491:
492:
496: public String getName()
497: {
498: return name;
499: }
500:
501:
505: public ServiceUIFactory getServiceUIFactory()
506: {
507:
508:
509:
510:
511:
512: return null;
513: }
514:
515:
518: public Class[] getSupportedAttributeCategories()
519: {
520: Set categories = new HashSet();
521:
522:
523: if (printerAttr.containsKey(JobPrioritySupported.class))
524: categories.add(JobPriority.class);
525: if (printerAttr.containsKey(JobHoldUntilSupported.class))
526: categories.add(JobHoldUntil.class);
527: if (printerAttr.containsKey(JobSheetsSupported.class))
528: categories.add(JobSheets.class);
529: if (printerAttr.containsKey(MultipleDocumentHandlingSupported.class))
530: categories.add(MultipleDocumentHandling.class);
531: if (printerAttr.containsKey(CopiesSupported.class))
532: categories.add(Copies.class);
533: if (printerAttr.containsKey(FinishingsSupported.class))
534: {
535:
536: Set set = getPrinterAttributeSet(FinishingsSupported.class);
537: if (! (set.size() == 1 && set.contains(FinishingsSupported.NONE)))
538: categories.add(Finishings.class);
539: }
540: if (printerAttr.containsKey(PageRangesSupported.class))
541: categories.add(PageRanges.class);
542: if (printerAttr.containsKey(SidesSupported.class))
543: categories.add(Sides.class);
544: if (printerAttr.containsKey(NumberUpSupported.class))
545: categories.add(NumberUp.class);
546: if (printerAttr.containsKey(OrientationRequestedSupported.class))
547: categories.add(OrientationRequested.class);
548: if (printerAttr.containsKey(MediaSupported.class))
549: categories.add(Media.class);
550: if (printerAttr.containsKey(PrinterResolutionSupported.class))
551: categories.add(PrinterResolution.class);
552: if (printerAttr.containsKey(PrintQualitySupported.class))
553: categories.add(PrintQuality.class);
554:
555:
556:
557:
558:
559: if (printerAttr.containsKey(CompressionSupported.class))
560: categories.add(Compression.class);
561: if (printerAttr.containsKey(JobImpressionsSupported.class))
562: categories.add(JobImpressions.class);
563: if (printerAttr.containsKey(JobKOctetsSupported.class))
564: categories.add(JobKOctets.class);
565: if (printerAttr.containsKey(JobMediaSheetsSupported.class))
566: categories.add(JobMediaSheets.class);
567:
568:
569: categories.add(Fidelity.class);
570: categories.add(JobName.class);
571: categories.add(RequestingUserName.class);
572:
573: return (Class[]) categories.toArray(new Class[categories.size()]);
574: }
575:
576:
585: public Object getSupportedAttributeValues(Class category, DocFlavor flavor,
586: AttributeSet attributes)
587: {
588:
589:
590:
591: if (category == null)
592: throw new NullPointerException("category may not be null");
593:
594: if (!Attribute.class.isAssignableFrom(category))
595: throw new IllegalArgumentException("category must be of type Attribute");
596:
597: if (flavor != null && !isDocFlavorSupported(flavor))
598: throw new IllegalArgumentException("flavor is not supported");
599:
600: if (!isAttributeCategorySupported(category))
601: return null;
602:
603:
604: if (category.equals(Fidelity.class))
605: return new Fidelity[] { Fidelity.FIDELITY_FALSE, Fidelity.FIDELITY_TRUE };
606: if (category.equals(JobName.class))
607: return JOB_NAME;
608: if (category.equals(RequestingUserName.class))
609: return REQUESTING_USER_NAME;
610:
611:
612: String categoryName = IppUtilities.getSupportedAttrName(category);
613:
614: IppResponse response = null;
615: try
616: {
617: IppRequest request = new IppRequest(printerUri.getURI(), user, passwd);
618: request.setOperationID(
619: (short) OperationsSupported.GET_PRINTER_ATTRIBUTES.getValue());
620: request.setOperationAttributeDefaults();
621: request.addOperationAttribute(new RequestedAttributes(categoryName));
622: request.addOperationAttribute(printerUri);
623:
624: if (flavor != null)
625: {
626: DocumentFormat f = DocumentFormat.createDocumentFormat(flavor);
627: request.addOperationAttribute(f);
628: }
629:
630: response = request.send();
631:
632: int status = response.getStatusCode();
633: if (! (status == IppStatusCode.SUCCESSFUL_OK
634: || status == IppStatusCode.SUCCESSFUL_OK_IGNORED_OR_SUBSTITUED_ATTRIBUTES
635: || status == IppStatusCode.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES) )
636: {
637: logger.log(Component.IPP, "Statuscode not OK - got:" + status);
638: }
639: }
640: catch (IOException e)
641: {
642:
643: logger.log(Component.IPP, "IOException", e);
644: }
645: catch (IppException e)
646: {
647:
648: logger.log(Component.IPP, "IPPException", e);
649: }
650:
651: return handleSupportedAttributeValuesResponse(response, category);
652: }
653:
654:
667: protected Object handleSupportedAttributeValuesResponse(IppResponse response,
668: Class category)
669: {
670: List printerAtts = response.getPrinterAttributes();
671:
672:
673: Map printerAttribute = (Map) printerAtts.get(0);
674: Class suppCategory = IppUtilities.getSupportedCategory(category);
675: Set attr = (Set) printerAttribute.get(suppCategory);
676:
677:
678:
679:
680:
681:
682:
683: if (suppCategory.equals(JobPrioritySupported.class))
684: return (JobPrioritySupported) attr.toArray(new JobPrioritySupported[1])[0];
685: if (suppCategory.equals(JobHoldUntilSupported.class))
686: return new JobHoldUntil(new Date());
687: if (suppCategory.equals(JobSheetsSupported.class))
688: return JobSheetsSupported.getAssociatedAttributeArray(attr);
689: if (suppCategory.equals(MultipleDocumentHandlingSupported.class))
690: return MultipleDocumentHandlingSupported.getAssociatedAttributeArray(attr);
691: if (suppCategory.equals(CopiesSupported.class))
692: return (CopiesSupported) attr.toArray(new CopiesSupported[1])[0];
693: if (suppCategory.equals(FinishingsSupported.class))
694: return FinishingsSupported.getAssociatedAttributeArray(attr);
695: if (suppCategory.equals(PageRangesSupported.class))
696: return new PageRanges[] { new PageRanges(1, Integer.MAX_VALUE) };
697: if (suppCategory.equals(OrientationRequestedSupported.class))
698: return OrientationRequestedSupported.getAssociatedAttributeArray(attr);
699: if (suppCategory.equals(MediaSupported.class))
700: return MediaSupported.getAssociatedAttributeArray(attr);
701: if (suppCategory.equals(PrinterResolutionSupported.class))
702: return PrinterResolutionSupported.getAssociatedAttributeArray(attr);
703: if (suppCategory.equals(PrintQualitySupported.class))
704: return PrintQualitySupported.getAssociatedAttributeArray(attr);
705: if (suppCategory.equals(CompressionSupported.class))
706: return CompressionSupported.getAssociatedAttributeArray(attr);
707:
708: if (suppCategory.equals(NumberUpSupported.class))
709: {
710: NumberUpSupported[] tmp = (NumberUpSupported[])
711: attr.toArray(new NumberUpSupported[attr.size()]);
712:
713: if (attr.size() == 1)
714: return tmp[0];
715:
716: int[][] members = new int[attr.size()][2];
717: for (int j = 0; j < attr.size(); j++)
718: {
719: int value = tmp[j].getMembers()[0][0];
720: members[j] = new int[] { value, value };
721: }
722:
723: NumberUpSupported supported = new NumberUpSupported(members);
724: return supported;
725: }
726:
727: return null;
728: }
729:
730:
733: public DocFlavor[] getSupportedDocFlavors()
734: {
735: return (DocFlavor[]) flavors.toArray(new DocFlavor[flavors.size()]);
736: }
737:
738:
745: public AttributeSet getUnsupportedAttributes(DocFlavor flavor,
746: AttributeSet attributes)
747: {
748: if (flavor != null && !isDocFlavorSupported(flavor))
749: throw new IllegalArgumentException("flavor is not supported");
750:
751: IppResponse response = null;
752: try
753: {
754: IppRequest request = new IppRequest(printerUri.getURI(), user, passwd);
755: short operationId = (short) OperationsSupported.VALIDATE_JOB.getValue();
756: request.setOperationID(operationId);
757: request.setOperationAttributeDefaults();
758: request.addOperationAttribute(printerUri);
759: request.addOperationAttribute(Fidelity.FIDELITY_TRUE);
760:
761: if (attributes != null && attributes.size() > 0)
762: {
763: request.addAndFilterJobOperationAttributes(attributes);
764: request.addAndFilterJobTemplateAttributes(attributes);
765: }
766:
767: if (flavor != null)
768: {
769: DocumentFormat f = DocumentFormat.createDocumentFormat(flavor);
770: request.addOperationAttribute(f);
771: }
772:
773: response = request.send();
774:
775: int status = response.getStatusCode();
776: if (! (status == IppStatusCode.SUCCESSFUL_OK
777: || status == IppStatusCode.SUCCESSFUL_OK_IGNORED_OR_SUBSTITUED_ATTRIBUTES
778: || status == IppStatusCode.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES) )
779: {
780: logger.log(Component.IPP, "Statuscode not OK - got:" + status);
781: }
782: }
783: catch (IOException e)
784: {
785:
786: logger.log(Component.IPP, "IOException", e);
787: }
788: catch (IppException e)
789: {
790:
791: logger.log(Component.IPP, "IPPException", e);
792: }
793:
794:
795: List unsupportedMaps = response.getUnsupportedAttributes();
796: if (unsupportedMaps.size() == 0)
797: return null;
798:
799: Map unsupportedAttr = (Map) unsupportedMaps.get(0);
800: if (unsupportedAttr.size() == 0)
801: return null;
802:
803:
804:
805: HashAttributeSet set = new HashAttributeSet();
806: Iterator it = unsupportedAttr.values().iterator();
807: while (it.hasNext())
808: {
809: Set unsupported = (Set) it.next();
810: Iterator it2 = unsupported.iterator();
811: while (it2.hasNext())
812: set.add((Attribute) it2.next());
813: }
814:
815: return set;
816: }
817:
818:
821: public boolean isAttributeCategorySupported(Class category)
822: {
823: if (category == null)
824: throw new NullPointerException("category may not be null");
825:
826: if (! Attribute.class.isAssignableFrom(category))
827: throw new IllegalArgumentException("category must be of type Attribute");
828:
829: return Arrays.asList(getSupportedAttributeCategories()).contains(category);
830: }
831:
832:
835: public boolean isAttributeValueSupported(Attribute attrval, DocFlavor flavor,
836: AttributeSet attributes)
837: {
838:
839: Object values = getSupportedAttributeValues(attrval.getCategory(),
840: flavor, attributes);
841:
842: if (values == null)
843: return false;
844:
845:
846: if (values.getClass().isArray())
847: return Arrays.asList((Object[]) values).contains(attrval);
848:
849:
850: if (values.getClass().equals(attrval.getCategory()))
851: return true;
852:
853:
854:
855: if (values.getClass().equals(CopiesSupported.class))
856: return ((CopiesSupported) values).contains((IntegerSyntax) attrval);
857:
858: if (values.getClass().equals(NumberUpSupported.class))
859: return ((NumberUpSupported) values).contains((IntegerSyntax) attrval);
860:
861: if (values.getClass().equals(JobPrioritySupported.class))
862: {
863: JobPriority priority = (JobPriority) attrval;
864: JobPrioritySupported maxSupported = (JobPrioritySupported) values;
865: if (priority.getValue() < maxSupported.getValue())
866: return true;
867: }
868:
869:
870:
871:
872:
873: return false;
874: }
875:
876:
877:
880: public boolean isDocFlavorSupported(DocFlavor flavor)
881: {
882: if (flavor == null)
883: throw new NullPointerException("DocFlavor may not be null.");
884:
885: return flavors.contains(flavor);
886: }
887:
888:
889:
892: public void addPrintServiceAttributeListener(
893: PrintServiceAttributeListener listener)
894: {
895: printServiceAttributeListener.add(listener);
896: }
897:
898:
901: public void removePrintServiceAttributeListener(
902: PrintServiceAttributeListener listener)
903: {
904: printServiceAttributeListener.remove(listener);
905: }
906:
907:
911: public String toString()
912: {
913: return "IppPrinter: " + getName();
914: }
915:
916:
921: public PrinterURI getPrinterURI()
922: {
923: return printerUri;
924: }
925: }