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 --- .../java/net/wotonomy/web/xml/XMLRPCServlet.java | 283 +++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCServlet.java (limited to 'projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCServlet.java') diff --git a/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCServlet.java b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCServlet.java new file mode 100644 index 0000000..a9981a4 --- /dev/null +++ b/projects/net.wotonomy.web/src/main/java/net/wotonomy/web/xml/XMLRPCServlet.java @@ -0,0 +1,283 @@ +/* +Wotonomy: OpenStep design patterns for pure Java applications. +Copyright (C) 2001 Intersect Software Corporation + +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.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Hashtable; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import net.wotonomy.foundation.NSSelector; +import net.wotonomy.foundation.internal.WotonomyException; + +/** +* A servlet that can make any java object into an XML-RPC server. +* Simply pass in the object to the constructor and XML-RPC requests +* to this servlet will call the appropriate methods and convert +* the results to an XML-RPC response.

+* +* Depending on your servlet container, it may be necessary to +* create a simple subclass that creates your handler object +* in its constructor and then calls setHandler().

+* +* Responses are in the specification's standard response format.

+* +* Faults are returned if any exception is thrown in the method, +* or if the specified method is not found on the object. +* The fault string is the toString value of the exception, +* and the fault code is the hasCode value of the exception.

+* +* Remember that this servlet only responds to POSTs, +* per the XML-RPC spec. +*/ +public class XMLRPCServlet extends HttpServlet +{ + protected Object handler; + protected boolean synchronizing; + private Hashtable selectorCache = new Hashtable(); // thread safe + private boolean copyStream = false; + + /** + * Default constructor initializes internal state. + */ + public XMLRPCServlet() + { + handler = null; + synchronizing = false; + } + + /** + * Constructor takes any java object and allows its methods + * to be invoked via XMLRPC requests to this servlet. + * Simply calls setHandler(). + */ + public XMLRPCServlet( Object aHandler ) + { + this(); + setHandler( aHandler ); + } + + /** + * Gets the object whose methods will be invoked to + * handle incoming requests. + */ + public Object getHandler() + { + return handler; + } + + /** + * Sets the object whose methods will be invoked to + * handle incoming requests. + */ + public void setHandler( Object aHandler ) + { + handler = aHandler; + } + + /** + * Gets whether the servlet should synchonize on the + * object before invoking methods on it. + * Defaults to false. + */ + public boolean isSynchronizing() + { + return synchronizing; + } + + /** + * Sets whether the servlet should synchonize on the + * object before invoking methods on it. + * Defaults to false. + */ + public void setSynchronizing( boolean willSynchronize ) + { + synchronizing = willSynchronize; + } + + /** + * Overridden to service the request. + */ + protected void doPost( + HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException + { + if ( getHandler() != null ) + { + InputStream input = req.getInputStream(); + byte[] copyOfRequest = null; + + if ( copyStream ) + { + ByteArrayOutputStream byteArray = + new ByteArrayOutputStream(); + int b; + while ( ( b = input.read() ) != -1 ) + { + byteArray.write( b ); + } + copyOfRequest = byteArray.toByteArray(); + input = new ByteArrayInputStream( copyOfRequest ); + } + + try + { + new XMLRPCDecoder().decode( input, + new Receiver( this, resp ) ); + } + catch ( WotonomyException exc ) + { + if ( copyOfRequest != null ) + { + System.out.println( new String( copyOfRequest ) ); + exc.printStackTrace(); + } + // catches io exceptions thrown in handleRequest. + Throwable t = exc.getWrappedThrowable(); + if ( t instanceof IOException ) + { + throw (IOException)t; + } + throw exc; + } + } + } + + /** + * Called by doPost after parsing an incoming request, + * and is responsible for invoking the specified method + * with the specified parameters on the handler object. + * (This implementation calls getOutputStream() on the response.) + * Override to customize the handling of the request. + */ + protected void handleRequest( String aMethodName, + Object[] aParameterArray, HttpServletResponse aResponse ) + { + OutputStream output = null; + + try + { + output = aResponse.getOutputStream(); + aResponse.setStatus( HttpServletResponse.SC_OK ); // always 200 + aResponse.setContentType( "text/xml" ); + } + catch ( IOException exc ) + { + // caught in doPost + throw new WotonomyException( exc ); + } + + // get the array of types + XMLRPCEncoder encoder = new XMLRPCEncoder(); + Class[] types = new Class[ aParameterArray.length ]; + for ( int i = 0; i < aParameterArray.length; i++ ) + { + types[i] = aParameterArray[i].getClass(); + } + + //TODO: selectors should be cached if possible + + Object handler = getHandler(); + if ( isSynchronizing() ) + { + synchronized ( handler ) + { + execute( encoder, handler, output, + new NSSelector( aMethodName, types ), aParameterArray ); + } + } + else + { + execute( encoder, handler, output, + new NSSelector( aMethodName, types ), aParameterArray ); + } + } + + private void execute( XMLRPCEncoder anEncoder, Object aHandler, + OutputStream output, NSSelector aSelector, Object[] aParameterArray ) + { + try + { + Object result = + aSelector.invoke( aHandler, aParameterArray ); + anEncoder.encodeResponse( result, output ); + } + catch ( Exception exc ) + { + anEncoder.encodeFault( + exc.hashCode(), exc.toString(), output ); + } + } + + private class Receiver implements XMLRPCReceiver + { + XMLRPCServlet controller; + HttpServletResponse response; + + public Receiver( + XMLRPCServlet aController, + HttpServletResponse aResponse ) + { + controller = aController; + response = aResponse; + } + + public void request( + String aMethodName, Object[] aParameterArray ) + { + controller.handleRequest( + aMethodName, aParameterArray, response ); + } + + public void response( + Object aResult ) + { + // does nothing + } + + public void fault( + int aFaultCode, String aFaultString) + { + // does nothing + } + } +} + +/* + * $Log$ + * Revision 1.1 2006/02/19 01:44:02 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.1 2001/02/07 19:24:28 mpowers + * Moved XML classes to separate package. + * + */ + -- cgit v1.2.3