Package de.netseeker.ejoe.handler

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

/*********************************************************************
* BaseRemotingHandler.java
* created on 23.07.2006 by netseeker
* $Id$
* $Log$
* Revision 1.11  2007/11/17 10:57:00  netseeker
* *** empty log message ***
*
* Revision 1.10  2007/03/22 21:01:35  netseeker
* *** empty log message ***
*
* Revision 1.9  2006/12/02 19:10:36  netseeker
* adapted move of RemotingRequest to the main package
*
* Revision 1.8  2006/11/27 22:58:28  netseeker
* *** empty log message ***
*
* Revision 1.7  2006/11/12 20:34:44  netseeker
* *** empty log message ***
*
* Revision 1.6  2006/11/11 19:13:16  netseeker
* added security mechanism for remote reflection as well as for permitted adapters
*
* Revision 1.5  2006/11/06 08:50:30  netseeker
* fixed java 1.4 support
*
* Revision 1.4  2006/11/05 16:59:31  netseeker
* added support for remote reflection via usage of RemotingHandlers
*
* Revision 1.3  2006/07/27 20:35:15  netseeker
* *** empty log message ***
*
*
* ====================================================================
*
*  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.io.InputStream;
import java.security.AccessControlException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import de.netseeker.ejoe.cache.ClassRegistry;
import de.netseeker.ejoe.cache.LRUMap;
import de.netseeker.ejoe.io.IOUtil;
import de.netseeker.ejoe.request.RemotingRequest;

/**
* Base class for the family of reflection based ServerHandlers. Basically these ServerHandlers allow the usage of
* remote method invocations which the EJOE Sever handles using:
* <ul>
* <li>either standard java reflection with caching enhancements or</li>
* <li>assisted reflection with dynmically generated and cached proxy classes, which don't have to use reflection after
* the first invocation</li>
* </ul>
*
* @author netseeker
* @since 0.3.9.1
*/
public abstract class BaseRemotingHandler implements ServerHandler, ClassRegistry
{
    private static final Logger logger             = Logger.getLogger( BaseRemotingHandler.class.getName() );

    /**
     * cache for all primitive-wrapper combinations
     */
    private static Hashtable    primitiveToWrapper = new Hashtable();

    /**
     * cache for all wrapper-primitive combinations
     */
    private static Hashtable    wrapperToPrimitive = new Hashtable();

    /**
     * permission store containing package/class -names which are allowed or not allowed to be used in remote reflection
     * calls
     */
    private static String[]     reflectionPermissions;

    /**
     * all permitted class names will be stored in this cache for faster lookup
     */
    private static Set          permissionCache    = Collections.synchronizedSet( new HashSet() );

    /**
     * pre-cache all known Wrapper-Primitive-Pairs as well as all known Primitive-Wrapper-Pairs
     */

    protected Map               classCache         = new LRUMap();

    static
    {
        registerTypeMappings();
        loadReflectionPermissions();
    }

    private static void registerTypeMappings()
    {
        primitiveToWrapper.put( Boolean.TYPE, Boolean.class );
        primitiveToWrapper.put( Byte.TYPE, Byte.class );
        primitiveToWrapper.put( Short.TYPE, Short.class );
        primitiveToWrapper.put( Character.TYPE, Character.class );
        primitiveToWrapper.put( Integer.TYPE, Integer.class );
        primitiveToWrapper.put( Long.TYPE, Long.class );
        primitiveToWrapper.put( Float.TYPE, Float.class );
        primitiveToWrapper.put( Double.TYPE, Double.class );
        wrapperToPrimitive.put( Boolean.class, Boolean.TYPE );
        wrapperToPrimitive.put( Byte.class, Byte.TYPE );
        wrapperToPrimitive.put( Short.class, Short.TYPE );
        wrapperToPrimitive.put( Character.class, Character.TYPE );
        wrapperToPrimitive.put( Integer.class, Integer.TYPE );
        wrapperToPrimitive.put( Long.class, Long.TYPE );
        wrapperToPrimitive.put( Float.class, Float.TYPE );
        wrapperToPrimitive.put( Double.class, Double.TYPE );
    }

