##### 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.5172413793103448;2,517
XMLPropertyListConfiguration$1 |
100% | 2/2
N/A | N/A
| 2.5172413793103448;2,517
XMLPropertyListConfiguration$ArrayNode |
100% | 5/5
N/A | N/A
| 2.5172413793103448;2,517
XMLPropertyListConfiguration$PListNode |
70% | 21/30
50% | 1/2
| 2.5172413793103448;2,517
XMLPropertyListConfiguration$XMLPropertyListHandler |
100% | 62/62
100% | 16/16
| 2.5172413793103448;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 |  |
     }