PropertyProxyRegistry.java :  » Google-tech » s3blazeds » flex » messaging » io » Java Open Source

Java Open Source » Google tech » s3blazeds 
s3blazeds » flex » messaging » io » PropertyProxyRegistry.java
/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * __________________
 *
 *  Copyright 2002 - 2007 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 **************************************************************************/
package flex.messaging.io;

import flex.messaging.LocalizedException;
import flex.messaging.MessageException;
import flex.messaging.io.amf.ASObject;

import javax.sql.RowSet;
import java.util.AbstractMap;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;

/**
 * Allows custom PropertyProxy's to be registered on a Class basis.
 *  
 * Class hierarchies can be optionally searched with the first match winning. 
 * The search starts by trying an exact Class match, then the immediate
 * interfaces are tried in the order that they are declared on the Class and
 * finally the process is repeated for the superclass, if one exists. If a
 * PropertyProxy is found in the immediate parent hierarchy (either the
 * immediate superclass or directly implemented interfaces) then the
 * implementing class is registered with the selected PropertyProxy to optimize
 * subsequent searches.
 */
public class PropertyProxyRegistry
{
    private final Map<Class, PropertyProxy> classRegistry = new IdentityHashMap<Class, PropertyProxy>();

    /**
     * A global registry that maps a Class type to a PropertyProxy.
     */
    private static final PropertyProxyRegistry registry = new PropertyProxyRegistry();
    static
    {
        preRegister();
    }

    /**
     * Constructs an empty PropertyProxy registry.
     */
    public PropertyProxyRegistry()
    {
        // No-op.
    }

    /**
     * Returns the static or "application scope" PropertyProxy registry. If
     * custom sets of PropertyProxies are required in different scopes then
     * new instances of PropertyProxyRegistry should be manually created,
     * however these will not be used for serialization.
     * 
     * @return The global PropertyProxy registry.
     */
    public static PropertyProxyRegistry getRegistry()
    {
        return registry;
    }

    /**
     * Call this on Message broker shutdown ONLY.
     * Clears the registry and removes the static global registry.
     */
    public static void release()
    {
        registry.clear();
    }

    
    /**
     * Pre-registers a few common types that are often proxied to 
     * speed up lookups.
     */
    private static void preRegister()
    {
        ThrowableProxy proxy = new ThrowableProxy();
        registry.register(MessageException.class, proxy);
        registry.register(LocalizedException.class, proxy);
        registry.register(Throwable.class, proxy);

        MapProxy mapProxy = new MapProxy();
        registry.register(ASObject.class, mapProxy);
        registry.register(HashMap.class, mapProxy);
        registry.register(AbstractMap.class, mapProxy);
        registry.register(Map.class, mapProxy);
    }

    /**
     * Returns a PropertyProxy suitable for the given instance and registers
     * the selected PropertyProxy for the Class of the instance. Note that 
     * the PropertyProxy is not cloned so either the PropertyProxy should be 
     * used as a template else you must first call clone() on the returned
     * PropertyProxy and then set the instance as the default on the resulting
     * clone.
     * 
     * @param instance the type to search for a suitable PropertyProxy. 
     * @return PropertyProxy suitable for the instance type.
     */
    public static PropertyProxy getProxyAndRegister(Object instance)
    {
        if (instance instanceof PropertyProxy)
            return (PropertyProxy)instance;

        Class c = instance.getClass();
        PropertyProxy proxy = getRegistry().getProxyAndRegister(c);

        if (proxy == null)
        {
            proxy = guessProxy(instance);
            getRegistry().register(c, proxy);
        }

        return proxy; 
    }

    /**
     * Returns a PropertyProxy suitable for the given instance but does not
     * register the selected PropertyProxy for the Class of the instance. Note
     * that the PropertyProxy is not cloned so either the PropertyProxy should
     * be used as a template else you must first call clone() on the returned
     * PropertyProxy and then set the instance as the default on the resulting
     * clone.
     * 
     * @param instance the type to search for a suitable PropertyProxy. 
     * @return PropertyProxy suitable for the instance type.
     */
    public static PropertyProxy getProxy(Object instance)
    {
        if (instance instanceof PropertyProxy)
            return (PropertyProxy)instance;

        Class c = instance.getClass();
        PropertyProxy proxy = getRegistry().getProxy(c);

        if (proxy == null)
        {
            proxy = guessProxy(instance);
        }

        proxy = (PropertyProxy)proxy.clone();
        proxy.setDefaultInstance(instance);
        return proxy;
    }

