Index: tests/src/test/java/org/apache/xmlrpc/test/BaseTest.java
===================================================================
--- tests/src/test/java/org/apache/xmlrpc/test/BaseTest.java	(revision 380260)
+++ tests/src/test/java/org/apache/xmlrpc/test/BaseTest.java	(working copy)
@@ -197,6 +197,18 @@
 			}
 			return result;
 		}
+        /** Returns nested single-element arrays pArg levels deep.
+         * The innermost array contains the integers from 0 to pArg-1.
+         * @param pArg Requested array nesting depth.
+         * @return Nested array of integers with the values 0..pArg-1
+         */
+        public Object[] nestedArrayResult(int pArg) {
+            Object[] result = objectArrayResult(pArg);
+            for (int i = 0; i < pArg; i++) {
+                result = new Object[] {result};
+            }
+            return result;
+        }
 		/** Returns a sum over the entries in the map. Each
 		 * key is multiplied with its value.
 		 * @param pArg The map being iterated.
@@ -240,7 +252,7 @@
 			}
 			return count(pNode);
 		}
-		private int count(Node pNode) {
+        private int count(Node pNode) {
 			if (INT_TAG.equals(pNode.getLocalName())  &&  INT_URI.equals(pNode.getNamespaceURI())) {
 				StringBuffer sb = new StringBuffer();
 				for (Node child = pNode.getFirstChild();  child != null;  child = child.getNextSibling()) {
@@ -689,24 +701,59 @@
 	 * object array.
 	 * @throws Exception The test failed.
 	 */
