Address Problem - Hard Coding , Need to create custom configuration for your application like struts configuration file to vary application behavior just by changing the file.
Apache Digester can do it for you easily.
Transforming an XML document into a corresponding hierarchy of
Java bean objects is a fairly easy using Apache Digester. See Digester in action below.
Digester introduces three important concepts:
- element matching patterns
- processing rules
- the object stack.
Example :
What you have -
1.Java Classes
2.XML files containing data
You have java classes and corresponding xml files. You want java classses instances to be created from xml data.
What extra code you need to write.
Step by step tasks
1. Add Apache Digester 3 jar file, Commons logging jar, Beanutils jar,cglib jar in your class path
2.If don't have the java classes, create java classes for corresponding xml file.Or if don't have xml files, create it as per the java classes.Note- property name,hierarchy in xml and java class should match, otherwise you need to provide mapping in your digester xml rule not mentioned here.
3.Create a digester rule xml file as mentioned in the example below
4.Use few lines of to load java objects from xml
Now In Action -
Here is my eclipse project structure :
Here is my eclipse project structure :
task 2 -
create data xml file as below you want data from which to be loaded
say - chain-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<catalogs>
<!-- Default Catalog: "Path Info" example -->
<catalog>
<!-- Command that maps "Path Info" patterns to Commands -->
<chain name="COMMAND_MAPPER">
<command className="org.apache.commons.chain.web.servlet.PathInfoMapper"/>
<command forward="/pathinfo.jsp" className="org.apache.commons.chain.apps.example.ForwardCommand"/>
</chain>
<!-- Foo Command -->
<chain name="/foo">
<command attribute="pathinfoFooCount" className="org.apache.commons.chain.apps.example.CountCommand"/>
</chain>
<!-- Bar Command -->
<chain name="/bar">
<command attribute="pathinfoBarCount" className="org.apache.commons.chain.apps.example.CountCommand"/>
</chain>
</catalog>
<!-- Catalog for "Request Parameter" example -->
<catalog name="reqparam">
<!-- Command that maps a "Request Parameter" to Commands -->
<chain name="COMMAND_MAPPER">
<command catalogName="reqparam" className="org.apache.commons.chain.web.servlet.RequestParameterMapper"/>
<command forward="/reqparam.jsp" className="org.apache.commons.chain.apps.example.ForwardCommand"/>
</chain>
<!-- Foo Command -->
<chain name="foo">
<command attribute="reqparamFooCount" className="org.apache.commons.chain.apps.example.CountCommand"/>
</chain>
<!-- Bar Command -->
<chain name="bar">
<command attribute="reqparamBarCount" className="org.apache.commons.chain.apps.example.CountCommand"/>
</chain>
</catalog>
</catalogs>
<catalogs>
<!-- Default Catalog: "Path Info" example -->
<catalog>
<!-- Command that maps "Path Info" patterns to Commands -->
<chain name="COMMAND_MAPPER">
<command className="org.apache.commons.chain.web.servlet.PathInfoMapper"/>
<command forward="/pathinfo.jsp" className="org.apache.commons.chain.apps.example.ForwardCommand"/>
</chain>
<!-- Foo Command -->
<chain name="/foo">
<command attribute="pathinfoFooCount" className="org.apache.commons.chain.apps.example.CountCommand"/>
</chain>
<!-- Bar Command -->
<chain name="/bar">
<command attribute="pathinfoBarCount" className="org.apache.commons.chain.apps.example.CountCommand"/>
</chain>
</catalog>
<!-- Catalog for "Request Parameter" example -->
<catalog name="reqparam">
<!-- Command that maps a "Request Parameter" to Commands -->
<chain name="COMMAND_MAPPER">
<command catalogName="reqparam" className="org.apache.commons.chain.web.servlet.RequestParameterMapper"/>
<command forward="/reqparam.jsp" className="org.apache.commons.chain.apps.example.ForwardCommand"/>
</chain>
<!-- Foo Command -->
<chain name="foo">
<command attribute="reqparamFooCount" className="org.apache.commons.chain.apps.example.CountCommand"/>
</chain>
<!-- Bar Command -->
<chain name="bar">
<command attribute="reqparamBarCount" className="org.apache.commons.chain.apps.example.CountCommand"/>
</chain>
</catalog>
</catalogs>
Create corresponding java classses
Catalog.java :
import java.util.ArrayList;
import java.util.List;
public class Catalog {
/**
* @uml.property name="name"
*/
private String name;
/**
* Getter of the property <tt>name</tt>
* @return Returns the name.
* @uml.property name="name"
*/
public String getName() {
return name;
}
/**
* Setter of the property <tt>name</tt>
* @param name The name to set.
* @uml.property name="name"
*/
public void setName(String name) {
this.name = name;
}
/**
* @uml.property name="chains"
*/
private List<Chain> chains=new ArrayList<Chain>();
public void addChains(Chain chain)
{
this.chains.add(chain);
}
}
import java.util.List;
public class Catalog {
/**
* @uml.property name="name"
*/
private String name;
/**
* Getter of the property <tt>name</tt>
* @return Returns the name.
* @uml.property name="name"
*/
public String getName() {
return name;
}
/**
* Setter of the property <tt>name</tt>
* @param name The name to set.
* @uml.property name="name"
*/
public void setName(String name) {
this.name = name;
}
/**
* @uml.property name="chains"
*/
private List<Chain> chains=new ArrayList<Chain>();
public void addChains(Chain chain)
{
this.chains.add(chain);
}
}
Chain.java :
import java.util.ArrayList;
import java.util.List;
public class Chain {
/**
* @uml.property name="name"
*/
private String name;
/**
* Getter of the property <tt>name</tt>
* @return Returns the name.
* @uml.property name="name"
*/
public String getName() {
return name;
}
/**
* Setter of the property <tt>name</tt>
* @param name The name to set.
* @uml.property name="name"
*/
public void setName(String name) {
this.name = name;
}
/**
* @uml.property name="commands"
*/
private List<Command> commands=new ArrayList<Command>();
/**
* Setter of the property <tt>commands</tt>
* @param commands The commands to set.
* @uml.property name="commands"
*/
public void addCommands(Command command) {
this.commands.add(command);
}
}
import java.util.List;
public class Chain {
/**
* @uml.property name="name"
*/
private String name;
/**
* Getter of the property <tt>name</tt>
* @return Returns the name.
* @uml.property name="name"
*/
public String getName() {
return name;
}
/**
* Setter of the property <tt>name</tt>
* @param name The name to set.
* @uml.property name="name"
*/
public void setName(String name) {
this.name = name;
}
/**
* @uml.property name="commands"
*/
private List<Command> commands=new ArrayList<Command>();
/**
* Setter of the property <tt>commands</tt>
* @param commands The commands to set.
* @uml.property name="commands"
*/
public void addCommands(Command command) {
this.commands.add(command);
}
}
Command.java :
import java.util.ArrayList;
import java.util.List;
public class Chain {
/**
* @uml.property name="name"
*/
private String name;
/**
* Getter of the property <tt>name</tt>
* @return Returns the name.
* @uml.property name="name"
*/
public String getName() {
return name;
}
/**
* Setter of the property <tt>name</tt>
* @param name The name to set.
* @uml.property name="name"
*/
public void setName(String name) {
this.name = name;
}
/**
* @uml.property name="commands"
*/
private List<Command> commands=new ArrayList<Command>();
/**
* Getter of the property <tt>commands</tt>
* @return Returns the commands.
* @uml.property name="commands"
*/
public List getCommands() {
return commands;
}
/**
* Setter of the property <tt>commands</tt>
* @param commands The commands to set.
* @uml.property name="commands"
*/
public void addCommands(Command command) {
this.commands.add(command);
}
}
import java.util.List;
public class Chain {
/**
* @uml.property name="name"
*/
private String name;
/**
* Getter of the property <tt>name</tt>
* @return Returns the name.
* @uml.property name="name"
*/
public String getName() {
return name;
}
/**
* Setter of the property <tt>name</tt>
* @param name The name to set.
* @uml.property name="name"
*/
public void setName(String name) {
this.name = name;
}
/**
* @uml.property name="commands"
*/
private List<Command> commands=new ArrayList<Command>();
/**
* Getter of the property <tt>commands</tt>
* @return Returns the commands.
* @uml.property name="commands"
*/
public List getCommands() {
return commands;
}
/**
* Setter of the property <tt>commands</tt>
* @param commands The commands to set.
* @uml.property name="commands"
*/
public void addCommands(Command command) {
this.commands.add(command);
}
}
task 3 - Create digester rules
digester-catalog-rules.xml
<?xml version="1.0"?>
<!DOCTYPE digester-rules PUBLIC
"-//Apache Commons //DTD digester-rules XML V1.0//EN"
"http://commons.apache.org/digester/dtds/digester-rules-3.0.dtd">
<digester-rules>
<pattern value="catalogs/catalog">
<object-create-rule classname="Catalog"/>
<set-properties-rule/>
<!-- comment :
<!DOCTYPE digester-rules PUBLIC
"-//Apache Commons //DTD digester-rules XML V1.0//EN"
"http://commons.apache.org/digester/dtds/digester-rules-3.0.dtd">
<digester-rules>
<pattern value="catalogs/catalog">
<object-create-rule classname="Catalog"/>
<set-properties-rule/>
<!-- comment :
<bean-property-setter-rule pattern="name"/>
use as shown above if say <catalog><name>reparam</name> </catalog> instead of <catalog name="reparam"> </catalog>
-->
<!-- Nested Pattern for Characters -->
<pattern value="chain">
<object-create-rule classname="Chain"/>
<set-properties-rule/>
<!-- Nested Pattern for Characters -->
<pattern value="command">
<object-create-rule classname="Command"/>
<set-properties-rule/>
<set-next-rule methodname="addCommands" paramtype="Command"/>
</pattern>
<set-next-rule methodname="addChains" paramtype="Chain"/>
</pattern>
<set-next-rule methodname="add" paramtype="Catalog"/>
</pattern>
</digester-rules>
<!-- Nested Pattern for Characters -->
<pattern value="chain">
<object-create-rule classname="Chain"/>
<set-properties-rule/>
<!-- Nested Pattern for Characters -->
<pattern value="command">
<object-create-rule classname="Command"/>
<set-properties-rule/>
<set-next-rule methodname="addCommands" paramtype="Command"/>
</pattern>
<set-next-rule methodname="addChains" paramtype="Chain"/>
</pattern>
<set-next-rule methodname="add" paramtype="Catalog"/>
</pattern>
</digester-rules>
task 4 - Client program to load xml data
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import org.apache.commons.digester3.Digester;
import org.apache.commons.digester3.binder.DigesterLoader;
import org.apache.commons.digester3.xmlrules.FromXmlRulesModule;
import org.xml.sax.SAXException;
import java.util.ArrayList;
import java.util.List;
public class runProgram {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
// Create an instance of the Digester from the XML rule set
DigesterLoader digesterLoader = DigesterLoader.newLoader(new FromXmlRulesModule() {
@Override
protected void loadRules() {
// TODO Auto-generated method stub
loadXMLRules( getClass( ).getResource("/com/tatu/resources/digester-catalog-rules.xml"));
}
});
Digester digester = digesterLoader.newDigester();
List<Catalog> catalogs = new ArrayList<Catalog>();
// Push a reference to the plays List on to the Stack
digester.push(catalogs);
// Parse the XML document
InputStream input = Digester.class.getClass().getResourceAsStream("/com/tatu/resources/chain-config.xml");
try {
Object root = digester.parse(input);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
import java.io.InputStream;
import java.net.URL;
import org.apache.commons.digester3.Digester;
import org.apache.commons.digester3.binder.DigesterLoader;
import org.apache.commons.digester3.xmlrules.FromXmlRulesModule;
import org.xml.sax.SAXException;
import java.util.ArrayList;
import java.util.List;
public class runProgram {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
// Create an instance of the Digester from the XML rule set
DigesterLoader digesterLoader = DigesterLoader.newLoader(new FromXmlRulesModule() {
@Override
protected void loadRules() {
// TODO Auto-generated method stub
loadXMLRules( getClass( ).getResource("/com/tatu/resources/digester-catalog-rules.xml"));
}
});
Digester digester = digesterLoader.newDigester();
List<Catalog> catalogs = new ArrayList<Catalog>();
// Push a reference to the plays List on to the Stack
digester.push(catalogs);
// Parse the XML document
InputStream input = Digester.class.getClass().getResourceAsStream("/com/tatu/resources/chain-config.xml");
try {
Object root = digester.parse(input);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Done. So have loaded the catalogs object with the xml data.
Points to be noted from the above solution:
1.object-create-rule creates an object
2.Rest of the rules are straightforward as their name suggests, object-create-rule creates a new instance, set-properties-rule sets the properties of the object from xml attributes like name attribute of catalog element whereas bean-property-setter-rule sets properties of the object from nested xml elements like say <catalog><name>reparam</name> </catalog> instead of <catalog name="reparam"> </catalog>
3- set-next-rule: (used for recursion) The set-next-rulerule moves to the next catalog, chain, and command tags. You have also specified the method to call in each case which will add the objects to a collection defined in the parent class, example : <set-next-rule methodname="addCommands" paramtype="Command"/>, here addCommands() method adds a command object to commands collection object defined in parent chain class.
4.You want new custom rules,create your own Rule class deriving from digester Rule class.
Any question, put your comments.
One more thought, you don't want all these shit inbetween the xml files and java classes. Guess what, there is a trick to avoid that. But I don't like this trick unless you are in hurry. But everytime you use shortcut, you have to lose flexibilities.
Trick is to use Apache Betwixt. Remember to use Betwixt, you need to use apache digester 2.1. For more go to apache Betwixt site.
Use Betwixt BeanWriter to write the java beans to a file and then, use BeanReader to read from that file. Once you get the file generated from BeanWriter, you can change the values abd load it with BeanReader. (Need to configure betwixt mapping omitted here)
// Write XML document
Writer writer = new FileWriter(
Digester.class.getClass().getResource("/com/tatu/resources/chain-config.xml").getPath().substring(1, Digester.class.getClass().getResource("/com/tatu/resources/chain-config.xml").getPath().indexOf("chain-config.xml")) + "chains-config-betwixt.xml");
BeanWriter beanWriter = new BeanWriter(writer);
beanWriter.enablePrettyPrint( );
beanWriter.write( catalogs );
writer.close();
//read it
Happy coding!!!
4.You want new custom rules,create your own Rule class deriving from digester Rule class.
Any question, put your comments.
One more thought, you don't want all these shit inbetween the xml files and java classes. Guess what, there is a trick to avoid that. But I don't like this trick unless you are in hurry. But everytime you use shortcut, you have to lose flexibilities.
Trick is to use Apache Betwixt. Remember to use Betwixt, you need to use apache digester 2.1. For more go to apache Betwixt site.
Use Betwixt BeanWriter to write the java beans to a file and then, use BeanReader to read from that file. Once you get the file generated from BeanWriter, you can change the values abd load it with BeanReader. (Need to configure betwixt mapping omitted here)
// Write XML document
Writer writer = new FileWriter(
Digester.class.getClass().getResource("/com/tatu/resources/chain-config.xml").getPath().substring(1, Digester.class.getClass().getResource("/com/tatu/resources/chain-config.xml").getPath().indexOf("chain-config.xml")) + "chains-config-betwixt.xml");
BeanWriter beanWriter = new BeanWriter(writer);
beanWriter.enablePrettyPrint( );
beanWriter.write( catalogs );
writer.close();
//read it
InputStream customCatalog =
BeanReader.class.getClass().getResourceAsStream("/com/tatu/resources/chain-config-betwixt.xml");
BeanReader beanReader = new BeanReader( );
beanReader.getXMLIntrospector( ).setWrapCollectionsInElement(false);
beanReader.registerBeanClass(Catalog.class);
Catalog ct = (Catalog) beanReader.parse( customCatalog );
BeanReader.class.getClass().getResourceAsStream("/com/tatu/resources/chain-config-betwixt.xml");
BeanReader beanReader = new BeanReader( );
beanReader.getXMLIntrospector( ).setWrapCollectionsInElement(false);
beanReader.registerBeanClass(Catalog.class);
Catalog ct = (Catalog) beanReader.parse( customCatalog );
Happy coding!!!
Thank u for ur nice post but the command Class is missing so i'm unable to test the appln. So can u please provide the Appln @
ReplyDeletejava4achuta@gmail.com
I think I skip it. Create a command class with three instance variables,forward, className and attribute. That will resolve your issue
DeleteThis comment has been removed by the author.
ReplyDeleteNice example!
ReplyDeleteThe class Command.java for lazy persons:
/************************/
public class Command {
private String className;
private String forward;
private String attribute;
private String catalogName;
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getForward() {
return forward;
}
public void setForward(String forward) {
this.forward = forward;
}
public String getAttribute() {
return attribute;
}
public void setAttribute(String attribute) {
this.attribute = attribute;
}
public String getCatalogName() {
return catalogName;
}
public void setCatalogName(String catalogName) {
this.catalogName = catalogName;
}
}
great
ReplyDeleteThanks for the post, I am techno savvy. I believe you hit the nail right on the head. I am highly impressed with your blog. It is very nicely explained. Your article adds best knowledge to our Java EE Training in Chennai. or learn thru Java EE Training in Chennai Students.
ReplyDeletethank you for your simple and direct example,
ReplyDeletefor whom face a problem with discription like "{ forPattern( "root" ).createObject().ofType( String ) } class 'com.acme.InOtherClassLoader' cannot be load"
just put the fully qualified class path for each class
This is my first time i visit here. I found such a substantial number of interesting stuff in your blog especially its examination. Really its inconceivable article. Keep it up. http://techalook.com
ReplyDeleteBeing a small business owner brings with it a whole host of challenges. Small business owners, especially sole proprietors, are at an increased risk of audit. Included in the article are some smart business practices that will not only help https://adesk.cheapsoftwaredownload.net/autodesk-maya.html define and grow your business, but will also help you document that you are running a real business and not just performing a hobby. Read this article to find out more about the IRS Hobby Loss Rule.
ReplyDeleteMost comprehensive information about confusing loan programs. Differences between Adjustable Rate Mortgages and Interest Only loans. buymodafinilonline.reviews
ReplyDeleteA business plan is a written description of the future of your business and more importantly, how you are going to get there. It is a document that explains what you are going to do to make your company profitable and how you are going to achieve this. It defines both your business model and your strategies to make this business model work and more importantly profitable. rhinoceros 3d download full
ReplyDeletepregancy is quite critical and also requires more of your time so that you can monitor your health progress” putlockers
ReplyDelete