Package de.dfki.util.xmlrpc

Source Code of de.dfki.util.xmlrpc.XmlRpc

/*
* Created on 22.07.2003
*
*/

package de.dfki.util.xmlrpc;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Vector;

import java.util.logging.Logger;

import de.dfki.util.xmlrpc.annotation.ConverterMappings;
import de.dfki.util.xmlrpc.client.ClientInvocationHandler;
import de.dfki.util.xmlrpc.client.StandardXmlRpcClient;
import de.dfki.util.xmlrpc.client.XmlRpcClient;
import de.dfki.util.xmlrpc.common.ApiParameter;
import de.dfki.util.xmlrpc.common.MethodSignature;
import de.dfki.util.xmlrpc.common.XmlRpcConnection;
import de.dfki.util.xmlrpc.conversion.EnhancedTypeConverter;
import de.dfki.util.xmlrpc.conversion.ParameterConverterRegistry;
import de.dfki.util.xmlrpc.conversion.TypeConversionException;
import de.dfki.util.xmlrpc.conversion.TypeConverter;
import de.dfki.util.xmlrpc.server.XmlRpcHandlerFactory;

/**
* Offers some useful static methods for creating remote clients and do type conversion.
*
* @author lauer
*/
public class XmlRpc
{
    private static Logger mLog = Logger.getLogger( XmlRpc.class.getName() );

    public static Logger log()
    {
        return ( mLog );
    }
   
    /**
     * XML-RPC Type constants. Also maps XML-RPC types to java types.
     *
     * @author lauer
     */
    public enum Type
    {
        INT(Integer.class, Integer.class, Integer.TYPE),
        BOOLEAN(Boolean.class, Boolean.class, Boolean.TYPE),
        STRING(String.class),
        DOUBLE(Double.class, Double.class, Double.TYPE),
        FLOAT(Float.class, Float.class, Float.TYPE)//non standard, but handy :-)
        DATE(Date.class),
        STRUCT(Map.class, Hashtable.class),
        ARRAY(Collection.class, Vector.class),
        BASE64(byte[].class),
        STRINGasBASE64(String.class),
       
        NONE(void.class);

        private Type( Class<?> javaClass )
        {
            this( javaClass, javaClass, null );
        }

        private Type( Class<?> baseClass, Class<?> parameterClass )
        {
            this( baseClass, parameterClass, null );
        }

        /**
         * Defines java type mappings for a XML-RPC type.
         * @param baseClass Instances of this XML-RPC type are assignable to this type.
         * @param parameterClass Parameters instances of this XML-RPC type generated by the XML-RPC runtime are of this type. 
         * @param primitiveType A XML-RPC type may be compatible to a primitive type.
         */
        private Type( Class<?> baseClass, Class<?> parameterClass,  Class<?> primitiveType )
        {
            mParameterClass = parameterClass;
            mBaseClass = baseClass;
            mPrimitiveType = primitiveType;
        }

        public Class<?> getCorrespondingBaseType()
        {
            return ( mBaseClass );
        }

        public Class<?> getCorrespondingParameterType()
        {
            return ( mParameterClass );
        }
       
        public Class<?> getCorrespondingPrimitiveType()
        {
            return( mPrimitiveType );
        }
       
        private Class<?> mBaseClass;
        private Class<?> mParameterClass;
        private Class<?> mPrimitiveType;
    }

    /**
     * Create a remote client which connects to the given host and port using the specified API.
     *
     * @param apiClass
     *        The client interface class.
     * @param handlerName
     *        The name of the server-side XML-RPC handler.
     * @param host
     *        The host the server is located at.
     * @param port
     *        The port the server is listening at.
     * @return An instance of a XML-RPC client. This instance can also be casted to
     *         {@link XmlRpcClient}.
     */
    public static <API> API createClient( final Class<API> apiClass,
                                          final String handlerName,
                                          final String host,
                                          final int port )
    {
        return( createClient( apiClass, handlerName, XmlRpcConnection.connect( host, port ) ) );
    }
       
    /**
     * Creates a XML-RPC client for the given API class. The client will be created in ClassLoader of
     * <code>Thread.currentThread()</code>.
     *
     * @param apiClass
     *        The client interface class.
     * @param handlerName
     *        The name of the server-side XML-RPC handler.
     * @param xmlRpcConnection
     *        The connection the client should connect to.
     * @return An instance of a XML-RPC client. This instance can also be casted to
     *         {@link XmlRpcClient}.
     */
    public static <API> API createClient( final Class<API> apiClass,
                                          final String handlerName,
                                          final XmlRpcConnection xmlRpcConnection )
    {
        final Object apiClient = Proxy.newProxyInstance( Thread.currentThread().getContextClassLoader(),
                                                         new Class[]{ XmlRpcClient.class, apiClass },
                                                         new ClientInvocationHandler( new StandardXmlRpcClient() ) );

        final XmlRpcClient asClient = (XmlRpcClient)apiClient;
        asClient.setConnection( xmlRpcConnection );
        asClient.setHandlerName( handlerName );
       
        ParameterConverterRegistry.readParameterConverterMappingsFromApiClass( apiClass );

        return( apiClass.cast( apiClient ) );
    }
   
