Skip to content

Commit 8b26e6e

Browse files
committed
Implemented the load() method of XMLPropertyListConfiguration in pure SAX, thus dropping the dependency on Digester and BeanUtils for this class
Added the INIConfiguration on the main page Updated my personal info git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/configuration/trunk@526941 13f79535-47bb-0310-9956-ffa450edef68
1 parent 8c42aa9 commit 8b26e6e

File tree

6 files changed

+177
-105
lines changed

6 files changed

+177
-105
lines changed

pom.xml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,9 @@
127127
<developer>
128128
<name>Emmanuel Bourg</name>
129129
<id>ebourg</id>
130-
<email>smanux@lfjr.net</email>
130+
<email>ebourg@apache.org</email>
131+
<organization>Ariane Software</organization>
132+
<timezone>+1</timezone>
131133
<roles>
132134
<role>Java Developer</role>
133135
</roles>
@@ -180,7 +182,7 @@
180182
<contributor>
181183
<name>Nicolas De Loof</name>
182184
<email>nicolas.deloof@gmail.com</email>
183-
<organization>capgemini</organization>
185+
<organization>Cap Gemini</organization>
184186
</contributor>
185187
</contributors>
186188

project.xml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,9 @@
171171
<developer>
172172
<name>Emmanuel Bourg</name>
173173
<id>ebourg</id>
174-
<email>smanux@lfjr.net</email>
174+
<email>ebourg@apache.org</email>
175+
<organization>Ariane Software</organization>
176+
<timezone>+1</timezone>
175177
</developer>
176178

177179
<developer>
@@ -220,7 +222,7 @@
220222
<contributor>
221223
<name>Nicolas De Loof</name>
222224
<email>nicolas.deloof@gmail.com</email>
223-
<organization>capgemini</organization>
225+
<organization>Cap Gemini</organization>
224226
</contributor>
225227

226228
</contributors>

src/java/org/apache/commons/configuration/plist/XMLPropertyListConfiguration.java

Lines changed: 160 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,23 @@
3232
import java.util.Iterator;
3333
import java.util.List;
3434
import java.util.Map;
35+
import javax.xml.parsers.SAXParser;
36+
import javax.xml.parsers.SAXParserFactory;
3537

3638
import org.apache.commons.codec.binary.Base64;
3739
import org.apache.commons.configuration.AbstractHierarchicalFileConfiguration;
3840
import org.apache.commons.configuration.Configuration;
3941
import org.apache.commons.configuration.ConfigurationException;
4042
import org.apache.commons.configuration.HierarchicalConfiguration;
4143
import org.apache.commons.configuration.MapConfiguration;
42-
import org.apache.commons.digester.AbstractObjectCreationFactory;
43-
import org.apache.commons.digester.Digester;
44-
import org.apache.commons.digester.ObjectCreateRule;
45-
import org.apache.commons.digester.SetNextRule;
4644
import org.apache.commons.lang.StringEscapeUtils;
4745
import org.apache.commons.lang.StringUtils;
46+
4847
import org.xml.sax.Attributes;
4948
import org.xml.sax.EntityResolver;
5049
import org.xml.sax.InputSource;
50+
import org.xml.sax.SAXException;
51+
import org.xml.sax.helpers.DefaultHandler;
5152

5253
/**
5354
* Mac OS X configuration file (http://www.apple.com/DTDs/PropertyList-1.0.dtd).
@@ -137,12 +138,12 @@ public XMLPropertyListConfiguration()
137138
* Creates a new instance of <code>XMLPropertyListConfiguration</code> and
138139
* copies the content of the specified configuration into this object.
139140
*
140-
* @param c the configuration to copy
141+
* @param configuration the configuration to copy
141142
* @since 1.4
142143
*/
143-
public XMLPropertyListConfiguration(HierarchicalConfiguration c)
144+
public XMLPropertyListConfiguration(HierarchicalConfiguration configuration)
144145
{
145-
super(c);
146+
super(configuration);
146147
}
147148

