Package de.netseeker.ejoe.handler

Source Code of de.netseeker.ejoe.handler.DefaultRemotingHandler

/*********************************************************************
* DefaultRemotingHandler.java
* created on 09.07.2006 by netseeker
* $$Source$$
* $$Date$$
* $$Revision$$
*
* ====================================================================
*
*  Copyright 2006 netseeker aka Michael Manske
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
* ====================================================================
*
* This file is part of the EJOE framework.
* For more information on the author, please see
* <http://www.manskes.de/>.
*
*********************************************************************/

package de.netseeker.ejoe.handler;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import de.netseeker.ejoe.cache.LRUMap;
import de.netseeker.ejoe.util.ContentStringBuilder;

/**
* Reflection based ServerHandler. This is the default implementation for EJOE's remote reflection feature. This class
* handles automatic mapping of object types to primitives for the method parameter to find the right method signature.
* Classes, parameter classes (including object-primitive-mapping) as well as methods will be cached to outperform usual
* reflection.
*
* @author netseeker
* @since 0.3.9.1
*/
public class DefaultRemotingHandler extends BaseRemotingHandler
{

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    private static final Logger log              = Logger.getLogger( DefaultRemotingHandler.class.getName() );

    private Map                 constructorCache = new LRUMap();

    private Map                 methodCache      = new LRUMap();

    private Map                 paramCache       = new LRUMap();

    Object handle( Class target, String method, Object[] args ) throws Exception
    {
        Object ret = null;

        Object[] types = getArgTypes( args );
        Class[] argTypes = (Class[]) types[0];
        Class[] argTypesPrimitive = (Class[]) types[1];

        if ( log.isLoggable( Level.FINE ) )
        {
            log.log( Level.FINE, target.getName() + '#' + method + '(' + ContentStringBuilder.toString( argTypes )
                    + ')' );
        }

/* Java 5 break compatibility with Java <= 1.4, because SUN changed the behavior of Class.getName()
* so the following code would break Java 1.4 backward compatibility
        if ( !target.getSimpleName().equals( method ) )
        {
            Method mtd = getMethodForArgumentTypes( target, method, argTypes, argTypesPrimitive );

            Object o = target.newInstance();
            ret = mtd.invoke( o, args );
        }
        else
        {
            Constructor constructor = getConstructorForArgumentTypes( target, argTypes, argTypesPrimitive );
            ret = constructor.newInstance( args );
        }
*/
        try
        {
            Method mtd = getMethodForArgumentTypes( target, method, argTypes, argTypesPrimitive );

            Object o = target.newInstance();
            ret = mtd.invoke( o, args );
        }
        catch(NoSuchMethodException e)
        {
            Constructor constructor = getConstructorForArgumentTypes( target, argTypes, argTypesPrimitive );
            ret = constructor.newInstance( args );
        }
       
        return ret;
    }

    /**
     * @param params array of objects for which the argument types has to be determined
     * @return an array of two class-arrays (Class[]) containing object types in the first class-array as well as their
     *         primitive representation in the second class-array
     */
    protected Object[] getArgTypes( Object[] params )
    {
        Class[] argTypes = null;
        Class[] argTypesPrimitive = null;

        if ( params != null && params.length > 0 )
        {
            // now we have to create an array of parameter types to find the
            // right method in the required class via reflection
            argTypes = new Class[params.length];
            // because we might get primitive parameters as objects, we have to
            // create a second array of parameter types
            // containing the corresponding primitve types
            argTypesPrimitive = new Class[params.length];

            for ( int i = 0; i < params.length; i++ )
            {
                // add the object type to the regular array of parameter types
                argTypes[i] = params[i].getClass();

                // now check if the parameter is a object type instead of a
                // primitive
                if ( !argTypes[i].isPrimitive() )
                {
                    // get the class name of the object type
                    String clName = argTypes[i].getName();

                    // do we have the corresponding primitive type already in
                    // cache?
                    if ( !paramCache.containsKey( clName ) )
                    {
                        try
                        {
                            // no, hence we have determine the corresponding
                            // primitive class via reflection
                            Field field = argTypes[i].getField( "TYPE" );
                            argTypesPrimitive[i] = (Class) field.get( params[i] );
                            // add the primitive type to the cache
                            paramCache.put( clName, argTypesPrimitive[i] );
                        }
                        catch ( NoSuchFieldException e )
                        {
                            // ok, can happen if the object type just has no
                            // corresponding primitive type
                            argTypesPrimitive[i] = argTypes[i];
                        }
                        catch ( Exception e )
                        {
                            // shouldn't happen

                            argTypesPrimitive[i] = argTypes[i];
                        }
                    }
                    // the corresponding primitive type was found in the cache
                    else
                    {
                        argTypesPrimitive[i] = (Class) paramCache.get( clName );
                    }
                }
                // the parameter was given as primitive
                else
                {
                    argTypesPrimitive[i] = argTypes[i];
                }
            }
        }
        // ok, no parameters given
        else
        {
            argTypes = new Class[] {};
            argTypesPrimitive = new Class[] {};
        }

        return new Object[] { argTypes, argTypesPrimitive };
    }

