2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.javax.print.ipp;
41 import gnu.classpath.debug.Component;
42 import gnu.classpath.debug.SystemLogger;
43 import gnu.javax.print.ipp.attribute.UnknownAttribute;
44 import gnu.javax.print.ipp.attribute.defaults.DocumentFormatDefault;
45 import gnu.javax.print.ipp.attribute.defaults.JobHoldUntilDefault;
46 import gnu.javax.print.ipp.attribute.defaults.JobSheetsDefault;
47 import gnu.javax.print.ipp.attribute.defaults.MediaDefault;
48 import gnu.javax.print.ipp.attribute.defaults.PrinterResolutionDefault;
49 import gnu.javax.print.ipp.attribute.job.AttributesCharset;
50 import gnu.javax.print.ipp.attribute.job.AttributesNaturalLanguage;
51 import gnu.javax.print.ipp.attribute.job.JobMoreInfo;
52 import gnu.javax.print.ipp.attribute.job.JobPrinterUri;
53 import gnu.javax.print.ipp.attribute.job.JobUri;
54 import gnu.javax.print.ipp.attribute.printer.CharsetConfigured;
55 import gnu.javax.print.ipp.attribute.printer.DocumentFormat;
56 import gnu.javax.print.ipp.attribute.printer.NaturalLanguageConfigured;
57 import gnu.javax.print.ipp.attribute.printer.PrinterCurrentTime;
58 import gnu.javax.print.ipp.attribute.printer.PrinterDriverInstaller;
59 import gnu.javax.print.ipp.attribute.supported.CharsetSupported;
60 import gnu.javax.print.ipp.attribute.supported.DocumentFormatSupported;
61 import gnu.javax.print.ipp.attribute.supported.GeneratedNaturalLanguageSupported;
62 import gnu.javax.print.ipp.attribute.supported.JobHoldUntilSupported;
63 import gnu.javax.print.ipp.attribute.supported.JobSheetsSupported;
64 import gnu.javax.print.ipp.attribute.supported.MediaSupported;
65 import gnu.javax.print.ipp.attribute.supported.PrinterResolutionSupported;
66 import gnu.javax.print.ipp.attribute.supported.PrinterUriSupported;
68 import java.io.ByteArrayOutputStream;
69 import java.io.DataInputStream;
70 import java.io.IOException;
71 import java.io.InputStream;
73 import java.net.URISyntaxException;
74 import java.util.ArrayList;
75 import java.util.Calendar;
76 import java.util.Date;
77 import java.util.HashMap;
78 import java.util.HashSet;
79 import java.util.List;
82 import java.util.logging.Logger;
84 import javax.print.attribute.Attribute;
85 import javax.print.attribute.standard.CopiesSupported;
86 import javax.print.attribute.standard.DateTimeAtCompleted;
87 import javax.print.attribute.standard.DateTimeAtCreation;
88 import javax.print.attribute.standard.DateTimeAtProcessing;
89 import javax.print.attribute.standard.JobImpressionsSupported;
90 import javax.print.attribute.standard.JobKOctetsSupported;
91 import javax.print.attribute.standard.JobMediaSheetsSupported;
92 import javax.print.attribute.standard.JobStateReason;
93 import javax.print.attribute.standard.JobStateReasons;
94 import javax.print.attribute.standard.NumberUpSupported;
95 import javax.print.attribute.standard.PrinterMoreInfo;
96 import javax.print.attribute.standard.PrinterMoreInfoManufacturer;
97 import javax.print.attribute.standard.PrinterStateReason;
98 import javax.print.attribute.standard.PrinterStateReasons;
99 import javax.print.attribute.standard.Severity;
102 * <code>IppResponse</code> models a response received from an IPP
103 * compatible server as described in RFC 2910 IPP 1.1 Encoding and Transport.
105 * @author Wolfgang Baer (WBaer@gmx.de)
107 public class IppResponse
111 * <code>ResponseReader</code> is responsible for parsing an IPP 1.1
112 * response stream. It provides access to the attribute groups after parsing
113 * via getter methods.
115 * The enconding of a response is structured as follows (for an official
116 * description please have a look at the RFC document mentioned above):
118 * <li>version-number - 2 bytes - required</li>
119 * <li>status-code - 2 bytes - required</li>
120 * <li>request-id - 4 bytes - required</li>
121 * <li>attribute-group - n bytes - 0 or more</li>
122 * <li>end-of-attributes-tag - 1 byte - required</li>
123 * <li>data - q bytes - optional</li>
126 * Where each attribute-group (if any) is encoded as follows:
128 * <li>begin-attribute-group-tag - 1 byte</li>
129 * <li>attribute - p bytes - 0 or more</li>
132 * Encoding of attributes:
134 * <li>attribute-with-one-value - q bytes</li>
135 * <li>additional-value - r bytes - 0 or more</li>
138 * Encoding of attribute-with-one-value:
140 * <li>value-tag - 1 byte</li>
141 * <li>name-length (value is u) - 2 bytes</li>
142 * <li>name - u bytes</li>
143 * <li>value-length (value is v) - 2 bytes</li>
144 * <li>value - v bytes</li>
147 * Encoding of additional value:
149 * <li>value-tag - 1 byte</li>
150 * <li>name-length (value is 0x0000) - 2 bytes</li>
151 * <li>value-length (value is w) - 2 bytes</li>
152 * <li>value - w bytes</li>
156 * @author Wolfgang Baer (WBaer@gmx.de)
160 /** The IPP version defaults to 1.1 */
161 private static final short VERSION = 0x0101;
164 * Parses the inputstream containing the response of the IPP request.
165 * @param input the inputstream
166 * @throws IppException if unexpected exceptions occur.
167 * @throws IOException if IO problems with the underlying inputstream occur.
169 public void parseResponse(InputStream input)
170 throws IppException, IOException
172 DataInputStream stream = new DataInputStream(input);
174 short version = stream.readShort();
175 status_code = stream.readShort();
176 request_id = stream.readInt();
178 if (VERSION != version)
179 throw new IppException("Version mismatch - "
180 + "implementation does not support other versions than IPP 1.1");
182 logger.log(Component.IPP, "Statuscode: "
183 + Integer.toHexString(status_code) + " Request-ID: " + request_id);
186 boolean proceed = true;
187 HashMap<Class<? extends Attribute>, Set<Attribute>> tmp;
188 // iterate over attribute-groups until end-of-attributes-tag is found
191 if (tag == 0) // only at start time
192 tag = stream.readByte();
194 logger.log(Component.IPP, "DelimiterTag: " + Integer.toHexString(tag));
196 // check if end of attributes
199 case IppDelimiterTag.END_OF_ATTRIBUTES_TAG:
202 case IppDelimiterTag.OPERATION_ATTRIBUTES_TAG:
203 tmp = new HashMap<Class<? extends Attribute>, Set<Attribute>>();
204 tag = parseAttributes(tmp, stream);
205 operationAttributes.add(tmp);
207 case IppDelimiterTag.JOB_ATTRIBUTES_TAG:
208 tmp = new HashMap<Class<? extends Attribute>, Set<Attribute>>();
209 tag = parseAttributes(tmp, stream);
210 jobAttributes.add(tmp);
212 case IppDelimiterTag.PRINTER_ATTRIBUTES_TAG:
213 tmp = new HashMap<Class<? extends Attribute>, Set<Attribute>>();
214 tag = parseAttributes(tmp, stream);
215 printerAttributes.add(tmp);
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);
224 throw new IppException("Unknown tag with value "
225 + Integer.toHexString(tag) + " occured.");
229 // if there are more bytes that has to be data.
230 ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
231 byte[] readbuf = new byte[2048];
234 while ((len = stream.read(readbuf)) > 0)
235 byteStream.write(readbuf, 0, len);
238 data = byteStream.toByteArray();
242 * The actual parsing of the attributes and further putting into the
243 * provided group maps.
244 * @param attributes the provided attribute group map.
245 * @param stream the provided stream to read from.
246 * @return The last read tag byte (normally a DelimiterTag)
247 * @throws IppException if unexpected exceptions occur.
248 * @throws IOException if IO problems with the underlying inputstream occur.
250 private byte parseAttributes(Map<Class<? extends Attribute>, Set<Attribute>> attributes,
251 DataInputStream stream)
252 throws IppException, IOException
254 Attribute lastAttribute = null;
255 Attribute attribute = null;
257 // declaration of variables
263 // tmp variables for parsing
264 // declared here so no name duplication occurs
270 byte tag = stream.readByte();
272 if (IppDelimiterTag.isDelimiterTag(tag))
275 // it must be a value tag now
276 // so we have either a attribute-with-one-value
277 // or (if setOf is possible) an additional-value
279 // (1) Length of the name
280 nameLength = stream.readShort();
282 // (2) The name itself
283 // may be an additional-value
284 if (nameLength == 0x0000)
285 name = lastAttribute.getName();
288 byte[] nameBytes = new byte[nameLength];
289 stream.read(nameBytes);
290 name = new String(nameBytes);
293 // (3) Length of the value
294 valueLength = stream.readShort();
296 // (4) The value itself
297 value = new byte[valueLength];
303 // out-of-band values
304 case IppValueTag.UNSUPPORTED:
305 case IppValueTag.UNKNOWN:
306 // TODO implement out-of-band handling
307 // We currently throw an exception to see when it occurs - not yet :-)
308 throw new IppException(
309 "Unexpected name value for out-of-band value tag " + tag);
310 case IppValueTag.NO_VALUE:
314 case IppValueTag.INTEGER:
315 int intValue = IppUtilities.convertToInt(value);
316 attribute = IppUtilities.getIntegerAttribute(name, intValue);
319 case IppValueTag.BOOLEAN:
320 // JPS API models boolean syntax type as enums
321 // 0x01 = true, 0x00 = false - all are enums
322 attribute = IppUtilities.getEnumAttribute(name, new Integer(value[0]));
325 case IppValueTag.ENUM:
326 int intVal = IppUtilities.convertToInt(value);
327 attribute = IppUtilities.getEnumAttribute(name, new Integer(intVal));
330 case IppValueTag.OCTECTSTRING_UNSPECIFIED:
331 // none exists according to spec
332 // so lets report as exception to see when it occurs
333 throw new IppException("Unspecified octet string occured.");
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);
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];
352 if (name.equals("printer-resolution-default"))
353 attribute = new PrinterResolutionDefault(crossFeed, feed, units);
354 else if (name.equals("printer-resolution-supported")) // may be here also
355 attribute = new PrinterResolutionSupported(crossFeed, feed, units);
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]);
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);
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);
381 case IppValueTag.KEYWORD:
382 str = new String(value);
383 if (name.equals("job-hold-until-supported")) // may also be name type
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")) // setOf
396 attribute = parseJobStateReasons(value, lastAttribute);
397 else if (name.equals("printer-state-reasons")) // setOf
398 attribute = parsePrinterStateReasons(value, lastAttribute);
400 attribute = IppUtilities.getEnumAttribute(name, str);
402 // all other stuff is either an enum or needs to be mapped to an
403 // UnknownAttribute instance. Enums catched here are:
404 // ipp-versions-supported, pdl-override-supported, compression-supported
405 // uri-authentication-supported, uri-security-supported, sides-supported
406 // sides-default, multiple-document-handling-supported, multiple-document-handling-default
409 case IppValueTag.URI:
412 uri = new URI(new String(value));
414 catch (URISyntaxException e)
416 throw new IppException("Wrong URI syntax encountered.", e);
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")) // setOf
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);
435 case IppValueTag.URI_SCHEME:
436 // only one uri-scheme exists - and its an enum
437 if (name.equals("reference-uri-schemes-supported"))
438 attribute = IppUtilities.getEnumAttribute(name, new String(value));
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")) // setOf
448 attribute = new CharsetSupported(str);
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")) // setOf
458 attribute = new GeneratedNaturalLanguageSupported(str);
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")) // setOf
466 attribute = new DocumentFormatSupported(str, null);
467 else if (name.equals("document-format")) // setOf
468 attribute = new DocumentFormat(str, null);
472 throw new IppException("Unknown tag with value "
473 + Integer.toHexString(tag) + " found.");
476 if (attribute == null)
477 attribute = new UnknownAttribute(tag, name, value);
479 addAttribute(attributes, attribute);
480 lastAttribute = attribute;
482 logger.log(Component.IPP, "Attribute: " + name
483 + " Value: " + attribute.toString());
488 * Adds a new attribute to the given attribute group. If this is the fist
489 * occurence of this attribute category a new set is created and associated
490 * with its category as key.
491 * @param attributeGroup
492 * the attribute group
494 * the attribute to add
496 private void addAttribute(Map<Class<? extends Attribute>, Set<Attribute>> attributeGroup,
499 Class<? extends Attribute> clazz = attribute.getCategory();
500 Set<Attribute> attributeValues = attributeGroup.get(clazz);
502 if (attributeValues == null) // first attribute of this category
504 attributeValues = new HashSet<Attribute>();
505 attributeGroup.put(clazz, attributeValues);
508 attributeValues.add(attribute);
512 * Parses a name with or without language attribute value from the byte[]
513 * and returns the result as an object[].
514 * @param value the byte[]
515 * @param lastAttr the last attribute
516 * @return The attribute.
518 private PrinterStateReasons parsePrinterStateReasons(byte[] value, Attribute lastAttr)
520 String str = new String(value);
521 PrinterStateReasons attribute;
523 if (lastAttr instanceof PrinterStateReasons)
524 attribute = (PrinterStateReasons) lastAttr;
526 attribute = new PrinterStateReasons();
528 // special case indicating no reasons
529 if (str.equals("none"))
532 Severity severity = null;
533 PrinterStateReason reason = null;
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;
542 if (severity != null)
543 str = str.substring(0, str.lastIndexOf('-'));
544 else // we must associate a severity
545 severity = Severity.REPORT;
547 reason = (PrinterStateReason)
548 IppUtilities.getEnumAttribute("printer-state-reason", str);
550 attribute.put(reason , severity);
555 * Parses a name with or without language attribute value from the byte[]
556 * and returns the result as an object[].
557 * @param value the byte[]
558 * @param lastAttr the last attribute
559 * @return The attribute.
561 private JobStateReasons parseJobStateReasons(byte[] value, Attribute lastAttr)
563 String str = new String(value);
564 JobStateReasons attribute;
566 if (lastAttr instanceof JobStateReasons)
567 attribute = (JobStateReasons) lastAttr;
569 attribute = new JobStateReasons();
571 // special case indicating no reasons
572 if (str.equals("none"))
575 JobStateReason reason = (JobStateReason)
576 IppUtilities.getEnumAttribute("job-state-reason", str);
578 attribute.add(reason);
583 * Parses a DateTime syntax attribute and returns the constructed Date
586 * The syntax value is defined as 11 octets follwing the DateAndTime format
589 * <li>field | octets | contents | range</li>
590 * <li>1 | 1-2 | year | 0..65536</li>
591 * <li>2 | 3 | month | 1..12</li>
592 * <li>3 | 4 | day | 1..31</li>
593 * <li>4 | 5 | hour | 0..23</li>
594 * <li>5 | 6 | minutes | 0..59</li>
595 * <li>6 | 7 | seconds | 0..60 (use 60 for leap-second)</li>
596 * <li>7 | 8 | deci-seconds | 0..9</li>
597 * <li>8 | 9 | direction from UTC | '+' / '-'</li>
598 * <li>9 | 10 | hours from UTC | 0..11</li>
599 * <li>10 | 11 | minutes from UTC | 0..59</li>
603 * @param value the byte[]
604 * @return The date object.
606 private Date parseDate(byte[] value)
608 short year = IppUtilities.convertToShort(value[0], value[1]);
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); // deci-seconds
619 // offset from timezone
620 int offsetMilli = value[9] * 3600000; // hours to millis
621 offsetMilli = offsetMilli + value[10] * 60000; // minutes to millis
623 if (((char) value[8]) == '-')
624 offsetMilli = offsetMilli * (-1);
626 cal.set(Calendar.ZONE_OFFSET, offsetMilli);
627 return cal.getTime();
632 * Logger for tracing - enable by passing
633 * -Dgnu.classpath.debug.components=ipp to the vm.
635 static final Logger logger = SystemLogger.SYSTEM;
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;
650 * Creates an <code>IppResponse</code> instance.
652 * @param uri the uri the request was directy to.
653 * @param operation_id the operation id of the request.
655 public IppResponse(URI uri, short operation_id)
658 this.operation_id = operation_id;
659 operationAttributes =
660 new ArrayList<Map<Class<? extends Attribute>, Set<Attribute>>>();
662 new ArrayList<Map<Class<? extends Attribute>, Set<Attribute>>>();
664 new ArrayList<Map<Class<? extends Attribute>, Set<Attribute>>>();
665 unsupportedAttributes =
666 new ArrayList<Map<Class<? extends Attribute>, Set<Attribute>>>();
670 * Sets the data received from the request sent.
672 * @param input the input stream received.
673 * @throws IppException if parsing fails.
675 protected void setResponseData(InputStream input) throws IppException
677 ResponseReader reader = new ResponseReader();
681 reader.parseResponse(input);
683 catch (IOException e)
685 throw new IppException(
686 "Exception during response parsing caused by IOException", e);
691 * Returns the uri of the original request.
692 * @return The URI of the request.
700 * Returns the operation id of the original request.
701 * @return The operation id of the request.
703 public int getOperationID()
709 * Returns the set of job attributes group maps.
710 * There may occur more than one group of type job attribute in a response
711 * because of e.g. multiple job or print service informations requested.
713 * @return The list of job attribute group maps.
715 public List<Map<Class<? extends Attribute>, Set<Attribute>>> getJobAttributes()
717 return jobAttributes;
721 * Returns the set of operation attributes group maps.
722 * There may occur more than one group of type job attribute in a response
723 * because of e.g. multiple job or print service informations requested.
725 * @return The list of operation attribute group maps.
727 public List<Map<Class<? extends Attribute>, Set<Attribute>>> getOperationAttributes()
729 return operationAttributes;
733 * Returns the set of printer attributes group maps.
734 * There may occur more than one group of type job attribute in a response
735 * because of e.g. multiple job or print service informations requested.
737 * @return The list of printer attribute group maps.
739 public List<Map<Class<? extends Attribute>, Set<Attribute>>> getPrinterAttributes()
741 return printerAttributes;
745 * Returns the ID of the initial request.
747 * @return The request ID.
749 public int getRequestID()
755 * Returns the status code of the response.
756 * Defined in {@link IppStatusCode}.
758 * @return The status code.
760 public short getStatusCode()
766 * Returns the set of unsupported attributes group maps.
767 * There may occur more than one group of type job attribute in a response
768 * because of e.g. multiple job or print service informations requested.
770 * @return The list of unsupported attribute group maps.
772 public List<Map<Class<? extends Attribute>, Set<Attribute>>> getUnsupportedAttributes()
774 return unsupportedAttributes;
778 * Returns the data of the response.
780 * @return The data as byte[].
782 public byte[] getData()