Merge from mainline.
[official-gcc.git] / libjava / classpath / gnu / javax / print / ipp / IppRequest.java
blob8abab519282b23206cdb68f6956553a93ab85df1
1 /* IppRequest.java --
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)
9 any later version.
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
19 02110-1301 USA.
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
24 combination.
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.CharsetSyntax;
44 import gnu.javax.print.ipp.attribute.NaturalLanguageSyntax;
45 import gnu.javax.print.ipp.attribute.RequestedAttributes;
46 import gnu.javax.print.ipp.attribute.job.AttributesCharset;
47 import gnu.javax.print.ipp.attribute.job.AttributesNaturalLanguage;
48 import gnu.javax.print.ipp.attribute.job.JobId;
49 import gnu.javax.print.ipp.attribute.job.JobUri;
50 import gnu.javax.print.ipp.attribute.printer.DocumentFormat;
52 import java.io.DataOutputStream;
53 import java.io.IOException;
54 import java.io.InputStream;
55 import java.io.OutputStream;
56 import java.net.HttpURLConnection;
57 import java.net.URI;
58 import java.net.URL;
59 import java.util.Calendar;
60 import java.util.Date;
61 import java.util.GregorianCalendar;
62 import java.util.List;
63 import java.util.logging.Logger;
65 import javax.print.attribute.Attribute;
66 import javax.print.attribute.AttributeSet;
67 import javax.print.attribute.DateTimeSyntax;
68 import javax.print.attribute.EnumSyntax;
69 import javax.print.attribute.HashAttributeSet;
70 import javax.print.attribute.IntegerSyntax;
71 import javax.print.attribute.ResolutionSyntax;
72 import javax.print.attribute.SetOfIntegerSyntax;
73 import javax.print.attribute.TextSyntax;
74 import javax.print.attribute.URISyntax;
75 import javax.print.attribute.standard.Compression;
76 import javax.print.attribute.standard.Copies;
77 import javax.print.attribute.standard.DocumentName;
78 import javax.print.attribute.standard.Fidelity;
79 import javax.print.attribute.standard.Finishings;
80 import javax.print.attribute.standard.JobHoldUntil;
81 import javax.print.attribute.standard.JobImpressions;
82 import javax.print.attribute.standard.JobKOctets;
83 import javax.print.attribute.standard.JobMediaSheets;
84 import javax.print.attribute.standard.JobName;
85 import javax.print.attribute.standard.JobOriginatingUserName;
86 import javax.print.attribute.standard.JobPriority;
87 import javax.print.attribute.standard.JobSheets;
88 import javax.print.attribute.standard.Media;
89 import javax.print.attribute.standard.MultipleDocumentHandling;
90 import javax.print.attribute.standard.NumberUp;
91 import javax.print.attribute.standard.OrientationRequested;
92 import javax.print.attribute.standard.PageRanges;
93 import javax.print.attribute.standard.PrintQuality;
94 import javax.print.attribute.standard.PrinterResolution;
95 import javax.print.attribute.standard.PrinterURI;
96 import javax.print.attribute.standard.RequestingUserName;
97 import javax.print.attribute.standard.SheetCollate;
98 import javax.print.attribute.standard.Sides;
101 * <code>IppRequest</code> models a request to an IPP compatible
102 * server as described in RFC 2910 - IPP/1.1: Encoding and Transport.
103 * <p>
104 * The byte stream is structured as follows (for an official description
105 * please have a look at the RFC document mentioned above):
106 * <ul>
107 * <li>version-number - 2 bytes - required</li>
108 * <li>operation-id - 2 bytes - required</li>
109 * <li>request-id - 4 bytes - required</li>
110 * <li>attribute-group - n bytes - 0 or more</li>
111 * <li>end-of-attributes-tag - 1 byte - required</li>
112 * <li>data - q bytes - optional</li>
113 * </ul>
114 * </p>
116 * @author Wolfgang Baer (WBaer@gmx.de)
118 public class IppRequest
122 * Helper class used to write the attributes of a request
123 * into the supplied data output stream in the correct way.
125 * @author Wolfgang Baer (WBaer@gmx.de)
127 class RequestWriter
129 private DataOutputStream out;
132 * Creates a RequestWriter.
134 * @param stream the stream to write to.
136 RequestWriter(DataOutputStream stream)
138 out = stream;
142 * Writes an attribute in IntegerSyntax into the stream.
143 * @param attribute the attribute
144 * @throws IOException if thrown by the stream
146 private void write(IntegerSyntax attribute) throws IOException
148 String name = ((Attribute) attribute).getName();
149 out.writeByte(IppValueTag.INTEGER);
150 out.writeShort(name.length());
151 out.write(name.getBytes());
152 out.writeShort(4); // length, integer is 4 bytes
153 out.writeInt(attribute.getValue());
157 * Writes an attribute in EnumSyntax into the stream.
158 * @param attribute the attribute
159 * @throws IOException if thrown by the stream
161 private void write(EnumSyntax attribute) throws IOException
163 // in JPS API enum syntax is used for enums, keyword and boolean types
164 String name = ((Attribute) attribute).getName();
166 // the enum value types
167 if (attribute instanceof Finishings
168 || attribute instanceof OrientationRequested
169 || attribute instanceof PrintQuality)
171 out.writeByte(IppValueTag.ENUM);
172 out.writeShort(name.length());
173 out.write(name.getBytes());
174 out.writeShort(4); // length, enum is 4 bytes
175 out.writeInt(attribute.getValue());
177 // the boolean value type
178 else if (attribute instanceof Fidelity)
180 out.writeByte(IppValueTag.BOOLEAN);
181 out.writeShort(name.length());
182 out.write(name.getBytes());
183 out.writeShort(1); // length, boolean is 1 bytes
184 out.writeByte(attribute.getValue() == 0 ? 0x00 : 0x01);
186 // the keyword value types
187 else
189 String keyword = attribute.toString();
190 out.writeByte(IppValueTag.KEYWORD);
191 out.writeShort(name.length());
192 out.write(name.getBytes());
193 out.writeShort(keyword.length());
194 out.write(keyword.getBytes());
199 * Writes an attribute in SetOfIntegerSyntax into the stream.
200 * @param attribute the attribute
201 * @throws IOException if thrown by the stream
203 private void write(SetOfIntegerSyntax attribute) throws IOException
205 String name = ((Attribute) attribute).getName();
206 int[][] ranges = attribute.getMembers();
207 for (int i = 0; i < ranges.length; i++)
209 out.writeByte(IppValueTag.RANGEOFINTEGER);
210 if (i == 0)
212 out.writeShort(name.length());
213 out.write(name.getBytes());
215 else
216 out.writeShort(0x0000); // only name-length
218 out.writeShort(8); // range is 8 bytes
219 out.writeInt(ranges[i][0]);
220 out.writeInt(ranges[i][1]);
225 * Writes an attribute in ResolutionSyntax into the stream.
226 * @param attribute the attribute
227 * @throws IOException if thrown by the stream
229 private void write(ResolutionSyntax attribute) throws IOException
231 String name = ((Attribute) attribute).getName();
232 out.writeByte(IppValueTag.RESOLUTION);
233 out.writeShort(name.length());
234 out.write(name.getBytes());
235 out.writeShort(9); // length fixed to 9
236 out.writeInt(attribute.getCrossFeedResolution(ResolutionSyntax.DPI));
237 out.writeInt(attribute.getFeedResolution(ResolutionSyntax.DPI));
238 out.writeByte(ResolutionSyntax.DPI);
242 * Writes an attribute in DateTimeSyntax into the stream.
243 * <p>
244 * The syntax value is defined as 11 octets follwing the
245 * DateAndTime format of RFC 1903. (see IppResponse)
246 * </p>
248 * @param attribute the attribute
249 * @throws IOException if thrown by the stream
251 private void write(DateTimeSyntax attribute) throws IOException
253 String name = ((Attribute) attribute).getName();
254 out.writeByte(IppValueTag.DATETIME);
255 out.writeShort(name.length());
256 out.write(name.getBytes());
257 out.writeShort(11); // length fixed to 11
259 Date date = attribute.getValue();
260 Calendar cal = new GregorianCalendar();
261 cal.setTime(date);
263 out.writeShort(cal.get(Calendar.YEAR));
264 out.writeByte(cal.get(Calendar.MONTH));
265 out.writeByte(cal.get(Calendar.DAY_OF_MONTH));
266 out.writeByte(cal.get(Calendar.HOUR_OF_DAY));
267 out.writeByte(cal.get(Calendar.MINUTE));
268 int second = cal.get(Calendar.SECOND);
269 out.writeByte(second == 0 ? 60 : second);
270 out.writeByte(cal.get(Calendar.MILLISECOND) / 100);
272 int offsetInMillis = cal.get(Calendar.ZONE_OFFSET);
273 char directionFromUTC = '+';
274 if (offsetInMillis < 0)
276 directionFromUTC = '-';
277 offsetInMillis = offsetInMillis * (-1);
280 out.writeByte(directionFromUTC);
281 out.writeByte(offsetInMillis / 3600000); // hours
282 out.writeByte((offsetInMillis % 3600000) / 60000); // minutes
286 * Writes an attribute in TextSyntax into the stream.
287 * <p>
288 * By default attributes are qritten as TEXT_WITHOUT_LANGUAGE value-tag.
289 * As some attributes in the JPS are TextSyntax attributes but actually
290 * of NAME value-tag in IPP this method checks for these attributes and
291 * writes them as NAME_WITHOUT_LANGUAGE value-tag into the stream.
292 * </p>
294 * @param attribute the attribute
295 * @param out the stream to write to
296 * @throws IOException if thrown by the stream
298 private void write(TextSyntax attribute) throws IOException
300 // We only use *WithoutLanguage, correct according to spec.
301 String name = ((Attribute) attribute).getName();
303 if (attribute instanceof RequestingUserName
304 || attribute instanceof JobName
305 || attribute instanceof DocumentName
306 || attribute instanceof JobOriginatingUserName)
307 out.writeByte(IppValueTag.NAME_WITHOUT_LANGUAGE);
308 else if (attribute instanceof DocumentFormat)
309 out.writeByte(IppValueTag.MIME_MEDIA_TYPE);
310 else
311 out.writeByte(IppValueTag.TEXT_WITHOUT_LANGUAGE);
313 out.writeShort(name.length());
314 out.write(name.getBytes());
315 out.writeShort(attribute.getValue().length());
316 out.write(attribute.getValue().getBytes());
320 * Writes an attribute in URISyntax into the stream.
321 * @param attribute the attribute
322 * @param out the stream to write to
323 * @throws IOException if thrown by the stream
325 private void write(URISyntax attribute) throws IOException
327 // only uriScheme syntax type should not appear
328 // in a request (reference-uri-schemes-supported)
329 String name = ((Attribute) attribute).getName();
330 String uriAscii = attribute.getURI().toASCIIString();
331 out.writeByte(IppValueTag.URI);
332 out.writeShort(name.length());
333 out.write(name.getBytes());
334 out.writeShort(uriAscii.length());
335 out.write(uriAscii.getBytes());
339 * Writes an attribute in CharsetSyntax into the stream.
340 * @param attribute the attribute
341 * @param out the stream to write to
342 * @throws IOException if thrown by the stream
344 private void write(CharsetSyntax attribute) throws IOException
346 String name = ((Attribute) attribute).getName();
347 out.writeByte(IppValueTag.CHARSET);
348 out.writeShort(name.length());
349 out.write(name.getBytes());
350 out.writeShort(attribute.getValue().length());
351 out.write(attribute.getValue().getBytes());
355 * Writes an attribute in NaturalLanguageSyntax into the stream.
356 * @param attribute the attribute
357 * @param out the stream to write to
358 * @throws IOException if thrown by the stream
360 private void write(NaturalLanguageSyntax attribute) throws IOException
362 String name = ((Attribute) attribute).getName();
363 out.writeByte(IppValueTag.NATURAL_LANGUAGE);
364 out.writeShort(name.length());
365 out.write(name.getBytes());
366 out.writeShort(attribute.getValue().length());
367 out.write(attribute.getValue().getBytes());
371 * Writes an attribute in RequestedAttributes into the stream.
372 * @param attribute the attribute
373 * @param out the stream to write to
374 * @throws IOException if thrown by the stream
376 private void write(RequestedAttributes attribute) throws IOException
378 List values = attribute.getValues();
380 String name = ((Attribute) attribute).getName();
381 out.writeByte(IppValueTag.KEYWORD);
382 out.writeShort(name.length());
383 out.write(name.getBytes());
384 out.writeShort(((String) values.get(0)).length());
385 out.write(((String) values.get(0)).getBytes());
387 for (int i=1; i < values.size(); i++)
389 out.writeByte(IppValueTag.KEYWORD);
390 out.writeShort(0x0000); // length for additional value
391 out.writeShort(((String) values.get(i)).length());
392 out.write(((String) values.get(i)).getBytes());
398 * Writes the given operation attribute group of the given map instance
399 * (key=group, values=set of attributes) into the supplied data
400 * output stream.
402 * @param attributes the set with the attributes.
404 * @throws IOException if thrown by the used DataOutputStream.
405 * @throws IppException if unknown attributes occur.
407 public void writeOperationAttributes(AttributeSet attributes)
408 throws IOException, IppException
410 out.write(IppDelimiterTag.OPERATION_ATTRIBUTES_TAG);
412 // its essential to write these two in this order and as first ones
413 Attribute att = attributes.get(AttributesCharset.class);
414 write((CharsetSyntax) att);
416 logger.log(Component.IPP, "Attribute: Name: <"
417 + att.getCategory().getName() + "> Value: <" + att.toString() + ">");
419 attributes.remove(AttributesCharset.class);
421 att = attributes.get(AttributesNaturalLanguage.class);
422 write((NaturalLanguageSyntax) att);
423 attributes.remove(AttributesNaturalLanguage.class);
425 logger.log(Component.IPP, "Attribute: Name: <"
426 + att.getCategory().getName() + "> Value: <" + att.toString() + ">");
428 // furthermore its essential to now write out the target attribute
429 PrinterURI printerUri = (PrinterURI) attributes.get(PrinterURI.class);
430 JobUri jobUri = (JobUri) attributes.get(JobUri.class);
431 JobId jobId = (JobId) attributes.get(JobId.class);
432 if (printerUri != null && jobId == null && jobUri == null)
434 write(printerUri);
435 attributes.remove(PrinterURI.class);
436 logger.log(Component.IPP, "Attribute: Name: <" + printerUri
437 .getCategory().getName() + "> Value: <" + printerUri.toString() + ">");
439 else if (jobUri != null && jobId == null && printerUri == null)
441 write(jobUri);
442 attributes.remove(JobUri.class);
443 logger.log(Component.IPP, "Attribute: Name: <" + jobUri
444 .getCategory().getName() + "> Value: <" + jobUri.toString() + ">");
446 else if (printerUri != null && jobId != null && jobUri == null)
448 write(printerUri); // must be third
449 write(jobId);
450 attributes.remove(PrinterURI.class);
451 attributes.remove(JobId.class);
452 logger.log(Component.IPP, "Attribute: Name: <" + printerUri
453 .getCategory().getName() + "> Value: <" + printerUri.toString() + ">");
454 logger.log(Component.IPP, "Attribute: Name: <" + jobId.getCategory()
455 .getName() + "> Value: <" + jobId.toString() + ">");
457 else if (jobUri != null && jobId != null)
459 write(jobUri);
460 attributes.remove(JobUri.class);
461 attributes.remove(JobId.class); // MUST NOT redundant
462 logger.log(Component.IPP, "Attribute: Name: <" + jobUri.getCategory()
463 .getName() + "> Value: <" + jobUri.toString() + ">");
465 else
467 new IppException("Unknown target operation attribute combination.");
470 writeAttributes(attributes);
474 * Writes the given attribute groups of the given map instance
475 * (key=group, values=set of attributes) into the supplied data
476 * output stream.
478 * @param attributes the set with the attributes.
480 * @throws IOException if thrown by the used DataOutputStream.
481 * @throws IppException if unknown attributes occur.
483 public void writeAttributes(AttributeSet attributes)
484 throws IOException, IppException
486 Attribute[] attributeArray = attributes.toArray();
487 for (int i = 0; i < attributeArray.length; i++)
489 logger.log(Component.IPP, "Attribute: Name: <" + attributeArray[i]
490 .getCategory().getName() + "> Value: <"
491 + attributeArray[i].toString() + ">");
493 if (attributeArray[i] instanceof IntegerSyntax)
494 write((IntegerSyntax) attributeArray[i]);
495 else if (attributeArray[i] instanceof TextSyntax)
496 write((TextSyntax) attributeArray[i]);
497 else if (attributeArray[i] instanceof DateTimeSyntax)
498 write((DateTimeSyntax) attributeArray[i]);
499 else if (attributeArray[i] instanceof ResolutionSyntax)
500 write((ResolutionSyntax) attributeArray[i]);
501 else if (attributeArray[i] instanceof SetOfIntegerSyntax)
502 write((SetOfIntegerSyntax) attributeArray[i]);
503 else if (attributeArray[i] instanceof EnumSyntax)
504 write((EnumSyntax) attributeArray[i]);
505 else if (attributeArray[i] instanceof URISyntax)
506 write((URISyntax) attributeArray[i]);
507 else if (attributeArray[i] instanceof CharsetSyntax)
508 write((CharsetSyntax) attributeArray[i]);
509 else if (attributeArray[i] instanceof NaturalLanguageSyntax)
510 write((NaturalLanguageSyntax) attributeArray[i]);
511 else if (attributeArray[i] instanceof RequestedAttributes)
512 write((RequestedAttributes) attributeArray[i]);
513 else
514 throw new IppException("Unknown syntax type");
521 * Logger for tracing - enable by passing
522 * -Dgnu.classpath.debug.components=ipp to the vm.
524 static final Logger logger = SystemLogger.SYSTEM;
527 * The request id counter simply counts up
528 * to give unique request ids per JVM instance.
530 private static int requestIdCounter = 1;
532 /** The IPP version defaults to 1.1 */
533 private static final short VERSION = 0x0101;
535 /** Signals if the request is already on its way */
536 private boolean alreadySent = false;
538 /** The operation type of this request. */
539 private short operation_id;
541 /**
542 * The request id of this request. This is
543 * assigned automatically by the constructor.
545 private final int request_id;
547 private AttributeSet operationAttributes;
549 private AttributeSet printerAttributes;
551 private AttributeSet jobAttributes;
553 private Object data;
555 private URI requestUri;
557 /** The underlying connection - IPP is http based */
558 private HttpURLConnection connection;
561 * Creates an IPPRequest instance.
563 * @param uri the URI of the request
564 * @param user the user if any
565 * @param password the password of the supplied user
567 public IppRequest(URI uri, String user, String password)
569 request_id = incrementRequestIdCounter();
570 requestUri = uri;
574 URL url = new URL("http",
575 user == null
576 ? uri.getHost() : user + ":"
577 + password + "@" + uri.getHost(),
578 uri.getPort(), uri.getPath());
580 connection = (HttpURLConnection) url.openConnection();
581 connection.setRequestMethod("POST");
582 connection.setDoOutput(true);
584 connection.setRequestProperty("Content-type", "application/ipp");
585 connection.setRequestProperty("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2");
587 catch (IOException e)
589 // MalformedURLException - uri is already checked
590 // ProtocolException - POST is correct method type
591 // IOException -HTTPURLConnection constructor actually
592 // does never throw this exception.
593 logger.log(Component.IPP, "Unexpected IOException", e);
596 logger.log(Component.IPP, "[IppConnection] Host: " + uri.getHost()
597 + " Port: " + uri.getPort() + " Path: "
598 + uri.getPath());
602 * Synchronized method to be called by the constructor
603 * to assign a unique request id to this request.
605 * @return The unique request id.
607 private synchronized int incrementRequestIdCounter()
609 return IppRequest.requestIdCounter++;
613 * Returns the id of this request.
615 * @return The request ID.
617 public int getRequestID()
619 return request_id;
622 /**
623 * Sets the data of the request. The data used in this
624 * request will be the one of the supplied inputstream
625 * instead of the alternative byte array possibility.
627 * @param stream the input stream to use for the data.
629 public void setData(InputStream stream)
631 data = stream;
634 /**
635 * Sets the data of the request. The data used in this
636 * request will be the one of the supplied byte[]
637 * instead of the alternative input stream possibility.
639 * @param bytes the byte[] to use for the data.
641 public void setData(byte[] bytes)
643 data = bytes;
647 * Sets the operation id for this request.
649 * @param id the operation id.
651 public void setOperationID(short id)
653 operation_id = id;
657 * Adds the default values for the operation
658 * attributes "attributes-charset" and
659 * "attributes-natural-language"
661 public void setOperationAttributeDefaults()
663 if (operationAttributes == null)
664 operationAttributes = new HashAttributeSet();
666 operationAttributes.add(AttributesCharset.UTF8);
667 operationAttributes.add(AttributesNaturalLanguage.EN);
671 * Add the job attribute of this request to the given
672 * attribute set.
674 * @param attribute the job attribute.
676 public void addJobAttribute(Attribute attribute)
678 if (jobAttributes == null)
679 jobAttributes = new HashAttributeSet();
681 jobAttributes.add(attribute);
685 * Sets the printer attribute of this request to the given
686 * attribute set.
688 * @param attribute the printer attribute.
690 public void addPrinterAttributes(Attribute attribute)
692 if (printerAttributes == null)
693 printerAttributes = new HashAttributeSet();
695 printerAttributes.add(attribute);
699 * Adds the given attribute to the operation attributes set.
701 * @param attribute the operation attribute to add.
703 public void addOperationAttribute(Attribute attribute)
705 if (operationAttributes == null)
706 operationAttributes = new HashAttributeSet();
708 operationAttributes.add(attribute);
712 * Filters from the given attribute set the job operation out
713 * and adds them to the operation attributes set.
715 * @param set the attributes to filter, may not be <code>null</code>.
717 public void addAndFilterJobOperationAttributes(AttributeSet set)
719 if (operationAttributes == null)
720 operationAttributes = new HashAttributeSet();
722 // document-natural-language - not defined in JPS attributes
723 // document-format - specified outside, special treatment
724 Attribute[] tmp = set.toArray();
725 for (int i = 0; i < tmp.length; i++)
727 if (tmp[i].getCategory().equals(JobName.class)
728 || tmp[i].getCategory().equals(Fidelity.class)
729 || tmp[i].getCategory().equals(JobImpressions.class)
730 || tmp[i].getCategory().equals(JobKOctets.class)
731 || tmp[i].getCategory().equals(JobMediaSheets.class)
732 || tmp[i].getCategory().equals(Compression.class)
733 || tmp[i].getCategory().equals(DocumentName.class)
734 || tmp[i].getCategory().equals(RequestingUserName.class))
736 operationAttributes.add(tmp[i]);
741 * Filters from the given attribute set the job template attributes
742 * out and adds them to the job attributes set.
744 * @param set the attributes to filter, may not be <code>null</code>.
746 public void addAndFilterJobTemplateAttributes(AttributeSet set)
748 if (jobAttributes == null)
749 jobAttributes = new HashAttributeSet();
751 // document-natural-language - not defined in JPS attributes
752 // document-format - specified outside, special treatment
753 Attribute[] tmp = set.toArray();
754 for (int i = 0; i < tmp.length; i++)
756 if (tmp[i].getCategory().equals(JobPriority.class)
757 || tmp[i].getCategory().equals(JobHoldUntil.class)
758 || tmp[i].getCategory().equals(JobSheets.class)
759 || tmp[i].getCategory().equals(MultipleDocumentHandling.class)
760 || tmp[i].getCategory().equals(Copies.class)
761 || tmp[i].getCategory().equals(Finishings.class)
762 || tmp[i].getCategory().equals(PageRanges.class)
763 || tmp[i].getCategory().equals(NumberUp.class)
764 || tmp[i].getCategory().equals(OrientationRequested.class)
765 || tmp[i].getCategory().equals(Media.class)
766 || tmp[i].getCategory().equals(PrinterResolution.class)
767 || tmp[i].getCategory().equals(PrintQuality.class)
768 || tmp[i].getCategory().equals(SheetCollate.class)
769 || tmp[i].getCategory().equals(Sides.class))
771 jobAttributes.add(tmp[i]);
776 * Does some validation of the supplied parameters and then
777 * sends the request to the ipp server or service.
779 * @return The response if any.
781 * @throws IllegalStateException if request is already sent
782 * @throws IppException if connection or request failed.
783 * @throws IOException if writing of the header, attributes or footer fails.
785 public IppResponse send() throws IppException, IOException
787 if (alreadySent)
788 throw new IllegalStateException("Request is already sent");
790 alreadySent = true;
792 OutputStream stream = stream = connection.getOutputStream();
793 DataOutputStream out = new DataOutputStream(stream);
795 // the header 8 bytes long
796 out.writeShort(VERSION);
797 out.writeShort(operation_id);
798 out.writeInt(request_id);
800 logger.log(Component.IPP, "OperationID: " + Integer.toHexString(operation_id)
801 + " RequestID: " + request_id);
803 // Pass stuff the the attribute writer which knows how to
804 // write the attributes in correct order
805 logger.log(Component.IPP, "Operation Attributes");
807 RequestWriter writer = new RequestWriter(out);
808 writer.writeOperationAttributes(operationAttributes);
810 if (jobAttributes != null)
812 logger.log(Component.IPP, "Job Attributes");
813 out.write(IppDelimiterTag.JOB_ATTRIBUTES_TAG);
814 writer.writeAttributes(jobAttributes);
816 if (printerAttributes != null)
818 logger.log(Component.IPP, "Printer Attributes");
819 out.write(IppDelimiterTag.PRINTER_ATTRIBUTES_TAG);
820 writer.writeAttributes(printerAttributes);
823 // write the delimiter to the data
824 out.write(IppDelimiterTag.END_OF_ATTRIBUTES_TAG);
826 // check if data is byte[] or inputstream
827 if (data instanceof InputStream)
829 byte[] readbuf = new byte[2048];
830 int len = 0;
831 while( (len = ((InputStream) data).read(readbuf)) > 0)
832 out.write(readbuf, 0, len);
834 else if (data != null)
836 out.write((byte[]) data);
839 out.flush();
840 stream.flush();
842 int responseCode = responseCode = connection.getResponseCode();
844 if (responseCode == HttpURLConnection.HTTP_OK)
846 IppResponse response = new IppResponse(requestUri, operation_id);
847 response.setResponseData(connection.getInputStream());
848 return response;
851 logger.log(Component.IPP, "HTTP-Statuscode: " + responseCode);
853 throw new IppException("Request failed got HTTP status code "
854 + responseCode);