Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
ConfigurationUtils |
|
| 4.590909090909091;4,591 | ||||
ConfigurationUtils$1 |
|
| 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 | * <properties fileName="/subdir/my.properties"/> | |
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 | } |