Package org.x2jb.bind

Source Code of org.x2jb.bind.HandlersRepository

/*
* XML 2 Java Binding (X2JB) - the excellent Java tool.
* Copyright 2009, by Richard Opalka.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not see the FSF site:
* http://www.fsf.org/ and search for the LGPL License document there.
*/
package org.x2jb.bind;

import java.io.IOException;
import java.io.InputStream;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.x2jb.bind.Messages.BundleKey;
import org.x2jb.bind.spi.handler.AttributeHandler;
import org.x2jb.bind.spi.handler.ElementHandler;

/**
* <code>HandlersRepository</code> holds default and user defined primitive type handlers.
* Each handler must implement either {@link ElementHandler} or {@link AttributeHandler} interface.
*
* @author <a href="mailto:richard_opalka@yahoo.com">Richard Opalka</a>
*/
final class HandlersRepository
{

    /**
     * Default handles config file location.
     */
    private static final String DEFAULT_HANDLERS = "META-INF/x2jb.handlers";
    /**
     * Default element handlers cache.
     */
    private static final Map< String, Object > DEFAULT_ELEMENT_HANDLERS = new HashMap< String, Object >();
    /**
     * Default attribute handlers cache.
     */
    private static final Map< String, Object > DEFAULT_ATTRIBUTE_HANDLERS = new HashMap< String, Object >();
    /**
     * User element handlers cache.
     */
    private static final Map< String, Object > USER_ELEMENT_HANDLERS = new HashMap< String, Object >();
    /**
     * User attribute handlers cache.
     */
    private static final Map< String, Object > USER_ATTRIBUTE_HANDLERS = new HashMap< String, Object >();
    /**
     * Repository lock.
     */
    private static Object repositoryLock = new Object();

    /**
     * Constructor.
     */
    private HandlersRepository()
    {
        // no instances
    }

    static
    {
        HandlersRepository.instantiateAllDefaultHandlers();
    }

    /**
     * Instantiates all default handlers registered in property file.
     * @throws RuntimeException if there was some problem during handler instantiation
     */
    private static void instantiateAllDefaultHandlers()
    {
        // not initialized yet
        final InputStream repositoryProps = AccessController.doPrivileged(
            new PrivilegedAction< InputStream >()
            {
                public InputStream run()
                {
                    return HandlersRepository.class.
                        getClassLoader().
                            getResourceAsStream( HandlersRepository.DEFAULT_HANDLERS );
                }
            }
        );
       

        if ( repositoryProps == null )
        {
            throw new BindingException
            (
                Messages.get( BundleKey.UNABLE_TO_READ_PROPERTY_FILE, HandlersRepository.DEFAULT_HANDLERS )
            );
        }

        // load properties
        final Properties props = new Properties();
        try
        {
            props.load( repositoryProps );
        }
        catch ( IOException ioe )
        {
            throw new BindingException
            (
                Messages.get( BundleKey.UNABLE_TO_READ_PROPERTY_FILE, HandlersRepository.DEFAULT_HANDLERS ), ioe
            );
        }

        // instantiate handlers
        for ( final Iterator<Object> i = props.keySet().iterator(); i.hasNext(); )
        {
            final String handlerOutputClass = ( String ) i.next();
            final String handlerClassName = props.getProperty( handlerOutputClass );
            final Object handler = HandlersRepository.instantiateHandler( handlerClassName );
            if ( handler instanceof ElementHandler )
            {
                // register element binding handler
                HandlersRepository.DEFAULT_ELEMENT_HANDLERS.put( handlerOutputClass, handler );
            }
            if ( handler instanceof AttributeHandler )
            {
                // register attribute binding handler
                HandlersRepository.DEFAULT_ATTRIBUTE_HANDLERS.put( handlerOutputClass, handler );
            }
        }
    }

    /**
     * Returns true if handler specified in binding exists, false otherwise.
     *
     * @param bean meta data
     * @param failIfNotFound if set to true and handler doesn't exist, <code>BindingException</code> will be thrown
     * @return true if handler exists, false otherwise
     */
    static boolean handlerExists( final BeanImpl bean, final boolean failIfNotFound )
    {
        return HandlersRepository.getHandler( bean, failIfNotFound ) != null;
    }

    /**
     * Binds XML element to object.
     *
     * @param value element which content will be used for object creation
     * @param bean meta data
     * @return instance of <code>clazz</code> class
     */
    static Object bindElementToObject( final Element value, final BeanImpl bean )
    {
        final Class< ? > handlerClass = bean.getTypeHandler();
        final Class< ? > clazz = bean.getType();
        ElementHandler handler;

        if ( handlerClass == null )
        {
            handler = ( ElementHandler ) HandlersRepository.getDefaultHandler( bean, true );
        }
        else
        {
            handler = ( ElementHandler ) HandlersRepository.getUserHandler( bean, true );
        }

        return handler.bind( value, clazz );
    }

