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<Class<? extends Attribute>, Set<Attribute>> printerAttr;
147:
148:
149: private HashSet<PrintServiceAttributeListener> 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<DocFlavor> flavors;
162:
163:
164: private PrinterURI printerUri;
165:
166:
167: private ArrayList<PrinterURI> 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 =
211: new HashSet<PrintServiceAttributeListener>();
212:
213: printerAttr = getPrinterAttributes();
214: processResponse();
215: }
216:
217:
223: private Map<Class<? extends Attribute>, Set<Attribute>> getPrinterAttributes()
224: throws IppException
225: {
226: IppResponse response = null;
227:
228: try
229: {
230: IppRequest request = new IppRequest(printerUri.getURI(), user, passwd);
231:
232: int operation = OperationsSupported.GET_PRINTER_ATTRIBUTES.getValue();
233: request.setOperationID((short) operation);
234: request.setOperationAttributeDefaults();
235: request.addOperationAttribute(printerUri);
236:
237: response = request.send();
238: }
239: catch (IOException e)
240: {
241: throw new IppException("IOException in IPP request/response.", e);
242: }
243:
244: return response.getPrinterAttributes().get(0);
245: }
246:
247:
254: private <T extends Attribute> Set<T> getPrinterAttributeSet(Class<T> attributeClass)
255: {
256: Set<Attribute> set = printerAttr.get(attributeClass);
257: Set<T> attSet = new HashSet<T>();
258: for (Attribute att : set)
259: attSet.add(attributeClass.cast(att));
260: return attSet;
261: }
262:
263:
273: private Attribute getPrinterDefaultAttribute(Class<? extends Attribute> attributeClass)
274: {
275: Set<Attribute> set = printerAttr.get(attributeClass);
276: return ((DefaultValueAttribute) set.toArray()[0]).getAssociatedAttribute();
277: }
278:
279:
282: private void processResponse()
283: {
284:
285: PrinterName[] tmp = getPrinterAttributeSet(PrinterName.class).toArray(new PrinterName[1]);
286: name = tmp[0].getValue();
287:
288:
289:
290:
291:
292:
293: flavors = new ArrayList<DocFlavor>();
294: Set<DocumentFormatSupported> flavorAttributes = getPrinterAttributeSet(DocumentFormatSupported.class);
295: if (flavorAttributes != null)
296: {
297: for (DocumentFormatSupported dfs : flavorAttributes)
298: {
299: String mimeType = dfs.getValue();
300:
301: if (mimeType.equals("text/plain"))
302: {
303: flavors.add(DocFlavor.CHAR_ARRAY.TEXT_PLAIN);
304: flavors.add(DocFlavor.READER.TEXT_PLAIN);
305: flavors.add(DocFlavor.STRING.TEXT_PLAIN);
306:
307:
308: mimeType = mimeType + "; charset=utf-8";
309: }
310: else if (mimeType.equals("text/html"))
311: {
312: flavors.add(DocFlavor.CHAR_ARRAY.TEXT_HTML);
313: flavors.add(DocFlavor.READER.TEXT_HTML);
314: flavors.add(DocFlavor.STRING.TEXT_HTML);
315:
316:
317: mimeType = mimeType + "; charset=utf-8";
318: }
319:
320:
321:
322:
323: boolean changed = false;
324: try
325: {
326: Class<?>[] clazzes = new Class<?>[] { DocFlavor.BYTE_ARRAY.class,
327: DocFlavor.INPUT_STREAM.class,
328: DocFlavor.URL.class
329: };
330:
331: for (int j = 0; j < clazzes.length; j++)
332: {
333: Field[] fields = clazzes[j].getDeclaredFields();
334: for (int i = 0; i < fields.length; i++)
335: {
336: if (fields[i].getType().equals(clazzes[j]))
337: {
338: DocFlavor flavor = (DocFlavor) fields[i].get(null);
339: if (flavor.getMimeType().equals(mimeType))
340: changed = flavors.add(flavor);
341: }
342: }
343: }
344: if (!changed)
345: {
346:
347: flavors.add(new DocFlavor(mimeType, "[B"));
348: flavors.add(new DocFlavor(mimeType, "java.io.InputStream"));
349: flavors.add(new DocFlavor(mimeType, "java.net.URL"));
350: }
351: }
352: catch (SecurityException e)
353: {
354:
355: }
356: catch (IllegalArgumentException e)
357: {
358:
359: }
360: catch (IllegalAccessException e)
361: {
362:
363: }
364: }
365:
366: if (this.getClass()
367: .isAssignableFrom(gnu.javax.print.CupsPrintService.class))
368: {
369:
370:
371: flavors.add(DocFlavor.SERVICE_FORMATTED.PAGEABLE);
372: flavors.add(DocFlavor.SERVICE_FORMATTED.PRINTABLE);
373: }
374: }
375:
376:
377: Set<PrinterUriSupported> uris = getPrinterAttributeSet(PrinterUriSupported.class);
378: printerUris = new ArrayList<PrinterURI>(uris.size());
379: for (PrinterUriSupported uri : uris)
380: {
381: printerUris.add( new PrinterURI(uri.getURI()));
382: }
383: }
384:
385:
390: public DocPrintJob createPrintJob()
391: {
392: return new DocPrintJobImpl(this, user, passwd);
393: }
394:
395:
396:
399: public <T extends PrintServiceAttribute> T getAttribute(Class<T> category)
400: {
401: if (category == null)
402: throw new NullPointerException("category may not be null");
403:
404: if (! PrintServiceAttribute.class.isAssignableFrom(category))
405: throw new IllegalArgumentException(
406: "category must be of type PrintServiceAttribute");
407:
408: Set<T> set = getPrinterAttributeSet(category);
409: if (set != null && set.size() > 0)
410: return set.iterator().next();
411:
412: return null;
413: }
414:
415:
418: public PrintServiceAttributeSet getAttributes()
419: {
420: PrintServiceAttributeSet set = new HashPrintServiceAttributeSet();
421:
422: for (Set<Attribute> attrSet : printerAttr.values())
423: {
424: for (Attribute attr : attrSet)
425: {
426: if (attr instanceof PrintServiceAttribute)
427: set.add(attr);
428: }
429: }
430:
431: return AttributeSetUtilities.unmodifiableView(set);
432: }
433:
434:
437: public Object getDefaultAttributeValue(Class<? extends Attribute> category)
438: {
439:
440: if (category.equals(Fidelity.class))
441: return Fidelity.FIDELITY_FALSE;
442: if (category.equals(JobName.class))
443: return JOB_NAME;
444: if (category.equals(RequestingUserName.class))
445: return REQUESTING_USER_NAME;
446:
447:
448: if (category.equals(JobPriority.class)
449: && printerAttr.containsKey(JobPriorityDefault.class))
450: return getPrinterDefaultAttribute(JobPriorityDefault.class);
451: if (category.equals(JobHoldUntil.class)
452: && printerAttr.containsKey(JobHoldUntilDefault.class))
453: return getPrinterDefaultAttribute(JobHoldUntilDefault.class);
454: if (category.equals(JobSheets.class)
455: && printerAttr.containsKey(JobSheetsDefault.class))
456: return getPrinterDefaultAttribute(JobSheetsDefault .class);
457: if (category.equals(MultipleDocumentHandling.class)
458: && printerAttr.containsKey(MultipleDocumentHandlingDefault.class))
459: return getPrinterDefaultAttribute(MultipleDocumentHandlingDefault.class);
460: if (category.equals(Copies.class)
461: && printerAttr.containsKey(CopiesDefault.class))
462: return getPrinterDefaultAttribute(CopiesDefault.class);
463: if (category.equals(Finishings.class)
464: && printerAttr.containsKey(FinishingsDefault.class))
465: return getPrinterDefaultAttribute(FinishingsDefault.class);
466: if (category.equals(Sides.class)
467: && printerAttr.containsKey(SidesDefault.class))
468: return getPrinterDefaultAttribute(SidesDefault.class);
469: if (category.equals(NumberUp.class)
470: && printerAttr.containsKey(NumberUpDefault.class))
471: return getPrinterDefaultAttribute(NumberUpDefault.class);
472: if (category.equals(OrientationRequested.class)
473: && printerAttr.containsKey(OrientationRequestedDefault.class))
474: return getPrinterDefaultAttribute(OrientationRequestedDefault.class);
475: if (category.equals(Media.class)
476: && printerAttr.containsKey(MediaDefault.class))
477: return getPrinterDefaultAttribute(MediaDefault.class);
478: if (category.equals(PrinterResolution.class)
479: && printerAttr.containsKey(PrinterResolutionDefault.class))
480: return getPrinterDefaultAttribute(PrinterResolutionDefault.class);
481: if (category.equals(PrintQuality.class)
482: && printerAttr.containsKey(PrintQualityDefault.class))
483: return getPrinterDefaultAttribute(PrintQualityDefault.class);
484: if (category.equals(Compression.class)
485: && printerAttr.containsKey(CompressionSupported.class))
486: return Compression.NONE;
487: if (category.equals(PageRanges.class))
488: return new PageRanges(1, Integer.MAX_VALUE);
489:
490: return null;
491: }
492:
493:
497: public String getName()
498: {
499: return name;
500: }
501:
502:
506: public ServiceUIFactory getServiceUIFactory()
507: {
508:
509:
510:
511:
512:
513: return null;
514: }
515:
516:
519: public Class<?>[] getSupportedAttributeCategories()
520: {
521: Set<Class<? extends Attribute>> categories =
522: new HashSet<Class<? extends Attribute>>();
523:
524:
525: if (printerAttr.containsKey(JobPrioritySupported.class))
526: categories.add(JobPriority.class);
527: if (printerAttr.containsKey(JobHoldUntilSupported.class))
528: categories.add(JobHoldUntil.class);
529: if (printerAttr.containsKey(JobSheetsSupported.class))
530: categories.add(JobSheets.class);
531: if (printerAttr.containsKey(MultipleDocumentHandlingSupported.class))
532: categories.add(MultipleDocumentHandling.class);
533: if (printerAttr.containsKey(CopiesSupported.class))
534: categories.add(Copies.class);
535: if (printerAttr.containsKey(FinishingsSupported.class))
536: {
537:
538: Set<FinishingsSupported> set = getPrinterAttributeSet(FinishingsSupported.class);
539: if (! (set.size() == 1 && set.contains(FinishingsSupported.NONE)))
540: categories.add(Finishings.class);
541: }
542: if (printerAttr.containsKey(PageRangesSupported.class))
543: categories.add(PageRanges.class);
544: if (printerAttr.containsKey(SidesSupported.class))
545: categories.add(Sides.class);
546: if (printerAttr.containsKey(NumberUpSupported.class))
547: categories.add(NumberUp.class);
548: if (printerAttr.containsKey(OrientationRequestedSupported.class))
549: categories.add(OrientationRequested.class);
550: if (printerAttr.containsKey(MediaSupported.class))
551: categories.add(Media.class);
552: if (printerAttr.containsKey(PrinterResolutionSupported.class))
553: categories.add(PrinterResolution.class);
554: if (printerAttr.containsKey(PrintQualitySupported.class))
555: categories.add(PrintQuality.class);
556:
557:
558:
559:
560:
561: if (printerAttr.containsKey(CompressionSupported.class))
562: categories.add(Compression.class);
563: if (printerAttr.containsKey(JobImpressionsSupported.class))
564: categories.add(JobImpressions.class);
565: if (printerAttr.containsKey(JobKOctetsSupported.class))
566: categories.add(JobKOctets.class);
567: if (printerAttr.containsKey(JobMediaSheetsSupported.class))
568: categories.add(JobMediaSheets.class);
569:
570:
571: categories.add(Fidelity.class);
572: categories.add(JobName.class);
573: categories.add(RequestingUserName.class);
574:
575: return categories.toArray(new Class[categories.size()]);
576: }
577:
578:
587: public Object getSupportedAttributeValues(Class<? extends Attribute> category,
588: DocFlavor flavor, AttributeSet attributes)
589: {
590:
591:
592:
593: if (category == null)
594: throw new NullPointerException("category may not be null");
595:
596: if (!Attribute.class.isAssignableFrom(category))
597: throw new IllegalArgumentException("category must be of type Attribute");
598:
599: if (flavor != null && !isDocFlavorSupported(flavor))
600: throw new IllegalArgumentException("flavor is not supported");
601:
602: if (!isAttributeCategorySupported(category))
603: return null;
604:
605:
606: if (category.equals(Fidelity.class))
607: return new Fidelity[] { Fidelity.FIDELITY_FALSE, Fidelity.FIDELITY_TRUE };
608: if (category.equals(JobName.class))
609: return JOB_NAME;
610: if (category.equals(RequestingUserName.class))
611: return REQUESTING_USER_NAME;
612:
613:
614: String categoryName = IppUtilities.getSupportedAttrName(category);
615:
616: IppResponse response = null;
617: try
618: {
619: IppRequest request = new IppRequest(printerUri.getURI(), user, passwd);
620: request.setOperationID(
621: (short) OperationsSupported.GET_PRINTER_ATTRIBUTES.getValue());
622: request.setOperationAttributeDefaults();
623: request.addOperationAttribute(new RequestedAttributes(categoryName));
624: request.addOperationAttribute(printerUri);
625:
626: if (flavor != null)
627: {
628: DocumentFormat f = DocumentFormat.createDocumentFormat(flavor);
629: request.addOperationAttribute(f);
630: }
631:
632: response = request.send();
633:
634: int status = response.getStatusCode();
635: if (! (status == IppStatusCode.SUCCESSFUL_OK
636: || status == IppStatusCode.SUCCESSFUL_OK_IGNORED_OR_SUBSTITUED_ATTRIBUTES
637: || status == IppStatusCode.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES) )
638: {
639: logger.log(Component.IPP, "Statuscode not OK - got:" + status);
640: }
641: }
642: catch (IOException e)
643: {
644:
645: logger.log(Component.IPP, "IOException", e);
646: }
647: catch (IppException e)
648: {
649:
650: logger.log(Component.IPP, "IPPException", e);
651: }
652:
653: return handleSupportedAttributeValuesResponse(response, category);
654: }
655:
656:
669: protected Object handleSupportedAttributeValuesResponse(IppResponse response,
670: Class<? extends Attribute> category)
671: {
672: List<Map<Class<? extends Attribute>, Set<Attribute>>> printerAtts =
673: response.getPrinterAttributes();
674:
675:
676: Map<Class<? extends Attribute>, Set<Attribute>> printerAttribute = printerAtts.get(0);
677: Class<? extends Attribute> suppCategory = IppUtilities.getSupportedCategory(category);
678: Set<Attribute> attr = printerAttribute.get(suppCategory);
679:
680:
681:
682:
683:
684:
685:
686: if (suppCategory.equals(JobPrioritySupported.class))
687: return (JobPrioritySupported) attr.iterator().next();
688: if (suppCategory.equals(JobHoldUntilSupported.class))
689: return new JobHoldUntil(new Date());
690: if (suppCategory.equals(JobSheetsSupported.class))
691: return JobSheetsSupported.getAssociatedAttributeArray(attr);
692: if (suppCategory.equals(MultipleDocumentHandlingSupported.class))
693: return MultipleDocumentHandlingSupported.getAssociatedAttributeArray(attr);
694: if (suppCategory.equals(CopiesSupported.class))
695: return (CopiesSupported) attr.iterator().next();
696: if (suppCategory.equals(FinishingsSupported.class))
697: return FinishingsSupported.getAssociatedAttributeArray(attr);
698: if (suppCategory.equals(PageRangesSupported.class))
699: return new PageRanges[] { new PageRanges(1, Integer.MAX_VALUE) };
700: if (suppCategory.equals(OrientationRequestedSupported.class))
701: return OrientationRequestedSupported.getAssociatedAttributeArray(attr);
702: if (suppCategory.equals(MediaSupported.class))
703: return MediaSupported.getAssociatedAttributeArray(attr);
704: if (suppCategory.equals(PrinterResolutionSupported.class))
705: return PrinterResolutionSupported.getAssociatedAttributeArray(attr);
706: if (suppCategory.equals(PrintQualitySupported.class))
707: return PrintQualitySupported.getAssociatedAttributeArray(attr);
708: if (suppCategory.equals(CompressionSupported.class))
709: return CompressionSupported.getAssociatedAttributeArray(attr);
710:
711: if (suppCategory.equals(NumberUpSupported.class))
712: {
713: if (attr.size() == 1)
714: return attr.iterator().next();
715:
716: int[][] members = new int[attr.size()][2];
717: Iterator<Attribute> it = attr.iterator();
718: for (int j = 0; j < attr.size(); j++)
719: {
720: int value = ((NumberUpSupported) it.next()).getMembers()[0][0];
721: members[j] = new int[] { value, value };
722: }
723:
724: NumberUpSupported supported = new NumberUpSupported(members);
725: return supported;
726: }
727:
728: return null;
729: }
730:
731:
734: public DocFlavor[] getSupportedDocFlavors()
735: {
736: return flavors.toArray(new DocFlavor[flavors.size()]);
737: }
738:
739:
746: public AttributeSet getUnsupportedAttributes(DocFlavor flavor,
747: AttributeSet attributes)
748: {
749: if (flavor != null && !isDocFlavorSupported(flavor))
750: throw new IllegalArgumentException("flavor is not supported");
751:
752: IppResponse response = null;
753: try
754: {
755: IppRequest request = new IppRequest(printerUri.getURI(), user, passwd);
756: short operationId = (short) OperationsSupported.VALIDATE_JOB.getValue();
757: request.setOperationID(operationId);
758: request.setOperationAttributeDefaults();
759: request.addOperationAttribute(printerUri);
760: request.addOperationAttribute(Fidelity.FIDELITY_TRUE);
761:
762: if (attributes != null && attributes.size() > 0)
763: {
764: request.addAndFilterJobOperationAttributes(attributes);
765: request.addAndFilterJobTemplateAttributes(attributes);
766: }
767:
768: if (flavor != null)
769: {
770: DocumentFormat f = DocumentFormat.createDocumentFormat(flavor);
771: request.addOperationAttribute(f);
772: }
773:
774: response = request.send();
775:
776: int status = response.getStatusCode();
777: if (! (status == IppStatusCode.SUCCESSFUL_OK
778: || status == IppStatusCode.SUCCESSFUL_OK_IGNORED_OR_SUBSTITUED_ATTRIBUTES
779: || status == IppStatusCode.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES) )
780: {
781: logger.log(Component.IPP, "Statuscode not OK - got:" + status);
782: }
783: }
784: catch (IOException e)
785: {
786:
787: logger.log(Component.IPP, "IOException", e);
788: }
789: catch (IppException e)
790: {
791:
792: logger.log(Component.IPP, "IPPException", e);
793: }
794:
795:
796: List<Map<Class<? extends Attribute>, Set<Attribute>>> unsupportedMaps =
797: response.getUnsupportedAttributes();
798: if (unsupportedMaps.size() == 0)
799: return null;
800:
801: Map<Class<? extends Attribute>, Set<Attribute>> unsupportedAttr = unsupportedMaps.get(0);
802: if (unsupportedAttr.size() == 0)
803: return null;
804:
805:
806:
807: HashAttributeSet set = new HashAttributeSet();
808: for (Set<Attribute> unsupported : unsupportedAttr.values())
809: {
810: for (Attribute att : unsupported)
811: set.add(att);
812: }
813:
814: return set;
815: }
816:
817:
820: public boolean isAttributeCategorySupported(Class<? extends Attribute> category)
821: {
822: if (category == null)
823: throw new NullPointerException("category may not be null");
824:
825: if (! Attribute.class.isAssignableFrom(category))
826: throw new IllegalArgumentException("category must be of type Attribute");
827:
828: return Arrays.asList(getSupportedAttributeCategories()).contains(category);
829: }
830:
831:
834: public boolean isAttributeValueSupported(Attribute attrval, DocFlavor flavor,
835: AttributeSet attributes)
836: {
837:
838: Object values = getSupportedAttributeValues(attrval.getCategory(),
839: flavor, attributes);
840:
841: if (values == null)
842: return false;
843:
844:
845: if (values.getClass().isArray())
846: return Arrays.asList((Object[]) values).contains(attrval);
847:
848:
849: if (values.getClass().equals(attrval.getCategory()))
850: return true;
851:
852:
853:
854: if (values.getClass().equals(CopiesSupported.class))
855: return ((CopiesSupported) values).contains((IntegerSyntax) attrval);
856:
857: if (values.getClass().equals(NumberUpSupported.class))
858: return ((NumberUpSupported) values).contains((IntegerSyntax) attrval);
859:
860: if (values.getClass().equals(JobPrioritySupported.class))
861: {
862: JobPriority priority = (JobPriority) attrval;
863: JobPrioritySupported maxSupported = (JobPrioritySupported) values;
864: if (priority.getValue() < maxSupported.getValue())
865: return true;
866: }
867:
868:
869:
870:
871:
872: return false;
873: }
874:
875:
876:
879: public boolean isDocFlavorSupported(DocFlavor flavor)
880: {
881: if (flavor == null)
882: throw new NullPointerException("DocFlavor may not be null.");
883:
884: return flavors.contains(flavor);
885: }
886:
887:
888:
891: public void addPrintServiceAttributeListener(
892: PrintServiceAttributeListener listener)
893: {
894: printServiceAttributeListener.add(listener);
895: }
896:
897:
900: public void removePrintServiceAttributeListener(
901: PrintServiceAttributeListener listener)
902: {
903: printServiceAttributeListener.remove(listener);
904: }
905:
906:
910: public String toString()
911: {
912: return "IppPrinter: " + getName();
913: }
914:
915:
920: public PrinterURI getPrinterURI()
921: {
922: return printerUri;
923: }
924: }