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 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();
204: tag = parseAttributes(tmp, stream);
205: operationAttributes.add(tmp);
206: break;
207: case IppDelimiterTag.JOB_ATTRIBUTES_TAG:
208: tmp = new HashMap();
209: tag = parseAttributes(tmp, stream);
210: jobAttributes.add(tmp);
211: break;
212: case IppDelimiterTag.PRINTER_ATTRIBUTES_TAG:
213: tmp = new HashMap();
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();
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 attributes, DataInputStream stream)
251: throws IppException, IOException
252: {
253: Attribute lastAttribute = null;
254: Attribute attribute = null;
255:
256:
257: short nameLength;
258: String name;
259: short valueLength;
260: byte[] value;
261:
262:
263:
264: URI uri;
265: String str;
266:
267: while (true)
268: {
269: byte tag = stream.readByte();
270:
271: if (IppDelimiterTag.isDelimiterTag(tag))
272: return tag;
273:
274:
275:
276:
277:
278:
279: nameLength = stream.readShort();
280:
281:
282:
283: if (nameLength == 0x0000)
284: name = lastAttribute.getName();
285: else
286: {
287: byte[] nameBytes = new byte[nameLength];
288: stream.read(nameBytes);
289: name = new String(nameBytes);
290: }
291:
292:
293: valueLength = stream.readShort();
294:
295:
296: value = new byte[valueLength];
297: stream.read(value);
298:
299:
300: switch (tag)
301: {
302:
303: case IppValueTag.UNSUPPORTED:
304: case IppValueTag.UNKNOWN:
305: case IppValueTag.NO_VALUE:
306:
307:
308: throw new IppException(
309: "Unexpected name value for out-of-band value tag");
310: case IppValueTag.INTEGER:
311: int intValue = IppUtilities.convertToInt(value);
312: attribute = IppUtilities.getIntegerAttribute(name, intValue);
313:
314: break;
315: case IppValueTag.BOOLEAN:
316:
317:
318: attribute = IppUtilities.getEnumAttribute(name, new Integer(value[0]));
319:
320: break;
321: case IppValueTag.ENUM:
322: int intVal = IppUtilities.convertToInt(value);
323: attribute = IppUtilities.getEnumAttribute(name, new Integer(intVal));
324:
325: break;
326: case IppValueTag.OCTECTSTRING_UNSPECIFIED:
327:
328:
329: throw new IppException("Unspecified octet string occured.");
330:
331: case IppValueTag.DATETIME:
332: Date date = parseDate(value);
333: if (name.equals("printer-current-time"))
334: attribute = new PrinterCurrentTime(date);
335: else if (name.equals("date-time-at-creation"))
336: attribute = new DateTimeAtCreation(date);
337: else if (name.equals("date-time-at-processing"))
338: attribute = new DateTimeAtProcessing(date);
339: else if (name.equals("date-time-at-completed"))
340: attribute = new DateTimeAtCompleted(date);
341:
342: break;
343: case IppValueTag.RESOLUTION:
344: int crossFeed = IppUtilities.convertToInt(value[0], value[1], value[2], value[3]);
345: int feed = IppUtilities.convertToInt(value[4], value[5], value[6], value[7]);
346: int units = value[8];
347:
348: if (name.equals("printer-resolution-default"))
349: attribute = new PrinterResolutionDefault(crossFeed, feed, units);
350: else if (name.equals("printer-resolution-supported"))
351: attribute = new PrinterResolutionSupported(crossFeed, feed, units);
352:
353: break;
354: case IppValueTag.RANGEOFINTEGER:
355: int lower = IppUtilities.convertToInt(value[0], value[1], value[2], value[3]);
356: int upper = IppUtilities.convertToInt(value[4], value[5], value[6], value[7]);
357:
358: if (name.equals("copies-supported"))
359: attribute = new CopiesSupported(lower, upper);
360: else if (name.equals("number-up-supported"))
361: attribute = new NumberUpSupported(lower, upper);
362: else if (name.equals("job-k-octets-supported"))
363: attribute = new JobKOctetsSupported(lower, upper);
364: else if (name.equals("job-impressions-supported"))
365: attribute = new JobImpressionsSupported(lower, upper);
366: else if (name.equals("job-media-sheets-supported"))
367: attribute = new JobMediaSheetsSupported(lower, upper);
368:
369: break;
370: case IppValueTag.TEXT_WITH_LANGUAGE:
371: case IppValueTag.TEXT_WITHOUT_LANGUAGE:
372: case IppValueTag.NAME_WITH_LANGUAGE:
373: case IppValueTag.NAME_WITHOUT_LANGUAGE:
374: attribute = IppUtilities.getTextAttribute(name, tag, value);
375:
376: break;
377: case IppValueTag.KEYWORD:
378: str = new String(value);
379: if (name.equals("job-hold-until-supported"))
380: attribute = new JobHoldUntilSupported(str, null);
381: else if (name.equals("job-hold-until-default"))
382: attribute = new JobHoldUntilDefault(str, null);
383: else if (name.equals("media-supported"))
384: attribute = new MediaSupported(str, null);
385: else if (name.equals("media-default"))
386: attribute = new MediaDefault(str, null);
387: else if (name.equals("job-sheets-default"))
388: attribute = new JobSheetsDefault(str, null);
389: else if (name.equals("job-sheets-supported"))
390: attribute = new JobSheetsSupported(str, null);
391: else if (name.equals("job-state-reasons"))
392: attribute = parseJobStateReasons(value, lastAttribute);
393: else if (name.equals("printer-state-reasons"))
394: attribute = parsePrinterStateReasons(value, lastAttribute);
395: else
396: attribute = IppUtilities.getEnumAttribute(name, str);
397:
398:
399:
400:
401:
402:
403:
404: break;
405: case IppValueTag.URI:
406: try
407: {
408: uri = new URI(new String(value));
409: }
410: catch (URISyntaxException e)
411: {
412: throw new IppException("Wrong URI syntax encountered.", e);
413: }
414:
415: if (name.equals("job-uri"))
416: attribute = new JobUri(uri);
417: else if (name.equals("job-printer-uri"))
418: attribute = new JobPrinterUri(uri);
419: else if (name.equals("job-more-info"))
420: attribute = new JobMoreInfo(uri);
421: else if (name.equals("printer-uri-supported"))
422: attribute = new PrinterUriSupported(uri);
423: else if (name.equals("printer-more-info"))
424: attribute = new PrinterMoreInfo(uri);
425: else if (name.equals("printer-driver-installer"))
426: attribute = new PrinterDriverInstaller(uri);
427: else if (name.equals("printer-more-info-manufacturer"))
428: attribute = new PrinterMoreInfoManufacturer(uri);
429:
430: break;
431: case IppValueTag.URI_SCHEME:
432:
433: if (name.equals("reference-uri-schemes-supported"))
434: attribute = IppUtilities.getEnumAttribute(name, new String(value));
435:
436: break;
437: case IppValueTag.CHARSET:
438: str = new String(value);
439: if (name.equals("attributes-charset"))
440: attribute = new AttributesCharset(str);
441: else if (name.equals("charset-configured"))
442: attribute = new CharsetConfigured(str);
443: else if (name.equals("charset-supported"))
444: attribute = new CharsetSupported(str);
445:
446: break;
447: case IppValueTag.NATURAL_LANGUAGE:
448: str = new String(value);
449: if (name.equals("attributes-natural-language"))
450: attribute = new AttributesNaturalLanguage(str);
451: else if (name.equals("natural-language-configured"))
452: attribute = new NaturalLanguageConfigured(str);
453: else if (name.equals("generated-natural-language-supported"))
454: attribute = new GeneratedNaturalLanguageSupported(str);
455:
456: break;
457: case IppValueTag.MIME_MEDIA_TYPE:
458: str = new String(value);
459: if (name.equals("document-format-default"))
460: attribute = new DocumentFormatDefault(str, null);
461: else if (name.equals("document-format-supported"))
462: attribute = new DocumentFormatSupported(str, null);
463: else if (name.equals("document-format"))
464: attribute = new DocumentFormat(str, null);
465:
466: break;
467: default:
468: throw new IppException("Unknown tag with value "
469: + Integer.toHexString(tag) + " found.");
470: }
471:
472: if (attribute == null)
473: attribute = new UnknownAttribute(tag, name, value);
474:
475: addAttribute(attributes, attribute);
476: lastAttribute = attribute;
477:
478: logger.log(Component.IPP, "Attribute: " + name
479: + " Value: " + attribute.toString());
480: }
481: }
482:
483:
492: private void addAttribute(Map attributeGroup, Attribute attribute)
493: {
494: Class clazz = attribute.getCategory();
495: Set attributeValues = (Set) attributeGroup.get(clazz);
496:
497: if (attributeValues == null)
498: {
499: attributeValues = new HashSet();
500: attributeGroup.put(clazz, attributeValues);
501: }
502:
503: attributeValues.add(attribute);
504: }
505:
506:
513: private PrinterStateReasons parsePrinterStateReasons(byte[] value, Attribute lastAttr)
514: {
515: String str = new String(value);
516: PrinterStateReasons attribute;
517:
518: if (lastAttr instanceof PrinterStateReasons)
519: attribute = (PrinterStateReasons) lastAttr;
520: else
521: attribute = new PrinterStateReasons();
522:
523:
524: if (str.equals("none"))
525: return attribute;
526:
527: Severity severity = null;
528: PrinterStateReason reason = null;
529:
530: if (str.endsWith(Severity.WARNING.toString()))
531: severity = Severity.WARNING;
532: else if (str.endsWith(Severity.REPORT.toString()))
533: severity = Severity.REPORT;
534: else if (str.endsWith(Severity.ERROR.toString()))
535: severity = Severity.ERROR;
536:
537: if (severity != null)
538: str = str.substring(0, str.lastIndexOf('-'));
539: else
540: severity = Severity.REPORT;
541:
542: reason = (PrinterStateReason)
543: IppUtilities.getEnumAttribute("printer-state-reason", str);
544:
545: attribute.put(reason , severity);
546: return attribute;
547: }
548:
549:
556: private JobStateReasons parseJobStateReasons(byte[] value, Attribute lastAttr)
557: {
558: String str = new String(value);
559: JobStateReasons attribute;
560:
561: if (lastAttr instanceof JobStateReasons)
562: attribute = (JobStateReasons) lastAttr;
563: else
564: attribute = new JobStateReasons();
565:
566:
567: if (str.equals("none"))
568: return attribute;
569:
570: JobStateReason reason = (JobStateReason)
571: IppUtilities.getEnumAttribute("job-state-reason", str);
572:
573: attribute.add(reason);
574: return attribute;
575: }
576:
577:
601: private Date parseDate(byte[] value)
602: {
603: short year = IppUtilities.convertToShort(value[0], value[1]);
604:
605: Calendar cal = Calendar.getInstance();
606: cal.set(Calendar.YEAR, year);
607: cal.set(Calendar.MONTH, value[2]);
608: cal.set(Calendar.DAY_OF_MONTH, value[3]);
609: cal.set(Calendar.HOUR_OF_DAY, value[4]);
610: cal.set(Calendar.MINUTE, value[5]);
611: cal.set(Calendar.SECOND, value[6]);
612: cal.set(Calendar.MILLISECOND, value[7] * 100);
613:
614:
615: int offsetMilli = value[9] * 3600000;
616: offsetMilli = offsetMilli + value[10] * 60000;
617:
618: if (((char) value[8]) == '-')
619: offsetMilli = offsetMilli * (-1);
620:
621: cal.set(Calendar.ZONE_OFFSET, offsetMilli);
622: return cal.getTime();
623: }
624: }
625:
626:
630: static final Logger logger = SystemLogger.SYSTEM;
631:
632: URI uri;
633: short operation_id;
634: short status_code;
635: int request_id;
636:
637: List operationAttributes;
638: List printerAttributes;
639: List jobAttributes;
640: List unsupportedAttributes;
641:
642: byte[] data;
643:
644:
650: public IppResponse(URI uri, short operation_id)
651: {
652: this.uri = uri;
653: this.operation_id = operation_id;
654: operationAttributes = new ArrayList();
655: jobAttributes = new ArrayList();
656: printerAttributes = new ArrayList();
657: unsupportedAttributes = new ArrayList();
658: }
659:
660:
666: protected void setResponseData(InputStream input) throws IppException
667: {
668: ResponseReader reader = new ResponseReader();
669:
670: try
671: {
672: reader.parseResponse(input);
673: }
674: catch (IOException e)
675: {
676: throw new IppException(
677: "Exception during response parsing caused by IOException", e);
678: }
679: }
680:
681:
685: public URI getURI()
686: {
687: return uri;
688: }
689:
690:
694: public int getOperationID()
695: {
696: return operation_id;
697: }
698:
699:
706: public List getJobAttributes()
707: {
708: return jobAttributes;
709: }
710:
711:
718: public List getOperationAttributes()
719: {
720: return operationAttributes;
721: }
722:
723:
730: public List getPrinterAttributes()
731: {
732: return printerAttributes;
733: }
734:
735:
740: public int getRequestID()
741: {
742: return request_id;
743: }
744:
745:
751: public short getStatusCode()
752: {
753: return status_code;
754: }
755:
756:
763: public List getUnsupportedAttributes()
764: {
765: return unsupportedAttributes;
766: }
767:
768:
773: public byte[] getData()
774: {
775: return data;
776: }
777:
778: }