Update: it seems that I failed to have brought accross that the visual look is not very important to me. However, you get actual functionality in your configuration files without necessarely having to give up a structured configuration format. Both the Groovy as the Janino examples are full languages and all the power of them is available right in the configuration files *and* processed dynamically and reloaded.
For a while I've been getting more and more irritated by XML. I don't like how I have to type in tags, how I have to escape text, how everything is passed in as regular text without any typing ... how unlike a regular programming language it is. XML might be great for portable document formats, but for configuration it now feels totally inappropriate.
So today I implemented a few alternative RIFE site structure configuration methods thanks to Groovy and Janino.
I'm very pleased with the results and the Janino version really feels nice. The fact that it's standard Java makes it possible to use all the features of my IDE (code completion, on-the-fly error checking, ...) and still have the benefit of a concise syntax and automatic reloading.
I have done the Groovy version in a similar way, but I only showed what the BuilderSupport class offers more. So the Groovy version is actually able of taking both approaches.
Take a look at the results:
Regular XML
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE site SYSTEM "/dtd/site.dtd">
<site fallbackid="ELEMENT4">
<globalexit name="globalexit1" destid="ELEMENT6"/>
<globalexit name="globalexit2" destid="SUBSITE.ELEMENT2"/>
<globalvar name="globalvar1"/>
<globalvar name="globalvar2"/>
<subsite id="SUBSITE" file="xml/test_xml2sitesubsite.xml" urlprefix="/subsite" inherits="ELEMENT4"/>
<group inherits="ELEMENT5">
<globalvar name="globalvar4"/>
<element id="ELEMENT6" file="xml/test_xml2elementinfo2.xml" url="/test/element6" inherits="ELEMENT3"/>
<element file="xml/test_xml2elementinfo3.xml" url="/test/element7"/>
</group>
<element id="ELEMENT1" file="xml/test_xml2elementinfo1.xml" url="/test/element1">
<datalink srcoutput="output1" destid="ELEMENT2" destinput="input1"/>
<datalink srcoutput="output1" destid="ELEMENT2" destinput="input2"/>
<flowlink srcexit="exit1" destid="ELEMENT2"/>
<flowlink srcexit="exit2" snapback="true"/>
<datalink srcoutput="output2" snapback="t" destinput="input2"/>
</element>
<element id="ELEMENT2" file="xml/test_xml2elementinfo2.xml" inherits="ELEMENT3" url="/test/element2"/>
<element id="ELEMENT3" file="xml/test_xml2elementinfo3.xml"/>
<element id="ELEMENT4" file="xml/test_xml2elementinfo4.xml"/>
<element id="ELEMENT5" file="xml/test_xml2elementinfo5.xml"/>
</site>
Groovy
processor.site(fallbackid:"ELEMENT4") {
globalexit(name:"globalexit1", destid:"ELEMENT6")
globalexit(name:"globalexit2", destid:"SUBSITE.ELEMENT2")
globalvar(name:"globalvar1") {
defaultvalue("default1")
}
globalvar(name:"globalvar2")
subsite(id:"SUBSITE", file:"groovy/test_groovy2sitesubsite.groovy", urlprefix:"/subsite", inherits:"ELEMENT4")
group(inherits:"ELEMENT5") {
globalvar(name:"globalvar4")
element(id:"ELEMENT6", file:"groovy/test_groovy2elementinfo2.groovy", url:"/test/element6", inherits:"ELEMENT3")
element(file:"groovy/test_groovy2elementinfo3.groovy", url:"/test/element7")
}
element(id:"ELEMENT1", file:"groovy/test_groovy2elementinfo1.groovy", url:"/test/element1") {
datalink(srcoutput:"output1", destid:"ELEMENT2", destinput:"input1")
datalink(srcoutput:"output1", destid:"ELEMENT2", destinput:"input2")
flowlink(srcexit:"exit1", destid:"ELEMENT2")
flowlink(srcexit:"exit2", snapback:true)
datalink(srcoutput:"output2", snapback:true, destinput:"input2")
}
element(id:"ELEMENT2", file:"groovy/test_groovy2elementinfo2.groovy", inherits:"ELEMENT3", url:"/test/element2")
element(id:"ELEMENT3", file:"groovy/test_groovy2elementinfo3.groovy")
element(id:"ELEMENT4", file:"groovy/test_groovy2elementinfo4.groovy")
element(id:"ELEMENT5", file:"groovy/test_groovy2elementinfo5.groovy")
}
Janino
builder
.setFallback("ELEMENT4")
.addGlobalExit("globalexit1","ELEMENT6")
.addGlobalExit("globalexit2", "SUBSITE.ELEMENT2")
.addGlobalVar("globalvar1", new String[] {"default1"})
.addGlobalVar("globalvar2")
.enterSubsite("janino/test_janino2sitesubsite.janino")
.setId("SUBSITE")
.setUrlPrefix("/subsite")
.setInherits("ELEMENT4")
.leaveSubsite()
.enterGroup()
.setInherits("ELEMENT5")
.addGlobalVar("globalvar4")
.enterElement("janino/test_janino2elementinfo2.janino")
.setId("ELEMENT6")
.setUrl("/test/element6")
.setInherits("ELEMENT3")
.leaveElement()
.enterElement("janino/test_janino2elementinfo3.janino")
.setUrl("/test/element7")
.leaveElement()
.leaveGroup()
.enterElement("janino/test_janino2elementinfo1.janino")
.setId("ELEMENT1")
.setUrl("/test/element1")
.addDataLink("output1", "ELEMENT2", "input1")
.addDataLink("output1", "ELEMENT2", "input2")
.addFlowLink("exit1", "ELEMENT2")
.addSnapbackFlowLink("exit2", false)
.addSnapbackDataLink("output2", "input2")
.leaveElement()
.enterElement("janino/test_janino2elementinfo2.janino")
.setId("ELEMENT2")
.setInherits("ELEMENT3")
.setUrl("/test/element2")
.leaveElement()
.enterElement("janino/test_janino2elementinfo3.janino")
.setId("ELEMENT3")
.leaveElement()
.enterElement("janino/test_janino2elementinfo4.janino")
.setId("ELEMENT4")
.leaveElement()
.enterElement("janino/test_janino2elementinfo5.janino")
.setId("ELEMENT5")
.leaveElement();