Author: jochen Date: Fri Feb 24 04:57:18 2006 New Revision: 380660 URL: http://svn.apache.org/viewcvs?rev=380660&view=rev Log: Accepted patch from XMLRPC-76.
Added: webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/AbstractReflectiveHandlerMapping.java webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/DynamicHandlerMapping.java Modified: webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/PropertyHandlerMapping.java webservices/xmlrpc/trunk/src/changes/changes.xml Added: webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/AbstractReflectiveHandlerMapping.java URL: http://svn.apache.org/viewcvs/webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/AbstractReflectiveHandlerMapping.java?rev=380660&view=auto ============================================================================== --- webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/AbstractReflectiveHandlerMapping.java (added) +++ webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/AbstractReflectiveHandlerMapping.java Fri Feb 24 04:57:18 2006 @@ -0,0 +1,153 @@ +package org.apache.xmlrpc.server; + +import org.apache.xmlrpc.XmlRpcRequest; +import org.apache.xmlrpc.XmlRpcException; +import org.apache.xmlrpc.XmlRpcHandler; +import org.apache.xmlrpc.common.XmlRpcNotAuthorizedException; + +import java.util.Map; +import java.util.HashMap; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.InvocationTargetException; + + +/** Abstract base class of handler mappings, which are + * using reflection. + */ +public abstract class AbstractReflectiveHandlerMapping 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; + } + + protected Map handlerMap = new HashMap(); + private AuthenticationHandler authenticationHandler; + + /** 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; + } + + /** Searches for methods in the given class. For any valid + * method, it creates an instance of [EMAIL PROTECTED] XmlRpcHandler}. + * Valid methods are defined as follows: + * <ul> + * <li>They must be public.</li> + * <li>They must not be static.</li> + * <li>The return type must not be void.</li> + * <li>The declaring class must not be + * [EMAIL PROTECTED] java.lang.Object}.</li> + * <li>If multiple methods with the same name exist, + * which meet the above conditins, then only the + * first method is valid.</li> + * </ul> + * @param pMap Handler map, in which created handlers are + * being registered. + * @param pKey Suffix for building handler names. A dot and + * the method name are being added. + * @param pType The class being inspected. + * @param pInstance The object being invoked. Note, that this + * object must be stateless: Multiple threads can run on it + * at the same time. + */ + protected void registerPublicMethods(Map pMap, String pKey, + Class pType, Object pInstance) { + if (pInstance == null) { + throw new NullPointerException("The object instance must not be null."); + } + Method[] methods = pType.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 = pKey + "." + method.getName(); + if (!pMap.containsKey(name)) { + pMap.put(name, newXmlRpcHandler(pType, pInstance, method)); + } + } + } + + /** Creates a new instance of [EMAIL PROTECTED] XmlRpcHandler}. + * @param pClass The class, which was inspected for handler + * methods. This is used for error messages only. Typically, + * it is the same than <pre>pInstance.getClass()</pre>. + * @param pInstance The object, which is being invoked by + * the created handler. Typically an instance of + * <code>pClass</code>. + * @param pMethod The method being invoked. + */ + protected XmlRpcHandler newXmlRpcHandler(final Class pClass, + final Object pInstance, final Method pMethod) { + if (pInstance == null) { + throw new NullPointerException("The object instance must not be null."); + } + 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(pInstance, 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); + } + } + }; + } + + /** Returns the [EMAIL PROTECTED] XmlRpcHandler} with the given name. + * @param pHandlerName The handlers name + * @throws XmlRpcNoSuchHandlerException A handler with the given + * name is unknown. + */ + public XmlRpcHandler getHandler(String pHandlerName) + throws XmlRpcNoSuchHandlerException, XmlRpcException { + XmlRpcHandler result = (XmlRpcHandler) handlerMap.get(pHandlerName); + if (result == null) { + throw new XmlRpcNoSuchHandlerException("No such handler: " + pHandlerName); + } + return result; + } +} Added: webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/DynamicHandlerMapping.java URL: http://svn.apache.org/viewcvs/webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/DynamicHandlerMapping.java?rev=380660&view=auto ============================================================================== --- webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/DynamicHandlerMapping.java (added) +++ webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/DynamicHandlerMapping.java Fri Feb 24 04:57:18 2006 @@ -0,0 +1,29 @@ +package org.apache.xmlrpc.server; + +import java.util.Iterator; + + +/** A handler mapping, which requires explicit registration + * of handlers. + */ +public class DynamicHandlerMapping extends AbstractReflectiveHandlerMapping { + /** Adds handlers for the given object to the mapping. + * The handlers are build by invoking + * [EMAIL PROTECTED] #registerPublicMethods(java.util.Map, String, Class, Object)}. + * @param pKey The class key, which is passed + * to [EMAIL PROTECTED] #registerPublicMethods(java.util.Map, String, Class, Object)}. + * @param pHandler The object, which is handling requests. + */ + public void addHandler(String pKey, Object pHandler) { + registerPublicMethods(handlerMap, pKey, pHandler.getClass(), pHandler); + } + + /** Removes all handlers with the given class key. + */ + public void removeHandler(String pKey) { + for (Iterator i = handlerMap.keySet().iterator(); i.hasNext();) { + String k = (String)i.next(); + if (k.startsWith(pKey)) i.remove(); + } + } +} Modified: webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/PropertyHandlerMapping.java URL: http://svn.apache.org/viewcvs/webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/PropertyHandlerMapping.java?rev=380660&r1=380659&r2=380660&view=diff ============================================================================== --- webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/PropertyHandlerMapping.java (original) +++ webservices/xmlrpc/trunk/server/src/main/java/org/apache/xmlrpc/server/PropertyHandlerMapping.java Fri Feb 24 04:57:18 2006 @@ -15,11 +15,7 @@ */ package org.apache.xmlrpc.server; -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; @@ -27,10 +23,6 @@ import java.util.Properties; 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 +39,64 @@ * 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; - } - - 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 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); - } - - /** 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; - } +public class PropertyHandlerMapping extends AbstractReflectiveHandlerMapping { + /** 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 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); + } + + 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; + } } Modified: webservices/xmlrpc/trunk/src/changes/changes.xml URL: http://svn.apache.org/viewcvs/webservices/xmlrpc/trunk/src/changes/changes.xml?rev=380660&r1=380659&r2=380660&view=diff ============================================================================== --- webservices/xmlrpc/trunk/src/changes/changes.xml (original) +++ webservices/xmlrpc/trunk/src/changes/changes.xml Fri Feb 24 04:57:18 2006 @@ -12,6 +12,11 @@ due-to-email="[EMAIL PROTECTED]"> The "string" tag could not be parsed. </action> + <action dev="jochen" type="enhancement" due-to="Walter Mundt" + due-to-email="[EMAIL PROTECTED]" + issue="XMLRPC76"> + Added the DynamicHandlerMapping. + </action> <action dev="jochen" type="enhancement"> The project is now splitted into three jar files: common, client, and server.