Search code examples
javaxmlgroovyapache-commonsapache-commons-config

How to save xml configuration filled with values from properties file in Apache Commons Configuration can't save


I am trying to use Apache Commons Configuration in groovy script to read values from a simple properties file and fill an XML template with these values from that file. The goal of this example is to be able to launch multiple instances of Tomcat with settings defined in properties files. Despite monstrosity of Apache Commons Configuration framework it was chosen because of its ability to read/write/validate different configuration types right out of the box.

Template is a piece of tomcat's server.xml:

<?xml version='1.0' encoding='utf-8'?>
<Server port="${tomcat.server.port}" shutdown="SHUTDOWN">
    <Service name="Catalina">
        <Connector port="${tomcat.http.port}"
                   address="${tomcat.http.ip}"/>
        <Engine jvmRoute="${tomcat.jvmroute}"/>
    </Service>
</Server>

And properties file (let's say tomcat.properties):

application=someapp
tomcat.server.port=8087
tomcat.http.port=8088
tomcat.jvmroute=${application}

I use DefaultConfigurationBuilder to combine these files into configuration. Definitions file is being created dynamically. Code:

import groovy.xml.MarkupBuilder
import org.apache.commons.configuration.*

String configurationDefinition = "tomcat.configuration.xml"
File configurationDefinitionFile = new File(configurationDefinition)
FileWriter configurationDefinitionWriter = new FileWriter(configurationDefinitionFile)
MarkupBuilder fileList = new MarkupBuilder(configurationDefinitionWriter)
fileList.configuration() {
    properties(fileName:'tomcat.properties')
    xml(fileName:'server.xml')
}
configurationDefinitionWriter.close()

DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
builder.setFile(configurationDefinitionFile);
Configuration propertiesConfig = builder.getConfiguration(true);
//propertiesConfig.getKeys().each {  propertyName ->
//    println("$propertyName = ${propertiesConfig.getString(propertyName)}")
//}

XMLConfiguration conf = (XMLConfiguration)propertiesConfig.getConfiguration(1)
//conf.getKeys().each {  propertyName ->
//    println("$propertyName = ${conf.getString(propertyName)}")
//}
conf.save("server_parsed.xml")

Saved file is identical to server.xml above. e.g. with port="${tomcat.server.port}" Is there any way to save it with values from properties file?


Solution

  • A deeper research of builder methods and the userguide helped to find out a way to do it.

    AbstractConfiguration provides the method interpolatedConfiguration(). This method creates a clone of the current configuration and then performs interpolation on all of its properties. So the result of this method is a configuration object with basically the same content as the original configuration, but with all variables replaced by their actual values (as far as this was possible).

    So the following piece of code works perfectly:

    import groovy.xml.MarkupBuilder
    import org.apache.commons.configuration.*
    
    String configurationDefinition = "tomcat.configuration.xml"
    File configurationDefinitionFile = new File(configurationDefinition)
    FileWriter configurationDefinitionWriter = new FileWriter(configurationDefinitionFile)
    MarkupBuilder fileList = new MarkupBuilder(configurationDefinitionWriter)
    fileList.configuration() {
        properties(fileName:'tomcat.properties')
        xml(fileName:'server.xml')
    }
    configurationDefinitionWriter.close()
    
    DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
    builder.setFile(configurationDefinitionFile);
    Configuration propertiesConfig = builder.getConfiguration(true);
    
    XMLConfiguration conf = (XMLConfiguration)propertiesConfig.getConfiguration(1)
    XMLConfiguration  interpolatedConf = (XMLConfiguration )conf.interpolatedConfiguration()
    interpolatedConf.save("server_parsed.xml")
    

    It's sad that google does not associate interpolation with substitution and replacement.