Return-Path:
By inheriting from {@link AbstractConfiguration}
this class
- * provides some extended functionaly, e.g. interpolation of property values.
+ * provides some extended functionality, e.g. interpolation of property values.
* Like in {@link PropertiesConfiguration}
property values can
- * contain delimiter characters (the comma ',' per default) and are then splitted
+ * contain delimiter characters (the comma ',' per default) and are then split
* into multiple values. This works for XML attributes and text content of
* elements as well. The delimiter can be escaped by a backslash. As an example
* consider the following XML fragment:
Here the content of the array
element will be splitted at
+ *
Here the content of the array
element will be split at
* the commas, so the array
key will be assigned 4 values. In the
* scalar
property and the text
attribute of the
* cite
element the comma is escaped, so that no splitting is
@@ -139,6 +144,7 @@
* @version $Revision$, $Date$
*/
public class XMLConfiguration extends AbstractHierarchicalFileConfiguration
+ implements EntityResolver
{
/**
* The serial version UID.
@@ -154,6 +160,9 @@
/** The document from this configuration's data source. */
private Document document;
+ /** Stores a map with the registered public IDs.*/
+ private Map registeredEntities = new HashMap();
+
/** Stores the name of the root element. */
private String rootElementName;
@@ -566,6 +575,7 @@
.newInstance();
factory.setValidating(isValidating());
DocumentBuilder result = factory.newDocumentBuilder();
+ result.setEntityResolver(this);
if (isValidating())
{
@@ -831,6 +841,97 @@
nd.addAttribute(convertToXMLNode((ConfigurationNode) it.next()));
}
return nd;
+ }
+
+ /**
+ *
+ * Registers the specified DTD URL for the specified public identifier. + *
+ *
+ * XMLConfiguration
contains an internal
+ * EntityResolver
implementation. This maps
+ * PUBLICID
's to URLs (from which the resource will be
+ * loaded). A common use case for this method is to register local URLs
+ * (possibly computed at runtime by a class loader) for DTDs. This allows
+ * the performance advantage of using a local version without having to
+ * ensure every SYSTEM
URI on every processed XML document is
+ * local. This implementation provides only basic functionality. If more
+ * sophisticated features are required, using
+ * {@link #setDocumentBuilder(DocumentBuilder)} to set a custom
+ * DocumentBuilder
(which also can be initialized with a
+ * custom EntityResolver
) is recommended.
+ *
+ * Note: This method will have no effect when a custom
+ * DocumentBuilder
has been set. (Setting a custom
+ * DocumentBuilder
overrides the internal implementation.)
+ *
+ * Note: This method must be called before the
+ * configuration is loaded. So the default constructor of
+ * XMLConfiguration
should be used, the location of the
+ * configuration file set, registerEntityId()
called, and
+ * finally the load()
method can be invoked.
+ *
EntityResolver
interface. It checks
+ * the passed in public ID against the registered entity IDs and uses a
+ * local URL if possible.
+ *
+ * @param publicId the public identifier of the entity being referenced
+ * @param systemId the system identifier of the entity being referenced
+ * @throws SAXException if a parsing exception occurs
+ * @since 1.5
+ */
+ public InputSource resolveEntity(String publicId, String systemId)
+ throws SAXException
+ {
+ // Has this system identifier been registered?
+ URL entityURL = null;
+ if (publicId != null)
+ {
+ entityURL = (URL) registeredEntities.get(publicId);
+ }
+
+ if (entityURL != null)
+ {
+ // Obtain an InputSource for this URL. This code is based on the
+ // createInputSourceFromURL() method of Commons Digester.
+ try
+ {
+ URLConnection connection = entityURL.openConnection();
+ connection.setUseCaches(false);
+ InputStream stream = connection.getInputStream();
+ InputSource source = new InputSource(stream);
+ source.setSystemId(entityURL.toExternalForm());
+ return source;
+ }
+ catch (IOException e)
+ {
+ throw new SAXException(e);
+ }
+ }
+ else
+ {
+ // default processing behavior
+ return null;
+ }
}
/**
Modified: commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java?rev=577436&r1=577435&r2=577436&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java (original)
+++ commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestXMLConfiguration.java Wed Sep 19 13:29:42 2007
@@ -1227,6 +1227,40 @@
}
/**
+ * Tests registering the publicId of a DTD.
+ */
+ public void testRegisterEntityId() throws ConfigurationException,
+ IOException
+ {
+ File dtdFile = new File("conf/properties.dtd");
+ final String publicId = "http://commons.apache.org/test/properties.dtd";
+ conf = new XMLConfiguration("testDtd.xml");
+ conf.setPublicID(publicId);
+ conf.save(testSaveConf);
+ XMLConfiguration checkConfig = new XMLConfiguration();
+ checkConfig.setFile(testSaveConf);
+ checkConfig.registerEntityId(publicId, dtdFile.toURL());
+ checkConfig.setValidating(true);
+ checkSavedConfig(checkConfig);
+ }
+
+ /**
+ * Tries to register a null public ID. This should cause an exception.
+ */
+ public void testRegisterEntityIdNull() throws IOException
+ {
+ try
+ {
+ conf.registerEntityId(null, new URL("http://commons.apache.org"));
+ fail("Could register null public ID!");
+ }
+ catch (IllegalArgumentException iex)
+ {
+ // ok
+ }
+ }
+
+ /**
* Prepares a configuration object for testing a reload operation.
*
* @return the initialized configuration