148149
/**
@@ -181,111 +182,33 @@ public XMLPropertyListConfiguration(URL url) throws ConfigurationException
181182

182183
public void load(Reader in) throws ConfigurationException
183184
{
184-
// set up the digester
185-
Digester digester = new Digester();
186-
187185
// set up the DTD validation
188-
digester.setEntityResolver(new EntityResolver()
186+
EntityResolver resolver = new EntityResolver()
189187
{
190188
public InputSource resolveEntity(String publicId, String systemId)
191189
{
192190
return new InputSource(getClass().getClassLoader().getResourceAsStream("PropertyList-1.0.dtd"));
193191
}
194-
});
195-
digester.setValidating(true);
196-
197-
// dictionary rules
198-
digester.addRule("*/key", new ObjectCreateRule(PListNode.class)
199-
{
200-
public void end() throws Exception
201-
{
202-
// leave the node on the stack to set the value
203-
}
204-
});
205-
206-
digester.addCallMethod("*/key", "setName", 0);
207-
208-
digester.addRule("*/dict/string", new SetNextAndPopRule("addChild"));
209-
digester.addRule("*/dict/data", new SetNextAndPopRule("addChild"));
210-
digester.addRule("*/dict/integer", new SetNextAndPopRule("addChild"));
211-
digester.addRule("*/dict/real", new SetNextAndPopRule("addChild"));
212-
digester.addRule("*/dict/true", new SetNextAndPopRule("addChild"));
213-
digester.addRule("*/dict/false", new SetNextAndPopRule("addChild"));
214-
digester.addRule("*/dict/date", new SetNextAndPopRule("addChild"));
215-
digester.addRule("*/dict/dict", new SetNextAndPopRule("addChild"));
216-
217-
digester.addCallMethod("*/dict/string", "addValue", 0);
218-
digester.addCallMethod("*/dict/data", "addDataValue", 0);
219-
digester.addCallMethod("*/dict/integer", "addIntegerValue", 0);
220-
digester.addCallMethod("*/dict/real", "addRealValue", 0);
221-
digester.addCallMethod("*/dict/true", "addTrueValue");
222-
digester.addCallMethod("*/dict/false", "addFalseValue");
223-
digester.addCallMethod("*/dict/date", "addDateValue", 0);
224-
225-
// rules for arrays
226-
digester.addRule("*/dict/array", new SetNextAndPopRule("addChild"));
227-
digester.addRule("*/dict/array", new ObjectCreateRule(ArrayNode.class));
228-
digester.addSetNext("*/dict/array", "addList");
229-
230-
digester.addRule("*/array/array", new ObjectCreateRule(ArrayNode.class));
231-
digester.addSetNext("*/array/array", "addList");
232-
233-
digester.addCallMethod("*/array/string", "addValue", 0);
234-
digester.addCallMethod("*/array/data", "addDataValue", 0);
235-
digester.addCallMethod("*/array/integer", "addIntegerValue", 0);
236-
digester.addCallMethod("*/array/real", "addRealValue", 0);
237-
digester.addCallMethod("*/array/true", "addTrueValue");
238-
digester.addCallMethod("*/array/false", "addFalseValue");
239-
digester.addCallMethod("*/array/date", "addDateValue", 0);
240-
241-
// rule for a dictionary in an array
242-
digester.addFactoryCreate("*/array/dict", new AbstractObjectCreationFactory()
243-
{
244-
public Object createObject(Attributes attributes) throws Exception
245-
{
246-
// create the configuration
247-
XMLPropertyListConfiguration config = new XMLPropertyListConfiguration();
248-
249-
// add it to the ArrayNode
250-
ArrayNode node = (ArrayNode) getDigester().peek();
251-
node.addValue(config);
252-
253-
// push the root on the stack
254-
return config.getRoot();
255-
}
256-
});
192+
};
257193

258194
// parse the file
259-
digester.push(getRoot());
195+
XMLPropertyListHandler handler = new XMLPropertyListHandler(getRoot());
260196
try
261197
{
262-
digester.parse(in);
198+
SAXParserFactory factory = SAXParserFactory.newInstance();
199+
factory.setValidating(true);
200+
201+
SAXParser parser = factory.newSAXParser();
202+
parser.getXMLReader().setEntityResolver(resolver);
203+
parser.getXMLReader().setContentHandler(handler);
204+
parser.getXMLReader().parse(new InputSource(in));
263205
}
264206
catch (Exception e)
265207
{
266208
throw new ConfigurationException("Unable to parse the configuration file", e);
267209
}
268210
}
269211

270-
/**
271-
* Digester rule that sets the object on the stack to the n-1 object
272-
* and remove both of them from the stack. This rule is used to remove
273-
* the configuration node from the stack once its value has been parsed.
274-
*/
275-
private class SetNextAndPopRule extends SetNextRule
276-
{
277-
public SetNextAndPopRule(String methodName)
278-
{
279-
super(methodName);
280-
}
281-
282-
public void end(String namespace, String name) throws Exception
283-
{
284-
super.end(namespace, name);
285-
digester.pop();
286-
}
287-
}
288-
289212
public void save(Writer out) throws ConfigurationException
290213
{
291214
PrintWriter writer = new PrintWriter(out);
@@ -438,6 +361,148 @@ else if (value instanceof byte[])
438361
}
439362
}
440363

