1   /*
2    * Copyright 2001-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */ 
16  
17  
18  package org.apache.commons.digester.rss;
19  
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.net.URL;
25  
26  import org.apache.commons.digester.Digester;
27  import org.apache.commons.logging.LogFactory;
28  import org.xml.sax.InputSource;
29  import org.xml.sax.SAXException;
30  
31  
32  /***
33   * <p>Implementation of <strong>org.apache.commons.digester.Digester</strong>
34   * designed to process input streams that conform to the <em>Rich Site
35   * Summary</em> DTD, version 0.91.  For more information about this format,
36   * see the <a href="http://my.netscape.com/publish/">My Netscape</a> site.</p>
37   *
38   * <p>The default implementation object returned by calling
39   * <code>parse()</code> (an instance of
40   * <code>org.apache.commons.digester.rss.Channel</code>)
41   * knows how to render itself in XML format via the <code>render()</code>
42   * method.  See the test <code>main()</code> method below for an
43   * example of using these classes.</p>
44   */
45  
46  public class RSSDigester extends Digester {
47  
48  
49      // ----------------------------------------------------------- Constructors
50  
51  
52  
53      // ----------------------------------------------------- Instance Variables
54  
55  
56      /***
57       * Have we been configured yet?
58       */
59      protected boolean configured = false;
60  
61  
62      /***
63       * The set of public identifiers, and corresponding resource names,
64       * for the versions of the DTDs that we know about.
65       */
66      protected static final String registrations[] = {
67          "-//Netscape Communications//DTD RSS 0.9//EN",
68          "/org/apache/commons/digester/rss/rss-0.9.dtd",
69          "-//Netscape Communications//DTD RSS 0.91//EN",
70          "/org/apache/commons/digester/rss/rss-0.91.dtd",
71      };
72  
73  
74      // ------------------------------------------------------------- Properties
75  
76  
77      /***
78       * The fully qualified class name of the <code>Channel</code>
79       * implementation class.
80       */
81      protected String channelClass = "org.apache.commons.digester.rss.Channel";
82  
83      public String getChannelClass() {
84          return (this.channelClass);
85      }
86  
87      public void setChannelClass(String channelClass) {
88          this.channelClass = channelClass;
89      }
90  
91  
92      /***
93       * The fully qualified class name of the <code>Image</code>
94       * implementation class.
95       */
96      protected String imageClass = "org.apache.commons.digester.rss.Image";
97  
98      public String getImageClass() {
99          return (this.imageClass);
100     }
101 
102     public void setImageClass(String imageClass) {
103         this.imageClass = imageClass;
104     }
105 
106 
107     /***
108      * The fully qualified class name of the <code>Item</code>
109      * implementation class.
110      */
111     protected String itemClass = "org.apache.commons.digester.rss.Item";
112 
113     public String getItemClass() {
114         return (this.itemClass);
115     }
116 
117     public void setItemClass(String itemClass) {
118         this.itemClass = itemClass;
119     }
120 
121 
122     /***
123      * The fully qualified class name of the <code>TextInput</code>
124      * implementation class.
125      */
126     protected String textInputClass =
127             "org.apache.commons.digester.rss.TextInput";
128 
129     public String getTextInputClass() {
130         return (this.textInputClass);
131     }
132 
133     public void setTextInputClass(String textInputClass) {
134         this.textInputClass = textInputClass;
135     }
136 
137 
138     // --------------------------------------------------------- Public Methods
139 
140 
141     /***
142      * Parse the content of the specified file using this Digester.  Returns
143      * the root element from the object stack (which will be the Channel).
144      *
145      * @param file File containing the XML data to be parsed
146      *
147      * @exception IOException if an input/output error occurs
148      * @exception SAXException if a parsing exception occurs
149      */
150     public Object parse(File file) throws IOException, SAXException {
151 
152         configure();
153         return (super.parse(file));
154 
155     }
156 
157 
158     /***
159      * Parse the content of the specified input source using this Digester.
160      * Returns the root element from the object stack (which will be the
161      * Channel).
162      *
163      * @param input Input source containing the XML data to be parsed
164      *
165      * @exception IOException if an input/output error occurs
166      * @exception SAXException if a parsing exception occurs
167      */
168     public Object parse(InputSource input) throws IOException, SAXException {
169 
170         configure();
171         return (super.parse(input));
172 
173     }
174 
175 
176     /***
177      * Parse the content of the specified input stream using this Digester.
178      * Returns the root element from the object stack (which will be
179      * the Channel).
180      *
181      * @param input Input stream containing the XML data to be parsed
182      *
183      * @exception IOException if an input/output error occurs
184      * @exception SAXException if a parsing exception occurs
185      */
186     public Object parse(InputStream input) throws IOException, SAXException {
187 
188         configure();
189         return (super.parse(input));
190 
191     }
192 
193 
194     /***
195      * Parse the content of the specified URI using this Digester.
196      * Returns the root element from the object stack (which will be
197      * the Channel).
198      *
199      * @param uri URI containing the XML data to be parsed
200      *
201      * @exception IOException if an input/output error occurs
202      * @exception SAXException if a parsing exception occurs
203      */
204     public Object parse(String uri) throws IOException, SAXException {
205 
206         configure();
207         return (super.parse(uri));
208 
209     }
210 
211 
212     // -------------------------------------------------------- Package Methods
213 
214 
215 
216     // ------------------------------------------------------ Protected Methods
217 
218 
219     /***
220      * Configure the parsing rules that will be used to process RSS input.
221      */
222     protected void configure() {
223 
224         if (configured) {
225             return;
226         }
227 
228         // Register local copies of the DTDs we understand
229         for (int i = 0; i < registrations.length; i += 2) {
230             URL url = this.getClass().getResource(registrations[i + 1]);
231             if (url != null) {
232                 register(registrations[i], url.toString());
233             }
234         }
235 
236         // FIXME - validate the "version" attribute of the rss element?
237 
238         // Add the rules for the Channel object
239         addObjectCreate("rss/channel", channelClass);
240         addCallMethod("rss/channel/copyright", "setCopyright", 0);
241         addCallMethod("rss/channel/description", "setDescription", 0);
242         addCallMethod("rss/channel/docs", "setDocs", 0);
243         addCallMethod("rss/channel/language", "setLanguage", 0);
244         addCallMethod("rss/channel/lastBuildDate", "setLastBuildDate", 0);
245         addCallMethod("rss/channel/link", "setLink", 0);
246         addCallMethod("rss/channel/managingEditor", "setManagingEditor", 0);
247         addCallMethod("rss/channel/pubDate", "setPubDate", 0);
248         addCallMethod("rss/channel/rating", "setRating", 0);
249         addCallMethod("rss/channel/skipDays/day", "addSkipDay", 0);
250         addCallMethod("rss/channel/skipHours/hour", "addSkipHour", 0);
251         addCallMethod("rss/channel/title", "setTitle", 0);
252         addCallMethod("rss/channel/webMaster", "setWebMaster", 0);
253 
254         // Add the rules for the Image object
255         addObjectCreate("rss/channel/image", imageClass);
256         addSetNext("rss/channel/image", "setImage",
257                 "org.apache.commons.digester.rss.Image");
258         addCallMethod("rss/channel/image/description", "setDescription", 0);
259         addCallMethod("rss/channel/image/height", "setHeight", 0,
260                 new Class[]{ Integer.TYPE });
261         addCallMethod("rss/channel/image/link", "setLink", 0);
262         addCallMethod("rss/channel/image/title", "setTitle", 0);
263         addCallMethod("rss/channel/image/url", "setURL", 0);
264         addCallMethod("rss/channel/image/width", "setWidth", 0,
265                 new Class[]{ Integer.TYPE });
266 
267         // Add the rules for the Item object
268         addObjectCreate("rss/channel/item", itemClass);
269         addSetNext("rss/channel/item", "addItem",
270                 "org.apache.commons.digester.rss.Item");
271         addCallMethod("rss/channel/item/description", "setDescription", 0);
272         addCallMethod("rss/channel/item/link", "setLink", 0);
273         addCallMethod("rss/channel/item/title", "setTitle", 0);
274 
275         // Add the rules for the TextInput object
276         addObjectCreate("rss/channel/textinput", textInputClass);
277         addSetNext("rss/channel/textinput", "setTextInput",
278                 "org.apache.commons.digester.rss.TextInput");
279         addCallMethod("rss/channel/textinput/description",
280                 "setDescription", 0);
281         addCallMethod("rss/channel/textinput/link", "setLink", 0);
282         addCallMethod("rss/channel/textinput/name", "setName", 0);
283         addCallMethod("rss/channel/textinput/title", "setTitle", 0);
284 
285         // Mark this digester as having been configured
286         configured = true;
287 
288     }
289 
290 
291     // ------------------------------------------------------ Test Main Program
292 
293 
294     /***
295      * Test main program that parses the channel description included in this
296      * package as a static resource.
297      *
298      * @param args The command line arguments (ignored)
299      */
300     public static void main(String args[]) {
301 
302         try {
303             System.out.println("RSSDigester Test Program");
304             System.out.println("Opening input stream ...");
305             InputStream is = RSSDigester.class.getResourceAsStream
306                     ("/org/apache/commons/digester/rss/rss-example.xml");
307             System.out.println("Creating new digester ...");
308             RSSDigester digester = new RSSDigester();
309             if ((args.length > 0) && (args[0].equals("-debug"))) {
310                 digester.setLogger(LogFactory.getLog("RSSDigester"));
311             }
312             System.out.println("Parsing input stream ...");
313             Channel channel = (Channel) digester.parse(is);
314             System.out.println("Closing input stream ...");
315             is.close();
316             System.out.println("Dumping channel info ...");
317             channel.render(System.out);
318         } catch (Exception e) {
319             System.out.println("-->Exception");
320             e.printStackTrace(System.out);
321         }
322 
323     }
324 
325 
326 }