    public static <API> API createClient( final Class<API> apiClass,
                                          final XmlRpcConnection xmlRpcConnection )
    {
        return( createClient( apiClass, "", xmlRpcConnection ) );
    }
   
   
    /**
     * Tests all methods of the given API whether they are XML-RPC compliant or not. Types which define proper type conversion
     * operations are treated as compliant types.
     *
     * @param apiClass
     *      The API class.
     * @return A Map which has an entry for each API method stating whether this method is XML-RPC compliant or not.
     */
    public static Map<Method,Boolean> getMethodXmlRpcComplianceMap( final Class<?> apiClass )
    {
        Map<Method,Boolean> complianceMap = new HashMap<Method, Boolean>();
        createClient( apiClass, null )//need this to fetch api converter mappings not yet registered
        for( Method method: apiClass.getDeclaredMethods() )
        {
            boolean isCompliant = true;
            try
            {
                MethodSignature.createFromMethod( method );
            }
            catch( Throwable e )
            {
                isCompliant = false;
            }
            complianceMap.put( method, isCompliant );
        }
       
        return( complianceMap );
    }

    private static boolean mUseAutomaticNullMasking = false;
    private static boolean mTreatUnknownTypesAsBeans = false;
   
    /**
     * Enables/Disables the automatic null-masking ability. That is, null-values in method calls
     * and return statements are automatically masked (as a zero-length byte-array)
     * and turned back to null-values on the receiver side.
     * <br>
     * NOTE: this feature works for all built-in XML-RPC types except BASE64 and for types
     * with user-defined conversions.
     *
     * @param b true enables masking mode. false disables it.
     */
    public static void useAutomaticNullMasking( boolean b )
    {
        mUseAutomaticNullMasking = b;
    }
   
    public static boolean usesAutomaticNullMasking()
    {
        return( mUseAutomaticNullMasking );
    }
   
    /**
     * Enables the fall-back behaviour to treat all unknown types as XmlRpcBeans (instead of throwing an exception).
     * @param b true, to enable this feature. false to disable it (=default)
     */
    public static void treatUnknownTypesAsBeans( boolean b )
    {
        mTreatUnknownTypesAsBeans = b;
    }
   
    public static boolean treatUnknownTypesAsBeans()
    {
        return( mTreatUnknownTypesAsBeans );
    }
   
    private static TypeConverter mTypeConverter = new EnhancedTypeConverter();
    public static TypeConverter getTypeConverter()
    {
        return( mTypeConverter );
    }

    /**
     * Converts an instance of a certain type into a XML-RPC representation. If
     * the type defines a type conversion (type annotation({@link de.dfki.util.xmlrpc.annotation.XmlRpc})
     * this is used for conversion. Converter mappings used in the API interface ({@link ConverterMappings})
     * will only be used if the API has been processed by a a
     * {@link #createClient} or a
     * {@link XmlRpcHandlerFactory#createHandlerFor(Object)} call before or a converter has been registered
     * before using {@link ParameterConverterRegistry#setParameterConverterForClass(Class, Class)}.
     *
     * @throws TypeConversionException:
     *         Denotes problems while converting representations. This may
     *         include missing annotations, illegal object types, missing converter mappings, ...
     */
    public static Object getXmlRpcRepresentation( Class<?> userPrepresentationType, Object toConvert )
        throws TypeConversionException
    {
//        if (toConvert == null)
//        {
//            throw( new TypeConversionException( "Object to convert must not be null" ) );
//        }
       
        ApiParameter p = ApiParameter.createFrom( userPrepresentationType );
        return( getTypeConverter().convertToXmlRpcRepresentation( p, toConvert ) );
    }

    /**
     * Same as {@link #getXmlRpcRepresentation(Class, Object)}. The repesentation type is taken directly from
     * the object to convert.
     */
    public static Object getXmlRpcRepresentation( Object toConvert )
        throws TypeConversionException
    {
        return( getXmlRpcRepresentation( toConvert.getClass() , toConvert ) );
    }

    /**
     * Converts a XML-RPC representation into an instance of the given type. If
     * the type defines a type conversion (type annotation({@link de.dfki.util.xmlrpc.annotation.XmlRpc})
     * this is used for conversion. Converter mappings used in the API interface ({@link ConverterMappings})
     * will only be used if the API has been processed by a a
     * {@link #createClient} or a
     * {@link XmlRpcHandlerFactory#createHandlerFor(Object)} call before.
     *
     * @param targetClass
     *        Type to convert to.
     * @param xmlRpcRepresentation
     *        The XML-RPC representation.
     * @throws TypeConversionException:
     *         Denotes problems while converting representations. This may
     *         include missing annotations, illegal object types, ...
     */
    @SuppressWarnings("unchecked")
    public static <T> T getUserRepresentation( Class<T> targetClass, Object xmlRpcRepresentation )
        throws TypeConversionException
    {
        if (xmlRpcRepresentation == null)
        {
            throw( new TypeConversionException( "Object to convert must not be null" ) );
        }

        ApiParameter p = ApiParameter.createFrom( targetClass );
        Object result = getTypeConverter().convertToUserRepresentation( p, xmlRpcRepresentation );
       
        //Note: a Class.cast( Object ) call will not manage to convert, e.g. an Integer to primitive int
        return( (T)result  );
    }
}
TOP

Related Classes of de.dfki.util.xmlrpc.XmlRpc

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.