KickJava   Java API By Example, From Geeks To Geeks.

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


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
55 import org.apache.avalon.framework.configuration.Configuration;
56 import org.apache.avalon.framework.configuration.ConfigurationException;
57 import org.apache.avalon.framework.configuration.DefaultConfiguration;
58 import org.apache.excalibur.configuration.ConfigurationUtil;
59
60 /**
61  * The ConfigurationSplitter will take two Configuration objects and calculate the
62  * differences between them.
63  *
64  * The resulting Configuration will contain special attribute that can be used by the
65  * ConfigurationMerger to reconstruct the original Configuration
66  *
67  * @see ConfigurationMerger
68  * @author <a HREF="mailto:proyal@apache.org">Peter Royal</a>
69  */

70 public class ConfigurationSplitter
71 {
72     /**
73      * Split a configuration, given a merged configuration and a base configuration.
74      * Functionally equivalent to producing a <i>diff</i> between the merged and base.
75      *
76      * @param merged Configuration that is a combination of the <i>result</i> and
77      * the <i>base</i> param
78      * @param base Configuration that when merged with the <i>result</i> will yield the
79      * <i>merged</i> param
80      *
81      * @return a Configuration that when merged with the <i>base</i> will yeild the
82      * <i>merged</i>
83      *
84      * @throws ConfigurationException if unable to split
85      */

86     public static Configuration split( final Configuration merged, final Configuration base )
87         throws ConfigurationException
88     {
89         final DefaultConfiguration layer = doSplit( merged, base, false );
90
91         layer.makeReadOnly();
92
93         return layer;
94     }
95
96     private static DefaultConfiguration doSplit( final Configuration merged,
97                                                  final Configuration base,
98                                                  final boolean isMerged )
99         throws ConfigurationException
100     {
101         final DefaultConfiguration layer =
102             new DefaultConfiguration( base.getName(),
103                                       "Merged [merged: " + merged.getLocation()
104                                       + ", base: " + base.getLocation() + "]" );
105
106         copyAttributes( layer, merged, base );
107         copyValue( layer, merged, base );
108         copyChildren( layer, merged, base );
109
110         if( isMerged )
111         {
112             layer.setAttribute( Constants.MERGE_ATTR, "true" );
113         }
114
115         return layer;
116     }
117
118     private static DefaultConfiguration doSplit( final Configuration merged,
119                                                  final Configuration base,
120                                                  final String JavaDoc keyAttr )
121         throws ConfigurationException
122     {
123         final DefaultConfiguration layer = doSplit( merged, base, true );
124
125         if( null != keyAttr )
126         {
127             layer.setAttribute( Constants.KEY_ATTR, keyAttr );
128         }
129
130         return layer;
131     }
132
133     private static void copyChildren( final DefaultConfiguration layer,
134                                       final Configuration merged,
135                                       final Configuration base )
136         throws ConfigurationException
137     {
138         final Configuration[] kids = merged.getChildren();
139
140         for( int i = 0; i < kids.length; i++ )
141         {
142             final Configuration mergedChild = kids[ i ];
143             final String JavaDoc name = mergedChild.getName();
144             final Configuration[] mc = merged.getChildren( name );
145             final Configuration[] bc = base.getChildren( name );
146
147             Configuration mergedWith;
148             String JavaDoc keyAttr = null;
149
150             if( bc.length > mc.length )
151             {
152                 throw new UnsupportedOperationException JavaDoc( "Unable to mask children from base "
153                                                          + "in layer" );
154             }
155             else if( bc.length == 0 )
156             {
157                 mergedWith = null;
158             }
159             else if( mc.length == 1 && bc.length == 1 )
160             {
161                 mergedWith = bc[ 0 ];
162             }
163             else //we know that mc.length > 1 here, so find the "key" attribute
164
{
165                 keyAttr = findUniqueAttributeName( mc );
166
167                 final String JavaDoc keyValue = mergedChild.getAttribute( keyAttr );
168                 final Configuration[] matches =
169                     ConfigurationUtil.match( base, name, keyAttr, keyValue );
170
171                 if( matches.length == 1 )
172                 {
173                     mergedWith = matches[ 0 ];
174                 }
175                 else
176                 {
177                     throw new ConfigurationException( "Multiple children in base with name '"
178                                                       + name + "' and attr '" + keyAttr
179                                                       + " = " + keyValue + "'" );
180                 }
181             }
182
183             if( null == mergedWith )
184             {
185                 layer.addChild( kids[ i ] );
186             }
187             else if( !ConfigurationUtil.equals( kids[ i ], mergedWith ) )
188             {
189                 final DefaultConfiguration layerChild = doSplit( kids[ i ], mergedWith, keyAttr );
190
191                 layerChild.makeReadOnly();
192
193                 layer.addChild( layerChild );
194             }
195         }
196     }
197
198     private static String JavaDoc findUniqueAttributeName( final Configuration[] c )
199         throws ConfigurationException
200     {
201         final HashSet JavaDoc testedAttributes = new HashSet JavaDoc();
202         String JavaDoc uniqueAttr = null;
203
204         for( int i = 0; i < c.length; i++ )
205         {
206             final String JavaDoc[] attrs = c[ i ].getAttributeNames();
207
208             for( int j = 0; j < attrs.length; j++ )
209             {
210                 final String JavaDoc attr = attrs[ j ];
211
212                 if( !testedAttributes.contains( attr )
213                     && isUniqueAttribute( attr, c[ i ].getAttribute( attr ), i, c ) )
214                 {
215                     if( null == uniqueAttr )
216                     {
217                         uniqueAttr = attr;
218                     }
219                     else
220                     {
221                         throw new ConfigurationException( "Multiple unique attributes for child "
222                                                           + "[name: " + c[ 0 ].getName()
223                                                           + ", unique1: " + uniqueAttr
224                                                           + ", unique2: " + attr + "]" );
225                     }
226                 }
227                 else
228                 {
229                     testedAttributes.add( attr );
230                 }
231             }
232         }
233
234         if( null == uniqueAttr )
235         {
236             throw new ConfigurationException( "Unable to find unique attribute for "
237                                               + "children of name: " + c[ 0 ].getName() );
238         }
239
240         return uniqueAttr;
241     }
242
243     private static boolean isUniqueAttribute( final String JavaDoc attr,
244                                               final String JavaDoc value,
245                                               final int currentConfig,
246                                               final Configuration[] c )
247     {
248         for( int i = 0; i < c.length; i++ )
249         {
250             if( i != currentConfig )
251             {
252                 try
253                 {
254                     if( value.equals( c[ i ].getAttribute( attr ) ) )
255                     {
256                         return false;
257                     }
258                 }
259                 catch( ConfigurationException e )
260                 {
261                     return false;
262                 }
263             }
264         }
265
266         return true;
267     }
268
269     private static void copyValue( final DefaultConfiguration layer,
270                                    final Configuration merged,
271                                    final Configuration base )
272     {
273         final String JavaDoc value = merged.getValue( null );
274
275         if( null != value )
276         {
277             try
278             {
279                 final String JavaDoc baseValue = base.getValue();
280
281                 if( !value.equals( baseValue ) )
282                 {
283                     layer.setValue( value );
284                 }
285             }
286             catch( ConfigurationException e )
287             {
288                 layer.setValue( value );
289             }
290         }
291     }
292
293     private static void copyAttributes( final DefaultConfiguration layer,
294                                         final Configuration merged,
295                                         final Configuration base )
296         throws ConfigurationException
297     {
298         final String JavaDoc[] mergedAttr = merged.getAttributeNames();
299
300         for( int i = 0; i < mergedAttr.length; i++ )
301         {
302             final String JavaDoc value = merged.getAttribute( mergedAttr[ i ] );
303
304             try
305             {
306                 final String JavaDoc baseValue = base.getAttribute( mergedAttr[ i ] );
307
308                 if( !value.equals( baseValue ) )
309                 {
310                     layer.setAttribute( mergedAttr[ i ], value );
311                 }
312             }
313             catch( ConfigurationException e )
314             {
315                 //not in base add to layer
316
layer.setAttribute( mergedAttr[ i ], value );
317             }
318         }
319     }
320
321 }
322
Popular Tags