##### Coverage Report - org.apache.commons.configuration.ConfigurationUtils

Classes in this File | Line Coverage | Branch Coverage | Complexity
ConfigurationUtils |
85% | 159/186
100% | 42/42
| 4.590909090909091;4,591
ConfigurationUtils$1 |
100% | 2/2
N/A | N/A
| 4.590909090909091;4,591

1 |  |
     /*
2 |  |
      * Licensed to the Apache Software Foundation (ASF) under one or more
3 |  |
      * contributor license agreements.  See the NOTICE file distributed with
4 |  |
      * this work for additional information regarding copyright ownership.
5 |  |
      * The ASF licenses this file to You under the Apache License, Version 2.0
6 |  |
      * (the "License"); you may not use this file except in compliance with
7 |  |
      * the License.  You may obtain a copy of the License at
8 |  |
      *
9 |  |
      *     http://www.apache.org/licenses/LICENSE-2.0
10 |  |
      *
11 |  |
      * Unless required by applicable law or agreed to in writing, software
12 |  |
      * distributed under the License is distributed on an "AS IS" BASIS,
13 |  |
      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 |  |
      * See the License for the specific language governing permissions and
15 |  |
      * limitations under the License.
16 |  |
      */
17 |  |
18 |  |
     package org.apache.commons.configuration;
19 |  |
20 |  |
     import java.io.File;
21 |  |
     import java.io.IOException;
22 |  |
     import java.io.InputStream;
23 |  |
     import java.io.PrintStream;
24 |  |
     import java.io.PrintWriter;
25 |  |
     import java.io.StringWriter;
26 |  |
     import java.lang.reflect.InvocationTargetException;
27 |  |
     import java.lang.reflect.Method;
28 |  |
     import java.net.MalformedURLException;
29 |  |
     import java.net.URL;
30 |  |
     import java.net.URLDecoder;
31 |  |
     import java.util.Iterator;
32 |  |
33 |  |
     import org.apache.commons.configuration.event.ConfigurationErrorEvent;
34 |  |
     import org.apache.commons.configuration.event.ConfigurationErrorListener;
35 |  |
     import org.apache.commons.configuration.event.EventSource;
36 |  |
     import org.apache.commons.configuration.tree.ExpressionEngine;
37 |  |
     import org.apache.commons.lang.StringUtils;
38 |  |
     import org.apache.commons.lang.SystemUtils;
39 |  |
     import org.apache.commons.logging.Log;
40 |  |
     import org.apache.commons.logging.LogFactory;
41 |  |
42 |  |
     /**
43 |  |
      * Miscellaneous utility methods for configurations.
44 |  |
      *
45 |  |
      * @see ConfigurationConverter Utility methods to convert configurations.
46 |  |
      *
47 |  |
      * @author <a href="mailto:herve.quiroz@esil.univ-mrs.fr">Herve Quiroz</a>
48 |  |
      * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a>
49 |  |
      * @author Emmanuel Bourg
50 |  |
      * @version $Revision: 720600 $, $Date: 2008-11-25 22:20:01 +0100 (Di, 25 Nov 2008) $
51 |  |
      */
52 |  |
     public final class ConfigurationUtils
