1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.wotonomy.web.xml;
20
21 import java.io.IOException;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.LinkedList;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Stack;
28
29 import net.wotonomy.foundation.internal.Introspector;
30 import net.wotonomy.foundation.internal.ValueConverter;
31 import net.wotonomy.foundation.internal.WotonomyException;
32
33 import org.xml.sax.Attributes;
34 import org.xml.sax.InputSource;
35 import org.xml.sax.Locator;
36 import org.xml.sax.SAXException;
37 import org.xml.sax.SAXParseException;
38 import org.xml.sax.helpers.DefaultHandler;
39
40 /***
41 * Used by XMLDecoder to implement the necessary interfaces
42 * required by the jclark xp parser.
43 * This class is not thread safe.
44 */
45 class XMLRPCDecoderHelper extends DefaultHandler
46 {
47 protected final Object nilMarker = new Object();
48 protected Stack valueStack;
49 protected String methodName;
50 protected int faultCode;
51 protected String faultString;
52 protected List parameters;
53 protected StringBuffer cdataBuffer;
54
55
56
57 public XMLRPCDecoderHelper()
58 {
59 valueStack = new Stack();
60 parameters = new LinkedList();
61 cdataBuffer = new StringBuffer();
62 reset();
63 }
64
65 public void reset()
66 {
67 valueStack.clear();
68 parameters.clear();
69 cdataBuffer.setLength( 0 );
70 methodName = null;
71 faultCode = 0;
72 faultString = null;
73 }
74
75 public boolean isRequest()
76 {
77 return ( methodName != null );
78 }
79
80 public boolean isResponse()
81 {
82 return ( methodName == null );
83 }
84
85 public boolean isFault()
86 {
87
88 return ( isResponse() ) && ( faultString != null );
89 }
90
91 public int getFaultCode()
92 {
93 return faultCode;
94 }
95
96 public String getFaultString()
97 {
98 return faultString;
99 }
100
101 public String getMethodName()
102 {
103 return methodName;
104 }
105
106 public Object[] getParameters()
107 {
108 return parameters.toArray();
109 }
110
111 public void endDocument() throws SAXException {
112
113 super.endDocument();
114 }
115
116 public void startDocument() throws SAXException {
117
118 super.startDocument();
119 reset();
120 }
121
122 public Object getResult()
123 {
124 if ( valueStack.empty() ) return null;
125 Object result = valueStack.peek();
126 if ( result == nilMarker ) result = null;
127 return result;
128 }
129
130
131 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
132 super.startElement(uri, localName, qName, attributes);
133 if ( XMLRPCEncoder.VALUE.equals( localName ) )
134 {
135 ValueMarker marker = new ValueMarker();
136 String classname = attributes.getValue( uri, XMLRPCEncoder.CLASS );
137 if ( classname != null )
138 {
139 try
140 {
141 Class c = Class.forName( classname );
142 if ( c != null )
143 {
144 marker.setMarkerClass( c );
145 }
146 }
147 catch ( Exception exc )
148 {
149 System.out.println( "XMLRPCDecoderHelper.startElement: " +
150 "Can't find class: " + classname );
151 }
152 }
153 valueStack.push( marker );
154 }
155 }
156
157 public void characters(char[] ch, int start, int length) throws SAXException {
158 super.characters(ch, start, length);
159 char[] someChars = new char[((start+length)<=ch.length) ? length : ch.length-start];
160 for (int i = 0; i < someChars.length; i++ ) {
161 someChars[i] = ch[start+i];
162 }
163 cdataBuffer.append(someChars);
164 }
165
166 public void endElement(String uri, String localName, String qName) throws SAXException {
167 super.endElement(uri, localName, qName);
168
169
170 if ( ( XMLRPCEncoder.STRING.equals( localName ) )
171 || ( cdataBuffer.length() > 0 ) )
172 {
173
174 valueStack.push( cdataBuffer.toString() );
175 cdataBuffer.setLength( 0 );
176 }
177
178 if ( XMLRPCEncoder.VALUE.equals( localName ) )
179 {
180 Object value = valueStack.pop();
181 try
182 {
183
184 ValueMarker marker = null;
185 Object markerValue = valueStack.pop();
186 if ( markerValue instanceof ValueMarker )
187 {
188 marker = (ValueMarker) markerValue;
189 }
190 else
191 {
192 throw new WotonomyException( "Expected value marker, found"
193 + markerValue.getClass() + " : " + markerValue );
194 }
195
196
197
198 if ( marker.getMarkerClass() != null )
199 {
200
201 if ( value instanceof Map )
202 {
203 Map map = (Map)value;
204 Map.Entry entry;
205 value = marker.getMarkerClass().newInstance();
206 Iterator it = map.entrySet().iterator();
207 Object entryValue;
208 while( it.hasNext() )
209 {
210 entry = (Map.Entry) it.next();
211 entryValue = entry.getValue();
212 if ( entryValue == nilMarker ) entryValue = null;
213 Introspector.set(
214 value, entry.getKey().toString(), entryValue );
215 }
216 }
217 if ( ! ( value.getClass().equals( marker.getMarkerClass() ) ) )
218 {
219 Object converted =
220 ValueConverter.convertObjectToClass(
221 value, marker.getMarkerClass() );
222 if ( converted != null )
223 {
224 value = converted;
225 }
226 }
227 }
228 }
229 catch ( Exception exc )
230 {
231
232 }
233
234 valueStack.push( value );
235
236 }
237 else
238 if ( XMLRPCEncoder.MEMBER.equals( localName ) )
239 {
240
241 }
242 else
243 if ( XMLRPCEncoder.STRUCT.equals( localName ) )
244 {
245
246 Object value;
247 Map map = new HashMap();
248 while ( ( ! valueStack.empty() )
249 && ( ! ( valueStack.peek() instanceof ValueMarker ) ) )
250 {
251 value = valueStack.pop();
252 map.put( valueStack.pop(), value );
253 }
254
255 valueStack.push( map );
256 }
257 else
258 if ( XMLRPCEncoder.ARRAY.equals( localName ) )
259 {
260
261
262 Object value;
263 LinkedList list = new LinkedList();
264 while ( ( ! valueStack.empty() )
265 && ( ! ( valueStack.peek() instanceof ValueMarker ) ) )
266 {
267 value = valueStack.pop();
268 if ( value == nilMarker ) value = null;
269 list.addFirst( value );
270 }
271
272 valueStack.push( list );
273 }
274 else
275 if ( XMLRPCEncoder.INT.equals( localName ) )
276 {
277 Object value = valueStack.pop();
278 try
279 {
280 valueStack.push(
281 new Integer( value.toString() ) );
282 }
283 catch ( NumberFormatException exc )
284 {
285 throw new WotonomyException(
286 "Invalid double format: " + value.toString() );
287 }
288 }
289 else
290 if ( XMLRPCEncoder.I4.equals( localName ) )
291 {
292 Object value = valueStack.pop();
293 try
294 {
295 valueStack.push(
296 new Integer( value.toString() ) );
297 }
298 catch ( NumberFormatException exc )
299 {
300 throw new WotonomyException(
301 "Invalid double format: " + value.toString() );
302 }
303 }
304 else
305 if ( XMLRPCEncoder.NIL.equals( localName ) )
306 {
307 valueStack.push( nilMarker );
308 }
309 else
310 if ( XMLRPCEncoder.DOUBLE.equals( localName ) )
311 {
312 Object value = valueStack.pop();
313 try
314 {
315 valueStack.push(
316 new Double( value.toString() ) );
317 }
318 catch ( NumberFormatException exc )
319 {
320 throw new WotonomyException(
321 "Invalid double format: " + value.toString() );
322 }
323 }
324 else
325 if ( XMLRPCEncoder.DATE.equals( localName ) )
326 {
327 Object value = valueStack.pop();
328 try
329 {
330 valueStack.push(
331 XMLRPCEncoder.DATEFORMAT8601.parseObject(
332 value.toString() ) );
333 }
334 catch ( Exception exc )
335 {
336 throw new WotonomyException(
337 "Invalid date format: " + value );
338 }
339 }
340 else
341 if ( XMLRPCEncoder.BOOLEAN.equals( localName ) )
342 {
343 Object value = valueStack.pop();
344 if ( XMLRPCEncoder.TRUE.equals( value ) )
345 {
346 valueStack.push( Boolean.TRUE );
347 }
348 else
349 if ( XMLRPCEncoder.FALSE.equals( value ) )
350 {
351 valueStack.push( Boolean.FALSE );
352 }
353 else
354 {
355 throw new WotonomyException(
356 "Invalid boolean format: " + value );
357 }
358 }
359 else
360 if ( XMLRPCEncoder.BASE64.equals( localName ) )
361 {
362 throw new WotonomyException( "Not implemented yet." );
363 }
364 else
365 if ( XMLRPCEncoder.FAULT.equals( localName ) )
366 {
367 Map faultMap = (Map) valueStack.pop();
368 try
369 {
370 faultCode = ((Integer)
371 faultMap.get( XMLRPCEncoder.FAULTCODE )).intValue();
372 faultString = (String) faultMap.get( XMLRPCEncoder.FAULTSTRING );
373 }
374 catch ( Exception exc )
375 {
376 throw new WotonomyException(
377 "Invalid fault format: " + faultMap );
378 }
379 }
380 else
381 if ( XMLRPCEncoder.METHODNAME.equals( localName ) )
382 {
383 methodName = (String) valueStack.pop();
384 }
385 else
386 if ( XMLRPCEncoder.PARAM.equals( localName ) )
387 {
388
389 parameters.add( getResult() );
390 }
391 }
392
393
394
395 public void endPrefixMapping(String prefix) throws SAXException {
396
397 super.endPrefixMapping(prefix);
398 }
399
400 public void error(SAXParseException e) throws SAXException {
401
402 super.error(e);
403 }
404
405 public void fatalError(SAXParseException e) throws SAXException {
406
407 super.fatalError(e);
408 }
409
410 public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
411
412 super.ignorableWhitespace(ch, start, length);
413 }
414
415 public void notationDecl(String name, String publicId, String systemId) throws SAXException {
416
417 super.notationDecl(name, publicId, systemId);
418 }
419
420 public void processingInstruction(String target, String data) throws SAXException {
421
422 super.processingInstruction(target, data);
423 }
424
425 public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
426
427 try {
428 if (false) throw new IOException("Fake exception to make it compile in both 1.4 and 1.5");
429 return super.resolveEntity(publicId, systemId);
430 } catch (IOException e) {
431 throw new SAXException(e.getClass().getName() + " thrown while resolving entity.",e);
432 }
433 }
434
435 public void setDocumentLocator(Locator locator) {
436
437 super.setDocumentLocator(locator);
438 }
439
440 public void skippedEntity(String name) throws SAXException {
441
442 super.skippedEntity(name);
443 }
444
445
446
447 public void startPrefixMapping(String prefix, String uri) throws SAXException {
448
449 super.startPrefixMapping(prefix, uri);
450 }
451
452 public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException {
453
454 super.unparsedEntityDecl(name, publicId, systemId, notationName);
455 }
456
457 public void warning(SAXParseException e) throws SAXException {
458
459 super.warning(e);
460 }
461
462
463
464
465 private class ValueMarker
466 {
467 private Class theClass;
468
469 public ValueMarker()
470 {
471 theClass = null;
472 }
473
474 public void setMarkerClass( Class aClass )
475 {
476 theClass = aClass;
477 }
478
479 public Class getMarkerClass()
480 {
481 return theClass;
482 }
483
484 public String toString()
485 {
486 return "[ValueMarker: " + theClass + "]";
487 }
488 }
489
490 }
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534