All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.codehaus.plexus.configuration.PlexusConfigurationUtils Maven / Gradle / Ivy

Go to download

The Maven Site Plugin is a plugin that generates a site for the current project.

The newest version!
package org.codehaus.plexus.configuration;


/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;


/**
 * Utilities for working with {@link PlexusConfiguration} objects
 * 
 * @author Eric Dalquist
 * @version $Revision: 25140 $
 */
public final class PlexusConfigurationUtils {
    /**
     * How duplicate entries should be handled post-merge, if true they are removed, if false they are not removed.
     * Defaults to false.
     */
    public static final String REMOVE_DUPLICATE_POLICY = "merge:removeDuplicates";
    
    /**
     * Defines the various types of merge policy type attributes
     */
    public enum MergePolicyType {
        /**
         * {@link MergePolicy} to apply to the element itself
         * @see MergePolicy
         */
        SELF_MERGE_POLICY("merge:self"),
        /**
         * {@link MergePolicy} to apply to children, only applicable if the {@link MergePolicy} for the element itself is MERGE
         * @see MergePolicy
         */
        CHILDREN_MERGE_POLICY("merge:children");
        
        private final String attributeName;
        
        private MergePolicyType(String attributeName) {
            this.attributeName = attributeName;
        }
        
        /**
         * @see #getMergePolicy(PlexusConfiguration, MergePolicy)
         */
        public MergePolicy getMergePolicy(PlexusConfiguration configuration) {
            return getMergePolicy(configuration, null);
        }

        /**
         * Get the {@link MergePolicy} configured on the {@link PlexusConfiguration} for this attribute type.
         * 
         * @param configuration The configuration element
         * @param defaultMergePolicy The default value to return if no {@link MergePolicy} is specified
         */
        public MergePolicy getMergePolicy(PlexusConfiguration configuration, MergePolicy defaultMergePolicy) {
            if (configuration == null) {
                return defaultMergePolicy;
            }

            final String duplicatePolicy = configuration.getAttribute(attributeName);
            if (duplicatePolicy == null) {
                return defaultMergePolicy;
            }
            
            try {
                return MergePolicy.valueOf(duplicatePolicy);
            }
            catch (IllegalArgumentException e) {
                throw new IllegalArgumentException(
                        "Cannot assign value " + duplicatePolicy + 
                        " to property " + attributeName + " of " + configuration.getName() +  
                        ". No enum const class " + MergePolicy.class.getName() + "." +
                        duplicatePolicy);
            }
        }
    }

    /**
     * Does a deep-comparison of two PlexusConfiguration objects 
     */
    public static Comparator PLEXUS_CONFIG_COMPARATOR = new PlexusConfigurationComparator();
    
    private PlexusConfigurationUtils() {
    }
    