    /**
     * Attempts to select a suitable proxy for the given instance
     * based on common type mappings.
     * @param instance the object to examine.
     * @return a proxy for getting properties.
     */
    private static PropertyProxy guessProxy(Object instance)
    {
        PropertyProxy proxy;

        if (instance instanceof Map)
        {
            proxy = new MapProxy();
        }
        else if (instance instanceof Throwable)
        {
            proxy = new ThrowableProxy();
        }
        else if (instance instanceof PageableRowSet || instance instanceof RowSet)
        {
            proxy = new PageableRowSetProxy();
        }
        else if (instance instanceof Dictionary)
        {
            proxy = new DictionaryProxy();
        }
        else
        {
            proxy = new BeanProxy();
        }

        return proxy;
    }

    /**
     * Locates a custom PropertyProxy for the given Class. The entire class
     * hierarchy is searched. Even if a match is found in the class heirarchy
     * the PropertyProxy is not registered for the given Class. 
     * 
     * @param c the Class used to search the registry.
     * @return the custom PropertyProxy registered for the Class or
     * null if a PropertyProxy was not found or if the given Class is null.
     */
    public PropertyProxy getProxy(Class c)
    {
        return getProxy(c, true, false);
    }

    /**
     * Locates a custom PropertyProxy for the given Class. The entire class
     * hierarchy is searched. If a match is found in the class heirarchy the
     * PropertyProxy is registered for the given class.
     * 
     * @param c the Class used to search the registry.
     * @return the custom PropertyProxy registered for the Class or
     * null if a PropertyProxy was not found or if the given Class is null.
     */
    public PropertyProxy getProxyAndRegister(Class c)
    {
        return getProxy(c, true, true);
    }

    /**
     * Locates a custom PropertyProxy for the given Class. If the
     * searchHierarchy argument is true the search starts by trying an exact
     * Class match, then the immediate interfaces are tried in the order that
     * they are declared on the Class and finally the process is repeated for
     * the superclass, if one exists.  
     * 
     * @param c the Class used to search the registry.
     * @param searchHierarchy if true the entire class hierarchy is searched.
     * @param autoRegister if true a successful match is registerd for top
     * level class
     * @return the custom PropertyProxy registered for the Class or
     * null if a PropertyProxy was not found or if the given Class is null.
     */
    public PropertyProxy getProxy(Class c, boolean searchHierarchy, boolean autoRegister)
    {
        if (c == null)
            return null;

        // Check for native Array so we can unwrap for Class component type
        if (c.isArray())
            c = c.getComponentType();

        // Locate PropertyProxy by Class reference
        PropertyProxy proxy = classRegistry.get(c); 

        if (proxy == null && searchHierarchy)
        {
            // Next, try matching PropertyProxy by interface
            Class[] interfaces = c.getInterfaces();
            for (int i = 0; i < interfaces.length; i++)
            {
                Class interfaceClass = interfaces[i];
                proxy = classRegistry.get(interfaceClass);
                if (proxy != null && autoRegister)
                {
                    register(c, proxy);
                    break;
                }
                else
                {
                    // Recursively check super interfaces too
                    proxy = getProxy(interfaceClass, searchHierarchy, autoRegister);
                    if (proxy != null)
                    {
                        break;
                    }
                }
            }
        }

        if (proxy == null && searchHierarchy)
        {
            // Finally, recursively search superclass hierarchy
            Class superclass = c.getSuperclass();
            if (superclass != null)
            {
                proxy = getProxy(superclass, searchHierarchy, autoRegister);
                if (proxy != null && autoRegister)
                {
                    register(c, proxy);
                }
            }
        }

        return proxy;
    }

    /**
     * Removes all items from the class registry.
     */
    public void clear()
    {
        synchronized(classRegistry)
        {
            classRegistry.clear();
        }
    }

    /**
     * Register a custom PropertyProxy for a Class.
     * 
     * @param c The key for the class registry.
     * @param proxy The custom PropertyProxy implementation.
     */
    public void register(Class c, PropertyProxy proxy)
    {
        synchronized(classRegistry)
        {
            classRegistry.put(c, proxy);
        }
    }

    /**
     * Removes a custom PropertyProxy from the registry.
     * 
     * @param c The Class to be removed from the registry.
     */
    public void unregister(Class c)
    {
        synchronized(classRegistry)
        {
            classRegistry.remove(c);
        }
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.