001package org.apache.commons.digester3.examples.api.addressbook;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one or more
005 * contributor license agreements.  See the NOTICE file distributed with
006 * this work for additional information regarding copyright ownership.
007 * The ASF licenses this file to You under the Apache License, Version 2.0
008 * (the "License"); you may not use this file except in compliance with
009 * the License.  You may obtain a copy of the License at
010 * 
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 * 
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */ 
019
020import org.apache.commons.digester3.Digester;
021
022/**
023 * A simple program to demonstrate the basic functionality of the
024 * Commons Digester module.
025 * <p>
026 * This code will parse the provided "example.xml" file to build a tree
027 * of java objects, then cause those objects to print out their values
028 * to demonstrate that the input file has been processed correctly.
029 * <p>
030 * As with all code, there are many ways of achieving the same goal;
031 * the solution here is only one possible solution to the problem.
032* <p> 
033 * Very verbose comments are included here, as this class is intended
034 * as a tutorial; if you look closely at method "addRules", you will
035 * see that the amount of code required to use the Digester is actually
036 * quite low.
037 * <p>
038 * Usage: java Main example.xml
039 */
040public class Main
041{
042
043    /**
044     * Main method : entry point for running this example program.
045     * <p>
046     * Usage: java Example example.xml
047     */
048    public static void main( String[] args )
049    {
050        if ( args.length != 1 )
051        {
052            usage();
053            System.exit( -1 );
054        }
055
056        String filename = args[0];
057
058        // Create a Digester instance
059        Digester d = new Digester();
060
061        // Prime the digester stack with an object for rules to
062        // operate on. Note that it is quite common for "this"
063        // to be the object pushed.
064        AddressBook book = new AddressBook();
065        d.push( book );
066
067        // Add rules to the digester that will be triggered while
068        // parsing occurs.
069        addRules( d );
070
071        // Process the input file.
072        try
073        {
074            java.io.File srcfile = new java.io.File( filename );
075            d.parse( srcfile );
076        }
077        catch ( java.io.IOException ioe )
078        {
079            System.out.println( "Error reading input file:" + ioe.getMessage() );
080            System.exit( -1 );
081        }
082        catch ( org.xml.sax.SAXException se )
083        {
084            System.out.println( "Error parsing input file:" + se.getMessage() );
085            System.exit( -1 );
086        }
087
088        // Print out all the contents of the address book, as loaded from
089        // the input file.
090        book.print();
091    }
092
093    private static void addRules( Digester d )
094    {
095
096        // --------------------------------------------------
097        // when we encounter a "person" tag, do the following:
098
099        // create a new instance of class Person, and push that
100        // object onto the digester stack of objects
101        d.addObjectCreate( "address-book/person", Person.class );
102
103        // map *any* attributes on the tag to appropriate
104        // setter-methods on the top object on the stack (the Person
105        // instance created by the preceeding rule).
106        //
107        // For example:
108        // if attribute "id" exists on the xml tag, and method setId
109        // with one parameter exists on the object that is on top of
110        // the digester object stack, then a call will be made to that
111        // method. The value will be type-converted from string to
112        // whatever type the target method declares (where possible),
113        // using the commons ConvertUtils functionality.
114        //
115        // Attributes on the xml tag for which no setter methods exist
116        // on the top object on the stack are just ignored.
117        d.addSetProperties( "address-book/person" );
118
119        // call the addPerson method on the second-to-top object on
120        // the stack (the AddressBook object), passing the top object
121        // on the stack (the recently created Person object).
122        d.addSetNext( "address-book/person", "addPerson" );
123
124        // --------------------------------------------------
125        // when we encounter a "name" tag, call setName on the top
126        // object on the stack, passing the text contained within the
127        // body of that name element [specifying a zero parameter count
128        // implies one actual parameter, being the body text].
129        // The top object on the stack will be a person object, because
130        // the pattern address-book/person always triggers the
131        // ObjectCreateRule we added previously.
132        d.addCallMethod( "address-book/person/name", "setName", 0 );
133
134        // --------------------------------------------------
135        // when we encounter an "email" tag, call addEmail on the top
136        // object on the stack, passing two parameters: the "type"
137        // attribute, and the text within the tag body.
138        d.addCallMethod( "address-book/person/email", "addEmail", 2 );
139        d.addCallParam( "address-book/person/email", 0, "type" );
140        d.addCallParam( "address-book/person/email", 1 );
141
142        // --------------------------------------------------
143        // When we encounter an "address" tag, create an instance of class
144        // Address and push it on the digester stack of objects. After
145        // doing that, call addAddress on the second-to-top object on the
146        // digester stack (a "Person" object), passing the top object on
147        // the digester stack (the "Address" object). And also set things
148        // up so that for each child xml element encountered between the start
149        // of the address tag and the end of the address tag, the text
150        // contained in that element is passed to a setXXX method on the
151        // Address object where XXX is the name of the xml element found.
152        d.addObjectCreate( "address-book/person/address", Address.class );
153        d.addSetNext( "address-book/person/address", "addAddress" );
154        d.addSetNestedProperties( "address-book/person/address" );
155    }
156
157    private static void usage()
158    {
159        System.out.println( "Usage: java Main example.xml" );
160    }
161
162}