Coverage Report - org.apache.commons.configuration.plist.XMLPropertyListConfiguration
 
Classes in this File Line Coverage Branch Coverage Complexity
XMLPropertyListConfiguration
80%
99/123
90%
19/21
2,517
XMLPropertyListConfiguration$1
100%
2/2
N/A
2,517
XMLPropertyListConfiguration$ArrayNode
100%
5/5
N/A
2,517
XMLPropertyListConfiguration$PListNode
70%
21/30
50%
1/2
2,517
XMLPropertyListConfiguration$XMLPropertyListHandler
100%
62/62
100%
16/16
2,517
 
 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  
 import javax.xml.parsers.SAXParser;
 36  
 import javax.xml.parsers.SAXParserFactory;
 37  
 
 38  
 import org.apache.commons.codec.binary.Base64;
 39  
 import org.apache.commons.configuration.AbstractHierarchicalFileConfiguration;
 40  
 import org.apache.commons.configuration.Configuration;
 41  
 import org.apache.commons.configuration.ConfigurationException;
 42  
 import org.apache.commons.configuration.HierarchicalConfiguration;
 43  
 import org.apache.commons.configuration.MapConfiguration;
 44  
 import org.apache.commons.lang.StringEscapeUtils;
 45  
 import org.apache.commons.lang.StringUtils;
 46  
 
 47  
 import org.xml.sax.Attributes;
 48  
 import org.xml.sax.EntityResolver;
 49  
 import org.xml.sax.InputSource;
 50  
 import org.xml.sax.SAXException;
 51  
 import org.xml.sax.helpers.DefaultHandler;
 52  
 
 53  
 /**
 54  
  * Property list file (plist) in XML format as used by Mac OS X (http://www.apple.com/DTDs/PropertyList-1.0.dtd).
 55  
  * This configuration doesn't support the binary format used in OS X 10.4.
 56  
  *
 57  
  * <p>Example:</p>
 58  
  * <pre>
 59  
  * &lt;?xml version="1.0"?>
 60  
  * &lt;!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
 61  
  * &lt;plist version="1.0">
 62  
  *     &lt;dict>
 63  
  *         &lt;key>string&lt;/key>
 64  
  *         &lt;string>value1&lt;/string>
 65  
  *
 66  
  *         &lt;key>integer&lt;/key>
 67  
  *         &lt;integer>12345&lt;/integer>
 68  
  *
 69  
  *         &lt;key>real&lt;/key>
 70  
  *         &lt;real>-123.45E-1&lt;/real>
 71  
  *
 72  
  *         &lt;key>boolean&lt;/key>
 73  
  *         &lt;true/>
 74  
  *
 75  
  *         &lt;key>date&lt;/key>
 76  
  *         &lt;date>2005-01-01T12:00:00-0700&lt;/date>
 77  
  *
 78  
  *         &lt;key>data&lt;/key>
 79  
  *         &lt;data>RHJhY28gRG9ybWllbnMgTnVucXVhbSBUaXRpbGxhbmR1cw==&lt;/data>
 80  
  *
 81  
  *         &lt;key>array&lt;/key>
 82  
  *         &lt;array>
 83  
  *             &lt;string>value1&lt;/string>
 84  
  *             &lt;string>value2&lt;/string>
 85  
  *             &lt;string>value3&lt;/string>
 86  
  *         &lt;/array>
 87  
  *
 88  
  *         &lt;key>dictionnary&lt;/key>
 89  
  *         &lt;dict>
 90  
  *             &lt;key>key1&lt;/key>
 91  
  *             &lt;string>value1&lt;/string>
 92  
  *             &lt;key>key2&lt;/key>
 93  
  *             &lt;string>value2&lt;/string>
 94  
  *             &lt;key>key3&lt;/key>
 95  
  *             &lt;string>value3&lt;/string>
 96  
  *         &lt;/dict>
 97  
  *
 98  
  *         &lt;key>nested&lt;/key>
 99  
  *         &lt;dict>
 100  
  *             &lt;key>node1&lt;/key>
 101  
  *             &lt;dict>
 102  
  *                 &lt;key>node2&lt;/key>
 103  
  *                 &lt;dict>
 104  
  *                     &lt;key>node3&lt;/key>
 105  
  *                     &lt;string>value&lt;/string>
 106  
  *                 &lt;/dict>
 107  
  *             &lt;/dict>
 108  
  *         &lt;/dict>
 109  
  *
 110  
  *     &lt;/dict>
 111  
  * &lt;/plist>
 112  
  * </pre>
 113  
  *
 114  
  * @since 1.2
 115  
  *
 116  
  * @author Emmanuel Bourg
 117  
  * @version $Revision: 532336 $, $Date: 2007-04-25 14:23:01 +0200 (Mi, 25 Apr 2007) $
 118  
  */
 119  
 public class XMLPropertyListConfiguration extends AbstractHierarchicalFileConfiguration
 120  
 {
 121  
     /**
 122  
      * The serial version UID.
 123  
      */
 124  
     private static final long serialVersionUID = -3162063751042475985L;
 125  
 
 126  
     /** Size of the indentation for the generated file. */
 127  
     private static final int INDENT_SIZE = 4;
 128  
 
 129  
     /**
 130  
      * Creates an empty XMLPropertyListConfiguration object which can be
 131  
      * used to synthesize a new plist file by adding values and
 132  
      * then saving().
 133  
      */
 134  
     public XMLPropertyListConfiguration()
 135  66
     {
 136  66
     }
 137  
 
 138  
     /**
 139  
      * Creates a new instance of <code>XMLPropertyListConfiguration</code> and
 140  
      * copies the content of the specified configuration into this object.
 141  
      *
 142  
      * @param configuration the configuration to copy
 143  
      * @since 1.4
 144  
      */
 145  
     public XMLPropertyListConfiguration(HierarchicalConfiguration configuration)
 146  
     {
 147  1
         super(configuration);
 148  1
     }
 149  
 
 150  
     /**
 151  
      * Creates and loads the property list from the specified file.
 152  
      *
 153  
      * @param fileName The name of the plist file to load.
 154  
      * @throws org.apache.commons.configuration.ConfigurationException Error
 155  
      * while loading the plist file
 156  
      */
 157  
     public XMLPropertyListConfiguration(String fileName) throws ConfigurationException
 158  
     {
 159  2
         super(fileName);
 160  2
     }
 161  
 
 162  
     /**
 163  
      * Creates and loads the property list from the specified file.
 164  
      *
 165  
      * @param file The plist file to load.
 166  
      * @throws ConfigurationException Error while loading the plist file
 167  
      */
 168  
     public XMLPropertyListConfiguration(File file) throws ConfigurationException
 169  
     {
 170  11
         super(file);
 171  11
     }
 172  
 
 173  
     /**
 174  
      * Creates and loads the property list from the specified URL.
 175  
      *
 176  
      * @param url The location of the plist file to load.
 177  
      * @throws ConfigurationException Error while loading the plist file
 178  
      */
 179  
     public XMLPropertyListConfiguration(URL url) throws ConfigurationException
 180  
     {
 181  0
         super(url);
 182  0
     }
 183  
 
 184  
     public void setProperty(String key, Object value)
 185  
     {
 186  
         // special case for byte arrays, they must be stored as is in the configuration
 187  4
         if (value instanceof byte[])
 188  
         {
 189  2
             fireEvent(EVENT_SET_PROPERTY, key, value, true);
 190  2
             setDetailEvents(false);
 191  
             try
 192  
             {
 193  2
                 clearProperty(key);
 194  2
                 addPropertyDirect(key, value);
 195  
             }
 196  
             finally
 197  
             {
 198  2
                 setDetailEvents(true);
 199  2
             }
 200  2
             fireEvent(EVENT_SET_PROPERTY, key, value, false);
 201  2
         }
 202  
         else
 203  
         {
 204  2
             super.setProperty(key, value);
 205  
         }
 206  4
     }
 207  
 
 208  
     public void addProperty(String key, Object value)
 209  
     {
 210  14
         if (value instanceof byte[])
 211  
         {
 212  2
             fireEvent(EVENT_ADD_PROPERTY, key, value, true);
 213  2
             addPropertyDirect(key, value);
 214  2
             fireEvent(EVENT_ADD_PROPERTY, key, value, false);
 215  2
         }
 216  
         else
 217  
         {
 218  12
             super.addProperty(key, value);
 219  
         }
 220  14
     }
 221  
 
 222  
     public void load(Reader in) throws ConfigurationException
 223  
     {
 224  
         // set up the DTD validation
 225  27
         EntityResolver resolver = new EntityResolver()
 226  
         {
 227  27
             public InputSource resolveEntity(String publicId, String systemId)
 228  
             {
 229  27
                 return new InputSource(getClass().getClassLoader().getResourceAsStream("PropertyList-1.0.dtd"));
 230  
             }
 231  
         };
 232  
 
 233  
         // parse the file
 234  27
         XMLPropertyListHandler handler = new XMLPropertyListHandler(getRoot());
 235  
         try
 236  
         {
 237  27
             SAXParserFactory factory = SAXParserFactory.newInstance();
 238  27
             factory.setValidating(true);
 239  
 
 240  27
             SAXParser parser = factory.newSAXParser();
 241  27
             parser.getXMLReader().setEntityResolver(resolver);
 242  27
             parser.getXMLReader().setContentHandler(handler);
 243  27
             parser.getXMLReader().parse(new InputSource(in));
 244  
         }
 245  0
         catch (Exception e)
 246  
         {
 247  0
             throw new ConfigurationException("Unable to parse the configuration file", e);
 248  27
         }
 249  27
     }
 250  
 
 251  
     public void save(Writer out) throws ConfigurationException
 252  
     {
 253  3
         PrintWriter writer = new PrintWriter(out);
 254  
 
 255  3
         if (getEncoding() != null)
 256  
         {
 257  0
             writer.println("<?xml version=\"1.0\" encoding=\"" + getEncoding() + "\"?>");
 258  0
         }
 259  
         else
 260  
         {
 261  3
             writer.println("<?xml version=\"1.0\"?>");
 262  
         }
 263  
 
 264  3
         writer.println("<!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">");
 265  3
         writer.println("<plist version=\"1.0\">");
 266  
 
 267  3
         printNode(writer, 1, getRoot());
 268  
 
 269  3
         writer.println("</plist>");
 270  3
         writer.flush();
 271  3
     }
 272  
 
 273  
     /**
 274  
      * Append a node to the writer, indented according to a specific level.
 275  
      */
 276  
     private void printNode(PrintWriter out, int indentLevel, Node node)
 277  
     {
 278  27
         String padding = StringUtils.repeat(" ", indentLevel * INDENT_SIZE);
 279  
 
 280  27
         if (node.getName() != null)
 281  
         {
 282  22
             out.println(padding + "<key>" + StringEscapeUtils.escapeXml(node.getName()) + "</key>");
 283  
         }
 284  
 
 285  27
         List children = node.getChildren();
 286  27
         if (!children.isEmpty())
 287  
         {
 288  9
             out.println(padding + "<dict>");
 289  
 
 290  9
             Iterator it = children.iterator();
 291  31
             while (it.hasNext())
 292  
             {
 293  22
                 Node child = (Node) it.next();
 294  22
                 printNode(out, indentLevel + 1, child);
 295  
 
 296  22
                 if (it.hasNext())
 297  
                 {
 298  13
                     out.println();
 299  
                 }
 300  22
             }
 301  
 
 302  9
             out.println(padding + "</dict>");
 303  9
         }
 304  
         else
 305  
         {
 306  18
             Object value = node.getValue();
 307  18
             printValue(out, indentLevel, value);
 308  
         }
 309  27
     }
 310  
 
 311  
     /**
 312  
      * Append a value to the writer, indented according to a specific level.
 313  
      */
 314  
     private void printValue(PrintWriter out, int indentLevel, Object value)
 315  
     {
 316  29
         String padding = StringUtils.repeat(" ", indentLevel * INDENT_SIZE);
 317  
 
 318  29
         if (value instanceof Date)
 319  
         {
 320  1
             out.println(padding + "<date>" + PListNode.format.format((Date) value) + "</date>");
 321  1
         }
 322  28
         else if (value instanceof Calendar)
 323  
         {
 324  0
             printValue(out, indentLevel, ((Calendar) value).getTime());
 325  0
         }
 326  28
         else if (value instanceof Number)
 327  
         {
 328  2
             if (value instanceof Double || value instanceof Float || value instanceof BigDecimal)
 329  
             {
 330  1
                 out.println(padding + "<real>" + value.toString() + "</real>");
 331  1
             }
 332  
             else
 333  
             {
 334  1
                 out.println(padding + "<integer>" + value.toString() + "</integer>");
 335  
             }
 336  1
         }
 337  26
         else if (value instanceof Boolean)
 338  
         {
 339  2
             if (((Boolean) value).booleanValue())
 340  
             {
 341  1
                 out.println(padding + "<true/>");
 342  1
             }
 343  
             else
 344  
             {
 345  1
                 out.println(padding + "<false/>");
 346  
             }
 347  1
         }
 348  24
         else if (value instanceof List)
 349  
         {
 350  5
             out.println(padding + "<array>");
 351  5
             Iterator it = ((List) value).iterator();
 352  16
             while (it.hasNext())
 353  
             {
 354  11
                 printValue(out, indentLevel + 1, it.next());
 355  11
             }
 356  5
             out.println(padding + "</array>");
 357  5
         }
 358  19
         else if (value instanceof HierarchicalConfiguration)
 359  
         {
 360  2
             printNode(out, indentLevel, ((HierarchicalConfiguration) value).getRoot());
 361  2
         }
 362  17
         else if (value instanceof Configuration)
 363  
         {
 364  
             // display a flat Configuration as a dictionary
 365  0
             out.println(padding + "<dict>");
 366  
 
 367  0
             Configuration config = (Configuration) value;
 368  0
             Iterator it = config.getKeys();
 369  0
             while (it.hasNext())
 370  
             {
 371  
                 // create a node for each property
 372  0
                 String key = (String) it.next();
 373  0
                 Node node = new Node(key);
 374  0
                 node.setValue(config.getProperty(key));
 375  
 
 376  
                 // print the node
 377  0
                 printNode(out, indentLevel + 1, node);
 378  
 
 379  0
                 if (it.hasNext())
 380  
                 {
 381  0
                     out.println();
 382  
                 }
 383  0
             }
 384  0
             out.println(padding + "</dict>");
 385  0
         }
 386  17
         else if (value instanceof Map)
 387  
         {
 388  
             // display a Map as a dictionary
 389  0
             Map map = (Map) value;
 390  0
             printValue(out, indentLevel, new MapConfiguration(map));
 391  0
         }
 392  17
         else if (value instanceof byte[])
 393  
         {
 394  3
             String base64 = new String(Base64.encodeBase64((byte[]) value));
 395  3
             out.println(padding + "<data>" + StringEscapeUtils.escapeXml(base64) + "</data>");
 396  3
         }
 397  
         else
 398  
         {
 399  14
             out.println(padding + "<string>" + StringEscapeUtils.escapeXml(String.valueOf(value)) + "</string>");
 400  
         }
 401  29
     }
 402  
 
 403  
     /**
 404  
      * SAX Handler to build the configuration nodes while the document is being parsed.
 405  
      */
 406  
     private class XMLPropertyListHandler extends DefaultHandler
 407  
     {
 408  
         /** The buffer containing the text node being read */
 409  27
         private StringBuffer buffer = new StringBuffer();
 410  
 
 411  
         /** The stack of configuration nodes */
 412  27
         private List stack = new ArrayList();
 413  
 
 414  
         public XMLPropertyListHandler(Node root)
 415  27
         {
 416  27
             push(root);
 417  27
         }
 418  
 
 419  
         /**
 420  
          * Return the node on the top of the stack.
 421  
          */
 422  
         private Node peek()
 423  
         {
 424  2010
             if (!stack.isEmpty())
 425  
             {
 426  1983
                 return (Node) stack.get(stack.size() - 1);
 427  
             }
 428  
             else
 429  
             {
 430  27
                 return null;
 431  
             }
 432  
         }
 433  
 
 434  
         /**
 435  
          * Remove and return the node on the top of the stack.
 436  
          */
 437  
         private Node pop()
 438  
         {
 439  731
             if (!stack.isEmpty())
 440  
             {
 441  704
                 return (Node) stack.remove(stack.size() - 1);
 442  
             }
 443  
             else
 444  
             {
 445  27
                 return null;
 446  
             }
 447  
         }
 448  
 
 449  
         /**
 450  
          * Put a node on the top of the stack.
 451  
          */
 452  
         private void push(Node node)
 453  
         {
 454  704
             stack.add(node);
 455  704
         }
 456  
 
 457  
         public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
 458  
         {
 459  1333
             if ("array".equals(qName))
 460  
             {
 461  125
                 push(new ArrayNode());
 462  125
             }
 463  1208
             else if ("dict".equals(qName))
 464  
             {
 465  177
                 if (peek() instanceof ArrayNode)
 466  
                 {
 467  
                     // create the configuration
 468  50
                     XMLPropertyListConfiguration config = new XMLPropertyListConfiguration();
 469  
 
 470  
                     // add it to the ArrayNode
 471  50
                     ArrayNode node = (ArrayNode) peek();
 472  50
                     node.addValue(config);
 473  
 
 474  
                     // push the root on the stack
 475  50
                     push(config.getRoot());
 476  
                 }
 477  
             }
 478  1333
         }
 479  
 
 480  
         public void endElement(String uri, String localName, String qName) throws SAXException
 481  
         {
 482  1333
             if ("key".equals(qName))
 483  
             {
 484  
                 // create a new node, link it to its parent and push it on the stack
 485  502
                 PListNode node = new PListNode();
 486  502
                 node.setName(buffer.toString());
 487  502
                 peek().addChild(node);
 488  502
                 push(node);
 489  502
             }
 490  831
             else if ("dict".equals(qName))
 491  
             {
 492  
                 // remove the root of the XMLPropertyListConfiguration previously pushed on the stack
 493  177
                 pop();
 494  177
             }
 495  
             else
 496  
             {
 497  654
                 if ("string".equals(qName))
 498  
                 {
 499  350
                     ((PListNode) peek()).addValue(buffer.toString());
 500  350
                 }
 501  304
                 else if ("integer".equals(qName))
 502  
                 {
 503  25
                     ((PListNode) peek()).addIntegerValue(buffer.toString());
 504  25
                 }
 505  279
                 else if ("real".equals(qName))
 506  
                 {
 507  25
                     ((PListNode) peek()).addRealValue(buffer.toString());
 508  25
                 }
 509  254
                 else if ("true".equals(qName))
 510  
                 {
 511  25
                     ((PListNode) peek()).addTrueValue();
 512  25
                 }
 513  229
                 else if ("false".equals(qName))
 514  
                 {
 515  25
                     ((PListNode) peek()).addFalseValue();
 516  25
                 }
 517  204
                 else if ("data".equals(qName))
 518  
                 {
 519  27
                     ((PListNode) peek()).addDataValue(buffer.toString());
 520  27
                 }
 521  177
                 else if ("date".equals(qName))
 522  
                 {
 523  25
                     ((PListNode) peek()).addDateValue(buffer.toString());
 524  25
                 }
 525  152
                 else if ("array".equals(qName))
 526  
                 {
 527  125
                     ArrayNode array = (ArrayNode) pop();
 528  125
                     ((PListNode) peek()).addList(array);
 529  
                 }
 530  
 
 531  
                 // remove the plist node on the stack once the value has been parsed,
 532  
                 // array nodes remains on the stack for the next values in the list
 533  654
                 if (!(peek() instanceof ArrayNode))
 534  
                 {
 535  429
                     pop();
 536  
                 }
 537  
             }
 538  
 
 539  1333
             buffer.setLength(0);
 540  1333
         }
 541  
 
 542  
         public void characters(char[] ch, int start, int length) throws SAXException
 543  
         {
 544  954
             buffer.append(ch, start, length);
 545  954
         }
 546  
     }
 547  
 
 548  
     /**
 549  
      * Node extension with addXXX methods to parse the typed data passed by the SAX handler.
 550  
      * <b>Do not use this class !</b> It is used internally by XMLPropertyConfiguration
 551  
      * to parse the configuration file, it may be removed at any moment in the future.
 552  
      */
 553  628
     public static class PListNode extends Node
 554  
     {
 555  
         /**
 556  
          * The serial version UID.
 557  
          */
 558  
         private static final long serialVersionUID = -7614060264754798317L;
 559  
 
 560  
         /** The standard format of dates in plist files. */
 561  2
         private static DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
 562  
 
 563  
         /**
 564  
          * Update the value of the node. If the existing value is null, it's
 565  
          * replaced with the new value. If the existing value is a list, the
 566  
          * specified value is appended to the list. If the existing value is
 567  
          * not null, a list with the two values is built.
 568  
          *
 569  
          * @param value the value to be added
 570  
          */
 571  
         public void addValue(Object value)
 572  
         {
 573  402
             if (getValue() == null)
 574  
             {
 575  402
                 setValue(value);
 576  402
             }
 577  0
             else if (getValue() instanceof List)
 578  
             {
 579  0
                 List list = (List) getValue();
 580  0
                 list.add(value);
 581  0
             }
 582  
             else
 583  
             {
 584  0
                 List list = new ArrayList();
 585  0
                 list.add(getValue());
 586  0
                 list.add(value);
 587  0
                 setValue(list);
 588  
             }
 589  402
         }
 590  
 
 591  
         /**
 592  
          * Parse the specified string as a date and add it to the values of the node.
 593  
          *
 594  
          * @param value the value to be added
 595  
          */
 596  
         public void addDateValue(String value)
 597  
         {
 598  
             try
 599  
             {
 600  25
                 addValue(format.parse(value));
 601  
             }
 602  0
             catch (ParseException e)
 603  
             {
 604  
                 // ignore
 605  
                 ;
 606  25
             }
 607  25
         }
 608  
 
 609  
         /**
 610  
          * Parse the specified string as a byte array in base 64 format
 611  
          * and add it to the values of the node.
 612  
          *
 613  
          * @param value the value to be added
 614  
          */
 615  
         public void addDataValue(String value)
 616  
         {
 617  27
             addValue(Base64.decodeBase64(value.getBytes()));
 618  27
         }
 619  
 
 620  
         /**
 621  
          * Parse the specified string as an Interger and add it to the values of the node.
 622  
          *
 623  
          * @param value the value to be added
 624  
          */
 625  
         public void addIntegerValue(String value)
 626  
         {
 627  25
             addValue(new Integer(value));
 628  25
         }
 629  
 
 630  
         /**
 631  
          * Parse the specified string as a Double and add it to the values of the node.
 632  
          *
 633  
          * @param value the value to be added
 634  
          */
 635  
         public void addRealValue(String value)
 636  
         {
 637  25
             addValue(new Double(value));
 638  25
         }
 639  
 
 640  
         /**
 641  
          * Add a boolean value 'true' to the values of the node.
 642  
          */
 643  
         public void addTrueValue()
 644  
         {
 645  25
             addValue(Boolean.TRUE);
 646  25
         }
 647  
 
 648  
         /**
 649  
          * Add a boolean value 'false' to the values of the node.
 650  
          */
 651  
         public void addFalseValue()
 652  
         {
 653  25
             addValue(Boolean.FALSE);
 654  25
         }
 655  
 
 656  
         /**
 657  
          * Add a sublist to the values of the node.
 658  
          *
 659  
          * @param node the node whose value will be added to the current node value
 660  
          */
 661  
         public void addList(ArrayNode node)
 662  
         {
 663  125
             addValue(node.getValue());
 664  125
         }
 665  
     }
 666  
 
 667  
     /**
 668  
      * Container for array elements. <b>Do not use this class !</b>
 669  
      * It is used internally by XMLPropertyConfiguration to parse the
 670  
      * configuration file, it may be removed at any moment in the future.
 671  
      */
 672  125
     public static class ArrayNode extends PListNode
 673  
     {
 674  
         /**
 675  
          * The serial version UID.
 676  
          */
 677  
         private static final long serialVersionUID = 5586544306664205835L;
 678  
 
 679  
         /** The list of values in the array. */
 680  125
         private List list = new ArrayList();
 681  
 
 682  
         /**
 683  
          * Add an object to the array.
 684  
          *
 685  
          * @param value the value to be added
 686  
          */
 687  
         public void addValue(Object value)
 688  
         {
 689  275
             list.add(value);
 690  275
         }
 691  
 
 692  
         /**
 693  
          * Return the list of values in the array.
 694  
          *
 695  
          * @return the {@link List} of values
 696  
          */
 697  
         public Object getValue()
 698  
         {
 699  125
             return list;
 700  
         }
 701  
     }
 702  
 }