KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > excalibur > configuration > merged > ConfigurationMerger


1 /*
2
3  ============================================================================
4                    The Apache Software License, Version 1.1
5  ============================================================================
6  
7  Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
8  
9  Redistribution and use in source and binary forms, with or without modifica-
10  tion, are permitted provided that the following conditions are met:
11  
12  1. Redistributions of source code must retain the above copyright notice,
13     this list of conditions and the following disclaimer.
14  
15  2. Redistributions in binary form must reproduce the above copyright notice,
16     this list of conditions and the following disclaimer in the documentation
17     and/or other materials provided with the distribution.
18  
19  3. The end-user documentation included with the redistribution, if any, must
20     include the following acknowledgment: "This product includes software
21     developed by the Apache Software Foundation (http://www.apache.org/)."
22     Alternately, this acknowledgment may appear in the software itself, if
23     and wherever such third-party acknowledgments normally appear.
24  
25  4. The names "Jakarta", "Avalon", "Excalibur" and "Apache Software Foundation"
26     must not be used to endorse or promote products derived from this software
27     without prior written permission. For written permission, please contact
28     apache@apache.org.
29  
30  5. Products derived from this software may not be called "Apache", nor may
31     "Apache" appear in their name, without prior written permission of the
32     Apache Software Foundation.
33  
34  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
35  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
36  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
37  APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
38  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
39  DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
40  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
41  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
43  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44  
45  This software consists of voluntary contributions made by many individuals
46  on behalf of the Apache Software Foundation. For more information on the
47  Apache Software Foundation, please see <http://www.apache.org/>.
48
49 */

50
51 package org.apache.excalibur.configuration.merged;
52
53 import java.util.HashSet JavaDoc;
54 import java.util.Set JavaDoc;
55
56 import org.apache.avalon.framework.configuration.Configuration;
57 import org.apache.avalon.framework.configuration.ConfigurationException;
58 import org.apache.avalon.framework.configuration.DefaultConfiguration;
59 import org.apache.excalibur.configuration.ConfigurationUtil;
60
61 /**
62  * The ConfigurationMerger will take a Configuration object and layer it over another.
63  *
64  * It will use special attributes on the layer's children to control how children
65  * of the layer and base are combined. In order for a child of the layer to be merged with a
66  * child of the base, the following must hold true:
67  * <ol>
68  * <li>The child in the <b>layer</b> Configuration has an attribute named
69  * <code>phoenix-configuration:merge</code> and its value is equal to a boolean
70  * <code>TRUE</code>
71  * </li>
72  * <li>There must be a single child in both the layer and base with the same getName() <b>OR</b>
73  * there exists an attribute named <code>phoenix-configuration:key-attribute</code>
74  * that names an attribute that exists on both the layer and base that can be used to match
75  * multiple children of the same getName()
76  * </li>
77  * </ol>
78  *
79  * @see ConfigurationSplitter
80  * @author <a HREF="mailto:proyal@apache.org">Peter Royal</a>
81  */

82 public class ConfigurationMerger
83 {
84     /**
85      * Merge two configurations.
86      *
87      * @param layer Configuration to <i>layer</i> over the base
88      * @param base Configuration <i>layer</i> will be merged with
89      *
90      * @return Result of merge
91      *
92      * @exception ConfigurationException if unable to merge
93      */

94     public static Configuration merge( final Configuration layer, final Configuration base )
95         throws ConfigurationException
96     {
97         final DefaultConfiguration merged =
98             new DefaultConfiguration( base.getName(),
99                                       "Merged [layer: " + layer.getLocation()
100                                       + ", base: " + base.getLocation() + "]" );
101
102         copyAttributes( base, merged );
103         copyAttributes( layer, merged );
104
105         mergeChildren( layer, base, merged );
106
107         merged.setValue( getValue( layer, base ) );
108         merged.makeReadOnly();
109
110         return merged;
111     }
112
113     private static void mergeChildren( final Configuration layer,
114                                        final Configuration base,
115                                        final DefaultConfiguration merged )
116         throws ConfigurationException
117     {
118         final Configuration[] lc = layer.getChildren();
119         final Configuration[] bc = base.getChildren();
120         final Set JavaDoc baseUsed = new HashSet JavaDoc();
121
122         for( int i = 0; i < lc.length; i++ )
123         {
124             final Configuration mergeWith = getMergePartner( lc[ i ], layer, base );
125
126             if( null == mergeWith )
127             {
128                 merged.addChild( lc[ i ] );
129             }
130             else
131             {
132                 merged.addChild( merge( lc[ i ], mergeWith ) );
133
134                 baseUsed.add( mergeWith );
135             }
136         }
137
138         for( int i = 0; i < bc.length; i++ )
139         {
140             if( !baseUsed.contains( bc[ i ] ) )
141             {
142                 merged.addChild( bc[ i ] );
143             }
144         }
145     }
146
147     private static Configuration getMergePartner( final Configuration toMerge,
148                                                   final Configuration layer,
149                                                   final Configuration base )
150         throws ConfigurationException
151     {
152         if( toMerge.getAttributeAsBoolean( Constants.MERGE_ATTR, false ) )
153         {
154             final String JavaDoc keyAttribute = toMerge.getAttribute( Constants.KEY_ATTR, null );
155             final String JavaDoc keyvalue =
156                 keyAttribute == null ? null : toMerge.getAttribute( keyAttribute );
157
158             final Configuration[] layerKids = ConfigurationUtil.match( layer,
159                                                                        toMerge.getName(),
160                                                                        keyAttribute,
161                                                                        keyvalue );
162
163             final Configuration[] baseKids = ConfigurationUtil.match( base,
164                                                                       toMerge.getName(),
165                                                                       keyAttribute,
166                                                                       keyvalue );
167
168             if( layerKids.length == 1 && baseKids.length == 1 )
169             {
170                 return baseKids[ 0 ];
171             }
172             else
173             {
174                 throw new ConfigurationException( "Unable to merge configuration item, "
175                                                   + "multiple matches on child or base [name: "
176                                                   + toMerge.getName() + "]" );
177             }
178         }
179
180         return null;
181     }
182
183     private static String JavaDoc getValue( final Configuration layer, final Configuration base )
184     {
185         try
186         {
187             return layer.getValue();
188         }
189         catch( ConfigurationException e )
190         {
191             return base.getValue( null );
192         }
193     }
194
195     private static void copyAttributes( final Configuration source,
196                                         final DefaultConfiguration dest )
197         throws ConfigurationException
198     {
199         final String JavaDoc[] names = source.getAttributeNames();
200
201         for( int i = 0; i < names.length; i++ )
202         {
203             if( !names[ i ].startsWith( Constants.MERGE_METADATA_PREFIX ) )
204             {
205                 dest.setAttribute( names[ i ], source.getAttribute( names[ i ] ) );
206             }
207         }
208     }
209 }
210
Popular Tags