    /**
     * Binds XML element array to object array.
     *
     * @param values XML elements which content will be used for objects creation
     * @param bean meta data
     * @return one dimensional array of instances of <code>clazz</code> class
     */
    static Object bindElementsToObjectArray( final List< Element > values, final BeanImpl bean )
    {
        final Class< ? > clazz = bean.getType();
        final Object array = ReflectionUtils.newArrayInstance( clazz, values.size() );
        final Class< ? > handlerClass = bean.getTypeHandler();
        ElementHandler handler;

        if ( handlerClass == null )
        {
            handler = ( ElementHandler ) HandlersRepository.getDefaultHandler( bean, true );
        }
        else
        {
            handler = ( ElementHandler ) HandlersRepository.getUserHandler( bean, true );
        }

        for ( int index = 0; index < values.size(); index++ )
        {
            final Object boundValue = handler.bind( values.get( index ), clazz );
            ReflectionUtils.setArrayValue( array, index, boundValue );
        }

        return array;
    }

    /**
     * Binds XML attribute value to object.
     *
     * @param value attribute which value will be used for object creation
     * @param bean meta data
     * @return instance of <code>clazz</code> class
     */
    static Object bindAttributeToObject( final Attr value, final BeanImpl bean )
    {
        final Class< ? > handlerClass = bean.getTypeHandler();
        final Class< ? > clazz = bean.getType();
        AttributeHandler handler;

        if ( handlerClass == null )
        {
            handler = ( AttributeHandler ) HandlersRepository.getDefaultHandler( bean, true );
        }
        else
        {
            handler = ( AttributeHandler ) HandlersRepository.getUserHandler( bean, true );
        }

        return handler.bind( value, clazz );
    }

    /**
     * Returns default value associated with the missing XML node.
     *
     * @param defaultValue default value
     * @param bean meta data
     * @return instance of <code>clazz</code> class
     */
    static Object getDefaultValue( final String defaultValue, final BeanImpl bean )
    {
        final Object handler;

        if ( bean.getTypeHandler() == null )
        {
            handler = HandlersRepository.getDefaultHandler( bean, true );
        }
        else
        {
            handler = HandlersRepository.getUserHandler( bean, true );
        }

        if ( handler instanceof ElementHandler )
        {
            return ( ( ElementHandler ) handler ).getDefault( defaultValue, bean.getType() );
        }
        else
        {
            return ( ( AttributeHandler ) handler ).getDefault( defaultValue, bean.getType() );
        }
    }

    /**
     * Returns handler instance or <code>BindingException</code> if there was a problem during handler instantiation.
     *
     * @param handlerName name of the handler to instantiate. Handler must contain default public constructor
     * @return BindingHandler created instance
     */
    private static Object instantiateHandler( final String handlerName )
    {
        final ClassLoader classLoader = HandlersRepository.class.getClassLoader();
        final Class< ? > handlerClass = ReflectionUtils.getClass( handlerName, classLoader );
        return HandlersRepository.instantiateHandler( handlerClass );
    }

    /**
     * Returns handler instance or <code>BindingException</code> if there was a problem during handler instantiation.
     *
     * @param handlerClass handler class to instantiate. Handler must contain default public constructor
     * @return BindingHandler created instance
     */
    private static Object instantiateHandler( final Class< ? > handlerClass )
    {
        try
        {
            return handlerClass.newInstance();
        }
        catch ( IllegalAccessException iae )
        {
            throw new BindingException
            (
                Messages.get( BundleKey.UNABLE_TO_INSTANTIATE_HANDLER, handlerClass.getName() ), iae
            );
        }
        catch ( InstantiationException ie )
        {
            throw new BindingException
            (
                Messages.get( BundleKey.UNABLE_TO_INSTANTIATE_HANDLER, handlerClass.getName() ), ie
            );
        }
    }

