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:
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73: import ;
74: import ;
75: import ;
76: import ;
77: import ;
78: import ;
79: import ;
80: import ;
81: import ;
82: import ;
83:
84: import ;
85: import ;
86: import ;
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:
101:
107: public class IppResponse
108: {
109:
110:
158: class ResponseReader
159: {
160:
161: private static final short VERSION = 0x0101;
162:
163:
169: public void parseResponse(InputStream input)
170: throws IppException, IOException
171: {
172: DataInputStream stream = new DataInputStream(input);
173:
174: short version = stream.readShort();
175: status_code = stream.readShort();
176: request_id = stream.readInt();
177:
178: if (VERSION != version)
179: throw new IppException("Version mismatch - "
180: + "implementation does not support other versions than IPP 1.1");
181:
182: logger.log(Component.IPP, "Statuscode: "
183: + Integer.toHexString(status_code) + " Request-ID: " + request_id);
184:
185: byte tag = 0;
186: boolean proceed = true;
187: HashMap<Class<? extends Attribute>, Set<Attribute>> tmp;
188:
189: while (proceed)
190: {
191: if (tag == 0)
192: tag = stream.readByte();
193:
194: logger.log(Component.IPP, "DelimiterTag: " + Integer.toHexString(tag));
195:
196:
197: switch (tag)
198: {
199: case IppDelimiterTag.END_OF_ATTRIBUTES_TAG:
200: proceed = false;
201: break;
202: case IppDelimiterTag.OPERATION_ATTRIBUTES_TAG:
203: tmp = new HashMap<Class<? extends Attribute>, Set<Attribute>>();
204: tag = parseAttributes(tmp, stream);
205: operationAttributes.add(tmp);
206: break;
207: case IppDelimiterTag.JOB_ATTRIBUTES_TAG:
208: tmp = new HashMap<Class<? extends Attribute>, Set<Attribute>>();
209: tag = parseAttributes(tmp, stream);
210: jobAttributes.add(tmp);
211: break;
212: case IppDelimiterTag.PRINTER_ATTRIBUTES_TAG:
213: tmp = new HashMap<Class<? extends Attribute>, Set<Attribute>>();
214: tag = parseAttributes(tmp, stream);
215: printerAttributes.add(tmp);
216: break;
217: case IppDelimiterTag.UNSUPPORTED_ATTRIBUTES_TAG:
218: System.out.println("Called");
219: tmp = new HashMap<Class<? extends Attribute>, Set<Attribute>>();
220: tag = parseAttributes(tmp, stream);
221: unsupportedAttributes.add(tmp);
222: break;
223: default:
224: throw new IppException("Unknown tag with value "
225: + Integer.toHexString(tag) + " occured.");
226: }
227: }
228:
229:
230: ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
231: byte[] readbuf = new byte[2048];
232: int len = 0;
233:
234: while ((len = stream.read(readbuf)) > 0)
235: byteStream.write(readbuf, 0, len);
236:
237: byteStream.flush();
238: data = byteStream.toByteArray();
239: }
240:
241:
250: private byte parseAttributes(Map<Class<? extends Attribute>, Set<Attribute>> attributes,
251: DataInputStream stream)
252: throws IppException, IOException
253: {
254: Attribute lastAttribute = null;
255: Attribute attribute = null;
256:
257:
258: short nameLength;
259: String name;
260: short valueLength;
261: byte[] value;
262:
263:
264:
265: URI uri;
266: String str;
267:
268: while (true)
269: {
270: byte tag = stream.readByte();
271:
272: if (IppDelimiterTag.isDelimiterTag(tag))
273: return tag;
274:
275:
276:
277:
278:
279:
280: nameLength = stream.readShort();
281:
282:
283:
284: if (nameLength == 0x0000)
285: name = lastAttribute.getName();
286: else
287: {
288: byte[] nameBytes = new byte[nameLength];
289: stream.read(nameBytes);
290: name = new String(nameBytes);
291: }
292:
293:
294: valueLength = stream.readShort();
295:
296:
297: value = new byte[valueLength];
298: stream.read(value);
299:
300:
301: switch (tag)
302: {
303:
304: case IppValueTag.UNSUPPORTED:
305: case IppValueTag.UNKNOWN:
306:
307:
308: throw new IppException(
309: "Unexpected name value for out-of-band value tag " + tag);
310: case IppValueTag.NO_VALUE:
311: attribute = null;
312:
313: break;
314: case IppValueTag.INTEGER:
315: int intValue = IppUtilities.convertToInt(value);
316: attribute = IppUtilities.getIntegerAttribute(name, intValue);
317:
318: break;
319: case IppValueTag.BOOLEAN:
320:
321:
322: attribute = IppUtilities.getEnumAttribute(name, new Integer(value[0]));
323:
324: break;
325: case IppValueTag.ENUM:
326: int intVal = IppUtilities.convertToInt(value);
327: attribute = IppUtilities.getEnumAttribute(name, new Integer(intVal));
328:
329: break;
330: case IppValueTag.OCTECTSTRING_UNSPECIFIED:
331:
332:
333: throw new IppException("Unspecified octet string occured.");
334:
335: case IppValueTag.DATETIME:
336: Date date = parseDate(value);
337: if (name.equals("printer-current-time"))
338: attribute = new PrinterCurrentTime(date);
339: else if (name.equals("date-time-at-creation"))
340: attribute = new DateTimeAtCreation(date);
341: else if (name.equals("date-time-at-processing"))
342: attribute = new DateTimeAtProcessing(date);
343: else if (name.equals("date-time-at-completed"))
344: attribute = new DateTimeAtCompleted(date);
345:
346: break;
347: case IppValueTag.RESOLUTION:
348: int crossFeed = IppUtilities.convertToInt(value[0], value[1], value[2], value[3]);
349: int feed = IppUtilities.convertToInt(value[4], value[5], value[6], value[7]);
350: int units = value[8];
351:
352: if (name.equals("printer-resolution-default"))
353: attribute = new PrinterResolutionDefault(crossFeed, feed, units);
354: else if (name.equals("printer-resolution-supported"))
355: attribute = new PrinterResolutionSupported(crossFeed, feed, units);
356:
357: break;
358: case IppValueTag.RANGEOFINTEGER:
359: int lower = IppUtilities.convertToInt(value[0], value[1], value[2], value[3]);
360: int upper = IppUtilities.convertToInt(value[4], value[5], value[6], value[7]);
361:
362: if (name.equals("copies-supported"))
363: attribute = new CopiesSupported(lower, upper);
364: else if (name.equals("number-up-supported"))
365: attribute = new NumberUpSupported(lower, upper);
366: else if (name.equals("job-k-octets-supported"))
367: attribute = new JobKOctetsSupported(lower, upper);
368: else if (name.equals("job-impressions-supported"))
369: attribute = new JobImpressionsSupported(lower, upper);
370: else if (name.equals("job-media-sheets-supported"))
371: attribute = new JobMediaSheetsSupported(lower, upper);
372:
373: break;
374: case IppValueTag.TEXT_WITH_LANGUAGE:
375: case IppValueTag.TEXT_WITHOUT_LANGUAGE:
376: case IppValueTag.NAME_WITH_LANGUAGE:
377: case IppValueTag.NAME_WITHOUT_LANGUAGE:
378: attribute = IppUtilities.getTextAttribute(name, tag, value);
379:
380: break;
381: case IppValueTag.KEYWORD:
382: str = new String(value);
383: if (name.equals("job-hold-until-supported"))
384: attribute = new JobHoldUntilSupported(str, null);
385: else if (name.equals("job-hold-until-default"))
386: attribute = new JobHoldUntilDefault(str, null);
387: else if (name.equals("media-supported"))
388: attribute = new MediaSupported(str, null);
389: else if (name.equals("media-default"))
390: attribute = new MediaDefault(str, null);
391: else if (name.equals("job-sheets-default"))
392: attribute = new JobSheetsDefault(str, null);
393: else if (name.equals("job-sheets-supported"))
394: attribute = new JobSheetsSupported(str, null);
395: else if (name.equals("job-state-reasons"))
396: attribute = parseJobStateReasons(value, lastAttribute);
397: else if (name.equals("printer-state-reasons"))
398: attribute = parsePrinterStateReasons(value, lastAttribute);
399: else
400: attribute = IppUtilities.getEnumAttribute(name, str);
401:
402:
403:
404:
405:
406:
407:
408: break;
409: case IppValueTag.URI:
410: try
411: {
412: uri = new URI(new String(value));
413: }
414: catch (URISyntaxException e)
415: {
416: throw new IppException("Wrong URI syntax encountered.", e);
417: }
418:
419: if (name.equals("job-uri"))
420: attribute = new JobUri(uri);
421: else if (name.equals("job-printer-uri"))
422: attribute = new JobPrinterUri(uri);
423: else if (name.equals("job-more-info"))
424: attribute = new JobMoreInfo(uri);
425: else if (name.equals("printer-uri-supported"))
426: attribute = new PrinterUriSupported(uri);
427: else if (name.equals("printer-more-info"))
428: attribute = new PrinterMoreInfo(uri);
429: else if (name.equals("printer-driver-installer"))
430: attribute = new PrinterDriverInstaller(uri);
431: else if (name.equals("printer-more-info-manufacturer"))
432: attribute = new PrinterMoreInfoManufacturer(uri);
433:
434: break;
435: case IppValueTag.URI_SCHEME:
436:
437: if (name.equals("reference-uri-schemes-supported"))
438: attribute = IppUtilities.getEnumAttribute(name, new String(value));
439:
440: break;
441: case IppValueTag.CHARSET:
442: str = new String(value);
443: if (name.equals("attributes-charset"))
444: attribute = new AttributesCharset(str);
445: else if (name.equals("charset-configured"))
446: attribute = new CharsetConfigured(str);
447: else if (name.equals("charset-supported"))
448: attribute = new CharsetSupported(str);
449:
450: break;
451: case IppValueTag.NATURAL_LANGUAGE:
452: str = new String(value);
453: if (name.equals("attributes-natural-language"))
454: attribute = new AttributesNaturalLanguage(str);
455: else if (name.equals("natural-language-configured"))
456: attribute = new NaturalLanguageConfigured(str);
457: else if (name.equals("generated-natural-language-supported"))
458: attribute = new GeneratedNaturalLanguageSupported(str);
459:
460: break;
461: case IppValueTag.MIME_MEDIA_TYPE:
462: str = new String(value);
463: if (name.equals("document-format-default"))
464: attribute = new DocumentFormatDefault(str, null);
465: else if (name.equals("document-format-supported"))
466: attribute = new DocumentFormatSupported(str, null);
467: else if (name.equals("document-format"))
468: attribute = new DocumentFormat(str, null);
469:
470: break;
471: default:
472: throw new IppException("Unknown tag with value "
473: + Integer.toHexString(tag) + " found.");
474: }
475:
476: if (attribute == null)
477: attribute = new UnknownAttribute(tag, name, value);
478:
479: addAttribute(attributes, attribute);
480: lastAttribute = attribute;
481:
482: logger.log(Component.IPP, "Attribute: " + name
483: + " Value: " + attribute.toString());
484: }
485: }
486:
487:
496: private void addAttribute(Map<Class<? extends Attribute>, Set<Attribute>> attributeGroup,
497: Attribute attribute)
498: {
499: Class<? extends Attribute> clazz = attribute.getCategory();
500: Set<Attribute> attributeValues = attributeGroup.get(clazz);
501:
502: if (attributeValues == null)
503: {
504: attributeValues = new HashSet<Attribute>();
505: attributeGroup.put(clazz, attributeValues);
506: }
507:
508: attributeValues.add(attribute);
509: }
510:
511:
518: private PrinterStateReasons parsePrinterStateReasons(byte[] value, Attribute lastAttr)
519: {
520: String str = new String(value);
521: PrinterStateReasons attribute;
522:
523: if (lastAttr instanceof PrinterStateReasons)
524: attribute = (PrinterStateReasons) lastAttr;
525: else
526: attribute = new PrinterStateReasons();
527:
528:
529: if (str.equals("none"))
530: return attribute;
531:
532: Severity severity = null;
533: PrinterStateReason reason = null;
534:
535: if (str.endsWith(Severity.WARNING.toString()))
536: severity = Severity.WARNING;
537: else if (str.endsWith(Severity.REPORT.toString()))
538: severity = Severity.REPORT;
539: else if (str.endsWith(Severity.ERROR.toString()))
540: severity = Severity.ERROR;
541:
542: if (severity != null)
543: str = str.substring(0, str.lastIndexOf('-'));
544: else
545: severity = Severity.REPORT;
546:
547: reason = (PrinterStateReason)
548: IppUtilities.getEnumAttribute("printer-state-reason", str);
549:
550: attribute.put(reason , severity);
551: return attribute;
552: }
553:
554:
561: private JobStateReasons parseJobStateReasons(byte[] value, Attribute lastAttr)
562: {
563: String str = new String(value);
564: JobStateReasons attribute;
565:
566: if (lastAttr instanceof JobStateReasons)
567: attribute = (JobStateReasons) lastAttr;
568: else
569: attribute = new JobStateReasons();
570:
571:
572: if (str.equals("none"))
573: return attribute;
574:
575: JobStateReason reason = (JobStateReason)
576: IppUtilities.getEnumAttribute("job-state-reason", str);
577:
578: attribute.add(reason);
579: return attribute;
580: }
581:
582:
606: private Date parseDate(byte[] value)
607: {
608: short year = IppUtilities.convertToShort(value[0], value[1]);
609:
610: Calendar cal = Calendar.getInstance();
611: cal.set(Calendar.YEAR, year);
612: cal.set(Calendar.MONTH, value[2]);
613: cal.set(Calendar.DAY_OF_MONTH, value[3]);
614: cal.set(Calendar.HOUR_OF_DAY, value[4]);
615: cal.set(Calendar.MINUTE, value[5]);
616: cal.set(Calendar.SECOND, value[6]);
617: cal.set(Calendar.MILLISECOND, value[7] * 100);
618:
619:
620: int offsetMilli = value[9] * 3600000;
621: offsetMilli = offsetMilli + value[10] * 60000;
622:
623: if (((char) value[8]) == '-')
624: offsetMilli = offsetMilli * (-1);
625:
626: cal.set(Calendar.ZONE_OFFSET, offsetMilli);
627: return cal.getTime();
628: }
629: }
630:
631:
635: static final Logger logger = SystemLogger.SYSTEM;
636:
637: URI uri;
638: short operation_id;
639: short status_code;
640: int request_id;
641:
642: List<Map<Class<? extends Attribute>, Set<Attribute>>> operationAttributes;
643: List<Map<Class<? extends Attribute>, Set<Attribute>>> printerAttributes;
644: List<Map<Class<? extends Attribute>, Set<Attribute>>> jobAttributes;
645: List<Map<Class<? extends Attribute>, Set<Attribute>>> unsupportedAttributes;
646:
647: byte[] data;
648:
649:
655: public IppResponse(URI uri, short operation_id)
656: {
657: this.uri = uri;
658: this.operation_id = operation_id;
659: operationAttributes =
660: new ArrayList<Map<Class<? extends Attribute>, Set<Attribute>>>();
661: jobAttributes =
662: new ArrayList<Map<Class<? extends Attribute>, Set<Attribute>>>();
663: printerAttributes =
664: new ArrayList<Map<Class<? extends Attribute>, Set<Attribute>>>();
665: unsupportedAttributes =
666: new ArrayList<Map<Class<? extends Attribute>, Set<Attribute>>>();
667: }
668:
669:
675: protected void setResponseData(InputStream input) throws IppException
676: {
677: ResponseReader reader = new ResponseReader();
678:
679: try
680: {
681: reader.parseResponse(input);
682: }
683: catch (IOException e)
684: {
685: throw new IppException(
686: "Exception during response parsing caused by IOException", e);
687: }
688: }
689:
690:
694: public URI getURI()
695: {
696: return uri;
697: }
698:
699:
703: public int getOperationID()
704: {
705: return operation_id;
706: }
707:
708:
715: public List<Map<Class<? extends Attribute>, Set<Attribute>>> getJobAttributes()
716: {
717: return jobAttributes;
718: }
719:
720:
727: public List<Map<Class<? extends Attribute>, Set<Attribute>>> getOperationAttributes()
728: {
729: return operationAttributes;
730: }
731:
732:
739: public List<Map<Class<? extends Attribute>, Set<Attribute>>> getPrinterAttributes()
740: {
741: return printerAttributes;
742: }
743:
744:
749: public int getRequestID()
750: {
751: return request_id;
752: }
753:
754:
760: public short getStatusCode()
761: {
762: return status_code;
763: }
764:
765:
772: public List<Map<Class<? extends Attribute>, Set<Attribute>>> getUnsupportedAttributes()
773: {
774: return unsupportedAttributes;
775: }
776:
777:
782: public byte[] getData()
783: {
784: return data;
785: }
786:
787: }