364+
/**
365+
* SAX Handler to build the configuration nodes while the document is being parsed.
366+
*/
367+
private class XMLPropertyListHandler extends DefaultHandler
368+
{
369+
private StringBuffer buffer = new StringBuffer();
370+
371+
private List stack = new ArrayList();
372+
373+
public XMLPropertyListHandler(Node root)
374+
{
375+
push(root);
376+
}
377+
378+
/**
379+
* Return the node on the top of the stack.
380+
*/
381+
private Node peek()
382+
{
383+
if (!stack.isEmpty())
384+
{
385+
return (Node) stack.get(stack.size() - 1);
386+
}
387+
else
388+
{
389+
return null;
390+
}
391+
}
392+
393+
/**
394+
* Remove and return the node on the top of the stack.
395+
*/
396+
private Node pop()
397+
{
398+
if (!stack.isEmpty())
399+
{
400+
return (Node) stack.remove(stack.size() - 1);
401+
}
402+
else
403+
{
404+
return null;
405+
}
406+
}
407+
408+
/**
409+
* Put a node on the top of the stack.
410+
*/
411+
private void push(Node node)
412+
{
413+
stack.add(node);
414+
}
415+
416+
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
417+
{
418+
if ("array".equals(qName))
419+
{
420+
push(new ArrayNode());
421+
}
422+
else if ("dict".equals(qName))
423+
{
424+
if (peek() instanceof ArrayNode)
425+
{
426+
// create the configuration
427+
XMLPropertyListConfiguration config = new XMLPropertyListConfiguration();
428+
429+
// add it to the ArrayNode
430+
ArrayNode node = (ArrayNode) peek();
431+
node.addValue(config);
432+
433+
// push the root on the stack
434+
push(config.getRoot());
435+
}
436+
}
437+
}
438+
439+
public void endElement(String uri, String localName, String qName) throws SAXException
440+
{
441+
if ("key".equals(qName))
442+
{
443+
// create a new node, link it to its parent and push it on the stack
444+
PListNode node = new PListNode();
445+
node.setName(buffer.toString());
446+
peek().addChild(node);
447+
push(node);
448+
}
449+
else if ("dict".equals(qName))
450+
{
451+
// remove the root of the XMLPropertyListConfiguration previously pushed on the stack
452+
pop();
453+
}
454+
else
455+
{
456+
if ("string".equals(qName))
457+
{
458+
((PListNode) peek()).addValue(buffer.toString());
459+
}
460+
else if ("integer".equals(qName))
461+
{
462+
((PListNode) peek()).addIntegerValue(buffer.toString());
463+
}
464+
else if ("real".equals(qName))
465+
{
466+
((PListNode) peek()).addRealValue(buffer.toString());
467+
}
468+
else if ("true".equals(qName))
469+
{
470+
((PListNode) peek()).addTrueValue();
471+
}
472+
else if ("false".equals(qName))
473+
{
474+
((PListNode) peek()).addFalseValue();
475+
}
476+
else if ("data".equals(qName))
477+
{
478+
((PListNode) peek()).addDataValue(buffer.toString());
479+
}
480+
else if ("date".equals(qName))
481+
{
482+
((PListNode) peek()).addDateValue(buffer.toString());
483+
}
484+
else if ("array".equals(qName))
485+
{
486+
ArrayNode array = (ArrayNode) pop();
487+
((PListNode) peek()).addList(array);
488+
}
489+
490+
// remove the plist node on the stack once the value has been parsed,
491+
// array nodes remains on the stack for the next values in the list
492+
if (!(peek() instanceof ArrayNode))
493+
{
494+
pop();
495+
}
496+
}
497+
498+
buffer.setLength(0);
499+
}
500+
501+
public void characters(char ch[], int start, int length) throws SAXException
502+
{
503+
buffer.append(ch, start, length);
504+
}
505+
}
441506

442507
/**
443508
* Node extension with addXXX methods to parse the typed data passed by Digester.

xdocs/changes.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323

2424
<body>
2525
<release version="1.5-SNAPSHOT" date="in SVN">
26+
<action dev="ebourg" type="update">
27+
XMLPropertyListConfiguration no longer requires commons-digester and
28+
commons-beanutils to work.
29+
</action>
2630
<action dev="ebourg" type="update">
2731
Fixed INIConfiguration to handle the quoted values and the lines
2832
containing a value and a comment.

0 commit comments

Comments
 (0)