    /**
     * Returns default handler instance or null if handler doesn't exist.
     *
     * @param bean meta data
     * @param failIfNotFound forces this method to throw BindingException if required handler will not be found
     * @return default element or attribute binding handler
     */
    private static Object getDefaultHandler( final BeanImpl bean, final boolean failIfNotFound )
    {
        final boolean elementHandler = bean.isElementNode();

        final Map< String, Object > handlers;
        if ( elementHandler )
        {
            handlers = HandlersRepository.DEFAULT_ELEMENT_HANDLERS;
        }
        else
        {
            handlers = HandlersRepository.DEFAULT_ATTRIBUTE_HANDLERS;
        }

        final Class< ? > clazz = bean.getType();
        final Object handler = handlers.get( clazz.getName() );
        if ( handler != null )
        {
            return handler;
        }

        // handler not found
        if ( failIfNotFound )
        {
            throw new BindingException
            (
                Messages.get
                (
                    BundleKey.DEFAULT_HANDLER_NOT_FOUND,
                    elementHandler ? "element" : "attribute", clazz.getName()
                )
            );
        }
        else
        {
            return null;
        }
    }

    /**
     * Returns user handler creating <b>clazz</b> instances or null if such handler doesn't exist.
     *
     * @param bean meta data
     * @param failIfNotFound forces this method to throw BindingException if required handler will not be found
     * @return element or attribute binding handler
     */
    private static Object getUserHandler( final BeanImpl bean, final boolean failIfNotFound )
    {
        final Class< ? > clazz = bean.getType();
        final Class< ? > handlerClass = bean.getTypeHandler();
        final boolean elementHandler = bean.isElementNode();
        Object handler = null;

        synchronized ( HandlersRepository.repositoryLock )
        {
            handler = HandlersRepository.getCachedUserHandler( elementHandler, handlerClass );

            if ( handler == null )
            {
                handler = HandlersRepository.createAndCacheHandler( elementHandler, handlerClass );
            }
        }

        final boolean isElementOrAttributeHandler = ( handler instanceof ElementHandler ) ||
            ( handler instanceof AttributeHandler );

        if ( ( handler != null ) && isElementOrAttributeHandler )
        {
            return handler;
        }

        // handler not found
        if ( failIfNotFound )
        {
            throw new BindingException
            (
                Messages.get
                (
                    BundleKey.CUSTOM_HANDLER_NOT_FOUND,
                    elementHandler ? "Element" : "Attribute", handlerClass.getName(), clazz.getName()
                )
            );
        }

        return null;
    }

    /**
     * Returns cached user handler or null.
     *
     * @param elementHandler indicates whether element or attribute handler should be returned
     * @param handlerClass handler to return
     * @return cached user handler or null
     */
    private static Object getCachedUserHandler( final boolean elementHandler, final Class< ? > handlerClass )
    {
        if ( elementHandler )
        {
            return HandlersRepository.USER_ELEMENT_HANDLERS.get( handlerClass.getName() );
        }
        else
        {
            return HandlersRepository.USER_ATTRIBUTE_HANDLERS.get( handlerClass.getName() );
        }
    }

    /**
     * Instantiates handler and puts it to user caches.
     *
     * @param handlerClass handler
     */
    private static void loadAndCacheUserHandler( final Class< ? > handlerClass )
    {
        final Object handler = HandlersRepository.instantiateHandler( handlerClass );

        if ( handler instanceof ElementHandler )
        {
            HandlersRepository.USER_ELEMENT_HANDLERS.put( handlerClass.getName(), handler );
        }

        if ( handler instanceof AttributeHandler )
        {
            HandlersRepository.USER_ATTRIBUTE_HANDLERS.put( handlerClass.getName(), handler );
        }
    }

    /**
     * Creates and caches user handler.
     *
     * @param elementHandler indicates whether attribute or element handler
     * @param handlerClass to return
     * @return created handler or null if not exists
     */
    private static Object createAndCacheHandler( final boolean elementHandler, final Class< ? > handlerClass )
    {
        HandlersRepository.loadAndCacheUserHandler( handlerClass );

        if ( elementHandler )
        {
            return HandlersRepository.USER_ELEMENT_HANDLERS.get( handlerClass.getName() );
        }
        else
        {
            return HandlersRepository.USER_ATTRIBUTE_HANDLERS.get( handlerClass.getName() );
        }
    }

    /**
     * Returns handler instance if handler specified in binding exists, null otherwise.
     *
     * @param bean meta data
     * @param failIfNotFound if set to true and handler doesn't exist, <code>BindingException</code> will be thrown
     * @return handler instance if handler specified in binding exists, null otherwise
     */
    static Object getHandler( final BeanImpl bean, final boolean failIfNotFound )
    {
        final Object handler;

        if ( bean.getTypeHandler() == null )
        {
            handler = HandlersRepository.getDefaultHandler( bean, failIfNotFound );
        }
        else
        {
            handler = HandlersRepository.getUserHandler( bean, failIfNotFound );
        }

        return handler;
    }

}
TOP

Related Classes of org.x2jb.bind.HandlersRepository

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.