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

Classes in this File | Line Coverage | Branch Coverage | Complexity
XMLPropertyListConfiguration |
82% | 88/107
90% | 19/21
| 2.5517241379310347;2,552
XMLPropertyListConfiguration$1 |
100% | 2/2
N/A | N/A
| 2.5517241379310347;2,552
XMLPropertyListConfiguration$ArrayNode |
100% | 5/5
N/A | N/A
| 2.5517241379310347;2,552
XMLPropertyListConfiguration$PListNode |
78% | 28/36
67% | 2/3
| 2.5517241379310347;2,552
XMLPropertyListConfiguration$XMLPropertyListHandler |
100% | 52/52
100% | 16/16
| 2.5517241379310347;2,552

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