~ubuntu-branches/ubuntu/saucy/commons-configuration/saucy

« back to all changes in this revision

Viewing changes to src/main/java/org/apache/commons/configuration/ConfigurationUtils.java

  • Committer: Package Import Robot
  • Author(s): Emmanuel Bourg
  • Date: 2013-07-01 16:29:44 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20130701162944-98waq5gogha5gpn1
Tags: 1.9-1
* New upstream release
* debian/control:
  - Updated Standards-Version to 3.9.4 (no changes)
  - Use canonical URLs for the Vcs-* fields
  - Added new build dependencies (libjavacc-maven-plugin-java, junit4)
  - Upgraded the dependency on the Servlet API (2.5 -> 3.0)
  - Removed the dependency on the Activation Framework (glassfish-activation)
  - Replaced the dependency on glassfish-mail with libgnumail-java
  - Removed the unused dependencies:
    liblog4j1.2-java-doc, libmaven-assembly-plugin-java
  - Replaced the dependency on libcommons-jexl-java by libcommons-jexl2-java
* debian/watch: Changed to point the official Apache distribution server
* Removed the obsolete file debian/ant.properties
* Installed the upstream changelog in the binary packages
* Added the report plugins to maven.ignoreRules
* Added the classpath attribute to the jar manifest

Show diffs side-by-side

added added

removed removed

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