You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by rd...@apache.org on 2003/09/25 22:05:47 UTC
cvs commit: jakarta-commons/digester/src/examples/api/catalog CatalogDigester.java
rdonkin 2003/09/25 13:05:47
Added: digester/src/examples/api/catalog CatalogDigester.java
Log:
Example of a catalog. Submitted by Simon Kitching.
Revision Changes Path
1.1 jakarta-commons/digester/src/examples/api/catalog/CatalogDigester.java
Index: CatalogDigester.java
===================================================================
/*
* $Header: /home/cvs/jakarta-commons/digester/src/examples/api/catalog/CatalogDigester.java,v 1.1 2003/09/25 20:05:47 rdonkin Exp $
* $Revision: 1.1 $
* $Date: 2003/09/25 20:05:47 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.AbstractObjectCreationFactory;
import org.apache.commons.digester.ExtendedBaseRules;
/**
* A simple program to demonstrate some of the functionality of the
* Commons Digester module.
* <p>
* This code will parse the provided "example.xml" file to build a tree
* of java objects, then cause those objects to print out their values
* to demonstrate that the input file has been processed correctly. The
* input file represents a catalog of items in a library.
* <p>
* As with all code, there are many ways of achieving the same goal;
* the solution here is only one possible implementation.
* <p>
* Very verbose comments are included here, as this class is intended
* as a tutorial; if you look closely at method "addRules", you will
* see that the amount of code required to use the Digester is actually
* quite low.
* <p>
* Usage: java CatalogDigester example.xml
*
* @author Simon Kitching
*/
public class CatalogDigester {
/**
* Main method : entry point for running this example program.
* <p>
* Usage: java CatalogDigester example.xml
*/
public static void main(String[] args) {
if (args.length != 1) {
usage();
System.exit(-1);
}
String filename = args[0];
// Create a Digester instance
Digester d = new Digester();
// some of the rules use "extended pattern matching", so we
// need to configure the digester with the corresponding
// pattern-matching implementation.
d.setRules( new ExtendedBaseRules() );
// Add rules to the digester that will be triggered while
// parsing occurs.
addRules(d);
// Process the input file.
try {
java.io.Reader reader = getInputData(filename);
d.parse(reader);
}
catch(java.io.IOException ioe) {
System.out.println("Error reading input file:" + ioe.getMessage());
System.exit(-1);
}
catch(org.xml.sax.SAXException se) {
System.out.println("Error parsing input file:" + se.getMessage());
System.exit(-1);
}
// get the first object created by the digester's rules
// (the "root" object).
Catalog catalog = (Catalog) d.getRoot();
// Print out all the contents of the catalog, as loaded from
// the input file.
catalog.print();
}
private static void addRules(Digester d) {
//--------------------------------------------------
// when we encounter the root "catalog" tag, create an
// instance of the Catalog class.
//
// Note that this approach is different from the approach taken in
// the AddressBook example, where an initial "root" object was
// explicitly created and pushed onto the digester stack before
// parsing started instead
//
// Either approach is fine.
d.addObjectCreate("catalog", Catalog.class);
//--------------------------------------------------
// when we encounter a book tag, we want to create a Book
// instance. However the Book class doesn't have a default
// constructor (one with no arguments), so we can't use
// the ObjectCreateRule. Instead, we use the FactoryCreateRule.
BookFactory factory = new BookFactory();
d.addFactoryCreate("catalog/book", factory);
// and add the book to the parent catalog object (which is
// the next-to-top object on the digester object stack).
d.addSetNext("catalog/book", "addItem");
// we want each subtag of book to map the text contents of
// the tag into a bean property with the same name as the tag.
// eg <title>foo</title> --> setTitle("foo")
//
// In order to use the wildcard "?" match, an ExtendedBaseRules
// instance must be set as the digester's rule matcher.
d.addBeanPropertySetter("catalog/book/?");
//-----------------------------------------------
// We are using the "AudioVisual" class to represent both
// dvds and videos, so when the "dvd" tag is encountered,
// create an AudioVisual object.
d.addObjectCreate("catalog/dvd", AudioVisual.class);
// add this dvd to the parent catalog object
d.addSetNext("catalog/dvd", "addItem");
// We want to map every xml attribute onto a corresponding
// property-setter method on the Dvd class instance. However
// this doesn't work with the xml attribute "year-made", because
// of the internal hyphen. We could use explicit CallMethodRule
// rules instead, or use a version of the SetPropertiesRule that
// allows us to override any troublesome mappings...
//
// If there was more than one troublesome mapping, we could
// use the method variant that takes arrays of xml-attribute-names
// and bean-property-names to override multiple mappings.
//
// For any attributes not explicitly mapped here, the default
// processing is applied, so xml attribute "category" --> setCategory.
d.addSetProperties("catalog/dvd", "year-made", "yearMade");
// We also need to tell this AudioVisual object that it is actually
// a dvd; we can use the ObjectParamRule to pass a string to any
// method. This usage is a little artificial - normally in this
// situation there would be separate Dvd and Video classes.
// Note also that equivalent behaviour could be implemented by
// using factory objects to create & initialise the AudioVisual
// objects with their type rather than using ObjectCreateRule.
d.addCallMethod("catalog/dvd", "setType", 1);
d.addObjectParam("catalog/dvd", 0, "dvd"); // pass literal "dvd" string
// Each tag of form "<attr id="foo" value="bar"/> needs to map
// to a call to setFoo("bar").
//
// This is an alternative to the BeanPropertySetter syntax of
// having the tag name indicate the attribute to set. It has
// advantages (like not requiring ExtendedBaseRules support),
// and disadvantages. It is commonly used with the FactoryCreateRule
// variant which allows the target class to be created to be
// specified in an xml attribute; this feature of FactoryCreateRule
// is not demonstrated in this example, but see the Apache Tomcat
// configuration files for an example of this usage.
//
// Note that despite the name similarity, there is no link
// between SetPropertyRule and SetPropertiesRule.
d.addSetProperty("catalog/dvd/attr", "id", "value");
//-----------------------------------------------
// and here we repeat the dvd rules, but for the video tag.
d.addObjectCreate("catalog/video", AudioVisual.class);
d.addSetNext("catalog/video", "addItem");
d.addSetProperties("catalog/video", "year-made", "yearMade");
d.addCallMethod("catalog/video", "setType", 1);
d.addObjectParam("catalog/video", 0, "video");
d.addSetProperty("catalog/video/attr", "id", "value");
}
/*
* Reads the specified file into memory, and returns a StringReader
* object which reads from that in-memory buffer.
* <p>
* This method exists just to demonstrate that the input to the
* digester doesn't need to be from a file; for example, xml could
* be read from a database or generated dynamically; any old buffer
* in memory can be processed by the digester.
* <p>
* Clearly, if the data is always coming from a file, then calling
* the Digester.parse method that takes a File object would be
* more sensible (see AddressBook example).
*/
private static java.io.Reader getInputData(String filename)
throws java.io.IOException {
java.io.File srcfile = new java.io.File(filename);
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(1000);
byte[] buf = new byte[100];
java.io.FileInputStream fis = new java.io.FileInputStream(srcfile);
for(;;) {
int nread = fis.read(buf);
if (nread == -1) {
break;
}
baos.write(buf, 0, nread);
}
fis.close();
return new java.io.StringReader( baos.toString() );
}
private static void usage() {
System.out.println("Usage: java CatalogDigester example.xml");
}
}