001: /*--
002:
003: Copyright (C) 2000-2003 Anthony Eden.
004: All rights reserved.
005:
006: Redistribution and use in source and binary forms, with or without
007: modification, are permitted provided that the following conditions
008: are met:
009:
010: 1. Redistributions of source code must retain the above copyright
011: notice, this list of conditions, and the following disclaimer.
012:
013: 2. Redistributions in binary form must reproduce the above copyright
014: notice, this list of conditions, and the disclaimer that follows
015: these conditions in the documentation and/or other materials
016: provided with the distribution.
017:
018: 3. The name "EdenLib" must not be used to endorse or promote products
019: derived from this software without prior written permission. For
020: written permission, please contact me@anthonyeden.com.
021:
022: 4. Products derived from this software may not be called "EdenLib", nor
023: may "EdenLib" appear in their name, without prior written permission
024: from Anthony Eden (me@anthonyeden.com).
025:
026: In addition, I request (but do not require) that you include in the
027: end-user documentation provided with the redistribution and/or in the
028: software itself an acknowledgement equivalent to the following:
029: "This product includes software developed by
030: Anthony Eden (http://www.anthonyeden.com/)."
031:
032: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
033: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
034: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
035: DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
036: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
037: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
038: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
039: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
040: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
041: IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
042: POSSIBILITY OF SUCH DAMAGE.
043:
044: For more information on EdenLib, please see <http://edenlib.sf.net/>.
045:
046: */
047:
048: package com.anthonyeden.lib.config;
049:
050: import com.anthonyeden.lib.config.sax.SAXConfigurationFactory;
051: import com.anthonyeden.lib.util.ClassUtilities;
052: import com.anthonyeden.lib.util.IOUtilities;
053: import org.apache.commons.vfs.*;
054:
055: import java.io.*;
056: import java.net.URL;
057: import java.util.List;
058:
059: /**
060: * Implementation of the Configuration interface which uses an XML
061: * document as its data source.
062: *
063: * @author Anthony Eden
064: * @author <a href="mailto:florin.patrascu@gmail.com">Florin T.PATRASCU</a>
065: */
066:
067: public class XMLConfiguration implements MutableConfiguration {
068: private Configuration configuration;
069: private static final String EMPTY_STRING = "";
070:
071: /**
072: * Construct an "anonymous" configuration object from the given XML String
073: *
074: * @param xmlString The xml string we want to load
075: * @deprecated please use the XMLConfiguration(id, xmlString)
076: */
077: public XMLConfiguration(String xmlString)
078: throws ConfigurationException {
079: this (EMPTY_STRING, xmlString, ConfigurationBase.ENCODING);
080: }
081:
082: /**
083: * Construct a configuration object from the given XML String
084: * with the given id.
085: *
086: * @param id
087: * @param xmlString The xml string we want to load
088: */
089: public XMLConfiguration(String id, String xmlString)
090: throws ConfigurationException {
091: this (id, xmlString, ConfigurationBase.ENCODING);
092: }
093:
094: /**
095: * Construct a configuration object from the given XML String
096: * with the given id.
097: *
098: * @param id used to identify the parsing sequence
099: * @param xmlString The xml string we want to load
100: * @param encoding character encoding
101: * @throws ConfigurationException
102: */
103:
104: public XMLConfiguration(String id, String xmlString, String encoding)
105: throws ConfigurationException {
106:
107: try {
108: load(id, new ByteArrayInputStream(xmlString
109: .getBytes(encoding)));
110: } catch (UnsupportedEncodingException e) {
111: e.printStackTrace();
112: throw new ConfigurationException("Unsupported encoding: "
113: + encoding + ", while parsing id: " + id
114: + ", containing: " + xmlString);
115: }
116: }
117:
118: /**
119: * Construct an XMLConfiguration from the given File.
120: *
121: * @param file The file
122: * @throws ConfigurationException
123: */
124:
125: public XMLConfiguration(File file) throws ConfigurationException {
126: load(file);
127: }
128:
129: public XMLConfiguration(String id, File file)
130: throws ConfigurationException {
131: load(id, file);
132: }
133:
134: private void load(String id, File file)
135: throws ConfigurationException {
136: if (file == null) {
137: throw new ConfigurationException("File cannot be null");
138: }
139:
140: InputStream in = null;
141: try {
142: in = new BufferedInputStream(new FileInputStream(file));
143: load(id, in);
144: } catch (Exception e) {
145: throw new ConfigurationException(e);
146: } finally {
147: IOUtilities.close(in);
148: }
149:
150: }
151:
152: /**
153: * Construct an XMLConfiguration from the given FileObject.
154: *
155: * @param file The file
156: * @throws ConfigurationException
157: */
158:
159: public XMLConfiguration(FileObject file)
160: throws ConfigurationException {
161: load(file);
162: }
163:
164: /**
165: * Construct an XMLConfiguration using the data at the given
166: * URL.
167: *
168: * @param url The URL
169: * @throws ConfigurationException
170: */
171:
172: public XMLConfiguration(URL url) throws ConfigurationException {
173: load(url);
174: }
175:
176: /**
177: * Construct an XMLConfiguration using the given InputStream.
178: *
179: * @param in The InputStream
180: * @throws ConfigurationException
181: */
182:
183: public XMLConfiguration(InputStream in)
184: throws ConfigurationException {
185: load(in);
186: }
187:
188: /**
189: * @param id
190: * @param in
191: * @throws ConfigurationException
192: */
193: public XMLConfiguration(String id, InputStream in)
194: throws ConfigurationException {
195: load(id, in);
196: }
197:
198: /**
199: * Construct an XMLConfiguration using the given reader.
200: *
201: * @param reader The Reader
202: * @throws ConfigurationException
203: */
204:
205: public XMLConfiguration(Reader reader)
206: throws ConfigurationException {
207: load(reader);
208: }
209:
210: /**
211: * Get the node's name.
212: *
213: * @return The node's name
214: */
215:
216: public String getName() {
217: return configuration.getName();
218: }
219:
220: /**
221: * Get the parent configuration object. This method will return null
222: * if this configuration object is the top-most configuration object
223: * in the configuration tree.
224: *
225: * @return The parent configuration object or null
226: */
227:
228: public Configuration getParent() {
229: return configuration.getParent();
230: }
231:
232: /**
233: * Get the child configuration object with the given name. If the
234: * child with the name does not exist then this method returns
235: * null. If more than one child with the given name exists then
236: * this method returns the first child.
237: *
238: * @param name The child name
239: * @return The first named child or null
240: */
241:
242: public Configuration getChild(String name) {
243: return configuration.getChild(name);
244: }
245:
246: /**
247: * Get the value of the first child configuration object with the
248: * given name. If the child cannot be found or the child had no
249: * data then this method returns null.
250: *
251: * @param name The child name
252: * @return The value or null
253: */
254:
255: public String getChildValue(String name) {
256: return configuration.getChildValue(name);
257: }
258:
259: /**
260: * Get the value of the first child configuration object with the
261: * given name. If the child cannot be found or the child had no
262: * data then this method returns the given default value.
263: *
264: * @param name The child name
265: * @param defaultValue The default value
266: * @return The value
267: */
268:
269: public String getChildValue(String name, String defaultValue) {
270: return configuration.getChildValue(name, defaultValue);
271: }
272:
273: /**
274: * Get a list of all child nodes.
275: *
276: * @return A List of Configuration objects
277: */
278:
279: public List getChildren() {
280: return configuration.getChildren();
281: }
282:
283: /**
284: * Get a list of all child nodes with the given name.
285: *
286: * @param name The child node name
287: * @return A List of Configuration objects
288: */
289:
290: public List getChildren(String name) {
291: //log.debug("getChildren(" + name + ")");
292: return configuration.getChildren(name);
293: }
294:
295: /**
296: * Get a List of attribute names.
297: *
298: * @return A List of attribute names
299: */
300:
301: public List getAttributeNames() {
302: return configuration.getAttributeNames();
303: }
304:
305: /**
306: * Get the named attribute or null.
307: *
308: * @param name The attribute name
309: * @return The attribute value
310: */
311:
312: public String getAttribute(String name) {
313: return configuration.getAttribute(name);
314: }
315:
316: /**
317: * Get the named attribute. If the attribute is not found then
318: * return the given default value.
319: *
320: * @param name The attribute name
321: * @param defaultValue The default value
322: * @return The attribute value
323: */
324:
325: public String getAttribute(String name, String defaultValue) {
326: return configuration.getAttribute(name, defaultValue);
327: }
328:
329: /**
330: * Get the node's value or null if the node contains no data.
331: *
332: * @return The node value or null
333: */
334:
335: public String getValue() {
336: return configuration.getValue();
337: }
338:
339: /**
340: * Get the node's value. If the node contains no data then return
341: * the given default value.
342: *
343: * @param defaultValue The default value
344: * @return The node value
345: */
346:
347: public String getValue(String defaultValue) {
348: return configuration.getValue(defaultValue);
349: }
350:
351: public Location getLocation() {
352: return configuration.getLocation();
353: }
354:
355: public void setLocation(String id) {
356: if (id != null)
357: configuration.setLocation(id);
358: }
359:
360: // MutableConfiguration implementation
361:
362: /**
363: * Set the node name.
364: *
365: * @param name The new node name
366: */
367:
368: public synchronized void setName(String name) {
369: if (configuration instanceof MutableConfiguration) {
370: ((MutableConfiguration) configuration).setName(name);
371: } else {
372: throw new UnsupportedOperationException(
373: "This configuration is not mutable.");
374: }
375: }
376:
377: /**
378: * Add a child node with no child value to the configuration. This
379: * method should be the same as calling
380: * <code>addChild(name, "")</code>
381: *
382: * @param name The name of the new configuration node
383: * @return The configuration node
384: */
385:
386: public MutableConfiguration addChild(String name) {
387: if (configuration instanceof MutableConfiguration) {
388: return ((MutableConfiguration) configuration).addChild(
389: name, EMPTY_STRING);
390: } else {
391: throw new UnsupportedOperationException(
392: "This configuration is not mutable.");
393: }
394: }
395:
396: /**
397: * Add a child node to the configuration.
398: *
399: * @param name The name of the new configuration node
400: * @param value The value of the new configuration node
401: * @return The configuration node
402: */
403:
404: public synchronized MutableConfiguration addChild(String name,
405: Object value) {
406: if (configuration instanceof MutableConfiguration) {
407: return ((MutableConfiguration) configuration).addChild(
408: name, value);
409: } else {
410: throw new UnsupportedOperationException(
411: "This configuration is not mutable.");
412: }
413: }
414:
415: /**
416: * Add a child node to the configuration.
417: *
418: * @param name The name of the new configuration node
419: * @param value The value of the new configuration node
420: * @param defaultValue The value to use in case the value is null
421: * @return The configuration node
422: */
423:
424: public synchronized MutableConfiguration addChild(String name,
425: Object value, Object defaultValue) {
426: if (configuration instanceof MutableConfiguration) {
427: return ((MutableConfiguration) configuration).addChild(
428: name, value, defaultValue);
429: } else {
430: throw new UnsupportedOperationException(
431: "This configuration is not mutable.");
432: }
433: }
434:
435: /**
436: * Add the configuration object as a child of this configuration object.
437: *
438: * @param child The child configuration object
439: */
440:
441: public synchronized void addChild(Configuration child) {
442: if (configuration instanceof MutableConfiguration) {
443: ((MutableConfiguration) configuration).addChild(child);
444: } else {
445: throw new UnsupportedOperationException(
446: "This configuration is not mutable.");
447: }
448: }
449:
450: /**
451: * Add an attribute with the given name.
452: *
453: * @param name The attribute name
454: * @param value The attribute value
455: */
456:
457: public synchronized void addAttribute(String name, Object value) {
458: if (configuration instanceof MutableConfiguration) {
459: ((MutableConfiguration) configuration).addAttribute(name,
460: value);
461: } else {
462: throw new UnsupportedOperationException(
463: "This configuration is not mutable.");
464: }
465: }
466:
467: /**
468: * Set the configuration object's value.
469: *
470: * @param value The new value
471: */
472:
473: public synchronized void setValue(String value) {
474: if (configuration instanceof MutableConfiguration) {
475: ((MutableConfiguration) configuration).setValue(value);
476: } else {
477: throw new UnsupportedOperationException(
478: "This configuration is not mutable.");
479: }
480: }
481:
482: /**
483: * Remove the specified configuration object.
484: *
485: * @param configuration The child configuration object
486: */
487:
488: public void removeChild(Configuration configuration) {
489: if (configuration instanceof MutableConfiguration) {
490: ((MutableConfiguration) this .configuration)
491: .removeChild(configuration);
492: } else {
493: throw new UnsupportedOperationException(
494: "This configuration is not mutable.");
495: }
496: }
497:
498: /**
499: * Remove all of the children of this configuration node.
500: */
501:
502: public void clearChildren() {
503: if (configuration instanceof MutableConfiguration) {
504: ((MutableConfiguration) configuration).clearChildren();
505: } else {
506: throw new UnsupportedOperationException(
507: "This configuration is not mutable.");
508: }
509: }
510:
511: /**
512: * Load the configuration from the file represented by the
513: * given file name. A File object is constructed using the
514: * given String. If the File exists then it is used to load
515: * the configuration information. If the File does not exist
516: * then the classpath will be searched for the given file name.
517: * <p/>
518: * <p>The filename cannot be null.
519: *
520: * @param filename The filename
521: * @throws ConfigurationException
522: */
523:
524: public void load(String filename) throws ConfigurationException {
525: if (filename == null) {
526: throw new ConfigurationException("Filename cannot be null");
527: }
528:
529: try {
530: FileSystemManager fsManager = VFS.getManager();
531: FileObject file = fsManager.resolveFile(filename);
532: if (file.exists()) {
533: load(file);
534: } else {
535: InputStream in = ClassUtilities
536: .getResourceAsStream(filename);
537: if (in != null) {
538: try {
539: load(in);
540: } catch (Exception e) {
541: IOUtilities.close(in);
542: }
543: } else {
544: throw new ConfigurationException("Configuration "
545: + filename + " not found");
546: }
547: }
548: } catch (FileSystemException e) {
549: throw new ConfigurationException(e);
550: }
551: }
552:
553: /**
554: * Load the configuration from the given file. The file
555: * cannot be null.
556: *
557: * @param file The file
558: * @throws ConfigurationException
559: */
560:
561: public void load(File file) throws ConfigurationException {
562: if (file == null) {
563: throw new ConfigurationException("File cannot be null");
564: }
565:
566: try {
567: FileSystemManager fsManager = VFS.getManager();
568: load(fsManager.toFileObject(file));
569: } catch (Exception e) {
570: throw new ConfigurationException(e);
571: }
572: }
573:
574: /**
575: * Load the configuration from the given FileObject. The FileObject
576: * cannot be null.
577: *
578: * @param file The FileObject
579: * @throws ConfigurationException
580: */
581:
582: public void load(FileObject file) throws ConfigurationException {
583: if (file == null) {
584: throw new ConfigurationException("File cannot be null");
585: }
586:
587: InputStream in = null;
588: try {
589: FileContent content = file.getContent();
590: in = content.getInputStream();
591: load(in);
592: } catch (Exception e) {
593: throw new ConfigurationException(e);
594: } finally {
595: IOUtilities.close(in);
596: }
597: }
598:
599: /**
600: * Load the configuration from the given URL. The URL
601: * cannot be null.
602: *
603: * @param url The URL
604: * @throws ConfigurationException
605: */
606:
607: public void load(URL url) throws ConfigurationException {
608: if (url == null) {
609: throw new ConfigurationException("URL cannot be null");
610: }
611:
612: InputStream in = null;
613: try {
614: in = url.openStream();
615: load(in);
616: } catch (Exception e) {
617: throw new ConfigurationException(e);
618: } finally {
619: IOUtilities.close(in);
620: }
621: }
622:
623: /**
624: * Load the configuration from the given InputStream. The
625: * InputStream cannot be null.
626: *
627: * @param in The InputStream
628: * @throws ConfigurationException
629: */
630:
631: public void load(String id, InputStream in)
632: throws ConfigurationException {
633: ConfigurationFactory configFactory = SAXConfigurationFactory
634: .getInstance();
635: configuration = configFactory.getConfiguration(id, in);
636:
637: }
638:
639: public void load(InputStream in) throws ConfigurationException {
640: load("", in);
641:
642: }
643:
644: /**
645: * Load the configuration from the given Reader. The reader
646: * cannot be null.
647: *
648: * @param reader The Reader
649: * @throws ConfigurationException
650: */
651:
652: public void load(Reader reader) throws ConfigurationException {
653: ConfigurationFactory configFactory = SAXConfigurationFactory
654: .getInstance();
655: configuration = configFactory.getConfiguration("", reader);
656:
657: }
658:
659: /**
660: * Save the configuration data to the given OutputStream.
661: *
662: * @param out The OutputStream
663: * @throws ConfigurationException
664: */
665:
666: public void save(OutputStream out) throws ConfigurationException {
667: if (!(configuration instanceof MutableConfiguration)) {
668: throw new UnsupportedOperationException(
669: "Configuration is not mutable");
670: }
671:
672: if (out == null) {
673: throw new ConfigurationException(
674: "OutputStream cannot be null");
675: }
676:
677: try {
678: ((MutableConfiguration) configuration).save(out);
679: } catch (ConfigurationException e) {
680: throw e;
681: } catch (Exception e) {
682: throw new ConfigurationException(e);
683: }
684: }
685:
686: /**
687: * Save the configuration data to the given Writer.
688: *
689: * @param out The Writer
690: * @throws ConfigurationException
691: */
692:
693: public void save(Writer out) throws ConfigurationException {
694: if (!(configuration instanceof MutableConfiguration)) {
695: throw new UnsupportedOperationException(
696: "Configuration is not mutable");
697: }
698:
699: if (out == null) {
700: throw new ConfigurationException("Writer cannot be null");
701: }
702:
703: try {
704: ((MutableConfiguration) configuration).save(out);
705: } catch (ConfigurationException e) {
706: throw e;
707: } catch (Exception e) {
708: throw new ConfigurationException(e);
709: }
710: }
711:
712: /**
713: * Returns this XMLConfiguration as a string.
714: * Internally it uses the save method, to obtain the string.
715: *
716: * @return this XMLConfiguration as a string
717: * @throws ConfigurationException
718: */
719: public String toXMLString() throws ConfigurationException {
720: StringWriter sw = new StringWriter();
721: this .save(sw);
722: return sw.toString();
723: }
724:
725: /**
726: * This is a deep copy of XMLConfiguration since atrributes and values are Strings and therefore immutable.
727: * Unless of course you modified the object manually and entered complex objects as values or attribute values.
728: * All this does is return the result of configuration.copy() call on the wrapped configuration object.
729: *
730: * @return copy of the wrapped Configuration object
731: */
732: public Configuration copy() {
733: return this.configuration.copy();
734: }
735: }
|