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:
306:
307: throw new IppException(
308: "Unexpected name value for out-of-band value tag " + tag);
309: case IppValueTag.NO_VALUE:
310: attribute = null;
311:
312: break;
313: case IppValueTag.INTEGER:
314: int intValue = IppUtilities.convertToInt(value);
315: attribute = IppUtilities.getIntegerAttribute(name, intValue);
316:
317: break;
318: case IppValueTag.BOOLEAN:
319:
320:
321: attribute = IppUtilities.getEnumAttribute(name, new Integer(value[0]));
322:
323: break;
324: case IppValueTag.ENUM:
325: int intVal = IppUtilities.convertToInt(value);
326: attribute = IppUtilities.getEnumAttribute(name, new Integer(intVal));
327:
328: break;
329: case IppValueTag.OCTECTSTRING_UNSPECIFIED:
330:
331:
332: throw new IppException("Unspecified octet string occured.");
333:
334: case IppValueTag.DATETIME:
335: Date date = parseDate(value);
336: if (name.equals("printer-current-time"))
337: attribute = new PrinterCurrentTime(date);
338: else if (name.equals("date-time-at-creation"))
339: attribute = new DateTimeAtCreation(date);
340: else if (name.equals("date-time-at-processing"))
341: attribute = new DateTimeAtProcessing(date);
342: else if (name.equals("date-time-at-completed"))
343: attribute = new DateTimeAtCompleted(date);
344:
345: break;
346: case IppValueTag.RESOLUTION:
347: int crossFeed = IppUtilities.convertToInt(value[0], value[1], value[2], value[3]);
348: int feed = IppUtilities.convertToInt(value[4], value[5], value[6], value[7]);
349: int units = value[8];
350:
351: if (name.equals("printer-resolution-default"))
352: attribute = new PrinterResolutionDefault(crossFeed, feed, units);
353: else if (name.equals("printer-resolution-supported"))
354: attribute = new PrinterResolutionSupported(crossFeed, feed, units);
355:
356: break;
357: case IppValueTag.RANGEOFINTEGER:
358: int lower = IppUtilities.convertToInt(value[0], value[1], value[2], value[3]);
359: int upper = IppUtilities.convertToInt(value[4], value[5], value[6], value[7]);
360:
361: if (name.equals("copies-supported"))
362: attribute = new CopiesSupported(lower, upper);
363: else if (name.equals("number-up-supported"))
364: attribute = new NumberUpSupported(lower, upper);
365: else if (name.equals("job-k-octets-supported"))
366: attribute = new JobKOctetsSupported(lower, upper);
367: else if (name.equals("job-impressions-supported"))
368: attribute = new JobImpressionsSupported(lower, upper);
369: else if (name.equals("job-media-sheets-supported"))
370: attribute = new JobMediaSheetsSupported(lower, upper);
371:
372: break;
373: case IppValueTag.TEXT_WITH_LANGUAGE:
374: case IppValueTag.TEXT_WITHOUT_LANGUAGE:
375: case IppValueTag.NAME_WITH_LANGUAGE:
376: case IppValueTag.NAME_WITHOUT_LANGUAGE:
377: attribute = IppUtilities.getTextAttribute(name, tag, value);
378:
379: break;
380: case IppValueTag.KEYWORD:
381: str = new String(value);
382: if (name.equals("job-hold-until-supported"))
383: attribute = new JobHoldUntilSupported(str, null);
384: else if (name.equals("job-hold-until-default"))
385: attribute = new JobHoldUntilDefault(str, null);
386: else if (name.equals("media-supported"))
387: attribute = new MediaSupported(str, null);
388: else if (name.equals("media-default"))
389: attribute = new MediaDefault(str, null);
390: else if (name.equals("job-sheets-default"))
391: attribute = new JobSheetsDefault(str, null);
392: else if (name.equals("job-sheets-supported"))
393: attribute = new JobSheetsSupported(str, null);
394: else if (name.equals("job-state-reasons"))
395: attribute = parseJobStateReasons(value, lastAttribute);
396: else if (name.equals("printer-state-reasons"))
397: attribute = parsePrinterStateReasons(value, lastAttribute);
398: else
399: attribute = IppUtilities.getEnumAttribute(name, str);
400:
401:
402:
403:
404:
405:
406:
407: break;
408: case IppValueTag.URI:
409: try
410: {
411: uri = new URI(new String(value));
412: }
413: catch (URISyntaxException e)
414: {
415: throw new IppException("Wrong URI syntax encountered.", e);
416: }
417:
418: if (name.equals("job-uri"))
419: attribute = new JobUri(uri);
420: else if (name.equals("job-printer-uri"))
421: attribute = new JobPrinterUri(uri);
422: else if (name.equals("job-more-info"))
423: attribute = new JobMoreInfo(uri);
424: else if (name.equals("printer-uri-supported"))
425: attribute = new PrinterUriSupported(uri);
426: else if (name.equals("printer-more-info"))
427: attribute = new PrinterMoreInfo(uri);
428: else if (name.equals("printer-driver-installer"))
429: attribute = new PrinterDriverInstaller(uri);
430: else if (name.equals("printer-more-info-manufacturer"))
431: attribute = new PrinterMoreInfoManufacturer(uri);
432:
433: break;
434: case IppValueTag.URI_SCHEME:
435:
436: if (name.equals("reference-uri-schemes-supported"))
437: attribute = IppUtilities.getEnumAttribute(name, new String(value));
438:
439: break;
440: case IppValueTag.CHARSET:
441: str = new String(value);
442: if (name.equals("attributes-charset"))
443: attribute = new AttributesCharset(str);
444: else if (name.equals("charset-configured"))
445: attribute = new CharsetConfigured(str);
446: else if (name.equals("charset-supported"))
447: attribute = new CharsetSupported(str);
448:
449: break;
450: case IppValueTag.NATURAL_LANGUAGE:
451: str = new String(value);
452: if (name.equals("attributes-natural-language"))
453: attribute = new AttributesNaturalLanguage(str);
454: else if (name.equals("natural-language-configured"))
455: attribute = new NaturalLanguageConfigured(str);
456: else if (name.equals("generated-natural-language-supported"))
457: attribute = new GeneratedNaturalLanguageSupported(str);
458:
459: break;
460: case IppValueTag.MIME_MEDIA_TYPE:
461: str = new String(value);
462: if (name.equals("document-format-default"))
463: attribute = new DocumentFormatDefault(str, null);
464: else if (name.equals("document-format-supported"))
465: attribute = new DocumentFormatSupported(str, null);
466: else if (name.equals("document-format"))
467: attribute = new DocumentFormat(str, null);
468:
469: break;
470: default:
471: throw new IppException("Unknown tag with value "
472: + Integer.toHexString(tag) + " found.");
473: }
474:
475: if (attribute == null)
476: attribute = new UnknownAttribute(tag, name, value);
477:
478: addAttribute(attributes, attribute);
479: lastAttribute = attribute;
480:
481: logger.log(Component.IPP, "Attribute: " + name
482: + " Value: " + attribute.toString());
483: }
484: }
485:
486:
495: private void addAttribute(Map attributeGroup, Attribute attribute)
496: {
497: Class clazz = attribute.getCategory();
498: Set attributeValues = (Set) attributeGroup.get(clazz);
499:
500: if (attributeValues == null)
501: {
502: attributeValues = new HashSet();
503: attributeGroup.put(clazz, attributeValues);
504: }
505:
506: attributeValues.add(attribute);
507: }
508:
509:
516: private PrinterStateReasons parsePrinterStateReasons(byte[] value, Attribute lastAttr)
517: {
518: String str = new String(value);
519: PrinterStateReasons attribute;
520:
521: if (lastAttr instanceof PrinterStateReasons)
522: attribute = (PrinterStateReasons) lastAttr;
523: else
524: attribute = new PrinterStateReasons();
525:
526:
527: if (str.equals("none"))
528: return attribute;
529:
530: Severity severity = null;
531: PrinterStateReason reason = null;
532:
533: if (str.endsWith(Severity.WARNING.toString()))
534: severity = Severity.WARNING;
535: else if (str.endsWith(Severity.REPORT.toString()))
536: severity = Severity.REPORT;
537: else if (str.endsWith(Severity.ERROR.toString()))
538: severity = Severity.ERROR;
539:
540: if (severity != null)
541: str = str.substring(0, str.lastIndexOf('-'));
542: else
543: severity = Severity.REPORT;
544:
545: reason = (PrinterStateReason)
546: IppUtilities.getEnumAttribute("printer-state-reason", str);
547:
548: attribute.put(reason , severity);
549: return attribute;
550: }
551:
552:
559: private JobStateReasons parseJobStateReasons(byte[] value, Attribute lastAttr)
560: {
561: String str = new String(value);
562: JobStateReasons attribute;
563:
564: if (lastAttr instanceof JobStateReasons)
565: attribute = (JobStateReasons) lastAttr;
566: else
567: attribute = new JobStateReasons();
568:
569:
570: if (str.equals("none"))
571: return attribute;
572:
573: JobStateReason reason = (JobStateReason)
574: IppUtilities.getEnumAttribute("job-state-reason", str);
575:
576: attribute.add(reason);
577: return attribute;
578: }
579:
580:
604: private Date parseDate(byte[] value)
605: {
606: short year = IppUtilities.convertToShort(value[0], value[1]);
607:
608: Calendar cal = Calendar.getInstance();
609: cal.set(Calendar.YEAR, year);
610: cal.set(Calendar.MONTH, value[2]);
611: cal.set(Calendar.DAY_OF_MONTH, value[3]);
612: cal.set(Calendar.HOUR_OF_DAY, value[4]);
613: cal.set(Calendar.MINUTE, value[5]);
614: cal.set(Calendar.SECOND, value[6]);
615: cal.set(Calendar.MILLISECOND, value[7] * 100);
616:
617:
618: int offsetMilli = value[9] * 3600000;
619: offsetMilli = offsetMilli + value[10] * 60000;
620:
621: if (((char) value[8]) == '-')
622: offsetMilli = offsetMilli * (-1);
623:
624: cal.set(Calendar.ZONE_OFFSET, offsetMilli);
625: return cal.getTime();
626: }
627: }
628:
629:
633: static final Logger logger = SystemLogger.SYSTEM;
634:
635: URI uri;
636: short operation_id;
637: short status_code;
638: int request_id;
639:
640: List operationAttributes;
641: List printerAttributes;
642: List jobAttributes;
643: List unsupportedAttributes;
644:
645: byte[] data;
646:
647:
653: public IppResponse(URI uri, short operation_id)
654: {
655: this.uri = uri;
656: this.operation_id = operation_id;
657: operationAttributes = new ArrayList();
658: jobAttributes = new ArrayList();
659: printerAttributes = new ArrayList();
660: unsupportedAttributes = new ArrayList();
661: }
662:
663:
669: protected void setResponseData(InputStream input) throws IppException
670: {
671: ResponseReader reader = new ResponseReader();
672:
673: try
674: {
675: reader.parseResponse(input);
676: }
677: catch (IOException e)
678: {
679: throw new IppException(
680: "Exception during response parsing caused by IOException", e);
681: }
682: }
683:
684:
688: public URI getURI()
689: {
690: return uri;
691: }
692:
693:
697: public int getOperationID()
698: {
699: return operation_id;
700: }
701:
702:
709: public List getJobAttributes()
710: {
711: return jobAttributes;
712: }
713:
714:
721: public List getOperationAttributes()
722: {
723: return operationAttributes;
724: }
725:
726:
733: public List getPrinterAttributes()
734: {
735: return printerAttributes;
736: }
737:
738:
743: public int getRequestID()
744: {
745: return request_id;
746: }
747:
748:
754: public short getStatusCode()
755: {
756: return status_code;
757: }
758:
759:
766: public List getUnsupportedAttributes()
767: {
768: return unsupportedAttributes;
769: }
770:
771:
776: public byte[] getData()
777: {
778: return data;
779: }
780:
781: }