    /**
     * Merge two elements, treats the two elements as if {@link MergePolicyType#SELF_MERGE_POLICY} is set to
     * {@link MergePolicy#MERGE} on the secondary argument
     */
    public static PlexusConfiguration merge(PlexusConfiguration primary, PlexusConfiguration secondary) {
        //Shortcuts for null configs
        if (secondary == null) {
            return primary;
        }
        if (primary == null) {
            return secondary;
        }
        
        //Sanity check the config element names
        final String newName = secondary.getName();
        final String existingName = primary.getName();
        if (!newName.equals(existingName)) {
            throw new IllegalArgumentException("Cannot merge two PlexusConfiguration elements with different names " + 
                    newName + "!=" + existingName);
        }
        
        //Merge the attributes
        mergeAttributes(primary, secondary);
        
        if (secondary.getChildCount() == 0 && primary.getChildCount() == 0) {
            //No children, just merge (overwrite) the existing value
            final String newValue = secondary.getValue();
            primary.setValue(newValue);
            return primary;
        }
        
        if (primary.getChildCount() == 0 && primary.getValue() != null) {
            //primary has no children but has a value, convert it to a child element with the same name as the parent
            final String value = primary.getValue();
            primary.setValue(null);
            primary.addChild(primary.getName(), value);
        }
        
        if (secondary.getChildCount() == 0 && secondary.getValue() != null) {
            //secondary has no children but has a value, convert it to a child element with the same name as the parent
            final String value = secondary.getValue();
            secondary.setValue(null);
            secondary.addChild(secondary.getName(), value);
        }

        //Clone the primary config so we can overwrite children if needed 
        final MutablePlexusConfiguration mergedConfiguration = new MutablePlexusConfiguration(primary);
        
        for (final PlexusConfiguration newChildConfiguration : secondary.getChildren()) {
            final MergePolicy selfMergePolicy = MergePolicyType.SELF_MERGE_POLICY.getMergePolicy(newChildConfiguration, MergePolicy.MERGE);

            switch (selfMergePolicy) {
                case FIRST: {
                    //Only add the newChildConfiguration if there is no existing child
                    
                    final String childName = newChildConfiguration.getName();
                    final PlexusConfiguration existingChildConfiguration = mergedConfiguration.getChild(childName, false);
                    if (existingChildConfiguration == null) {
                        mergedConfiguration.addChild(newChildConfiguration);
                    }
                    
                    break;
                }
                case LAST: {
                    //Just wholesale replace the existing child
                    //If primary has more than one child with the specified name only replace the last instance
                    
                    mergedConfiguration.replaceLastChild(newChildConfiguration);
                    
                    break;
                }
                case MERGE: {
                    final MergePolicy childrenMergePolicy = MergePolicyType.CHILDREN_MERGE_POLICY.getMergePolicy(newChildConfiguration, selfMergePolicy);
                    switch (childrenMergePolicy) {
                        case BOTH: {
                            final String childName = newChildConfiguration.getName();
                            final PlexusConfiguration existingChildConfiguration = mergedConfiguration.getChild(childName, false);
                            
                            if (existingChildConfiguration == null) {
                                mergedConfiguration.addChild(newChildConfiguration);
                            }
                            else {
                                //Merge attributes
                                mergeAttributes(existingChildConfiguration, newChildConfiguration);
                                
                                //If removing duplicates create set of all existing children for easy comparison
                                final Set existingChildren;
                                final boolean removeDuplicates = Boolean.parseBoolean(newChildConfiguration.getAttribute(REMOVE_DUPLICATE_POLICY));
                                if (removeDuplicates) {
                                    existingChildren = new TreeSet(PLEXUS_CONFIG_COMPARATOR);
                                    Collections.addAll(existingChildren, existingChildConfiguration.getChildren());
                                }
                                else {
                                    existingChildren = Collections.emptySet();
                                }
                                
                                //Copy over new childrent into existing parent, not adding any new child that is in the existingChildConfiguration set
                                for (final PlexusConfiguration child : newChildConfiguration.getChildren()) {
                                    if (!existingChildren.contains(child)) {
                                        existingChildConfiguration.addChild(child);
                                    }
                                }
                            }
                            
                            break;
                        }
                        case FIRST: {
                            final String childName = newChildConfiguration.getName();
                            final PlexusConfiguration existingChildConfiguration = mergedConfiguration.getChild(childName, false);
                            if (existingChildConfiguration == null) {
                                mergedConfiguration.addChild(newChildConfiguration);
                            }
                            
                            break;
                        }
                        case LAST:
                        case MERGE: {
                            final String childName = newChildConfiguration.getName();
                            final PlexusConfiguration existingChildConfiguration = mergedConfiguration.getChild(childName);
                            final PlexusConfiguration mergedChildConfiguration = merge(existingChildConfiguration, newChildConfiguration);
                            
                            mergedConfiguration.replaceLastChild(mergedChildConfiguration);
                            break;
                        }
                    }
                    
                    break;
                }
                case BOTH: {
                    //Just add the new child
                    
                    mergedConfiguration.addChild(newChildConfiguration);
                    
                    break;
                }
            }
        }
        
        return mergedConfiguration;
    }

    /**
     * Copies attributes from the secondary config item into the primar config item
     */
    private static void mergeAttributes(PlexusConfiguration primary, PlexusConfiguration secondary) {
        //merge attributes means overwriting existing attributes with new values
        for (final String attributeName : secondary.getAttributeNames()) {
            final String value = secondary.getAttribute(attributeName);
            primary.setAttribute(attributeName, value);
        }
    }
    
    private static class PlexusConfigurationComparator implements Comparator {
        /* (non-Javadoc)
         * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
         */
        public int compare(PlexusConfiguration o1, PlexusConfiguration o2) {
            //Check name
            final int name = nullSafeCompare(o1.getName(), o2.getName());
            if (name != 0) {
                return name;
            }
            
            //Check value
            final int value = nullSafeCompare(o1.getValue(), o2.getValue());
            if (value != 0) {
                return value;
            }
    
            //Check attributes (order doesn't matter)
            final Set attrNames1 = new LinkedHashSet(Arrays.asList(o1.getAttributeNames()));
            final Set attrNames2 = new LinkedHashSet(Arrays.asList(o2.getAttributeNames()));
            if (!attrNames1.equals(attrNames2)) {
                return -1;
            }
            for (final String attrName : attrNames1) {
                final int attrComp = nullSafeCompare(o1.getAttribute(attrName), o2.getAttribute(attrName));
                if (attrComp != 0) {
                    return attrComp;
                }
            }
            
            //Check children (order matters)
            if (o1.getChildCount() < o2.getChildCount()) {
                return -1;
            }
            if (o1.getChildCount() > o2.getChildCount()) {
                return 1;
            }
            if (o1.getChildCount() > 0) {
                final PlexusConfiguration[] children1 = o1.getChildren();
                final PlexusConfiguration[] children2 = o2.getChildren();
                
                for (int index = 0; index < children1.length; index++) {
                    final int child = compare(children1[index], children2[index]);
                    if (child != 0) {
                        return child;
                    }
                }
            }
            
            return 0;
        }
    
        private > int nullSafeCompare(T o1, T o2) {
            if (o1 == o2) {
                return 0;
            }
            
            if (o1 == null) {
                return -1;
            }
            if (o2 == null) {
                return 1;
            }
            
            return o1.compareTo(o2);
        }
    };
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy