Initial import.
authormvirak <mvirak@b34d1714-897f-11dd-9205-735403a6da14>
Tue, 23 Sep 2008 15:42:56 +0000 (15:42 +0000)
committermvirak <mvirak@b34d1714-897f-11dd-9205-735403a6da14>
Tue, 23 Sep 2008 15:42:56 +0000 (15:42 +0000)
git-svn-id: http://jspi.googlecode.com/svn/trunk@3 b34d1714-897f-11dd-9205-735403a6da14

116 files changed:
jspi/src/main/java/com/google/code/jspi/AttributeParser.java [new file with mode: 0644]
jspi/src/main/java/com/google/code/jspi/IppResponseIppImpl.java [new file with mode: 0644]
jspi/src/main/java/com/google/code/jspi/IppServlet.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/CancelableJob.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/IppConnection.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/IppHttpConnection.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/IppMultiDocPrintService.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/IppPrintService.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/IppPrintServiceLookup.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/IppPrintServiceLookupTest.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/IppPrintServiceTest.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/IppRequest.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/IppRequestCupsImpl.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/IppRequestFactory.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/IppResponse.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/IppServer.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/Job.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/MediaMultiDoc.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/MediaMultiDocJob.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/Messages.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/MultiDocEvent.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/MultiDocJob.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/MultiDocListener.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/SimpleMultiDoc.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/TestJarLookup.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/AttributeHelper.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/AttributeParser.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/AttributeWriter.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/AttributeWriterTest.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/DefaultAttribute.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/IppAttributeName.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/IppAttributeNameTest.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/IppDelimiterTag.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/IppStatus.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/IppValueTag.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/auth/RequestingUserPassword.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/cups/DeviceClass.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/cups/DeviceUri.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/cups/JobKLimit.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/cups/JobPageLimit.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/cups/JobQuotaPeriod.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/cups/MemberNames.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/cups/MemberUris.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/cups/PrinterType.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/Charset.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/DetailedStatusMessage.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/DocumentFormat.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/LastDocument.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/NaturalLanguage.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/RequestedAttributes.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/StatusMessage.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/UnknownAttribute.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/jobdesc/JobId.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/jobdesc/JobMoreInfo.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/jobdesc/JobOriginatingHostName.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/jobdesc/JobPrinterUpTime.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/jobdesc/JobPrinterUri.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/jobdesc/JobUri.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/jobdesc/LdJobStateReason.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/jobdesc/TimeAtCompleted.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/jobdesc/TimeAtCreation.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/jobdesc/TimeAtProcessing.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/jobtempl/LdJobHoldUntil.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/jobtempl/LdMediaTray.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/MultipleOperationTimeout.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/NaturalLanguageConfigured.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/PrinterCurrentTime.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/PrinterDriverInstaller.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/PrinterStateMessage.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/PrinterUpTime.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/defaults/CharsetConfigured.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/defaults/CopiesDefault.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/defaults/DocumentFormatDefault.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/defaults/FinishingsDefault.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/defaults/JobHoldUntilDefault.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/defaults/JobPriorityDefault.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/defaults/JobSheetsDefault.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/defaults/MediaDefault.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/defaults/MultipleDocumentHandlingDefault.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/defaults/NumberUpDefault.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/defaults/OrientationRequestedDefault.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/defaults/SidesDefault.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/CharsetSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/CompressionSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/DocumentFormatSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/FinishingsSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/GeneratedNaturalLanguageSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/IppVersionsSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/JobHoldUntilSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/JobSheetsSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/MediaSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/MultipleDocumentHandlingSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/MultipleDocumentJobsSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/OperationsSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/OrientationRequestedSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/OutputBinSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/PageRangesSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/PrinterUriSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/SidesSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/UriAuthenticationSupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/ipp/printerdesc/supported/UriSecuritySupported.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/attribute/undocumented/PrinterStateTime.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/examples/Messages.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/examples/MultiDocExample.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/examples/SimpleDocExample.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/examples/examples.properties [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/exception/AuthenticationException.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/exception/EndOfAttributesException.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/test.properties [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/test/IppRequestTestImpl.java [new file with mode: 0644]
jspi/src/main/java/de/lohndirekt/print/test/IppRequestTestImplTest.java [new file with mode: 0644]
jspi/src/main/webapp/META-INF/MANIFEST.MF [new file with mode: 0644]
jspi/src/main/webapp/WEB-INF/lib/commons-httpclient-2.0.1.jar [new file with mode: 0644]
jspi/src/main/webapp/WEB-INF/lib/commons-logging.jar [new file with mode: 0644]
jspi/src/main/webapp/WEB-INF/lib/junit.jar [new file with mode: 0644]
jspi/src/main/webapp/WEB-INF/web.xml [new file with mode: 0644]

diff --git a/jspi/src/main/java/com/google/code/jspi/AttributeParser.java b/jspi/src/main/java/com/google/code/jspi/AttributeParser.java
new file mode 100644 (file)
index 0000000..3af6575
--- /dev/null
@@ -0,0 +1,398 @@
+package com.google.code.jspi;\r
+\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.lang.reflect.Constructor;\r
+import java.lang.reflect.Field;\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.text.DateFormat;\r
+import java.text.DecimalFormat;\r
+import java.text.ParseException;\r
+import java.text.SimpleDateFormat;\r
+import java.util.Date;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.Locale;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import javax.print.attribute.Attribute;\r
+import javax.print.attribute.EnumSyntax;\r
+\r
+import de.lohndirekt.print.attribute.AttributeWriter;\r
+import de.lohndirekt.print.attribute.IppAttributeName;\r
+import de.lohndirekt.print.attribute.IppDelimiterTag;\r
+import de.lohndirekt.print.attribute.IppValueTag;\r
+import de.lohndirekt.print.attribute.ipp.Charset;\r
+import de.lohndirekt.print.exception.EndOfAttributesException;\r
+\r
+/**\r
+ * @author bpusch\r
+ *\r
+ */\r
+public final class AttributeParser {\r
+\r
+       private final static EndOfAttributesException END_OF_ATTRIBUTES_EXCEPTION = new EndOfAttributesException();\r
+\r
+       private final static Logger log = Logger.getLogger(AttributeParser.class.getName());\r
+\r
+       \r
+\r
+       /**\r
+        * @param name\r
+        * @param values\r
+        * @return\r
+        */\r
+       private static Attribute getAttribute(String name, Object[] values) {\r
+               Attribute attribute = null;\r
+               IppAttributeName attrName = IppAttributeName.get(name);\r
+               Class attrClass = attrName.getAttributeClass();\r
+               Class superClass = attrClass.getSuperclass();\r
+               if (superClass != null) {\r
+                       if (superClass.equals(EnumSyntax.class)) {\r
+                               try {\r
+                                       Field[] fields = attrClass.getDeclaredFields();\r
+                                       for (int i = 0; i < fields.length; i++) {\r
+                                               Field field = fields[i];\r
+                                               if (field.getType().equals(attrClass)) {\r
+                                                       EnumSyntax attr = (EnumSyntax) field.get(null);\r
+                                                       if (values[0] instanceof String) {\r
+                                                               if (attr.toString().equals(values[0])) {\r
+                                                                       attribute = (Attribute) attr;\r
+                                                                       break;\r
+                                                               }\r
+                                                       } else {\r
+                                                               if (attr.getValue() == ((Integer) values[0]).intValue()) {\r
+                                                                       attribute = (Attribute) attr;\r
+                                                                       break;\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               } catch (SecurityException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (IllegalArgumentException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (IllegalAccessException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               }\r
+\r
+                       } else {\r
+                               Class[] parameters = toClassArray(values);\r
+                               try {\r
+                                       Constructor constructor = attrClass.getDeclaredConstructor(parameters);\r
+                                       attribute = (Attribute) constructor.newInstance(values);\r
+                               } catch (SecurityException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (NoSuchMethodException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (IllegalArgumentException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (InstantiationException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (IllegalAccessException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (InvocationTargetException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               return attribute;\r
+       }\r
+\r
+       /**\r
+            * @param byteArray\r
+            * @param byteCount\r
+            * @param lastAttribute\r
+            * @return\r
+            */\r
+       private static Attribute parseAttribute(InputStream in, Attribute lastAttribute)\r
+               throws IOException, EndOfAttributesException {\r
+\r
+               int valueTag;\r
+               while ((valueTag = in.read()) < IppValueTag.UNSUPPORTED_VALUE.getValue()) {\r
+                       if (valueTag == IppDelimiterTag.END_ATTRIBUTES.getValue()) {\r
+                               throw END_OF_ATTRIBUTES_EXCEPTION;\r
+                       }\r
+               }\r
+\r
+               int nameLength = parseInt2(in);\r
+               //          parse the Attribute-Name\r
+               String name;\r
+               if (nameLength == 0) {\r
+                       name = lastAttribute.getName();\r
+               } else {\r
+                       name = parseString(in, nameLength);\r
+               }\r
+               \r
+\r
+               Object[] values = parseValues(valueTag, in);\r
+\r
+               return getAttribute(name, values);\r
+       }\r
+    \r
+    private static String parseString(InputStream in, int nameLength) throws IOException{\r
+        return parseString(in, nameLength, Charset.US_ASCII.getValue());\r
+    }\r
+    \r
+    private static String parseNameAndTextString(InputStream in, int nameLength) throws IOException{\r
+        return parseString(in, nameLength, AttributeWriter.DEFAULT_CHARSET.getValue());\r
+    }\r
+\r
+       /**\r
+        * @param in\r
+        * @param nameLength\r
+        */\r
+       private static String parseString(InputStream in, int nameLength, String charsetName) throws IOException {\r
+               byte[] bytes = new byte[nameLength];\r
+               in.read(bytes);\r
+               return new String(bytes, charsetName);\r
+\r
+       }\r
+    \r
+    \r
+    \r
+    \r
+       /**\r
+        * @param byteArray\r
+        * @param valueOffset\r
+        * @return\r
+        */\r
+       private static Date parseDate(InputStream in) throws IOException {\r
+               DecimalFormat twoDigits = new DecimalFormat("00");\r
+        DecimalFormat threeDigits = new DecimalFormat("000");\r
+               DecimalFormat fourDigits = new DecimalFormat("0000");\r
+               //year is encoded in network-byte order\r
+               int year = parseInt2(in);\r
+               int month = in.read();\r
+               int day = in.read();\r
+               int hour = in.read();\r
+               int minute = in.read();\r
+               int second = in.read();\r
+               int deci = in.read();\r
+               int mili = deci * 100;\r
+               char direction = (char) in.read();\r
+               int hoursFromUtc = in.read();\r
+               int minutesFromUtc = in.read();\r
+\r
+               String yearString = fourDigits.format(year);\r
+               String monthString = twoDigits.format(month);\r
+               String dayString = twoDigits.format(day);\r
+               String hourString = twoDigits.format(hour);\r
+               String minuteString = twoDigits.format(minute);\r
+               String secondString = twoDigits.format(second);\r
+               String miliString = threeDigits.format(mili);\r
+               String timeZone = direction + twoDigits.format(hoursFromUtc) + twoDigits.format(minutesFromUtc);\r
+               String dateString =\r
+                       yearString\r
+                               + "-"\r
+                               + monthString\r
+                               + "-"\r
+                               + dayString\r
+                               + " "\r
+                               + hourString\r
+                               + ":"\r
+                               + minuteString\r
+                               + ":"\r
+                               + secondString\r
+                               + ":"\r
+                               + miliString\r
+                               + timeZone;\r
+               DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSSZ");\r
+               Date date = null;\r
+               try {\r
+                       date = dateFormat.parse(dateString);\r
+               } catch (ParseException e) {\r
+                       log.log(Level.SEVERE, e.getMessage(), e);\r
+               }\r
+               return date;\r
+       }\r
+\r
+       private static int parseInt4(InputStream in) throws IOException {\r
+\r
+               //Same parsing as in java.io.DataInput readInt()\r
+               int a = in.read();\r
+               int b = in.read();\r
+               int c = in.read();\r
+               int d = in.read();\r
+               int value = (((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff));\r
+               return value;\r
+       }\r
+\r
+       /**\r
+        * @param bytes\r
+        * @param offset\r
+        * @return\r
+        */\r
+       private static int parseInt4(byte[] bytes, int offset) {\r
+\r
+               //Same parsing as in java.io.DataInput readInt()\r
+               byte a = bytes[offset++];\r
+               byte b = bytes[offset++];\r
+               byte c = bytes[offset++];\r
+               byte d = bytes[offset++];\r
+               int value = (((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff));\r
+               return value;\r
+       }\r
+\r
+       private static int parseInt2(InputStream in) throws IOException {\r
+\r
+               //Same parsing as in java.io.DataInput readInt()\r
+               int a = in.read();\r
+               int b = in.read();\r
+               int value = ((a & 0xff) << 8) | ((b & 0xff));\r
+               return value;\r
+       }\r
+\r
+       /**\r
+        * @param bytes\r
+        * @return map of attributes (key -> category, value -> Set with attributes)\r
+        * \r
+        *\r
+        */\r
+       public static Map parseRequest(InputStream response) throws IOException {\r
+               Map attributes = new HashMap();\r
+               long start = System.currentTimeMillis();\r
+               Attribute lastAttribute = null;\r
+               boolean finished = false;\r
+               response.read();\r
+\r
+               while (!finished) {\r
+                       Attribute attribute = null;\r
+                       try {\r
+                               attribute = parseAttribute(response, lastAttribute);\r
+                               if (attribute != null) {\r
+                                       lastAttribute = attribute;\r
+                                       attributes = put(attributes, attribute);\r
+                                       if (log.isLoggable(Level.FINEST)) {\r
+                                               log.finest("parsed attribute(" + attribute.getName() + "): " + attribute.toString());\r
+                                       }\r
+                               } else {\r
+                                       if (log.isLoggable(Level.FINEST)) {\r
+\r
+                                               log.finest("Attribute was null");\r
+                                       }\r
+                               }\r
+                       } catch (EndOfAttributesException e) {\r
+\r
+                               finished = true;\r
+                               if (log.isLoggable(Level.INFO)) {\r
+                                       log.info("--- Attribute parsing finished ---");\r
+                               }\r
+                       }\r
+               }\r
+               long end = System.currentTimeMillis();\r
+               if (log.isLoggable(Level.INFO)) {\r
+                   log.info("Parsing took " + (end - start) + "ms.");\r
+               }\r
+               return attributes;\r
+       }\r
+\r
+       \r
+       /**\r
+     * @param byteArray\r
+     * @param valueOffset\r
+     * @param valueLength\r
+     * @return\r
+     */\r
+       private static URI parseUri(InputStream in, int valueLength) throws IOException {\r
+               String uriString = parseString(in, valueLength);\r
+               URI uri = null;\r
+               try {\r
+                       uri = new URI(uriString);\r
+               } catch (URISyntaxException e) {\r
+                       throw new RuntimeException(e);\r
+               }\r
+               return uri;\r
+       }\r
+\r
+       \r
+       /**\r
+     * @param valueTag\r
+     * @param byteArray\r
+     * @param valueOffset\r
+     * @param valueLength\r
+     * @return\r
+     */\r
+       private static Object[] parseValues(int valueTag, InputStream in) throws IOException {\r
+        int valueLength = parseInt2(in);\r
+               Object[] values = null;\r
+               if (valueTag == IppValueTag.INTEGER.getValue() || valueTag == IppValueTag.ENUM.getValue()) {\r
+                       Integer number = new Integer(parseInt4(in));\r
+                       values = new Object[] { number };\r
+               } else if (\r
+                       valueTag == IppValueTag.STRING.getValue()\r
+                               || valueTag == IppValueTag.TEXT.getValue()\r
+                               || valueTag == IppValueTag.NAME.getValue()){\r
+            String word = parseNameAndTextString(in, valueLength);\r
+            values = new Object[] { word, Locale.getDefault()};                    \r
+        } else if (\r
+            valueTag == IppValueTag.CHARSET.getValue()\r
+                || valueTag == IppValueTag.LANGUAGE.getValue()\r
+                               || valueTag == IppValueTag.MIMETYPE.getValue()) {\r
+                       String word = parseString(in, valueLength);\r
+                       values = new Object[] { word, Locale.getDefault()};\r
+               } else if (valueTag == IppValueTag.URI.getValue()) {\r
+                       URI uri = parseUri(in, valueLength);\r
+                       values = new Object[] { uri };\r
+               } else if (valueTag == IppValueTag.KEYWORD.getValue()) {\r
+                       String word = parseString(in, valueLength);\r
+                       values = new Object[] { word, Locale.getDefault()};\r
+               } else if (valueTag == IppValueTag.BOOLEAN.getValue()) {\r
+                       Integer bool = new Integer(in.read());\r
+                       values = new Object[] { bool };\r
+               } else if (valueTag == IppValueTag.RANGE.getValue()) {\r
+                       Integer lowerBound = new Integer(parseInt4(in));\r
+                       Integer upperBound = new Integer(parseInt4(in));\r
+                       values = new Object[] { lowerBound, upperBound };\r
+               } else if (valueTag == IppValueTag.DATE.getValue()) {\r
+\r
+                       Date date = parseDate(in);\r
+                       values = new Object[] { date };\r
+               } else if (valueTag == IppValueTag.NOVALUE.getValue()) {\r
+                       values = new Object[] {\r
+                       };\r
+               } else {\r
+                       throw new IllegalArgumentException("\"" + Integer.toHexString(valueTag) + "\" is not a valid value-tag");\r
+               }\r
+               return values;\r
+       }\r
+\r
+\r
+       /**\r
+        * @param attributes\r
+        * @param attribute\r
+        */\r
+       private static Map put(Map attributes, Attribute attribute) {\r
+               Set values = (Set) attributes.get(attribute.getCategory());\r
+               if (values == null) {\r
+                       values = new HashSet();\r
+                       attributes.put(attribute.getCategory(), values);\r
+               }\r
+               values.add(attribute);\r
+               return attributes;\r
+       }\r
+\r
+       /**\r
+        * @param values\r
+        * @return\r
+        */\r
+       private static Class[] toClassArray(Object[] values) {\r
+               Class[] classes = new Class[values.length];\r
+               for (int i = 0; i < values.length; i++) {\r
+                       Class clazz = values[i].getClass();\r
+                       if (clazz.equals(Integer.class)) {\r
+                               clazz = int.class;\r
+                       }\r
+                       classes[i] = clazz;\r
+               }\r
+               return classes;\r
+       }\r
+\r
+}\r
diff --git a/jspi/src/main/java/com/google/code/jspi/IppResponseIppImpl.java b/jspi/src/main/java/com/google/code/jspi/IppResponseIppImpl.java
new file mode 100644 (file)
index 0000000..5c489ff
--- /dev/null
@@ -0,0 +1,151 @@
+package com.google.code.jspi;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.logging.Logger;
+
+import javax.print.attribute.Attribute;
+import javax.print.attribute.AttributeSet;
+import javax.print.attribute.HashAttributeSet;
+import javax.print.attribute.HashPrintJobAttributeSet;
+import javax.print.attribute.PrintJobAttributeSet;
+
+import de.lohndirekt.print.attribute.AttributeHelper;
+import de.lohndirekt.print.attribute.AttributeWriter;
+import de.lohndirekt.print.attribute.IppDelimiterTag;
+import de.lohndirekt.print.attribute.IppStatus;
+import de.lohndirekt.print.attribute.ipp.Charset;
+import de.lohndirekt.print.attribute.ipp.NaturalLanguage;
+
+public class IppResponseIppImpl {
+       private final Logger log = Logger.getLogger(this.getClass().getName());
+
+       private final IppStatus status;
+
+    // Id wird in der Cups-API zwar Uebergeben, ist aber auch immer 1.
+       private final int id = 1;
+
+       private final PrintJobAttributeSet jobAttributes = new HashPrintJobAttributeSet();
+
+       private final AttributeSet operationAttributes = new HashAttributeSet();
+
+       private final AttributeSet printerAttributes = new HashAttributeSet();
+    
+    private static final NaturalLanguage NATURAL_LANGUAGE_DEFAULT = NaturalLanguage.EN;
+
+       private static final Charset CHARSET_DEFAULT = Charset.UTF_8;
+       
+       public IppResponseIppImpl(IppStatus status) {
+               super();
+               this.status = status;
+        operationAttributes.add(CHARSET_DEFAULT);
+               operationAttributes.add(NATURAL_LANGUAGE_DEFAULT);
+       }
+       
+       /**
+        * @return
+        */
+       public IppStatus getStatus() {
+               return status;
+       }
+       
+    private byte[] ippFooter() {
+               byte[] footer = new byte[1];
+               footer[0] = (byte) IppDelimiterTag.END_ATTRIBUTES.getValue();
+               return footer;
+       }
+
+       private byte[] ippHeader() {
+               // Ipp header data according to http://www.ietf.org/rfc/rfc2910.txt
+               ByteArrayOutputStream out = new ByteArrayOutputStream(8);
+               // The first 2 bytes represent the IPP version number (1.1)
+               // major version-number
+               out.write((byte) 1);
+               // minor version-number
+               out.write((byte) 1);
+               // 2 byte status id
+               AttributeWriter.writeInt2(this.status.getStatus(), out);
+               // 4 byte request id
+               AttributeWriter.writeInt4(this.id, out);
+               return out.toByteArray();
+       }
+       
+    private byte[] ippAttributes() throws UnsupportedEncodingException {
+               ByteArrayOutputStream out = new ByteArrayOutputStream();
+               operationAttributes(out);
+               printerAttributes(out);
+               jobAttributes(out);
+               byte[] body = out.toByteArray();
+               return body;
+       }
+
+       /**
+        * @param out
+        * @return
+        */
+       private void jobAttributes(ByteArrayOutputStream out)
+                       throws UnsupportedEncodingException {
+               if (!jobAttributes.isEmpty()) {
+                       out.write((byte) IppDelimiterTag.BEGIN_JOB_ATTRIBUTES.getValue());
+                       for (int i = 0; i < jobAttributes.toArray().length; i++) {
+                               Attribute attribute = jobAttributes.toArray()[i];
+                               AttributeWriter.attributeBytes(attribute, out);
+                       }
+               }
+       }
+
+       /**
+        * 
+        * @param out
+        * @return
+        */
+       private void printerAttributes(ByteArrayOutputStream out)
+                       throws UnsupportedEncodingException {
+               if (!printerAttributes.isEmpty()) {
+                       out.write((byte) IppDelimiterTag.BEGIN_PRINTER_ATTRIBUTES
+                                       .getValue());
+                       Attribute[] attributes = printerAttributes.toArray();
+                       for (int i = 0; i < attributes.length; i++) {
+                               AttributeWriter.attributeBytes(attributes[i], out);
+                       }
+               }
+       }
+
+       /**
+        * 
+        * @param out
+        * @return
+        */
+       private void operationAttributes(ByteArrayOutputStream out)
+                       throws UnsupportedEncodingException {
+               if (!operationAttributes.isEmpty()) {
+                       out.write((byte) IppDelimiterTag.BEGIN_OPERATION_ATTRIBUTES
+                                       .getValue());
+                       Attribute[] attributes = AttributeHelper
+                                       .getOrderedOperationAttributeArray(operationAttributes);
+                       for (int i = 0; i < attributes.length; i++) {
+                               AttributeWriter.attributeBytes(attributes[i], out);
+                       }
+               }
+       }
+    
+       public void write(OutputStream os) throws IOException {
+               os.write(this.ippHeader());
+               os.write(this.ippAttributes());
+               os.write(this.ippFooter());
+       }
+
+       public PrintJobAttributeSet getJobAttributes() {
+               return jobAttributes;
+       }
+
+       public AttributeSet getOperationAttributes() {
+               return operationAttributes;
+       }
+
+       public AttributeSet getPrinterAttributes() {
+               return printerAttributes;
+       }
+
+}
diff --git a/jspi/src/main/java/com/google/code/jspi/IppServlet.java b/jspi/src/main/java/com/google/code/jspi/IppServlet.java
new file mode 100644 (file)
index 0000000..5b876ed
--- /dev/null
@@ -0,0 +1,104 @@
+package com.google.code.jspi;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import de.lohndirekt.print.attribute.IppStatus;
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.OperationsSupported;
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.PrinterUriSupported;
+
+/**
+ * Servlet implementation class IppServlet
+ */
+public class IppServlet extends HttpServlet {
+       private static final long serialVersionUID = 1L;
+    
+       private Map attributes;
+       private OperationsSupported operationId;
+       private byte[] jobdata;
+    
+       /**
+        * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
+        */
+       @Override
+       protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+        System.out.println("");
+        System.out.println("H E A D E R S");
+        System.out.println("");
+        Enumeration headerNames = request.getHeaderNames();
+        while (headerNames.hasMoreElements()) {
+                       String headerName = (String) headerNames.nextElement();
+                       System.out
+                                       .println(headerName + ":" + request.getHeader(headerName));
+               }
+               System.out.println("");
+               System.out.println("B O D Y");
+               System.out.println("");
+               ServletInputStream inputStream = request.getInputStream();
+               parseRequest(inputStream);
+               System.out.println("Operazione richiesta : 0x"
+                               + Integer.toHexString(this.operationId.getValue()));
+               if (this.operationId.getValue() == OperationsSupported.CUPS_GET_PRINTERS
+                               .getValue()) {
+                       IppResponseIppImpl ippresponse = new IppResponseIppImpl(
+                                       IppStatus.SUCCESSFUL_OK);
+                       try {
+                               ippresponse.getPrinterAttributes().add(
+                                               new PrinterUriSupported(new URI(
+                                                               "http://127.0.0.1:9090/ipp/IppServlet")));
+                       } catch (URISyntaxException e) {
+                               e.printStackTrace();
+                       }
+                       ippresponse.write(response.getOutputStream());
+               }
+               
+               if (this.operationId.getValue() == OperationsSupported.PRINT_JOB
+                               .getValue()) {
+                       IppResponseIppImpl ippresponse = new IppResponseIppImpl(
+                                       IppStatus.SUCCESSFUL_OK);
+                       ippresponse.write(response.getOutputStream());
+                       java.io.File tempFile = java.io.File
+                                       .createTempFile("unijob", "tmp");
+                       FileOutputStream faos = new FileOutputStream(tempFile);
+                       faos.write(this.jobdata);
+                       faos.close();
+                       System.out.println("Scritti : [" + this.jobdata.length
+                                       + "] bytes in : [" + tempFile.getAbsolutePath() + "]");
+               }
+
+               response.getOutputStream().close();
+       }
+       
+    private void parseRequest(InputStream request) throws IOException {
+               byte[] header = new byte[8];
+               request.read(header);
+               this.operationId = new OperationsSupported((header[2] << 8) + header[3]);
+               if (request.available() != 0) {
+                       this.attributes = AttributeParser.parseRequest(request);
+               } else {
+                       this.attributes = new HashMap();
+               }
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();
+               while (request.available() != 0) {
+                       baos.write(request.read());
+               }
+               baos.close();
+               this.jobdata = baos.toByteArray();
+               request.close();
+       }
+
+}
diff --git a/jspi/src/main/java/de/lohndirekt/print/CancelableJob.java b/jspi/src/main/java/de/lohndirekt/print/CancelableJob.java
new file mode 100644 (file)
index 0000000..e60783b
--- /dev/null
@@ -0,0 +1,73 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */package de.lohndirekt.print;\r
+\r
+import java.io.IOException;\r
+import java.util.logging.Level;\r
+\r
+import javax.print.CancelablePrintJob;\r
+import javax.print.PrintException;\r
+import javax.print.attribute.AttributeSet;\r
+import javax.print.attribute.HashAttributeSet;\r
+import javax.print.event.PrintJobEvent;\r
+\r
+import de.lohndirekt.print.attribute.IppStatus;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.OperationsSupported;\r
+\r
+/**\r
+ * @author bpusch\r
+ *\r
+ */\r
+class CancelableJob extends Job implements CancelablePrintJob{\r
+    \r
+    \r
+       /**\r
+        * @param service\r
+        */\r
+       public CancelableJob(IppPrintService service) {\r
+               super(service);\r
+       }\r
+    \r
+    public void cancel() throws PrintException {\r
+            if (!ok) {\r
+                throw new PrintException("Job has not been sent. Cannot be canceled");\r
+            }\r
+            AttributeSet operationAttributes = new HashAttributeSet();\r
+            operationAttributes.add(this.jobUri);\r
+            try {\r
+                IppResponse response =\r
+                    sendRequest(\r
+                        OperationsSupported.CANCEL_JOB,\r
+                        operationAttributes);\r
+                if (response.getStatus().equals(IppStatus.SUCCESSFUL_OK)\r
+                    || response.getStatus().equals(\r
+                        IppStatus.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES)\r
+                    || response.getStatus().equals(\r
+                        IppStatus.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES)) {\r
+                    notifyJobListeners(PrintJobEvent.JOB_CANCELED);\r
+                }\r
+            } catch (IOException e) {\r
+                log.log(Level.SEVERE, e.getMessage(), e);\r
+                throw new PrintException("Cannot be canceled: IOException", e);\r
+            }\r
+        }\r
+    \r
+    \r
+    \r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/IppConnection.java b/jspi/src/main/java/de/lohndirekt/print/IppConnection.java
new file mode 100644 (file)
index 0000000..44081c8
--- /dev/null
@@ -0,0 +1,50 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+\r
+import org.apache.commons.httpclient.HttpException;\r
+\r
+/**\r
+ *  \r
+ * @author sefftinge\r
+ * \r
+ */\r
+interface IppConnection {\r
+    /**\r
+     * @return content of the response\r
+     * @throws IOException\r
+     */\r
+    public abstract InputStream getIppResponse() throws IOException;\r
+\r
+    /**\r
+     * @return the statuscode of last request\r
+     * @throws IOException\r
+     */\r
+    public abstract int getStatusCode() throws IOException;\r
+\r
+    /**\r
+     * @param stream\r
+     */\r
+    public abstract void setIppRequest(InputStream stream);\r
+\r
+    public abstract boolean execute() throws HttpException, IOException;\r
+}
\ No newline at end of file
diff --git a/jspi/src/main/java/de/lohndirekt/print/IppHttpConnection.java b/jspi/src/main/java/de/lohndirekt/print/IppHttpConnection.java
new file mode 100644 (file)
index 0000000..d0e4e24
--- /dev/null
@@ -0,0 +1,135 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.net.HttpURLConnection;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import org.apache.commons.httpclient.Credentials;\r
+import org.apache.commons.httpclient.HttpClient;\r
+import org.apache.commons.httpclient.HttpException;\r
+import org.apache.commons.httpclient.UsernamePasswordCredentials;\r
+import org.apache.commons.httpclient.methods.EntityEnclosingMethod;\r
+import org.apache.commons.httpclient.methods.PostMethod;\r
+\r
+import de.lohndirekt.print.exception.AuthenticationException;\r
+\r
+\r
+/**\r
+ * simple facade / abstraction layer to "commons httpclient"\r
+ * \r
+ * @author sefftinge\r
+ *  \r
+ */\r
+class IppHttpConnection implements IppConnection {\r
+\r
+    private Logger log = Logger.getLogger(this.getClass().getName());\r
+\r
+    private HttpClient httpConn;\r
+\r
+    private PostMethod method;\r
+\r
+    /**\r
+     * @param uri\r
+     * @param user\r
+     * @param passwd\r
+     * @param useStream\r
+     */\r
+    public IppHttpConnection(URI uri, String user, String passwd) {\r
+        try {\r
+            httpConn = new HttpClient();\r
+            method = new PostMethod(toHttpURI(uri).toString());\r
+            method.addRequestHeader("Content-type", "application/ipp");\r
+            method.addRequestHeader("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2");\r
+            method.setRequestContentLength(EntityEnclosingMethod.CONTENT_LENGTH_AUTO);\r
+            // authentication\r
+            if (user != null && user.trim().length() > 0) {\r
+                if (log.isLoggable(Level.FINER)) {\r
+                    log.log(Level.SEVERE, "Using username: "+user+" , passwd.length "+passwd.length());\r
+                }\r
+                method.setDoAuthentication(true);\r
+                Credentials creds = new UsernamePasswordCredentials(user,\r
+                        passwd);\r
+                httpConn.getState().setCredentials(null,\r
+                        toHttpURI(uri).getHost(), creds);\r
+                \r
+            }\r
+            \r
+        } catch (Exception e) {\r
+            log.log(Level.SEVERE, e.getMessage(), e);\r
+        }\r
+    }\r
+\r
+    \r
+    /**\r
+     * @return content of the response\r
+     * @throws IOException\r
+     */\r
+    public InputStream getIppResponse() throws IOException {\r
+        return method.getResponseBodyAsStream();\r
+    }\r
+\r
+    /**\r
+     * @return the statuscode of last request\r
+     * @throws IOException\r
+     */\r
+    public int getStatusCode() throws IOException {\r
+        return method.getStatusCode();\r
+    }\r
+\r
+    private static URI toHttpURI(URI uri) {\r
+        if (uri.getScheme().equals("ipp")) {\r
+            String uriString = uri.toString().replaceFirst("ipp", "http");\r
+            // TODO remove this hack!\r
+//            uriString = uriString.replaceAll("(\\d{1,3}\\.){3}\\d{1,3}:\\d{1,}", "127.0.0.1:631");\r
+            // endof hack\r
+            try {\r
+                uri = new URI(uriString);\r
+            } catch (URISyntaxException e) {\r
+                throw new RuntimeException("toHttpURI buggy? : uri was " + uri);\r
+            }\r
+        }\r
+        return uri;\r
+    }\r
+\r
+    /**\r
+     * @param stream\r
+     */\r
+    public void setIppRequest(InputStream stream) {\r
+        method.setRequestBody(stream);\r
+    }\r
+    \r
+    public boolean execute() throws HttpException, IOException {\r
+        if (this.method.validate()) {\r
+            httpConn.executeMethod(method);\r
+            if (this.getStatusCode()==HttpURLConnection.HTTP_UNAUTHORIZED) {\r
+                throw new AuthenticationException(method.getStatusText());\r
+            }\r
+            return true;\r
+        } else {\r
+            return false;\r
+        }\r
+    }\r
+\r
+}
\ No newline at end of file
diff --git a/jspi/src/main/java/de/lohndirekt/print/IppMultiDocPrintService.java b/jspi/src/main/java/de/lohndirekt/print/IppMultiDocPrintService.java
new file mode 100644 (file)
index 0000000..8c5a334
--- /dev/null
@@ -0,0 +1,48 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+\r
+import java.net.URI;\r
+\r
+import javax.print.MultiDocPrintJob;\r
+import javax.print.MultiDocPrintService;\r
+/**\r
+ * @author bpusch\r
+ *\r
+ * \r
+ */\r
+class IppMultiDocPrintService extends IppPrintService implements MultiDocPrintService {\r
+\r
+\r
+    /**\r
+     * @param uri\r
+     */\r
+    public IppMultiDocPrintService(URI uri){\r
+        super(uri);\r
+    }\r
+\r
+    /* (non-Javadoc)\r
+     * @see javax.print.MultiDocPrintService#createMultiDocPrintJob()\r
+     */\r
+    public MultiDocPrintJob createMultiDocPrintJob() {\r
+        return new MediaMultiDocJob(this);\r
+    }\r
+\r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/IppPrintService.java b/jspi/src/main/java/de/lohndirekt/print/IppPrintService.java
new file mode 100644 (file)
index 0000000..e99b229
--- /dev/null
@@ -0,0 +1,536 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+import java.io.IOException;\r
+import java.net.URI;\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.HashSet;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Locale;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import javax.print.DocFlavor;\r
+import javax.print.DocPrintJob;\r
+import javax.print.PrintException;\r
+import javax.print.PrintService;\r
+import javax.print.ServiceUIFactory;\r
+import javax.print.attribute.*;\r
+import javax.print.attribute.standard.PrinterURI;\r
+import javax.print.attribute.standard.RequestingUserName;\r
+import javax.print.event.PrintServiceAttributeListener;\r
+\r
+import de.lohndirekt.print.attribute.IppAttributeName;\r
+import de.lohndirekt.print.attribute.IppStatus;\r
+import de.lohndirekt.print.attribute.auth.RequestingUserPassword;\r
+import de.lohndirekt.print.attribute.ipp.DocumentFormat;\r
+import de.lohndirekt.print.attribute.ipp.jobdesc.JobId;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.DocumentFormatSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.OperationsSupported;\r
+\r
+/**\r
+ * @author bpusch\r
+ *\r
+ * \r
+ */\r
+public class IppPrintService implements PrintService {\r
+\r
+       private final Logger log = Logger.getLogger(this.getClass().getName());\r
+       private DocFlavor[] supportedFlavors = null;\r
+       private URI uri;\r
+       private RequestingUserName requestingUserName = null;\r
+       private RequestingUserPassword requestingUserPassword = null;\r
+       private Map attributes = null;\r
+       \r
+       /**\r
+        * @param uri\r
+        */\r
+       public IppPrintService(URI uri) {\r
+               this.uri = uri;\r
+       }\r
+       \r
+       \r
+\r
+       /**\r
+        * @return\r
+        */\r
+       URI getUri() {\r
+               return this.uri;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see javax.print.PrintService#getName()\r
+        */\r
+       public String getName() {\r
+               return uri.getPath().substring(uri.getPath().lastIndexOf("/") + 1);\r
+       }\r
+\r
+       /**\r
+        * \r
+        */\r
+       public void reset() {\r
+               supportedFlavors = null;\r
+               attributes = null;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see javax.print.PrintService#createPrintJob()\r
+        */\r
+       public DocPrintJob createPrintJob() {\r
+               return new CancelableJob(this);\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see javax.print.PrintService#getAttributes()\r
+        */\r
+       public PrintServiceAttributeSet getAttributes() {\r
+               PrintServiceAttributeSet set = new HashPrintServiceAttributeSet();\r
+               for (Iterator mapIter = getAllAttributes().values().iterator(); mapIter.hasNext();) {\r
+                       Set values = (Set) mapIter.next();\r
+                       for (Iterator listIter = values.iterator(); listIter.hasNext();) {\r
+                               Attribute attribute = (Attribute) listIter.next();\r
+                               if (attribute instanceof PrintServiceAttribute) {\r
+                                       set.add(attribute);\r
+                               }\r
+                       }\r
+               }\r
+               return set;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see javax.print.PrintService#getAttribute(java.lang.Class)\r
+        */\r
+       public PrintServiceAttribute getAttribute(Class category) {\r
+               if (category == null) {\r
+                       throw new NullPointerException("category must not be null");\r
+               }\r
+               //TODO As CUPS seems not to support this operation-tag (requested-attributes), we need to get all attributes\r
+               Set attributes = (Set) getAllAttributes().get(category);\r
+               if (attributes != null) {\r
+                       try {\r
+                               return (PrintServiceAttribute) attributes.iterator().next();\r
+                       } catch (ClassCastException e) {\r
+                               throw new IllegalArgumentException("category must be a Class that implements interface PrintServiceAttribute");\r
+                       }\r
+               }\r
+               return null;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see javax.print.PrintService#getSupportedDocFlavors()\r
+        */\r
+       public DocFlavor[] getSupportedDocFlavors() {\r
+               if (supportedFlavors == null) {\r
+                       List flavors = new ArrayList();\r
+                       Set flavorAttributes =\r
+                               (Set) getAllAttributes().get(IppAttributeName.DOCUMENT_FORMAT_SUPORTED.getCategory());\r
+                       if (flavorAttributes != null) {\r
+                               for (Iterator iter = flavorAttributes.iterator(); iter.hasNext();) {\r
+                                       Attribute attribute = (Attribute) iter.next();\r
+                                       String mimeType = ((DocumentFormatSupported) attribute).getValue();\r
+                                       if (mimeType.equals(DocFlavor.BYTE_ARRAY.AUTOSENSE.getMimeType())) {\r
+                                               flavors.add(DocFlavor.INPUT_STREAM.AUTOSENSE);\r
+                                       } else if (mimeType.equals(DocFlavor.BYTE_ARRAY.GIF.getMimeType())) {\r
+                                               flavors.add(DocFlavor.INPUT_STREAM.GIF);\r
+                                       } else if (mimeType.equals(DocFlavor.BYTE_ARRAY.JPEG.getMimeType())) {\r
+                                               flavors.add(DocFlavor.INPUT_STREAM.JPEG);\r
+                                       } else if (mimeType.equals(DocFlavor.BYTE_ARRAY.PCL.getMimeType())) {\r
+                                               flavors.add(DocFlavor.INPUT_STREAM.PCL);\r
+                                       } else if (mimeType.equals(DocFlavor.BYTE_ARRAY.PDF.getMimeType())) {\r
+                                               flavors.add(DocFlavor.INPUT_STREAM.PDF);\r
+                                       } else if (mimeType.equals(DocFlavor.BYTE_ARRAY.POSTSCRIPT.getMimeType())) {\r
+                                               flavors.add(DocFlavor.INPUT_STREAM.POSTSCRIPT);\r
+                                       } else if (mimeType.equals(DocFlavor.BYTE_ARRAY.PNG.getMimeType())) {\r
+                                               flavors.add(DocFlavor.INPUT_STREAM.PNG);\r
+                                       } else if (mimeType.equals(DocFlavor.BYTE_ARRAY.TEXT_HTML_HOST.getMimeType().substring(0, 9))) {\r
+                                               flavors.add(DocFlavor.INPUT_STREAM.TEXT_HTML_HOST);\r
+                                       } else if (mimeType.equals(DocFlavor.BYTE_ARRAY.TEXT_PLAIN_HOST.getMimeType().substring(0, 10))) {\r
+                                               flavors.add(DocFlavor.INPUT_STREAM.TEXT_PLAIN_HOST);\r
+                                       }\r
+                               }\r
+                       }\r
+                       DocFlavor[] flavorArray = new DocFlavor[flavors.size()];\r
+                       flavorArray = (DocFlavor[]) flavors.toArray(flavorArray);\r
+                       supportedFlavors = flavorArray;\r
+               }\r
+               return supportedFlavors;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see javax.print.PrintService#isDocFlavorSupported(javax.print.DocFlavor)\r
+        */\r
+       public boolean isDocFlavorSupported(DocFlavor flavor) {\r
+               List supportedFlavors = Arrays.asList(getSupportedDocFlavors());\r
+               return supportedFlavors.contains(flavor);\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see javax.print.PrintService#getSupportedAttributeCategories()\r
+        */\r
+       public Class[] getSupportedAttributeCategories() {\r
+               Set supportedCategories = new HashSet();\r
+               //Attributes named in 4.2 of rfc2911 are optional\r
+               if (getAllAttributes().containsKey(IppAttributeName.JOB_PRIORIY_SUPPORTED.getCategory())) {\r
+                       supportedCategories.add(IppAttributeName.JOB_PRIORIY.getCategory());\r
+               }\r
+               if (getAllAttributes().containsKey(IppAttributeName.JOB_HOLD_UNTIL_SUPPORTED.getCategory())) {\r
+                       supportedCategories.add(IppAttributeName.JOB_HOLD_UNTIL.getCategory());\r
+               }\r
+               if (getAllAttributes().containsKey(IppAttributeName.JOB_SHEETS_SUPORTED.getCategory())) {\r
+                       supportedCategories.add(IppAttributeName.JOB_SHEETS.getCategory());\r
+               }\r
+               if (getAllAttributes().containsKey(IppAttributeName.MULTIPLE_DOCUMENT_HANDLING_SUPPORTED.getCategory())) {\r
+                       supportedCategories.add(IppAttributeName.MULTIPLE_DOCUMENT_HANDLING.getCategory());\r
+               }\r
+               if (getAllAttributes().containsKey(IppAttributeName.COPIES_SUPPORTED.getCategory())) {\r
+                       supportedCategories.add(IppAttributeName.COPIES.getCategory());\r
+               }\r
+               if (getAllAttributes().containsKey(IppAttributeName.FINISHINGS_SUPPORTED.getCategory())) {\r
+                       supportedCategories.add(IppAttributeName.FINISHINGS.getCategory());\r
+               }\r
+               if (getAllAttributes().containsKey(IppAttributeName.PAGE_RANGES_SUPPORTED.getCategory())) {\r
+                       supportedCategories.add(IppAttributeName.PAGE_RANGES.getCategory());\r
+               }\r
+               if (getAllAttributes().containsKey(IppAttributeName.SIDES_SUPPORTED.getCategory())) {\r
+                       supportedCategories.add(IppAttributeName.SIDES.getCategory());\r
+               }\r
+               if (getAllAttributes().containsKey(IppAttributeName.NUMBER_UP_SUPPORTED.getCategory())) {\r
+                       supportedCategories.add(IppAttributeName.NUMBER_UP.getCategory());\r
+               }\r
+               if (getAllAttributes().containsKey(IppAttributeName.ORIENTATION_REQUESTED_SUPPORTED.getCategory())) {\r
+                       supportedCategories.add(IppAttributeName.ORIENTATION_REQUESTED.getCategory());\r
+               }\r
+               if (getAllAttributes().containsKey(IppAttributeName.MEDIA_SUPPORTED.getCategory())) {\r
+                       supportedCategories.add(IppAttributeName.MEDIA.getCategory());\r
+               }\r
+               if (getAllAttributes().containsKey(IppAttributeName.PRINTER_RESOLUTION.getCategory())) {\r
+                       //printer-resolution-supported attribute currently not implemented\r
+               }\r
+               if (getAllAttributes().containsKey(IppAttributeName.PRINT_QUALITY.getCategory())) {\r
+                       //print-quality-supported attribute currently not implemented\r
+               }\r
+               if (getAllAttributes().containsKey(IppAttributeName.JOB_K_OCTETS_SUPPORTED.getCategory())) {\r
+                       supportedCategories.add(IppAttributeName.JOB_K_OCTETS.getCategory());\r
+               }\r
+               if (getAllAttributes().containsKey(IppAttributeName.JOB_IMPRESSIONS_SUPPORTED.getCategory())) {\r
+                       supportedCategories.add(IppAttributeName.JOB_IMPRESSIONS.getCategory());\r
+               }\r
+               if (getAllAttributes().containsKey(IppAttributeName.JOB_MEDIA_SHEETS_SUPPORTED.getCategory())) {\r
+                       supportedCategories.add(IppAttributeName.JOB_MEDIA_SHEETS.getCategory());\r
+               }\r
+               //Printer object MUST support compression attribute\r
+               supportedCategories.add(IppAttributeName.COMPRESSION.getCategory());\r
+               Class[] categories = new Class[supportedCategories.size()];\r
+               categories = (Class[]) supportedCategories.toArray(categories);\r
+               return categories;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see javax.print.PrintService#isAttributeCategorySupported(java.lang.Class)\r
+        */\r
+       public boolean isAttributeCategorySupported(Class category) {\r
+               return Arrays.asList(this.getSupportedAttributeCategories()).contains(category);\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see javax.print.PrintService#getDefaultAttributeValue(java.lang.Class)\r
+        */\r
+       public Object getDefaultAttributeValue(Class category) {\r
+               //Only the attributes listed in rfc2911 4.2(Job Template Attributes) make sense here\r
+               Object value = null;\r
+               if (category.equals(IppAttributeName.JOB_PRIORIY.getCategory())) {\r
+                       Attribute attr = getAttribute(IppAttributeName.JOB_PRIORITY_DEFAULT.getCategory());\r
+                       if (attr != null) {\r
+                               value = new Integer(((IntegerSyntax) attr).getValue());\r
+                       }\r
+               } else if (category.equals(IppAttributeName.JOB_HOLD_UNTIL.getCategory())) {\r
+                       Attribute attr = getAttribute(IppAttributeName.JOB_HOLD_UNTIL.getCategory());\r
+                       if (attr != null) {\r
+                               value = new Integer(((TextSyntax) attr).getValue());\r
+                       }\r
+               } else if (category.equals(IppAttributeName.JOB_SHEETS_DEFAULT.getCategory())) {\r
+                       Attribute attr = getAttribute(IppAttributeName.JOB_SHEETS_DEFAULT.getCategory());\r
+                       if (attr != null) {\r
+                               value = new Integer(((TextSyntax) attr).getValue());\r
+                       }\r
+               } else if (category.equals(IppAttributeName.COPIES.getCategory())) {\r
+                       Attribute attr = getAttribute(IppAttributeName.COPIES_DEFAULT.getCategory());\r
+                       if (attr != null) {\r
+                               value = new Integer(((IntegerSyntax) attr).getValue());\r
+                       }\r
+               } else if (category.equals(IppAttributeName.FINISHINGS.getCategory())) {\r
+                       Attribute attr = getAttribute(IppAttributeName.FINISHINGS_DEFAULT.getCategory());\r
+                       if (attr != null) {\r
+                               value = new Integer(((IntegerSyntax) attr).toString());\r
+                       }\r
+               } else if (category.equals(IppAttributeName.SIDES.getCategory())) {\r
+                       Attribute attr = getAttribute(IppAttributeName.SIDES_DEFAULT.getCategory());\r
+                       if (attr != null) {\r
+                               value = new Integer(((TextSyntax) attr).getValue());\r
+                       }\r
+               } else if (category.equals(IppAttributeName.NUMBER_UP.getCategory())) {\r
+                       Attribute attr = getAttribute(IppAttributeName.NUMBER_UP_DEFAULT.getCategory());\r
+                       if (attr != null) {\r
+                               value = new Integer(((IntegerSyntax) attr).getValue());\r
+                       }\r
+               } else if (category.equals(IppAttributeName.ORIENTATION_REQUESTED.getCategory())) {\r
+                       Attribute attr = getAttribute(IppAttributeName.ORIENTATION_REQUESTED_DEFAULT.getCategory());\r
+                       if (attr != null) {\r
+                               value = ((TextSyntax) attr).getValue();\r
+                       }\r
+               } else if (category.equals(IppAttributeName.MEDIA.getCategory())) {\r
+                       Attribute attr = getAttribute(IppAttributeName.MEDIA_DEFAULT.getCategory());\r
+                       if (attr != null) {\r
+                               value = ((TextSyntax) attr).getValue();\r
+                       }\r
+               } else if (category.equals(IppAttributeName.PRINTER_RESOLUTION.getCategory())) {\r
+                       //Cups does not support the printer-resolution-default attribute\r
+               } else if (category.equals(IppAttributeName.PRINT_QUALITY.getCategory())) {\r
+                       //Cups does not support the print-quality-default attribute\r
+               } else if (category.equals(IppAttributeName.MULTIPLE_DOCUMENT_HANDLING.getCategory())) {\r
+                       Attribute attr = getAttribute(IppAttributeName.MULTIPLE_DOCUMENT_HANDLING_DEFAULT.getCategory());\r
+                       if (attr != null) {\r
+                               value = ((TextSyntax) attr).getValue();\r
+                       }\r
+               }\r
+               return value;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see javax.print.PrintService#getSupportedAttributeValues(java.lang.Class, javax.print.DocFlavor, javax.print.attribute.AttributeSet)\r
+        */\r
+       public Object getSupportedAttributeValues(Class category, DocFlavor flavor, AttributeSet attributes) {\r
+               Set supportedAttributes = new HashSet();\r
+               // Only the attributes listed in rfc2911 4.2(Job Template Attributes) do make sense here\r
+               if (category.equals(IppAttributeName.JOB_PRIORIY.getCategory())) {\r
+                       supportedAttributes = (Set) getAllAttributes().get(IppAttributeName.JOB_PRIORIY_SUPPORTED.getCategory());\r
+               } else if (category.equals(IppAttributeName.JOB_HOLD_UNTIL.getCategory())) {\r
+                       supportedAttributes = (Set) getAllAttributes().get(IppAttributeName.JOB_HOLD_UNTIL_SUPPORTED.getCategory());\r
+               } else if (category.equals(IppAttributeName.JOB_SHEETS.getCategory())) {\r
+                       supportedAttributes = (Set) getAllAttributes().get(IppAttributeName.JOB_SHEETS_SUPORTED.getCategory());\r
+               } else if (category.equals(IppAttributeName.MULTIPLE_DOCUMENT_HANDLING.getCategory())) {\r
+                       supportedAttributes =\r
+                               (Set) getAllAttributes().get(IppAttributeName.MULTIPLE_DOCUMENT_HANDLING_SUPPORTED.getCategory());\r
+               } else if (category.equals(IppAttributeName.COPIES.getCategory())) {\r
+                       supportedAttributes = (Set) getAllAttributes().get(IppAttributeName.COPIES_SUPPORTED.getCategory());\r
+               } else if (category.equals(IppAttributeName.FINISHINGS.getCategory())) {\r
+                       supportedAttributes = (Set) getAllAttributes().get(IppAttributeName.FINISHINGS_SUPPORTED.getCategory());\r
+               } else if (category.equals(IppAttributeName.SIDES.getCategory())) {\r
+                       supportedAttributes = (Set) getAllAttributes().get(IppAttributeName.SIDES_SUPPORTED.getCategory());\r
+               }\r
+               //TODO page-ranges\r
+               else if (category.equals(IppAttributeName.NUMBER_UP.getCategory())) {\r
+                       supportedAttributes = (Set) getAllAttributes().get(IppAttributeName.NUMBER_UP_SUPPORTED.getCategory());\r
+               } else if (category.equals(IppAttributeName.ORIENTATION_REQUESTED.getCategory())) {\r
+                       supportedAttributes =\r
+                               (Set) getAllAttributes().get(IppAttributeName.ORIENTATION_REQUESTED_SUPPORTED.getCategory());\r
+               } else if (category.equals(IppAttributeName.MEDIA.getCategory())) {\r
+                       supportedAttributes = (Set) getAllAttributes().get(IppAttributeName.MEDIA_SUPPORTED.getCategory());\r
+               } else if (category.equals(IppAttributeName.PRINTER_RESOLUTION)) {\r
+                       //printer-resolution-supported attribute currently not implemented\r
+               } else if (category.equals(IppAttributeName.PRINT_QUALITY.getCategory())) {\r
+                       //printer-quality-supported attribute currently not implemented\r
+               } else if (category.equals(IppAttributeName.MULTIPLE_DOCUMENT_HANDLING.getCategory())) {\r
+                       supportedAttributes =\r
+                               (Set) getAllAttributes().get(IppAttributeName.MULTIPLE_DOCUMENT_HANDLING_SUPPORTED.getCategory());\r
+               } else if (category.equals(IppAttributeName.JOB_IMPRESSIONS.getCategory())) {\r
+                       supportedAttributes =\r
+                               (Set) getAllAttributes().get(IppAttributeName.JOB_IMPRESSIONS_SUPPORTED.getCategory());\r
+               } else if (category.equals(IppAttributeName.JOB_K_OCTETS.getCategory())) {\r
+                       supportedAttributes = (Set) getAllAttributes().get(IppAttributeName.JOB_K_OCTETS_SUPPORTED.getCategory());\r
+               } else if (category.equals(IppAttributeName.JOB_MEDIA_SHEETS.getCategory())) {\r
+                       supportedAttributes =\r
+                               (Set) getAllAttributes().get(IppAttributeName.JOB_MEDIA_SHEETS_SUPPORTED.getCategory());\r
+               } else if (category.equals(IppAttributeName.COMPRESSION.getCategory())) {\r
+                       supportedAttributes = (Set) getAllAttributes().get(IppAttributeName.COMPRESSION_SUPORTED.getCategory());\r
+               }\r
+               if (supportedAttributes == null) {\r
+                       supportedAttributes = new HashSet();\r
+               }\r
+               return supportedAttributes.toArray(new Attribute[supportedAttributes.size()]);\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see javax.print.PrintService#isAttributeValueSupported(javax.print.attribute.Attribute, javax.print.DocFlavor, javax.print.attribute.AttributeSet)\r
+        */\r
+       public boolean isAttributeValueSupported(Attribute attrVal, DocFlavor flavor, AttributeSet attributes) {\r
+               AttributeSet operationAttributes = new HashAttributeSet();\r
+               if (flavor != null) {\r
+                       operationAttributes.add(new DocumentFormat(flavor.getMimeType(), Locale.getDefault()));\r
+               }\r
+               IppRequest request = this.request(OperationsSupported.VALIDATE_JOB);\r
+               if (attributes == null) {\r
+                       attributes = new HashAttributeSet();\r
+               }\r
+               attributes.add(attrVal);\r
+               Object[] attributeArray = attributes.toArray();\r
+               PrintJobAttributeSet jobAttributes = new HashPrintJobAttributeSet();\r
+               for (int i = 0; i < attributeArray.length; i++) {\r
+                       Attribute attribute = (Attribute) attributeArray[i];\r
+                       //attributes-charset, attributes-natural-language etc. are not set by the user\r
+                       if (attribute instanceof PrintRequestAttribute && attribute instanceof PrintJobAttribute) {\r
+                               if (attribute.getCategory().equals(IppAttributeName.JOB_NAME.getCategory())\r
+                                       || attribute.getCategory().equals(IppAttributeName.FIDELITY.getCategory())\r
+                                       || attribute.getCategory().equals(IppAttributeName.JOB_IMPRESSIONS.getCategory())\r
+                                       || attribute.getCategory().equals(IppAttributeName.JOB_K_OCTETS.getCategory())\r
+                                       || attribute.getCategory().equals(IppAttributeName.JOB_MEDIA_SHEETS.getCategory())) {\r
+                                       operationAttributes.add(attribute);\r
+                               } else if (\r
+                                       attribute.getCategory().equals(IppAttributeName.JOB_NAME.getCategory())\r
+                                               || attribute.getCategory().equals(IppAttributeName.FIDELITY.getCategory())) {\r
+                                       //do nothing, Job Template Attributes can not be used in a Validate-Job operation\r
+                               } else {\r
+                                       jobAttributes.add(attribute);\r
+                               }\r
+                       }\r
+               }\r
+               request.addOperationAttributes(operationAttributes);\r
+               request.setJobAttributes(jobAttributes);\r
+               IppResponse response = null;\r
+               try {\r
+                       response = request.send();\r
+               } catch (IOException e) {\r
+                       log.log(Level.SEVERE, e.getMessage(), e);\r
+               }\r
+               boolean supported = false;\r
+               if (response != null) {\r
+                       if (response.getStatus().equals(IppStatus.SUCCESSFUL_OK)\r
+                               || response.getStatus().equals(IppStatus.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES)\r
+                               || response.getStatus().equals(IppStatus.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES)) {\r
+                               supported = true;\r
+                       }\r
+               }\r
+               return supported;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see javax.print.PrintService#getUnsupportedAttributes(javax.print.DocFlavor, javax.print.attribute.AttributeSet)\r
+        */\r
+       public AttributeSet getUnsupportedAttributes(DocFlavor flavor, AttributeSet attributes) {\r
+               return null;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see javax.print.PrintService#getServiceUIFactory()\r
+        */\r
+       public ServiceUIFactory getServiceUIFactory() {\r
+               return null;\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see javax.print.PrintService#addPrintServiceAttributeListener(javax.print.event.PrintServiceAttributeListener)\r
+        */\r
+       public void addPrintServiceAttributeListener(PrintServiceAttributeListener listener) {\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see javax.print.PrintService#removePrintServiceAttributeListener(javax.print.event.PrintServiceAttributeListener)\r
+        */\r
+       public void removePrintServiceAttributeListener(PrintServiceAttributeListener listener) {\r
+       }\r
+\r
+       /**\r
+        * @return\r
+        */\r
+       private Map getAllAttributes() {\r
+               if (this.attributes == null) {\r
+                       IppRequest request = this.request(OperationsSupported.GET_PRINTER_ATTRIBUTES);\r
+                       IppResponse response = null;\r
+                       try {\r
+                               response = request.send();\r
+                       } catch (IOException e) {\r
+                               log.log(Level.SEVERE, e.getMessage(), e);\r
+                       }\r
+                       if (response != null) {\r
+                               this.attributes = response.getAttributes();\r
+                       }\r
+               }\r
+               return this.attributes;\r
+       }\r
+\r
+       public String toString() {\r
+               return this.getName();\r
+       }\r
+\r
+       /**\r
+        * @param operation\r
+        * @return\r
+        */\r
+       protected IppRequest request(OperationsSupported operation) {\r
+               IppRequest request = IppRequestFactory.createIppRequest(this.uri, operation, this.getRequestingUserName(), this.getRequestingUserPassword());\r
+               AttributeSet operationAttributes = new HashAttributeSet();\r
+               operationAttributes.add(new PrinterURI(this.uri));\r
+               request.addOperationAttributes(operationAttributes);\r
+               return request;\r
+       }\r
+\r
+       /**\r
+        * Returns a job with the given JobId, or null if no such\r
+        * Job exists.\r
+        * <br>\r
+        * Use jobExists to check for a Job with this JobId.\r
+        * <br>\r
+        * This method might return a Job which is not hold by this PrintService\r
+        * but the same CUPS server \r
+        * \r
+        * @param jobId\r
+        * @return the corresponding Job wihth the given JobId, or null if no such Job exists \r
+        * @throws PrintException\r
+        */\r
+       //public Methods which are not part of the JPS API\r
+       public DocPrintJob getJob(JobId jobId) throws PrintException {\r
+               Job job = Job.getJob(this, jobId);\r
+               return job;\r
+       }\r
+\r
+       /**\r
+        * \r
+        * Check for a Job with the given JobId.\r
+        * <br>\r
+        * This method might return true, even if the printservice does not hold any \r
+        * job with the given JobId, but another PrintService on the same \r
+        * Cups server does. \r
+        * \r
+        * @param jobId\r
+        * @return true if a Job with the given JobId exists, false otherwise\r
+        * @throws PrintException\r
+        */\r
+       public boolean jobExists(JobId jobId) throws PrintException {\r
+               return Job.getJob(this, jobId) != null;\r
+       }\r
+\r
+    \r
+    public RequestingUserName getRequestingUserName() {\r
+        return requestingUserName;\r
+    }\r
+    public void setRequestingUserName(RequestingUserName requestingUserName) {\r
+        this.requestingUserName = requestingUserName;\r
+    }\r
+    public RequestingUserPassword getRequestingUserPassword() {\r
+        return requestingUserPassword;\r
+    }\r
+    public void setRequestingUserPassword(\r
+            RequestingUserPassword requestingUserPassword) {\r
+        this.requestingUserPassword = requestingUserPassword;\r
+    }\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/IppPrintServiceLookup.java b/jspi/src/main/java/de/lohndirekt/print/IppPrintServiceLookup.java
new file mode 100644 (file)
index 0000000..c9117d4
--- /dev/null
@@ -0,0 +1,199 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.util.ArrayList;\r
+import java.util.HashSet;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Locale;\r
+import java.util.Set;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import javax.print.DocFlavor;\r
+import javax.print.MultiDocPrintService;\r
+import javax.print.PrintService;\r
+import javax.print.PrintServiceLookup;\r
+import javax.print.attribute.Attribute;\r
+import javax.print.attribute.AttributeSet;\r
+import javax.print.attribute.standard.RequestingUserName;\r
+\r
+import de.lohndirekt.print.attribute.auth.RequestingUserPassword;\r
+\r
+/** \r
+ * \r
+ * @author bpusch\r
+ * \r
+ * <p>\r
+ * This is an implementation of the Java Print Service API for IPP.<p>\r
+ * To use this implementation do one of the following:\r
+ * <p>\r
+ *     1. Set the system properties\r
+ * <ul>\r
+ * <li><code>de.lohndirekt.print.IppPrintService.uri</code></li>\r
+ * <li><code>de.lohndirekt.print.IppPrintService.username</code></li>\r
+ * <li><code>de.lohndirekt.print.IppPrintService.password</code></li>\r
+ * </ul>\r
+ * and use the default constructor\r
+ * <p>\r
+ *  2. use the 3 parameter constructor\r
+ * <p>\r
+ *  then register the instance by invoking javax.print.PrintServiceLookup.registerServiceProvider<br>\r
+ * <br>\r
+ *  @see javax.print.PrintServiceLookup#registerServiceProvider\r
+ */\r
+public class IppPrintServiceLookup extends PrintServiceLookup {\r
+    public final static String URI_KEY = "de.lohndirekt.print.IppPrintService.uri";\r
+    public final static String USERNAME_KEY = "de.lohndirekt.print.IppPrintService.username";\r
+    public final static String PASSWORD_KEY = "de.lohndirekt.print.IppPrintService.password";\r
+    private List cupsServers = new ArrayList();\r
+    private Logger log = Logger.getLogger(this.getClass().getName());\r
+\r
+    /**\r
+     * <p>\r
+     * default constructor uses the values set in\r
+     * <p>\r
+     * <code>de.lohndirekt.print.IppPrintService.uri</code><br>\r
+     * <code>de.lohndirekt.print.IppPrintService.username</code><br>\r
+     * <code>de.lohndirekt.print.IppPrintService.password</code><br>\r
+     */\r
+    public IppPrintServiceLookup() {\r
+        String myUri = (String) System.getProperties().get(URI_KEY);\r
+        String user = (String) System.getProperties().get(USERNAME_KEY);\r
+        String password = (String) System.getProperties().get(PASSWORD_KEY);\r
+        URI uri = null;\r
+        if (myUri == null) {\r
+            throw new NullPointerException("System property " + URI_KEY + " not set!");\r
+        } else if (user == null) {\r
+            throw new NullPointerException("System property " + USERNAME_KEY + " not set!");\r
+        } else if (password == null) {\r
+            throw new NullPointerException("System property " + PASSWORD_KEY + " not set!");\r
+        }\r
+        try {\r
+            uri = new URI(myUri);\r
+        } catch (URISyntaxException e) {\r
+            throw new NullPointerException("System property " + URI_KEY + " - " + myUri + " is not a valid Uri!");\r
+        }\r
+        cupsServers.add(new IppServer(uri, new RequestingUserName(user,Locale.getDefault()), new RequestingUserPassword(password,Locale.getDefault())));\r
+    }\r
+\r
+    /**\r
+     * This constructor uses the given parameters to connect to an IPP service\r
+     * \r
+     * @param uri the uri of the ipp service\r
+     * @param username used for authentication\r
+     * @param password used for authentication\r
+     */\r
+    public IppPrintServiceLookup(URI uri, String username, String password) {\r
+        cupsServers.add(new IppServer(uri, new RequestingUserName(username,Locale.getDefault()),new RequestingUserPassword(password,Locale.getDefault())));\r
+    }\r
+\r
+    /* (non-Javadoc)\r
+     * @see javax.print.PrintServiceLookup#getPrintServices(javax.print.DocFlavor, javax.print.attribute.AttributeSet)\r
+     */\r
+    public PrintService[] getPrintServices(DocFlavor flavor, AttributeSet attributes) {\r
+        PrintService[] services = getPrintServices();\r
+        List fittingServices = new ArrayList();\r
+        for (int i = 0; i < services.length; i++) {\r
+            IppPrintService service = (IppPrintService) services[i];\r
+            if (checkService(service, flavor, attributes)) {\r
+                fittingServices.add(service);\r
+            }\r
+        }\r
+        PrintService[] serviceArray = new PrintService[fittingServices.size()];\r
+        return (PrintService[]) fittingServices.toArray(serviceArray);\r
+    }\r
+\r
+    /* (non-Javadoc)\r
+     * @see javax.print.PrintServiceLookup#getPrintServices()\r
+     */\r
+    public PrintService[] getPrintServices() {\r
+        List services = new ArrayList();\r
+        try {\r
+            for (Iterator iter = cupsServers.iterator(); iter.hasNext();) {\r
+                IppServer server = (IppServer) iter.next();\r
+                services.addAll(server.getPrintServices());\r
+            }\r
+        } catch (RuntimeException e) {\r
+            log.log(Level.SEVERE, e.getMessage(), e);\r
+        }\r
+        PrintService[] serviceArray = new PrintService[services.size()];\r
+        return (PrintService[]) services.toArray(serviceArray);\r
+    }\r
+\r
+    /**\r
+     * @param service\r
+     * @param flavor\r
+     * @param attributes\r
+     * @return\r
+     */\r
+    private boolean checkService(IppPrintService service, DocFlavor flavor, AttributeSet attributes) {\r
+        if (flavor == null || service.isDocFlavorSupported(flavor)) {\r
+            if (attributes != null) {\r
+                Attribute[] attrArray = attributes.toArray();\r
+                for (int j = 0; j < attrArray.length; j++) {\r
+                    Attribute attribute = attrArray[j];\r
+                    if (service.isAttributeValueSupported(attribute, flavor, null)) {\r
+                        return true;\r
+                    }\r
+                }\r
+            } else {\r
+                return true;\r
+            }\r
+        }\r
+        return false;\r
+    }\r
+\r
+    /* (non-Javadoc)\r
+     * @see javax.print.PrintServiceLookup#getMultiDocPrintServices(javax.print.DocFlavor[], javax.print.attribute.AttributeSet)\r
+     */\r
+    public MultiDocPrintService[] getMultiDocPrintServices(DocFlavor[] flavors, AttributeSet attributes) {\r
+        Set multiDocServices = new HashSet();\r
+        PrintService[] services = getPrintServices(null, attributes);\r
+        for (int i = 0; i < services.length; i++) {\r
+            PrintService service = services[i];\r
+            if (flavors != null) {\r
+                for (int j = 0; j < flavors.length; j++) {\r
+                    DocFlavor flavor = flavors[j];\r
+                    if (!service.isDocFlavorSupported(flavor)) {\r
+                        break;\r
+                    }\r
+                }\r
+            }\r
+            multiDocServices.add(new IppMultiDocPrintService(((IppPrintService) service).getUri()));\r
+        }\r
+        return (MultiDocPrintService[]) multiDocServices.toArray(new MultiDocPrintService[multiDocServices.size()]);\r
+\r
+    }\r
+\r
+    /* (non-Javadoc)\r
+     * @see javax.print.PrintServiceLookup#getDefaultPrintService()\r
+     */\r
+    public PrintService getDefaultPrintService() {\r
+        PrintService[] services = this.getPrintServices();\r
+        if (services.length > 0) {\r
+            return services[0];\r
+        }\r
+        return null;\r
+    }\r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/IppPrintServiceLookupTest.java b/jspi/src/main/java/de/lohndirekt/print/IppPrintServiceLookupTest.java
new file mode 100644 (file)
index 0000000..e0d7643
--- /dev/null
@@ -0,0 +1,68 @@
+package de.lohndirekt.print;\r
+\r
+import java.util.Locale;\r
+\r
+import javax.print.DocFlavor;\r
+import javax.print.PrintService;\r
+import javax.print.attribute.AttributeSet;\r
+import javax.print.attribute.HashAttributeSet;\r
+import javax.print.attribute.standard.RequestingUserName;\r
+\r
+import de.lohndirekt.print.attribute.auth.RequestingUserPassword;\r
+\r
+import junit.framework.TestCase;\r
+\r
+/**\r
+ * @author bpusch\r
+ *\r
+ */\r
+public class IppPrintServiceLookupTest extends TestCase {\r
+\r
+       /**\r
+        * Constructor for IppPrintServiceLookupTest.\r
+        * @param name\r
+        */\r
+       public IppPrintServiceLookupTest(String name) {\r
+               super(name);\r
+       }\r
+\r
+       /*\r
+        * @see TestCase#setUp()\r
+        */\r
+       protected void setUp() throws Exception {\r
+               super.setUp();\r
+               //setting cups properties\r
+               System.getProperties().setProperty(IppPrintServiceLookup.URI_KEY, Messages.getString("cups.uri")); //$NON-NLS-1$\r
+               System.getProperties().setProperty(IppPrintServiceLookup.USERNAME_KEY, Messages.getString("cups.username")); //$NON-NLS-1$\r
+               System.getProperties().setProperty(IppPrintServiceLookup.PASSWORD_KEY, Messages.getString("cups.password")); //$NON-NLS-1$\r
+               System.getProperties().setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog"); //$NON-NLS-1$\r
+               System.getProperties().setProperty("org.apache.commons.logging.simplelog.showdatetime", "true");\r
+               System.getProperties().setProperty("org.apache.commons.logging.simplelog.log.httpclient.wire", "debug");\r
+               System.getProperties().setProperty("org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient", "debug");\r
+       }\r
+\r
+//     public void testGetServices(){\r
+//             PrintService[] services = new IppPrintServiceLookup().getPrintServices(DocFlavor.INPUT_STREAM.POSTSCRIPT ,null);\r
+//             assertTrue(services.length>0);\r
+//             \r
+//             //IppPrintServiceLookup must not return any pageable enabled services\r
+//             services = new IppPrintServiceLookup().getPrintServices(DocFlavor.SERVICE_FORMATTED.PAGEABLE, null);\r
+//             assertEquals(0,services.length);\r
+//     }\r
+       \r
+       \r
+       \r
+       public void testGetServicesAuthenticated(){\r
+               RequestingUserName user = new RequestingUserName(Messages.getString("cups.username"), Locale.GERMANY);\r
+               RequestingUserPassword pass = new RequestingUserPassword(Messages.getString("cups.password"), Locale.GERMANY);\r
+               \r
+               AttributeSet set = new HashAttributeSet();\r
+               set.add(user);\r
+               set.add(pass);\r
+               \r
+               PrintService[] services = new IppPrintServiceLookup().getPrintServices(DocFlavor.INPUT_STREAM.POSTSCRIPT ,null);\r
+               assertTrue(services.length>0);\r
+               \r
+               \r
+       }\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/IppPrintServiceTest.java b/jspi/src/main/java/de/lohndirekt/print/IppPrintServiceTest.java
new file mode 100644 (file)
index 0000000..9d791e6
--- /dev/null
@@ -0,0 +1,120 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+\r
+import java.net.URI;\r
+import java.util.Arrays;\r
+import java.util.List;\r
+import java.util.logging.Logger;\r
+\r
+import javax.print.PrintService;\r
+import javax.print.attribute.Attribute;\r
+\r
+import junit.framework.TestCase;\r
+import de.lohndirekt.print.attribute.IppAttributeName;\r
+import de.lohndirekt.print.test.IppRequestTestImpl;\r
+\r
+/**\r
+ * @author bpusch\r
+ *\r
+ */\r
+public class IppPrintServiceTest extends TestCase {\r
+\r
+    PrintService service;\r
+    Logger log;\r
+\r
+    /**\r
+     * Constructor for IppPrintServiceTest.\r
+     * @param arg0\r
+     */\r
+    public IppPrintServiceTest(String arg0) {\r
+        super(arg0);\r
+    }\r
+\r
+    /*\r
+     * @see TestCase#setUp()\r
+     */\r
+    protected void setUp() throws Exception {\r
+        super.setUp();\r
+        System.setProperty(IppRequestFactory.IPP_REQUEST_IMPL_KEY, IppRequestTestImpl.class.getName());\r
+        IppPrintServiceLookup lookup = new IppPrintServiceLookup(new URI("http://127.0.0.1"), "", "");\r
+        PrintService[] services = lookup.getPrintServices();\r
+        this.service = services[0];\r
+        this.log = Logger.getLogger(this.getName());\r
+    }\r
+\r
+    public void testGetSupportedAttributeCategories() {\r
+        Class[] categories = this.service.getSupportedAttributeCategories();\r
+        assertNotNull(categories);\r
+        List cats = Arrays.asList(categories);\r
+        assertTrue(cats.contains(IppAttributeName.JOB_PRIORIY.getCategory()));\r
+        assertTrue(cats.contains(IppAttributeName.JOB_HOLD_UNTIL.getCategory()));\r
+        assertTrue(cats.contains(IppAttributeName.JOB_SHEETS.getCategory()));\r
+        assertTrue(cats.contains(IppAttributeName.MULTIPLE_DOCUMENT_HANDLING.getCategory()));\r
+        assertTrue(cats.contains(IppAttributeName.COPIES.getCategory()));\r
+        assertTrue(cats.contains(IppAttributeName.FINISHINGS.getCategory()));\r
+        assertTrue(cats.contains(IppAttributeName.SIDES.getCategory()));\r
+        assertTrue(cats.contains(IppAttributeName.NUMBER_UP.getCategory()));\r
+        assertTrue(cats.contains(IppAttributeName.ORIENTATION_REQUESTED.getCategory()));\r
+        assertTrue(cats.contains(IppAttributeName.MEDIA.getCategory()));\r
+        assertTrue(cats.contains(IppAttributeName.COMPRESSION.getCategory()));\r
+        assertTrue(cats.contains(IppAttributeName.JOB_K_OCTETS.getCategory()));\r
+        assertTrue(cats.contains(IppAttributeName.JOB_IMPRESSIONS.getCategory()));\r
+        assertTrue(cats.contains(IppAttributeName.JOB_MEDIA_SHEETS.getCategory()));\r
+    }\r
+\r
+    public void testIsAttributeCategorySupported() {\r
+        Class category = IppAttributeName.JOB_SHEETS.getCategory();\r
+        boolean supported = this.service.isAttributeCategorySupported(category);\r
+        assertEquals(Arrays.asList(this.service.getSupportedAttributeCategories()).contains(category), supported);\r
+        \r
+    }\r
+\r
+    public void testGetSupportedAttributeValues() {\r
+        Class category = IppAttributeName.MEDIA.getCategory();\r
+        Attribute[] attrs = (Attribute[]) this.service.getSupportedAttributeValues(category, null, null);\r
+        assertEquals("Should be 2 media-supported attributes", 2, attrs.length);\r
+        for (int j = 0; j < attrs.length; j++) {\r
+            Attribute attribute = attrs[j];\r
+            assertEquals(IppAttributeName.MEDIA_SUPPORTED.getCategory(), attribute.getCategory());\r
+        }\r
+        category = IppAttributeName.COMPRESSION.getCategory();\r
+        attrs = (Attribute[]) this.service.getSupportedAttributeValues(category, null, null);\r
+        for (int j = 0; j < attrs.length; j++) {\r
+            Attribute attribute = attrs[j];\r
+            assertEquals(IppAttributeName.COMPRESSION_SUPORTED.getCategory(), attribute.getCategory());\r
+        }\r
+        category = IppAttributeName.JOB_PRIORIY.getCategory();\r
+        attrs = (Attribute[]) this.service.getSupportedAttributeValues(category, null, null);\r
+        assertEquals("Should be 1 job-priority-supported attribute", 1, attrs.length);\r
+        for (int j = 0; j < attrs.length; j++) {\r
+            Attribute attribute = attrs[j];\r
+            assertEquals(IppAttributeName.JOB_PRIORIY_SUPPORTED.getCategory(), attribute.getCategory());\r
+        }\r
+        category = IppAttributeName.SIDES.getCategory();\r
+        attrs = (Attribute[]) this.service.getSupportedAttributeValues(category, null, null);\r
+        assertEquals("Should be 2 sides-supported attributes", 2, attrs.length);\r
+        for (int j = 0; j < attrs.length; j++) {\r
+            Attribute attribute = attrs[j];\r
+            assertEquals(IppAttributeName.SIDES_SUPPORTED.getCategory(), attribute.getCategory());\r
+        }\r
+\r
+    }\r
+   \r
+}
\ No newline at end of file
diff --git a/jspi/src/main/java/de/lohndirekt/print/IppRequest.java b/jspi/src/main/java/de/lohndirekt/print/IppRequest.java
new file mode 100644 (file)
index 0000000..7e7d244
--- /dev/null
@@ -0,0 +1,39 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+\r
+import javax.print.attribute.AttributeSet;\r
+import javax.print.attribute.PrintJobAttributeSet;\r
+\r
+/**\r
+ * @author sefftinge\r
+ *\r
+ */\r
+public interface IppRequest {\r
+       \r
+       IppResponse send() throws IOException;\r
+       void setData(byte[] data);\r
+       void setData(InputStream data);\r
+       void setJobAttributes(PrintJobAttributeSet attributes);\r
+       void addOperationAttributes(AttributeSet attributes);\r
+       void setPrinterAttributes(AttributeSet attributes);\r
+}
\ No newline at end of file
diff --git a/jspi/src/main/java/de/lohndirekt/print/IppRequestCupsImpl.java b/jspi/src/main/java/de/lohndirekt/print/IppRequestCupsImpl.java
new file mode 100644 (file)
index 0000000..4eeca85
--- /dev/null
@@ -0,0 +1,398 @@
+/**\r
+ * Copyright (C) 2004 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.SequenceInputStream;\r
+import java.io.UnsupportedEncodingException;\r
+import java.net.HttpURLConnection;\r
+import java.net.URI;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+import java.util.Vector;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import javax.print.attribute.Attribute;\r
+import javax.print.attribute.AttributeSet;\r
+import javax.print.attribute.HashAttributeSet;\r
+import javax.print.attribute.HashPrintJobAttributeSet;\r
+import javax.print.attribute.PrintJobAttributeSet;\r
+import javax.print.attribute.TextSyntax;\r
+\r
+import de.lohndirekt.print.attribute.AttributeHelper;\r
+import de.lohndirekt.print.attribute.AttributeParser;\r
+import de.lohndirekt.print.attribute.AttributeWriter;\r
+import de.lohndirekt.print.attribute.IppAttributeName;\r
+import de.lohndirekt.print.attribute.IppDelimiterTag;\r
+import de.lohndirekt.print.attribute.IppStatus;\r
+import de.lohndirekt.print.attribute.ipp.Charset;\r
+import de.lohndirekt.print.attribute.ipp.NaturalLanguage;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.OperationsSupported;\r
+\r
+/**\r
+ * @author bpusch, speters, sefftinge\r
+ *  \r
+ */\r
+class IppRequestCupsImpl implements IppRequest {\r
+    class IppResponseIppImpl implements IppResponse {\r
+        private Logger log = Logger.getLogger(this.getClass().getName());\r
+\r
+        private IppStatus status;\r
+\r
+        private Map attributes;\r
+\r
+        IppResponseIppImpl(InputStream response) {\r
+            try{\r
+                parseResponse(response);\r
+            } catch (IOException e) {\r
+                log.log(Level.SEVERE, e.getMessage(), e);\r
+                throw new RuntimeException(e);\r
+            }\r
+            \r
+        }\r
+\r
+        private void parseResponse(InputStream response) throws IOException {\r
+            byte[] header = new byte[8];\r
+            response.read(header);\r
+            this.status = IppStatus.get((int) (header[2] << 8)\r
+                    + (int) header[3]);\r
+            if (response.available() != 0) {\r
+                this.attributes = AttributeParser.parseResponse(response);\r
+            } else {\r
+                this.attributes = new HashMap();\r
+            }\r
+            if (log.isLoggable(Level.FINEST)) {\r
+                log.finest("Status: " + status.getText());\r
+            }\r
+        }\r
+\r
+        /**\r
+         * @return\r
+         */\r
+        public Map getAttributes() {\r
+            return attributes;\r
+        }\r
+\r
+        /**\r
+         * @return\r
+         */\r
+        public IppStatus getStatus() {\r
+            return status;\r
+        }\r
+\r
+    }\r
+\r
+    private IppConnection conn;\r
+\r
+    private boolean sent = false;\r
+\r
+    private Object data;\r
+\r
+    private URI path;\r
+\r
+    private OperationsSupported operation;\r
+\r
+    //Id wird in der Cups-API zwar übergeben, ist aber auch immer 1.\r
+    private int id = 1;\r
+\r
+    private PrintJobAttributeSet jobAttributes = new HashPrintJobAttributeSet();\r
+\r
+    private AttributeSet operationAttributes = new HashAttributeSet();\r
+\r
+    private AttributeSet printerAttributes = new HashAttributeSet();\r
+\r
+    private Logger log = Logger.getLogger(this.getClass().getName());\r
+\r
+    private static final int SEND_REQUEST_COUNT = 3;\r
+\r
+    private static final int SEND_REQUEST_TIMEOUT = 50;\r
+    \r
+    private static final NaturalLanguage NATURAL_LANGUAGE_DEFAULT = NaturalLanguage.EN;\r
+    \r
+    private static final Charset CHARSET_DEFAULT = Charset.UTF_8;\r
+    \r
+\r
+    /**\r
+     * @param operation\r
+     */\r
+    IppRequestCupsImpl(URI path, OperationsSupported operation) {\r
+        this.path = path;\r
+        this.operation = operation;\r
+        init();\r
+    }\r
+\r
+    /**\r
+     * @param printerAttributes\r
+     */\r
+    public void setPrinterAttributes(AttributeSet attrs) {\r
+        this.printerAttributes = attrs;\r
+    }\r
+\r
+    /**\r
+     *  \r
+     */\r
+    private void init() {\r
+        setStandardAttributes();\r
+    }\r
+\r
+    /**\r
+     *  \r
+     */\r
+    private void setStandardAttributes() {\r
+        operationAttributes.add(CHARSET_DEFAULT);\r
+        operationAttributes.add(NATURAL_LANGUAGE_DEFAULT);\r
+    }\r
+\r
+    /**\r
+     *  \r
+     */\r
+    private byte[] ippFooter() {\r
+        byte[] footer = new byte[1];\r
+        footer[0] = (byte) IppDelimiterTag.END_ATTRIBUTES.getValue();\r
+        return footer;\r
+    }\r
+\r
+    /**\r
+     *  \r
+     */\r
+    private byte[] ippAttributes() throws UnsupportedEncodingException {\r
+        ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+        operationAttributes(out);\r
+        printerAttributes(out);\r
+        jobAttributes(out);\r
+        byte[] body = out.toByteArray();\r
+        return body;\r
+    }\r
+\r
+    /**\r
+     * @param out\r
+     * @return\r
+     */\r
+    private void jobAttributes(ByteArrayOutputStream out) throws UnsupportedEncodingException {\r
+        if (!jobAttributes.isEmpty()) {\r
+            out.write((byte) IppDelimiterTag.BEGIN_JOB_ATTRIBUTES\r
+                            .getValue());\r
+            for (int i = 0; i < jobAttributes.toArray().length; i++) {\r
+                Attribute attribute = (Attribute) jobAttributes.toArray()[i];\r
+                AttributeWriter.attributeBytes(attribute, out);\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     *\r
+     * @param out\r
+     * @return\r
+     */\r
+    private void printerAttributes(ByteArrayOutputStream out) throws UnsupportedEncodingException {\r
+        if (!printerAttributes.isEmpty()) {\r
+            out.write((byte) IppDelimiterTag.BEGIN_PRINTER_ATTRIBUTES\r
+                            .getValue());\r
+            Attribute[] attributes = printerAttributes.toArray();\r
+            for (int i = 0; i < attributes.length; i++) {\r
+                AttributeWriter.attributeBytes(attributes[i], out);\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * \r
+     * @param out\r
+     * @return\r
+     */\r
+    private void operationAttributes(ByteArrayOutputStream out) throws UnsupportedEncodingException {\r
+        if (!operationAttributes.isEmpty()) {\r
+            out.write((byte) IppDelimiterTag.BEGIN_OPERATION_ATTRIBUTES\r
+                            .getValue());\r
+            Attribute[] attributes = AttributeHelper.getOrderedOperationAttributeArray(operationAttributes);\r
+            for (int i = 0; i < attributes.length; i++) {\r
+                AttributeWriter.attributeBytes(attributes[i], out);\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     *  \r
+     */\r
+    private byte[] ippHeader() {\r
+        //Ipp header data according to http://www.ietf.org/rfc/rfc2910.txt\r
+        ByteArrayOutputStream out = new ByteArrayOutputStream(8);\r
+        //The first 2 bytes represent the IPP version number (1.1)\r
+        //major version-number\r
+        out.write((byte) 1);\r
+        //minor version-number\r
+        out.write((byte) 1);\r
+        //2 byte operation id\r
+        AttributeWriter.writeInt2(this.operation.getValue(), out);\r
+        //4 byte request id\r
+        AttributeWriter.writeInt4(this.id, out);\r
+        return out.toByteArray();\r
+    }\r
+\r
+    /**\r
+     * @param attributes\r
+     */\r
+    public void addOperationAttributes(AttributeSet attributes) {\r
+        this.operationAttributes.addAll(attributes);\r
+    }\r
+\r
+    /**\r
+     * @param stream\r
+     */\r
+    public void setData(InputStream data) {\r
+        this.data = data;\r
+    }\r
+\r
+    public void setData(byte[] data) {\r
+        this.data = data;\r
+    }\r
+\r
+    /**\r
+     * @param attributes\r
+     */\r
+    public void setJobAttributes(PrintJobAttributeSet attributes) {\r
+        this.jobAttributes = attributes;\r
+    }\r
+\r
+    /**\r
+     * @see de.lohndirekt.print.IppRequest#send()\r
+     * @throws IllegalArgumentException\r
+     *             when called twice\r
+     */\r
+    public IppResponse send() throws IOException {\r
+        if (sent) {\r
+            throw new IllegalStateException("Send must not be called twice");\r
+        }\r
+\r
+        String username = findUserName(this.operationAttributes);\r
+        String password = findPassword(this.operationAttributes);\r
+        boolean ok = false;\r
+        int tries = 0;\r
+        while (!ok && tries < SEND_REQUEST_COUNT) {\r
+            tries++;\r
+\r
+            this.conn = new IppHttpConnection(this.path, username, password);\r
+\r
+            Vector v = new Vector();\r
+            v.add(new ByteArrayInputStream(this.ippHeader()));\r
+            v.add(new ByteArrayInputStream(this.ippAttributes()));\r
+            v.add(new ByteArrayInputStream(this.ippFooter()));\r
+            if (this.data != null) {\r
+                v.add(this.getDataAsInputStream());\r
+            }\r
+            SequenceInputStream stream = new SequenceInputStream(v.elements());\r
+            conn.setIppRequest(stream);\r
+            conn.execute();\r
+\r
+            if (conn.getStatusCode() != HttpURLConnection.HTTP_OK) {\r
+                if (log.isLoggable(Level.INFO)) {\r
+                    String msg = "Cups seems to be busy - STATUSCODE "+conn.getStatusCode();\r
+                    if (tries < SEND_REQUEST_COUNT) {\r
+                        msg += " - going to retry in " + SEND_REQUEST_TIMEOUT\r
+                                + " ms";\r
+                    }\r
+                    log.warning(msg);\r
+                }\r
+                try {\r
+                    Thread.sleep(50);\r
+                } catch (InterruptedException e) {\r
+                    if (log.isLoggable(Level.INFO)) {\r
+                        log.info(e.getMessage());\r
+                    }\r
+                }\r
+            } else {\r
+                ok = true;\r
+            }\r
+\r
+        }\r
+        this.sent = true;\r
+        return getResponse();\r
+    }\r
+\r
+    /**\r
+     * @param list\r
+     * @return\r
+     */\r
+    private String findUserName(AttributeSet list) {\r
+        if (list != null) {\r
+            TextSyntax attr = (TextSyntax) list.get(IppAttributeName.REQUESTING_USER_NAME\r
+                    .getCategory());\r
+            if (attr != null) {\r
+                return attr.getValue();\r
+            }\r
+        }\r
+        return null;\r
+    }\r
+\r
+    /**\r
+     * @param list\r
+     * @return\r
+     */\r
+    private String findPassword(AttributeSet list) {\r
+        if (list != null) {\r
+            TextSyntax attr = (TextSyntax) list.get(IppAttributeName.REQUESTING_USER_PASSWD\r
+                    .getCategory());\r
+            if (attr != null) {\r
+                return attr.getValue();\r
+            }\r
+        }\r
+        return null;\r
+    }\r
+\r
+    /**\r
+     * @return\r
+     */\r
+    private InputStream getDataAsInputStream() {\r
+        if (data == null) {\r
+            return null;\r
+//        } else if (data instanceof FileInputStream) {\r
+//            FileInputStream in = (FileInputStream) data;\r
+//            try {\r
+//                             if (in.getFD().valid()){\r
+//                    //TODO remove this hack\r
+//                                 in=new FileInputStream("./testfiles/test.pdf");\r
+//                             }\r
+//                     } catch (IOException e) {\r
+//                             log.log(Level.WARNING, "", e);\r
+//                     }\r
+//            return in;\r
+        } else if (data instanceof InputStream) {\r
+            InputStream in = (InputStream) data;\r
+            return in;\r
+        } else if (data instanceof byte[]) {\r
+            return new ByteArrayInputStream((byte[]) data);\r
+        } else {\r
+            throw new IllegalStateException("unknown data format : "\r
+                    + data.getClass());\r
+        }\r
+    }\r
+\r
+    private IppResponse getResponse() throws IOException {\r
+        if (this.conn.getStatusCode()==HttpURLConnection.HTTP_OK) {\r
+            return new IppResponseIppImpl(conn.getIppResponse());\r
+        } else {\r
+            return null;\r
+        }\r
+    }\r
+\r
+}
\ No newline at end of file
diff --git a/jspi/src/main/java/de/lohndirekt/print/IppRequestFactory.java b/jspi/src/main/java/de/lohndirekt/print/IppRequestFactory.java
new file mode 100644 (file)
index 0000000..c9c8e8d
--- /dev/null
@@ -0,0 +1,73 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+\r
+import java.lang.reflect.Constructor;\r
+import java.net.URI;\r
+\r
+import javax.print.attribute.AttributeSet;\r
+import javax.print.attribute.HashAttributeSet;\r
+import javax.print.attribute.standard.RequestingUserName;\r
+\r
+import de.lohndirekt.print.attribute.auth.RequestingUserPassword;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.OperationsSupported;\r
+\r
+/**\r
+ * @author bpusch\r
+ *  \r
+ */\r
+public final class IppRequestFactory {\r
+\r
+    final static String IPP_REQUEST_IMPL_KEY = "de.lohndirekt.print.IppRequest.Impl";\r
+\r
+    final static IppRequest createIppRequest(URI uri,\r
+            OperationsSupported operation, RequestingUserName user,\r
+            RequestingUserPassword passwd) {\r
+        String requestClassName = System.getProperty(IPP_REQUEST_IMPL_KEY);\r
+        IppRequest request = null;\r
+        if (requestClassName == null) {\r
+            request = new IppRequestCupsImpl(uri, operation);\r
+        } else {\r
+            Class clazz = null;\r
+            try {\r
+                clazz = Class.forName(requestClassName);\r
+            } catch (ClassNotFoundException e) {\r
+                throw new IllegalArgumentException("Class " + requestClassName\r
+                        + " does not exist.");\r
+            }\r
+\r
+            try {\r
+                Constructor constructor = clazz\r
+                        .getDeclaredConstructor(new Class[] { URI.class,\r
+                                OperationsSupported.class });\r
+                request = (IppRequest) constructor.newInstance(new Object[] {\r
+                        uri, operation });\r
+            } catch (Exception e) {\r
+                throw new RuntimeException(e);\r
+            }\r
+        }\r
+        if (user != null && passwd != null) {\r
+            AttributeSet set = new HashAttributeSet();\r
+            set.add(user);\r
+            set.add(passwd);\r
+            request.addOperationAttributes(set);\r
+        }\r
+        return request;\r
+    }\r
+}
\ No newline at end of file
diff --git a/jspi/src/main/java/de/lohndirekt/print/IppResponse.java b/jspi/src/main/java/de/lohndirekt/print/IppResponse.java
new file mode 100644 (file)
index 0000000..5a7b65a
--- /dev/null
@@ -0,0 +1,38 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+\r
+import java.util.Map;\r
+\r
+import de.lohndirekt.print.attribute.IppStatus;\r
+\r
+/**\r
+ * @author sefftinge\r
+ *\r
+ */\r
+public interface IppResponse {\r
+    /**\r
+     * @return attributes\r
+     */\r
+    public abstract Map getAttributes();\r
+    /**\r
+     * @return the IppStatus \r
+     */\r
+    public abstract IppStatus getStatus();\r
+}
\ No newline at end of file
diff --git a/jspi/src/main/java/de/lohndirekt/print/IppServer.java b/jspi/src/main/java/de/lohndirekt/print/IppServer.java
new file mode 100644 (file)
index 0000000..82ea7ff
--- /dev/null
@@ -0,0 +1,94 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+\r
+import java.io.IOException;\r
+import java.net.URI;\r
+import java.util.ArrayList;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Set;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import javax.print.attribute.Attribute;\r
+import javax.print.attribute.URISyntax;\r
+import javax.print.attribute.standard.RequestingUserName;\r
+\r
+import de.lohndirekt.print.attribute.IppAttributeName;\r
+import de.lohndirekt.print.attribute.auth.RequestingUserPassword;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.OperationsSupported;\r
+\r
+/**\r
+ * @author bpusch\r
+ *\r
+ */\r
+class IppServer {\r
+\r
+       private final Logger log = Logger.getLogger(this.getClass().getName());\r
+       private URI uri;\r
+       private RequestingUserName user;\r
+       private RequestingUserPassword passwd;\r
+       \r
+       IppServer(URI uri, RequestingUserName user, RequestingUserPassword passwd) {\r
+               this.uri = uri;\r
+               this.user = user;\r
+               this.passwd = passwd;\r
+       }\r
+\r
+       /**\r
+        * @return a list of all PrintServices (printers as well as classes)\r
+        *                      known to the CUPS server  \r
+        */\r
+       List getPrintServices() {\r
+               List services = new ArrayList();\r
+               services.addAll(getServices(OperationsSupported.CUPS_GET_PRINTERS,user,passwd));\r
+               services.addAll(getServices(OperationsSupported.CUPS_GET_CLASSES,user,passwd));\r
+               return services;\r
+       }\r
+       \r
+       private List getServices(OperationsSupported operation,RequestingUserName user, RequestingUserPassword passwd){\r
+               if (!(operation==OperationsSupported.CUPS_GET_CLASSES || operation == OperationsSupported.CUPS_GET_PRINTERS)){\r
+                       throw new IllegalArgumentException("Operation not applicable");\r
+               }\r
+               IppResponse response = null;\r
+               IppRequest request = IppRequestFactory.createIppRequest(this.uri, operation,user,passwd);\r
+               try {\r
+                       response = request.send();\r
+               } catch (IOException e) {\r
+                       log.log(Level.SEVERE, e.getMessage(),e);\r
+               }\r
+               List services = new ArrayList();\r
+               if (response != null) {\r
+                       Set uriAttributes = (Set)response.getAttributes().get(IppAttributeName.PRINTER_URI_SUPPORTED.getCategory());\r
+                       if (uriAttributes != null) {\r
+                               for (Iterator iter = uriAttributes.iterator(); iter.hasNext();) {\r
+                                       Attribute attribute = (Attribute)iter.next();\r
+                                       URI printerUri = ((URISyntax)attribute).getURI();\r
+                                       IppPrintService service = new IppPrintService(printerUri);\r
+                                       service.setRequestingUserName(user);\r
+                                       service.setRequestingUserPassword(passwd);\r
+                                       services.add(service);\r
+                               }\r
+                       }\r
+               }\r
+               return services;\r
+       }\r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/Job.java b/jspi/src/main/java/de/lohndirekt/print/Job.java
new file mode 100644 (file)
index 0000000..a9b3188
--- /dev/null
@@ -0,0 +1,305 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+\r
+import java.io.IOException;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import javax.print.Doc;\r
+import javax.print.DocPrintJob;\r
+import javax.print.PrintException;\r
+import javax.print.PrintService;\r
+import javax.print.attribute.Attribute;\r
+import javax.print.attribute.AttributeSet;\r
+import javax.print.attribute.HashAttributeSet;\r
+import javax.print.attribute.HashPrintJobAttributeSet;\r
+import javax.print.attribute.PrintJobAttribute;\r
+import javax.print.attribute.PrintJobAttributeSet;\r
+import javax.print.attribute.PrintRequestAttributeSet;\r
+import javax.print.event.PrintJobAttributeListener;\r
+import javax.print.event.PrintJobEvent;\r
+import javax.print.event.PrintJobListener;\r
+\r
+import de.lohndirekt.print.attribute.AttributeHelper;\r
+import de.lohndirekt.print.attribute.IppAttributeName;\r
+import de.lohndirekt.print.attribute.IppStatus;\r
+import de.lohndirekt.print.attribute.ipp.jobdesc.JobId;\r
+import de.lohndirekt.print.attribute.ipp.jobdesc.JobUri;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.OperationsSupported;\r
+\r
+/**\r
+ * @author bpusch\r
+ *\r
+ */\r
+class Job implements DocPrintJob {\r
+       protected boolean ok = false;\r
+       protected Logger log = Logger.getLogger(this.getClass().getName());\r
+       protected IppPrintService printService;\r
+       private PrintJobAttributeSet jobAttributes;\r
+       protected JobUri jobUri;\r
+       private List jobListeners;\r
+       private Map attributeListeners;\r
+\r
+       /**\r
+        * @param service\r
+        */\r
+       public Job(IppPrintService service) {\r
+               this.printService = service;\r
+       }\r
+\r
+       /**\r
+        *\r
+        */\r
+       public PrintService getPrintService() {\r
+               return this.printService;\r
+       }\r
+\r
+       /**\r
+        *\r
+        */\r
+       public PrintJobAttributeSet getAttributes() {\r
+               return this.jobAttributes;\r
+       }\r
+\r
+       /**\r
+        *\r
+        */\r
+       public void print(Doc doc, PrintRequestAttributeSet attributes) throws PrintException {\r
+               IppRequest request = null;\r
+               request = this.printService.request(OperationsSupported.PRINT_JOB);\r
+               try {\r
+                       request.setData(doc.getStreamForBytes());\r
+               } catch (IOException e) {\r
+                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                       throw new PrintException("Error getting document data (" + description(attributes) + "): " + e.getMessage());\r
+               }\r
+               //add the operation attributes\r
+               AttributeSet operationAttributes = new HashAttributeSet();\r
+               operationAttributes.addAll(AttributeHelper.jobOperationAttributes(attributes));\r
+               operationAttributes.addAll(AttributeHelper.docOperationAttributes(doc));\r
+               request.addOperationAttributes(operationAttributes);\r
+               //set the job template attributes\r
+               request.setJobAttributes(AttributeHelper.jobAttributes(attributes));\r
+               IppResponse response = null;\r
+               try {\r
+                       response = request.send();\r
+                       notifyJobListeners(PrintJobEvent.DATA_TRANSFER_COMPLETE);\r
+               } catch (IOException e) {\r
+                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                       throw new PrintException("Error sending " + description(attributes) + " to IPP service: " + e.getMessage());\r
+               }\r
+               if (response != null && response.getStatus()!=null) {\r
+                       Map responseAttributes = response.getAttributes();\r
+                       updateAttributes(responseAttributes);\r
+                       if (response.getStatus().equals(IppStatus.SUCCESSFUL_OK)\r
+                               || response.getStatus().equals(IppStatus.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES)\r
+                               || response.getStatus().equals(IppStatus.SUCCESSFUL_OK_IGNORED_OR_SUBSTITUTED_ATTRIBUTES)) {\r
+                               if (responseAttributes.containsKey(IppAttributeName.JOB_URI.getCategory())) {\r
+                                       Set jobUriList = (Set) responseAttributes.get(IppAttributeName.JOB_URI.getCategory());\r
+                                       this.jobUri = (JobUri) jobUriList.iterator().next();\r
+                               }\r
+                               notifyJobListeners(PrintJobEvent.JOB_COMPLETE);\r
+                               this.ok = true;\r
+                       } else {\r
+                               notifyJobListeners(PrintJobEvent.JOB_FAILED);\r
+                               this.ok = false;\r
+                       }\r
+               } else {\r
+                       notifyJobListeners(PrintJobEvent.JOB_FAILED);\r
+                       this.ok = false;\r
+               }\r
+               notifyJobListeners(PrintJobEvent.NO_MORE_EVENTS);\r
+               if (!this.ok){\r
+                   String msg = "Printing " + description(attributes) + "  failed";\r
+                   if (response != null && response.getStatus()!=null) {\r
+                       msg+=": Server status was '"+response.getStatus().getStatus()+" - "+response.getStatus().getText()+"'!";\r
+                   }\r
+                       throw new PrintException(msg);\r
+               }\r
+       }\r
+\r
+       \r
+\r
+       public void addPrintJobListener(PrintJobListener listener) {\r
+               if (listener != null) {\r
+                       if (jobListeners == null) {\r
+                               jobListeners = new ArrayList();\r
+                       }\r
+                       jobListeners.add(listener);\r
+               }\r
+       }\r
+\r
+       public void removePrintJobListener(PrintJobListener listener) {\r
+               if (listener != null) {\r
+                       jobListeners.remove(listener);\r
+               }\r
+       }\r
+\r
+       public void addPrintJobAttributeListener(PrintJobAttributeListener listener, PrintJobAttributeSet attributes) {\r
+               if (listener != null) {\r
+                       if (attributeListeners == null) {\r
+                               attributeListeners = new HashMap();\r
+                       }\r
+                       attributeListeners.put(listener, attributes);\r
+               }\r
+       }\r
+\r
+       public void removePrintJobAttributeListener(PrintJobAttributeListener listener) {\r
+               if (listener != null) {\r
+                       attributeListeners.remove(listener);\r
+               }\r
+       }\r
+\r
+       void notifyJobListeners(int eventType) {\r
+               if (jobListeners != null) {\r
+                       PrintJobEvent event = new PrintJobEvent(this, eventType);\r
+                       for (Iterator iter = jobListeners.iterator(); iter.hasNext();) {\r
+                               PrintJobListener listener = (PrintJobListener) iter.next();\r
+                               if (eventType == PrintJobEvent.DATA_TRANSFER_COMPLETE) {\r
+                                       listener.printDataTransferCompleted(event);\r
+                               } else if (eventType == PrintJobEvent.JOB_CANCELED) {\r
+                                       listener.printJobCanceled(event);\r
+                               } else if (eventType == PrintJobEvent.JOB_COMPLETE) {\r
+                                       listener.printJobCompleted(event);\r
+                               } else if (eventType == PrintJobEvent.JOB_FAILED) {\r
+                                       listener.printJobFailed(event);\r
+                               } else if (eventType == PrintJobEvent.NO_MORE_EVENTS) {\r
+                                       listener.printJobNoMoreEvents(event);\r
+                               } else if (eventType == PrintJobEvent.REQUIRES_ATTENTION) {\r
+                                       listener.printJobRequiresAttention(event);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       IppResponse sendRequest(OperationsSupported operation, AttributeSet operationAttributes) throws IOException {\r
+               IppRequest request = this.request(operation);\r
+               request.addOperationAttributes(operationAttributes);\r
+               IppResponse response = null;\r
+               response = request.send();\r
+               return response;\r
+       }\r
+\r
+       private IppRequest request(OperationsSupported operation) {\r
+               IppRequest request = IppRequestFactory.createIppRequest(this.jobUri.getURI(), operation, this.printService.getRequestingUserName(), this.printService.getRequestingUserPassword());\r
+               AttributeSet operationAttributes = new HashAttributeSet();\r
+               operationAttributes.add(this.jobUri);\r
+               request.addOperationAttributes(operationAttributes);\r
+               return request;\r
+       }\r
+\r
+       //  public methods which are not part of the JPS API\r
+       /**\r
+        * \r
+        * This method returns the Job with the given JobId that is held by \r
+        * the given PrintService.\r
+        * <br>\r
+        * This method might return a Job which is not hold by this PrintService\r
+        * but the same CUPS server \r
+        * \r
+        * @param service\r
+        * @param id\r
+        * @return the corresponding Job wihth the given JobId, or null if no such \r
+        *          Job exists\r
+        * @throws PrintException\r
+        */\r
+       static Job getJob(IppPrintService service, JobId id) throws PrintException {\r
+               Job job = new Job(service);\r
+               job.printService = service;\r
+               URI jobUri;\r
+               try {\r
+                       jobUri =\r
+                               new URI(\r
+                                       service.getUri().getScheme(),\r
+                                       service.getUri().getAuthority(),\r
+                                       "/jobs/" + id.getValue(),\r
+                                       service.getUri().getQuery(),\r
+                                       service.getUri().getFragment());\r
+               } catch (URISyntaxException e) {\r
+                       throw new PrintException("Internal bug.", e);\r
+               }\r
+               job.jobUri = new JobUri(jobUri);\r
+               try {\r
+                       job.updateAttributes();\r
+               } catch (IllegalStateException e) {\r
+                       job = null;\r
+               }\r
+               return job;\r
+       }\r
+       \r
+       /**\r
+        * @param responseAttributes\r
+        */\r
+       private void updateAttributes(Map responseAttributes) {\r
+               this.jobAttributes = new HashPrintJobAttributeSet();\r
+               for (Iterator iter = responseAttributes.values().iterator(); iter.hasNext();) {\r
+                       Set values = (Set) iter.next();\r
+                       for (Iterator listIter = values.iterator(); listIter.hasNext();) {\r
+                               Attribute attribute = (Attribute) listIter.next();\r
+                               if (attribute instanceof PrintJobAttribute)\r
+                                       this.jobAttributes.add(attribute);\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Updates the Job's attributes to the current values.\r
+        * \r
+        * @throws PrintException\r
+        */\r
+       private void updateAttributes() throws PrintException {\r
+               try {\r
+                   AttributeSet operationAttributes = new HashAttributeSet();\r
+                       IppResponse response = sendRequest(OperationsSupported.GET_JOB_ATTRIBUTES, operationAttributes);\r
+                       if (!response.getStatus().equals(IppStatus.SUCCESSFUL_OK)\r
+                               && !response.getStatus().equals(IppStatus.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES)\r
+                               && !response.getStatus().equals(IppStatus.SUCCESSFUL_OK_IGNORED_OR_SUBSTITUTED_ATTRIBUTES)) {\r
+                               if (response.getStatus().equals(IppStatus.CLIENT_ERROR_NOT_FOUND)) {\r
+                                       throw new IllegalStateException("Job with uri '" + this.jobUri.toString() + "does not exist.");\r
+                               }\r
+                               throw new PrintException("Request not successful.");\r
+                       }\r
+                       Map attribsMap = response.getAttributes();\r
+                       updateAttributes(attribsMap);\r
+                       \r
+               } catch (IOException e) {\r
+                       throw new PrintException("Update failed.", e);\r
+               }\r
+       }\r
+       \r
+       private String description(PrintRequestAttributeSet attributes){\r
+               String description = "job";\r
+               if (attributes != null){\r
+                       Attribute jobName = attributes.get(IppAttributeName.JOB_NAME.getCategory());\r
+                       if (jobName != null){\r
+                               description += " " + jobName.toString();\r
+                       }\r
+               }\r
+               return description;\r
+       }\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/MediaMultiDoc.java b/jspi/src/main/java/de/lohndirekt/print/MediaMultiDoc.java
new file mode 100644 (file)
index 0000000..d476a3b
--- /dev/null
@@ -0,0 +1,51 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+\r
+import javax.print.Doc;\r
+import javax.print.attribute.standard.Media;\r
+\r
+\r
+\r
+/**\r
+ * @author bpusch\r
+ *\r
+ */\r
+class MediaMultiDoc extends SimpleMultiDoc {\r
+       \r
+       Media media = null;\r
+       \r
+       public static MediaMultiDoc create(Doc doc, Media media) {\r
+               \r
+               return new MediaMultiDoc(doc, media, false);\r
+       }\r
+\r
+       public static SimpleMultiDoc create(Doc doc, Media media, boolean lastDoc) {\r
+               return new MediaMultiDoc(doc, media, lastDoc);\r
+       }\r
+\r
+       /**\r
+        * \r
+        */\r
+       private MediaMultiDoc(Doc doc, Media media, boolean lastDoc) {\r
+               super(doc,lastDoc);\r
+               this.media = media;\r
+       }\r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/MediaMultiDocJob.java b/jspi/src/main/java/de/lohndirekt/print/MediaMultiDocJob.java
new file mode 100644 (file)
index 0000000..1c43253
--- /dev/null
@@ -0,0 +1,33 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+\r
+/**\r
+ * @author bpusch\r
+ *\r
+ */\r
+class MediaMultiDocJob extends MultiDocJob {\r
+\r
+    /**\r
+     * @param service\r
+     */\r
+    public MediaMultiDocJob(IppMultiDocPrintService service) {\r
+        super(service);\r
+    }\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/Messages.java b/jspi/src/main/java/de/lohndirekt/print/Messages.java
new file mode 100644 (file)
index 0000000..f13b181
--- /dev/null
@@ -0,0 +1,52 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+\r
+import java.util.MissingResourceException;\r
+import java.util.ResourceBundle;\r
+\r
+/**\r
+ * @author ld-development\r
+ *\r
+ * \r
+ */\r
+public class Messages {\r
+\r
+    private static final String BUNDLE_NAME = "de.lohndirekt.print.test"; //$NON-NLS-1$\r
+\r
+    private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);\r
+\r
+    /**\r
+     * \r
+     */\r
+    private Messages() {\r
+\r
+    }\r
+    /**\r
+     * @param key\r
+     * @return\r
+     */\r
+    public static String getString(String key) {\r
+        try {\r
+            return RESOURCE_BUNDLE.getString(key);\r
+        } catch (MissingResourceException e) {\r
+            return '!' + key + '!';\r
+        }\r
+    }\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/MultiDocEvent.java b/jspi/src/main/java/de/lohndirekt/print/MultiDocEvent.java
new file mode 100644 (file)
index 0000000..33880b6
--- /dev/null
@@ -0,0 +1,38 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+\r
+package de.lohndirekt.print;\r
+\r
+import javax.print.MultiDoc;\r
+import javax.print.event.PrintEvent;\r
+\r
+/**\r
+ * @author bpusch\r
+ *\r
+ */\r
+class MultiDocEvent extends PrintEvent {\r
+       \r
+       /**\r
+        * \r
+        */\r
+       public MultiDocEvent(MultiDoc source)  {\r
+               super(source);\r
+       }\r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/MultiDocJob.java b/jspi/src/main/java/de/lohndirekt/print/MultiDocJob.java
new file mode 100644 (file)
index 0000000..a16a655
--- /dev/null
@@ -0,0 +1,177 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import javax.print.DocFlavor;\r
+import javax.print.MultiDoc;\r
+import javax.print.MultiDocPrintJob;\r
+import javax.print.PrintException;\r
+import javax.print.attribute.AttributeSet;\r
+import javax.print.attribute.DocAttributeSet;\r
+import javax.print.attribute.HashAttributeSet;\r
+import javax.print.attribute.PrintRequestAttributeSet;\r
+import javax.print.event.PrintJobEvent;\r
+\r
+import de.lohndirekt.print.attribute.AttributeHelper;\r
+import de.lohndirekt.print.attribute.IppAttributeName;\r
+import de.lohndirekt.print.attribute.IppStatus;\r
+import de.lohndirekt.print.attribute.ipp.jobdesc.JobUri;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.OperationsSupported;\r
+/**\r
+ * @author bpusch\r
+ *\r
+ */\r
+class MultiDocJob extends Job implements MultiDocPrintJob {\r
+    \r
+       Logger log = Logger.getLogger(this.getClass().getName());\r
+    \r
+       /**\r
+        * \r
+        */\r
+       protected MultiDocJob(IppMultiDocPrintService service) {\r
+               super(service);\r
+       }\r
+    \r
+       void processMultiDocEvent(MultiDocEvent event) {\r
+               SimpleMultiDoc doc = (SimpleMultiDoc) event.getSource();\r
+               sendDocument(doc);\r
+       }\r
+    \r
+       /**\r
+        *\r
+        */\r
+       public void print(MultiDoc multiDoc, PrintRequestAttributeSet attributes) throws PrintException {\r
+               SimpleMultiDoc multi = (SimpleMultiDoc) multiDoc;\r
+               multi.addMultiDocListener(new MDListener());\r
+               createJob(attributes);\r
+               sendDocument(multi);\r
+       }\r
+    \r
+       private void createJob(PrintRequestAttributeSet attributes) {\r
+               IppRequest request = null;\r
+               request = this.printService.request(OperationsSupported.CREATE_JOB);\r
+               //add the operationn attributes\r
+               request.addOperationAttributes(AttributeHelper.jobOperationAttributes(attributes));\r
+               request.setJobAttributes(AttributeHelper.jobAttributes(attributes));\r
+               IppResponse response = null;\r
+               try {\r
+                       response = request.send();\r
+               } catch (IOException e) {\r
+                       log.log(Level.SEVERE, e.getMessage(), e);\r
+               }\r
+               if (response != null) {\r
+                       Map responseAttributes = response.getAttributes();\r
+                       if (responseAttributes.containsKey(IppAttributeName.JOB_URI.getCategory())) {\r
+                               Set jobUriSet = (Set) responseAttributes.get(IppAttributeName.JOB_URI.getCategory());\r
+                               this.jobUri = (JobUri) jobUriSet.iterator().next();\r
+                       }\r
+                       if (response.getStatus().equals(IppStatus.SUCCESSFUL_OK)\r
+                               || response.getStatus().equals(IppStatus.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES)\r
+                               || response.getStatus().equals(IppStatus.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES)) {\r
+                       } else {\r
+                               notifyJobListeners(PrintJobEvent.JOB_FAILED);\r
+                       }\r
+               } else {\r
+                       notifyJobListeners(PrintJobEvent.JOB_FAILED);\r
+               }\r
+       }\r
+    \r
+       protected void sendDocument(SimpleMultiDoc multiDoc) {\r
+               IppRequest request = null;\r
+               AttributeSet operationAttributes = new HashAttributeSet();\r
+               request = this.request(OperationsSupported.SEND_DOCUMENT);\r
+               IppResponse response = null;\r
+               try {\r
+                       operationAttributes.addAll(AttributeHelper.docOperationAttributes(multiDoc));\r
+                       request.addOperationAttributes(operationAttributes);\r
+                       if (multiDoc.getDoc().getDocFlavor() instanceof DocFlavor.INPUT_STREAM) {\r
+                               DocAttributeSet set = multiDoc.getDoc().getAttributes();\r
+                               request.setData((InputStream) multiDoc.getDoc().getPrintData());\r
+                       }\r
+                       response = request.send();\r
+               } catch (IOException e) {\r
+                       log.log(Level.SEVERE, e.getMessage(), e);\r
+               }\r
+               if (response != null) {\r
+                       Map responseAttributes = response.getAttributes();\r
+                       if (responseAttributes.containsKey(IppAttributeName.JOB_URI.getCategory())) {\r
+                               Set jobUriSet = (Set) responseAttributes.get(IppAttributeName.JOB_URI.getCategory());\r
+                               this.jobUri = (JobUri) jobUriSet.iterator().next();\r
+                       }\r
+                       if (response.getStatus().equals(IppStatus.SUCCESSFUL_OK)\r
+                               || response.getStatus().equals(IppStatus.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES)\r
+                               || response.getStatus().equals(IppStatus.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES)) {\r
+                       } else {\r
+                               notifyJobListeners(PrintJobEvent.JOB_FAILED);\r
+                       }\r
+               } else {\r
+                       notifyJobListeners(PrintJobEvent.JOB_FAILED);\r
+               }\r
+               if (multiDoc.isLast()) {\r
+                       releaseJob();\r
+               }\r
+       }\r
+    \r
+       /**\r
+        * \r
+        */\r
+       private void releaseJob() {\r
+               IppRequest request = this.request(OperationsSupported.RELEASE_JOB);\r
+               IppResponse response = null;\r
+               try {\r
+                       response = request.send();\r
+                       \r
+               } catch (IOException e) {\r
+                       log.log(Level.SEVERE, e.getMessage(), e);\r
+               }\r
+               if (response != null) {\r
+                       if (response.getStatus().equals(IppStatus.SUCCESSFUL_OK)\r
+                               || response.getStatus().equals(IppStatus.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES)\r
+                               || response.getStatus().equals(IppStatus.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES)) {\r
+                               notifyJobListeners(PrintJobEvent.JOB_COMPLETE);\r
+                       } else {\r
+                               notifyJobListeners(PrintJobEvent.JOB_FAILED);\r
+                       }\r
+               } else {\r
+                       notifyJobListeners(PrintJobEvent.JOB_FAILED);\r
+               }\r
+       }\r
+    \r
+       private IppRequest request(OperationsSupported operation) {\r
+               IppRequest request = IppRequestFactory.createIppRequest(this.jobUri.getURI(), operation, this.printService.getRequestingUserName(), this.printService.getRequestingUserPassword());\r
+               AttributeSet operationAttributes = new HashAttributeSet();\r
+               operationAttributes.add(new JobUri(this.jobUri.getURI()));\r
+               request.addOperationAttributes(operationAttributes);\r
+               return request;\r
+       }\r
+    \r
+       private class MDListener implements MultiDocListener {\r
+               public void processEvent(MultiDocEvent event) throws IOException {\r
+                       log.log(Level.FINEST, "MultiDocevent");\r
+                       processMultiDocEvent(event);\r
+               }\r
+       }\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/MultiDocListener.java b/jspi/src/main/java/de/lohndirekt/print/MultiDocListener.java
new file mode 100644 (file)
index 0000000..5372dee
--- /dev/null
@@ -0,0 +1,35 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+\r
+package de.lohndirekt.print;\r
+\r
+import java.io.IOException;\r
+\r
+\r
+\r
+/**\r
+ * @author bpusch\r
+ *\r
+ */\r
+interface MultiDocListener {\r
+\r
+       \r
+       public void processEvent(MultiDocEvent event) throws IOException;\r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/SimpleMultiDoc.java b/jspi/src/main/java/de/lohndirekt/print/SimpleMultiDoc.java
new file mode 100644 (file)
index 0000000..4146418
--- /dev/null
@@ -0,0 +1,135 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+\r
+import java.io.IOException;\r
+import java.util.ArrayList;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+\r
+import javax.print.Doc;\r
+import javax.print.MultiDoc;\r
+\r
+/**\r
+ * @author bpusch\r
+ *\r
+ */\r
+public class SimpleMultiDoc implements MultiDoc {\r
+\r
+    private List listeners;\r
+    Doc doc = null;\r
+    boolean lastDoc = false;\r
+    SimpleMultiDoc next = null;\r
+\r
+    public static SimpleMultiDoc create(Doc doc) {\r
+        return new SimpleMultiDoc(doc, false);\r
+    }\r
+\r
+    public static SimpleMultiDoc create(Doc doc, boolean lastDoc) {\r
+        return new SimpleMultiDoc(doc, lastDoc);\r
+    }\r
+\r
+    /**\r
+     * \r
+     */\r
+    protected SimpleMultiDoc(Doc doc, boolean lastDoc) {\r
+        if (doc == null) {\r
+            throw new NullPointerException("Doc must not be null");\r
+        }\r
+        this.doc = doc;\r
+        this.lastDoc = lastDoc;\r
+    }\r
+\r
+    /**\r
+     * Adds a new MultiDoc.\r
+     * If the next MultiDoc has already been set, it tries to add it there\r
+     * \r
+     * @param doc\r
+     * @param lastDoc\r
+     * @throws IllegalStateException if this has already been the last Document\r
+     */\r
+    public void setNext(Doc doc, boolean lastDoc) {\r
+        if (this.lastDoc) {\r
+            throw new IllegalStateException("Last Doc already sent");\r
+        }\r
+        if (doc == null) {\r
+            throw new NullPointerException("Doc must not be null");\r
+        }\r
+        if (next == null) {\r
+            this.next = new SimpleMultiDoc(doc, lastDoc);\r
+        } else {\r
+            this.next.setNext(doc, lastDoc);\r
+        }\r
+        this.notifyListeners();\r
+    }\r
+\r
+    public void setNext(Doc doc) {\r
+        setNext(doc, false);\r
+    }\r
+\r
+    /**\r
+     *\r
+     */\r
+\r
+    public Doc getDoc() throws IOException {\r
+        return this.doc;\r
+    }\r
+\r
+    /**\r
+     *\r
+     */\r
+    public MultiDoc next() throws IOException {\r
+        if (!this.available()) {\r
+            throw new IllegalStateException("Next MultiDoc is not yet available");\r
+        }\r
+        return this.next;\r
+    }\r
+\r
+    public boolean available() {\r
+        return (!this.lastDoc && this.next != null);\r
+    }\r
+\r
+    public boolean isLast() {\r
+        return lastDoc;\r
+    }\r
+\r
+    public String toString() {\r
+        return this.getClass() + " - " + this.doc.toString();\r
+    }\r
+\r
+    public void addMultiDocListener(MultiDocListener listener) {\r
+        if (this.listeners == null) {\r
+            this.listeners = new ArrayList();\r
+        }\r
+        this.listeners.add(listener);\r
+    }\r
+\r
+    private void notifyListeners() {\r
+        if (this.listeners != null) {\r
+            for (Iterator iter = this.listeners.iterator(); iter.hasNext();) {\r
+                MultiDocListener listener = (MultiDocListener) iter.next();\r
+                try {\r
+                    listener.processEvent(new MultiDocEvent(this.next));\r
+                } catch (IOException e) {\r
+                    //TODO handle exception appropriatly\r
+                }\r
+            }\r
+        }\r
+    }\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/TestJarLookup.java b/jspi/src/main/java/de/lohndirekt/print/TestJarLookup.java
new file mode 100644 (file)
index 0000000..5eb784a
--- /dev/null
@@ -0,0 +1,46 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print;\r
+\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+\r
+import javax.print.PrintService;\r
+\r
+import de.lohndirekt.print.IppPrintServiceLookup;\r
+\r
+/**\r
+ * @author sefftinge\r
+ *\r
+ */\r
+public class TestJarLookup {\r
+\r
+    public static void main(String[] args) throws URISyntaxException {\r
+        System.getProperties().setProperty("de.lohndirekt.print.IppPrintService.uri", "192.168.0.60:631");\r
+        testServices();\r
+    }\r
+\r
+    private static void testServices() throws URISyntaxException {\r
+        PrintService[] services = new IppPrintServiceLookup(new URI("ipp://192.168.0.60:631"),"username","password").getPrintServices();\r
+        for (int i = 0; i < services.length; i++) {\r
+            PrintService service = services[i];\r
+            System.out.println(service.getName());\r
+        }\r
+    }\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/attribute/AttributeHelper.java b/jspi/src/main/java/de/lohndirekt/print/attribute/AttributeHelper.java
new file mode 100644 (file)
index 0000000..96db01b
--- /dev/null
@@ -0,0 +1,168 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print.attribute;\r
+\r
+import java.io.IOException;\r
+import java.util.Locale;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import javax.print.Doc;\r
+import javax.print.attribute.Attribute;\r
+import javax.print.attribute.AttributeSet;\r
+import javax.print.attribute.HashAttributeSet;\r
+import javax.print.attribute.HashPrintJobAttributeSet;\r
+import javax.print.attribute.PrintJobAttribute;\r
+import javax.print.attribute.PrintJobAttributeSet;\r
+import javax.print.attribute.PrintRequestAttributeSet;\r
+import javax.print.attribute.standard.DocumentName;\r
+\r
+import de.lohndirekt.print.SimpleMultiDoc;\r
+import de.lohndirekt.print.attribute.ipp.DocumentFormat;\r
+import de.lohndirekt.print.attribute.ipp.LastDocument;\r
+\r
+/**\r
+ * @author ld-development\r
+ *\r
+ * \r
+ */\r
+public final class AttributeHelper {\r
+\r
+    private final static Logger log = Logger.getLogger(AttributeHelper.class.getName());\r
+    /**\r
+     * filters the given attributes\r
+     * \r
+     * @param attributes\r
+     * @return only the attributes wich are of type <code>PrintJobAttribute</code> and not operation attributes \r
+     */\r
+    public final static PrintJobAttributeSet jobAttributes(PrintRequestAttributeSet attributes) {\r
+        PrintJobAttributeSet jobAttributes = new HashPrintJobAttributeSet();\r
+        if (attributes != null) {\r
+            AttributeSet invalidAttributes = jobOperationAttributes(attributes);\r
+            Object[] attributeArray = attributes.toArray();\r
+            for (int i = 0; i < attributeArray.length; i++) {\r
+                Attribute attribute = (Attribute) attributeArray[i];\r
+                //attributes-charset, attributes-natural-language etc. are not set by the user\r
+                if (attribute instanceof PrintJobAttribute && !(invalidAttributes.containsValue(attribute))) {\r
+                    jobAttributes.add(attribute);\r
+                }\r
+            }\r
+        }\r
+        return jobAttributes;\r
+    }\r
+\r
+    /**\r
+     * filters the given attributes\r
+     * \r
+     * @param attributes\r
+     * @return only job-operation attributes\r
+     */\r
+    public final static AttributeSet jobOperationAttributes(PrintRequestAttributeSet attributes) {\r
+        AttributeSet operationAttributes = new HashAttributeSet();\r
+        if (attributes != null) {\r
+            Object[] attributeArray = attributes.toArray();\r
+            for (int i = 0; i < attributeArray.length; i++) {\r
+                Attribute attribute = (Attribute) attributeArray[i];\r
+                //attributes-charset, attributes-natural-language etc. are not set by the user\r
+                if (attribute.getCategory().equals(IppAttributeName.JOB_NAME.getCategory())\r
+                    || attribute.getCategory().equals(IppAttributeName.FIDELITY.getCategory())\r
+                    || attribute.getCategory().equals(IppAttributeName.JOB_IMPRESSIONS.getCategory())\r
+                    || attribute.getCategory().equals(IppAttributeName.JOB_K_OCTETS.getCategory())\r
+                    || attribute.getCategory().equals(IppAttributeName.JOB_MEDIA_SHEETS.getCategory())\r
+                    || attribute.getCategory().equals(IppAttributeName.JOB_NAME.getCategory())\r
+                    || attribute.getCategory().equals(IppAttributeName.COMPRESSION.getCategory())\r
+                    || attribute.getCategory().equals(IppAttributeName.REQUESTING_USER_NAME.getCategory())\r
+                    || attribute.getCategory().equals(IppAttributeName.REQUESTING_USER_PASSWD.getCategory())) {\r
+                    operationAttributes.add(attribute);\r
+                }\r
+            }\r
+        }\r
+        return operationAttributes;\r
+    }\r
+\r
+    /**\r
+     * @param multiDoc\r
+     * @return a <code>List</code> with the document-format, document-name and last-document\r
+     */\r
+    public final static AttributeSet docOperationAttributes(SimpleMultiDoc multiDoc) {\r
+        AttributeSet operationAttributes = new HashAttributeSet();\r
+        try {\r
+            operationAttributes = docOperationAttributes(multiDoc.getDoc());\r
+        } catch (IOException e) {\r
+            log.log(Level.SEVERE, "Could not get Doc from multiDoc", e);\r
+        }\r
+        LastDocument lastDocument;\r
+        if (multiDoc.isLast()) {\r
+            lastDocument = LastDocument.TRUE;\r
+        } else {\r
+            lastDocument = LastDocument.FALSE;\r
+        }\r
+        operationAttributes.add(lastDocument);\r
+        return operationAttributes;\r
+    }\r
+\r
+    /**\r
+     * @param doc\r
+     * @return a <code>List</code> with the document-format and document-name\r
+     */\r
+    public final static AttributeSet docOperationAttributes(Doc doc) {\r
+        AttributeSet operationAttributes = new HashAttributeSet();\r
+        if (doc.getAttributes() != null) {\r
+            DocumentName docName = (DocumentName) doc.getAttributes().get(IppAttributeName.DOCUMENT_NAME.getCategory());\r
+            if (docName != null) {\r
+                operationAttributes.add(docName);\r
+            }\r
+        }\r
+        operationAttributes.add(new DocumentFormat(doc.getDocFlavor().getMimeType(), Locale.getDefault()));\r
+        return operationAttributes;\r
+    }\r
+\r
+    /**\r
+     * @param operationAttributes2\r
+     * @return\r
+     */\r
+    public final static Attribute[] getOrderedOperationAttributeArray(AttributeSet operationAttributes2) {\r
+        AttributeSet copy = new HashAttributeSet(operationAttributes2);\r
+        Attribute[] attributes = new Attribute[copy.size()];\r
+        int i = 0;\r
+        // start with Charset\r
+        Class category = IppAttributeName.CHARSET.getCategory();\r
+        if (copy.containsKey(category)) {\r
+            attributes[i] = copy.get(category);\r
+            copy.remove(category);\r
+            i++;\r
+        }\r
+        // start with Charset\r
+        category = IppAttributeName.NATURAL_LANGUAGE.getCategory();\r
+        if (copy.containsKey(category)) {\r
+            attributes[i] = copy.get(category);\r
+            copy.remove(category);\r
+            i++;\r
+        }\r
+        // add the rest\r
+        Attribute[] remaining = copy.toArray();\r
+        for (int j = 0; j < remaining.length; j++) {\r
+            attributes[i+j] = remaining[j];\r
+        }\r
+        return attributes;\r
+    }\r
+    \r
+    \r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/attribute/AttributeParser.java b/jspi/src/main/java/de/lohndirekt/print/attribute/AttributeParser.java
new file mode 100644 (file)
index 0000000..203c6ab
--- /dev/null
@@ -0,0 +1,488 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print.attribute;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.lang.reflect.Constructor;\r
+import java.lang.reflect.Field;\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.text.DateFormat;\r
+import java.text.DecimalFormat;\r
+import java.text.ParseException;\r
+import java.text.SimpleDateFormat;\r
+import java.util.Date;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.Locale;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import javax.print.attribute.Attribute;\r
+import javax.print.attribute.EnumSyntax;\r
+import javax.print.attribute.standard.JobStateReason;\r
+import javax.print.attribute.standard.JobStateReasons;\r
+import javax.print.attribute.standard.PrinterStateReason;\r
+import javax.print.attribute.standard.PrinterStateReasons;\r
+import javax.print.attribute.standard.Severity;\r
+\r
+import de.lohndirekt.print.attribute.ipp.Charset;\r
+import de.lohndirekt.print.attribute.ipp.jobdesc.LdJobStateReason;\r
+import de.lohndirekt.print.exception.EndOfAttributesException;\r
+\r
+/**\r
+ * @author bpusch\r
+ *\r
+ */\r
+public final class AttributeParser {\r
+\r
+       private final static EndOfAttributesException END_OF_ATTRIBUTES_EXCEPTION = new EndOfAttributesException();\r
+\r
+       private final static Logger log = Logger.getLogger(AttributeParser.class.getName());\r
+\r
+       \r
+\r
+       /**\r
+        * @param name\r
+        * @param values\r
+        * @return\r
+        */\r
+       private static Attribute getAttribute(String name, Object[] values) {\r
+               Attribute attribute = null;\r
+               IppAttributeName attrName = IppAttributeName.get(name);\r
+               Class attrClass = attrName.getAttributeClass();\r
+               Class superClass = attrClass.getSuperclass();\r
+               if (superClass != null) {\r
+                       if (superClass.equals(EnumSyntax.class)) {\r
+                               try {\r
+                                       Field[] fields = attrClass.getDeclaredFields();\r
+                                       for (int i = 0; i < fields.length; i++) {\r
+                                               Field field = fields[i];\r
+                                               if (field.getType().equals(attrClass)) {\r
+                                                       EnumSyntax attr = (EnumSyntax) field.get(null);\r
+                                                       if (values[0] instanceof String) {\r
+                                                               if (attr.toString().equals(values[0])) {\r
+                                                                       attribute = (Attribute) attr;\r
+                                                                       break;\r
+                                                               }\r
+                                                       } else {\r
+                                                               if (attr.getValue() == ((Integer) values[0]).intValue()) {\r
+                                                                       attribute = (Attribute) attr;\r
+                                                                       break;\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               } catch (SecurityException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (IllegalArgumentException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (IllegalAccessException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               }\r
+\r
+                       } else {\r
+                               Class[] parameters = toClassArray(values);\r
+                               try {\r
+                                       Constructor constructor = attrClass.getDeclaredConstructor(parameters);\r
+                                       attribute = (Attribute) constructor.newInstance(values);\r
+                               } catch (SecurityException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (NoSuchMethodException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (IllegalArgumentException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (InstantiationException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (IllegalAccessException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               } catch (InvocationTargetException e) {\r
+                                       log.log(Level.SEVERE, e.getMessage(), e);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               return attribute;\r
+       }\r
+\r
+       /**\r
+            * @param byteArray\r
+            * @param byteCount\r
+            * @param lastAttribute\r
+            * @return\r
+            */\r
+       private static Attribute parseAttribute(InputStream in, Attribute lastAttribute)\r
+               throws IOException, EndOfAttributesException {\r
+\r
+               int valueTag;\r
+               while ((valueTag = in.read()) < IppValueTag.UNSUPPORTED_VALUE.getValue()) {\r
+                       if (valueTag == IppDelimiterTag.END_ATTRIBUTES.getValue()) {\r
+                               throw END_OF_ATTRIBUTES_EXCEPTION;\r
+                       }\r
+               }\r
+\r
+               int nameLength = parseInt2(in);\r
+               //          parse the Attribute-Name\r
+               String name;\r
+               if (nameLength == 0) {\r
+                       name = lastAttribute.getName();\r
+               } else {\r
+                       name = parseString(in, nameLength);\r
+               }\r
+               \r
+\r
+               Object[] values = parseValues(valueTag, in);\r
+\r
+               if (name.equals(IppAttributeName.PRINTER_STATE_REASONS.getName())) {\r
+                       return parsePrinterStateReasons((String) values[0], lastAttribute);\r
+               } else if (name.equals(IppAttributeName.JOB_STATE_REASONS.getName())) {\r
+                       return parseJobStateReasons(values, lastAttribute);\r
+               } else {\r
+                       return getAttribute(name, values);\r
+               }\r
+       }\r
+    \r
+    private static String parseString(InputStream in, int nameLength) throws IOException{\r
+        return parseString(in, nameLength, Charset.US_ASCII.getValue());\r
+    }\r
+    \r
+    private static String parseNameAndTextString(InputStream in, int nameLength) throws IOException{\r
+        return parseString(in, nameLength, AttributeWriter.DEFAULT_CHARSET.getValue());\r
+    }\r
+\r
+       /**\r
+        * @param in\r
+        * @param nameLength\r
+        */\r
+       private static String parseString(InputStream in, int nameLength, String charsetName) throws IOException {\r
+               byte[] bytes = new byte[nameLength];\r
+               in.read(bytes);\r
+               return new String(bytes, charsetName);\r
+\r
+       }\r
+    \r
+    \r
+    \r
+    \r
+       /**\r
+        * @param byteArray\r
+        * @param valueOffset\r
+        * @return\r
+        */\r
+       private static Date parseDate(InputStream in) throws IOException {\r
+               DecimalFormat twoDigits = new DecimalFormat("00");\r
+        DecimalFormat threeDigits = new DecimalFormat("000");\r
+               DecimalFormat fourDigits = new DecimalFormat("0000");\r
+               //year is encoded in network-byte order\r
+               int year = parseInt2(in);\r
+               int month = in.read();\r
+               int day = in.read();\r
+               int hour = in.read();\r
+               int minute = in.read();\r
+               int second = in.read();\r
+               int deci = in.read();\r
+               int mili = deci * 100;\r
+               char direction = (char) in.read();\r
+               int hoursFromUtc = (int) in.read();\r
+               int minutesFromUtc = (int) in.read();\r
+\r
+               String yearString = fourDigits.format((long) year);\r
+               String monthString = twoDigits.format((long) month);\r
+               String dayString = twoDigits.format((long) day);\r
+               String hourString = twoDigits.format((long) hour);\r
+               String minuteString = twoDigits.format((long) minute);\r
+               String secondString = twoDigits.format((long) second);\r
+               String miliString = threeDigits.format((long) mili);\r
+               String timeZone = direction + twoDigits.format((long) hoursFromUtc) + twoDigits.format((long) minutesFromUtc);\r
+               String dateString =\r
+                       yearString\r
+                               + "-"\r
+                               + monthString\r
+                               + "-"\r
+                               + dayString\r
+                               + " "\r
+                               + hourString\r
+                               + ":"\r
+                               + minuteString\r
+                               + ":"\r
+                               + secondString\r
+                               + ":"\r
+                               + miliString\r
+                               + timeZone;\r
+               DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSSZ");\r
+               Date date = null;\r
+               try {\r
+                       date = dateFormat.parse(dateString);\r
+               } catch (ParseException e) {\r
+                       log.log(Level.SEVERE, e.getMessage(), e);\r
+               }\r
+               return date;\r
+       }\r
+\r
+       private static int parseInt4(InputStream in) throws IOException {\r
+\r
+               //Same parsing as in java.io.DataInput readInt()\r
+               int a = in.read();\r
+               int b = in.read();\r
+               int c = in.read();\r
+               int d = in.read();\r
+               int value = (((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff));\r
+               return value;\r
+       }\r
+\r
+       /**\r
+        * @param bytes\r
+        * @param offset\r
+        * @return\r
+        */\r
+       private static int parseInt4(byte[] bytes, int offset) {\r
+\r
+               //Same parsing as in java.io.DataInput readInt()\r
+               byte a = bytes[offset++];\r
+               byte b = bytes[offset++];\r
+               byte c = bytes[offset++];\r
+               byte d = bytes[offset++];\r
+               int value = (((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff));\r
+               return value;\r
+       }\r
+\r
+       private static int parseInt2(InputStream in) throws IOException {\r
+\r
+               //Same parsing as in java.io.DataInput readInt()\r
+               int a = in.read();\r
+               int b = in.read();\r
+               int value = ((a & 0xff) << 8) | ((b & 0xff));\r
+               return value;\r
+       }\r
+\r
+       \r
+\r
+       /**\r
+       * @param string\r
+       * @param lastAttribute\r
+       * @return\r
+       */\r
+       private static Attribute parseJobStateReasons(Object[] values, Attribute lastAttribute) {\r
+               JobStateReasons reasons;\r
+               if (lastAttribute instanceof JobStateReasons) {\r
+                       reasons = (JobStateReasons) lastAttribute;\r
+               } else {\r
+                       reasons = new JobStateReasons();\r
+               }\r
+               JobStateReason reason = null;\r
+               if (values[0].equals(LdJobStateReason.NONE.toString())) {\r
+                       reason = LdJobStateReason.NONE;\r
+               } else {\r
+                       reason = (JobStateReason) getAttribute(IppAttributeName.JOB_STATE_REASON.getName(), values);\r
+               }\r
+               reasons.add(reason);\r
+               return reasons;\r
+       }\r
+\r
+       /**\r
+        * @param reasonAndSeverity\r
+        * @param lastAttribute\r
+        * @return\r
+        */\r
+       private static PrinterStateReasons parsePrinterStateReasons(String reasonAndSeverity, Attribute lastAttribute) {\r
+               Severity severity = null;\r
+               int severityOffset = 0;\r
+               if ((severityOffset = reasonAndSeverity.indexOf(Severity.ERROR.toString())) > 0) {\r
+                       severity = Severity.ERROR;\r
+               } else if ((severityOffset = reasonAndSeverity.indexOf(Severity.REPORT.toString())) > 0) {\r
+                       severity = Severity.REPORT;\r
+               } else if ((severityOffset = reasonAndSeverity.indexOf(Severity.WARNING.toString())) > 0) {\r
+                       severity = Severity.WARNING;\r
+               }\r
+               String reasonString;\r
+               if (severityOffset != -1) {\r
+                       //subtract 1 for the hyphen\r
+                       severityOffset--;\r
+                       reasonString = reasonAndSeverity.substring(0, severityOffset - 1);\r
+               } else {\r
+                       reasonString = reasonAndSeverity;\r
+               }\r
+               Object[] values = new Object[] { reasonString };\r
+               PrinterStateReason reason =\r
+                       (PrinterStateReason) getAttribute(IppAttributeName.PRINTER_STATE_REASON.getName(), values);\r
+               PrinterStateReasons reasons;\r
+               if (lastAttribute instanceof PrinterStateReasons) {\r
+                       reasons = (PrinterStateReasons) lastAttribute;\r
+               } else {\r
+                       reasons = new PrinterStateReasons();\r
+               }\r
+               if (reason != null) {\r
+                       if (severity == null) {\r
+                               severity = Severity.ERROR;\r
+                       }\r
+                       reasons.put(reason, severity);\r
+               }\r
+               return reasons;\r
+       }\r
+\r
+       /**\r
+        * @param bytes\r
+        * @return map of attributes (key -> category, value -> Set with attributes)\r
+        * \r
+        *\r
+        */\r
+       public static Map parseResponse(InputStream response) throws IOException {\r
+               Map attributes = new HashMap();\r
+               long start = System.currentTimeMillis();\r
+               Attribute lastAttribute = null;\r
+               boolean finished = false;\r
+               response.read();\r
+\r
+               while (!finished) {\r
+                       Attribute attribute = null;\r
+                       try {\r
+                               attribute = parseAttribute(response, lastAttribute);\r
+                               if (attribute != null) {\r
+                                       lastAttribute = attribute;\r
+                                       attributes = put(attributes, attribute);\r
+                                       if (log.isLoggable(Level.FINEST)) {\r
+                                               log.finest("parsed attribute(" + attribute.getName() + "): " + attribute.toString());\r
+                                       }\r
+                               } else {\r
+                                       if (log.isLoggable(Level.FINEST)) {\r
+\r
+                                               log.finest("Attribute was null");\r
+                                       }\r
+                               }\r
+                       } catch (EndOfAttributesException e) {\r
+\r
+                               finished = true;\r
+                               if (log.isLoggable(Level.INFO)) {\r
+                                       log.info("--- Attribute parsing finished ---");\r
+                               }\r
+                       }\r
+               }\r
+               long end = System.currentTimeMillis();\r
+               if (log.isLoggable(Level.INFO)) {\r
+                   log.info("Parsing took " + (end - start) + "ms.");\r
+               }\r
+               return attributes;\r
+       }\r
+\r
+       \r
+       /**\r
+     * @param byteArray\r
+     * @param valueOffset\r
+     * @param valueLength\r
+     * @return\r
+     */\r
+       private static URI parseUri(InputStream in, int valueLength) throws IOException {\r
+               String uriString = parseString(in, valueLength);\r
+               URI uri = null;\r
+               try {\r
+                       uri = new URI(uriString);\r
+               } catch (URISyntaxException e) {\r
+                       throw new RuntimeException(e);\r
+               }\r
+               return uri;\r
+       }\r
+\r
+       \r
+       /**\r
+     * @param valueTag\r
+     * @param byteArray\r
+     * @param valueOffset\r
+     * @param valueLength\r
+     * @return\r
+     */\r
+       private static Object[] parseValues(int valueTag, InputStream in) throws IOException {\r
+        int valueLength = parseInt2(in);\r
+               Object[] values = null;\r
+               if (valueTag == IppValueTag.INTEGER.getValue() || valueTag == IppValueTag.ENUM.getValue()) {\r
+                       Integer number = new Integer(parseInt4(in));\r
+                       values = new Object[] { number };\r
+               } else if (\r
+                       valueTag == IppValueTag.STRING.getValue()\r
+                               || valueTag == IppValueTag.TEXT.getValue()\r
+                               || valueTag == IppValueTag.NAME.getValue()){\r
+            String word = parseNameAndTextString(in, valueLength);\r
+            values = new Object[] { word, Locale.getDefault()};                    \r
+        } else if (\r
+            valueTag == IppValueTag.CHARSET.getValue()\r
+                || valueTag == IppValueTag.LANGUAGE.getValue()\r
+                               || valueTag == IppValueTag.MIMETYPE.getValue()) {\r
+                       String word = parseString(in, valueLength);\r
+                       values = new Object[] { word, Locale.getDefault()};\r
+               } else if (valueTag == IppValueTag.URI.getValue()) {\r
+                       URI uri = parseUri(in, valueLength);\r
+                       values = new Object[] { uri };\r
+               } else if (valueTag == IppValueTag.KEYWORD.getValue()) {\r
+                       String word = parseString(in, valueLength);\r
+                       values = new Object[] { word, Locale.getDefault()};\r
+               } else if (valueTag == IppValueTag.BOOLEAN.getValue()) {\r
+                       Integer bool = new Integer(in.read());\r
+                       values = new Object[] { bool };\r
+               } else if (valueTag == IppValueTag.RANGE.getValue()) {\r
+                       Integer lowerBound = new Integer(parseInt4(in));\r
+                       Integer upperBound = new Integer(parseInt4(in));\r
+                       values = new Object[] { lowerBound, upperBound };\r
+               } else if (valueTag == IppValueTag.DATE.getValue()) {\r
+\r
+                       Date date = parseDate(in);\r
+                       values = new Object[] { date };\r
+               } else if (valueTag == IppValueTag.NOVALUE.getValue()) {\r
+                       values = new Object[] {\r
+                       };\r
+               } else {\r
+                       throw new IllegalArgumentException("\"" + Integer.toHexString(valueTag) + "\" is not a valid value-tag");\r
+               }\r
+               return values;\r
+       }\r
+\r
+\r
+       /**\r
+        * @param attributes\r
+        * @param attribute\r
+        */\r
+       private static Map put(Map attributes, Attribute attribute) {\r
+               Set values = (Set) attributes.get(attribute.getCategory());\r
+               if (values == null) {\r
+                       values = new HashSet();\r
+                       attributes.put(attribute.getCategory(), values);\r
+               }\r
+               values.add(attribute);\r
+               return attributes;\r
+       }\r
+\r
+       /**\r
+        * @param values\r
+        * @return\r
+        */\r
+       private static Class[] toClassArray(Object[] values) {\r
+               Class[] classes = new Class[values.length];\r
+               for (int i = 0; i < values.length; i++) {\r
+                       Class clazz = values[i].getClass();\r
+                       if (clazz.equals(Integer.class)) {\r
+                               clazz = int.class;\r
+                       }\r
+                       classes[i] = clazz;\r
+               }\r
+               return classes;\r
+       }\r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/attribute/AttributeWriter.java b/jspi/src/main/java/de/lohndirekt/print/attribute/AttributeWriter.java
new file mode 100644 (file)
index 0000000..163dfba
--- /dev/null
@@ -0,0 +1,290 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print.attribute;\r
+\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.UnsupportedEncodingException;\r
+import java.util.Calendar;\r
+import java.util.Date;\r
+import java.util.GregorianCalendar;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+import java.util.TimeZone;\r
+\r
+import javax.print.attribute.Attribute;\r
+import javax.print.attribute.DateTimeSyntax;\r
+import javax.print.attribute.EnumSyntax;\r
+import javax.print.attribute.IntegerSyntax;\r
+import javax.print.attribute.ResolutionSyntax;\r
+import javax.print.attribute.SetOfIntegerSyntax;\r
+import javax.print.attribute.TextSyntax;\r
+import javax.print.attribute.URISyntax;\r
+\r
+import de.lohndirekt.print.attribute.ipp.Charset;\r
+import de.lohndirekt.print.attribute.ipp.NaturalLanguage;\r
+\r
+public final class AttributeWriter {\r
+    \r
+    private final static int MILIS_IN_MINUTE = 1000*60;\r
+    private final static int MILIS_IN_HOUR =MILIS_IN_MINUTE*60;\r
+    private static Map encodings = new HashMap();\r
+    \r
+    public final static Charset DEFAULT_CHARSET = Charset.ISO_8859_1;\r
+    \r
+       /**\r
+        * @param bytes\r
+        * @param byteNr\r
+        * @param attribute\r
+        * @return\r
+        */\r
+       private static void fillName(ByteArrayOutputStream out, Attribute attribute) {\r
+               String name = attribute.getName();\r
+               fillName(out, name);\r
+       }\r
+\r
+       private static void fillName(ByteArrayOutputStream out, String name) {\r
+               //name length\r
+        writeInt2(name.length(), out);\r
+               //name of attribute\r
+               writeString(name, out);\r
+        \r
+       }\r
+\r
+       /**\r
+        * @param attribute\r
+        * @param bytes\r
+        * @return\r
+        */\r
+       private static void attributeBytes(IntegerSyntax attribute, ByteArrayOutputStream out)   {\r
+               //value tag\r
+               out.write((byte) IppValueTag.INTEGER.getValue());\r
+               //name\r
+               fillName(out, (Attribute) attribute);\r
+               //value length (always 4 bytes)\r
+        writeInt2(4, out);\r
+        //value\r
+        writeInt4(attribute.getValue(), out);\r
+       }\r
+\r
+       /**\r
+        * @param attribute\r
+        * @param bytes\r
+        * @return\r
+        */\r
+       private static void attributeBytes(SetOfIntegerSyntax attribute, ByteArrayOutputStream out)   {\r
+               int[][] members = attribute.getMembers();\r
+               for (int i = 0; i < members.length; i++) {\r
+                       int[] range = members[i];\r
+                       int lowerBound = range[0];\r
+                       int upperBound = range[1];\r
+\r
+                       //value tag\r
+                       out.write((byte) IppValueTag.RANGE.getValue());\r
+                       //name\r
+                       if (i == 0) {\r
+                               fillName(out, (Attribute) attribute);\r
+                       } else {\r
+                               fillName(out, "");\r
+                       }\r
+                       //value length (always 8 bytes)\r
+            writeInt2(8, out);\r
+\r
+                       //(Lower bound first)Integer in 4 bytes\r
+            writeInt4(lowerBound, out);\r
+                       //(Upper bound)Integer in 4 bytes\r
+            writeInt4(upperBound, out);\r
+               }\r
+       }\r
+       /**\r
+        * @param attribute\r
+        * @param bytes\r
+        * @return\r
+        */\r
+       private static void attributeBytes(TextSyntax attribute, ByteArrayOutputStream out)  {\r
+               // value tag\r
+               if (attribute instanceof Charset) {\r
+                       out.write((byte) IppValueTag.CHARSET.getValue());\r
+               } else if (attribute instanceof NaturalLanguage) {\r
+                       out.write((byte) IppValueTag.LANGUAGE.getValue());\r
+               } else {\r
+                       out.write((byte) IppValueTag.NAME.getValue());\r
+               }\r
+               //name\r
+               fillName(out, (Attribute) attribute);\r
+               //value length \r
+        writeInt2(attribute.toString().length(), out);\r
+        writeNameAndTextString(attribute.toString(), out);\r
+       }\r
+\r
+       /**\r
+        * @param attribute\r
+        * @param bytes\r
+        * @return\r
+        */\r
+       private static void attributeBytes(EnumSyntax attribute, ByteArrayOutputStream out)  {\r
+               // Value tag\r
+               out.write((byte) IppValueTag.TEXT.getValue());\r
+               // Name\r
+               fillName(out, (Attribute) attribute);\r
+               // value length\r
+        writeInt2(attribute.toString().length(), out);\r
+        writeString(attribute.toString(), out);\r
+       }\r
+    \r
+       /**\r
+     * \r
+     * uses UTC time, not local time zone to encode the date\r
+     * \r
+        * @param attribute\r
+        * @param bytes\r
+        * @return\r
+        */\r
+       private static void attributeBytes(DateTimeSyntax attribute, ByteArrayOutputStream out)  {\r
+        \r
+        \r
+               //Value tag\r
+               out.write((byte) IppValueTag.DATE.getValue());\r
+               //Name\r
+               fillName(out, (Attribute) attribute);\r
+               //Value length (always 11 bytes)\r
+        writeInt2(11, out);\r
+        \r
+               Date date = attribute.getValue();\r
+        TimeZone zone = TimeZone.getTimeZone("UTC");\r
+        Calendar cal = new GregorianCalendar(zone);\r
+               cal.setTime(date);\r
+        \r
+        int year = cal.get(GregorianCalendar.YEAR);\r
+               int month = cal.get(Calendar.MONTH) + 1;\r
+               int day = cal.get(Calendar.DAY_OF_MONTH);\r
+               int hour = cal.get(Calendar.HOUR_OF_DAY);\r
+               int minute = cal.get(Calendar.MINUTE);\r
+               int second = cal.get(Calendar.SECOND);\r
+               int deci = cal.get(Calendar.MILLISECOND) / 100;\r
+        int offset = zone.getOffset(cal.getTimeInMillis());\r
+               int hoursFromUtc = offset / MILIS_IN_HOUR;\r
+               int minutesFromUtc = offset % MILIS_IN_HOUR / MILIS_IN_MINUTE;\r
+               char direction = '+';\r
+               if (hoursFromUtc < 0) {\r
+                       direction = '-';\r
+                       hoursFromUtc *= -1;\r
+               }\r
+        writeInt2(year, out);\r
+               out.write((byte) month);\r
+               out.write((byte) day);\r
+               out.write((byte) hour);\r
+               out.write((byte) minute);\r
+               out.write((byte) second);\r
+               out.write((byte) deci);\r
+               out.write((byte) direction);\r
+               out.write((byte) hoursFromUtc);\r
+               out.write((byte) minutesFromUtc);\r
+       }\r
+       /**\r
+        * @param attribute\r
+        * @param bytes\r
+        * @return\r
+        */\r
+       private static void attributeBytes(URISyntax attribute, ByteArrayOutputStream out)  {\r
+               //Value tag\r
+               out.write((byte) IppValueTag.URI.getValue());\r
+               //Name\r
+               fillName(out, (Attribute) attribute);\r
+               //value length\r
+        writeInt2(attribute.toString().length(), out);\r
+               writeString(attribute.toString(), out);\r
+       }\r
+\r
+       /**\r
+        * @param attribute\r
+        * @param bytes\r
+        * @return\r
+        */\r
+       private static void attributeBytes(ResolutionSyntax attribute, ByteArrayOutputStream out)  {\r
+               //Value tag\r
+               out.write((byte) IppValueTag.INTEGER.getValue());\r
+               //Name\r
+               fillName(out, (Attribute) attribute);\r
+        //Value length (always 9)\r
+        out.write((byte) 0);\r
+        out.write((byte) 9);\r
+               int feedResolution = attribute.getFeedResolution(ResolutionSyntax.DPI);\r
+               int crossFeedResolution = attribute.getCrossFeedResolution(ResolutionSyntax.DPI);\r
+        //(Lower bound first)Integer in 4 bytes\r
+               writeInt4(crossFeedResolution, out);\r
+               //(Upper bound)Integer in 4 bytes\r
+               writeInt4(feedResolution, out);\r
+               out.write((byte) ResolutionSyntax.DPI);\r
+       }\r
+    \r
+    public static void writeInt4(int value, ByteArrayOutputStream out){\r
+        out.write((byte) ((value & 0xff000000) >> 24));\r
+        out.write((byte) ((value & 0xff0000) >> 16));\r
+        out.write((byte) ((value & 0xff00) >> 8));\r
+        out.write((byte) (value & 0xff));     \r
+    }\r
+    \r
+    public static void writeInt2(int value, ByteArrayOutputStream out){\r
+        out.write((byte) ((value & 0xff00) >> 8));\r
+        out.write((byte) (value & 0xff));     \r
+    }\r
+    \r
+    public static void writeString(String value, ByteArrayOutputStream out, String charsetName) {\r
+        byte[] bytes;\r
+               try {\r
+                       bytes = value.getBytes(charsetName);\r
+               } catch (UnsupportedEncodingException e) {\r
+            throw new IllegalArgumentException(charsetName + " encoding not supported by JVM");\r
+               }\r
+        out.write(bytes, 0, bytes.length);\r
+    }\r
+    \r
+    public static void writeString(String value, ByteArrayOutputStream out){\r
+        writeString(value, out, Charset.US_ASCII.getValue());\r
+    }\r
+    \r
+    public static void writeNameAndTextString(String value, ByteArrayOutputStream out) {\r
+        writeString(value, out, DEFAULT_CHARSET.getValue());\r
+    }\r
+\r
+       /**\r
+     * @param attribute\r
+     * @return\r
+     */\r
+       public static void attributeBytes(Attribute attribute, ByteArrayOutputStream out) {\r
+        if (attribute instanceof IntegerSyntax) {\r
+                       attributeBytes((IntegerSyntax) attribute, out);\r
+               } else if (attribute instanceof TextSyntax) {\r
+                       attributeBytes((TextSyntax) attribute, out);\r
+               } else if (attribute instanceof DateTimeSyntax) {\r
+                       attributeBytes((DateTimeSyntax) attribute, out);\r
+               } else if (attribute instanceof ResolutionSyntax) {\r
+                       attributeBytes((ResolutionSyntax) attribute, out);\r
+               } else if (attribute instanceof SetOfIntegerSyntax) {\r
+                       attributeBytes((SetOfIntegerSyntax) attribute, out);\r
+               } else if (attribute instanceof EnumSyntax) {\r
+                       attributeBytes((EnumSyntax) attribute, out);\r
+               } else if (attribute instanceof URISyntax) {\r
+                       attributeBytes((URISyntax) attribute, out);\r
+               } else {\r
+                       throw new IllegalArgumentException("The given attribute is of an unknown SubType (only IntegerSyntax, TextSyntax, DateTimeSyntax, ResolutionSyntax, SetOfIntegerSyntax, EnumSyntax and URISyntax supported)");\r
+               }\r
+       }\r
+\r
+}
\ No newline at end of file
diff --git a/jspi/src/main/java/de/lohndirekt/print/attribute/AttributeWriterTest.java b/jspi/src/main/java/de/lohndirekt/print/attribute/AttributeWriterTest.java
new file mode 100644 (file)
index 0000000..52c5819
--- /dev/null
@@ -0,0 +1,203 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print.attribute;\r
+\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.IOException;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.util.Calendar;\r
+import java.util.Date;\r
+import java.util.Locale;\r
+import java.util.TimeZone;\r
+\r
+import javax.print.attribute.standard.CopiesSupported;\r
+import javax.print.attribute.standard.JobHoldUntil;\r
+import javax.print.attribute.standard.JobName;\r
+import javax.print.attribute.standard.JobPriority;\r
+import javax.print.attribute.standard.JobState;\r
+import javax.print.attribute.standard.PrinterResolution;\r
+import javax.print.attribute.standard.PrinterURI;\r
+\r
+import junit.framework.TestCase;\r
+import de.lohndirekt.print.attribute.cups.JobPageLimit;\r
+import de.lohndirekt.print.attribute.ipp.Charset;\r
+import de.lohndirekt.print.attribute.ipp.jobdesc.JobUri;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.PrinterCurrentTime;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.PageRangesSupported;\r
+\r
+/**\r
+ * @author ld-development\r
+ * \r
+ * \r
+ */\r
+public class AttributeWriterTest extends TestCase {\r
+    \r
+    ByteArrayOutputStream out;\r
+    \r
+    protected void setUp() throws Exception {\r
+            super.setUp();\r
+            out = new ByteArrayOutputStream();\r
+        }\r
+\r
+\r
+    private Date date(String timeZoneId){\r
+        TimeZone zone = TimeZone.getTimeZone(timeZoneId);\r
+        Calendar cal = Calendar.getInstance(zone);\r
+\r
+        cal.set(Calendar.YEAR, 2003);\r
+        cal.set(Calendar.MONTH, Calendar.JUNE);\r
+        cal.set(Calendar.DAY_OF_MONTH, 1);\r
+        cal.set(Calendar.MINUTE, 48);\r
+        cal.set(Calendar.SECOND, 9);\r
+        cal.set(Calendar.MILLISECOND, 47);\r
+        cal.set(Calendar.HOUR_OF_DAY, 13);\r
+        Date date = cal.getTime();\r
+        \r
+        return date;\r
+    }\r
+    /**\r
+     * \r
+     */\r
+    public void testAttributeWriterForDateTimeSyntax() throws IOException {\r
+       \r
+        //testing for TimeZone Asia/Omsk\r
+        //1:48:09 P.M. in Greenwich obviously means 1:48:09 P.M. in Greenwich\r
+        Date d = date("UTC");\r
+        \r
+        // testing lohndirekt attribute\r
+        AttributeWriter.attributeBytes(new PrinterCurrentTime(d), out);\r
+        assertEquals(new byte[] { 49, 0, 20, 112, 114, 105, 110, 116, 101, 114, 45, 99, 117, 114, 114, 101, 110, 116, 45, 116, 105, 109, 101, 0, 11, 7, -45, 6, 1, 13, 48, 9, 0, 43, 0, 0 }, out.toByteArray());\r
+        \r
+        //testing javax.print attribute\r
+        out.reset();\r
+        AttributeWriter.attributeBytes(new JobHoldUntil(d), out);\r
+        assertEquals(new byte[] { 49, 0, 14, 106, 111, 98, 45, 104, 111, 108, 100, 45, 117, 110, 116, 105, 108, 0, 11, 7, -45, 6, 1, 13, 48, 9, 0, 43, 0, 0 }, out.toByteArray());\r
+        \r
+        //testing for TimeZone Asia/Omsk\r
+        //1:48:09 P.M. in Omsk means 6:48:09 A.M. in Greenwich\r
+        d = date("Asia/Omsk");\r
+        \r
+        // testing lohndirekt attribute\r
+        out.reset();\r
+        AttributeWriter.attributeBytes(new PrinterCurrentTime(d), out);\r
+        assertEquals(new byte[] { 49, 0, 20, 112, 114, 105, 110, 116, 101, 114, 45, 99, 117, 114, 114, 101, 110, 116, 45, 116, 105, 109, 101, 0, 11, 7, -45, 6, 1, 6, 48, 9, 0, 43, 0, 0 }, out.toByteArray());\r
+\r
+        //testing javax.print attribute\r
+        out.reset();\r
+        AttributeWriter.attributeBytes(new JobHoldUntil(d), out);\r
+        assertEquals(new byte[] { 49, 0, 14, 106, 111, 98, 45, 104, 111, 108, 100, 45, 117, 110, 116, 105, 108, 0, 11, 7, -45, 6, 1, 6, 48, 9, 0, 43, 0, 0 }, out.toByteArray());\r
+    }\r
+\r
+    /**\r
+     * \r
+     */\r
+    public void testAttributeWriterForEnumSyntax() throws IOException {\r
+        // testing lohndirekt attribute\r
+        AttributeWriter.attributeBytes(PageRangesSupported.SUPPORTED, out);\r
+        assertEquals(\r
+            new byte[] { 65, 0, 21, 112, 97, 103, 101, 45, 114, 97, 110, 103, 101, 115, 45, 115, 117, 112, 112, 111, 114, 116, 101, 100, 0, 13, 110, 111, 116, 32, 115, 117, 112, 112, 111, 114, 116, 101, 100 },\r
+            out.toByteArray());\r
+\r
+        // testing javax.print attribute\r
+        out.reset();\r
+        AttributeWriter.attributeBytes(JobState.CANCELED, out);\r
+        assertEquals(new byte[] { 65, 0, 9, 106, 111, 98, 45, 115, 116, 97, 116, 101, 0, 8, 99, 97, 110, 99, 101, 108, 101, 100 }, out.toByteArray());\r
+\r
+    }\r
+    /**\r
+     * \r
+     */\r
+    public void testAttributeWriterForIntegerSyntax() throws IOException {\r
+        // testing lohndirekt attribute\r
+        AttributeWriter.attributeBytes(new JobPageLimit(3), out);\r
+        assertEquals(new byte[] { 33, 0, 14, 106, 111, 98, 45, 112, 97, 103, 101, 45, 108, 105, 109, 105, 116, 0, 4, 0, 0, 0, 3 }, out.toByteArray());\r
+\r
+        // testing javax.print attribute\r
+        out.reset();\r
+        AttributeWriter.attributeBytes(new JobPriority(3), out);\r
+        assertEquals(new byte[] { 33, 0, 12, 106, 111, 98, 45, 112, 114, 105, 111, 114, 105, 116, 121, 0, 4, 0, 0, 0, 3 }, out.toByteArray());\r
+    }\r
+    /**\r
+     * \r
+     */\r
+    public void testAttributeWriterForResolutionSyntax() throws IOException {\r
+        // testing javax.print attribute\r
+        AttributeWriter.attributeBytes(new PrinterResolution(800, 800, PrinterResolution.DPI), out);\r
+        assertEquals(\r
+            new byte[] { 33, 0, 18, 112, 114, 105, 110, 116, 101, 114, 45, 114, 101, 115, 111, 108, 117, 116, 105, 111, 110, 0, 9, 0, 0, 3, 32, 0, 0, 3, 32, 100},\r
+        out.toByteArray());\r
+    }\r
+    /**\r
+     * \r
+     */\r
+    public void testAttributeWriterForSetOfIntegerSyntax() throws IOException {\r
+        // testing javax.print attribute\r
+        AttributeWriter.attributeBytes(new CopiesSupported(1,5), out);\r
+        assertEquals(\r
+            new byte[] { 51, 0, 16, 99, 111, 112, 105, 101, 115, 45, 115, 117, 112, 112, 111, 114, 116, 101, 100, 0, 8, 0, 0, 0, 1, 0, 0, 0, 5 },\r
+        out.toByteArray());\r
+    }\r
+    /**\r
+     * \r
+     */\r
+    public void testAttributeWriterForTextSyntax() throws IOException {\r
+        // testing lohndirekt attribute\r
+        AttributeWriter.attributeBytes(Charset.ISO_8859_15, out);\r
+        assertEquals(\r
+            new byte[] { 71, 0, 18, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 45, 99, 104, 97, 114, 115, 101, 116, 0, 11, 105, 115, 111, 45, 56, 56, 53, 57, 45, 49, 53 },\r
+        out.toByteArray());\r
+\r
+        // testing javax.print attribute\r
+        out.reset();\r
+        AttributeWriter.attributeBytes(new JobName("testJob",Locale.GERMANY), out);\r
+        assertEquals(\r
+            new byte[] { 66, 0, 8, 106, 111, 98, 45, 110, 97, 109, 101, 0, 7, 116, 101, 115, 116, 74, 111, 98 },\r
+        out.toByteArray());\r
+    }\r
+    /**\r
+     * \r
+     */\r
+    public void testAttributeWriterForURISyntax() throws URISyntaxException, IOException {\r
+        URI uri = new URI("http://www.google.de/");\r
+        // testing lohndirekt attribute\r
+        AttributeWriter.attributeBytes(new JobUri(uri), out);\r
+        assertEquals(\r
+            new byte[] { 69, 0, 7, 106, 111, 98, 45, 117, 114, 105, 0, 21, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 103, 111, 111, 103, 108, 101, 46, 100, 101, 47 },\r
+        out.toByteArray());\r
+\r
+        // testing javax.print attribute\r
+        out.reset();\r
+        AttributeWriter.attributeBytes(new PrinterURI(uri), out);\r
+        assertEquals(\r
+            new byte[] { 69, 0, 11, 112, 114, 105, 110, 116, 101, 114, 45, 117, 114, 105, 0, 21, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 103, 111, 111, 103, 108, 101, 46, 100, 101, 47 },\r
+        out.toByteArray());\r
+    }\r
+\r
+    /**\r
+     * @param expected\r
+     * @param actual\r
+     */\r
+    private void assertEquals(byte[] expected, byte[] actual) {\r
+        assertEquals(new String(expected), new String(actual));\r
+    }\r
+\r
+\r
+       \r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/attribute/DefaultAttribute.java b/jspi/src/main/java/de/lohndirekt/print/attribute/DefaultAttribute.java
new file mode 100644 (file)
index 0000000..f77cd1c
--- /dev/null
@@ -0,0 +1,26 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print.attribute;\r
+\r
+import javax.print.attribute.Attribute;\r
+\r
+\r
+public interface DefaultAttribute extends Attribute{\r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/attribute/IppAttributeName.java b/jspi/src/main/java/de/lohndirekt/print/attribute/IppAttributeName.java
new file mode 100644 (file)
index 0000000..742f2a5
--- /dev/null
@@ -0,0 +1,531 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print.attribute;\r
+\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
+import java.util.Date;\r
+import java.util.HashMap;\r
+import java.util.Locale;\r
+import java.util.Map;\r
+import java.util.logging.Logger;\r
+\r
+import javax.print.attribute.Attribute;\r
+import javax.print.attribute.standard.ColorSupported;\r
+import javax.print.attribute.standard.Compression;\r
+import javax.print.attribute.standard.Copies;\r
+import javax.print.attribute.standard.CopiesSupported;\r
+import javax.print.attribute.standard.DateTimeAtCompleted;\r
+import javax.print.attribute.standard.DateTimeAtCreation;\r
+import javax.print.attribute.standard.DateTimeAtProcessing;\r
+import javax.print.attribute.standard.DocumentName;\r
+import javax.print.attribute.standard.Fidelity;\r
+import javax.print.attribute.standard.Finishings;\r
+import javax.print.attribute.standard.JobImpressions;\r
+import javax.print.attribute.standard.JobImpressionsCompleted;\r
+import javax.print.attribute.standard.JobImpressionsSupported;\r
+import javax.print.attribute.standard.JobKOctets;\r
+import javax.print.attribute.standard.JobKOctetsProcessed;\r
+import javax.print.attribute.standard.JobKOctetsSupported;\r
+import javax.print.attribute.standard.JobMediaSheets;\r
+import javax.print.attribute.standard.JobMediaSheetsCompleted;\r
+import javax.print.attribute.standard.JobMediaSheetsSupported;\r
+import javax.print.attribute.standard.JobMessageFromOperator;\r
+import javax.print.attribute.standard.JobName;\r
+import javax.print.attribute.standard.JobOriginatingUserName;\r
+import javax.print.attribute.standard.JobPriority;\r
+import javax.print.attribute.standard.JobPrioritySupported;\r
+import javax.print.attribute.standard.JobSheets;\r
+import javax.print.attribute.standard.JobState;\r
+import javax.print.attribute.standard.JobStateReason;\r
+import javax.print.attribute.standard.JobStateReasons;\r
+import javax.print.attribute.standard.MediaSizeName;\r
+import javax.print.attribute.standard.MultipleDocumentHandling;\r
+import javax.print.attribute.standard.NumberOfDocuments;\r
+import javax.print.attribute.standard.NumberOfInterveningJobs;\r
+import javax.print.attribute.standard.NumberUp;\r
+import javax.print.attribute.standard.NumberUpSupported;\r
+import javax.print.attribute.standard.OrientationRequested;\r
+import javax.print.attribute.standard.OutputDeviceAssigned;\r
+import javax.print.attribute.standard.PDLOverrideSupported;\r
+import javax.print.attribute.standard.PageRanges;\r
+import javax.print.attribute.standard.PagesPerMinute;\r
+import javax.print.attribute.standard.PagesPerMinuteColor;\r
+import javax.print.attribute.standard.PresentationDirection;\r
+import javax.print.attribute.standard.PrintQuality;\r
+import javax.print.attribute.standard.PrinterInfo;\r
+import javax.print.attribute.standard.PrinterIsAcceptingJobs;\r
+import javax.print.attribute.standard.PrinterLocation;\r
+import javax.print.attribute.standard.PrinterMakeAndModel;\r
+import javax.print.attribute.standard.PrinterMessageFromOperator;\r
+import javax.print.attribute.standard.PrinterMoreInfo;\r
+import javax.print.attribute.standard.PrinterMoreInfoManufacturer;\r
+import javax.print.attribute.standard.PrinterName;\r
+import javax.print.attribute.standard.PrinterResolution;\r
+import javax.print.attribute.standard.PrinterState;\r
+import javax.print.attribute.standard.PrinterStateReason;\r
+import javax.print.attribute.standard.PrinterStateReasons;\r
+import javax.print.attribute.standard.PrinterURI;\r
+import javax.print.attribute.standard.QueuedJobCount;\r
+import javax.print.attribute.standard.ReferenceUriSchemesSupported;\r
+import javax.print.attribute.standard.RequestingUserName;\r
+import javax.print.attribute.standard.Severity;\r
+import javax.print.attribute.standard.SheetCollate;\r
+import javax.print.attribute.standard.Sides;\r
+\r
+import de.lohndirekt.print.attribute.auth.RequestingUserPassword;\r
+import de.lohndirekt.print.attribute.cups.DeviceClass;\r
+import de.lohndirekt.print.attribute.cups.DeviceUri;\r
+import de.lohndirekt.print.attribute.cups.JobKLimit;\r
+import de.lohndirekt.print.attribute.cups.JobPageLimit;\r
+import de.lohndirekt.print.attribute.cups.JobQuotaPeriod;\r
+import de.lohndirekt.print.attribute.cups.MemberNames;\r
+import de.lohndirekt.print.attribute.cups.MemberUris;\r
+import de.lohndirekt.print.attribute.cups.PrinterType;\r
+import de.lohndirekt.print.attribute.ipp.Charset;\r
+import de.lohndirekt.print.attribute.ipp.DetailedStatusMessage;\r
+import de.lohndirekt.print.attribute.ipp.DocumentFormat;\r
+import de.lohndirekt.print.attribute.ipp.NaturalLanguage;\r
+import de.lohndirekt.print.attribute.ipp.StatusMessage;\r
+import de.lohndirekt.print.attribute.ipp.UnknownAttribute;\r
+import de.lohndirekt.print.attribute.ipp.jobdesc.JobId;\r
+import de.lohndirekt.print.attribute.ipp.jobdesc.JobMoreInfo;\r
+import de.lohndirekt.print.attribute.ipp.jobdesc.JobOriginatingHostName;\r
+import de.lohndirekt.print.attribute.ipp.jobdesc.JobPrinterUpTime;\r
+import de.lohndirekt.print.attribute.ipp.jobdesc.JobPrinterUri;\r
+import de.lohndirekt.print.attribute.ipp.jobdesc.JobUri;\r
+import de.lohndirekt.print.attribute.ipp.jobdesc.TimeAtCompleted;\r
+import de.lohndirekt.print.attribute.ipp.jobdesc.TimeAtCreation;\r
+import de.lohndirekt.print.attribute.ipp.jobdesc.TimeAtProcessing;\r
+import de.lohndirekt.print.attribute.ipp.jobtempl.LdJobHoldUntil;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.MultipleOperationTimeout;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.NaturalLanguageConfigured;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.PrinterCurrentTime;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.PrinterDriverInstaller;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.PrinterStateMessage;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.PrinterUpTime;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.defaults.CharsetConfigured;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.defaults.CopiesDefault;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.defaults.DocumentFormatDefault;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.defaults.FinishingsDefault;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.defaults.JobHoldUntilDefault;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.defaults.JobPriorityDefault;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.defaults.JobSheetsDefault;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.defaults.MediaDefault;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.defaults.MultipleDocumentHandlingDefault;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.defaults.NumberUpDefault;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.defaults.OrientationRequestedDefault;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.defaults.SidesDefault;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.CharsetSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.CompressionSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.DocumentFormatSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.FinishingsSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.GeneratedNaturalLanguageSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.IppVersionsSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.JobHoldUntilSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.JobSheetsSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.MediaSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.MultipleDocumentHandlingSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.MultipleDocumentJobsSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.OperationsSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.OrientationRequestedSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.OutputBinSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.PageRangesSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.PrinterUriSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.SidesSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.UriAuthenticationSupported;\r
+import de.lohndirekt.print.attribute.ipp.printerdesc.supported.UriSecuritySupported;\r
+import de.lohndirekt.print.attribute.undocumented.PrinterStateTime;\r
+\r
+/**\r
+ * @author bpusch\r
+ *\r
+ */\r
+public final class IppAttributeName {\r
+       private final static Logger log = Logger.getLogger(AttributeParser.class.getName());\r
+       \r
+       /*\r
+        * Attributes defined in javax.print.attribute.standard\r
+        */\r
+       public static final IppAttributeName COLOR_SUPPORTED = new IppAttributeName(ColorSupported.SUPPORTED);\r
+       public static final IppAttributeName COMPRESSION = new IppAttributeName(Compression.NONE);\r
+       public static final IppAttributeName COPIES = new IppAttributeName(new Copies(1));\r
+       public static final IppAttributeName COPIES_SUPPORTED = new IppAttributeName(new CopiesSupported(1));\r
+       public static final IppAttributeName DATE_TIME_AT_COMPLETION = new IppAttributeName(new DateTimeAtCompleted(new Date()));\r
+       public static final IppAttributeName DATE_TIME_AT_CREATION = new IppAttributeName(new DateTimeAtCreation(new Date()));\r
+       public static final IppAttributeName DATE_TIME_AT_PROCESSING = new IppAttributeName(new DateTimeAtProcessing(new Date()));\r
+       public static final IppAttributeName DOCUMENT_NAME = new IppAttributeName(new DocumentName("", Locale.CANADA));\r
+       public static final IppAttributeName FIDELITY = new IppAttributeName(Fidelity.FIDELITY_TRUE);\r
+       public static final IppAttributeName FINISHINGS = new IppAttributeName(Finishings.BIND);\r
+       public static final IppAttributeName JOB_IMPRESSIONS = new IppAttributeName(new JobImpressions(1));\r
+       public static final IppAttributeName JOB_IMPRESSIONS_COMPLETED = new IppAttributeName(new JobImpressionsCompleted(1));\r
+       public static final IppAttributeName JOB_IMPRESSIONS_SUPPORTED = new IppAttributeName(new JobImpressionsSupported(1, 1));\r
+       public static final IppAttributeName JOB_K_OCTETS = new IppAttributeName(new JobKOctets(1));\r
+       public static final IppAttributeName JOB_K_OCTETS_PROCESSED = new IppAttributeName(new JobKOctetsProcessed(1));\r
+       public static final IppAttributeName JOB_K_OCTETS_SUPPORTED = new IppAttributeName(new JobKOctetsSupported(1, 1));\r
+       public static final IppAttributeName JOB_MEDIA_SHEETS = new IppAttributeName(new JobMediaSheets(1));\r
+       public static final IppAttributeName JOB_MEDIA_SHEETS_COMPLETED = new IppAttributeName(new JobMediaSheetsCompleted(1));\r
+       public static final IppAttributeName JOB_MEDIA_SHEETS_SUPPORTED = new IppAttributeName(new JobMediaSheetsSupported(1, 1));\r
+       public static final IppAttributeName JOB_MESSAGE_FROM_OPERATOR =\r
+               new IppAttributeName(new JobMessageFromOperator("", Locale.CANADA));\r
+       public static final IppAttributeName JOB_NAME = new IppAttributeName(new JobName("", Locale.CANADA));\r
+       public static final IppAttributeName JOB_ORIGINATING_USER_NAME =\r
+               new IppAttributeName(new JobOriginatingUserName("", Locale.CANADA));\r
+       public static final IppAttributeName JOB_PRIORIY = new IppAttributeName(new JobPriority(1));\r
+       public static final IppAttributeName JOB_PRIORIY_SUPPORTED = new IppAttributeName(new JobPrioritySupported(1));\r
+       public static final IppAttributeName JOB_SHEETS = new IppAttributeName(JobSheets.NONE);\r
+       public static final IppAttributeName JOB_STATE = new IppAttributeName(JobState.ABORTED);\r
+       public static final IppAttributeName JOB_STATE_REASON = new IppAttributeName(JobStateReason.ABORTED_BY_SYSTEM);\r
+       public static final IppAttributeName JOB_STATE_REASONS = new IppAttributeName(new JobStateReasons());\r
+       //Could be MediaName,MediaSizeName or MediaTray\r
+       public static final IppAttributeName MEDIA = new IppAttributeName(MediaSizeName.A);\r
+       public static final IppAttributeName MULTIPLE_DOCUMENT_HANDLING =\r
+               new IppAttributeName(MultipleDocumentHandling.SEPARATE_DOCUMENTS_COLLATED_COPIES);\r
+       public static final IppAttributeName NUMBER_OF_DOCUMENTS = new IppAttributeName(new NumberOfDocuments(1));\r
+       public static final IppAttributeName NUMBER_OF_INTERVENING_JOBS = new IppAttributeName(new NumberOfInterveningJobs(1));\r
+       public static final IppAttributeName NUMBER_UP = new IppAttributeName(new NumberUp(1));\r
+       public static final IppAttributeName NUMBER_UP_SUPPORTED = new IppAttributeName(new NumberUpSupported(1));\r
+       public static final IppAttributeName ORIENTATION_REQUESTED = new IppAttributeName(OrientationRequested.LANDSCAPE);\r
+       public static final IppAttributeName OUTPUT_DEVICE_ASSIGNED =\r
+               new IppAttributeName(new OutputDeviceAssigned("", Locale.CANADA));\r
+       public static final IppAttributeName PAGE_RANGES = new IppAttributeName(new PageRanges(1));\r
+       public static final IppAttributeName PAGES_PER_MINUTE = new IppAttributeName(new PagesPerMinute(1));\r
+       public static final IppAttributeName PAGES_PER_MINUTE_COLOR = new IppAttributeName(new PagesPerMinuteColor(1));\r
+       public static final IppAttributeName PDL_OVERRIDE_SUPPORTED = new IppAttributeName(PDLOverrideSupported.ATTEMPTED);\r
+       public static final IppAttributeName PRESENTATION_DIRECTION = new IppAttributeName(PresentationDirection.TOBOTTOM_TOLEFT);\r
+       public static final IppAttributeName PRINTER_INFO = new IppAttributeName(new PrinterInfo("", Locale.CANADA));\r
+       public static final IppAttributeName PRINTER_IS_ACCEPTING_JOBS = new IppAttributeName(PrinterIsAcceptingJobs.ACCEPTING_JOBS);\r
+       public static final IppAttributeName PRINTER_LOCATION = new IppAttributeName(new PrinterLocation("", Locale.CANADA));\r
+       public static final IppAttributeName PRINTER_MAKE_AND_MODEL =\r
+               new IppAttributeName(new PrinterMakeAndModel("", Locale.CANADA));\r
+       public static final IppAttributeName PRINTER_MESSAGE_FROM_OPERATOR =\r
+               new IppAttributeName(new PrinterMessageFromOperator("", Locale.CANADA));\r
+       public static final IppAttributeName PRINTER_MORE_INFO = new IppAttributeName(new PrinterMoreInfo(IppAttributeName.getURI()));\r
+       public static final IppAttributeName PRINTER_MORE_INFO_MANUFACTURER =\r
+               new IppAttributeName(new PrinterMoreInfoManufacturer(IppAttributeName.getURI()));\r
+       public static final IppAttributeName PRINTER_NAME = new IppAttributeName(new PrinterName("", Locale.CANADA));\r
+       public static final IppAttributeName PRINTER_RESOLUTION = new IppAttributeName(new PrinterResolution(1, 1, 1));\r
+       public static final IppAttributeName PRINTER_STATE = new IppAttributeName(PrinterState.IDLE);\r
+       public static final IppAttributeName PRINTER_STATE_REASON = new IppAttributeName(PrinterStateReason.CONNECTING_TO_DEVICE);\r
+       public static final IppAttributeName PRINTER_STATE_REASONS = new IppAttributeName(new PrinterStateReasons());\r
+       public static final IppAttributeName PRINTER_URI = new IppAttributeName(new PrinterURI(IppAttributeName.getURI()));\r
+       public static final IppAttributeName PRINT_QUALITY = new IppAttributeName(PrintQuality.DRAFT);\r
+       public static final IppAttributeName QUEUED_JOB_COUNT = new IppAttributeName(new QueuedJobCount(1));\r
+       public static final IppAttributeName REFERENCE_URI_SCHEMES_SUPPORTED =\r
+               new IppAttributeName(ReferenceUriSchemesSupported.FILE);\r
+       public static final IppAttributeName REQUESTING_USER_NAME = new IppAttributeName(new RequestingUserName("", Locale.CANADA));\r
+       public static final IppAttributeName REQUESTING_USER_PASSWD = new IppAttributeName(new RequestingUserPassword("", Locale.CANADA));\r
+       public static final IppAttributeName SEVERITY = new IppAttributeName(Severity.ERROR);\r
+       public static final IppAttributeName SHEET_COLLATE = new IppAttributeName(SheetCollate.COLLATED);\r
+       public static final IppAttributeName SIDES = new IppAttributeName(Sides.DUPLEX);\r
+\r
+       /*\r
+        * IPP standard attributes defined in de.lohndirekt.attribute.ipp\r
+        */\r
+       public static final IppAttributeName CHARSET = new IppAttributeName(new Charset("x", Locale.getDefault()));\r
+       public static final IppAttributeName CHARSET_CONFIGURED =\r
+               new IppAttributeName(new CharsetConfigured("x", Locale.getDefault()));\r
+       public static final IppAttributeName CHARSET_SUPORTED = new IppAttributeName(new CharsetSupported("x", Locale.getDefault()));\r
+       public static final IppAttributeName COMPRESSION_SUPORTED =\r
+               new IppAttributeName(new CompressionSupported("x", Locale.getDefault()));\r
+       public static final IppAttributeName COPIES_DEFAULT = new IppAttributeName(new CopiesDefault(1));\r
+    public static final IppAttributeName DETAILED_STATUS_MESSAGE = new IppAttributeName(new DetailedStatusMessage("x", Locale.getDefault()));\r
+    public static final IppAttributeName DOCUMENT_FORMAT =\r
+               new IppAttributeName(new DocumentFormat("x", Locale.getDefault()));\r
+       public static final IppAttributeName DOCUMENT_FORMAT_SUPORTED =\r
+               new IppAttributeName(new DocumentFormatSupported("x", Locale.getDefault()));\r
+       public static final IppAttributeName DOCUMENT_FORMAT_DEFAULT =\r
+               new IppAttributeName(new DocumentFormatDefault("x", Locale.getDefault()));\r
+       public static final IppAttributeName FINISHINGS_DEFAULT = new IppAttributeName(new FinishingsDefault(1));\r
+       public static final IppAttributeName FINISHINGS_SUPPORTED = new IppAttributeName(new FinishingsSupported(1));\r
+       public static final IppAttributeName IPP_VERSIONS_SUPPORTED =\r
+               new IppAttributeName(new IppVersionsSupported("x", Locale.getDefault()));\r
+    public static final IppAttributeName JOB_HOLD_UNTIL = new IppAttributeName(new LdJobHoldUntil("x", Locale.getDefault()));    \r
+       public static final IppAttributeName JOB_HOLD_UNTIL_DEFAULT = new IppAttributeName(new JobHoldUntilDefault("x", Locale.getDefault()));\r
+       public static final IppAttributeName JOB_HOLD_UNTIL_SUPPORTED = new IppAttributeName(new JobHoldUntilSupported("x", Locale.getDefault()));\r
+       public static final IppAttributeName JOB_ID = new IppAttributeName(new JobId(1));\r
+       public static final IppAttributeName JOB_MORE_INFO = new IppAttributeName(new JobMoreInfo(IppAttributeName.getURI()));\r
+       public static final IppAttributeName JOB_ORIGINATING_HOST_NAME =\r
+               new IppAttributeName(new JobOriginatingHostName("x", Locale.getDefault()));\r
+       public static final IppAttributeName JOB_PRINTER_UP_TIME = new IppAttributeName(new JobPrinterUpTime(1));\r
+       public static final IppAttributeName JOB_PRINTER_URI = new IppAttributeName(new JobPrinterUri(getURI()));\r
+       public static final IppAttributeName JOB_PRIORITY_DEFAULT = new IppAttributeName(new JobPriorityDefault(1));\r
+       public static final IppAttributeName JOB_SHEETS_DEFAULT =\r
+               new IppAttributeName(new JobSheetsDefault("x", Locale.getDefault()));\r
+       public static final IppAttributeName JOB_SHEETS_SUPORTED =\r
+               new IppAttributeName(new JobSheetsSupported("x", Locale.getDefault()));\r
+       public static final IppAttributeName JOB_URI =\r
+               new IppAttributeName(new JobUri(IppAttributeName.getURI()));\r
+       public static final IppAttributeName GENERATED_NATURAL_LANGUAGE_SUPPORTED =\r
+               new IppAttributeName(new GeneratedNaturalLanguageSupported("x", Locale.getDefault()));\r
+       public static final IppAttributeName MEDIA_DEFAULT = new IppAttributeName(new MediaDefault("x", Locale.getDefault()));\r
+       public static final IppAttributeName MEDIA_SUPPORTED = new IppAttributeName(new MediaSupported("x", Locale.getDefault()));\r
+    public static final IppAttributeName MULTIPLE_DOCUMENT_HANDLING_DEFAULT =\r
+        new IppAttributeName(new MultipleDocumentHandlingDefault("x", Locale.getDefault()));\r
+    public static final IppAttributeName MULTIPLE_DOCUMENT_HANDLING_SUPPORTED =\r
+        new IppAttributeName(new MultipleDocumentHandlingSupported("x", Locale.getDefault()));\r
+    public static final IppAttributeName MULTIPLE_DOCUMENT_JOBS_SUPPORTED =\r
+               new IppAttributeName(new MultipleDocumentJobsSupported(1));\r
+       public static final IppAttributeName MULTIPLE_OPERATION_TIMEOUT = new IppAttributeName(new MultipleOperationTimeout(1));\r
+       public static final IppAttributeName NATURAL_LANGUAGE = new IppAttributeName(new NaturalLanguage("x", Locale.getDefault()));\r
+       public static final IppAttributeName NATURAL_LANGUAGE_CONFIGURED =\r
+               new IppAttributeName(new NaturalLanguageConfigured("x", Locale.getDefault()));\r
+       public static final IppAttributeName NUMBER_UP_DEFAULT = new IppAttributeName(new NumberUpDefault(1));\r
+       public static final IppAttributeName OPERATIONS_SUPPORTED = new IppAttributeName(new OperationsSupported(1));\r
+       public static final IppAttributeName ORIENTATION_REQUESTED_DEFAULT = new IppAttributeName(new OrientationRequestedDefault(1));\r
+       public static final IppAttributeName ORIENTATION_REQUESTED_SUPPORTED =\r
+               new IppAttributeName(new OrientationRequestedSupported(1));\r
+       public static final IppAttributeName PAGE_RANGES_SUPPORTED = new IppAttributeName(new PageRangesSupported(1));\r
+       public static final IppAttributeName PRINTER_CURRENT_TIME = new IppAttributeName(new PrinterCurrentTime(new Date()));\r
+       public static final IppAttributeName PRINTER_DRIVER_INSTALLER =\r
+               new IppAttributeName(new PrinterDriverInstaller(IppAttributeName.getURI()));\r
+       public static final IppAttributeName PRINTER_STATE_MESSAGE =\r
+               new IppAttributeName(new PrinterStateMessage("x", Locale.getDefault()));\r
+       public static final IppAttributeName PRINTER_TYPE = new IppAttributeName(new PrinterType(1));\r
+       public static final IppAttributeName PRINTER_UP_TIME = new IppAttributeName(new PrinterUpTime(1));\r
+       public static final IppAttributeName PRINTER_URI_SUPPORTED =\r
+               new IppAttributeName(new PrinterUriSupported(IppAttributeName.getURI()));\r
+       public static final IppAttributeName SIDES_DEFAULT = new IppAttributeName(new SidesDefault("x", Locale.getDefault()));\r
+       public static final IppAttributeName SIDES_SUPPORTED = new IppAttributeName(new SidesSupported("x", Locale.getDefault()));\r
+       public static final IppAttributeName STATUS_MESSAGE = new IppAttributeName(new StatusMessage("x", Locale.getDefault()));\r
+       public static final IppAttributeName TIME_AT_COMPLETED = new IppAttributeName(new TimeAtCompleted(1));\r
+       public static final IppAttributeName TIME_AT_CREATION = new IppAttributeName(new TimeAtCreation(1));\r
+                                                                                                     public static final IppAttributeName TIME_AT_PROCESSING = new IppAttributeName(new TimeAtProcessing(1));\r
+       public static final IppAttributeName URI_AUTHENTICATION_SUPPORTED =\r
+               new IppAttributeName(new UriAuthenticationSupported("x", Locale.getDefault()));\r
+       public static final IppAttributeName URI_SECURITY_SUPPORTED =\r
+               new IppAttributeName(new UriSecuritySupported("x", Locale.getDefault()));\r
+       \r
+       \r
+       /*\r
+        * CUPS IPP extension attributes defined in de.lohndirekt.attribute.cups\r
+        */\r
+       public static final IppAttributeName DEVICE_CLASS = new IppAttributeName(new DeviceClass("x", Locale.getDefault()));\r
+       public static final IppAttributeName DEVICE_URI = new IppAttributeName(new DeviceUri(IppAttributeName.getURI()));\r
+       public static final IppAttributeName Job_K_LIMIT = new IppAttributeName(new JobKLimit(1));\r
+       public static final IppAttributeName JOB_PAGE_LIMIT = new IppAttributeName(new JobPageLimit(1));\r
+       public static final IppAttributeName JOB_QUOTA_PERIOD = new IppAttributeName(new JobQuotaPeriod(1));\r
+       public static final IppAttributeName MEMBER_NAMES = new IppAttributeName(new MemberNames("x", Locale.getDefault()));\r
+       public static final IppAttributeName MEMBER_URIS = new IppAttributeName(new MemberUris(IppAttributeName.getURI()));\r
+       public static final IppAttributeName PRINTER_STATE_TIME = new IppAttributeName(new PrinterStateTime(1));\r
+       \r
+       /*\r
+        * undocumented IPP attributes used by CUPS\r
+        */\r
+       public static final IppAttributeName OUTPUT_BIN_SUPPORTED =\r
+               new IppAttributeName(new OutputBinSupported("x", Locale.getDefault()));\r
+       \r
+       \r
+       private static Map attributesByName = new HashMap();;\r
+       private static Map attributesByCategory = new HashMap();;\r
+\r
+       /**\r
+                * \r
+                */\r
+       private static URI getURI() {\r
+               try {\r
+                       return new URI("http://www.lohndirekt.de");\r
+               } catch (URISyntaxException e) {\r
+                       throw new RuntimeException(e);\r
+               }\r
+\r
+       }\r
+\r
+       private static void put(IppAttributeName attr) {\r
+               attributesByName.put(attr.getName(), attr);\r
+               attributesByCategory.put(attr.getCategory(), attr);\r
+       }\r
+\r
+       /**\r
+        * \r
+        */\r
+       static {\r
+               put(IppAttributeName.CHARSET);\r
+               put(IppAttributeName.CHARSET_CONFIGURED);\r
+               put(IppAttributeName.CHARSET_SUPORTED);\r
+               put(IppAttributeName.COLOR_SUPPORTED);\r
+               put(IppAttributeName.COMPRESSION);\r
+               put(IppAttributeName.COMPRESSION_SUPORTED);\r
+               put(IppAttributeName.COPIES);\r
+               put(IppAttributeName.COPIES_DEFAULT);\r
+               put(IppAttributeName.COPIES_SUPPORTED);\r
+               put(IppAttributeName.DATE_TIME_AT_COMPLETION);\r
+               put(IppAttributeName.DATE_TIME_AT_CREATION);\r
+               put(IppAttributeName.DATE_TIME_AT_PROCESSING);\r
+               put(IppAttributeName.DEVICE_CLASS);\r
+               put(IppAttributeName.DEVICE_URI);\r
+        put(IppAttributeName.DETAILED_STATUS_MESSAGE);\r
+               put(IppAttributeName.DOCUMENT_NAME);\r
+               put(IppAttributeName.DOCUMENT_FORMAT);\r
+               put(IppAttributeName.DOCUMENT_FORMAT_DEFAULT);\r
+               put(IppAttributeName.DOCUMENT_FORMAT_SUPORTED);\r
+               put(IppAttributeName.FIDELITY);\r
+               put(IppAttributeName.FINISHINGS);\r
+               put(IppAttributeName.FINISHINGS_DEFAULT);\r
+               put(IppAttributeName.FINISHINGS_SUPPORTED);\r
+               put(IppAttributeName.GENERATED_NATURAL_LANGUAGE_SUPPORTED);\r
+               put(IppAttributeName.IPP_VERSIONS_SUPPORTED);\r
+        put(IppAttributeName.JOB_HOLD_UNTIL);\r
+               put(IppAttributeName.JOB_HOLD_UNTIL_DEFAULT);\r
+               put(IppAttributeName.JOB_HOLD_UNTIL_SUPPORTED);\r
+               put(IppAttributeName.JOB_ID);\r
+               put(IppAttributeName.JOB_IMPRESSIONS);\r
+               put(IppAttributeName.JOB_IMPRESSIONS_COMPLETED);\r
+               put(IppAttributeName.JOB_IMPRESSIONS_SUPPORTED);\r
+               put(IppAttributeName.Job_K_LIMIT);\r
+               put(IppAttributeName.JOB_K_OCTETS);\r
+               put(IppAttributeName.JOB_K_OCTETS_PROCESSED);\r
+               put(IppAttributeName.JOB_K_OCTETS_SUPPORTED);\r
+               put(IppAttributeName.JOB_MEDIA_SHEETS);\r
+               put(IppAttributeName.JOB_MEDIA_SHEETS_COMPLETED);\r
+               put(IppAttributeName.JOB_MEDIA_SHEETS_SUPPORTED);\r
+               put(IppAttributeName.JOB_MESSAGE_FROM_OPERATOR);\r
+               put(IppAttributeName.JOB_MORE_INFO);\r
+               put(IppAttributeName.JOB_NAME);\r
+               put(IppAttributeName.JOB_ORIGINATING_HOST_NAME);\r
+               put(IppAttributeName.JOB_ORIGINATING_USER_NAME);\r
+               put(IppAttributeName.JOB_PAGE_LIMIT);\r
+               put(IppAttributeName.JOB_PRINTER_UP_TIME);\r
+               put(IppAttributeName.JOB_PRINTER_URI);\r
+               put(IppAttributeName.JOB_PRIORIY);\r
+               put(IppAttributeName.JOB_PRIORITY_DEFAULT);\r
+               put(IppAttributeName.JOB_PRIORIY_SUPPORTED);\r
+               put(IppAttributeName.JOB_QUOTA_PERIOD);\r
+               put(IppAttributeName.JOB_SHEETS);\r
+               put(IppAttributeName.JOB_SHEETS_DEFAULT);\r
+               put(IppAttributeName.JOB_SHEETS_SUPORTED);\r
+               put(IppAttributeName.JOB_STATE);\r
+               put(IppAttributeName.JOB_STATE_REASON);\r
+               put(IppAttributeName.JOB_STATE_REASONS);\r
+               put(IppAttributeName.JOB_URI);\r
+               put(IppAttributeName.MEDIA);\r
+               put(IppAttributeName.MEDIA_DEFAULT);\r
+               put(IppAttributeName.MEDIA_SUPPORTED);\r
+               put(IppAttributeName.MEMBER_NAMES);\r
+               put(IppAttributeName.MEMBER_URIS);\r
+               put(IppAttributeName.MULTIPLE_DOCUMENT_HANDLING);\r
+        put(IppAttributeName.MULTIPLE_DOCUMENT_HANDLING_DEFAULT);\r
+               put(IppAttributeName.MULTIPLE_DOCUMENT_HANDLING_SUPPORTED);\r
+               put(IppAttributeName.MULTIPLE_DOCUMENT_JOBS_SUPPORTED);\r
+               put(IppAttributeName.MULTIPLE_OPERATION_TIMEOUT);\r
+               put(IppAttributeName.NATURAL_LANGUAGE);\r
+               put(IppAttributeName.NATURAL_LANGUAGE_CONFIGURED);\r
+               put(IppAttributeName.NUMBER_OF_DOCUMENTS);\r
+               put(IppAttributeName.NUMBER_OF_INTERVENING_JOBS);\r
+               put(IppAttributeName.NUMBER_UP);\r
+               put(IppAttributeName.NUMBER_UP_DEFAULT);\r
+               put(IppAttributeName.NUMBER_UP_SUPPORTED);\r
+               put(IppAttributeName.OPERATIONS_SUPPORTED);\r
+               put(IppAttributeName.ORIENTATION_REQUESTED);\r
+               put(IppAttributeName.ORIENTATION_REQUESTED_DEFAULT);\r
+               put(IppAttributeName.ORIENTATION_REQUESTED_SUPPORTED);\r
+               put(IppAttributeName.OUTPUT_BIN_SUPPORTED);\r
+               put(IppAttributeName.OUTPUT_DEVICE_ASSIGNED);\r
+               put(IppAttributeName.PAGE_RANGES);\r
+               put(IppAttributeName.PAGE_RANGES_SUPPORTED);\r
+               put(IppAttributeName.PAGES_PER_MINUTE);\r
+               put(IppAttributeName.PAGES_PER_MINUTE_COLOR);\r
+               put(IppAttributeName.PDL_OVERRIDE_SUPPORTED);\r
+               put(IppAttributeName.PRESENTATION_DIRECTION);\r
+               put(IppAttributeName.PRINT_QUALITY);\r
+               put(IppAttributeName.PRINTER_CURRENT_TIME);\r
+               put(IppAttributeName.PRINTER_DRIVER_INSTALLER);\r
+               put(IppAttributeName.PRINTER_INFO);\r
+               put(IppAttributeName.PRINTER_IS_ACCEPTING_JOBS);\r
+               put(IppAttributeName.PRINTER_LOCATION);\r
+               put(IppAttributeName.PRINTER_MAKE_AND_MODEL);\r
+               put(IppAttributeName.PRINTER_MESSAGE_FROM_OPERATOR);\r
+               put(IppAttributeName.PRINTER_MORE_INFO);\r
+               put(IppAttributeName.PRINTER_MORE_INFO_MANUFACTURER);\r
+               put(IppAttributeName.PRINTER_NAME);\r
+               put(IppAttributeName.PRINTER_RESOLUTION);\r
+               put(IppAttributeName.PRINTER_STATE);\r
+               put(IppAttributeName.PRINTER_STATE_MESSAGE);\r
+               put(IppAttributeName.PRINTER_STATE_REASON);\r
+               put(IppAttributeName.PRINTER_STATE_REASONS);\r
+               put(IppAttributeName.PRINTER_STATE_TIME);\r
+               put(IppAttributeName.PRINTER_TYPE);\r
+               put(IppAttributeName.PRINTER_UP_TIME);\r
+               put(IppAttributeName.PRINTER_URI);\r
+               put(IppAttributeName.PRINTER_URI_SUPPORTED);\r
+               put(IppAttributeName.QUEUED_JOB_COUNT);\r
+               put(IppAttributeName.REFERENCE_URI_SCHEMES_SUPPORTED);\r
+               put(IppAttributeName.REQUESTING_USER_NAME);\r
+               put(IppAttributeName.REQUESTING_USER_PASSWD);\r
+               put(IppAttributeName.SEVERITY);\r
+               put(IppAttributeName.SHEET_COLLATE);\r
+               put(IppAttributeName.SIDES);\r
+               put(IppAttributeName.SIDES_DEFAULT);\r
+               put(IppAttributeName.SIDES_SUPPORTED);\r
+               put(IppAttributeName.STATUS_MESSAGE);\r
+               put(IppAttributeName.TIME_AT_COMPLETED);\r
+               put(IppAttributeName.TIME_AT_CREATION);\r
+               put(IppAttributeName.TIME_AT_PROCESSING);\r
+               put(IppAttributeName.URI_AUTHENTICATION_SUPPORTED);\r
+               put(IppAttributeName.URI_SECURITY_SUPPORTED);\r
+       }\r
+\r
+       public static IppAttributeName get(String attributeName) {\r
+               IppAttributeName attrib =(IppAttributeName)attributesByName.get(attributeName);\r
+               if (attrib == null) {\r
+                       log.warning("Unknown Attribute " + attributeName + ".");\r
+                       attrib = new IppAttributeName(new UnknownAttribute(attributeName, Locale.getDefault()));\r
+               }\r
+               return attrib;\r
+       }\r
+\r
+       public static IppAttributeName get(Class category) {\r
+           IppAttributeName attrib =(IppAttributeName)attributesByCategory.get(category);\r
+               if (attrib == null) {\r
+                       log.warning("Unknown Category " + category + ".");\r
+                       attrib = new IppAttributeName(new UnknownAttribute(category.getName(), Locale.getDefault()));\r
+               }\r
+               return attrib;\r
+       }\r
+       // End of static part\r
+\r
+       private String methodName;\r
+       private Class attributeClass;\r
+       private Class category;\r
+\r
+       private IppAttributeName(Attribute attribute) {\r
+               this.methodName = attribute.getName();\r
+               this.attributeClass = attribute.getClass();\r
+               this.category = attribute.getCategory();\r
+       }\r
+\r
+       /**\r
+        * @return\r
+        */\r
+       public Class getAttributeClass() {\r
+               return attributeClass;\r
+       }\r
+\r
+       public String getName() {\r
+               return this.methodName;\r
+       }\r
+\r
+       /**\r
+        * \r
+        */\r
+       public Class getCategory() {\r
+               return this.category;\r
+       }\r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/attribute/IppAttributeNameTest.java b/jspi/src/main/java/de/lohndirekt/print/attribute/IppAttributeNameTest.java
new file mode 100644 (file)
index 0000000..a0d41c7
--- /dev/null
@@ -0,0 +1,60 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print.attribute;\r
+\r
+import java.util.Locale;\r
+\r
+import junit.framework.TestCase;\r
+import de.lohndirekt.print.attribute.ipp.UnknownAttribute;\r
+\r
+/**\r
+ * @author bpusch\r
+ *\r
+ * \r
+ */\r
+public class IppAttributeNameTest extends TestCase {\r
+\r
+    /**\r
+     * Constructor for IppAttributeNameTest.\r
+     * @param name\r
+     */\r
+    public IppAttributeNameTest(String name) {\r
+        super(name);\r
+    }\r
+\r
+    \r
+    /*\r
+     * Test for IppAttributeName get(String)\r
+     */\r
+    public void testGetString() {\r
+        IppAttributeName attributeName = IppAttributeName.get("attribute-does-not-exist");\r
+        assertNotNull("IppAttributeName is null",attributeName);\r
+        assertEquals("IppAttributeName should be UNKNOWN_ATTRIBUTE", attributeName.getCategory(), new UnknownAttribute("x",Locale.getDefault()).getCategory());\r
+    }\r
+\r
+    /*\r
+     * Test for IppAttributeName get(Class)\r
+     */\r
+    public void testGetClass() {\r
+        IppAttributeName attributeName = IppAttributeName.get(String.class);\r
+                assertNotNull("IppAttributeName is null",attributeName);\r
+                assertEquals("IppAttributeName should be UNKNOWN_ATTRIBUTE", attributeName.getCategory(), new UnknownAttribute("x",Locale.getDefault()).getCategory());\r
+    }\r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/attribute/IppDelimiterTag.java b/jspi/src/main/java/de/lohndirekt/print/attribute/IppDelimiterTag.java
new file mode 100644 (file)
index 0000000..908d906
--- /dev/null
@@ -0,0 +1,52 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print.attribute;\r
+\r
+/**\r
+ *Bezeichnungen übernommen aus <link>www.ietf.org/rfc/rfc2910.txt</link>\r
+ *Tags ohne Bezeichnung sind dort nicht aufgeführt, werden aber in der Cups-API verwendet\r
+ */\r
+public class IppDelimiterTag {\r
+       \r
+       private String description = "";\r
+       private int value = 0;\r
+\r
+       public static final IppDelimiterTag ZERO = new IppDelimiterTag(0x00, "");\r
+       public static final IppDelimiterTag BEGIN_OPERATION_ATTRIBUTES = new IppDelimiterTag(0x01, "operation-attributes-tag");\r
+       public static final IppDelimiterTag BEGIN_JOB_ATTRIBUTES = new IppDelimiterTag(0x02, "job-attributes-tag");\r
+       public static final IppDelimiterTag END_ATTRIBUTES = new IppDelimiterTag(0x03, "end-of-attributes-tag");\r
+       public static final IppDelimiterTag BEGIN_PRINTER_ATTRIBUTES = new IppDelimiterTag(0x04, "printer-attributes-tag");\r
+       public static final IppDelimiterTag UNSUPPORTED_GROUP = new IppDelimiterTag(0x05, "unsupported-attributes-tag");\r
+       public static final IppDelimiterTag SUBSCRIPTION = new IppDelimiterTag(0x06, "");\r
+       public static final IppDelimiterTag EVENT_NOTIFICATION = new IppDelimiterTag(0x07, "");\r
+       \r
+       private IppDelimiterTag(int value, String description) {\r
+                       this.value = value;\r
+                       this.description = description;\r
+               }\r
+       \r
+               public int getValue(){\r
+                       return this.value;\r
+               }\r
+               \r
+               public String toString(){\r
+                       return this.description;\r
+               }\r
+       \r
+}
\ No newline at end of file
diff --git a/jspi/src/main/java/de/lohndirekt/print/attribute/IppStatus.java b/jspi/src/main/java/de/lohndirekt/print/attribute/IppStatus.java
new file mode 100644 (file)
index 0000000..54ef905
--- /dev/null
@@ -0,0 +1,147 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print.attribute;\r
+\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+public final class IppStatus {\r
+\r
+       public static final IppStatus SUCCESSFUL_OK = new IppStatus("successful-ok", 0x0000);\r
+       public static final IppStatus SUCCESSFUL_OK_IGNORED_OR_SUBSTITUTED_ATTRIBUTES =\r
+               new IppStatus("successful-ok-ignored-or-substituted-attributes", 0x0001);\r
+       public static final IppStatus SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES =\r
+               new IppStatus("successful-ok-conflicting-attributes", 0x0002);\r
+       public static final IppStatus CLIENT_ERROR_BAD_REQUEST = new IppStatus("client-error-bad-request", 0x0400);\r
+       public static final IppStatus CLIENT_ERROR_FORBIDDEN = new IppStatus("client-error-forbidden", 0x0401);\r
+       public static final IppStatus CLIENT_ERROR_NOT_AUTHENTICATED = new IppStatus("client-error-not-authenticated", 0x0402);\r
+       public static final IppStatus CLIENT_ERROR_NOT_AUTHORIZED = new IppStatus("client-error-not-authorized", 0x0403);\r
+       public static final IppStatus CLIENT_ERROR_NOT_POSSIBLE = new IppStatus("client-error-not-possible", 0x0404);\r
+       public static final IppStatus CLIENT_ERROR_TIMEOUT = new IppStatus("client-error-timeout", 0x0405);\r
+       public static final IppStatus CLIENT_ERROR_NOT_FOUND = new IppStatus("client-error-not-found", 0x0406);\r
+       public static final IppStatus CLIENT_ERROR_GONE = new IppStatus("client-error-gone", 0x0407);\r
+       public static final IppStatus CLIENT_ERROR_REQUEST_ENTITY_TOO_LARGE =\r
+               new IppStatus("client-error-request-entity-too-large", 0x0408);\r
+       public static final IppStatus CLIENT_ERROR_REQUEST_VALUE_TOO_LONG =\r
+               new IppStatus("client-error-request-value-too-long", 0x0409);\r
+       public static final IppStatus CLIENT_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED =\r
+               new IppStatus("client-error-document-format-not-supported", 0x040A);\r
+       public static final IppStatus CLIENT_ERROR_ATTRIBUTES_OR_VALUES_NOT_SUPPORTED =\r
+               new IppStatus("client-error-attributes-or-values-not-supported", 0x040B);\r
+       public static final IppStatus CLIENT_ERROR_URI_SCHEME_NOT_SUPPORTED =\r
+               new IppStatus("client-error-uri-scheme-not-supported", 0x040C);\r
+       public static final IppStatus CLIENT_ERROR_CHARSET_NOT_SUPPORTED =\r
+               new IppStatus("client-error-charset-not-supported", 0x040D);\r
+       public static final IppStatus CLIENT_ERROR_CONFLICTING_ATTRIBUTES =\r
+               new IppStatus("client-error-conflicting-attributes", 0x040E);\r
+       public static final IppStatus CLIENT_ERROR_COMPRESSION_NOT_SUPPORTED =\r
+               new IppStatus("client-error-compression-not-supported", 0x040F);\r
+       public static final IppStatus CLIENT_ERROR_COMPRESSION_ERROR = new IppStatus("client-error-compression-error", 0x0410);\r
+       public static final IppStatus CLIENT_ERROR_DOCUMENT_FORMAT_ERROR =\r
+               new IppStatus("client-error-document-format-error", 0x0411);\r
+       public static final IppStatus CLIENT_ERROR_DOCUMENT_ACCESS_ERROR =\r
+               new IppStatus("client-error-document-access-error", 0x0412);\r
+       public static final IppStatus SERVER_ERROR_INTERNAL_ERROR = new IppStatus("server-error-internal-error", 0x0500);\r
+       public static final IppStatus SERVER_ERROR_OPERATION_NOT_SUPPORTED =\r
+               new IppStatus("server-error-operation-not-supported", 0x0501);\r
+       public static final IppStatus SERVER_ERROR_SERVICE_UNAVAILABLE = new IppStatus("server-error-service-unavailable", 0x0502);\r
+       public static final IppStatus SERVER_ERROR_VERSION_NOT_SUPPORTED =\r
+               new IppStatus("server-error-version-not-supported", 0x0503);\r
+       public static final IppStatus SERVER_ERROR_DEVICE_ERROR = new IppStatus("server-error-device-error", 0x0504);\r
+       public static final IppStatus SERVER_ERROR_TEMPORARY_ERROR = new IppStatus("server-error-temporary-error", 0x0505);\r
+       public static final IppStatus SERVER_ERROR_NOT_ACCEPTING_JOBS = new IppStatus("server-error-not-accepting-jobs", 0x0506);\r
+       public static final IppStatus SERVER_ERROR_BUSY = new IppStatus("server-error-busy", 0x0507);\r
+       public static final IppStatus SERVER_ERROR_JOB_CANCELED = new IppStatus("server-error-job-canceled", 0x0508);\r
+       public static final IppStatus SERVER_ERROR_MULTIPLE_DOCUMENT_JOBS_NOT_SUPPORTED =\r
+               new IppStatus("server-error-multiple-document-jobs-not-supported", 0x0509);\r
+\r
+       private static Map stati;\r
+\r
+       private static void init() {\r
+               stati = new HashMap();\r
+               put(SUCCESSFUL_OK);\r
+               put(SUCCESSFUL_OK_IGNORED_OR_SUBSTITUTED_ATTRIBUTES);\r
+               put(SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES);\r
+               put(CLIENT_ERROR_BAD_REQUEST);\r
+               put(CLIENT_ERROR_FORBIDDEN);\r
+               put(CLIENT_ERROR_NOT_AUTHENTICATED);\r
+               put(CLIENT_ERROR_NOT_AUTHORIZED);\r
+               put(CLIENT_ERROR_NOT_POSSIBLE);\r
+               put(CLIENT_ERROR_TIMEOUT);\r
+               put(CLIENT_ERROR_NOT_FOUND);\r
+               put(CLIENT_ERROR_GONE);\r
+               put(CLIENT_ERROR_REQUEST_ENTITY_TOO_LARGE);\r
+               put(CLIENT_ERROR_REQUEST_VALUE_TOO_LONG);\r
+               put(CLIENT_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED);\r
+               put(CLIENT_ERROR_ATTRIBUTES_OR_VALUES_NOT_SUPPORTED);\r
+               put(CLIENT_ERROR_URI_SCHEME_NOT_SUPPORTED);\r
+               put(CLIENT_ERROR_CHARSET_NOT_SUPPORTED);\r
+               put(CLIENT_ERROR_CONFLICTING_ATTRIBUTES);\r
+               put(CLIENT_ERROR_COMPRESSION_NOT_SUPPORTED);\r
+               put(CLIENT_ERROR_COMPRESSION_ERROR);\r
+               put(CLIENT_ERROR_DOCUMENT_FORMAT_ERROR);\r
+               put(CLIENT_ERROR_DOCUMENT_ACCESS_ERROR);\r
+               put(SERVER_ERROR_INTERNAL_ERROR);\r
+               put(SERVER_ERROR_OPERATION_NOT_SUPPORTED);\r
+               put(SERVER_ERROR_SERVICE_UNAVAILABLE);\r
+               put(SERVER_ERROR_VERSION_NOT_SUPPORTED);\r
+               put(SERVER_ERROR_DEVICE_ERROR);\r
+               put(SERVER_ERROR_TEMPORARY_ERROR);\r
+               put(SERVER_ERROR_NOT_ACCEPTING_JOBS);\r
+               put(SERVER_ERROR_BUSY);\r
+               put(SERVER_ERROR_JOB_CANCELED);\r
+               put(SERVER_ERROR_MULTIPLE_DOCUMENT_JOBS_NOT_SUPPORTED);\r
+\r
+       }\r
+\r
+       /**\r
+        * @param status2\r
+        */\r
+       private static void put(IppStatus status) {\r
+               stati.put(new Integer(status.getStatus()), status);\r
+       }\r
+\r
+       public static IppStatus get(int statusCode) {\r
+               if (stati == null) {\r
+                       init();\r
+               }\r
+               return (IppStatus)stati.get(new Integer(statusCode));\r
+       }\r
+\r
+       /*\r
+        * End of static part\r
+        */\r
+\r
+       private String text;\r
+       private int status;\r
+\r
+       private IppStatus(String statusText, int statusCode) {\r
+               this.status = statusCode;\r
+               this.text = statusText;\r
+       }\r
+\r
+       public String getText() {\r
+               return this.text;\r
+       }\r
+\r
+       public int getStatus() {\r
+               return this.status;\r
+       }\r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/attribute/IppValueTag.java b/jspi/src/main/java/de/lohndirekt/print/attribute/IppValueTag.java
new file mode 100644 (file)
index 0000000..8f95b7d
--- /dev/null
@@ -0,0 +1,74 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print.attribute;\r
+\r
+/**\r
+ *Bezeichnungen übernommen aus <link>www.ietf.org/rfc/rfc2910.txt</link>\r
+ *Tags ohne Bezeichnung sind dort nicht aufgeführt, werden aber in der Cups-API verwendet\r
+ */\r
+public class IppValueTag {\r
+       \r
+       private String description;\r
+       private int value = 0;\r
+\r
+       public static final IppValueTag UNSUPPORTED_VALUE = new IppValueTag(0x10, "unsupported");\r
+       public static final IppValueTag DEFAULT = new IppValueTag(0x11, "'default' ");\r
+       public static final IppValueTag UNKNOWN = new IppValueTag(0x12, "unknown");\r
+       public static final IppValueTag NOVALUE = new IppValueTag(0x13, "no-value");\r
+       public static final IppValueTag NOTSETTABLE = new IppValueTag(0x15, "");\r
+       public static final IppValueTag DELETEATTR = new IppValueTag(0x16, "");\r
+       public static final IppValueTag ADMINDEFINE = new IppValueTag(0x17, "");\r
+       public static final IppValueTag INTEGER = new IppValueTag(0x21, "integer");\r
+       public static final IppValueTag BOOLEAN = new IppValueTag(0x22, "boolean");\r
+       public static final IppValueTag ENUM = new IppValueTag(0x23, "enum");\r
+       public static final IppValueTag STRING = new IppValueTag(0x30, "octetString");\r
+       public static final IppValueTag DATE = new IppValueTag(0x31, "dateTime");\r
+       public static final IppValueTag RESOLUTION = new IppValueTag(0x32, "resolution");\r
+       public static final IppValueTag RANGE = new IppValueTag(0x33, "rangeOfInteger");\r
+       public static final IppValueTag BEGIN_COLLECTION = new IppValueTag(0x34, "");\r
+       public static final IppValueTag TEXTLANG = new IppValueTag(0x35, "resolution");\r
+       public static final IppValueTag NAMELANG = new IppValueTag(0x36, "nameWithLanguage");\r
+       public static final IppValueTag END_COLLECTION = new IppValueTag(0x37, "");\r
+       public static final IppValueTag TEXT = new IppValueTag(0x41, "textWithoutLanguage");\r
+       public static final IppValueTag NAME = new IppValueTag(0x42, "nameWithoutLanguage");\r
+       public static final IppValueTag KEYWORD = new IppValueTag(0x44, "keyword");\r
+       public static final IppValueTag URI = new IppValueTag(0x45, "uri");\r
+       public static final IppValueTag URISCHEME = new IppValueTag(0x46, "uriScheme");\r
+       public static final IppValueTag CHARSET = new IppValueTag(0x47, "charset");\r
+       public static final IppValueTag LANGUAGE = new IppValueTag(0x48, "naturalLanguage");\r
+       public static final IppValueTag MIMETYPE = new IppValueTag(0x49, "mimeMediaType");\r
+       public static final IppValueTag MEMBERNAME = new IppValueTag(0x4A, "");\r
+       public static final IppValueTag MASK = new IppValueTag(0x7FFFFFFF, "");\r
+       public static final IppValueTag COPY = new IppValueTag(0x80000001, "");\r
+\r
+       private IppValueTag(int value, String description) {\r
+               this.value = value;\r
+               this.description = description;\r
+       }\r
+\r
+       public int getValue() {\r
+               return this.value;\r
+       }\r
+       \r
+       \r
+       public String toString() {\r
+               return this.description;\r
+       }\r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/attribute/auth/RequestingUserPassword.java b/jspi/src/main/java/de/lohndirekt/print/attribute/auth/RequestingUserPassword.java
new file mode 100644 (file)
index 0000000..b89289e
--- /dev/null
@@ -0,0 +1,56 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print.attribute.auth;\r
+\r
+import java.util.Locale;\r
+\r
+import javax.print.attribute.PrintRequestAttribute;\r
+import javax.print.attribute.TextSyntax;\r
+\r
+public class RequestingUserPassword extends TextSyntax implements PrintRequestAttribute{\r
+\r
+       \r
+       /**\r
+        * @param value\r
+        */\r
+       public RequestingUserPassword(String name, Locale locale) {\r
+               super(name, locale);\r
+       }\r
+\r
+       /**\r
+        *\r
+        */\r
+\r
+       public Class getCategory() {\r
+               return RequestingUserPassword.class;\r
+       }\r
+\r
+       /**\r
+        *\r
+        */\r
+\r
+       public static String getIppName() {\r
+               return "requesting-user-password";\r
+       }\r
+\r
+       public String getName() {\r
+               return RequestingUserPassword.getIppName();\r
+       }\r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/attribute/cups/DeviceClass.java b/jspi/src/main/java/de/lohndirekt/print/attribute/cups/DeviceClass.java
new file mode 100644 (file)
index 0000000..4607f1a
--- /dev/null
@@ -0,0 +1,65 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print.attribute.cups;\r
+\r
+import java.util.Locale;\r
+\r
+import javax.print.attribute.Attribute;\r
+import javax.print.attribute.TextSyntax;\r
+\r
+\r
+public class DeviceClass extends TextSyntax implements Attribute {\r
+       \r
+public final static DeviceClass FILE = new DeviceClass("file", Locale.getDefault());\r
+       public final static DeviceClass DIRECT = new DeviceClass("direct", Locale.getDefault());\r
+       public final static DeviceClass SERIAL = new DeviceClass("serial", Locale.getDefault());\r
+       public final static DeviceClass NETWORK = new DeviceClass("network", Locale.getDefault());\r
+\r
+       /**\r
+        * @param value\r
+        * @param locale\r
+        */\r
+       public DeviceClass(String value, Locale locale) {\r
+               super(value, locale);\r
+       }\r
+\r
+       /**\r
+        *\r
+        */\r
+\r
+       public Class getCategory() {\r
+               return this.getClass();\r
+       }\r
+\r
+       /**\r
+        *\r
+        */\r
+\r
+       public String getName() {\r
+               return DeviceClass.getIppName();\r
+       }\r
+\r
+       /**\r
+        * \r
+        */\r
+       public static String getIppName() {\r
+               return "device-class";\r
+       }\r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/attribute/cups/DeviceUri.java b/jspi/src/main/java/de/lohndirekt/print/attribute/cups/DeviceUri.java
new file mode 100644 (file)
index 0000000..1c626ce
--- /dev/null
@@ -0,0 +1,56 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print.attribute.cups;\r
+\r
+import java.net.URI;\r
+\r
+import javax.print.attribute.Attribute;\r
+import javax.print.attribute.URISyntax;\r
+\r
+\r
+public class DeviceUri extends URISyntax implements Attribute {\r
+\r
+       /**\r
+        * @param uri\r
+        */\r
+       public DeviceUri(URI uri) {\r
+               super(uri);\r
+       }\r
+\r
+       /**\r
+        *\r
+        */\r
+\r
+       public Class getCategory() {\r
+               return this.getClass();\r
+       }\r
+\r
+       /**\r
+        *\r
+        */\r
+\r
+       public String getName() {\r
+               return DeviceUri.getIppName();\r
+       }\r
+       \r
+       public static String getIppName(){\r
+               return "device-uri";\r
+       }\r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/attribute/cups/JobKLimit.java b/jspi/src/main/java/de/lohndirekt/print/attribute/cups/JobKLimit.java
new file mode 100644 (file)
index 0000000..17177dd
--- /dev/null
@@ -0,0 +1,59 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print.attribute.cups;\r
+\r
+import javax.print.attribute.IntegerSyntax;\r
+import javax.print.attribute.PrintServiceAttribute;\r
+\r
+\r
+public class JobKLimit extends IntegerSyntax implements PrintServiceAttribute {\r
+\r
+       /**\r
+        * @param value\r
+        */\r
+       public JobKLimit(int value) {\r
+               super(value);\r
+       }\r
+\r
+       /**\r
+        * @param value\r
+        * @param lowerBound\r
+        * @param upperBound\r
+        */\r
+       public JobKLimit(int value, int lowerBound, int upperBound) {\r
+               super(value, lowerBound, upperBound);\r
+       }\r
+\r
+               /**\r
+        *\r
+        */\r
+\r
+       public Class getCategory() {\r
+               return this.getClass();\r
+       }\r
+\r
+       public String getName() {\r
+               return JobKLimit.getIppName();\r
+       }\r
+       \r
+       public static String getIppName(){\r
+               return "job-k-limit";\r
+       }\r
+\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/attribute/cups/JobPageLimit.java b/jspi/src/main/java/de/lohndirekt/print/attribute/cups/JobPageLimit.java
new file mode 100644 (file)
index 0000000..ed73339
--- /dev/null
@@ -0,0 +1,58 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print.attribute.cups;\r
+\r
+import javax.print.attribute.IntegerSyntax;\r
+import javax.print.attribute.PrintServiceAttribute;\r
+\r
+\r
+public class JobPageLimit extends IntegerSyntax implements PrintServiceAttribute {\r
+\r
+       /**\r
+        * @param value\r
+        */\r
+       public JobPageLimit(int value) {\r
+               super(value);\r
+       }\r
+\r
+       /**\r
+        * @param value\r
+        * @param lowerBound\r
+        * @param upperBound\r
+        */\r
+       public JobPageLimit(int value, int lowerBound, int upperBound) {\r
+               super(value, lowerBound, upperBound);\r
+       }\r
+\r
+       /**\r
+        *\r
+        */\r
+\r
+       public Class getCategory() {\r
+               return this.getClass();\r
+       }\r
+\r
+       public String getName() {\r
+               return JobPageLimit.getIppName();\r
+       }\r
+       \r
+       public static String getIppName(){\r
+               return "job-page-limit";\r
+       }\r
+}\r
diff --git a/jspi/src/main/java/de/lohndirekt/print/attribute/cups/JobQuotaPeriod.java b/jspi/src/main/java/de/lohndirekt/print/attribute/cups/JobQuotaPeriod.java
new file mode 100644 (file)
index 0000000..9e99693
--- /dev/null
@@ -0,0 +1,63 @@
+/**\r
+ * Copyright (C) 2003 <a href="http://www.lohndirekt.de/">lohndirekt.de</a>\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ * \r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *  \r
+ */\r
+package de.lohndirekt.print.attribute.cups;\r
+\r
+import javax.print.attribute.IntegerSyntax;\r
+import javax.print.attribute.PrintServiceAttribute;\r
+\r
+\r
+public class JobQuotaPeriod extends IntegerSyntax implements PrintServiceAttribute {\r
+\r
+       /**\r
+        * @param value\r
+        */\r
+       public JobQuotaPeriod(int value) {\r
+               super(value);\r
+       }\r
+\r
+       /**\r
+        * @param value\r
+        * @param lowerBound\r
+        * @param upperBound\r
+        */\r
+       public JobQuo