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:
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:
65: import ;
66: import ;
67: import ;
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: import ;
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:
100:
118: public class IppRequest
119: {
120:
121:
124: private static final int timeout = 1000;
125:
126:
132: class RequestWriter
133: {
134: private DataOutputStream out;
135:
136:
141: RequestWriter(DataOutputStream stream)
142: {
143: out = stream;
144: }
145:
146:
151: private void write(IntegerSyntax attribute) throws IOException
152: {
153: String name = ((Attribute) attribute).getName();
154: out.writeByte(IppValueTag.INTEGER);
155: out.writeShort(name.length());
156: out.write(name.getBytes());
157: out.writeShort(4);
158: out.writeInt(attribute.getValue());
159: }
160:
161:
166: private void write(EnumSyntax attribute) throws IOException
167: {
168:
169: String name = ((Attribute) attribute).getName();
170:
171:
172: if (attribute instanceof Finishings
173: || attribute instanceof OrientationRequested
174: || attribute instanceof PrintQuality)
175: {
176: out.writeByte(IppValueTag.ENUM);
177: out.writeShort(name.length());
178: out.write(name.getBytes());
179: out.writeShort(4);
180: out.writeInt(attribute.getValue());
181: }
182:
183: else if (attribute instanceof Fidelity)
184: {
185: out.writeByte(IppValueTag.BOOLEAN);
186: out.writeShort(name.length());
187: out.write(name.getBytes());
188: out.writeShort(1);
189: out.writeByte(attribute.getValue() == 0 ? 0x00 : 0x01);
190: }
191:
192: else
193: {
194: String keyword = attribute.toString();
195: out.writeByte(IppValueTag.KEYWORD);
196: out.writeShort(name.length());
197: out.write(name.getBytes());
198: out.writeShort(keyword.length());
199: out.write(keyword.getBytes());
200: }
201: }
202:
203:
208: private void write(SetOfIntegerSyntax attribute) throws IOException
209: {
210: String name = ((Attribute) attribute).getName();
211: int[][] ranges = attribute.getMembers();
212: for (int i = 0; i < ranges.length; i++)
213: {
214: out.writeByte(IppValueTag.RANGEOFINTEGER);
215: if (i == 0)
216: {
217: out.writeShort(name.length());
218: out.write(name.getBytes());
219: }
220: else
221: out.writeShort(0x0000);
222:
223: out.writeShort(8);
224: out.writeInt(ranges[i][0]);
225: out.writeInt(ranges[i][1]);
226: }
227: }
228:
229:
234: private void write(ResolutionSyntax attribute) throws IOException
235: {
236: String name = ((Attribute) attribute).getName();
237: out.writeByte(IppValueTag.RESOLUTION);
238: out.writeShort(name.length());
239: out.write(name.getBytes());
240: out.writeShort(9);
241: out.writeInt(attribute.getCrossFeedResolution(ResolutionSyntax.DPI));
242: out.writeInt(attribute.getFeedResolution(ResolutionSyntax.DPI));
243: out.writeByte(ResolutionSyntax.DPI);
244: }
245:
246:
256: private void write(DateTimeSyntax attribute) throws IOException
257: {
258: String name = ((Attribute) attribute).getName();
259: out.writeByte(IppValueTag.DATETIME);
260: out.writeShort(name.length());
261: out.write(name.getBytes());
262: out.writeShort(11);
263:
264: Date date = attribute.getValue();
265: Calendar cal = new GregorianCalendar();
266: cal.setTime(date);
267:
268: out.writeShort(cal.get(Calendar.YEAR));
269: out.writeByte(cal.get(Calendar.MONTH));
270: out.writeByte(cal.get(Calendar.DAY_OF_MONTH));
271: out.writeByte(cal.get(Calendar.HOUR_OF_DAY));
272: out.writeByte(cal.get(Calendar.MINUTE));
273: int second = cal.get(Calendar.SECOND);
274: out.writeByte(second == 0 ? 60 : second);
275: out.writeByte(cal.get(Calendar.MILLISECOND) / 100);
276:
277: int offsetInMillis = cal.get(Calendar.ZONE_OFFSET);
278: char directionFromUTC = '+';
279: if (offsetInMillis < 0)
280: {
281: directionFromUTC = '-';
282: offsetInMillis = offsetInMillis * (-1);
283: }
284:
285: out.writeByte(directionFromUTC);
286: out.writeByte(offsetInMillis / 3600000);
287: out.writeByte((offsetInMillis % 3600000) / 60000);
288: }
289:
290:
303: private void write(TextSyntax attribute) throws IOException
304: {
305:
306: String name = ((Attribute) attribute).getName();
307:
308: if (attribute instanceof RequestingUserName
309: || attribute instanceof JobName
310: || attribute instanceof DocumentName
311: || attribute instanceof JobOriginatingUserName)
312: out.writeByte(IppValueTag.NAME_WITHOUT_LANGUAGE);
313: else if (attribute instanceof DocumentFormat)
314: out.writeByte(IppValueTag.MIME_MEDIA_TYPE);
315: else
316: out.writeByte(IppValueTag.TEXT_WITHOUT_LANGUAGE);
317:
318: out.writeShort(name.length());
319: out.write(name.getBytes());
320: out.writeShort(attribute.getValue().length());
321: out.write(attribute.getValue().getBytes());
322: }
323:
324:
330: private void write(URISyntax attribute) throws IOException
331: {
332:
333:
334: String name = ((Attribute) attribute).getName();
335: String uriAscii = attribute.getURI().toASCIIString();
336: out.writeByte(IppValueTag.URI);
337: out.writeShort(name.length());
338: out.write(name.getBytes());
339: out.writeShort(uriAscii.length());
340: out.write(uriAscii.getBytes());
341: }
342:
343:
349: private void write(CharsetSyntax attribute) throws IOException
350: {
351: String name = ((Attribute) attribute).getName();
352: out.writeByte(IppValueTag.CHARSET);
353: out.writeShort(name.length());
354: out.write(name.getBytes());
355: out.writeShort(attribute.getValue().length());
356: out.write(attribute.getValue().getBytes());
357: }
358:
359:
365: private void write(NaturalLanguageSyntax attribute) throws IOException
366: {
367: String name = ((Attribute) attribute).getName();
368: out.writeByte(IppValueTag.NATURAL_LANGUAGE);
369: out.writeShort(name.length());
370: out.write(name.getBytes());
371: out.writeShort(attribute.getValue().length());
372: out.write(attribute.getValue().getBytes());
373: }
374:
375:
381: private void write(RequestedAttributes attribute) throws IOException
382: {
383: String[] values = attribute.getValues();
384:
385: String name = ((Attribute) attribute).getName();
386: out.writeByte(IppValueTag.KEYWORD);
387: out.writeShort(name.length());
388: out.write(name.getBytes());
389: out.writeShort(values[0].length());
390: out.write(values[0].getBytes());
391:
392: for (int i=1; i < values.length; i++)
393: {
394: out.writeByte(IppValueTag.KEYWORD);
395: out.writeShort(0x0000);
396: out.writeShort(values[i].length());
397: out.write(values[i].getBytes());
398: }
399: }
400:
401:
402:
412: public void writeOperationAttributes(AttributeSet attributes)
413: throws IOException, IppException
414: {
415: out.write(IppDelimiterTag.OPERATION_ATTRIBUTES_TAG);
416:
417:
418: Attribute att = attributes.get(AttributesCharset.class);
419: write((CharsetSyntax) att);
420:
421: logger.log(Component.IPP, "Attribute: Name: <"
422: + att.getCategory().getName() + "> Value: <" + att.toString() + ">");
423:
424: attributes.remove(AttributesCharset.class);
425:
426: att = attributes.get(AttributesNaturalLanguage.class);
427: write((NaturalLanguageSyntax) att);
428: attributes.remove(AttributesNaturalLanguage.class);
429:
430: logger.log(Component.IPP, "Attribute: Name: <"
431: + att.getCategory().getName() + "> Value: <" + att.toString() + ">");
432:
433:
434: PrinterURI printerUri = (PrinterURI) attributes.get(PrinterURI.class);
435: JobUri jobUri = (JobUri) attributes.get(JobUri.class);
436: JobId jobId = (JobId) attributes.get(JobId.class);
437: RequestedAttributes reqAttrs
438: = (RequestedAttributes)attributes.get(RequestedAttributes.class);
439: if (printerUri != null && jobId == null && jobUri == null)
440: {
441: write(printerUri);
442: attributes.remove(PrinterURI.class);
443: logger.log(Component.IPP, "Attribute: Name: <" + printerUri
444: .getCategory().getName() + "> Value: <" + printerUri.toString() + ">");
445: }
446: else if (jobUri != null && jobId == null && printerUri == null)
447: {
448: write(jobUri);
449: attributes.remove(JobUri.class);
450: logger.log(Component.IPP, "Attribute: Name: <" + jobUri
451: .getCategory().getName() + "> Value: <" + jobUri.toString() + ">");
452: }
453: else if (printerUri != null && jobId != null && jobUri == null)
454: {
455: write(printerUri);
456: write(jobId);
457: attributes.remove(PrinterURI.class);
458: attributes.remove(JobId.class);
459: logger.log(Component.IPP, "Attribute: Name: <" + printerUri
460: .getCategory().getName() + "> Value: <" + printerUri.toString() + ">");
461: logger.log(Component.IPP, "Attribute: Name: <" + jobId.getCategory()
462: .getName() + "> Value: <" + jobId.toString() + ">");
463: }
464: else if (jobUri != null && jobId != null)
465: {
466: write(jobUri);
467: attributes.remove(JobUri.class);
468: attributes.remove(JobId.class);
469: logger.log(Component.IPP, "Attribute: Name: <" + jobUri.getCategory()
470: .getName() + "> Value: <" + jobUri.toString() + ">");
471: }
472: else if (reqAttrs != null)
473: {
474: write(reqAttrs);
475: attributes.remove(RequestedAttributes.class);
476: logger.log(Component.IPP, "RequestedAttributes: <" + reqAttrs + ">");
477: }
478: else
479: {
480: throw new IppException("Unknown target operation attribute combination.");
481: }
482:
483: writeAttributes(attributes);
484: }
485:
486:
496: public void writeAttributes(AttributeSet attributes)
497: throws IOException, IppException
498: {
499: Attribute[] attributeArray = attributes.toArray();
500: for (int i = 0; i < attributeArray.length; i++)
501: {
502: logger.log(Component.IPP, "Attribute: Name: <" + attributeArray[i]
503: .getCategory().getName() + "> Value: <"
504: + attributeArray[i].toString() + ">");
505:
506: if (attributeArray[i] instanceof IntegerSyntax)
507: write((IntegerSyntax) attributeArray[i]);
508: else if (attributeArray[i] instanceof TextSyntax)
509: write((TextSyntax) attributeArray[i]);
510: else if (attributeArray[i] instanceof DateTimeSyntax)
511: write((DateTimeSyntax) attributeArray[i]);
512: else if (attributeArray[i] instanceof ResolutionSyntax)
513: write((ResolutionSyntax) attributeArray[i]);
514: else if (attributeArray[i] instanceof SetOfIntegerSyntax)
515: write((SetOfIntegerSyntax) attributeArray[i]);
516: else if (attributeArray[i] instanceof EnumSyntax)
517: write((EnumSyntax) attributeArray[i]);
518: else if (attributeArray[i] instanceof URISyntax)
519: write((URISyntax) attributeArray[i]);
520: else if (attributeArray[i] instanceof CharsetSyntax)
521: write((CharsetSyntax) attributeArray[i]);
522: else if (attributeArray[i] instanceof NaturalLanguageSyntax)
523: write((NaturalLanguageSyntax) attributeArray[i]);
524: else if (attributeArray[i] instanceof RequestedAttributes)
525: write((RequestedAttributes) attributeArray[i]);
526: else
527: throw new IppException("Unknown syntax type");
528: }
529: }
530:
531: }
532:
533:
537: static final Logger logger = SystemLogger.SYSTEM;
538:
539:
543: private static int requestIdCounter = 1;
544:
545:
546: private static final short VERSION = 0x0101;
547:
548:
549: private boolean alreadySent = false;
550:
551:
552: private short operation_id;
553:
554:
558: private final int request_id;
559:
560: private AttributeSet operationAttributes;
561:
562: private AttributeSet printerAttributes;
563:
564: private AttributeSet jobAttributes;
565:
566: private Object data;
567:
568: private URI requestUri;
569:
570:
571: private HttpURLConnection connection;
572:
573:
580: public IppRequest(URI uri, String user, String password)
581: {
582: request_id = incrementRequestIdCounter();
583: requestUri = uri;
584:
585: try
586: {
587: URL url = new URL("http",
588: user == null
589: ? uri.getHost() : user + ":"
590: + password + "@" + uri.getHost(),
591: uri.getPort(), uri.getPath());
592:
593: connection = (HttpURLConnection) url.openConnection();
594: connection.setRequestMethod("POST");
595: connection.setDoOutput(true);
596:
597: connection.setRequestProperty("Content-type", "application/ipp");
598: connection.setRequestProperty("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2");
599: }
600: catch (IOException e)
601: {
602:
603:
604:
605:
606: logger.log(Component.IPP, "Unexpected IOException", e);
607: }
608:
609: logger.log(Component.IPP, "[IppConnection] Host: " + uri.getHost()
610: + " Port: " + uri.getPort() + " Path: "
611: + uri.getPath());
612: }
613:
614:
620: private synchronized int incrementRequestIdCounter()
621: {
622: return IppRequest.requestIdCounter++;
623: }
624:
625:
630: public int getRequestID()
631: {
632: return request_id;
633: }
634:
635:
642: public void setData(InputStream stream)
643: {
644: data = stream;
645: }
646:
647:
654: public void setData(byte[] bytes)
655: {
656: data = bytes;
657: }
658:
659:
664: public void setOperationID(short id)
665: {
666: operation_id = id;
667: }
668:
669:
674: public void setOperationAttributeDefaults()
675: {
676: if (operationAttributes == null)
677: operationAttributes = new HashAttributeSet();
678:
679: operationAttributes.add(AttributesCharset.UTF8);
680: operationAttributes.add(AttributesNaturalLanguage.EN);
681: }
682:
683:
689: public void addJobAttribute(Attribute attribute)
690: {
691: if (jobAttributes == null)
692: jobAttributes = new HashAttributeSet();
693:
694: jobAttributes.add(attribute);
695: }
696:
697:
703: public void addPrinterAttributes(Attribute attribute)
704: {
705: if (printerAttributes == null)
706: printerAttributes = new HashAttributeSet();
707:
708: printerAttributes.add(attribute);
709: }
710:
711:
716: public void addOperationAttribute(Attribute attribute)
717: {
718: if (operationAttributes == null)
719: operationAttributes = new HashAttributeSet();
720:
721: operationAttributes.add(attribute);
722: }
723:
724:
730: public void addAndFilterJobOperationAttributes(AttributeSet set)
731: {
732: if (operationAttributes == null)
733: operationAttributes = new HashAttributeSet();
734:
735:
736:
737: Attribute[] tmp = set.toArray();
738: for (int i = 0; i < tmp.length; i++)
739: {
740: if (tmp[i].getCategory().equals(JobName.class)
741: || tmp[i].getCategory().equals(Fidelity.class)
742: || tmp[i].getCategory().equals(JobImpressions.class)
743: || tmp[i].getCategory().equals(JobKOctets.class)
744: || tmp[i].getCategory().equals(JobMediaSheets.class)
745: || tmp[i].getCategory().equals(Compression.class)
746: || tmp[i].getCategory().equals(DocumentName.class)
747: || tmp[i].getCategory().equals(RequestingUserName.class))
748:
749: operationAttributes.add(tmp[i]);
750: }
751: }
752:
753:
759: public void addAndFilterJobTemplateAttributes(AttributeSet set)
760: {
761: if (jobAttributes == null)
762: jobAttributes = new HashAttributeSet();
763:
764:
765:
766: Attribute[] tmp = set.toArray();
767: for (int i = 0; i < tmp.length; i++)
768: {
769: if (tmp[i].getCategory().equals(JobPriority.class)
770: || tmp[i].getCategory().equals(JobHoldUntil.class)
771: || tmp[i].getCategory().equals(JobSheets.class)
772: || tmp[i].getCategory().equals(MultipleDocumentHandling.class)
773: || tmp[i].getCategory().equals(Copies.class)
774: || tmp[i].getCategory().equals(Finishings.class)
775: || tmp[i].getCategory().equals(PageRanges.class)
776: || tmp[i].getCategory().equals(NumberUp.class)
777: || tmp[i].getCategory().equals(OrientationRequested.class)
778: || tmp[i].getCategory().equals(Media.class)
779: || tmp[i].getCategory().equals(PrinterResolution.class)
780: || tmp[i].getCategory().equals(PrintQuality.class)
781: || tmp[i].getCategory().equals(SheetCollate.class)
782: || tmp[i].getCategory().equals(Sides.class))
783:
784: jobAttributes.add(tmp[i]);
785: }
786: }
787:
788:
798: public IppResponse send() throws IppException, IOException
799: {
800: if (alreadySent)
801: throw new IllegalStateException("Request is already sent");
802:
803: alreadySent = true;
804:
805: OutputStream stream = connection.getOutputStream();
806: DataOutputStream out = new DataOutputStream(stream);
807:
808:
809: out.writeShort(VERSION);
810: out.writeShort(operation_id);
811: out.writeInt(request_id);
812:
813: logger.log(Component.IPP, "OperationID: " + Integer.toHexString(operation_id)
814: + " RequestID: " + request_id);
815:
816:
817:
818: logger.log(Component.IPP, "Operation Attributes");
819:
820: RequestWriter writer = new RequestWriter(out);
821: writer.writeOperationAttributes(operationAttributes);
822:
823: if (jobAttributes != null)
824: {
825: logger.log(Component.IPP, "Job Attributes");
826: out.write(IppDelimiterTag.JOB_ATTRIBUTES_TAG);
827: writer.writeAttributes(jobAttributes);
828: }
829: if (printerAttributes != null)
830: {
831: logger.log(Component.IPP, "Printer Attributes");
832: out.write(IppDelimiterTag.PRINTER_ATTRIBUTES_TAG);
833: writer.writeAttributes(printerAttributes);
834: }
835:
836:
837: out.write(IppDelimiterTag.END_OF_ATTRIBUTES_TAG);
838:
839:
840: if (data instanceof InputStream)
841: {
842: byte[] readbuf = new byte[2048];
843: int len = 0;
844: while( (len = ((InputStream) data).read(readbuf)) > 0)
845: out.write(readbuf, 0, len);
846: }
847: else if (data != null)
848: {
849: out.write((byte[]) data);
850: }
851:
852: out.flush();
853: stream.flush();
854:
855:
856:
857:
858: connection.setConnectTimeout( timeout );
859:
860: int responseCode = connection.getResponseCode();
861:
862: if (responseCode == HttpURLConnection.HTTP_OK)
863: {
864: IppResponse response = new IppResponse(requestUri, operation_id);
865: response.setResponseData(connection.getInputStream());
866: return response;
867: }
868:
869: logger.log(Component.IPP, "HTTP-Statuscode: " + responseCode);
870:
871: throw new IppException("Request failed got HTTP status code "
872: + responseCode);
873: }
874:
875: }