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: List 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(((String) values.get(0)).length());
390: out.write(((String) values.get(0)).getBytes());
391:
392: for (int i=1; i < values.size(); i++)
393: {
394: out.writeByte(IppValueTag.KEYWORD);
395: out.writeShort(0x0000);
396: out.writeShort(((String) values.get(i)).length());
397: out.write(((String) values.get(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: if (printerUri != null && jobId == null && jobUri == null)
438: {
439: write(printerUri);
440: attributes.remove(PrinterURI.class);
441: logger.log(Component.IPP, "Attribute: Name: <" + printerUri
442: .getCategory().getName() + "> Value: <" + printerUri.toString() + ">");
443: }
444: else if (jobUri != null && jobId == null && printerUri == null)
445: {
446: write(jobUri);
447: attributes.remove(JobUri.class);
448: logger.log(Component.IPP, "Attribute: Name: <" + jobUri
449: .getCategory().getName() + "> Value: <" + jobUri.toString() + ">");
450: }
451: else if (printerUri != null && jobId != null && jobUri == null)
452: {
453: write(printerUri);
454: write(jobId);
455: attributes.remove(PrinterURI.class);
456: attributes.remove(JobId.class);
457: logger.log(Component.IPP, "Attribute: Name: <" + printerUri
458: .getCategory().getName() + "> Value: <" + printerUri.toString() + ">");
459: logger.log(Component.IPP, "Attribute: Name: <" + jobId.getCategory()
460: .getName() + "> Value: <" + jobId.toString() + ">");
461: }
462: else if (jobUri != null && jobId != null)
463: {
464: write(jobUri);
465: attributes.remove(JobUri.class);
466: attributes.remove(JobId.class);
467: logger.log(Component.IPP, "Attribute: Name: <" + jobUri.getCategory()
468: .getName() + "> Value: <" + jobUri.toString() + ">");
469: }
470: else
471: {
472: new IppException("Unknown target operation attribute combination.");
473: }
474:
475: writeAttributes(attributes);
476: }
477:
478:
488: public void writeAttributes(AttributeSet attributes)
489: throws IOException, IppException
490: {
491: Attribute[] attributeArray = attributes.toArray();
492: for (int i = 0; i < attributeArray.length; i++)
493: {
494: logger.log(Component.IPP, "Attribute: Name: <" + attributeArray[i]
495: .getCategory().getName() + "> Value: <"
496: + attributeArray[i].toString() + ">");
497:
498: if (attributeArray[i] instanceof IntegerSyntax)
499: write((IntegerSyntax) attributeArray[i]);
500: else if (attributeArray[i] instanceof TextSyntax)
501: write((TextSyntax) attributeArray[i]);
502: else if (attributeArray[i] instanceof DateTimeSyntax)
503: write((DateTimeSyntax) attributeArray[i]);
504: else if (attributeArray[i] instanceof ResolutionSyntax)
505: write((ResolutionSyntax) attributeArray[i]);
506: else if (attributeArray[i] instanceof SetOfIntegerSyntax)
507: write((SetOfIntegerSyntax) attributeArray[i]);
508: else if (attributeArray[i] instanceof EnumSyntax)
509: write((EnumSyntax) attributeArray[i]);
510: else if (attributeArray[i] instanceof URISyntax)
511: write((URISyntax) attributeArray[i]);
512: else if (attributeArray[i] instanceof CharsetSyntax)
513: write((CharsetSyntax) attributeArray[i]);
514: else if (attributeArray[i] instanceof NaturalLanguageSyntax)
515: write((NaturalLanguageSyntax) attributeArray[i]);
516: else if (attributeArray[i] instanceof RequestedAttributes)
517: write((RequestedAttributes) attributeArray[i]);
518: else
519: throw new IppException("Unknown syntax type");
520: }
521: }
522:
523: }
524:
525:
529: static final Logger logger = SystemLogger.SYSTEM;
530:
531:
535: private static int requestIdCounter = 1;
536:
537:
538: private static final short VERSION = 0x0101;
539:
540:
541: private boolean alreadySent = false;
542:
543:
544: private short operation_id;
545:
546:
550: private final int request_id;
551:
552: private AttributeSet operationAttributes;
553:
554: private AttributeSet printerAttributes;
555:
556: private AttributeSet jobAttributes;
557:
558: private Object data;
559:
560: private URI requestUri;
561:
562:
563: private HttpURLConnection connection;
564:
565:
572: public IppRequest(URI uri, String user, String password)
573: {
574: request_id = incrementRequestIdCounter();
575: requestUri = uri;
576:
577: try
578: {
579: URL url = new URL("http",
580: user == null
581: ? uri.getHost() : user + ":"
582: + password + "@" + uri.getHost(),
583: uri.getPort(), uri.getPath());
584:
585: connection = (HttpURLConnection) url.openConnection();
586: connection.setRequestMethod("POST");
587: connection.setDoOutput(true);
588:
589: connection.setRequestProperty("Content-type", "application/ipp");
590: connection.setRequestProperty("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2");
591: }
592: catch (IOException e)
593: {
594:
595:
596:
597:
598: logger.log(Component.IPP, "Unexpected IOException", e);
599: }
600:
601: logger.log(Component.IPP, "[IppConnection] Host: " + uri.getHost()
602: + " Port: " + uri.getPort() + " Path: "
603: + uri.getPath());
604: }
605:
606:
612: private synchronized int incrementRequestIdCounter()
613: {
614: return IppRequest.requestIdCounter++;
615: }
616:
617:
622: public int getRequestID()
623: {
624: return request_id;
625: }
626:
627:
634: public void setData(InputStream stream)
635: {
636: data = stream;
637: }
638:
639:
646: public void setData(byte[] bytes)
647: {
648: data = bytes;
649: }
650:
651:
656: public void setOperationID(short id)
657: {
658: operation_id = id;
659: }
660:
661:
666: public void setOperationAttributeDefaults()
667: {
668: if (operationAttributes == null)
669: operationAttributes = new HashAttributeSet();
670:
671: operationAttributes.add(AttributesCharset.UTF8);
672: operationAttributes.add(AttributesNaturalLanguage.EN);
673: }
674:
675:
681: public void addJobAttribute(Attribute attribute)
682: {
683: if (jobAttributes == null)
684: jobAttributes = new HashAttributeSet();
685:
686: jobAttributes.add(attribute);
687: }
688:
689:
695: public void addPrinterAttributes(Attribute attribute)
696: {
697: if (printerAttributes == null)
698: printerAttributes = new HashAttributeSet();
699:
700: printerAttributes.add(attribute);
701: }
702:
703:
708: public void addOperationAttribute(Attribute attribute)
709: {
710: if (operationAttributes == null)
711: operationAttributes = new HashAttributeSet();
712:
713: operationAttributes.add(attribute);
714: }
715:
716:
722: public void addAndFilterJobOperationAttributes(AttributeSet set)
723: {
724: if (operationAttributes == null)
725: operationAttributes = new HashAttributeSet();
726:
727:
728:
729: Attribute[] tmp = set.toArray();
730: for (int i = 0; i < tmp.length; i++)
731: {
732: if (tmp[i].getCategory().equals(JobName.class)
733: || tmp[i].getCategory().equals(Fidelity.class)
734: || tmp[i].getCategory().equals(JobImpressions.class)
735: || tmp[i].getCategory().equals(JobKOctets.class)
736: || tmp[i].getCategory().equals(JobMediaSheets.class)
737: || tmp[i].getCategory().equals(Compression.class)
738: || tmp[i].getCategory().equals(DocumentName.class)
739: || tmp[i].getCategory().equals(RequestingUserName.class))
740:
741: operationAttributes.add(tmp[i]);
742: }
743: }
744:
745:
751: public void addAndFilterJobTemplateAttributes(AttributeSet set)
752: {
753: if (jobAttributes == null)
754: jobAttributes = new HashAttributeSet();
755:
756:
757:
758: Attribute[] tmp = set.toArray();
759: for (int i = 0; i < tmp.length; i++)
760: {
761: if (tmp[i].getCategory().equals(JobPriority.class)
762: || tmp[i].getCategory().equals(JobHoldUntil.class)
763: || tmp[i].getCategory().equals(JobSheets.class)
764: || tmp[i].getCategory().equals(MultipleDocumentHandling.class)
765: || tmp[i].getCategory().equals(Copies.class)
766: || tmp[i].getCategory().equals(Finishings.class)
767: || tmp[i].getCategory().equals(PageRanges.class)
768: || tmp[i].getCategory().equals(NumberUp.class)
769: || tmp[i].getCategory().equals(OrientationRequested.class)
770: || tmp[i].getCategory().equals(Media.class)
771: || tmp[i].getCategory().equals(PrinterResolution.class)
772: || tmp[i].getCategory().equals(PrintQuality.class)
773: || tmp[i].getCategory().equals(SheetCollate.class)
774: || tmp[i].getCategory().equals(Sides.class))
775:
776: jobAttributes.add(tmp[i]);
777: }
778: }
779:
780:
790: public IppResponse send() throws IppException, IOException
791: {
792: if (alreadySent)
793: throw new IllegalStateException("Request is already sent");
794:
795: alreadySent = true;
796:
797: OutputStream stream = connection.getOutputStream();
798: DataOutputStream out = new DataOutputStream(stream);
799:
800:
801: out.writeShort(VERSION);
802: out.writeShort(operation_id);
803: out.writeInt(request_id);
804:
805: logger.log(Component.IPP, "OperationID: " + Integer.toHexString(operation_id)
806: + " RequestID: " + request_id);
807:
808:
809:
810: logger.log(Component.IPP, "Operation Attributes");
811:
812: RequestWriter writer = new RequestWriter(out);
813: writer.writeOperationAttributes(operationAttributes);
814:
815: if (jobAttributes != null)
816: {
817: logger.log(Component.IPP, "Job Attributes");
818: out.write(IppDelimiterTag.JOB_ATTRIBUTES_TAG);
819: writer.writeAttributes(jobAttributes);
820: }
821: if (printerAttributes != null)
822: {
823: logger.log(Component.IPP, "Printer Attributes");
824: out.write(IppDelimiterTag.PRINTER_ATTRIBUTES_TAG);
825: writer.writeAttributes(printerAttributes);
826: }
827:
828:
829: out.write(IppDelimiterTag.END_OF_ATTRIBUTES_TAG);
830:
831:
832: if (data instanceof InputStream)
833: {
834: byte[] readbuf = new byte[2048];
835: int len = 0;
836: while( (len = ((InputStream) data).read(readbuf)) > 0)
837: out.write(readbuf, 0, len);
838: }
839: else if (data != null)
840: {
841: out.write((byte[]) data);
842: }
843:
844: out.flush();
845: stream.flush();
846:
847:
848:
849:
850: connection.setConnectTimeout( timeout );
851:
852: int responseCode = connection.getResponseCode();
853:
854: if (responseCode == HttpURLConnection.HTTP_OK)
855: {
856: IppResponse response = new IppResponse(requestUri, operation_id);
857: response.setResponseData(connection.getInputStream());
858: return response;
859: }
860:
861: logger.log(Component.IPP, "HTTP-Statuscode: " + responseCode);
862:
863: throw new IppException("Request failed got HTTP status code "
864: + responseCode);
865: }
866:
867: }