View Javadoc

1   /*
2    * Copyright 2001-2005 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License")
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.commons.configuration;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.PrintStream;
23  import java.io.PrintWriter;
24  import java.io.StringWriter;
25  import java.net.MalformedURLException;
26  import java.net.URL;
27  import java.net.URLDecoder;
28  import java.util.Iterator;
29  
30  import org.apache.commons.lang.StringUtils;
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  
34  /***
35   * Miscellaneous utility methods for configurations.
36   *
37   * @see ConfigurationConverter Utility methods to convert configurations.
38   *
39   * @author <a href="mailto:herve.quiroz@esil.univ-mrs.fr">Herve Quiroz</a>
40   * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a>
41   * @author Emmanuel Bourg
42   * @version $Revision$, $Date: 2005-12-14 16:20:30 +0100 (Wed, 14 Dec 2005) $
43   */
44  public final class ConfigurationUtils
45  {
46      /*** Constant for the file URL protocol.*/
47      static final String PROTOCOL_FILE = "file";
48  
49      /*** The logger.*/
50      private static Log log = LogFactory.getLog(ConfigurationUtils.class);
51  
52      /***
53       * Private constructor. Prevents instances from being created.
54       */
55      private ConfigurationUtils()
56      {
57          // to prevent instanciation...
58      }
59  
60      /***
61       * Dump the configuration key/value mappings to some ouput stream.
62       *
63       * @param configuration the configuration
64       * @param out the output stream to dump the configuration to
65       */
66      public static void dump(Configuration configuration, PrintStream out)
67      {
68          dump(configuration, new PrintWriter(out));
69      }
70  
71      /***
72       * Dump the configuration key/value mappings to some writer.
73       *
74       * @param configuration the configuration
75       * @param out the writer to dump the configuration to
76       */
77      public static void dump(Configuration configuration, PrintWriter out)
78      {
79          Iterator keys = configuration.getKeys();
80          while (keys.hasNext())
81          {
82              String key = (String) keys.next();
83              Object value = configuration.getProperty(key);
84              out.print(key);
85              out.print("=");
86              out.print(value);
87  
88              if (keys.hasNext())
89              {
90                  out.println();
91              }
92          }
93  
94          out.flush();
95      }
96  
97      /***
98       * Get a string representation of the key/value mappings of a
99       * configuration.
100      *
101      * @param configuration the configuration
102      * @return a string representation of the configuration
103      */
104     public static String toString(Configuration configuration)
105     {
106         StringWriter writer = new StringWriter();
107         dump(configuration, new PrintWriter(writer));
108         return writer.toString();
109     }
110 
111     /***
112      * Copy all properties from the source configuration to the target
113      * configuration. Properties in the target configuration are replaced with
114      * the properties with the same key in the source configuration.
115      * <em>Note:</em> This method won't work well on hierarchical configurations
116      * because it is not able to copy information about the properties'
117      * structure. So when dealing with hierarchical configuration objects their
118      * <code>{@link HierarchicalConfiguration#clone() clone()}</code> methods
119      * should be used.
120      *
121      * @param source the source configuration
122      * @param target the target configuration
123      * @since 1.1
124      */
125     public static void copy(Configuration source, Configuration target)
126     {
127         Iterator keys = source.getKeys();
128         while (keys.hasNext())
129         {
130             String key = (String) keys.next();
131             target.setProperty(key, source.getProperty(key));
132         }
133     }
134 
135     /***
136      * Append all properties from the source configuration to the target
137      * configuration. Properties in the source configuration are appended to
138      * the properties with the same key in the target configuration.
139      *
140      * @param source the source configuration
141      * @param target the target configuration
142      * @since 1.1
143      */
144     public static void append(Configuration source, Configuration target)
145     {
146         Iterator keys = source.getKeys();
147         while (keys.hasNext())
148         {
149             String key = (String) keys.next();
150             target.addProperty(key, source.getProperty(key));
151         }
152     }
153 
154     /***
155      * Constructs a URL from a base path and a file name. The file name can
156      * be absolute, relative or a full URL. If necessary the base path URL is
157      * applied.
158      *
159      * @param basePath the base path URL (can be <b>null</b>)
160      * @param file the file name
161      * @return the resulting URL
162      * @throws MalformedURLException if URLs are invalid
163      */
164     public static URL getURL(String basePath, String file) throws MalformedURLException
165     {
166         File f = new File(file);
167         if (f.isAbsolute()) // already absolute?
168         {
169             return f.toURL();
170         }
171 
172         try
173         {
174             if (basePath == null)
175             {
176                 return new URL(file);
177             }
178             else
179             {
180                 URL base = new URL(basePath);
181                 return new URL(base, file);
182             }
183         }
184         catch (MalformedURLException uex)
185         {
186             return constructFile(basePath, file).toURL();
187         }
188     }
189 
190     /***
191      * Helper method for constructing a file object from a base path and a
192      * file name. This method is called if the base path passed to
193      * <code>getURL()</code> does not seem to be a valid URL.
194      *
195      * @param basePath the base path
196      * @param fileName the file name
197      * @return the resulting file
198      */
199     static File constructFile(String basePath, String fileName)
200     {
201         File file = null;
202 
203         File absolute = null;
204         if (fileName != null)
205         {
206             absolute = new File(fileName);
207         }
208 
209         if (StringUtils.isEmpty(basePath) || (absolute != null && absolute.isAbsolute()))
210         {
211             file = new File(fileName);
212         }
213         else
214         {
215             StringBuffer fName = new StringBuffer();
216             fName.append(basePath);
217 
218             // My best friend. Paranoia.
219             if (!basePath.endsWith(File.separator))
220             {
221                 fName.append(File.separator);
222             }
223 
224             //
225             // We have a relative path, and we have
226             // two possible forms here. If we have the
227             // "./" form then just strip that off first
228             // before continuing.
229             //
230             if (fileName.startsWith("." + File.separator))
231             {
232                 fName.append(fileName.substring(2));
233             }
234             else
235             {
236                 fName.append(fileName);
237             }
238 
239             file = new File(fName.toString());
240         }
241 
242         return file;
243     }
244 
245     /***
246      * Return the location of the specified resource by searching the user home
247      * directory, the current classpath and the system classpath.
248      *
249      * @param name the name of the resource
250      *
251      * @return the location of the resource
252      */
253     public static URL locate(String name)
254     {
255         return locate(null, name);
256     }
257 
258     /***
259      * Return the location of the specified resource by searching the user home
260      * directory, the current classpath and the system classpath.
261      *
262      * @param base the base path of the resource
263      * @param name the name of the resource
264      *
265      * @return the location of the resource
266      */
267     public static URL locate(String base, String name)
268     {
269         if (name == null)
270         {
271             // undefined, always return null
272             return null;
273         }
274 
275         URL url = null;
276 
277         // attempt to create an URL directly
278         try
279         {
280             if (base == null)
281             {
282                 url = new URL(name);
283             }
284             else
285             {
286                 URL baseURL = new URL(base);
287                 url = new URL(baseURL, name);
288 
289                 // check if the file exists
290                 InputStream in = null;
291                 try
292                 {
293                     in = url.openStream();
294                 }
295                 finally
296                 {
297                     if (in != null)
298                     {
299                         in.close();
300                     }
301                 }
302             }
303 
304             log.debug("Configuration loaded from the URL " + url);
305         }
306         catch (IOException e)
307         {
308             url = null;
309         }
310 
311         // attempt to load from an absolute path
312         if (url == null)
313         {
314             File file = new File(name);
315             if (file.isAbsolute() && file.exists()) // already absolute?
316             {
317                 try
318                 {
319                     url = file.toURL();
320                     log.debug("Configuration loaded from the absolute path " + name);
321                 }
322                 catch (MalformedURLException e)
323                 {
324                     e.printStackTrace();
325                 }
326             }
327         }
328 
329         // attempt to load from the base directory
330         if (url == null)
331         {
332             try
333             {
334                 File file = constructFile(base, name);
335                 if (file != null && file.exists())
336                 {
337                     url = file.toURL();
338                 }
339 
340                 if (url != null)
341                 {
342                     log.debug("Configuration loaded from the base path " + name);
343                 }
344             }
345             catch (IOException e)
346             {
347                 e.printStackTrace();
348             }
349         }
350 
351         // attempt to load from the user home directory
352         if (url == null)
353         {
354             try
355             {
356                 File file = constructFile(System.getProperty("user.home"), name);
357                 if (file != null && file.exists())
358                 {
359                     url = file.toURL();
360                 }
361 
362                 if (url != null)
363                 {
364                     log.debug("Configuration loaded from the home path " + name);
365                 }
366 
367             }
368             catch (IOException e)
369             {
370                 e.printStackTrace();
371             }
372         }
373 
374         // attempt to load from the context classpath
375         if (url == null)
376         {
377             ClassLoader loader = Thread.currentThread().getContextClassLoader();
378             url = loader.getResource(name);
379 
380             if (url != null)
381             {
382                 log.debug("Configuration loaded from the context classpath (" + name + ")");
383             }
384         }
385 
386         // attempt to load from the system classpath
387         if (url == null)
388         {
389             url = ClassLoader.getSystemResource(name);
390 
391             if (url != null)
392             {
393                 log.debug("Configuration loaded from the system classpath (" + name + ")");
394             }
395         }
396 
397         return url;
398     }
399 
400     /***
401      * Return the path without the file name, for example http://xyz.net/foo/bar.xml
402      * results in http://xyz.net/foo/
403      *
404      * @param url the URL from which to extract the path
405      * @return the path component of the passed in URL
406      */
407     static String getBasePath(URL url)
408     {
409         if (url == null)
410         {
411             return null;
412         }
413 
414         String s = url.toString();
415 
416         if (s.endsWith("/") || StringUtils.isEmpty(url.getPath()))
417         {
418             return s;
419         }
420         else
421         {
422             return s.substring(0, s.lastIndexOf("/") + 1);
423         }
424     }
425 
426     /***
427      * Extract the file name from the specified URL.
428      *
429      * @param url the URL from which to extract the file name
430      * @return the extracted file name
431      */
432     static String getFileName(URL url)
433     {
434         if (url == null)
435         {
436             return null;
437         }
438 
439         String path = url.getPath();
440 
441         if (path.endsWith("/") || StringUtils.isEmpty(path))
442         {
443             return null;
444         }
445         else
446         {
447             return path.substring(path.lastIndexOf("/") + 1);
448         }
449     }
450 
451     /***
452      * Tries to convert the specified base path and file name into a file object.
453      * This method is called e.g. by the save() methods of file based
454      * configurations. The parameter strings can be relative files, absolute
455      * files and URLs as well.
456      *
457      * @param basePath the base path
458      * @param fileName the file name
459      * @return the file object (<b>null</b> if no file can be obtained)
460      */
461     public static File getFile(String basePath, String fileName)
462     {
463         // Check if URLs are involved
464         URL url;
465         try
466         {
467             url = new URL(new URL(basePath), fileName);
468         }
469         catch (MalformedURLException mex1)
470         {
471             try
472             {
473                 url = new URL(fileName);
474             }
475             catch (MalformedURLException mex2)
476             {
477                 url = null;
478             }
479         }
480 
481         if (url != null)
482         {
483             return fileFromURL(url);
484         }
485 
486         return constructFile(basePath, fileName);
487     }
488 
489     /***
490      * Tries to convert the specified URL to a file object. If this fails,
491      * <b>null</b> is returned.
492      *
493      * @param url the URL
494      * @return the resulting file object
495      */
496     public static File fileFromURL(URL url)
497     {
498         if (PROTOCOL_FILE.equals(url.getProtocol()))
499         {
500             return new File(URLDecoder.decode(url.getPath()));
501         }
502         else
503         {
504             return null;
505         }
506     }
507 }