001package org.apache.commons.digester3.rss;
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 java.io.File;
021import java.io.IOException;
022import java.io.InputStream;
023
024import org.apache.commons.digester3.Digester;
025import org.apache.commons.logging.LogFactory;
026import org.xml.sax.InputSource;
027import org.xml.sax.SAXException;
028
029
030/**
031 * <p>Implementation of <strong>org.apache.commons.digester3.Digester</strong>
032 * designed to process input streams that conform to the <em>Rich Site
033 * Summary</em> DTD, version 0.91.  For more information about this format,
034 * see the <a href="http://my.netscape.com/publish/">My Netscape</a> site.</p>
035 *
036 * <p>The default implementation object returned by calling
037 * <code>parse()</code> (an instance of
038 * <code>org.apache.commons.digester3.rss.Channel</code>)
039 * knows how to render itself in XML format via the <code>render()</code>
040 * method.  See the test <code>main()</code> method below for an
041 * example of using these classes.</p>
042 */
043
044public class RSSDigester
045    extends Digester
046{
047
048    // ----------------------------------------------------------- Constructors
049
050    // ----------------------------------------------------- Instance Variables
051
052    /**
053     * Have we been configured yet?
054     */
055    protected boolean configured = false;
056
057    // ------------------------------------------------------------- Properties
058
059    /**
060     * The fully qualified class name of the <code>Channel</code>
061     * implementation class.
062     */
063    protected String channelClass = "org.apache.commons.digester3.rss.Channel";
064
065    public String getChannelClass()
066    {
067        return ( this.channelClass );
068    }
069
070    public void setChannelClass( String channelClass )
071    {
072        this.channelClass = channelClass;
073    }
074
075    /**
076     * The fully qualified class name of the <code>Image</code>
077     * implementation class.
078     */
079    protected String imageClass = "org.apache.commons.digester3.rss.Image";
080
081    public String getImageClass()
082    {
083        return ( this.imageClass );
084    }
085
086    public void setImageClass( String imageClass )
087    {
088        this.imageClass = imageClass;
089    }
090
091    /**
092     * The fully qualified class name of the <code>Item</code>
093     * implementation class.
094     */
095    protected String itemClass = "org.apache.commons.digester3.rss.Item";
096
097    public String getItemClass()
098    {
099        return ( this.itemClass );
100    }
101
102    public void setItemClass( String itemClass )
103    {
104        this.itemClass = itemClass;
105    }
106
107    /**
108     * The fully qualified class name of the <code>TextInput</code>
109     * implementation class.
110     */
111    protected String textInputClass = "org.apache.commons.digester3.rss.TextInput";
112
113    public String getTextInputClass()
114    {
115        return ( this.textInputClass );
116    }
117
118    public void setTextInputClass( String textInputClass )
119    {
120        this.textInputClass = textInputClass;
121    }
122
123    // --------------------------------------------------------- Public Methods
124
125    /**
126     * Parse the content of the specified file using this Digester.  Returns
127     * the root element from the object stack (which will be the Channel).
128     *
129     * @param file File containing the XML data to be parsed
130     *
131     * @exception IOException if an input/output error occurs
132     * @exception SAXException if a parsing exception occurs
133     */
134    @Override
135    public <T> T parse( File file )
136        throws IOException, SAXException
137    {
138        configure();
139        return ( super.<T>parse( file ) );
140    }
141
142    /**
143     * Parse the content of the specified input source using this Digester.
144     * Returns the root element from the object stack (which will be the
145     * Channel).
146     *
147     * @param input Input source containing the XML data to be parsed
148     *
149     * @exception IOException if an input/output error occurs
150     * @exception SAXException if a parsing exception occurs
151     */
152    @Override
153    public <T> T parse( InputSource input )
154        throws IOException, SAXException
155    {
156        configure();
157        return ( super.<T>parse( input ) );
158    }
159
160
161    /**
162     * Parse the content of the specified input stream using this Digester.
163     * Returns the root element from the object stack (which will be
164     * the Channel).
165     *
166     * @param input Input stream containing the XML data to be parsed
167     *
168     * @exception IOException if an input/output error occurs
169     * @exception SAXException if a parsing exception occurs
170     */
171    @Override
172    public <T> T parse( InputStream input )
173        throws IOException, SAXException
174    {
175        configure();
176        return ( super.<T>parse( input ) );
177    }
178
179    /**
180     * Parse the content of the specified URI using this Digester.
181     * Returns the root element from the object stack (which will be
182     * the Channel).
183     *
184     * @param uri URI containing the XML data to be parsed
185     *
186     * @exception IOException if an input/output error occurs
187     * @exception SAXException if a parsing exception occurs
188     */
189    @Override
190    public <T> T parse( String uri )
191        throws IOException, SAXException
192    {
193        configure();
194        return ( super.<T>parse( uri ) );
195    }
196
197    // -------------------------------------------------------- Package Methods
198
199    // ------------------------------------------------------ Protected Methods
200
201    /**
202     * Configure the parsing rules that will be used to process RSS input.
203     */
204    @Override
205    protected void configure()
206    {
207        if ( configured )
208        {
209            return;
210        }
211
212        // FIXME - validate the "version" attribute of the rss element?
213
214        // Add the rules for the Channel object
215        addObjectCreate( "rss/channel", channelClass );
216        addCallMethod( "rss/channel/copyright", "setCopyright", 0 );
217        addCallMethod( "rss/channel/description", "setDescription", 0 );
218        addCallMethod( "rss/channel/docs", "setDocs", 0 );
219        addCallMethod( "rss/channel/language", "setLanguage", 0 );
220        addCallMethod( "rss/channel/lastBuildDate", "setLastBuildDate", 0 );
221        addCallMethod( "rss/channel/link", "setLink", 0 );
222        addCallMethod( "rss/channel/managingEditor", "setManagingEditor", 0 );
223        addCallMethod( "rss/channel/pubDate", "setPubDate", 0 );
224        addCallMethod( "rss/channel/rating", "setRating", 0 );
225        addCallMethod( "rss/channel/skipDays/day", "addSkipDay", 0 );
226        addCallMethod( "rss/channel/skipHours/hour", "addSkipHour", 0 );
227        addCallMethod( "rss/channel/title", "setTitle", 0 );
228        addCallMethod( "rss/channel/webMaster", "setWebMaster", 0 );
229
230        // Add the rules for the Image object
231        addObjectCreate( "rss/channel/image", imageClass );
232        addSetNext( "rss/channel/image", "setImage", "org.apache.commons.digester3.rss.Image" );
233        addCallMethod( "rss/channel/image/description", "setDescription", 0 );
234        addCallMethod( "rss/channel/image/height", "setHeight", 0, new Class[] { Integer.TYPE } );
235        addCallMethod( "rss/channel/image/link", "setLink", 0 );
236        addCallMethod( "rss/channel/image/title", "setTitle", 0 );
237        addCallMethod( "rss/channel/image/url", "setURL", 0 );
238        addCallMethod( "rss/channel/image/width", "setWidth", 0, new Class[] { Integer.TYPE } );
239
240        // Add the rules for the Item object
241        addObjectCreate( "rss/channel/item", itemClass );
242        addSetNext( "rss/channel/item", "addItem", "org.apache.commons.digester3.rss.Item" );
243        addCallMethod( "rss/channel/item/description", "setDescription", 0 );
244        addCallMethod( "rss/channel/item/link", "setLink", 0 );
245        addCallMethod( "rss/channel/item/title", "setTitle", 0 );
246
247        // Add the rules for the TextInput object
248        addObjectCreate( "rss/channel/textinput", textInputClass );
249        addSetNext( "rss/channel/textinput", "setTextInput", "org.apache.commons.digester3.rss.TextInput" );
250        addCallMethod( "rss/channel/textinput/description", "setDescription", 0 );
251        addCallMethod( "rss/channel/textinput/link", "setLink", 0 );
252        addCallMethod( "rss/channel/textinput/name", "setName", 0 );
253        addCallMethod( "rss/channel/textinput/title", "setTitle", 0 );
254
255        // Mark this digester as having been configured
256        configured = true;
257    }
258
259    // ------------------------------------------------------ Test Main Program
260
261    /**
262     * Test main program that parses the channel description included in this
263     * package as a static resource.
264     *
265     * @param args The command line arguments (ignored)
266     */
267    public static void main( String args[] )
268    {
269        try
270        {
271            System.out.println( "RSSDigester Test Program" );
272            System.out.println( "Opening input stream ..." );
273            InputStream is =
274                RSSDigester.class.getResourceAsStream( "/org/apache/commons/digester3/rss/rss-example.xml" );
275            System.out.println( "Creating new digester ..." );
276            RSSDigester digester = new RSSDigester();
277            if ( ( args.length > 0 ) && ( args[0].equals( "-debug" ) ) )
278            {
279                digester.setLogger( LogFactory.getLog( "RSSDigester" ) );
280            }
281            System.out.println( "Parsing input stream ..." );
282            Channel channel = (Channel) digester.parse( is );
283            System.out.println( "Closing input stream ..." );
284            is.close();
285            System.out.println( "Dumping channel info ..." );
286            channel.render( System.out );
287        }
288        catch ( Exception e )
289        {
290            System.out.println( "-->Exception" );
291            e.printStackTrace( System.out );
292        }
293    }
294
295}