Package org.codehaus.loom.components.configuration.merger

Source Code of org.codehaus.loom.components.configuration.merger.ConfigurationMerger

/* ====================================================================
* Loom Software License, version 1.1
*
* Copyright (c) 2003, Loom Group. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. Neither the name of the Loom Group nor the name "Loom" nor
*    the names of its contributors may be used to endorse or promote
*    products derived from this software without specific prior
*    written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* ====================================================================
*
* Loom includes code from the Apache Software Foundation
*
* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 1997-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment:
*    "This product includes software developed by the
*    Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software
*    itself, if and wherever such third-party acknowledgments
*    normally appear.
*
* 4. The names "Jakarta", "Avalon", and "Apache Software Foundation"
*    must not be used to endorse or promote products derived from this
*    software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
*    nor may "Apache" appear in their name, without prior written
*    permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package org.codehaus.loom.components.configuration.merger;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.codehaus.dna.Configuration;
import org.codehaus.dna.ConfigurationException;
import org.codehaus.dna.impl.DefaultConfiguration;

/**
* The ConfigurationMerger will take a Configuration object and layer it over
* another.
*
* It will use special attributes on the layer's children to control how
* children of the layer and base are combined. In order for a child of the
* layer to be merged with a child of the base, the following must hold true:
* <ol> <li>The child in the <b>layer</b> Configuration has an attribute named
* <code>phoenix-configuration:merge</code> and its value is equal to a boolean
* <code>TRUE</code> </li> <li>There must be a single child in both the layer
* and base with the same getName() <b>OR</b> there exists an attribute named
* <code>phoenix-configuration:key-attribute</code> that names an attribute that
* exists on both the layer and base that can be used to match multiple children
* of the same getName() </li> </ol>
*
* @author <a href="mailto:proyal@apache.org">Peter Royal</a>
* @see ConfigurationSplitter
*/
public class ConfigurationMerger
{
    /**
     * Merge two configurations.
     *
     * @param layer Configuration to <i>layer</i> over the base
     * @param base Configuration <i>layer</i> will be merged with
     * @return Result of merge
     * @throws ConfigurationException if unable to merge
     */
    public static Configuration merge( final Configuration layer,
                                       final Configuration base )
        throws ConfigurationException
    {
        final DefaultConfiguration merged =
            new DefaultConfiguration( base.getName(),
                                      base.getPath(),
                                      "Merged [layer: " +
                                      layer.getLocation()
                                      + ", base: " + base.getLocation() + "]" );

        copyAttributes( base, merged );
        copyAttributes( layer, merged );

        mergeChildren( layer, base, merged );

        final String value = getValue( layer, base );
        if( null != value )
        {
            merged.setValue( value );
        }

        return merged;
    }

    private static void mergeChildren( final Configuration layer,
                                       final Configuration base,
                                       final DefaultConfiguration merged )
        throws ConfigurationException
    {
        final Configuration[] lc = layer.getChildren();
        final Configuration[] bc = base.getChildren();
        final Set baseUsed = new HashSet();
        final List toMergeUsed = new ArrayList();

        for( int i = 0; i < lc.length; i++ )
        {
            final Configuration mergeWith =
                getMergePartner( lc[ i ], layer, base );

            if( null == mergeWith )
            {
                toMergeUsed.add( lc[ i ] );
            }
            else
            {
                toMergeUsed.add( merge( lc[ i ], mergeWith ) );
                baseUsed.add( mergeWith );
            }
        }

        for( int i = 0; i < bc.length; i++ )
        {
            if( !baseUsed.contains( bc[ i ] ) )
            {
                merged.addChild( bc[ i ] );
            }
        }

        final int count = toMergeUsed.size();
        for( int i = 0; i < count; i++ )
        {
            merged.addChild( (Configuration)toMergeUsed.get( i ) );
        }
    }

    private static Configuration getMergePartner( final Configuration toMerge,
                                                  final Configuration layer,
                                                  final Configuration base )
        throws ConfigurationException
    {
        if( toMerge.getAttributeAsBoolean( Constants.MERGE_ATTR, false ) )
        {
            final String keyAttribute = toMerge.getAttribute(
                Constants.KEY_ATTR, null );
            final String keyvalue =
                keyAttribute == null ?
                null :
                toMerge.getAttribute( keyAttribute );

            final Configuration[] layerKids = match( layer,
                                                     toMerge.getName(),
                                                     keyAttribute,
                                                     keyvalue );

            final Configuration[] baseKids = match( base,
                                                    toMerge.getName(),
                                                    keyAttribute,
                                                    keyvalue );

            if( layerKids.length == 1 && baseKids.length == 1 )
            {
                return baseKids[ 0 ];
            }
            else
            {
                throw new ConfigurationException( "Unable to merge configuration item, "
                                                  +
                                                  "multiple matches on child or base [name: "
                                                  + toMerge.getName() + "]",
                                                  toMerge.getPath(),
                                                  toMerge.getLocation() );
            }
        }

        return null;
    }

    private static String getValue( final Configuration layer,
                                    final Configuration base )
    {
        try
        {
            return layer.getValue();
        }
        catch( ConfigurationException e )
        {
            return base.getValue( null );
        }
    }

    private static void copyAttributes( final Configuration source,
                                        final DefaultConfiguration dest )
        throws ConfigurationException
    {
        final String[] names = source.getAttributeNames();

        for( int i = 0; i < names.length; i++ )
        {
            if( !names[ i ].startsWith( Constants.MERGE_METADATA_PREFIX ) )
            {
                dest.setAttribute( names[ i ],
                                   source.getAttribute( names[ i ] ) );
            }
        }
    }

    /**
     * Return all occurance of a configuration child containing the supplied
     * attribute name.
     *
     * @param config the configuration
     * @param element the name of child elements to select from the
     * configuration
     * @param attribute the attribute name to filter (null will match any
     * attribute name)
     * @return an array of configuration instances matching the query
     */
    public static Configuration[] match( final Configuration config,
                                         final String element,
                                         final String attribute )
    {
        return match( config, element, attribute, null );
    }

    /**
     * Return occurance of a configuration child containing the supplied
     * attribute name and value.
     *
     * @param config the configuration
     * @param element the name of child elements to select from the
     * configuration
     * @param attribute the attribute name to filter (null will match any
     * attribute name )
     * @param value the attribute value to match (null will match any attribute
     * value)
     * @return an array of configuration instances matching the query
     */
    public static Configuration[] match( final Configuration config,
                                         final String element,
                                         final String attribute,
                                         final String value )
    {
        final ArrayList list = new ArrayList();
        final Configuration[] children = config.getChildren( element );

        for( int i = 0; i < children.length; i++ )
        {
            if( null == attribute )
            {
                list.add( children[ i ] );
            }
            else
            {
                final String v =
                    children[ i ].getAttribute( attribute, null );

                if( v != null )
                {
                    if( (value == null) || v.equals( value ) )
                    {
                        // it's a match
                        list.add( children[ i ] );
                    }
                }
            }
        }

        return (Configuration[])list.toArray( new Configuration[ list.size() ] );
    }
}
TOP

Related Classes of org.codehaus.loom.components.configuration.merger.ConfigurationMerger

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.