    /**
     * Similiar to {@link #getMethodForArgumentTypes(Class, String, Class[], Class[])} but tries to lookup constructors
     * instead
     *
     * @param clazz
     * @param argTypes
     * @param argTypesPrimitive
     * @return
     * @throws SecurityException
     * @throws NoSuchMethodException
     */
    protected Constructor getConstructorForArgumentTypes( Class clazz, Class[] argTypes, Class[] argTypesPrimitive )
            throws SecurityException, NoSuchMethodException
    {
        String className = clazz.getName();

        // try to find the method in the constructor-cache while using the array
        // of
        // object types for the given parameters
        Constructor constr = (Constructor) constructorCache.get( className + ContentStringBuilder.toString( argTypes ) );

        if ( constr == null )
        {
            // ok, then try to find the constructor in the constructor-cache
            // while using
            // the array of primitive types for the given parameters
            constr = (Constructor) constructorCache
                    .get( className + ContentStringBuilder.toString( argTypesPrimitive ) );
        }

        if ( constr == null )
        {
            // seems as this is the first search for the constructor
            try
            {
                // try to get the constructor via reflection while using the
                // array of
                // object types for the given parameters
                constr = clazz.getConstructor( argTypes );
                constructorCache.put( className + ContentStringBuilder.toString( argTypes ), constr );
            }
            catch ( NoSuchMethodException e )
            {
                // ok, maybe the parameter types don't match, lets try the array
                // of primitive types for the given parameters
                constr = clazz.getConstructor( argTypesPrimitive );
                constructorCache.put( className + ContentStringBuilder.toString( argTypesPrimitive ), constr );
            }
        }

        return constr;
    }

    /**
     * @param clazz
     * @param mName
     * @param argTypes
     * @param argTypesPrimitive
     * @return
     * @throws SecurityException
     * @throws NoSuchMethodException
     */
    protected Method getMethodForArgumentTypes( Class clazz, String mName, Class[] argTypes, Class[] argTypesPrimitive )
            throws SecurityException, NoSuchMethodException
    {
        String key = clazz.getName() + '#' + mName;
        String argTypesKey = ContentStringBuilder.toString( argTypes );

        // try to find the method in the method-cache while using the array of
        // object types for the given parameters
        Method mtd = (Method) methodCache.get( key + argTypesKey );

        if ( mtd == null && argTypesPrimitive != null )
        {
            // ok, then try to find the method in the method-cache while using
            // the array of primitive types for the given parameters
            mtd = (Method) methodCache.get( key + ContentStringBuilder.toString( argTypesPrimitive ) );
        }

        if ( mtd == null )
        {
            // seems as this is the first invocation of the method
            try
            {
                // try to get the method via reflection while using the array of
                // object types for the given parameters
                mtd = clazz.getMethod( mName, argTypes );
                methodCache.put( key + ContentStringBuilder.toString( argTypes ), mtd );
            }
            catch ( NoSuchMethodException e )
            {
                // ok, maybe the parameter types don't match, lets try the array
                // of primitive types for the given parameters
                if ( argTypesPrimitive != null )
                {
                    mtd = clazz.getMethod( mName, argTypesPrimitive );
                    methodCache.put( key + ContentStringBuilder.toString( argTypesPrimitive ), mtd );
                }
                else
                {
                    throw new NoSuchMethodException( key + argTypesKey );
                }
            }
        }

        return mtd;
    }
}
TOP

Related Classes of de.netseeker.ejoe.handler.DefaultRemotingHandler

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.