From aedc34d55462a75e329bbf342251ff6504cd117e Mon Sep 17 00:00:00 2001 From: Benjamin Culkin Date: Sun, 19 May 2024 17:56:33 -0400 Subject: Initial import from SVN --- .../net/wotonomy/web/xml/XMLRPCDecoderHelper.java | 534 +++++++++++++++++++++ 1 file changed, 534 insertions(+) create mode 100644 projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java (limited to 'projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCDecoderHelper.java') 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. + * + * + */ + -- cgit v1.2.3