1 /*
2 * Copyright (C) The JContainer Group. All rights reserved.
3 *
4 * This software is published under the terms of the JContainer
5 * Software License version 1.1, a copy of which has been included
6 * with this distribution in the LICENSE.txt file.
7 */
8 package org.jcontainer.dna.impl;
9
10 import java.util.ArrayList;
11 import java.util.HashMap;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Set;
15 import org.jcontainer.dna.Configuration;
16 import org.jcontainer.dna.ConfigurationException;
17
18 /***
19 * In memory Configuration implementation.
20 * The developer should create the DefaultConfiguration,
21 * associate value, attributes and/or child elements configuration
22 * and then invoke {@link #makeReadOnly()} before passing the
23 * Configuration to the client component.
24 *
25 * @version $Revision: 1.23 $ $Date: 2003/09/23 10:57:28 $
26 */
27 public class DefaultConfiguration
28 extends AbstractFreezable
29 implements Configuration
30 {
31 /***
32 * Postfix indicating that location is generated.
33 */
34 private static final String AUTOGEN_POSTFIX = "<autogen>";
35
36 /***
37 * The constant that boolean values must equal to be "true".
38 */
39 private static final String TRUE_STRING = "true";
40
41 /***
42 * Constant for empty String array to reduce
43 * creation cost for empty array.
44 */
45 private static final String[] EMPTY_STRING_ARRAY = new String[ 0 ];
46
47 /***
48 * Constant for empty configuration array to reduce
49 * creation cost for empty array.
50 */
51 private static final Configuration[] EMPTY_CONFIG_ARRAY = new Configuration[ 0 ];
52
53 /***
54 * The name of configuration element.
55 */
56 private final String m_name;
57
58 /***
59 * The location of configuration element in source.
60 * May be empty string if unknown.
61 */
62 private final String m_location;
63
64 /***
65 * The path of configuration element in document.
66 * May be empty string if unknown.
67 */
68 private final String m_path;
69
70 /***
71 * The attributes defined by configuration (May be null).
72 */
73 private Map m_attributes;
74
75 /***
76 * The child elements defined by
77 * configuration (May be null). If
78 * {@link #m_value} not null then
79 * m_children must be null.
80 */
81 private List m_children;
82
83 /***
84 * The value contained in configuration
85 * (May be null). If {@link #m_children} not
86 * null then m_value must be null.
87 */
88 private String m_value;
89
90 /***
91 * Create a DefaultConfiguration instance.
92 *
93 * @param name the name of configuration element
94 * @param location the location of configuration element in source
95 * @param path the path of configuration element in document
96 */
97 public DefaultConfiguration( final String name,
98 final String location,
99 final String path )
100 {
101 if( null == name )
102 {
103 throw new NullPointerException( "name" );
104 }
105 if( null == path )
106 {
107 throw new NullPointerException( "path" );
108 }
109 if( null == location )
110 {
111 throw new NullPointerException( "location" );
112 }
113 m_name = name;
114 m_path = path;
115 m_location = location;
116 }
117
118 /***
119 * Return the name of the configuration element.
120 *
121 * @return the name of the configuration element.
122 */
123 public String getName()
124 {
125 return m_name;
126 }
127
128 /***
129 * Return the path to the configuration element.
130 * The path should be in the xpath form but may
131 * be the empty string if unabel to determine path.
132 *
133 * @return the path to the configuration element.
134 */
135 public final String getPath()
136 {
137 return m_path;
138 }
139
140 /***
141 * Return the location of configuration element.
142 * Usually of the form "uri[:line number[:column number]]"
143 * if possible. ie "file:myFile.xml:80:2". However the line
144 * number and column number may be elided if unavailable.
145 *
146 * @return the location of configuration element.
147 */
148 public String getLocation()
149 {
150 return m_location;
151 }
152
153 /***
154 * Return an array of all the child elements.
155 *
156 * @return an array of all the child elements.
157 */
158 public Configuration[] getChildren()
159 {
160 final List childList = getChildList();
161 if( null == childList )
162 {
163 return EMPTY_CONFIG_ARRAY;
164 }
165 else
166 {
167 return (Configuration[])childList.toArray( new Configuration[ childList.size() ] );
168 }
169 }
170
171 /***
172 * Return an array of all the child elements with specified name.
173 *
174 * @param name the name of child configuration objects
175 * @return an array of all the child elements with specified name.
176 */
177 public Configuration[] getChildren( final String name )
178 {
179 if( null == name )
180 {
181 throw new NullPointerException( "name" );
182 }
183 final List children = getChildList();
184 if( null == children )
185 {
186 return EMPTY_CONFIG_ARRAY;
187 }
188 else
189 {
190 final ArrayList results = new ArrayList();
191 final int count = children.size();
192 for( int i = 0; i < count; i++ )
193 {
194 final Configuration child = (Configuration)children.get( i );
195 if( child.getName().equals( name ) )
196 {
197 results.add( child );
198 }
199 }
200 return (Configuration[])results.toArray( new Configuration[ results.size() ] );
201 }
202 }
203
204 /***
205 * Return a child Configuration element with specified name.
206 * If no such element exists an element will be autocreated.
207 *
208 * @param name the name of child configuration object
209 * @return a child Configuration element with specified name.
210 */
211 public Configuration getChild( final String name )
212 {
213 return getChild( name, true );
214 }
215
216 /***
217 * Return a child Configuration element with specified name.
218 * If no such element exists and createChild is true then an
219 * element will be autocreated otherwise null will be returned.
220 *
221 * @param name the name of child configuration object
222 * @param createChild true if child should be created if it does not exist
223 * @return a child Configuration element with specified name.
224 */
225 public Configuration getChild( final String name,
226 final boolean createChild )
227 {
228 if( null == name )
229 {
230 throw new NullPointerException( "name" );
231 }
232 final List children = getChildList();
233 if( null != children )
234 {
235 final int count = children.size();
236 for( int i = 0; i < count; i++ )
237 {
238 final Configuration child = (Configuration)children.get( i );
239 if( child.getName().equals( name ) )
240 {
241 return child;
242 }
243 }
244 }
245 if( createChild )
246 {
247 final String path = getPath() + ConfigurationUtil.PATH_SEPARATOR + getName();
248 return new DefaultConfiguration( name, generateLocation(), path );
249 }
250 else
251 {
252 return null;
253 }
254
255 }
256
257 /***
258 * Return text value of element.
259 *
260 * @return the value
261 * @throws ConfigurationException if no value in element
262 */
263 public String getValue()
264 throws ConfigurationException
265 {
266 if( null != m_value )
267 {
268 return m_value;
269 }
270 else
271 {
272 final String message = "No value specified";
273 throw new ConfigurationException( message, getPath(), getLocation() );
274 }
275 }
276
277 /***
278 * Return text value of element.
279 * Use specified default if no value in element.
280 *
281 * @param defaultValue the default value
282 * @return the value
283 */
284 public String getValue( final String defaultValue )
285 {
286 if( null != m_value )
287 {
288 return m_value;
289 }
290 else
291 {
292 return defaultValue;
293 }
294 }
295
296 /***
297 * Return text value of element as a boolean.
298 *
299 * @return the value
300 * @throws ConfigurationException if no value in element
301 * or value can not be converted to correct type
302 */
303 public boolean getValueAsBoolean()
304 throws ConfigurationException
305 {
306 return getValue().equals( "true" );
307 }
308
309 /***
310 * Return text value of element as a boolean.
311 * Use specified default if no value in element or
312 * value can not be converted to correct type.
313 *
314 * @param defaultValue the default value
315 * @return the value
316 */
317 public boolean getValueAsBoolean( final boolean defaultValue )
318 {
319 if( null == m_value )
320 {
321 return defaultValue;
322 }
323 else
324 {
325 return m_value.equals( TRUE_STRING );
326 }
327 }
328
329 /***
330 * Return text value of element as an integer.
331 *
332 * @return the value
333 * @throws ConfigurationException if no value in element
334 * or value can not be converted to correct type
335 */
336 public int getValueAsInteger()
337 throws ConfigurationException
338 {
339 try
340 {
341 return Integer.parseInt( getValue() );
342 }
343 catch( final NumberFormatException nfe )
344 {
345 final String message =
346 "Unable to parse " + getValue() + " as an integer";
347 throw new ConfigurationException( message, getPath(), getLocation(), nfe );
348 }
349 }
350
351 /***
352 * Return text value of element as an integer.
353 * Use specified default if no value in element or
354 * value can not be converted to correct type.
355 *
356 * @param defaultValue the default value
357 * @return the value
358 */
359 public int getValueAsInteger( final int defaultValue )
360 {
361 if( null == m_value )
362 {
363 return defaultValue;
364 }
365 else
366 {
367 try
368 {
369 return Integer.parseInt( m_value );
370 }
371 catch( final NumberFormatException nfe )
372 {
373 return defaultValue;
374 }
375 }
376 }
377
378 /***
379 * Return text value of element as a long.
380 *
381 * @return the value
382 * @throws ConfigurationException if no value in element
383 * or value can not be converted to correct type
384 */
385 public long getValueAsLong()
386 throws ConfigurationException
387 {
388 try
389 {
390 return Long.parseLong( getValue() );
391 }
392 catch( final NumberFormatException nfe )
393 {
394 final String message =
395 "Unable to parse " + getValue() + " as a Long";
396 throw new ConfigurationException( message, getPath(), getLocation(), nfe );
397 }
398 }
399
400 /***
401 * Return text value of element as a long.
402 * Use specified default if no value in element or
403 * value can not be converted to correct type.
404 *
405 * @param defaultValue the default value
406 * @return the value
407 */
408 public long getValueAsLong( final long defaultValue )
409 {
410 if( null == m_value )
411 {
412 return defaultValue;
413 }
414 else
415 {
416 try
417 {
418 return Long.parseLong( m_value );
419 }
420 catch( final NumberFormatException nfe )
421 {
422 return defaultValue;
423 }
424 }
425 }
426
427 /***
428 * Return text value of element as a float.
429 *
430 * @return the value
431 * @throws ConfigurationException if no value in element
432 * or value can not be converted to correct type
433 */
434 public float getValueAsFloat()
435 throws ConfigurationException
436 {
437 try
438 {
439 return Float.parseFloat( getValue() );
440 }
441 catch( final NumberFormatException nfe )
442 {
443 final String message =
444 "Unable to parse " + getValue() + " as a Long";
445 throw new ConfigurationException( message, getPath(), getLocation(), nfe );
446 }
447 }
448
449 /***
450 * Return text value of element as a float.
451 * Use specified default if no value in element or
452 * value can not be converted to correct type.
453 *
454 * @param defaultValue the default value
455 * @return the value
456 */
457 public float getValueAsFloat( final float defaultValue )
458 {
459 if( null == m_value )
460 {
461 return defaultValue;
462 }
463 else
464 {
465 try
466 {
467 return Float.parseFloat( m_value );
468 }
469 catch( final NumberFormatException nfe )
470 {
471 return defaultValue;
472 }
473 }
474 }
475
476 /***
477 * Return an array of all the attribute names.
478 *
479 * @return an array of all the attribute names.
480 */
481 public String[] getAttributeNames()
482 {
483 final Map attributeMap = getAttributeMap();
484 if( null == attributeMap )
485 {
486 return EMPTY_STRING_ARRAY;
487 }
488 else
489 {
490 final Set keys = attributeMap.keySet();
491 return (String[])attributeMap.keySet().toArray( new String[ keys.size() ] );
492 }
493 }
494
495 /***
496 * Return attribute value with specified name.
497 *
498 * @param name the attribute name
499 * @return the attribute value
500 * @throws ConfigurationException if no attribute with
501 * specified name
502 */
503 public String getAttribute( final String name )
504 throws ConfigurationException
505 {
506 final String value = doGetAttribute( name );
507 if( null != value )
508 {
509 return value;
510 }
511 else
512 {
513 final String message =
514 "Attribute named " + name + " not specified.";
515 throw new ConfigurationException( message, getPath(), getLocation() );
516 }
517 }
518
519 /***
520 * Return attribute value with specified name.
521 * If no attribute with specified name then return
522 * default value.
523 *
524 * @param name the attribute name
525 * @param defaultValue the default value
526 * @return the attribute value
527 */
528 public String getAttribute( final String name,
529 final String defaultValue )
530 {
531 final String value = doGetAttribute( name );
532 if( null != value )
533 {
534 return value;
535 }
536 else
537 {
538 return defaultValue;
539 }
540 }
541
542 /***
543 * Return attribute value with specified name or null
544 * if no such attribute.
545 *
546 * @param name the attribute name
547 * @return the attribute value
548 */
549 private String doGetAttribute( final String name )
550 {
551 if( null == name )
552 {
553 throw new NullPointerException( "name" );
554 }
555 final Map attributeMap = getAttributeMap();
556 if( null != attributeMap )
557 {
558 final String value = (String)attributeMap.get( name );
559 if( null != value )
560 {
561 return value;
562 }
563 }
564 return null;
565 }
566
567 /***
568 * Return attribute value with specified name as a boolean.
569 *
570 * @param name the attribute name
571 * @return the attribute value
572 * @throws ConfigurationException if no attribute with
573 * specified name or attribute can not be converted
574 * to correct type
575 */
576 public boolean getAttributeAsBoolean( final String name )
577 throws ConfigurationException
578 {
579 return getAttribute( name ).equals( TRUE_STRING );
580 }
581
582 /***
583 * Return attribute value with specified name as a boolean.
584 * If no attribute with specified name or attribute can
585 * not be converted to correct type then return
586 * default value.
587 *
588 * @param name the attribute name
589 * @param defaultValue the default value
590 * @return the attribute value
591 */
592 public boolean getAttributeAsBoolean( final String name,
593 final boolean defaultValue )
594 {
595 final String value = getAttribute( name, null );
596 if( null != value )
597 {
598 return value.equals( TRUE_STRING );
599 }
600 return defaultValue;
601 }
602
603 /***
604 * Return attribute value with specified name as an integer.
605 *
606 * @param name the attribute name
607 * @return the attribute value
608 * @throws ConfigurationException if no attribute with
609 * specified name or attribute can not be converted
610 * to correct type
611 */
612 public int getAttributeAsInteger( final String name )
613 throws ConfigurationException
614 {
615 final String value = getAttribute( name );
616 try
617 {
618 return Integer.parseInt( value );
619 }
620 catch( final NumberFormatException nfe )
621 {
622 final String message =
623 "Unable to parse " + value + " as an Integer.";
624 throw new ConfigurationException( message, getPath(), getLocation() );
625 }
626 }
627
628 /***
629 * Return attribute value with specified name as an integer.
630 * If no attribute with specified name or attribute can
631 * not be converted to correct type then return
632 * default value.
633 *
634 * @param name the attribute name
635 * @param defaultValue the default value
636 * @return the attribute value
637 */
638 public int getAttributeAsInteger( final String name,
639 final int defaultValue )
640 {
641 final String value = getAttribute( name, null );
642 if( null != value )
643 {
644 try
645 {
646 return Integer.parseInt( value );
647 }
648 catch( final NumberFormatException nfe )
649 {
650 //Fall through to return defaultValue
651 }
652 }
653 return defaultValue;
654 }
655
656 /***
657 * Return attribute value with specified name as a long.
658 *
659 * @param name the attribute name
660 * @return the attribute value
661 * @throws ConfigurationException if no attribute with
662 * specified name or attribute can not be converted
663 * to correct type
664 */
665 public long getAttributeAsLong( final String name )
666 throws ConfigurationException
667 {
668 final String value = getAttribute( name );
669 try
670 {
671 return Long.parseLong( value );
672 }
673 catch( final NumberFormatException nfe )
674 {
675 final String message =
676 "Unable to parse " + value + " as a Long.";
677 throw new ConfigurationException( message, getPath(), getLocation() );
678 }
679 }
680
681 /***
682 * Return attribute value with specified name as a long.
683 * If no attribute with specified name or attribute can
684 * not be converted to correct type then return
685 * default value.
686 *
687 * @param name the attribute name
688 * @param defaultValue the default value
689 * @return the attribute value
690 */
691 public long getAttributeAsLong( final String name,
692 final long defaultValue )
693 {
694 final String value = getAttribute( name, null );
695 if( null != value )
696 {
697 try
698 {
699 return Long.parseLong( value );
700 }
701 catch( final NumberFormatException nfe )
702 {
703 //Fall through to return defaultValue
704 }
705 }
706 return defaultValue;
707 }
708
709 /***
710 * Return attribute value with specified name as afloat.
711 *
712 * @param name the attribute name
713 * @return the attribute value
714 * @throws ConfigurationException if no attribute with
715 * specified name or attribute can not be converted
716 * to correct type
717 */
718 public float getAttributeAsFloat( final String name )
719 throws ConfigurationException
720 {
721 final String value = getAttribute( name );
722 try
723 {
724 return Float.parseFloat( value );
725 }
726 catch( final NumberFormatException nfe )
727 {
728 final String message =
729 "Unable to parse " + value + " as a Float.";
730 throw new ConfigurationException( message, getPath(), getLocation() );
731 }
732 }
733
734 /***
735 * Return attribute value with specified name as a float.
736 * If no attribute with specified name or attribute can
737 * not be converted to correct type then return
738 * default value.
739 *
740 * @param name the attribute name
741 * @param defaultValue the default value
742 * @return the attribute value
743 */
744 public float getAttributeAsFloat( final String name,
745 final float defaultValue )
746 {
747 final String value = getAttribute( name, null );
748 if( null != value )
749 {
750 try
751 {
752 return Float.parseFloat( value );
753 }
754 catch( final NumberFormatException nfe )
755 {
756 //Fall through to return defaultValue
757 }
758 }
759 return defaultValue;
760 }
761
762 /***
763 * Mark the configuration and child configurations as read only.
764 */
765 public void makeReadOnly()
766 {
767 super.makeReadOnly();
768 final List children = getChildList();
769 if( null != children )
770 {
771 final int count = children.size();
772 for( int i = 0; i < count; i++ )
773 {
774 final Configuration configuration = (Configuration)children.get( i );
775 if( configuration instanceof Freezable )
776 {
777 ( (Freezable)configuration ).makeReadOnly();
778 }
779 }
780 }
781 }
782
783 /***
784 * Set an attribute of configuration.
785 *
786 * @param key the attribute key
787 * @param value the attribute value
788 */
789 public void setAttribute( final String key,
790 final String value )
791 {
792 if( null == key )
793 {
794 throw new NullPointerException( "key" );
795 }
796 if( null == value )
797 {
798 throw new NullPointerException( "value" );
799 }
800 checkWriteable();
801 if( null == m_attributes )
802 {
803 m_attributes = new HashMap();
804 }
805 m_attributes.put( key, value );
806 }
807
808 /***
809 * Add a child configuration element.
810 *
811 * @param configuration the child configuration element.
812 */
813 public void addChild( final Configuration configuration )
814 {
815 if( null == configuration )
816 {
817 throw new NullPointerException( "configuration" );
818 }
819 checkWriteable();
820 if( null != m_value )
821 {
822 throwMixedContentException();
823 }
824 if( null == m_children )
825 {
826 m_children = new ArrayList();
827 }
828 m_children.add( configuration );
829 }
830
831 /***
832 * Set the value of the configuration element.
833 *
834 * @param value the value of the configuration element.
835 */
836 public void setValue( final String value )
837 {
838 if( null == value )
839 {
840 throw new NullPointerException( "value" );
841 }
842 checkWriteable();
843 final List children = getChildList();
844 if( null != children && 0 != children.size() )
845 {
846 throwMixedContentException();
847 }
848 m_value = value;
849 }
850
851 /***
852 * Overide toString to improve ability to debug implementation.
853 *
854 * @return string representation of object
855 */
856 public String toString()
857 {
858 final StringBuffer sb = new StringBuffer();
859 sb.append( "[Configuration name='" );
860 sb.append( getName() );
861 sb.append( "'" );
862 if( null != m_attributes )
863 {
864 sb.append( " attributes=" );
865 sb.append( m_attributes );
866 }
867 sb.append( "]" );
868 return sb.toString();
869 }
870
871 /***
872 * Return the list of child configuration objects.
873 *
874 * @return the list of child configuration objects.
875 */
876 protected final List getChildList()
877 {
878 return m_children;
879 }
880
881 /***
882 * Return the backing map for attributes.
883 *
884 * @return the backing map for attributes.
885 */
886 protected final Map getAttributeMap()
887 {
888 return m_attributes;
889 }
890
891 /***
892 * Generate a location string that postfixes
893 * autogenerated marker.
894 *
895 * @return a autogenerated location string
896 */
897 protected final String generateLocation()
898 {
899 final String location = getLocation();
900 if( !location.endsWith( AUTOGEN_POSTFIX ) )
901 {
902 return location + AUTOGEN_POSTFIX;
903 }
904 else
905 {
906 return location;
907 }
908 }
909
910 /***
911 * Throw an IllegalStateException warning about
912 * mixed content.
913 */
914 protected final void throwMixedContentException()
915 {
916 final String message =
917 "Configuration objects do not support Mixed content. " +
918 "Configuration elements should not have both a value and " +
919 "child elements.";
920 throw new IllegalStateException( message );
921 }
922 }
This page was automatically generated by Maven