53 |  |
     {
54 |  |
         /** Constant for the file URL protocol.*/
55 |  |
         static final String PROTOCOL_FILE = "file";
56 |  |
57 |  |
         /** Constant for the resource path separator.*/
58 |  |
         static final String RESOURCE_PATH_SEPARATOR = "/";
59 |  |
60 |  |
         /** Constant for the name of the clone() method.*/
61 |  |
         private static final String METHOD_CLONE = "clone";
62 |  |
63 |  |
         /** Constant for Java version 1.4.*/
64 |  |
         private static final float JAVA_1_4 = 1.4f;
65 |  |
66 |  |
         /** The logger.*/
67 | 72 |
         private static Log log = LogFactory.getLog(ConfigurationUtils.class);
68 |  |
69 |  |
         /**
70 |  |
          * Private constructor. Prevents instances from being created.
71 |  |
          */
72 |  |
         private ConfigurationUtils()
73 | 0 |
         {
74 |  |
             // to prevent instantiation...
75 | 0 |
         }
76 |  |
77 |  |
         /**
78 |  |
          * Dump the configuration key/value mappings to some ouput stream.
79 |  |
          *
80 |  |
          * @param configuration the configuration
81 |  |
          * @param out the output stream to dump the configuration to
82 |  |
          */
83 |  |
         public static void dump(Configuration configuration, PrintStream out)
84 |  |
         {
85 | 0 |
             dump(configuration, new PrintWriter(out));
86 | 0 |
         }
87 |  |
88 |  |
         /**
89 |  |
          * Dump the configuration key/value mappings to some writer.
90 |  |
          *
91 |  |
          * @param configuration the configuration
92 |  |
          * @param out the writer to dump the configuration to
93 |  |
          */
94 |  |
         public static void dump(Configuration configuration, PrintWriter out)
95 |  |
         {
96 | 5 |
             Iterator keys = configuration.getKeys();
97 | 11 |
             while (keys.hasNext())
98 |  |
             {
99 | 6 |
                 String key = (String) keys.next();
100 | 6 |
                 Object value = configuration.getProperty(key);
101 | 6 |
                 out.print(key);
102 | 6 |
                 out.print("=");
103 | 6 |
                 out.print(value);
104 |  |
105 | 6 |
                 if (keys.hasNext())
106 |  |
                 {
107 | 2 |
                     out.println();
108 |  |
                 }
109 |  |
             }
110 |  |
111 | 5 |
             out.flush();
112 | 5 |
         }
113 |  |
114 |  |
         /**
115 |  |
          * Get a string representation of the key/value mappings of a
116 |  |
          * configuration.
117 |  |
          *
118 |  |
          * @param configuration the configuration
119 |  |
          * @return a string representation of the configuration
120 |  |
          */
121 |  |
         public static String toString(Configuration configuration)
122 |  |
         {
123 | 5 |
             StringWriter writer = new StringWriter();
124 | 5 |
             dump(configuration, new PrintWriter(writer));
125 | 5 |
             return writer.toString();
126 |  |
         }
127 |  |
128 |  |
         /**
129 |  |
          * <p>Copy all properties from the source configuration to the target
130 |  |
          * configuration. Properties in the target configuration are replaced with
131 |  |
          * the properties with the same key in the source configuration.</p>
132 |  |
          * <p><em>Note:</em> This method is not able to handle some specifics of
133 |  |
          * configurations derived from <code>AbstractConfiguration</code> (e.g.
134 |  |
          * list delimiters). For a full support of all of these features the
135 |  |
          * <code>copy()</code> method of <code>AbstractConfiguration</code> should
136 |  |
          * be used. In a future release this method might become deprecated.</p>
137 |  |
          *
138 |  |
          * @param source the source configuration
139 |  |
          * @param target the target configuration
140 |  |
          * @since 1.1
141 |  |
          */
142 |  |
         public static void copy(Configuration source, Configuration target)
143 |  |
         {
144 | 9 |
             Iterator keys = source.getKeys();
145 | 99 |
             while (keys.hasNext())
146 |  |
             {
147 | 90 |
                 String key = (String) keys.next();
148 | 90 |
                 target.setProperty(key, source.getProperty(key));
149 |  |
             }
150 | 9 |
         }
151 |  |
152 |  |
         /**
153 |  |
          * <p>Append all properties from the source configuration to the target
154 |  |
          * configuration. Properties in the source configuration are appended to
155 |  |
          * the properties with the same key in the target configuration.</p>
156 |  |
          * <p><em>Note:</em> This method is not able to handle some specifics of
157 |  |
          * configurations derived from <code>AbstractConfiguration</code> (e.g.
158 |  |
          * list delimiters). For a full support of all of these features the
159 |  |
          * <code>copy()</code> method of <code>AbstractConfiguration</code> should
160 |  |
          * be used. In a future release this method might become deprecated.</p>
161 |  |
          *
162 |  |
          * @param source the source configuration
163 |  |
          * @param target the target configuration
164 |  |
          * @since 1.1
165 |  |
          */
166 |  |
         public static void append(Configuration source, Configuration target)
167 |  |
         {
168 | 1 |
             Iterator keys = source.getKeys();
169 | 3 |
             while (keys.hasNext())
170 |  |
             {
171 | 2 |
                 String key = (String) keys.next();
172 | 2 |
                 target.addProperty(key, source.getProperty(key));
173 |  |
             }
174 | 1 |
         }
175 |  |
176 |  |
         /**
177 |  |
          * Converts the passed in configuration to a hierarchical one. If the
178 |  |
          * configuration is already hierarchical, it is directly returned. Otherwise
179 |  |
          * all properties are copied into a new hierarchical configuration.
180 |  |
          *
181 |  |
          * @param conf the configuration to convert
182 |  |
          * @return the new hierarchical configuration (the result is <b>null</b> if
183 |  |
          * and only if the passed in configuration is <b>null</b>)
184 |  |
          * @since 1.3
185 |  |
          */
186 |  |
         public static HierarchicalConfiguration convertToHierarchical(
187 |  |
                 Configuration conf)
188 |  |
         {
189 | 5 |
             return convertToHierarchical(conf, null);
190 |  |
         }
191 |  |
192 |  |
         /**
193 |  |
          * Converts the passed in <code>Configuration</code> object to a
194 |  |
          * hierarchical one using the specified <code>ExpressionEngine</code>. This
195 |  |
          * conversion works by adding the keys found in the configuration to a newly
196 |  |
          * created hierarchical configuration. When adding new keys to a
197 |  |
          * hierarchical configuration the keys are interpreted by its
198 |  |
          * <code>ExpressionEngine</code>. If they contain special characters (e.g.
199 |  |
          * brackets) that are treated in a special way by the default expression
200 |  |
          * engine, it may be necessary using a specific engine that can deal with
201 |  |
          * such characters. Otherwise <b>null</b> can be passed in for the
202 |  |
          * <code>ExpressionEngine</code>; then the default expression engine is
203 |  |
          * used. If the passed in configuration is already hierarchical, it is
204 |  |
          * directly returned. (However, the <code>ExpressionEngine</code> is set if
205 |  |
          * it is not <b>null</b>.) Otherwise all properties are copied into a new
206 |  |
          * hierarchical configuration.
207 |  |
          *
208 |  |
          * @param conf the configuration to convert
209 |  |
          * @param engine the <code>ExpressionEngine</code> for the hierarchical
210 |  |
          *        configuration or <b>null</b> for the default
211 |  |
          * @return the new hierarchical configuration (the result is <b>null</b> if
212 |  |
          *         and only if the passed in configuration is <b>null</b>)
213 |  |
          * @since 1.6
214 |  |
          */
215 |  |
         public static HierarchicalConfiguration convertToHierarchical(
216 |  |
                 Configuration conf, ExpressionEngine engine)
217 |  |
         {
218 | 146 |
             if (conf == null)
219 |  |
             {
220 | 1 |
                 return null;
221 |  |
             }
222 |  |
223 | 145 |
             if (conf instanceof HierarchicalConfiguration)
224 |  |
             {
225 | 66 |
                 HierarchicalConfiguration hc = (HierarchicalConfiguration) conf;
226 | 66 |
                 if (engine != null)
227 |  |
                 {
228 | 1 |
                     hc.setExpressionEngine(engine);
229 |  |
                 }
230 |  |
231 | 66 |
                 return hc;
232 |  |
             }
233 |  |
             else
234 |  |
             {
235 | 79 |
                 HierarchicalConfiguration hc = new HierarchicalConfiguration();
236 | 79 |
                 if (engine != null)
237 |  |
                 {
238 | 2 |
                     hc.setExpressionEngine(engine);
239 |  |
                 }
240 |  |
241 |  |
                 // Workaround for problem with copy()
242 | 79 |
                 boolean delimiterParsingStatus = hc.isDelimiterParsingDisabled();
243 | 79 |
                 hc.setDelimiterParsingDisabled(true);
244 | 79 |
                 hc.append(conf);
245 | 79 |
                 hc.setDelimiterParsingDisabled(delimiterParsingStatus);
246 | 79 |
                 return hc;
247 |  |
             }
248 |  |
         }
249 |  |
250 |  |
         /**
251 |  |
          * Clones the given configuration object if this is possible. If the passed
252 |  |
          * in configuration object implements the <code>Cloneable</code>
253 |  |
          * interface, its <code>clone()</code> method will be invoked. Otherwise
254 |  |
          * an exception will be thrown.
255 |  |
          *
256 |  |
          * @param config the configuration object to be cloned (can be <b>null</b>)
257 |  |
          * @return the cloned configuration (<b>null</b> if the argument was
258 |  |
          * <b>null</b>, too)
259 |  |
          * @throws ConfigurationRuntimeException if cloning is not supported for
260 |  |
          * this object
261 |  |
          * @since 1.3
262 |  |
          */
263 |  |
         public static Configuration cloneConfiguration(Configuration config)
264 |  |
                 throws ConfigurationRuntimeException
265 |  |
         {
266 | 12 |
             if (config == null)
267 |  |
             {
268 | 1 |
                 return null;
269 |  |
             }
270 |  |
             else
271 |  |
             {
272 |  |
                 try
273 |  |
                 {
274 | 11 |
                     return (Configuration) clone(config);
275 |  |
                 }
276 | 2 |
                 catch (CloneNotSupportedException cnex)
277 |  |
                 {
278 | 2 |
                     throw new ConfigurationRuntimeException(cnex);
279 |  |
                 }
280 |  |
             }
281 |  |
         }
282 |  |
283 |  |
         /**
284 |  |
          * An internally used helper method for cloning objects. This implementation
285 |  |
          * is not very sophisticated nor efficient. Maybe it can be replaced by an
286 |  |
          * implementation from Commons Lang later. The method checks whether the
287 |  |
          * passed in object implements the <code>Cloneable</code> interface. If
288 |  |
          * this is the case, the <code>clone()</code> method is invoked by
289 |  |
          * reflection. Errors that occur during the cloning process are re-thrown as
290 |  |
          * runtime exceptions.
291 |  |
          *
292 |  |
          * @param obj the object to be cloned
293 |  |
          * @return the cloned object
294 |  |
          * @throws CloneNotSupportedException if the object cannot be cloned
295 |  |
          */
296 |  |
         static Object clone(Object obj) throws CloneNotSupportedException
297 |  |
         {
298 | 23 |
             if (obj instanceof Cloneable)
299 |  |
             {
300 |  |
                 try
301 |  |
                 {
302 | 21 |
                     Method m = obj.getClass().getMethod(METHOD_CLONE, null);
303 | 21 |
                     return m.invoke(obj, null);
304 |  |
                 }
305 | 0 |
                 catch (NoSuchMethodException nmex)
306 |  |
                 {
307 | 0 |
                     throw new CloneNotSupportedException(
308 |  |
                             "No clone() method found for class"
309 |  |
                                     + obj.getClass().getName());
310 |  |
                 }
311 | 0 |
                 catch (IllegalAccessException iaex)
312 |  |
                 {
313 | 0 |
                     throw new ConfigurationRuntimeException(iaex);
314 |  |
                 }
315 | 0 |
                 catch (InvocationTargetException itex)
316 |  |
                 {
317 | 0 |
                     throw new ConfigurationRuntimeException(itex);
318 |  |
                 }
319 |  |
             }
320 |  |
             else
321 |  |
             {
322 | 2 |
                 throw new CloneNotSupportedException(obj.getClass().getName()
323 |  |
                         + " does not implement Cloneable");
324 |  |
             }
325 |  |
         }
326 |  |
327 |  |
         /**
328 |  |
          * Constructs a URL from a base path and a file name. The file name can
329 |  |
          * be absolute, relative or a full URL. If necessary the base path URL is
330 |  |
          * applied.
331 |  |
          *
332 |  |
          * @param basePath the base path URL (can be <b>null</b>)
333 |  |
          * @param file the file name
334 |  |
          * @return the resulting URL
335 |  |
          * @throws MalformedURLException if URLs are invalid
336 |  |
          */
337 |  |
         public static URL getURL(String basePath, String file) throws MalformedURLException
338 |  |
         {
339 | 8 |
             File f = new File(file);
340 | 8 |
             if (f.isAbsolute()) // already absolute?
341 |  |
             {
342 | 2 |
                 return toURL(f);
343 |  |
             }
344 |  |
345 |  |
             try
346 |  |
             {
347 | 6 |
                 if (basePath == null)
348 |  |
                 {
349 | 2 |
                     return new URL(file);
350 |  |
                 }
351 |  |
                 else
352 |  |
                 {
353 | 4 |
                     URL base = new URL(basePath);
354 | 3 |
                     return new URL(base, file);
355 |  |
                 }
356 |  |
             }
357 | 2 |
             catch (MalformedURLException uex)
358 |  |
             {
359 | 2 |
                 return toURL(constructFile(basePath, file));
360 |  |
             }
361 |  |
         }
362 |  |
363 |  |
         /**
364 |  |
          * Helper method for constructing a file object from a base path and a
365 |  |
          * file name. This method is called if the base path passed to
366 |  |
          * <code>getURL()</code> does not seem to be a valid URL.
367 |  |
          *
368 |  |
          * @param basePath the base path
369 |  |
          * @param fileName the file name
370 |  |
          * @return the resulting file
371 |  |
          */
372 |  |
         static File constructFile(String basePath, String fileName)
373 |  |
         {
374 | 740 |
             File file = null;
375 |  |
376 | 740 |
             File absolute = null;
377 | 740 |
             if (fileName != null)
378 |  |
             {
379 | 740 |
                 absolute = new File(fileName);
380 |  |
             }
381 |  |
382 | 740 |
             if (StringUtils.isEmpty(basePath) || (absolute != null && absolute.isAbsolute()))
383 |  |
             {
384 | 63 |
                 file = new File(fileName);
385 |  |
             }
386 |  |
             else
387 |  |
             {
388 | 677 |
                 StringBuffer fName = new StringBuffer();
389 | 677 |
                 fName.append(basePath);
390 |  |
391 |  |
                 // My best friend. Paranoia.
392 | 677 |
                 if (!basePath.endsWith(File.separator))
393 |  |
                 {
394 | 677 |
                     fName.append(File.separator);
395 |  |
                 }
396 |  |
397 |  |
                 //
398 |  |
                 // We have a relative path, and we have
399 |  |
                 // two possible forms here. If we have the
400 |  |
                 // "./" form then just strip that off first
401 |  |
                 // before continuing.
402 |  |
                 //
403 | 677 |
                 if (fileName.startsWith("." + File.separator))
404 |  |
                 {
405 | 0 |
                     fName.append(fileName.substring(2));
406 |  |
                 }
407 |  |
                 else
408 |  |
                 {
409 | 677 |
                     fName.append(fileName);
410 |  |
                 }
411 |  |
412 | 677 |
                 file = new File(fName.toString());
413 |  |
             }
414 |  |
415 | 740 |
             return file;
416 |  |
         }
417 |  |
418 |  |
         /**
419 |  |
          * Return the location of the specified resource by searching the user home
420 |  |
          * directory, the current classpath and the system classpath.
421 |  |
          *
422 |  |
          * @param name the name of the resource
423 |  |
          *
424 |  |
          * @return the location of the resource
425 |  |
          */
426 |  |
         public static URL locate(String name)
427 |  |
         {
428 | 0 |
             return locate(null, name);
429 |  |
         }
430 |  |
431 |  |
         /**
432 |  |
          * Return the location of the specified resource by searching the user home
433 |  |
          * directory, the current classpath and the system classpath.
434 |  |
          *
435 |  |
          * @param base the base path of the resource
436 |  |
          * @param name the name of the resource
437 |  |
          *
438 |  |
          * @return the location of the resource
439 |  |
          */
440 |  |
         public static URL locate(String base, String name)
441 |  |
         {
442 | 5237 |
             if (log.isDebugEnabled())
443 |  |
             {
444 | 0 |
                 StringBuffer buf = new StringBuffer();
445 | 0 |
                 buf.append("ConfigurationUtils.locate(): base is ").append(base);
446 | 0 |
                 buf.append(", name is ").append(name);
447 | 0 |
                 log.debug(buf.toString());
448 |  |
             }
449 |  |
450 | 5237 |
             if (name == null)
451 |  |
             {
452 |  |
                 // undefined, always return null
453 | 6 |
                 return null;
454 |  |
             }
455 |  |
456 | 5231 |
             URL url = null;
457 |  |
458 |  |
             // attempt to create an URL directly
459 |  |
             try
460 |  |
             {
461 | 5231 |
                 if (base == null)
462 |  |
                 {
463 | 345 |
                     url = new URL(name);
464 |  |
                 }
465 |  |
                 else
466 |  |
                 {
467 | 4886 |
                     URL baseURL = new URL(base);
468 | 4316 |
                     url = new URL(baseURL, name);
469 |  |
470 |  |
                     // check if the file exists
471 | 4314 |
                     InputStream in = null;
472 |  |
                     try
473 |  |
                     {
474 | 4314 |
                         in = url.openStream();
475 |  |
                     }
476 |  |
                     finally
477 |  |
                     {
478 | 4314 |
                         if (in != null)
479 |  |
                         {
480 | 4296 |
                             in.close();
481 |  |
                         }
482 |  |
                     }
483 |  |
                 }
484 |  |
485 | 4296 |
                 log.debug("Loading configuration from the URL " + url);
486 |  |
             }
487 | 935 |
             catch (IOException e)
488 |  |
             {
489 | 935 |
                 url = null;
490 | 4296 |
             }
491 |  |
492 |  |
             // attempt to load from an absolute path
493 | 5231 |
             if (url == null)
494 |  |
             {
495 | 935 |
                 File file = new File(name);
496 | 935 |
                 if (file.isAbsolute() && file.exists()) // already absolute?
497 |  |
                 {
498 |  |
                     try
499 |  |
                     {
500 | 292 |
                         url = toURL(file);
501 | 292 |
                         log.debug("Loading configuration from the absolute path " + name);
502 |  |
                     }
503 | 0 |
                     catch (MalformedURLException e)
504 |  |
                     {
505 | 0 |
                         log.warn("Could not obtain URL from file", e);
506 | 292 |
                     }
507 |  |
                 }
508 |  |
             }
509 |  |
510 |  |
             // attempt to load from the base directory
511 | 5231 |
             if (url == null)
512 |  |
             {
513 |  |
                 try
514 |  |
                 {
515 | 643 |
                     File file = constructFile(base, name);
516 | 643 |
                     if (file != null && file.exists())
517 |  |
                     {
518 | 585 |
                         url = toURL(file);
519 |  |
                     }
520 |  |
521 | 643 |
                     if (url != null)
522 |  |
                     {
523 | 585 |
                         log.debug("Loading configuration from the path " + file);
524 |  |
                     }
525 |  |
                 }
526 | 0 |
                 catch (MalformedURLException e)
527 |  |
                 {
528 | 0 |
                     log.warn("Could not obtain URL from file", e);
529 | 643 |
                 }
530 |  |
             }
531 |  |
532 |  |
             // attempt to load from the user home directory
533 | 5231 |
             if (url == null)
534 |  |
             {
535 |  |
                 try
536 |  |
                 {
537 | 58 |
                     File file = constructFile(System.getProperty("user.home"), name);
538 | 58 |
                     if (file != null && file.exists())
539 |  |
                     {
540 | 1 |
                         url = toURL(file);
541 |  |
                     }
542 |  |
543 | 58 |
                     if (url != null)
544 |  |
                     {
545 | 1 |
                         log.debug("Loading configuration from the home path " + file);
546 |  |
                     }
547 |  |
548 |  |
                 }
549 | 0 |
                 catch (MalformedURLException e)
550 |  |
                 {
551 | 0 |
                     log.warn("Could not obtain URL from file", e);
552 | 58 |
                 }
553 |  |
             }
554 |  |
555 |  |
             // attempt to load from classpath
556 | 5231 |
             if (url == null)
557 |  |
             {
558 | 57 |
                 url = locateFromClasspath(name);
559 |  |
             }
560 | 5231 |
             return url;
561 |  |
         }
562 |  |
563 |  |
         /**
564 |  |
          * Tries to find a resource with the given name in the classpath.
565 |  |
          * @param resourceName the name of the resource
566 |  |
          * @return the URL to the found resource or <b>null</b> if the resource
567 |  |
          * cannot be found
568 |  |
          */
569 |  |
         static URL locateFromClasspath(String resourceName)
570 |  |
         {
571 | 57 |
             URL url = null;
572 |  |
             // attempt to load from the context classpath
573 | 57 |
             ClassLoader loader = Thread.currentThread().getContextClassLoader();
574 | 57 |
             if (loader != null)
575 |  |
             {
576 | 56 |
                 url = loader.getResource(resourceName);
577 |  |
578 | 56 |
                 if (url != null)
579 |  |
                 {
580 | 27 |
                     log.debug("Loading configuration from the context classpath (" + resourceName + ")");
581 |  |
                 }
582 |  |
             }
583 |  |
584 |  |
             // attempt to load from the system classpath
585 | 57 |
             if (url == null)
586 |  |
             {
587 | 30 |
                 url = ClassLoader.getSystemResource(resourceName);
588 |  |
589 | 30 |
                 if (url != null)
590 |  |
                 {
591 | 0 |
                     log.debug("Loading configuration from the system classpath (" + resourceName + ")");
592 |  |
                 }
593 |  |
             }
594 | 57 |
             return url;
595 |  |
         }
596 |  |
597 |  |
         /**
598 |  |
          * Return the path without the file name, for example http://xyz.net/foo/bar.xml
599 |  |
          * results in http://xyz.net/foo/
600 |  |
          *
601 |  |
          * @param url the URL from which to extract the path
602 |  |
          * @return the path component of the passed in URL
603 |  |
          */
604 |  |
         static String getBasePath(URL url)
605 |  |
         {
606 | 28 |
             if (url == null)
607 |  |
             {
608 | 0 |
                 return null;
609 |  |
             }
610 |  |
611 | 28 |
             String s = url.toString();
612 |  |
613 | 28 |
             if (s.endsWith("/") || StringUtils.isEmpty(url.getPath()))
614 |  |
             {
615 | 3 |
                 return s;
616 |  |
             }
617 |  |
             else
618 |  |
             {
619 | 25 |
                 return s.substring(0, s.lastIndexOf("/") + 1);
620 |  |
             }
621 |  |
         }
622 |  |
623 |  |
         /**
624 |  |
          * Extract the file name from the specified URL.
625 |  |
          *
626 |  |
          * @param url the URL from which to extract the file name
627 |  |
          * @return the extracted file name
628 |  |
          */
629 |  |
         static String getFileName(URL url)
630 |  |
         {
631 | 26 |
             if (url == null)
632 |  |
             {
633 | 1 |
                 return null;
634 |  |
             }
635 |  |
636 | 25 |
             String path = url.getPath();
637 |  |
638 | 25 |
             if (path.endsWith("/") || StringUtils.isEmpty(path))
639 |  |
             {
640 | 1 |
                 return null;
641 |  |
             }
642 |  |
             else
643 |  |
             {
644 | 24 |
                 return path.substring(path.lastIndexOf("/") + 1);
645 |  |
             }
646 |  |
         }
647 |  |
648 |  |
         /**
649 |  |
          * Tries to convert the specified base path and file name into a file object.
650 |  |
          * This method is called e.g. by the save() methods of file based
651 |  |
          * configurations. The parameter strings can be relative files, absolute
652 |  |
          * files and URLs as well. This implementation checks first whether the passed in
653 |  |
          * file name is absolute. If this is the case, it is returned. Otherwise
654 |  |
          * further checks are performed whether the base path and file name can be
655 |  |
          * combined to a valid URL or a valid file name. <em>Note:</em> The test
656 |  |
          * if the passed in file name is absolute is performed using
657 |  |
          * <code>java.io.File.isAbsolute()</code>. If the file name starts with a
658 |  |
          * slash, this method will return <b>true</b> on Unix, but <b>false</b> on
659 |  |
          * Windows. So to ensure correct behavior for relative file names on all
660 |  |
          * platforms you should never let relative paths start with a slash. E.g.
661 |  |
          * in a configuration definition file do not use something like that:
662 |  |
          * <pre>
663 |  |
          * &lt;properties fileName="/subdir/my.properties"/&gt;
664 |  |
          * </pre>
665 |  |
          * Under Windows this path would be resolved relative to the configuration
666 |  |
          * definition file. Under Unix this would be treated as an absolute path
667 |  |
          * name.
668 |  |
          *
669 |  |
          * @param basePath the base path
670 |  |
          * @param fileName the file name
671 |  |
          * @return the file object (<b>null</b> if no file can be obtained)
672 |  |
          */
673 |  |
         public static File getFile(String basePath, String fileName)
674 |  |
         {
675 |  |
             // Check if the file name is absolute
676 | 50 |
             File f = new File(fileName);
677 | 50 |
             if (f.isAbsolute())
678 |  |
             {
679 | 8 |
                 return f;
680 |  |
             }
681 |  |
682 |  |
             // Check if URLs are involved
683 |  |
             URL url;
684 |  |
             try
685 |  |
             {
686 | 42 |
                 url = new URL(new URL(basePath), fileName);
687 |  |
             }
688 | 39 |
             catch (MalformedURLException mex1)
689 |  |
             {
690 |  |
                 try
691 |  |
                 {
692 | 39 |
                     url = new URL(fileName);
693 |  |
                 }
694 | 37 |
                 catch (MalformedURLException mex2)
695 |  |
                 {
696 | 37 |
                     url = null;
697 | 2 |
                 }
698 | 3 |
             }
699 |  |
700 | 42 |
             if (url != null)
701 |  |
             {
702 | 5 |
                 return fileFromURL(url);
703 |  |
             }
704 |  |
705 | 37 |
             return constructFile(basePath, fileName);
706 |  |
         }
707 |  |
708 |  |
         /**
709 |  |
          * Tries to convert the specified URL to a file object. If this fails,
710 |  |
          * <b>null</b> is returned.
711 |  |
          *
712 |  |
          * @param url the URL
713 |  |
          * @return the resulting file object
714 |  |
          */
715 |  |
         public static File fileFromURL(URL url)
716 |  |
         {
717 | 9326 |
             if (PROTOCOL_FILE.equals(url.getProtocol()))
718 |  |
             {
719 | 9320 |
                 return new File(URLDecoder.decode(url.getPath()));
720 |  |
             }
721 |  |
             else
722 |  |
             {
723 | 6 |
                 return null;
724 |  |
             }
725 |  |
         }
726 |  |
727 |  |
         /**
728 |  |
          * Convert the specified file into an URL. This method is equivalent
729 |  |
          * to file.toURI().toURL() on Java 1.4 and above, and equivalent to
730 |  |
          * file.toURL() on Java 1.3. This is to work around a bug in the JDK
731 |  |
          * preventing the transformation of a file into an URL if the file name
732 |  |
          * contains a '#' character. See the issue CONFIGURATION-300 for
733 |  |
          * more details.
734 |  |
          *
735 |  |
          * @param file the file to be converted into an URL
736 |  |
          */
737 |  |
         static URL toURL(File file) throws MalformedURLException
738 |  |
         {
739 | 895 |
             if (SystemUtils.isJavaVersionAtLeast(JAVA_1_4))
740 |  |
             {
741 |  |
                 try
742 |  |
                 {
743 | 895 |
                     Method toURI = file.getClass().getMethod("toURI", (Class[]) null);
744 | 895 |
                     Object uri = toURI.invoke(file, (Class[]) null);
745 | 895 |
                     Method toURL = uri.getClass().getMethod("toURL", (Class[]) null);
746 | 895 |
                     URL url = (URL) toURL.invoke(uri, (Class[]) null);
747 |  |
748 | 895 |
                     return url;
749 |  |
                 }
750 | 0 |
                 catch (Exception e)
751 |  |
                 {
752 | 0 |
                     throw new MalformedURLException(e.getMessage());
753 |  |
                 }
754 |  |
             }
755 |  |
             else
756 |  |
             {
757 | 0 |
                 return file.toURL();
758 |  |
             }
759 |  |
         }
760 |  |
761 |  |
         /**
762 |  |
          * Enables runtime exceptions for the specified configuration object. This
763 |  |
          * method can be used for configuration implementations that may face errors
764 |  |
          * on normal property access, e.g. <code>DatabaseConfiguration</code> or
765 |  |
          * <code>JNDIConfiguration</code>. Per default such errors are simply
766 |  |
          * logged and then ignored. This implementation will register a special
767 |  |
          * <code>{@link ConfigurationErrorListener}</code> that throws a runtime
768 |  |
          * exception (namely a <code>ConfigurationRuntimeException</code>) on
769 |  |
          * each received error event.
770 |  |
          *
771 |  |
          * @param src the configuration, for which runtime exceptions are to be
772 |  |
          * enabled; this configuration must be derived from
773 |  |
          * <code>{@link EventSource}</code>
774 |  |
          */
775 |  |
         public static void enableRuntimeExceptions(Configuration src)
776 |  |
         {
777 | 3 |
             if (!(src instanceof EventSource))
778 |  |
             {
779 | 2 |
                 throw new IllegalArgumentException(
780 |  |
                         "Configuration must be derived from EventSource!");
781 |  |
             }
782 | 1 |
             ((EventSource) src).addErrorListener(new ConfigurationErrorListener()
783 |  |
             {
784 | 1 |
                 public void configurationError(ConfigurationErrorEvent event)
785 |  |
                 {
786 |  |
                     // Throw a runtime exception
787 | 1 |
                     throw new ConfigurationRuntimeException(event.getCause());
788 |  |
                 }
789 |  |
             });
790 | 1 |
         }
791 |  |
     }