##### Coverage Report - org.apache.commons.configuration.plist.XMLPropertyListConfiguration

Classes in this File | Line Coverage | Branch Coverage | Complexity
XMLPropertyListConfiguration |
82% | 93/113
91% | 20/22
| 2.0434782608695654;2,043
XMLPropertyListConfiguration$1 |
100% | 2/2
N/A | N/A
| 2.0434782608695654;2,043
XMLPropertyListConfiguration$2 |
100% | 2/2
N/A | N/A
| 2.0434782608695654;2,043
XMLPropertyListConfiguration$3 |
100% | 5/5
N/A | N/A
| 2.0434782608695654;2,043
XMLPropertyListConfiguration$ArrayNode |
100% | 5/5
N/A | N/A
| 2.0434782608695654;2,043
XMLPropertyListConfiguration$PListNode |
71% | 20/28
50% | 1/2
| 2.0434782608695654;2,043
XMLPropertyListConfiguration$SetNextAndPopRule |
100% | 6/6
N/A | N/A
| 2.0434782608695654;2,043

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.plist;
19 |  |
20 |  |
     import java.io.File;
21 |  |
     import java.io.PrintWriter;
22 |  |
     import java.io.Reader;
23 |  |
     import java.io.Writer;
24 |  |
     import java.math.BigDecimal;
25 |  |
     import java.net.URL;
26 |  |
     import java.text.DateFormat;
27 |  |
     import java.text.ParseException;
28 |  |
     import java.text.SimpleDateFormat;
29 |  |
     import java.util.ArrayList;
30 |  |
     import java.util.Calendar;
31 |  |
     import java.util.Date;
32 |  |
     import java.util.Iterator;
33 |  |
     import java.util.List;
34 |  |
     import java.util.Map;
35 |  |
36 |  |
     import org.apache.commons.codec.binary.Base64;
37 |  |
     import org.apache.commons.configuration.AbstractHierarchicalFileConfiguration;
38 |  |
     import org.apache.commons.configuration.Configuration;
39 |  |
     import org.apache.commons.configuration.ConfigurationException;
40 |  |
     import org.apache.commons.configuration.HierarchicalConfiguration;
41 |  |
     import org.apache.commons.configuration.MapConfiguration;
42 |  |
     import org.apache.commons.digester.AbstractObjectCreationFactory;
43 |  |
     import org.apache.commons.digester.Digester;
44 |  |
     import org.apache.commons.digester.ObjectCreateRule;
45 |  |
     import org.apache.commons.digester.SetNextRule;
46 |  |
     import org.apache.commons.lang.StringEscapeUtils;
47 |  |
     import org.apache.commons.lang.StringUtils;
48 |  |
     import org.xml.sax.Attributes;
49 |  |
     import org.xml.sax.EntityResolver;
50 |  |
     import org.xml.sax.InputSource;