-	public void testObjectArrayResult() throws Exception {
+	public void testNestedArrayResult() throws Exception {
 		for (int i = 0;  i < providers.length;  i++) {
-			testObjectArrayResult(providers[i]);
+			testNestedArrayResult(providers[i]);
 		}
 	}
 
-	private void testObjectArrayResult(ClientProvider pProvider) throws Exception {
-		final Object[] objects = new Object[]{new Integer(0), new Integer(1),
-											  new Integer(2), new Integer(3)};
-		final String methodName = "Remote.objectArrayResult";
+	private void testNestedArrayResult(ClientProvider pProvider) throws Exception {
+		Object[] objects = new Object[]{new Integer(0), new Integer(1),
+                                        new Integer(2), new Integer(3)};
+        final String methodName = "Remote.nestedArrayResult";
 		final Object[] params = new Object[]{new Integer(4)};
 		final XmlRpcClient client = pProvider.getClient();
 		Object result = client.execute(getConfig(pProvider), methodName, params);
-		assertTrue(Arrays.equals(objects, (Object[]) result));
+        // Arrays.deepEquals would be nice here, but it is 1.5-only
+        for (int i = 0; i < 4; i++) {
+            assertTrue(result instanceof Object[]);
+            Object[] ra = (Object[])result;
+            assertEquals(ra.length, 1);
+            result = ra[0];
+        }
+        assertTrue(Arrays.equals(objects, (Object[]) result));
 		result = client.execute(getExConfig(pProvider), methodName, params);
-		assertTrue(Arrays.equals(objects, (Object[]) result));
+        for (int i = 0; i < 4; i++) {
+            assertTrue(result instanceof Object[]);
+            Object[] ra = (Object[])result;
+            assertEquals(ra.length, 1);
+            result = ra[0];
+        }
+        assertTrue(Arrays.equals(objects, (Object[]) result));
 	}
 
+    /** Test, whether we can invoke a method, returning a
+     * nested object array.
+     * @throws Exception The test failed.
+     */
+    public void testObjectArrayResult() throws Exception {
+        for (int i = 0;  i < providers.length;  i++) {
+            testObjectArrayResult(providers[i]);
+        }
+    }
+
+    private void testObjectArrayResult(ClientProvider pProvider) throws Exception {
+        final Object[] objects = new Object[]{new Integer(0), new Integer(1),
+                                              new Integer(2), new Integer(3)};
+        final String methodName = "Remote.objectArrayResult";
+        final Object[] params = new Object[]{new Integer(4)};
+        final XmlRpcClient client = pProvider.getClient();
+        Object result = client.execute(getConfig(pProvider), methodName, params);
+        assertTrue(Arrays.equals(objects, (Object[]) result));
+        result = client.execute(getExConfig(pProvider), methodName, params);
+        assertTrue(Arrays.equals(objects, (Object[]) result));
+    }
+
 	/** Test, whether we can invoke a method, passing a map.
 	 * @throws Exception The test failed.
 	 */
Index: server/src/main/java/org/apache/xmlrpc/server/XmlRpcListableHandlerMapping.java
===================================================================
--- server/src/main/java/org/apache/xmlrpc/server/XmlRpcListableHandlerMapping.java	(revision 0)
+++ server/src/main/java/org/apache/xmlrpc/server/XmlRpcListableHandlerMapping.java	(revision 0)
@@ -0,0 +1,12 @@
+package org.apache.xmlrpc.server;
+
+import org.apache.xmlrpc.XmlRpcException;
+
+public interface XmlRpcListableHandlerMapping extends XmlRpcHandlerMapping {
+    /** Return a list of valid method names for this XmlRpcHandler.
+     *
+     * @return the available methods on this handler
+     * @throws XmlRpcException An internal error occurred.
+     */
+    public String[] listMethods() throws XmlRpcException;
+}
Index: server/src/main/java/org/apache/xmlrpc/server/AbstractReflectiveHandlerMapping.java
===================================================================
--- server/src/main/java/org/apache/xmlrpc/server/AbstractReflectiveHandlerMapping.java	(revision 0)
+++ server/src/main/java/org/apache/xmlrpc/server/AbstractReflectiveHandlerMapping.java	(revision 0)
@@ -0,0 +1,251 @@
+package org.apache.xmlrpc.server;
+
+import org.apache.xmlrpc.XmlRpcRequest;
+import org.apache.xmlrpc.XmlRpcException;
+import org.apache.xmlrpc.XmlRpcHandler;
+import org.apache.xmlrpc.XmlRpcMetaDataHandler;
+import org.apache.xmlrpc.common.XmlRpcNotAuthorizedException;
+import org.w3c.dom.Node;
+
+import java.util.*;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.InvocationTargetException;
+import java.io.Serializable;
+
+public abstract class AbstractReflectiveHandlerMapping implements XmlRpcListableHandlerMapping {
+    protected Map handlerMap = new HashMap();
+    private AuthenticationHandler authenticationHandler;
+
+    /** Returns the authentication handler, if any, or null.
+     * @return the current authentication handler
+     */
+    public AuthenticationHandler getAuthenticationHandler() {
+        return authenticationHandler;
+    }
+
+    /** Sets the authentication handler, if any, or null.
+     * @param pAuthenticationHandler the new authentication handler (may be null)
+     */
+    public void setAuthenticationHandler(
+            AuthenticationHandler pAuthenticationHandler) {
+        authenticationHandler = pAuthenticationHandler;
+    }
+
+    protected void registerPublicMethods(Map handlerMap, String key, Class type, Object instance) {
+        Method[] methods = type.getMethods();
+        for (int i = 0;  i < methods.length;  i++) {
+            final Method method = methods[i];
+            if (!Modifier.isPublic(method.getModifiers())) {
+                continue;  // Ignore methods, which aren't public
+            }
+            if (Modifier.isStatic(method.getModifiers())) {
+                continue;  // Ignore methods, which are static
+            }
+            if (method.getReturnType() == void.class) {
+                continue;  // Ignore void methods.
+            }
+            if (method.getDeclaringClass() == Object.class) {
+                continue;  // Ignore methods from Object.class
+            }
+            String name = key + "." + method.getName();
+            if (handlerMap.containsKey(name)) {
+                XmlRpcHandler h = (XmlRpcHandler)handlerMap.get(name);
+                if (h instanceof ReflectiveXmlRpcHandler) {
+                    ReflectiveXmlRpcHandler rh = (ReflectiveXmlRpcHandler)h;
+                    if (rh.getInstance() == instance) {
+                        rh.addMethod(method);
+                    }
+                }
+            } else {
+                handlerMap.put(name, newXmlRpcHandler(type, instance, method));
+            }
+        }
+    }
+
+    protected XmlRpcHandler newXmlRpcHandler(final Class pClass, final Object pValue, final Method pMethod) {
+        return new ReflectiveXmlRpcHandler(pMethod, pValue, pClass);
+    }
+
+    public XmlRpcHandler getHandler(String handlerName)
+            throws XmlRpcNoSuchHandlerException, XmlRpcException {
+        XmlRpcHandler result = (XmlRpcHandler) handlerMap.get(handlerName);
+        if (result == null) {
+            throw new XmlRpcNoSuchHandlerException("No such handler: " + handlerName);
+        }
+        return result;
+    }
+
+    /** An object implementing this interface may be used
+     * to validate user names and passwords.
+     */
+    public interface AuthenticationHandler {
+        /** Returns, whether the user is authenticated and
+         * authorized to perform the request.
+         * @param pRequest The request to check for authorization.
+         * @return whether the request is authorized
+         * @throws org.apache.xmlrpc.XmlRpcException An internal error occurred.
+         */
+        boolean isAuthorized(XmlRpcRequest pRequest)
+            throws XmlRpcException;
+    }
+
+    public String[] listMethods() throws XmlRpcException {
+        return (String[])handlerMap.keySet().toArray(new String[0]);
+    }
+
+    private class ReflectiveXmlRpcHandler implements XmlRpcMetaDataHandler {
+        private final List methods;
+        private final Object instance;
+        private final Class type;
+
+        public ReflectiveXmlRpcHandler(Method method, Object instance, Class type) {
+            this.methods = new ArrayList(5);
+            this.methods.add(method);
+            this.instance = instance;
+            this.type = type;
+        }
+
+        public Object execute(XmlRpcRequest pRequest) throws XmlRpcException {
+            AuthenticationHandler authHandler = getAuthenticationHandler();
+            if (authHandler != null  &&  !authHandler.isAuthorized(pRequest)) {
+                throw new XmlRpcNotAuthorizedException("Not authorized");
+            }
+
+            Object[] args = new Object[pRequest.getParameterCount()];
+            for (int j = 0;  j < args.length;  j++) {
+                args[j] = pRequest.getParameter(j);
+            }
+
+            Method method = null;
+            for (int i = 0; i < methods.size(); i++) {
+                method = (Method)methods.get(i);
+                List sig = getMethodSignature(method);
+                if (sig.size() - 1 != args.length)
+                    continue;
+                for (int j = 1; j < sig.size(); j++) {
+                    Class[] parameterTypes = method.getParameterTypes();
+                    if (args[j-1] == null && !parameterTypes[j-1].isPrimitive())
+                        continue; // allow nulls for anything that we can
+
+                    String sigType = (String)sig.get(j);
+                    String reqType = mapType(args[j-1].getClass());
+                    if (sigType.equals(reqType)) {
+                        if (List.class == parameterTypes[j-1]) {
+                            args[j-1] = Arrays.asList((Object[])args[j-1]);
+                        }
+                    } else {
+                        method = null;
+                        break;
+                    }
+                }
+                if (method != null) // found a compatible method
+                    break;
+            }
+            if (method == null)
+                throw new XmlRpcNoSuchHandlerException("Wrong parameters");
+
+            try {
+                return method.invoke(instance, args);
+            } catch (IllegalAccessException e) {
+                throw new XmlRpcException("Illegal access to method "
+                                          + method.getName() + " in class "
+                                          + type.getName(), e);
+            } catch (IllegalArgumentException e) {
+                throw new XmlRpcException("Illegal argument for method "
+                                          + method.getName() + " in class "
+                                          + type.getName(), e);
+            } catch (InvocationTargetException e) {
+                Throwable t = e.getTargetException();
+                throw new XmlRpcException("Failed to invoke method "
+                                          + method.getName() + " in class "
+                                          + type.getName() + ": "
+                                          + t.getMessage(), t);
+            }
+        }
+
+        public Object getInstance() {
+            return instance;
+        }
+
+        public void addMethod(Method method) {
+            try {
+                getMethodSignature(method);
+            } catch (XmlRpcException e) {
+                return; // ignore non-exportable methods
+            }
+            methods.add(method);
+        }
+
+        public List getSignatures() throws XmlRpcException {
+            List returnVal = new ArrayList(methods.size());
+            for (int i = 0; i < methods.size(); i++) {
+                Method m = (Method)methods.get(i);
+                ArrayList entry = getMethodSignature(m);
+                returnVal.add(entry);
+            }
+            return returnVal;
+        }
+
+        private ArrayList getMethodSignature(Method m) throws XmlRpcException {
+            Class returnType = m.getReturnType();
+            Class[] paramTypes = m.getParameterTypes();
+            ArrayList entry = new ArrayList(paramTypes.length+1);
+            entry.add(mapType(returnType));
+            for (int j = 0; j < paramTypes.length; j++) {
+                entry.add(mapType(paramTypes[j]));
+            }
+            return entry;
+        }
+
+        public String methodHelp() throws XmlRpcException {
+            throw new XmlRpcException("method help not supported");
+        }
+
+        private String mapType(Class type) throws XmlRpcException {
+            if (type == null)
+                return "nil";
+
+            // base types
+            if (type == Integer.TYPE || type == Integer.class)
+                return "int";
+            if (type == Double.TYPE || type == Double.class)
+                return "double";
+            if (type == Boolean.TYPE || type == Boolean.class)
+                return "boolean";
+            if (type == String.class)
+                return "string";
+            if (List.class.isAssignableFrom(type))
+                return "array";
+            if (Map.class.isAssignableFrom(type))
+                return "struct";
+            if (Date.class.isAssignableFrom(type))
+                return "dateTime.iso8601";
+            if (Object[].class.isAssignableFrom(type))
+                return "array";
+            if (type == byte[].class)
+                return "base64";
+            if (type == Object.class)
+                return "undefined";
+
+            // extension types
+            if (type == void.class)
+                return "nil";
+            if (type == Byte.TYPE || type == Byte.class)
+                return "i1";
+            if (type == Short.TYPE || type == Short.class)
+                return "i2";
+            if (type == Long.TYPE || type == Long.class)
+                return "i8";
+            if (type == Float.TYPE || type == Float.class)
+                return "float";
+            if (Node.class.isAssignableFrom(type))
+                return "dom";
+            if (Serializable.class.isAssignableFrom(type)) // last resort
+                return "serializable";
+
+            // give up
+            throw new XmlRpcException("cannot find XML-RPC type for " + type.getName());
+        }
+    }
+}
Index: server/src/main/java/org/apache/xmlrpc/server/XmlRpcSystemImpl.java
===================================================================
--- server/src/main/java/org/apache/xmlrpc/server/XmlRpcSystemImpl.java	(revision 0)
+++ server/src/main/java/org/apache/xmlrpc/server/XmlRpcSystemImpl.java	(revision 0)
@@ -0,0 +1,33 @@
+package org.apache.xmlrpc.server;
+
+import org.apache.xmlrpc.XmlRpcHandler;
+import org.apache.xmlrpc.XmlRpcException;
+import org.apache.xmlrpc.XmlRpcMetaDataHandler;
+
+import java.util.List;
+
+public class XmlRpcSystemImpl {
+    private XmlRpcHandlerMapping mapping;
+    private boolean listable;
+    XmlRpcSystemImpl(XmlRpcHandlerMapping mapping) {
+        this.mapping = mapping;
+        listable = (mapping instanceof XmlRpcListableHandlerMapping);
+    }
+    private XmlRpcMetaDataHandler getHandler(String name, String operation) throws XmlRpcException {
+        XmlRpcHandler xrh = mapping.getHandler(name);
+        if (xrh instanceof XmlRpcMetaDataHandler)
+            return (XmlRpcMetaDataHandler)xrh;
+        throw new XmlRpcException(operation + " not supported for " + name);
+    }
+    public List methodSignature(String methodName) throws XmlRpcException {
+        return getHandler(methodName, "system.methodSignature").getSignatures();
+    }
+    public String methodHelp(String methodName) throws XmlRpcException {
+        return getHandler(methodName, "system.methodHelp").methodHelp();
+    }
+    public String[] listMethods() throws XmlRpcException {
+        if (!listable)
+            throw new XmlRpcException("system.methodList not supported");
+        return ((XmlRpcListableHandlerMapping)mapping).listMethods();
+    }
+}
Index: server/src/main/java/org/apache/xmlrpc/server/DynamicHandlerMapping.java
===================================================================
--- server/src/main/java/org/apache/xmlrpc/server/DynamicHandlerMapping.java	(revision 0)
+++ server/src/main/java/org/apache/xmlrpc/server/DynamicHandlerMapping.java	(revision 0)
@@ -0,0 +1,29 @@
+package org.apache.xmlrpc.server;
+
+import org.apache.xmlrpc.XmlRpcException;
+
+import java.util.Iterator;
+
+public class DynamicHandlerMapping extends AbstractReflectiveHandlerMapping {
+
+    public void addHandler(String key, Object handler)
+    {
+        registerPublicMethods(handlerMap, key, handler.getClass(), handler);
+    }
+
+    public void addSubMap(String key, final XmlRpcListableHandlerMapping subMapping) throws XmlRpcException {
+        String[] subHandlerMethods = subMapping.listMethods();
+        for (int i = 0; i < subHandlerMethods.length; i++) {
+            String method = subHandlerMethods[i];
+            handlerMap.put(key + "." + method, subMapping.getHandler(method));
+        }
+    }
+
+    public void remove(String key)
+    {
+        for (Iterator i = handlerMap.keySet().iterator(); i.hasNext();) {
+            String k = (String)i.next();
+            if (k.startsWith(key)) i.remove();
+        }
+    }
+}
Index: server/src/main/java/org/apache/xmlrpc/server/PropertyHandlerMapping.java
===================================================================
--- server/src/main/java/org/apache/xmlrpc/server/PropertyHandlerMapping.java	(revision 380260)
+++ server/src/main/java/org/apache/xmlrpc/server/PropertyHandlerMapping.java	(working copy)
@@ -17,9 +17,6 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
 import java.net.URL;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -28,9 +25,6 @@
 
 import org.apache.xmlrpc.XmlRpcException;
 import org.apache.xmlrpc.XmlRpcHandler;
-import org.apache.xmlrpc.XmlRpcRequest;
-import org.apache.xmlrpc.common.XmlRpcHttpRequestConfig;
-import org.apache.xmlrpc.common.XmlRpcNotAuthorizedException;
 
 
 /** A handler mapping based on a property file. The property file
@@ -47,162 +41,76 @@
  * A typical use would be, to specify interface names as the
  * property keys and implementations as the values.
  */
-public class PropertyHandlerMapping implements XmlRpcHandlerMapping {
-	/** An object implementing this interface may be used
-	 * to validate user names and passwords.
-	 */
-	public interface AuthenticationHandler {
-		/** Returns, whether the user is authenticated and
-		 * authorized to perform the request.
-		 */
-		boolean isAuthorized(XmlRpcRequest pRequest)
-			throws XmlRpcException;
-	}
+public class PropertyHandlerMapping extends AbstractReflectiveHandlerMapping {
 
-	private final Map handlerMap;
-	private AuthenticationHandler authenticationHandler;
+    /** Creates a new instance, loading the property file
+     * from the given URL.
+     * @param pClassLoader Classloader being used to load the classes.
+     * @param pURL The URL, from which the property file is being
+     * loaded.
+     * @throws IOException Loading the property file failed.
+     * @throws XmlRpcException Initializing the handlers failed.
+     */
+    public PropertyHandlerMapping(ClassLoader pClassLoader, URL pURL)
+            throws IOException, XmlRpcException {
+        handlerMap = load(pClassLoader, pURL);
+    }
 
-	/** Creates a new instance, loading the property file
-	 * from the given URL.
-	 * @param pClassLoader Classloader being used to load the classes.
-	 * @param pURL The URL, from which the property file is being
-	 * loaded.
-	 * @throws IOException Loading the property file failed.
-	 * @throws XmlRpcException Initializing the handlers failed.
-	 */
-	public PropertyHandlerMapping(ClassLoader pClassLoader, URL pURL)
-			throws IOException, XmlRpcException {
-		handlerMap = load(pClassLoader, pURL);
-	}
+    /** Creates a new instance, loading the given property file.
+     * @param pClassLoader Classloader being used to load the classes.
+     * @param pFile File being loaded.
+     * @throws IOException Loading the property file failed.
+     * @throws XmlRpcException Initializing the handlers failed.
+     */
+    public PropertyHandlerMapping(ClassLoader pClassLoader, File pFile)
+            throws IOException, XmlRpcException {
+        handlerMap = load(pClassLoader, pFile.toURL());
+    }
 
-	/** Creates a new instance, loading the given property file.
-	 * @param pClassLoader Classloader being used to load the classes.
-	 * @param pFile File being loaded.
-	 * @throws IOException Loading the property file failed.
-	 * @throws XmlRpcException Initializing the handlers failed.
-	 */
-	public PropertyHandlerMapping(ClassLoader pClassLoader, File pFile)
-			throws IOException, XmlRpcException {
-		handlerMap = load(pClassLoader, pFile.toURL());
-	}
+    /** Creates a new instance, loading the properties from
+     * the given resource.
+     * @param pClassLoader Classloader being used to locate
+     * the resource.
+     * @param pResource Resource being loaded.
+     * @throws IOException Loading the property file failed.
+     * @throws XmlRpcException Initializing the handlers failed.
+     */
+    public PropertyHandlerMapping(ClassLoader pClassLoader, String pResource)
+            throws IOException, XmlRpcException {
+        URL url = pClassLoader.getResource(pResource);
+        if (url == null) {
+            throw new IOException("Unable to locate resource " + pResource);
+        }
+        handlerMap = load(pClassLoader, url);
+    }
 
-	/** Creates a new instance, loading the properties from
-	 * the given resource.
-	 * @param pClassLoader Classloader being used to locate
-	 * the resource.
-	 * @param pResource Resource being loaded.
-	 * @throws IOException Loading the property file failed.
-	 * @throws XmlRpcException Initializing the handlers failed.
-	 */
-	public PropertyHandlerMapping(ClassLoader pClassLoader, String pResource)
-			throws IOException, XmlRpcException {
-		URL url = pClassLoader.getResource(pResource);
-		if (url == null) {
-			throw new IOException("Unable to locate resource " + pResource);
-		}
-		handlerMap = load(pClassLoader, url);
-	}
-
-	/** Returns the authentication handler, if any, or null.
-	 */
-	public AuthenticationHandler getAuthenticationHandler() {
-		return authenticationHandler;
-	}
-
-	/** Sets the authentication handler, if any, or null.
-	 */
-	public void setAuthenticationHandler(
-			AuthenticationHandler pAuthenticationHandler) {
-		authenticationHandler = pAuthenticationHandler;
-	}
-
-	private Map load(ClassLoader pClassLoader, URL pURL) throws IOException, XmlRpcException {
-		Map map = new HashMap();
-		Properties props = new Properties();
-		props.load(pURL.openStream());
-		for (Iterator iter = props.entrySet().iterator();  iter.hasNext();  ) {
-			Map.Entry entry = (Map.Entry) iter.next();
-			String key = (String) entry.getKey();
-			String value = (String) entry.getValue();
-			final Class c;
-			try {
-				c = pClassLoader.loadClass(value);
-			} catch (ClassNotFoundException e) {
-				throw new XmlRpcException("Unable to load class: " + value, e);
-			}
-			if (c == null) {
-				throw new XmlRpcException(0, "Loading class " + value + " returned null.");
-			}
-			final Object o;
-			try {
-				o = c.newInstance();
-			} catch (InstantiationException e) {
-				throw new XmlRpcException("Failed to instantiate class " + c.getName(), e);
-			} catch (IllegalAccessException e) {
-				throw new XmlRpcException("Illegal access when instantiating class " + c.getName(), e);
-			}
-			Method[] methods = c.getMethods();
-			for (int i = 0;  i < methods.length;  i++) {
-				final Method method = methods[i];
-				if (!Modifier.isPublic(method.getModifiers())) {
-					continue;  // Ignore methods, which aren't public
-				}
-				if (Modifier.isStatic(method.getModifiers())) {
-					continue;  // Ignore methods, which are static
-				}
-				if (method.getReturnType() == void.class) {
-					continue;  // Ignore void methods.
-				}
-				if (method.getDeclaringClass() == Object.class) {
-					continue;  // Ignore methods from Object.class
-				}
-				String name = key + "." + method.getName();
-				if (!map.containsKey(name)) {
-					map.put(name, newXmlRpcHandler(c, o, method));
-				}
-			}
-		}
-		return map;
-	}
-
-	protected XmlRpcHandler newXmlRpcHandler(final Class pClass, final Object pValue, final Method pMethod) {
-		return new XmlRpcHandler(){
-			public Object execute(XmlRpcRequest pRequest) throws XmlRpcException {
-				AuthenticationHandler authHandler = getAuthenticationHandler();
-				if (authHandler != null  &&  !authHandler.isAuthorized(pRequest)) {
-					throw new XmlRpcNotAuthorizedException("Not authorized");
-				}
-				Object[] args = new Object[pRequest.getParameterCount()];
-				for (int j = 0;  j < args.length;  j++) {
-					args[j] = pRequest.getParameter(j);
-				}
-				try {
-					return pMethod.invoke(pValue, args);
-				} catch (IllegalAccessException e) {
-					throw new XmlRpcException("Illegal access to method "
-											  + pMethod.getName() + " in class "
-											  + pClass.getName(), e);
-				} catch (IllegalArgumentException e) {
-					throw new XmlRpcException("Illegal argument for method "
-											  + pMethod.getName() + " in class "
-											  + pClass.getName(), e);
-				} catch (InvocationTargetException e) {
-					Throwable t = e.getTargetException();
-					throw new XmlRpcException("Failed to invoke method "
-											  + pMethod.getName() + " in class "
-											  + pClass.getName() + ": "
-											  + t.getMessage(), t);
-				}
-			}
-		};
-	}
-
-	public XmlRpcHandler getHandler(String handlerName)
-			throws XmlRpcNoSuchHandlerException, XmlRpcException {
-		XmlRpcHandler result = (XmlRpcHandler) handlerMap.get(handlerName);
-		if (result == null) {
-			throw new XmlRpcNoSuchHandlerException("No such handler: " + handlerName);
-		}
-		return result;
-	}
+    private Map load(ClassLoader pClassLoader, URL pURL) throws IOException, XmlRpcException {
+        Map map = new HashMap();
+        Properties props = new Properties();
+        props.load(pURL.openStream());
+        for (Iterator iter = props.entrySet().iterator();  iter.hasNext();  ) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            String key = (String) entry.getKey();
+            String value = (String) entry.getValue();
+            final Class c;
+            try {
+                c = pClassLoader.loadClass(value);
+            } catch (ClassNotFoundException e) {
+                throw new XmlRpcException("Unable to load class: " + value, e);
+            }
+            if (c == null) {
+                throw new XmlRpcException(0, "Loading class " + value + " returned null.");
+            }
+            final Object o;
+            try {
+                o = c.newInstance();
+            } catch (InstantiationException e) {
+                throw new XmlRpcException("Failed to instantiate class " + c.getName(), e);
+            } catch (IllegalAccessException e) {
+                throw new XmlRpcException("Illegal access when instantiating class " + c.getName(), e);
+            }
+            registerPublicMethods(map, key, c, o);
+        }
+        return map;
+    }
 }
Index: common/src/main/java/org/apache/xmlrpc/XmlRpcException.java
===================================================================
--- common/src/main/java/org/apache/xmlrpc/XmlRpcException.java	(revision 380260)
+++ common/src/main/java/org/apache/xmlrpc/XmlRpcException.java	(working copy)
@@ -82,8 +82,8 @@
 		super.printStackTrace(pStream);
 		if (linkedException != null) {
 			pStream.println("Caused by:");
+            linkedException.printStackTrace(pStream);
 		}
-		linkedException.printStackTrace(pStream);
 	}
 
 	public void printStackTrace(PrintWriter pWriter) {
Index: common/src/main/java/org/apache/xmlrpc/XmlRpcMetaDataHandler.java
===================================================================
--- common/src/main/java/org/apache/xmlrpc/XmlRpcMetaDataHandler.java	(revision 0)
+++ common/src/main/java/org/apache/xmlrpc/XmlRpcMetaDataHandler.java	(revision 0)
@@ -0,0 +1,11 @@
+package org.apache.xmlrpc;
+
+import java.util.List;
+
+public interface XmlRpcMetaDataHandler extends XmlRpcHandler {
+    Object execute(XmlRpcRequest pRequest) throws XmlRpcException;
+
+    List getSignatures() throws XmlRpcException;
+
+    String methodHelp() throws XmlRpcException;
+}
