git-svn-id: http://jspi.googlecode.com/svn/trunk@4 b34d1714-897f-11dd-9205-735403a6da14
[clinton/mirror/jspi/.git] / jspi / src / main / java / com / google / code / jspi / AttributeParser.java
CommitLineData
3ea135bb 1package com.google.code.jspi;\r
2\r
3\r
4import java.io.IOException;\r
5import java.io.InputStream;\r
6import java.lang.reflect.Constructor;\r
7import java.lang.reflect.Field;\r
8import java.lang.reflect.InvocationTargetException;\r
9import java.net.URI;\r
10import java.net.URISyntaxException;\r
11import java.text.DateFormat;\r
12import java.text.DecimalFormat;\r
13import java.text.ParseException;\r
14import java.text.SimpleDateFormat;\r
15import java.util.Date;\r
16import java.util.HashMap;\r
17import java.util.HashSet;\r
18import java.util.Locale;\r
19import java.util.Map;\r
20import java.util.Set;\r
21import java.util.logging.Level;\r
22import java.util.logging.Logger;\r
23\r
24import javax.print.attribute.Attribute;\r
25import javax.print.attribute.EnumSyntax;\r
26\r
27import de.lohndirekt.print.attribute.AttributeWriter;\r
28import de.lohndirekt.print.attribute.IppAttributeName;\r
29import de.lohndirekt.print.attribute.IppDelimiterTag;\r
30import de.lohndirekt.print.attribute.IppValueTag;\r
31import de.lohndirekt.print.attribute.ipp.Charset;\r
32import de.lohndirekt.print.exception.EndOfAttributesException;\r
33\r
34/**\r
35 * @author bpusch\r
36 *\r
37 */\r
38public final class AttributeParser {\r
39\r
40 private final static EndOfAttributesException END_OF_ATTRIBUTES_EXCEPTION = new EndOfAttributesException();\r
41\r
42 private final static Logger log = Logger.getLogger(AttributeParser.class.getName());\r
43\r
44 \r
45\r
46 /**\r
47 * @param name\r
48 * @param values\r
49 * @return\r
50 */\r
51 private static Attribute getAttribute(String name, Object[] values) {\r
52 Attribute attribute = null;\r
53 IppAttributeName attrName = IppAttributeName.get(name);\r
54 Class attrClass = attrName.getAttributeClass();\r
55 Class superClass = attrClass.getSuperclass();\r
56 if (superClass != null) {\r
57 if (superClass.equals(EnumSyntax.class)) {\r
58 try {\r
59 Field[] fields = attrClass.getDeclaredFields();\r
60 for (int i = 0; i < fields.length; i++) {\r
61 Field field = fields[i];\r
62 if (field.getType().equals(attrClass)) {\r
63 EnumSyntax attr = (EnumSyntax) field.get(null);\r
64 if (values[0] instanceof String) {\r
65 if (attr.toString().equals(values[0])) {\r
66 attribute = (Attribute) attr;\r
67 break;\r
68 }\r
69 } else {\r
70 if (attr.getValue() == ((Integer) values[0]).intValue()) {\r
71 attribute = (Attribute) attr;\r
72 break;\r
73 }\r
74 }\r
75 }\r
76 }\r
77 } catch (SecurityException e) {\r
78 log.log(Level.SEVERE, e.getMessage(), e);\r
79 } catch (IllegalArgumentException e) {\r
80 log.log(Level.SEVERE, e.getMessage(), e);\r
81 } catch (IllegalAccessException e) {\r
82 log.log(Level.SEVERE, e.getMessage(), e);\r
83 }\r
84\r
85 } else {\r
86 Class[] parameters = toClassArray(values);\r
87 try {\r
88 Constructor constructor = attrClass.getDeclaredConstructor(parameters);\r
89 attribute = (Attribute) constructor.newInstance(values);\r
90 } catch (SecurityException e) {\r
91 log.log(Level.SEVERE, e.getMessage(), e);\r
92 } catch (NoSuchMethodException e) {\r
93 log.log(Level.SEVERE, e.getMessage(), e);\r
94 } catch (IllegalArgumentException e) {\r
95 log.log(Level.SEVERE, e.getMessage(), e);\r
96 } catch (InstantiationException e) {\r
97 log.log(Level.SEVERE, e.getMessage(), e);\r
98 } catch (IllegalAccessException e) {\r
99 log.log(Level.SEVERE, e.getMessage(), e);\r
100 } catch (InvocationTargetException e) {\r
101 log.log(Level.SEVERE, e.getMessage(), e);\r
102 }\r
103 }\r
104 }\r
105\r
106 return attribute;\r
107 }\r
108\r
109 /**\r
110 * @param byteArray\r
111 * @param byteCount\r
112 * @param lastAttribute\r
113 * @return\r
114 */\r
115 private static Attribute parseAttribute(InputStream in, Attribute lastAttribute)\r
116 throws IOException, EndOfAttributesException {\r
117\r
118 int valueTag;\r
119 while ((valueTag = in.read()) < IppValueTag.UNSUPPORTED_VALUE.getValue()) {\r
120 if (valueTag == IppDelimiterTag.END_ATTRIBUTES.getValue()) {\r
121 throw END_OF_ATTRIBUTES_EXCEPTION;\r
122 }\r
123 }\r
124\r
125 int nameLength = parseInt2(in);\r
126 // parse the Attribute-Name\r
127 String name;\r
128 if (nameLength == 0) {\r
129 name = lastAttribute.getName();\r
130 } else {\r
131 name = parseString(in, nameLength);\r
132 }\r
133 \r
134\r
135 Object[] values = parseValues(valueTag, in);\r
136\r
137 return getAttribute(name, values);\r
138 }\r
139 \r
140 private static String parseString(InputStream in, int nameLength) throws IOException{\r
141 return parseString(in, nameLength, Charset.US_ASCII.getValue());\r
142 }\r
143 \r
144 private static String parseNameAndTextString(InputStream in, int nameLength) throws IOException{\r
145 return parseString(in, nameLength, AttributeWriter.DEFAULT_CHARSET.getValue());\r
146 }\r
147\r
148 /**\r
149 * @param in\r
150 * @param nameLength\r
151 */\r
152 private static String parseString(InputStream in, int nameLength, String charsetName) throws IOException {\r
153 byte[] bytes = new byte[nameLength];\r
154 in.read(bytes);\r
155 return new String(bytes, charsetName);\r
156\r
157 }\r
158 \r
159 \r
160 \r
161 \r
162 /**\r
163 * @param byteArray\r
164 * @param valueOffset\r
165 * @return\r
166 */\r
167 private static Date parseDate(InputStream in) throws IOException {\r
168 DecimalFormat twoDigits = new DecimalFormat("00");\r
169 DecimalFormat threeDigits = new DecimalFormat("000");\r
170 DecimalFormat fourDigits = new DecimalFormat("0000");\r
171 //year is encoded in network-byte order\r
172 int year = parseInt2(in);\r
173 int month = in.read();\r
174 int day = in.read();\r
175 int hour = in.read();\r
176 int minute = in.read();\r
177 int second = in.read();\r
178 int deci = in.read();\r
179 int mili = deci * 100;\r
180 char direction = (char) in.read();\r
181 int hoursFromUtc = in.read();\r
182 int minutesFromUtc = in.read();\r
183\r
184 String yearString = fourDigits.format(year);\r
185 String monthString = twoDigits.format(month);\r
186 String dayString = twoDigits.format(day);\r
187 String hourString = twoDigits.format(hour);\r
188 String minuteString = twoDigits.format(minute);\r
189 String secondString = twoDigits.format(second);\r
190 String miliString = threeDigits.format(mili);\r
191 String timeZone = direction + twoDigits.format(hoursFromUtc) + twoDigits.format(minutesFromUtc);\r
192 String dateString =\r
193 yearString\r
194 + "-"\r
195 + monthString\r
196 + "-"\r
197 + dayString\r
198 + " "\r
199 + hourString\r
200 + ":"\r
201 + minuteString\r
202 + ":"\r
203 + secondString\r
204 + ":"\r
205 + miliString\r
206 + timeZone;\r
207 DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSSZ");\r
208 Date date = null;\r
209 try {\r
210 date = dateFormat.parse(dateString);\r
211 } catch (ParseException e) {\r
212 log.log(Level.SEVERE, e.getMessage(), e);\r
213 }\r
214 return date;\r
215 }\r
216\r
217 private static int parseInt4(InputStream in) throws IOException {\r
218\r
219 //Same parsing as in java.io.DataInput readInt()\r
220 int a = in.read();\r
221 int b = in.read();\r
222 int c = in.read();\r
223 int d = in.read();\r
224 int value = (((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff));\r
225 return value;\r
226 }\r
227\r
228 /**\r
229 * @param bytes\r
230 * @param offset\r
231 * @return\r
232 */\r
233 private static int parseInt4(byte[] bytes, int offset) {\r
234\r
235 //Same parsing as in java.io.DataInput readInt()\r
236 byte a = bytes[offset++];\r
237 byte b = bytes[offset++];\r
238 byte c = bytes[offset++];\r
239 byte d = bytes[offset++];\r
240 int value = (((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff));\r
241 return value;\r
242 }\r
243\r
244 private static int parseInt2(InputStream in) throws IOException {\r
245\r
246 //Same parsing as in java.io.DataInput readInt()\r
247 int a = in.read();\r
248 int b = in.read();\r
249 int value = ((a & 0xff) << 8) | ((b & 0xff));\r
250 return value;\r
251 }\r
252\r
253 /**\r
254 * @param bytes\r
255 * @return map of attributes (key -> category, value -> Set with attributes)\r
256 * \r
257 *\r
258 */\r
259 public static Map parseRequest(InputStream response) throws IOException {\r
260 Map attributes = new HashMap();\r
261 long start = System.currentTimeMillis();\r
262 Attribute lastAttribute = null;\r
263 boolean finished = false;\r
264 response.read();\r
265\r
266 while (!finished) {\r
267 Attribute attribute = null;\r
268 try {\r
269 attribute = parseAttribute(response, lastAttribute);\r
270 if (attribute != null) {\r
271 lastAttribute = attribute;\r
272 attributes = put(attributes, attribute);\r
273 if (log.isLoggable(Level.FINEST)) {\r
274 log.finest("parsed attribute(" + attribute.getName() + "): " + attribute.toString());\r
275 }\r
276 } else {\r
277 if (log.isLoggable(Level.FINEST)) {\r
278\r
279 log.finest("Attribute was null");\r
280 }\r
281 }\r
282 } catch (EndOfAttributesException e) {\r
283\r
284 finished = true;\r
285 if (log.isLoggable(Level.INFO)) {\r
286 log.info("--- Attribute parsing finished ---");\r
287 }\r
288 }\r
289 }\r
290 long end = System.currentTimeMillis();\r
291 if (log.isLoggable(Level.INFO)) {\r
292 log.info("Parsing took " + (end - start) + "ms.");\r
293 }\r
294 return attributes;\r
295 }\r
296\r
297 \r
298 /**\r
299 * @param byteArray\r
300 * @param valueOffset\r
301 * @param valueLength\r
302 * @return\r
303 */\r
304 private static URI parseUri(InputStream in, int valueLength) throws IOException {\r
305 String uriString = parseString(in, valueLength);\r
306 URI uri = null;\r
307 try {\r
308 uri = new URI(uriString);\r
309 } catch (URISyntaxException e) {\r
310 throw new RuntimeException(e);\r
311 }\r
312 return uri;\r
313 }\r
314\r
315 \r
316 /**\r
317 * @param valueTag\r
318 * @param byteArray\r
319 * @param valueOffset\r
320 * @param valueLength\r
321 * @return\r
322 */\r
323 private static Object[] parseValues(int valueTag, InputStream in) throws IOException {\r
324 int valueLength = parseInt2(in);\r
325 Object[] values = null;\r
326 if (valueTag == IppValueTag.INTEGER.getValue() || valueTag == IppValueTag.ENUM.getValue()) {\r
327 Integer number = new Integer(parseInt4(in));\r
328 values = new Object[] { number };\r
329 } else if (\r
330 valueTag == IppValueTag.STRING.getValue()\r
331 || valueTag == IppValueTag.TEXT.getValue()\r
332 || valueTag == IppValueTag.NAME.getValue()){\r
333 String word = parseNameAndTextString(in, valueLength);\r
334 values = new Object[] { word, Locale.getDefault()}; \r
335 } else if (\r
336 valueTag == IppValueTag.CHARSET.getValue()\r
337 || valueTag == IppValueTag.LANGUAGE.getValue()\r
338 || valueTag == IppValueTag.MIMETYPE.getValue()) {\r
339 String word = parseString(in, valueLength);\r
340 values = new Object[] { word, Locale.getDefault()};\r
341 } else if (valueTag == IppValueTag.URI.getValue()) {\r
342 URI uri = parseUri(in, valueLength);\r
343 values = new Object[] { uri };\r
344 } else if (valueTag == IppValueTag.KEYWORD.getValue()) {\r
345 String word = parseString(in, valueLength);\r
346 values = new Object[] { word, Locale.getDefault()};\r
347 } else if (valueTag == IppValueTag.BOOLEAN.getValue()) {\r
348 Integer bool = new Integer(in.read());\r
349 values = new Object[] { bool };\r
350 } else if (valueTag == IppValueTag.RANGE.getValue()) {\r
351 Integer lowerBound = new Integer(parseInt4(in));\r
352 Integer upperBound = new Integer(parseInt4(in));\r
353 values = new Object[] { lowerBound, upperBound };\r
354 } else if (valueTag == IppValueTag.DATE.getValue()) {\r
355\r
356 Date date = parseDate(in);\r
357 values = new Object[] { date };\r
358 } else if (valueTag == IppValueTag.NOVALUE.getValue()) {\r
359 values = new Object[] {\r
360 };\r
361 } else {\r
362 throw new IllegalArgumentException("\"" + Integer.toHexString(valueTag) + "\" is not a valid value-tag");\r
363 }\r
364 return values;\r
365 }\r
366\r
367\r
368 /**\r
369 * @param attributes\r
370 * @param attribute\r
371 */\r
372 private static Map put(Map attributes, Attribute attribute) {\r
373 Set values = (Set) attributes.get(attribute.getCategory());\r
374 if (values == null) {\r
375 values = new HashSet();\r
376 attributes.put(attribute.getCategory(), values);\r
377 }\r
378 values.add(attribute);\r
379 return attributes;\r
380 }\r
381\r
382 /**\r
383 * @param values\r
384 * @return\r
385 */\r
386 private static Class[] toClassArray(Object[] values) {\r
387 Class[] classes = new Class[values.length];\r
388 for (int i = 0; i < values.length; i++) {\r
389 Class clazz = values[i].getClass();\r
390 if (clazz.equals(Integer.class)) {\r
391 clazz = int.class;\r
392 }\r
393 classes[i] = clazz;\r
394 }\r
395 return classes;\r
396 }\r
397\r
398}\r