|
From: <jas...@ma...> - 2005-06-09 15:28:03
|
Quite a few folks have wanted some way to extend/enhance Spring's XML configuration file mechanism to provide more concise XML with richer XML validation (through schemas and XSD extension etc). Here's some background ideas... http://article.gmane.org/gmane.comp.java.springframework.devel/8301/ match=neater+xml++xsd Yet another project I work on, ServiceMix, needed this - and I didn't have the heart to go down the XSLT route I've done before (e.g. on ActiveMQ) - so I thought I'd experiment actually working on Spring to provide an 'XML extension point' for XML configuration files. Example ======= First here's the example of what the XML looks like in ServiceMix before, using standard Spring - then afterwards with the 'XML extensions' so you can see the kind of thing I mean. regular Spring config. http://cvs.servicemix.codehaus.org/servicemix/base/src/test/resources/ org/servicemix/jbi/config/example-spring.xml?rev=HEAD&view=auto extended Spring http://cvs.servicemix.codehaus.org/servicemix/base/src/test/resources/ org/servicemix/jbi/config/example.xml?rev=HEAD&view=auto Now ServiceMix users can use a *much* more concise XML, if they want - we can easily add an XSD that can validate the ServiceMix model much better - but we can still mix and match all the great Spring XML stuff in there too. Its just a couple of trivial, simple macros (<components>, <component> and <qname>) to simplify the XML. From ServiceMix's perspective, we've implemented these new tags in the XML using a couple of pretty-trivial classes. The neat thing about this is that folks can now start to mix and match custom XML languages with the Spring XML. e.g. folks building Geronimo's web, JCA and EJB containers can use Spring XML to deal with J2EE deployment descriptors, but allow those files to include Spring XML too! Implementation ============ Now we could use inheritance to add custom XML processing (we did this in ActiveMQ) - each library developer would then provide their own definition reader / bean factory implementation; the problem with that is there are so many kinds of bean factory & application context and many ways to make them - having a custom bean factory didn't seem a clean solution. Plus I'd like us to mix and match different extensions together into the same Spring XML document. So I decided to try add a 'META-INF/services/' style of auto-discovery. The basic idea is that the standard spring configuration mechanism, will parse the regular Spring XML elements, but any new ones it doesn't recognise, it will see if there is an ElementProcessor class registered for the given element name (using namespaces too if need be). An ElementProcessor is a trivial little plugin interface allowing folks to turn any-old-XML into regular Spring <bean> <property> elements. Using XML extensions ================ So if you parse the this example 'extended' spring XML, with the latest CVS HEAD and the ServiceMix jar on your classpath... http://cvs.servicemix.codehaus.org/servicemix/base/src/test/resources/ org/servicemix/jbi/config/example.xml?rev=HEAD&view=auto it will automatically parse these new XML extensions! (To use the ServiceMix example above, since it uses arbitrary XML namespaces, you have to turn of XML validation to avoid using the DTD (*)) The neat thing is, different folks can now provide different extensions on the classpath. So we could have groovy, activemq, servicemix, geronimo-jca and geronimo-ejb, all making their own extensions, having their own XSDs and all used freely inside a single XML document. Impact ===== As it turns out, the impact on the code was surprisingly small and the entire thing only took about a day to implement - most of which was on the ServiceMix side of things (which is much less than the XSLT took to get right on ActiveMQ! :). The impact on the Spring codebase is a couple of fairly straightforward small methods added to the current parser, 1 new extension interface (ElementProcessor) and an optional helper class, ElementProcessorSupport that wraps up a bunch of useful helper methods for transforming DOM nodes and adding Spring XML elements. Due to the minimal impact of these changes & ease of backing them out again, I've gone ahead and checked them straight in. Please take a look and see what you think. I'm using ServiceMix (http:// servicemix.org/) as the test case right now; if there's general agreement among the team with this approach, I'll add some spring specific test cases into CVS to test it out inside the spring unit test suite. Remaining Issues ============= This whole spike was surprisingly simple to do and had minimal impact on Spring. (*) The only gotcha was, Spring uses XML validation by default - which forces a DOCTYPE to be specified - and DOCTYPEs don't like arbitrary namespaces to be used. So I've added an xmlValidating property on AbstractXmlApplicationContext and a new constructor on BeanFactory so you can turn off validation if you want to. (There could be other places in the code that might need to allow validation to be turned off, but that should do for a start). I guess if we had a Spring XSD, then we could enforce validation all the time and folks who wish to extend the XML must specify one more more XSD references in the XML? Thoughts? James ------- http://radio.weblogs.com/0112098/ |