|
|||||
|
|||||
Dynamic Registration Tags
In this article, we'll demonstrate a few ways to dramatically simplify configuration task to configure similar components. ProblemNormally, one top level tag registers one component. If we have 1000 components to register into the container, we need at least 1000 top level tags to finish the task. This is fine if the configuration of these components differ from each other. It is however a pain if they share the same pattern. For instance, the following configuration declares a bunch of domain classes as Java Bean using auto-wiring: <body> <bean id="Customer" class="com.mycompany.Customer" property-names="*" autowire="bytype"/> <bean id="Account" class="com.mycompany.Account" property-names="*" autowire="bytype"/> <bean id="Bank" class="com.mycompany.Bank" property-names="*" autowire="bytype"/> <bean id="Person" class="com.mycompany.Person" property-names="*" autowire="bytype"/> ... </body> These definitions share very similar pattern. The only thing different is the class name and the id. SolutionFor this case, there are two out-of-box optional Nut classes that can help:
If we load the ForeachRegisterNut as <define>: <nut name="define" class="jfun.yan.xml.nuts.optional.ForeachRegisterNut"/> We can simplify the definitions into one tag: <nut name="define" class="jfun.yan.xml.nuts.optional.ForeachRegisterNut"/> <body> <define names="Customer,Account,Bank,Person"> <function params="name"> <bean class="com.mycompany.${name}" property-names="*" autowire="bytype"/> </function> </define> </body> <define> will repeatedly call the nested function by passing every name into it. The result will be dynamically registered into the container. Just in case you don't already know, the "${name}" is string interpolation. It evaluates to "com.mycompany.Customer" when the value of variable "name" is "Customer". Now, all we have to do is just listing the simple class names in the "names" attribute. The PropertiesRegisterNut is slightly different than ForeachRegisterNut in that it doesn't require you explicitly listing all the names. Instead, it accepts a property file name and read the keys and values from this file. So, if we have a properties file named "domains.properties" located in the classpath under "/com/mycompany/": Customer=com.mycompany.Customer Account=com.mycompany.Account Bank=com.mycompany.Bank Person=com.mycompany.Person we can load the PropertiesRegisterNut and use it as: <nut name="register" class="jfun.yan.xml.nuts.optional.PropertiesRegisterNut"/> <body> <register resource="/com/mycompany/domains.properties"> <function params="id,name"> <bean class="$name" property-names="*" autowire="bytype"/> </function> </define> </body> Sometimes, we may want to register Customer under fully qualified name "com.mycompany.Customer". This can be done with the "prefix" attribute of these two Nut classes. For example: <nut name="register" class="jfun.yan.xml.nuts.optional.PropertiesRegisterNut"/> <body> <register prefix="com.mycompany." resource="/com/mycompany/domains.properties"> <function params="prefix,id,name"> <bean class="${prefix}${name}" property-names="*" autowire="bytype"/> </function> </define> </body> Or, <nut name="define" class="jfun.yan.xml.nuts.optional.ForeachRegisterNut"/> <body> <define prefix="com.mycompany." names="Customer,Account,Bank,Person"> <function params="prefix,name"> <bean class="${prefix}${name}" property-names="*" autowire="bytype"/> </function> </define> </body> Restrictions
More ExtensionForeachRegisterNut and PropertiesRegisterNut both extend from AbstractLoopRegisterNut. In case these two tags cannot handle your case, just extend from them or from AbstractLoopRegisterNut to provide your own implementation. You may for example implement auto-registration of classes from a jar file, or any other mechanism. |
|||||
|
Copyright 2003-2006 - The Codehaus. All rights reserved unless otherwise noted.
Powered by Atlassian Confluence
|
|||||