summaryrefslogtreecommitdiff
path: root/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java
diff options
context:
space:
mode:
Diffstat (limited to 'projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java')
-rw-r--r--projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java534
1 files changed, 534 insertions, 0 deletions
diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java
new file mode 100644
index 0000000..2368672
--- /dev/null
+++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java
@@ -0,0 +1,534 @@
+/*
+Wotonomy: OpenStep design patterns for pure Java applications.
+Copyright (C) 2000 Michael Powers
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, see http://www.gnu.org
+*/
+
+package net.wotonomy.web.xml;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import net.wotonomy.foundation.internal.Introspector;
+import net.wotonomy.foundation.internal.ValueConverter;
+import net.wotonomy.foundation.internal.WotonomyException;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+* Used by XMLDecoder to implement the necessary interfaces
+* required by the jclark xp parser.
+* This class is not thread safe.
+*/
+class XMLRPCDecoderHelper extends DefaultHandler
+{
+ protected final Object nilMarker = new Object();
+ protected Stack valueStack;
+ protected String methodName;
+ protected int faultCode;
+ protected String faultString;
+ protected List parameters;
+ protected StringBuffer cdataBuffer;
+
+
+
+ public XMLRPCDecoderHelper()
+ {
+ valueStack = new Stack();
+ parameters = new LinkedList();
+ cdataBuffer = new StringBuffer();
+ reset();
+ }
+
+ public void reset()
+ {
+ valueStack.clear();
+ parameters.clear();
+ cdataBuffer.setLength( 0 );
+ methodName = null;
+ faultCode = 0;
+ faultString = null;
+ }
+
+ public boolean isRequest()
+ {
+ return ( methodName != null );
+ }
+
+ public boolean isResponse()
+ {
+ return ( methodName == null );
+ }
+
+ public boolean isFault()
+ {
+ // faults are responses
+ return ( isResponse() ) && ( faultString != null );
+ }
+
+ public int getFaultCode()
+ {
+ return faultCode;
+ }
+
+ public String getFaultString()
+ {
+ return faultString;
+ }
+
+ public String getMethodName()
+ {
+ return methodName;
+ }
+
+ public Object[] getParameters()
+ {
+ return parameters.toArray();
+ }
+
+ public void endDocument() throws SAXException {
+ // TODO Auto-generated method stub
+ super.endDocument();
+ }
+
+ public void startDocument() throws SAXException {
+ // TODO Auto-generated method stub
+ super.startDocument();
+ reset();
+ }
+
+ public Object getResult()
+ {
+ if ( valueStack.empty() ) return null;
+ Object result = valueStack.peek();
+ if ( result == nilMarker ) result = null;
+ return result;
+ }
+
+
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ super.startElement(uri, localName, qName, attributes);
+ if ( XMLRPCEncoder.VALUE.equals( localName ) )
+ {
+ ValueMarker marker = new ValueMarker();
+ String classname = attributes.getValue( uri, XMLRPCEncoder.CLASS );
+ if ( classname != null )
+ {
+ try
+ {
+ Class c = Class.forName( classname );
+ if ( c != null )
+ {
+ marker.setMarkerClass( c );
+ }
+ }
+ catch ( Exception exc )
+ {
+ System.out.println( "XMLRPCDecoderHelper.startElement: " +
+ "Can't find class: " + classname );
+ }
+ }
+ valueStack.push( marker );
+ }
+ }
+
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ super.characters(ch, start, length);
+ char[] someChars = new char[((start+length)<=ch.length) ? length : ch.length-start];
+ for (int i = 0; i < someChars.length; i++ ) {
+ someChars[i] = ch[start+i];
+ }
+ cdataBuffer.append(someChars);
+ }
+
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ super.endElement(uri, localName, qName);
+
+ // if any cdata is buffered or if string value
+ if ( ( XMLRPCEncoder.STRING.equals( localName ) )
+ || ( cdataBuffer.length() > 0 ) )
+ {
+ // push value on the stack
+ valueStack.push( cdataBuffer.toString() );
+ cdataBuffer.setLength( 0 );
+ }
+
+ if ( XMLRPCEncoder.VALUE.equals( localName ) )
+ {
+ Object value = valueStack.pop();
+ try
+ {
+// ValueMarker marker = (ValueMarker) valueStack.pop();
+ ValueMarker marker = null;
+ Object markerValue = valueStack.pop();
+ if ( markerValue instanceof ValueMarker )
+ {
+ marker = (ValueMarker) markerValue;
+ }
+ else
+ {
+ throw new WotonomyException( "Expected value marker, found"
+ + markerValue.getClass() + " : " + markerValue );
+ }
+
+//System.out.println( "getMarkerClass: " + marker.getMarkerClass() + " : " + value );
+//System.out.println( valueStack );
+ if ( marker.getMarkerClass() != null )
+ {
+ // apply introspection
+ if ( value instanceof Map )
+ {
+ Map map = (Map)value;
+ Map.Entry entry;
+ value = marker.getMarkerClass().newInstance();
+ Iterator it = map.entrySet().iterator();
+ Object entryValue;
+ while( it.hasNext() )
+ {
+ entry = (Map.Entry) it.next();
+ entryValue = entry.getValue();
+ if ( entryValue == nilMarker ) entryValue = null;
+ Introspector.set(
+ value, entry.getKey().toString(), entryValue );
+ }
+ }
+ if ( ! ( value.getClass().equals( marker.getMarkerClass() ) ) )
+ {
+ Object converted =
+ ValueConverter.convertObjectToClass(
+ value, marker.getMarkerClass() );
+ if ( converted != null )
+ {
+ value = converted;
+ }
+ }
+ }
+ }
+ catch ( Exception exc )
+ {
+ // fall back on unconverted value
+ }
+
+ valueStack.push( value );
+// System.out.println( "convertedValue: " + value + "("+ value.getClass() +")" );
+ }
+ else
+ if ( XMLRPCEncoder.MEMBER.equals( localName ) ) // Map.Entry
+ {
+ // leave key and value to be handled by struct
+ }
+ else
+ if ( XMLRPCEncoder.STRUCT.equals( localName ) ) // write Entries to map or object
+ {
+ // write values to array (reverse the order)
+ Object value;
+ Map map = new HashMap();
+ while ( ( ! valueStack.empty() )
+ && ( ! ( valueStack.peek() instanceof ValueMarker ) ) )
+ {
+ value = valueStack.pop();
+ map.put( valueStack.pop(), value );
+ }
+ // push the list on the stack
+ valueStack.push( map );
+ }
+ else
+ if ( XMLRPCEncoder.ARRAY.equals( localName ) )
+ {
+//System.out.println( "ended ARRAY: " + valueStack.size() );
+ // write values to array (reverse the order)
+ Object value;
+ LinkedList list = new LinkedList();
+ while ( ( ! valueStack.empty() )
+ && ( ! ( valueStack.peek() instanceof ValueMarker ) ) )
+ {
+ value = valueStack.pop();
+ if ( value == nilMarker ) value = null;
+ list.addFirst( value );
+ }
+ // push the list on the stack
+ valueStack.push( list );
+ }
+ else
+ if ( XMLRPCEncoder.INT.equals( localName ) )
+ {
+ Object value = valueStack.pop();
+ try
+ {
+ valueStack.push(
+ new Integer( value.toString() ) );
+ }
+ catch ( NumberFormatException exc )
+ {
+ throw new WotonomyException(
+ "Invalid double format: " + value.toString() );
+ }
+ }
+ else
+ if ( XMLRPCEncoder.I4.equals( localName ) )
+ {
+ Object value = valueStack.pop();
+ try
+ {
+ valueStack.push(
+ new Integer( value.toString() ) );
+ }
+ catch ( NumberFormatException exc )
+ {
+ throw new WotonomyException(
+ "Invalid double format: " + value.toString() );
+ }
+ }
+ else
+ if ( XMLRPCEncoder.NIL.equals( localName ) )
+ {
+ valueStack.push( nilMarker );
+ }
+ else
+ if ( XMLRPCEncoder.DOUBLE.equals( localName ) )
+ {
+ Object value = valueStack.pop();
+ try
+ {
+ valueStack.push(
+ new Double( value.toString() ) );
+ }
+ catch ( NumberFormatException exc )
+ {
+ throw new WotonomyException(
+ "Invalid double format: " + value.toString() );
+ }
+ }
+ else
+ if ( XMLRPCEncoder.DATE.equals( localName ) )
+ {
+ Object value = valueStack.pop();
+ try
+ {
+ valueStack.push(
+ XMLRPCEncoder.DATEFORMAT8601.parseObject(
+ value.toString() ) );
+ }
+ catch ( Exception exc )
+ {
+ throw new WotonomyException(
+ "Invalid date format: " + value );
+ }
+ }
+ else
+ if ( XMLRPCEncoder.BOOLEAN.equals( localName ) )
+ {
+ Object value = valueStack.pop();
+ if ( XMLRPCEncoder.TRUE.equals( value ) )
+ {
+ valueStack.push( Boolean.TRUE );
+ }
+ else
+ if ( XMLRPCEncoder.FALSE.equals( value ) )
+ {
+ valueStack.push( Boolean.FALSE );
+ }
+ else
+ {
+ throw new WotonomyException(
+ "Invalid boolean format: " + value );
+ }
+ }
+ else
+ if ( XMLRPCEncoder.BASE64.equals( localName ) )
+ {
+ throw new WotonomyException( "Not implemented yet." );
+ }
+ else
+ if ( XMLRPCEncoder.FAULT.equals( localName ) )
+ {
+ Map faultMap = (Map) valueStack.pop();
+ try
+ {
+ faultCode = ((Integer)
+ faultMap.get( XMLRPCEncoder.FAULTCODE )).intValue();
+ faultString = (String) faultMap.get( XMLRPCEncoder.FAULTSTRING );
+ }
+ catch ( Exception exc )
+ {
+ throw new WotonomyException(
+ "Invalid fault format: " + faultMap );
+ }
+ }
+ else
+ if ( XMLRPCEncoder.METHODNAME.equals( localName ) )
+ {
+ methodName = (String) valueStack.pop();
+ }
+ else
+ if ( XMLRPCEncoder.PARAM.equals( localName ) )
+ {
+ //NOTE: this leaves the parameter on the stack
+ parameters.add( getResult() );
+ }
+ }
+
+
+
+ public void endPrefixMapping(String prefix) throws SAXException {
+ // TODO Auto-generated method stub
+ super.endPrefixMapping(prefix);
+ }
+
+ public void error(SAXParseException e) throws SAXException {
+ // TODO Auto-generated method stub
+ super.error(e);
+ }
+
+ public void fatalError(SAXParseException e) throws SAXException {
+ // TODO Auto-generated method stub
+ super.fatalError(e);
+ }
+
+ public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
+ // TODO Auto-generated method stub
+ super.ignorableWhitespace(ch, start, length);
+ }
+
+ public void notationDecl(String name, String publicId, String systemId) throws SAXException {
+ // TODO Auto-generated method stub
+ super.notationDecl(name, publicId, systemId);
+ }
+
+ public void processingInstruction(String target, String data) throws SAXException {
+ // TODO Auto-generated method stub
+ super.processingInstruction(target, data);
+ }
+
+ public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
+ // NOTE: Sun accepted an incompatible api difference. The (false) should be tossed by hotspot
+ try {
+ if (false) throw new IOException("Fake exception to make it compile in both 1.4 and 1.5");
+ return super.resolveEntity(publicId, systemId);
+ } catch (IOException e) {
+ throw new SAXException(e.getClass().getName() + " thrown while resolving entity.",e);
+ }
+ }
+
+ public void setDocumentLocator(Locator locator) {
+ // TODO Auto-generated method stub
+ super.setDocumentLocator(locator);
+ }
+
+ public void skippedEntity(String name) throws SAXException {
+ // TODO Auto-generated method stub
+ super.skippedEntity(name);
+ }
+
+
+
+ public void startPrefixMapping(String prefix, String uri) throws SAXException {
+ // TODO Auto-generated method stub
+ super.startPrefixMapping(prefix, uri);
+ }
+
+ public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException {
+ // TODO Auto-generated method stub
+ super.unparsedEntityDecl(name, publicId, systemId, notationName);
+ }
+
+ public void warning(SAXParseException e) throws SAXException {
+ // TODO Auto-generated method stub
+ super.warning(e);
+ }
+
+
+ // marker class
+
+ private class ValueMarker
+ {
+ private Class theClass;
+
+ public ValueMarker()
+ {
+ theClass = null;
+ }
+
+ public void setMarkerClass( Class aClass )
+ {
+ theClass = aClass;
+ }
+
+ public Class getMarkerClass()
+ {
+ return theClass;
+ }
+
+ public String toString()
+ {
+ return "[ValueMarker: " + theClass + "]";
+ }
+ }
+
+}
+
+/*
+ * $Log$
+ * Revision 1.1 2006/02/19 01:44:03 cgruber
+ * Add xmlrpc files
+ * Remove jclark and replace with dom4j and javax.xml.sax stuff
+ * Re-work dependencies and imports so it all compiles.
+ *
+ * Revision 1.1 2006/02/16 13:22:22 cgruber
+ * Check in all sources in eclipse-friendly maven-enabled packages.
+ *
+ * Revision 1.7 2003/08/06 23:07:53 chochos
+ * general code cleanup (mostly, removing unused imports)
+ *
+ * Revision 1.6 2001/03/03 15:16:35 mpowers
+ * Fixed bug in decoding empty strings: string handler did nothing and
+ * empty cdatas were ignored, so no value was placed on the stack.
+ *
+ * Revision 1.5 2001/02/17 16:52:06 mpowers
+ * Changes in imports to support building with jdk1.1 collections.
+ *
+ * Revision 1.4 2001/02/09 15:51:39 mpowers
+ * Fixed a pernicious bug: I was using the character event entirely
+ * incorrectly, but the problem only exhibited itself with large data
+ * and even then only randomly. Now using a string buffer.
+ *
+ * Revision 1.3 2001/02/07 19:24:28 mpowers
+ * Moved XML classes to separate package.
+ *
+ * Revision 1.2 2001/02/06 14:34:23 mpowers
+ * Forgot to rename the package declarations.
+ *
+ * Revision 1.1 2001/02/06 14:31:19 mpowers
+ * Moving XML utilities from util to xml package.
+ *
+ * Revision 1.1.1.1 2000/12/21 15:52:39 mpowers
+ * Contributing wotonomy.
+ *
+ * Revision 1.2 2000/12/20 16:25:48 michael
+ * Added log to all files.
+ *
+ *
+ */
+