51 |  |
52 |  |
     /**
53 |  |
      * Mac OS X configuration file (http://www.apple.com/DTDs/PropertyList-1.0.dtd).
54 |  |
      *
55 |  |
      * <p>Example:</p>
56 |  |
      * <pre>
57 |  |
      * &lt;?xml version="1.0"?>
58 |  |
      * &lt;!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
59 |  |
      * &lt;plist version="1.0">
60 |  |
      *     &lt;dict>
61 |  |
      *         &lt;key>string&lt;/key>
62 |  |
      *         &lt;string>value1&lt;/string>
63 |  |
      *
64 |  |
      *         &lt;key>integer&lt;/key>
65 |  |
      *         &lt;integer>12345&lt;/integer>
66 |  |
      *
67 |  |
      *         &lt;key>real&lt;/key>
68 |  |
      *         &lt;real>-123.45E-1&lt;/real>
69 |  |
      *
70 |  |
      *         &lt;key>boolean&lt;/key>
71 |  |
      *         &lt;true/>
72 |  |
      *
73 |  |
      *         &lt;key>date&lt;/key>
74 |  |
      *         &lt;date>2005-01-01T12:00:00-0700&lt;/date>
75 |  |
      *
76 |  |
      *         &lt;key>data&lt;/key>
77 |  |
      *         &lt;data>RHJhY28gRG9ybWllbnMgTnVucXVhbSBUaXRpbGxhbmR1cw==&lt;/data>
78 |  |
      *
79 |  |
      *         &lt;key>array&lt;/key>
80 |  |
      *         &lt;array>
81 |  |
      *             &lt;string>value1&lt;/string>
82 |  |
      *             &lt;string>value2&lt;/string>
83 |  |
      *             &lt;string>value3&lt;/string>
84 |  |
      *         &lt;/array>
85 |  |
      *
86 |  |
      *         &lt;key>dictionnary&lt;/key>
87 |  |
      *         &lt;dict>
88 |  |
      *             &lt;key>key1&lt;/key>
89 |  |
      *             &lt;string>value1&lt;/string>
90 |  |
      *             &lt;key>key2&lt;/key>
91 |  |
      *             &lt;string>value2&lt;/string>
92 |  |
      *             &lt;key>key3&lt;/key>
93 |  |
      *             &lt;string>value3&lt;/string>
94 |  |
      *         &lt;/dict>
95 |  |
      *
96 |  |
      *         &lt;key>nested&lt;/key>
97 |  |
      *         &lt;dict>
98 |  |
      *             &lt;key>node1&lt;/key>
99 |  |
      *             &lt;dict>
100 |  |
      *                 &lt;key>node2&lt;/key>
101 |  |
      *                 &lt;dict>
102 |  |
      *                     &lt;key>node3&lt;/key>
103 |  |
      *                     &lt;string>value&lt;/string>
104 |  |
      *                 &lt;/dict>
105 |  |
      *             &lt;/dict>
106 |  |
      *         &lt;/dict>
107 |  |
      *
108 |  |
      *     &lt;/dict>
109 |  |
      * &lt;/plist>
110 |  |
      * </pre>
111 |  |
      *
112 |  |
      * @since 1.2
113 |  |
      *
114 |  |
      * @author Emmanuel Bourg
115 |  |
      * @version $Revision: 439648 $, $Date: 2006-09-02 22:42:10 +0200 (Sa, 02 Sep 2006) $
116 |  |
      */
117 |  |
     public class XMLPropertyListConfiguration extends AbstractHierarchicalFileConfiguration
