123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876 |
- /* IppRequest.java --
- Copyright (C) 2006 Free Software Foundation, Inc.
- This file is part of GNU Classpath.
- GNU Classpath is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
- GNU Classpath is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNU Classpath; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301 USA.
- Linking this library statically or dynamically with other modules is
- making a combined work based on this library. Thus, the terms and
- conditions of the GNU General Public License cover the whole
- combination.
- As a special exception, the copyright holders of this library give you
- permission to link this library with independent modules to produce an
- executable, regardless of the license terms of these independent
- modules, and to copy and distribute the resulting executable under
- terms of your choice, provided that you also meet, for each linked
- independent module, the terms and conditions of the license of that
- module. An independent module is a module which is not derived from
- or based on this library. If you modify this library, you may extend
- this exception to your version of the library, but you are not
- obligated to do so. If you do not wish to do so, delete this
- exception statement from your version. */
- package gnu.javax.print.ipp;
- import gnu.classpath.debug.Component;
- import gnu.classpath.debug.SystemLogger;
- import gnu.javax.print.ipp.attribute.CharsetSyntax;
- import gnu.javax.print.ipp.attribute.NaturalLanguageSyntax;
- import gnu.javax.print.ipp.attribute.RequestedAttributes;
- import gnu.javax.print.ipp.attribute.job.AttributesCharset;
- import gnu.javax.print.ipp.attribute.job.AttributesNaturalLanguage;
- import gnu.javax.print.ipp.attribute.job.JobId;
- import gnu.javax.print.ipp.attribute.job.JobUri;
- import gnu.javax.print.ipp.attribute.printer.DocumentFormat;
- import java.io.DataOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.net.HttpURLConnection;
- import java.net.URI;
- import java.net.URL;
- import java.util.Calendar;
- import java.util.Date;
- import java.util.GregorianCalendar;
- import java.util.List;
- import java.util.logging.Logger;
- import javax.print.attribute.Attribute;
- import javax.print.attribute.AttributeSet;
- import javax.print.attribute.DateTimeSyntax;
- import javax.print.attribute.EnumSyntax;
- import javax.print.attribute.HashAttributeSet;
- import javax.print.attribute.IntegerSyntax;
- import javax.print.attribute.ResolutionSyntax;
- import javax.print.attribute.SetOfIntegerSyntax;
- import javax.print.attribute.TextSyntax;
- import javax.print.attribute.URISyntax;
- import javax.print.attribute.standard.Compression;
- import javax.print.attribute.standard.Copies;
- import javax.print.attribute.standard.DocumentName;
- import javax.print.attribute.standard.Fidelity;
- import javax.print.attribute.standard.Finishings;
- import javax.print.attribute.standard.JobHoldUntil;
- import javax.print.attribute.standard.JobImpressions;
- import javax.print.attribute.standard.JobKOctets;
- import javax.print.attribute.standard.JobMediaSheets;
- import javax.print.attribute.standard.JobName;
- import javax.print.attribute.standard.JobOriginatingUserName;
- import javax.print.attribute.standard.JobPriority;
- import javax.print.attribute.standard.JobSheets;
- import javax.print.attribute.standard.Media;
- import javax.print.attribute.standard.MultipleDocumentHandling;
- import javax.print.attribute.standard.NumberUp;
- import javax.print.attribute.standard.OrientationRequested;
- import javax.print.attribute.standard.PageRanges;
- import javax.print.attribute.standard.PrintQuality;
- import javax.print.attribute.standard.PrinterResolution;
- import javax.print.attribute.standard.PrinterURI;
- import javax.print.attribute.standard.RequestingUserName;
- import javax.print.attribute.standard.SheetCollate;
- import javax.print.attribute.standard.Sides;
- /**
- * <code>IppRequest</code> models a request to an IPP compatible
- * server as described in RFC 2910 - IPP/1.1: Encoding and Transport.
- * <p>
- * The byte stream is structured as follows (for an official description
- * please have a look at the RFC document mentioned above):
- * <ul>
- * <li>version-number - 2 bytes - required</li>
- * <li>operation-id - 2 bytes - required</li>
- * <li>request-id - 4 bytes - required</li>
- * <li>attribute-group - n bytes - 0 or more</li>
- * <li>end-of-attributes-tag - 1 byte - required</li>
- * <li>data - q bytes - optional</li>
- * </ul>
- * </p>
- *
- * @author Wolfgang Baer (WBaer@gmx.de)
- */
- public class IppRequest
- {
- /**
- * The printer-poll timeout.
- */
- private static final int timeout = 1000;
- /**
- * Helper class used to write the attributes of a request
- * into the supplied data output stream in the correct way.
- *
- * @author Wolfgang Baer (WBaer@gmx.de)
- */
- class RequestWriter
- {
- private DataOutputStream out;
- /**
- * Creates a RequestWriter.
- *
- * @param stream the stream to write to.
- */
- RequestWriter(DataOutputStream stream)
- {
- out = stream;
- }
- /**
- * Writes an attribute in IntegerSyntax into the stream.
- * @param attribute the attribute
- * @throws IOException if thrown by the stream
- */
- private void write(IntegerSyntax attribute) throws IOException
- {
- String name = ((Attribute) attribute).getName();
- out.writeByte(IppValueTag.INTEGER);
- out.writeShort(name.length());
- out.write(name.getBytes());
- out.writeShort(4); // length, integer is 4 bytes
- out.writeInt(attribute.getValue());
- }
- /**
- * Writes an attribute in EnumSyntax into the stream.
- * @param attribute the attribute
- * @throws IOException if thrown by the stream
- */
- private void write(EnumSyntax attribute) throws IOException
- {
- // in JPS API enum syntax is used for enums, keyword and boolean types
- String name = ((Attribute) attribute).getName();
- // the enum value types
- if (attribute instanceof Finishings
- || attribute instanceof OrientationRequested
- || attribute instanceof PrintQuality)
- {
- out.writeByte(IppValueTag.ENUM);
- out.writeShort(name.length());
- out.write(name.getBytes());
- out.writeShort(4); // length, enum is 4 bytes
- out.writeInt(attribute.getValue());
- }
- // the boolean value type
- else if (attribute instanceof Fidelity)
- {
- out.writeByte(IppValueTag.BOOLEAN);
- out.writeShort(name.length());
- out.write(name.getBytes());
- out.writeShort(1); // length, boolean is 1 bytes
- out.writeByte(attribute.getValue() == 0 ? 0x00 : 0x01);
- }
- // the keyword value types
- else
- {
- String keyword = attribute.toString();
- out.writeByte(IppValueTag.KEYWORD);
- out.writeShort(name.length());
- out.write(name.getBytes());
- out.writeShort(keyword.length());
- out.write(keyword.getBytes());
- }
- }
- /**
- * Writes an attribute in SetOfIntegerSyntax into the stream.
- * @param attribute the attribute
- * @throws IOException if thrown by the stream
- */
- private void write(SetOfIntegerSyntax attribute) throws IOException
- {
- String name = ((Attribute) attribute).getName();
- int[][] ranges = attribute.getMembers();
- for (int i = 0; i < ranges.length; i++)
- {
- out.writeByte(IppValueTag.RANGEOFINTEGER);
- if (i == 0)
- {
- out.writeShort(name.length());
- out.write(name.getBytes());
- }
- else
- out.writeShort(0x0000); // only name-length
- out.writeShort(8); // range is 8 bytes
- out.writeInt(ranges[i][0]);
- out.writeInt(ranges[i][1]);
- }
- }
- /**
- * Writes an attribute in ResolutionSyntax into the stream.
- * @param attribute the attribute
- * @throws IOException if thrown by the stream
- */
- private void write(ResolutionSyntax attribute) throws IOException
- {
- String name = ((Attribute) attribute).getName();
- out.writeByte(IppValueTag.RESOLUTION);
- out.writeShort(name.length());
- out.write(name.getBytes());
- out.writeShort(9); // length fixed to 9
- out.writeInt(attribute.getCrossFeedResolution(ResolutionSyntax.DPI));
- out.writeInt(attribute.getFeedResolution(ResolutionSyntax.DPI));
- out.writeByte(ResolutionSyntax.DPI);
- }
- /**
- * Writes an attribute in DateTimeSyntax into the stream.
- * <p>
- * The syntax value is defined as 11 octets follwing the
- * DateAndTime format of RFC 1903. (see IppResponse)
- * </p>
- *
- * @param attribute the attribute
- * @throws IOException if thrown by the stream
- */
- private void write(DateTimeSyntax attribute) throws IOException
- {
- String name = ((Attribute) attribute).getName();
- out.writeByte(IppValueTag.DATETIME);
- out.writeShort(name.length());
- out.write(name.getBytes());
- out.writeShort(11); // length fixed to 11
- Date date = attribute.getValue();
- Calendar cal = new GregorianCalendar();
- cal.setTime(date);
- out.writeShort(cal.get(Calendar.YEAR));
- out.writeByte(cal.get(Calendar.MONTH));
- out.writeByte(cal.get(Calendar.DAY_OF_MONTH));
- out.writeByte(cal.get(Calendar.HOUR_OF_DAY));
- out.writeByte(cal.get(Calendar.MINUTE));
- int second = cal.get(Calendar.SECOND);
- out.writeByte(second == 0 ? 60 : second);
- out.writeByte(cal.get(Calendar.MILLISECOND) / 100);
- int offsetInMillis = cal.get(Calendar.ZONE_OFFSET);
- char directionFromUTC = '+';
- if (offsetInMillis < 0)
- {
- directionFromUTC = '-';
- offsetInMillis = offsetInMillis * (-1);
- }
- out.writeByte(directionFromUTC);
- out.writeByte(offsetInMillis / 3600000); // hours
- out.writeByte((offsetInMillis % 3600000) / 60000); // minutes
- }
- /**
- * Writes an attribute in TextSyntax into the stream.
- * <p>
- * By default attributes are qritten as TEXT_WITHOUT_LANGUAGE value-tag.
- * As some attributes in the JPS are TextSyntax attributes but actually
- * of NAME value-tag in IPP this method checks for these attributes and
- * writes them as NAME_WITHOUT_LANGUAGE value-tag into the stream.
- * </p>
- *
- * @param attribute the attribute
- * @param out the stream to write to
- * @throws IOException if thrown by the stream
- */
- private void write(TextSyntax attribute) throws IOException
- {
- // We only use *WithoutLanguage, correct according to spec.
- String name = ((Attribute) attribute).getName();
- if (attribute instanceof RequestingUserName
- || attribute instanceof JobName
- || attribute instanceof DocumentName
- || attribute instanceof JobOriginatingUserName)
- out.writeByte(IppValueTag.NAME_WITHOUT_LANGUAGE);
- else if (attribute instanceof DocumentFormat)
- out.writeByte(IppValueTag.MIME_MEDIA_TYPE);
- else
- out.writeByte(IppValueTag.TEXT_WITHOUT_LANGUAGE);
- out.writeShort(name.length());
- out.write(name.getBytes());
- out.writeShort(attribute.getValue().length());
- out.write(attribute.getValue().getBytes());
- }
- /**
- * Writes an attribute in URISyntax into the stream.
- * @param attribute the attribute
- * @param out the stream to write to
- * @throws IOException if thrown by the stream
- */
- private void write(URISyntax attribute) throws IOException
- {
- // only uriScheme syntax type should not appear
- // in a request (reference-uri-schemes-supported)
- String name = ((Attribute) attribute).getName();
- String uriAscii = attribute.getURI().toASCIIString();
- out.writeByte(IppValueTag.URI);
- out.writeShort(name.length());
- out.write(name.getBytes());
- out.writeShort(uriAscii.length());
- out.write(uriAscii.getBytes());
- }
- /**
- * Writes an attribute in CharsetSyntax into the stream.
- * @param attribute the attribute
- * @param out the stream to write to
- * @throws IOException if thrown by the stream
- */
- private void write(CharsetSyntax attribute) throws IOException
- {
- String name = ((Attribute) attribute).getName();
- out.writeByte(IppValueTag.CHARSET);
- out.writeShort(name.length());
- out.write(name.getBytes());
- out.writeShort(attribute.getValue().length());
- out.write(attribute.getValue().getBytes());
- }
- /**
- * Writes an attribute in NaturalLanguageSyntax into the stream.
- * @param attribute the attribute
- * @param out the stream to write to
- * @throws IOException if thrown by the stream
- */
- private void write(NaturalLanguageSyntax attribute) throws IOException
- {
- String name = ((Attribute) attribute).getName();
- out.writeByte(IppValueTag.NATURAL_LANGUAGE);
- out.writeShort(name.length());
- out.write(name.getBytes());
- out.writeShort(attribute.getValue().length());
- out.write(attribute.getValue().getBytes());
- }
- /**
- * Writes an attribute in RequestedAttributes into the stream.
- * @param attribute the attribute
- * @param out the stream to write to
- * @throws IOException if thrown by the stream
- */
- private void write(RequestedAttributes attribute) throws IOException
- {
- String[] values = attribute.getValues();
- String name = ((Attribute) attribute).getName();
- out.writeByte(IppValueTag.KEYWORD);
- out.writeShort(name.length());
- out.write(name.getBytes());
- out.writeShort(values[0].length());
- out.write(values[0].getBytes());
- for (int i=1; i < values.length; i++)
- {
- out.writeByte(IppValueTag.KEYWORD);
- out.writeShort(0x0000); // length for additional value
- out.writeShort(values[i].length());
- out.write(values[i].getBytes());
- }
- }
- /**
- * Writes the given operation attribute group of the given map instance
- * (key=group, values=set of attributes) into the supplied data
- * output stream.
- *
- * @param attributes the set with the attributes.
- *
- * @throws IOException if thrown by the used DataOutputStream.
- * @throws IppException if unknown attributes occur.
- */
- public void writeOperationAttributes(AttributeSet attributes)
- throws IOException, IppException
- {
- out.write(IppDelimiterTag.OPERATION_ATTRIBUTES_TAG);
- // its essential to write these two in this order and as first ones
- Attribute att = attributes.get(AttributesCharset.class);
- write((CharsetSyntax) att);
- logger.log(Component.IPP, "Attribute: Name: <"
- + att.getCategory().getName() + "> Value: <" + att.toString() + ">");
- attributes.remove(AttributesCharset.class);
- att = attributes.get(AttributesNaturalLanguage.class);
- write((NaturalLanguageSyntax) att);
- attributes.remove(AttributesNaturalLanguage.class);
- logger.log(Component.IPP, "Attribute: Name: <"
- + att.getCategory().getName() + "> Value: <" + att.toString() + ">");
- // furthermore its essential to now write out the target attribute
- PrinterURI printerUri = (PrinterURI) attributes.get(PrinterURI.class);
- JobUri jobUri = (JobUri) attributes.get(JobUri.class);
- JobId jobId = (JobId) attributes.get(JobId.class);
- RequestedAttributes reqAttrs
- = (RequestedAttributes)attributes.get(RequestedAttributes.class);
- if (printerUri != null && jobId == null && jobUri == null)
- {
- write(printerUri);
- attributes.remove(PrinterURI.class);
- logger.log(Component.IPP, "Attribute: Name: <" + printerUri
- .getCategory().getName() + "> Value: <" + printerUri.toString() + ">");
- }
- else if (jobUri != null && jobId == null && printerUri == null)
- {
- write(jobUri);
- attributes.remove(JobUri.class);
- logger.log(Component.IPP, "Attribute: Name: <" + jobUri
- .getCategory().getName() + "> Value: <" + jobUri.toString() + ">");
- }
- else if (printerUri != null && jobId != null && jobUri == null)
- {
- write(printerUri); // must be third
- write(jobId);
- attributes.remove(PrinterURI.class);
- attributes.remove(JobId.class);
- logger.log(Component.IPP, "Attribute: Name: <" + printerUri
- .getCategory().getName() + "> Value: <" + printerUri.toString() + ">");
- logger.log(Component.IPP, "Attribute: Name: <" + jobId.getCategory()
- .getName() + "> Value: <" + jobId.toString() + ">");
- }
- else if (jobUri != null && jobId != null)
- {
- write(jobUri);
- attributes.remove(JobUri.class);
- attributes.remove(JobId.class); // MUST NOT redundant
- logger.log(Component.IPP, "Attribute: Name: <" + jobUri.getCategory()
- .getName() + "> Value: <" + jobUri.toString() + ">");
- }
- else if (reqAttrs != null)
- {
- write(reqAttrs);
- attributes.remove(RequestedAttributes.class);
- logger.log(Component.IPP, "RequestedAttributes: <" + reqAttrs + ">");
- }
- else
- {
- throw new IppException("Unknown target operation attribute combination.");
- }
- writeAttributes(attributes);
- }
- /**
- * Writes the given attribute groups of the given map instance
- * (key=group, values=set of attributes) into the supplied data
- * output stream.
- *
- * @param attributes the set with the attributes.
- *
- * @throws IOException if thrown by the used DataOutputStream.
- * @throws IppException if unknown attributes occur.
- */
- public void writeAttributes(AttributeSet attributes)
- throws IOException, IppException
- {
- Attribute[] attributeArray = attributes.toArray();
- for (int i = 0; i < attributeArray.length; i++)
- {
- logger.log(Component.IPP, "Attribute: Name: <" + attributeArray[i]
- .getCategory().getName() + "> Value: <"
- + attributeArray[i].toString() + ">");
- if (attributeArray[i] instanceof IntegerSyntax)
- write((IntegerSyntax) attributeArray[i]);
- else if (attributeArray[i] instanceof TextSyntax)
- write((TextSyntax) attributeArray[i]);
- else if (attributeArray[i] instanceof DateTimeSyntax)
- write((DateTimeSyntax) attributeArray[i]);
- else if (attributeArray[i] instanceof ResolutionSyntax)
- write((ResolutionSyntax) attributeArray[i]);
- else if (attributeArray[i] instanceof SetOfIntegerSyntax)
- write((SetOfIntegerSyntax) attributeArray[i]);
- else if (attributeArray[i] instanceof EnumSyntax)
- write((EnumSyntax) attributeArray[i]);
- else if (attributeArray[i] instanceof URISyntax)
- write((URISyntax) attributeArray[i]);
- else if (attributeArray[i] instanceof CharsetSyntax)
- write((CharsetSyntax) attributeArray[i]);
- else if (attributeArray[i] instanceof NaturalLanguageSyntax)
- write((NaturalLanguageSyntax) attributeArray[i]);
- else if (attributeArray[i] instanceof RequestedAttributes)
- write((RequestedAttributes) attributeArray[i]);
- else
- throw new IppException("Unknown syntax type");
- }
- }
- }
- /**
- * Logger for tracing - enable by passing
- * -Dgnu.classpath.debug.components=ipp to the vm.
- */
- static final Logger logger = SystemLogger.SYSTEM;
- /**
- * The request id counter simply counts up
- * to give unique request ids per JVM instance.
- */
- private static int requestIdCounter = 1;
- /** The IPP version defaults to 1.1 */
- private static final short VERSION = 0x0101;
- /** Signals if the request is already on its way */
- private boolean alreadySent = false;
- /** The operation type of this request. */
- private short operation_id;
- /**
- * The request id of this request. This is
- * assigned automatically by the constructor.
- */
- private final int request_id;
- private AttributeSet operationAttributes;
- private AttributeSet printerAttributes;
- private AttributeSet jobAttributes;
- private Object data;
- private URI requestUri;
- /** The underlying connection - IPP is http based */
- private HttpURLConnection connection;
- /**
- * Creates an IPPRequest instance.
- *
- * @param uri the URI of the request
- * @param user the user if any
- * @param password the password of the supplied user
- */
- public IppRequest(URI uri, String user, String password)
- {
- request_id = incrementRequestIdCounter();
- requestUri = uri;
- try
- {
- URL url = new URL("http",
- user == null
- ? uri.getHost() : user + ":"
- + password + "@" + uri.getHost(),
- uri.getPort(), uri.getPath());
- connection = (HttpURLConnection) url.openConnection();
- connection.setRequestMethod("POST");
- connection.setDoOutput(true);
- connection.setRequestProperty("Content-type", "application/ipp");
- connection.setRequestProperty("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2");
- }
- catch (IOException e)
- {
- // MalformedURLException - uri is already checked
- // ProtocolException - POST is correct method type
- // IOException -HTTPURLConnection constructor actually
- // does never throw this exception.
- logger.log(Component.IPP, "Unexpected IOException", e);
- }
- logger.log(Component.IPP, "[IppConnection] Host: " + uri.getHost()
- + " Port: " + uri.getPort() + " Path: "
- + uri.getPath());
- }
- /**
- * Synchronized method to be called by the constructor
- * to assign a unique request id to this request.
- *
- * @return The unique request id.
- */
- private synchronized int incrementRequestIdCounter()
- {
- return IppRequest.requestIdCounter++;
- }
- /**
- * Returns the id of this request.
- *
- * @return The request ID.
- */
- public int getRequestID()
- {
- return request_id;
- }
- /**
- * Sets the data of the request. The data used in this
- * request will be the one of the supplied inputstream
- * instead of the alternative byte array possibility.
- *
- * @param stream the input stream to use for the data.
- */
- public void setData(InputStream stream)
- {
- data = stream;
- }
- /**
- * Sets the data of the request. The data used in this
- * request will be the one of the supplied byte[]
- * instead of the alternative input stream possibility.
- *
- * @param bytes the byte[] to use for the data.
- */
- public void setData(byte[] bytes)
- {
- data = bytes;
- }
- /**
- * Sets the operation id for this request.
- *
- * @param id the operation id.
- */
- public void setOperationID(short id)
- {
- operation_id = id;
- }
- /**
- * Adds the default values for the operation
- * attributes "attributes-charset" and
- * "attributes-natural-language"
- */
- public void setOperationAttributeDefaults()
- {
- if (operationAttributes == null)
- operationAttributes = new HashAttributeSet();
- operationAttributes.add(AttributesCharset.UTF8);
- operationAttributes.add(AttributesNaturalLanguage.EN);
- }
- /**
- * Add the job attribute of this request to the given
- * attribute set.
- *
- * @param attribute the job attribute.
- */
- public void addJobAttribute(Attribute attribute)
- {
- if (jobAttributes == null)
- jobAttributes = new HashAttributeSet();
- jobAttributes.add(attribute);
- }
- /**
- * Sets the printer attribute of this request to the given
- * attribute set.
- *
- * @param attribute the printer attribute.
- */
- public void addPrinterAttributes(Attribute attribute)
- {
- if (printerAttributes == null)
- printerAttributes = new HashAttributeSet();
- printerAttributes.add(attribute);
- }
- /**
- * Adds the given attribute to the operation attributes set.
- *
- * @param attribute the operation attribute to add.
- */
- public void addOperationAttribute(Attribute attribute)
- {
- if (operationAttributes == null)
- operationAttributes = new HashAttributeSet();
- operationAttributes.add(attribute);
- }
- /**
- * Filters from the given attribute set the job operation out
- * and adds them to the operation attributes set.
- *
- * @param set the attributes to filter, may not be <code>null</code>.
- */
- public void addAndFilterJobOperationAttributes(AttributeSet set)
- {
- if (operationAttributes == null)
- operationAttributes = new HashAttributeSet();
- // document-natural-language - not defined in JPS attributes
- // document-format - specified outside, special treatment
- Attribute[] tmp = set.toArray();
- for (int i = 0; i < tmp.length; i++)
- {
- if (tmp[i].getCategory().equals(JobName.class)
- || tmp[i].getCategory().equals(Fidelity.class)
- || tmp[i].getCategory().equals(JobImpressions.class)
- || tmp[i].getCategory().equals(JobKOctets.class)
- || tmp[i].getCategory().equals(JobMediaSheets.class)
- || tmp[i].getCategory().equals(Compression.class)
- || tmp[i].getCategory().equals(DocumentName.class)
- || tmp[i].getCategory().equals(RequestingUserName.class))
- operationAttributes.add(tmp[i]);
- }
- }
- /**
- * Filters from the given attribute set the job template attributes
- * out and adds them to the job attributes set.
- *
- * @param set the attributes to filter, may not be <code>null</code>.
- */
- public void addAndFilterJobTemplateAttributes(AttributeSet set)
- {
- if (jobAttributes == null)
- jobAttributes = new HashAttributeSet();
- // document-natural-language - not defined in JPS attributes
- // document-format - specified outside, special treatment
- Attribute[] tmp = set.toArray();
- for (int i = 0; i < tmp.length; i++)
- {
- if (tmp[i].getCategory().equals(JobPriority.class)
- || tmp[i].getCategory().equals(JobHoldUntil.class)
- || tmp[i].getCategory().equals(JobSheets.class)
- || tmp[i].getCategory().equals(MultipleDocumentHandling.class)
- || tmp[i].getCategory().equals(Copies.class)
- || tmp[i].getCategory().equals(Finishings.class)
- || tmp[i].getCategory().equals(PageRanges.class)
- || tmp[i].getCategory().equals(NumberUp.class)
- || tmp[i].getCategory().equals(OrientationRequested.class)
- || tmp[i].getCategory().equals(Media.class)
- || tmp[i].getCategory().equals(PrinterResolution.class)
- || tmp[i].getCategory().equals(PrintQuality.class)
- || tmp[i].getCategory().equals(SheetCollate.class)
- || tmp[i].getCategory().equals(Sides.class))
- jobAttributes.add(tmp[i]);
- }
- }
- /**
- * Does some validation of the supplied parameters and then
- * sends the request to the ipp server or service.
- *
- * @return The response if any.
- *
- * @throws IllegalStateException if request is already sent
- * @throws IppException if connection or request failed.
- * @throws IOException if writing of the header, attributes or footer fails.
- */
- public IppResponse send() throws IppException, IOException
- {
- if (alreadySent)
- throw new IllegalStateException("Request is already sent");
- alreadySent = true;
- OutputStream stream = connection.getOutputStream();
- DataOutputStream out = new DataOutputStream(stream);
- // the header 8 bytes long
- out.writeShort(VERSION);
- out.writeShort(operation_id);
- out.writeInt(request_id);
- logger.log(Component.IPP, "OperationID: " + Integer.toHexString(operation_id)
- + " RequestID: " + request_id);
- // Pass stuff the the attribute writer which knows how to
- // write the attributes in correct order
- logger.log(Component.IPP, "Operation Attributes");
- RequestWriter writer = new RequestWriter(out);
- writer.writeOperationAttributes(operationAttributes);
- if (jobAttributes != null)
- {
- logger.log(Component.IPP, "Job Attributes");
- out.write(IppDelimiterTag.JOB_ATTRIBUTES_TAG);
- writer.writeAttributes(jobAttributes);
- }
- if (printerAttributes != null)
- {
- logger.log(Component.IPP, "Printer Attributes");
- out.write(IppDelimiterTag.PRINTER_ATTRIBUTES_TAG);
- writer.writeAttributes(printerAttributes);
- }
- // write the delimiter to the data
- out.write(IppDelimiterTag.END_OF_ATTRIBUTES_TAG);
- // check if data is byte[] or inputstream
- if (data instanceof InputStream)
- {
- byte[] readbuf = new byte[2048];
- int len = 0;
- while( (len = ((InputStream) data).read(readbuf)) > 0)
- out.write(readbuf, 0, len);
- }
- else if (data != null)
- {
- out.write((byte[]) data);
- }
- out.flush();
- stream.flush();
- // Set the connection timeout, for if the printer is offline.
- // FIXME: The print services polling should probably be done in its
- // own thread.
- connection.setConnectTimeout( timeout );
- int responseCode = connection.getResponseCode();
- if (responseCode == HttpURLConnection.HTTP_OK)
- {
- IppResponse response = new IppResponse(requestUri, operation_id);
- response.setResponseData(connection.getInputStream());
- return response;
- }
- logger.log(Component.IPP, "HTTP-Statuscode: " + responseCode);
- throw new IppException("Request failed got HTTP status code "
- + responseCode);
- }
- }
|