    private static void loadReflectionPermissions()
    {
        Properties props = new Properties();
        InputStream in = null;
        try
        {
            in = BaseRemotingHandler.class.getResourceAsStream( "/ejoe-reflection-conf.properties" );
            props.load( in );
        }
        catch ( Exception e )
        {
            logger
                    .log(
                          Level.INFO,
                          "No customized ejoe-reflection-conf.properties found on classpath! If you don't want to use"
                                  + " the default reflection permissions (META-INF/ejoe-reflection-conf.properties) "
                                  + " make sure you have placed a valid ejoe-reflection-conf.properties file in your classpath." );
            try
            {
                in = BaseRemotingHandler.class.getResourceAsStream( "/META-INF/ejoe-reflection-conf.properties" );
                props.load( in );
            }
            catch ( Exception ioe )
            {
                logger.log( Level.SEVERE,
                            "Reflection permissions could no be read from /META-INF/ejoe-reflection-conf.properties!!! "
                                    + " No remote reflection will be available in EJServer!" );
            }
        }
        finally
        {
            IOUtil.closeQuiet( in );
        }

        if ( props != null )
        {
            String name = null;
            reflectionPermissions = new String[props.size()];
            int count = 0;

            for ( Iterator it = props.keySet().iterator(); it.hasNext(); )
            {
                name = (String) it.next();
                reflectionPermissions[count] = name;
                count++;
            }
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see de.netseeker.ejoe.handler.ServerHandler#handle(java.lang.Object)
     */
    public Object handle( Object params ) throws Exception
    {
        RemotingRequest request = (RemotingRequest) params;

        if ( request.getClazz() == null )
        {
            throw new IllegalArgumentException( "Parameter \"targetClass\" not found in request!" );
        }

        if ( request.getMethod() == null )
        {
            throw new IllegalArgumentException( "Parameter \"targetMethod\" not found in request!" );
        }

        Class clazz = getClassByName( request.getClazz() );

        if ( clazz.isInterface() )
        {
            throw new IllegalArgumentException( "Parameter \"targetClass\" must not be an interface!" );
        }
        else if ( clazz.isPrimitive() )
        {
            throw new IllegalArgumentException( "Parameter \"targetClass\" must not be an primitive!" );
        }

        return handle( clazz, request.getMethod(), request.getArgs() );
    }

    /**
     * Returns the appropiate wrapper type for the given primitive type, eg. Integer for int
     *
     * @param primitive primitive java type
     * @return appropiate java wrapper type
     */
    public static Class getWrapperForPrimitive( Class primitive )
    {
        return (Class) primitiveToWrapper.get( primitive );
    }

    /**
     * Returns the appropiate primitive type for the given wrapper type, eg. int for Integer
     *
     * @param wrapper java wrapper type
     * @return appropiate java primitive type
     */
    public static Class getPrimitiveForWrapper( Class wrapper )
    {
        return (Class) wrapperToPrimitive.get( wrapper );
    }

    /**
     * Either loads a class via reflection or (if already cached) from a Class-cache
     *
     * @param cName complete name of the class with package names
     * @return a Class
     * @throws ClassNotFoundException
     */
    protected Class getClassByName( String cName ) throws ClassNotFoundException, AccessControlException
    {
        // first try to get the Class-object from cache
        Class clazz = (Class) classCache.get( cName );

        // ok, never loaded this class before or it was removed from cache
        if ( clazz == null )
        {
            if ( isReflectionPermitted( cName ) )
            {
                clazz = Class.forName( cName );
                classCache.put( cName, clazz );
            }
            else
            {
                throw new AccessControlException( "EJOE does not permit usage of \"" + cName
                        + "\" for remote reflection calls!" );
            }
        }

        return clazz;
    }

    private final boolean isReflectionPermitted( String className )
    {
        if ( permissionCache.contains( className ) ) return true;

        String entry = null, subName = className;
        int index = -1;

        for ( int i = 0; i < reflectionPermissions.length; i++ )
        {
            entry = reflectionPermissions[i];
            if ( entry.equals( className ) )
            {
                permissionCache.add( className );
                return true;
            }
            if ( entry.endsWith( "*" ) )
            {
                index = subName.lastIndexOf( '.' );
                while ( index != -1 )
                {
                    subName = subName.substring( 0, index );
                    if ( entry.startsWith( subName ) )
                    {
                        permissionCache.add( className );
                        return true;
                    }
                    index = subName.lastIndexOf( '.' );
                }
            }
        }

        return false;
    }

    /*
     * (non-Javadoc)
     *
     * @see de.netseeker.ejoe.handler.ClassRegistry#registerClassMapping(java.lang.String, java.lang.String)
     */
    public void registerClassMapping( String clazz, String alias )
    {
        if ( !classCache.containsKey( alias ) )
        {
            try
            {
                Class theClass = Class.forName( clazz );
                classCache.put( alias, theClass );
                classCache.put( clazz, theClass );
            }
            catch ( ClassNotFoundException e )
            {
                logger.log( Level.SEVERE, e.getMessage(), e );
            }
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see de.netseeker.ejoe.handler.ClassRegistry#deRegisterClassMapping(java.lang.String)
     */
    public boolean deRegisterClassMapping( String alias )
    {
        Class theClass = (Class) classCache.get( alias );
        boolean removed = false;

        if ( theClass != null )
        {
            classCache.remove( alias );
            classCache.remove( theClass.getName() );
            removed = true;
        }

        return removed;
    }

    /**
     * @param target
     * @param method
     * @param args
     * @return
     */
    abstract Object handle( Class target, String method, Object[] args ) throws Exception;
}
TOP

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

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.