118 |  |
     {
119 |  |
         /**
120 |  |
          * The serial version UID.
121 |  |
          */
122 |  |
         private static final long serialVersionUID = -3162063751042475985L;
123 |  |
124 |  |
         /** Size of the indentation for the generated file. */
125 |  |
         private static final int INDENT_SIZE = 4;
126 |  |
127 |  |
         /**
128 |  |
          * Creates an empty XMLPropertyListConfiguration object which can be
129 |  |
          * used to synthesize a new plist file by adding values and
130 |  |
          * then saving().
131 |  |
          */
132 |  |
         public XMLPropertyListConfiguration()
133 | 35 |
         {
134 | 35 |
         }
135 |  |
136 |  |
         /**
137 |  |
          * Creates and loads the property list from the specified file.
138 |  |
          *
139 |  |
          * @param fileName The name of the plist file to load.
140 |  |
          * @throws org.apache.commons.configuration.ConfigurationException Error while loading the plist file
141 |  |
          */
142 |  |
         public XMLPropertyListConfiguration(String fileName) throws ConfigurationException
143 |  |
         {
144 | 0 |
             super(fileName);
145 | 0 |
         }
146 |  |
147 |  |
         /**
148 |  |
          * Creates and loads the property list from the specified file.
149 |  |
          *
150 |  |
          * @param file The plist file to load.
151 |  |
          * @throws ConfigurationException Error while loading the plist file
152 |  |
          */
153 |  |
         public XMLPropertyListConfiguration(File file) throws ConfigurationException
154 |  |
         {
155 | 1 |
             super(file);
156 | 1 |
         }
157 |  |
158 |  |
         /**
159 |  |
          * Creates and loads the property list from the specified URL.
160 |  |
          *
161 |  |
          * @param url The location of the plist file to load.
162 |  |
          * @throws ConfigurationException Error while loading the plist file
163 |  |
          */
164 |  |
         public XMLPropertyListConfiguration(URL url) throws ConfigurationException
165 |  |
         {
166 | 0 |
             super(url);
167 | 0 |
         }
168 |  |
169 |  |
         public void load(Reader in) throws ConfigurationException
170 |  |
         {
171 |  |
             // set up the digester
172 | 12 |
             Digester digester = new Digester();
173 |  |
174 |  |
             // set up the DTD validation
175 | 14 |
             digester.setEntityResolver(new EntityResolver()
176 |  |
             {
177 | 12 |
                 public InputSource resolveEntity(String publicId, String systemId)
178 |  |
                 {
179 | 12 |
                     return new InputSource(getClass().getClassLoader().getResourceAsStream("PropertyList-1.0.dtd"));
180 |  |
                 }
181 |  |
             });
182 | 12 |
             digester.setValidating(true);
183 |  |
184 |  |
             // dictionary rules
185 | 12 |
             digester.addRule("*/key", new ObjectCreateRule(PListNode.class)
186 |  |
             {
187 | 12 |
                 public void end() throws Exception
188 |  |
                 {
189 |  |
                     // leave the node on the stack to set the value
190 | 240 |
                 }
191 |  |
             });
192 |  |
193 | 12 |
             digester.addCallMethod("*/key", "setName", 0);
194 |  |
195 | 12 |
             digester.addRule("*/dict/string", new SetNextAndPopRule("addChild"));
196 | 12 |
             digester.addRule("*/dict/data", new SetNextAndPopRule("addChild"));
197 | 12 |
             digester.addRule("*/dict/integer", new SetNextAndPopRule("addChild"));
198 | 12 |
             digester.addRule("*/dict/real", new SetNextAndPopRule("addChild"));
199 | 12 |
             digester.addRule("*/dict/true", new SetNextAndPopRule("addChild"));
200 | 12 |
             digester.addRule("*/dict/false", new SetNextAndPopRule("addChild"));
201 | 12 |
             digester.addRule("*/dict/date", new SetNextAndPopRule("addChild"));
202 | 12 |
             digester.addRule("*/dict/dict", new SetNextAndPopRule("addChild"));
203 |  |
204 | 12 |
             digester.addCallMethod("*/dict/string", "addValue", 0);
205 | 12 |
             digester.addCallMethod("*/dict/data", "addDataValue", 0);
206 | 12 |
             digester.addCallMethod("*/dict/integer", "addIntegerValue", 0);
207 | 12 |
             digester.addCallMethod("*/dict/real", "addRealValue", 0);
208 | 12 |
             digester.addCallMethod("*/dict/true", "addTrueValue");
209 | 12 |
             digester.addCallMethod("*/dict/false", "addFalseValue");
210 | 12 |
             digester.addCallMethod("*/dict/date", "addDateValue", 0);
211 |  |
212 |  |
             // rules for arrays
213 | 12 |
             digester.addRule("*/dict/array", new SetNextAndPopRule("addChild"));
214 | 12 |
             digester.addRule("*/dict/array", new ObjectCreateRule(ArrayNode.class));
215 | 12 |
             digester.addSetNext("*/dict/array", "addList");
216 |  |
217 | 12 |
             digester.addRule("*/array/array", new ObjectCreateRule(ArrayNode.class));
218 | 12 |
             digester.addSetNext("*/array/array", "addList");
219 |  |
220 | 12 |
             digester.addCallMethod("*/array/string", "addValue", 0);
221 | 12 |
             digester.addCallMethod("*/array/data", "addDataValue", 0);
222 | 12 |
             digester.addCallMethod("*/array/integer", "addIntegerValue", 0);
223 | 12 |
             digester.addCallMethod("*/array/real", "addRealValue", 0);
224 | 12 |
             digester.addCallMethod("*/array/true", "addTrueValue");
225 | 12 |
             digester.addCallMethod("*/array/false", "addFalseValue");
226 | 12 |
             digester.addCallMethod("*/array/date", "addDateValue", 0);
227 |  |
228 |  |
             // rule for a dictionary in an array
229 | 12 |
             digester.addFactoryCreate("*/array/dict", new AbstractObjectCreationFactory()
230 |  |
             {
231 | 12 |
                 public Object createObject(Attributes attributes) throws Exception
232 |  |
                 {
233 |  |
                     // create the configuration
234 | 24 |
                     XMLPropertyListConfiguration config = new XMLPropertyListConfiguration();
235 |  |
236 |  |
                     // add it to the ArrayNode
237 | 24 |
                     ArrayNode node = (ArrayNode) getDigester().peek();
238 | 24 |
                     node.addValue(config);
239 |  |
240 |  |
                     // push the root on the stack
241 | 24 |
                     return config.getRoot();
242 |  |
                 }
243 |  |
             });
244 |  |
245 |  |
             // parse the file
246 | 12 |
             digester.push(getRoot());
247 |  |
             try
248 |  |
             {
249 | 12 |
                 digester.parse(in);
250 | 12 |
             }
251 |  |
             catch (Exception e)
252 |  |
             {
253 | 0 |
                 throw new ConfigurationException("Unable to parse the configuration file", e);
254 |  |
             }
255 | 12 |
         }
256 |  |
257 |  |
         /**
258 |  |
          * Digester rule that sets the object on the stack to the n-1 object
259 |  |
          * and remove both of them from the stack. This rule is used to remove
260 |  |
          * the configuration node from the stack once its value has been parsed.
261 |  |
          */
262 |  |
         private class SetNextAndPopRule extends SetNextRule
263 |  |
         {
264 |  |
             public SetNextAndPopRule(String methodName)
265 | 108 |
             {
266 | 108 |
                 super(methodName);
267 | 108 |
             }
268 |  |
269 |  |
             public void end(String namespace, String name) throws Exception
270 |  |
             {
271 | 240 |
                 super.end(namespace, name);
272 | 240 |
                 digester.pop();
273 | 240 |
             }
274 |  |
         }
275 |  |
276 |  |
         public void save(Writer out) throws ConfigurationException
277 |  |
         {
278 | 1 |
             PrintWriter writer = new PrintWriter(out);
279 |  |
280 | 1 |
             if (getEncoding() != null)
281 |  |
             {
282 | 0 |
                 writer.println("<?xml version=\"1.0\" encoding=\"" + getEncoding() + "\"?>");
283 |  |
             }
284 |  |
             else
285 |  |
             {
286 | 1 |
                 writer.println("<?xml version=\"1.0\"?>");
287 |  |
             }
288 |  |
289 | 1 |
             writer.println("<!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">");
290 | 1 |
             writer.println("<plist version=\"1.0\">");
291 |  |
292 | 1 |
             printNode(writer, 1, getRoot());
293 |  |
294 | 1 |
             writer.println("</plist>");
295 | 1 |
             writer.flush();
296 | 1 |
         }
297 |  |
298 |  |
         /**
299 |  |
          * Append a node to the writer, indented according to a specific level.
300 |  |
          */
301 |  |
         private void printNode(PrintWriter out, int indentLevel, Node node)
302 |  |
         {
303 | 23 |
             String padding = StringUtils.repeat(" ", indentLevel * INDENT_SIZE);
304 |  |
305 | 23 |
             if (node.getName() != null)
306 |  |
             {
307 | 20 |
                 out.println(padding + "<key>" + StringEscapeUtils.escapeXml(node.getName()) + "</key>");
308 |  |
             }
309 |  |
310 | 23 |
             List children = node.getChildren();
311 | 23 |
             if (!children.isEmpty())
312 |  |
             {
313 | 7 |
                 out.println(padding + "<dict>");
314 |  |
315 | 7 |
                 Iterator it = children.iterator();
316 | 34 |
                 while (it.hasNext())
317 |  |
                 {
318 | 20 |
                     Node child = (Node) it.next();
319 | 20 |
                     printNode(out, indentLevel + 1, child);
320 |  |
321 | 20 |
                     if (it.hasNext())
322 |  |
                     {
323 | 13 |
                         out.println();
324 |  |
                     }
325 |  |
                 }
326 |  |
327 | 7 |
                 out.println(padding + "</dict>");
328 |  |
             }
329 |  |
             else
330 |  |
             {
331 | 16 |
                 Object value = node.getValue();
332 | 16 |
                 printValue(out, indentLevel, value);
333 |  |
             }
334 | 23 |
         }
335 |  |
336 |  |
         /**
337 |  |
          * Append a value to the writer, indented according to a specific level.
338 |  |
          */
339 |  |
         private void printValue(PrintWriter out, int indentLevel, Object value)
340 |  |
         {
341 | 27 |
             String padding = StringUtils.repeat(" ", indentLevel * INDENT_SIZE);
342 |  |
343 | 27 |
             if (value instanceof Date)
344 |  |
             {
345 | 1 |
                 out.println(padding + "<date>" + PListNode.format.format((Date) value) + "</date>");
346 |  |
             }
347 | 26 |
             else if (value instanceof Calendar)
348 |  |
             {
349 | 0 |
                 printValue(out, indentLevel, ((Calendar) value).getTime());
350 |  |
             }
351 | 26 |
             else if (value instanceof Number)
352 |  |
             {
353 | 2 |
                 if (value instanceof Double || value instanceof Float || value instanceof BigDecimal)
354 |  |
                 {
355 | 1 |
                     out.println(padding + "<real>" + value.toString() + "</real>");
356 |  |
                 }
357 |  |
                 else
358 |  |
                 {
359 | 1 |
                     out.println(padding + "<integer>" + value.toString() + "</integer>");
360 |  |
                 }
361 |  |
             }
362 | 24 |
             else if (value instanceof Boolean)
363 |  |
             {
364 | 2 |
                 if (((Boolean) value).booleanValue())
365 |  |
                 {
366 | 1 |
                     out.println(padding + "<true/>");
367 |  |
                 }
368 |  |
                 else
369 |  |
                 {
370 | 1 |
                     out.println(padding + "<false/>");
371 |  |
                 }
372 |  |
             }
373 | 22 |
             else if (value instanceof List)
374 |  |
             {
375 | 5 |
                 out.println(padding + "<array>");
376 | 5 |
                 Iterator it = ((List) value).iterator();
377 | 21 |
                 while (it.hasNext())
378 |  |
                 {
379 | 11 |
                     printValue(out, indentLevel + 1, it.next());
380 |  |
                 }
381 | 5 |
                 out.println(padding + "</array>");
382 |  |
             }
383 | 17 |
             else if (value instanceof HierarchicalConfiguration)
384 |  |
             {
385 | 2 |
                 printNode(out, indentLevel, ((HierarchicalConfiguration) value).getRoot());
386 |  |
             }
387 | 15 |
             else if (value instanceof Configuration)
388 |  |
             {
389 |  |
                 // display a flat Configuration as a dictionary
390 | 0 |
                 out.println(padding + "<dict>");
391 |  |
392 | 0 |
                 Configuration config = (Configuration) value;
393 | 0 |
                 Iterator it = config.getKeys();
394 | 0 |
                 while (it.hasNext())
395 |  |
                 {
396 |  |
                     // create a node for each property
397 | 0 |
                     String key = (String) it.next();
398 | 0 |
                     Node node = new Node(key);
399 | 0 |
                     node.setValue(config.getProperty(key));
400 |  |
401 |  |
                     // print the node
402 | 0 |
                     printNode(out, indentLevel + 1, node);
403 |  |
404 | 0 |
                     if (it.hasNext())
405 |  |
                     {
406 | 0 |
                         out.println();
407 |  |
                     }
408 |  |
                 }
409 | 0 |
                 out.println(padding + "</dict>");
410 |  |
             }
411 | 15 |
             else if (value instanceof Map)
412 |  |
             {
413 |  |
                 // display a Map as a dictionary
414 | 0 |
                 Map map = (Map) value;
415 | 0 |
                 printValue(out, indentLevel, new MapConfiguration(map));
416 |  |
             }
417 | 15 |
             else if (value instanceof byte[])
418 |  |
             {
419 | 1 |
                 String base64 = new String(Base64.encodeBase64((byte[]) value));
420 | 1 |
                 out.println(padding + "<data>" + StringEscapeUtils.escapeXml(base64) + "</data>");
421 |  |
             }
422 |  |
             else
423 |  |
             {
424 | 14 |
                 out.println(padding + "<string>" + StringEscapeUtils.escapeXml(String.valueOf(value)) + "</string>");
425 |  |
             }
426 | 27 |
         }
427 |  |
428 |  |
429 |  |
         /**
430 |  |
          * Node extension with addXXX methods to parse the typed data passed by Digester.
431 |  |
          * <b>Do not use this class !</b> It is used internally by XMLPropertyConfiguration
432 |  |
          * to parse the configuration file, it may be removed at any moment in the future.
433 |  |
          */
434 | 301 |
         public static class PListNode extends Node
435 |  |
         {
436 |  |
             /**
437 |  |
              * The serial version UID.
438 |  |
              */
439 |  |
             private static final long serialVersionUID = -7614060264754798317L;
440 |  |
441 |  |
             /** The standard format of dates in plist files. */
442 | 1 |
             private static DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
443 |  |
444 |  |
             /**
445 |  |
              * Update the value of the node. If the existing value is null, it's
446 |  |
              * replaced with the new value. If the existing value is a list, the
447 |  |
              * specified value is appended to the list. If the existing value is
448 |  |
              * not null, a list with the two values is built.
449 |  |
              *
450 |  |
              * @param value the value to be added
451 |  |
              */
452 |  |
             public void addValue(Object value)
453 |  |
             {
454 | 192 |
                 if (getValue() == null)
455 |  |
                 {
456 | 192 |
                     setValue(value);
457 |  |
                 }
458 | 0 |
                 else if (getValue() instanceof List)
459 |  |
                 {
460 | 0 |
                     List list = (List) getValue();
461 | 0 |
                     list.add(value);
462 |  |
                 }
463 |  |
                 else
464 |  |
                 {
465 | 0 |
                     List list = new ArrayList();
466 | 0 |
                     list.add(getValue());
467 | 0 |
                     list.add(value);
468 | 0 |
                     setValue(list);
469 |  |
                 }
470 | 192 |
             }
471 |  |
472 |  |
             /**
473 |  |
              * Parse the specified string as a date and add it to the values of the node.
474 |  |
              *
475 |  |
              * @param value the value to be added
476 |  |
              */
477 |  |
             public void addDateValue(String value)
478 |  |
             {
479 |  |
                 try
480 |  |
                 {
481 | 12 |
                     addValue(format.parse(value));
482 | 12 |
                 }
483 |  |
                 catch (ParseException e)
484 |  |
                 {
485 | 0 |
                     e.printStackTrace();
486 |  |
                 }
487 | 12 |
             }
488 |  |
489 |  |
             /**
490 |  |
              * Parse the specified string as a byte array in base 64 format
491 |  |
              * and add it to the values of the node.
492 |  |
              *
493 |  |
              * @param value the value to be added
494 |  |
              */
495 |  |
             public void addDataValue(String value)
496 |  |
             {
497 | 12 |
                 addValue(Base64.decodeBase64(value.getBytes()));
498 | 12 |
             }
499 |  |
500 |  |
             /**
501 |  |
              * Parse the specified string as an Interger and add it to the values of the node.
502 |  |
              *
503 |  |
              * @param value the value to be added
504 |  |
              */
505 |  |
             public void addIntegerValue(String value)
506 |  |
             {
507 | 12 |
                 addValue(new Integer(value));
508 | 12 |
             }
509 |  |
510 |  |
             /**
511 |  |
              * Parse the specified string as a Double and add it to the values of the node.
512 |  |
              *
513 |  |
              * @param value the value to be added
514 |  |
              */
515 |  |
             public void addRealValue(String value)
516 |  |
             {
517 | 12 |
                 addValue(new Double(value));
518 | 12 |
             }
519 |  |
520 |  |
             /**
521 |  |
              * Add a boolean value 'true' to the values of the node.
522 |  |
              */
523 |  |
             public void addTrueValue()
524 |  |
             {
525 | 12 |
                 addValue(Boolean.TRUE);
526 | 12 |
             }
527 |  |
528 |  |
             /**
529 |  |
              * Add a boolean value 'false' to the values of the node.
530 |  |
              */
531 |  |
             public void addFalseValue()
532 |  |
             {
533 | 12 |
                 addValue(Boolean.FALSE);
534 | 12 |
             }
535 |  |
536 |  |
             /**
537 |  |
              * Add a sublist to the values of the node.
538 |  |
              *
539 |  |
              * @param node the node whose value will be added to the current node value
540 |  |
              */
541 |  |
             public void addList(ArrayNode node)
542 |  |
             {
543 | 60 |
                 addValue(node.getValue());
544 | 60 |
             }
545 |  |
         }
546 |  |
547 |  |
         /**
548 |  |
          * Container for array elements. <b>Do not use this class !</b>
549 |  |
          * It is used internally by XMLPropertyConfiguration to parse the
550 |  |
          * configuration file, it may be removed at any moment in the future.
551 |  |
          */
552 | 120 |
         public static class ArrayNode extends PListNode
553 |  |
         {
554 |  |
             /**
555 |  |
              * The serial version UID.
556 |  |
              */
557 |  |
             private static final long serialVersionUID = 5586544306664205835L;
558 |  |
559 |  |
             /** The list of values in the array. */
560 | 60 |
             private List list = new ArrayList();
561 |  |
562 |  |
             /**
563 |  |
              * Add an object to the array.
564 |  |
              *
565 |  |
              * @param value the value to be added
566 |  |
              */
567 |  |
             public void addValue(Object value)
568 |  |
             {
569 | 132 |
                 list.add(value);
570 | 132 |
             }
571 |  |
572 |  |
             /**
573 |  |
              * Return the list of values in the array.
574 |  |
              *
575 |  |
              * @return the {@link List} of values
576 |  |
              */
577 |  |
             public Object getValue()
578 |  |
             {
579 | 60 |
                 return list;
580 |  |
             }
581 |  |
         }
582 |  |
     }