KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > avalon > excalibur > catalog > XMLCatalogReader


1 /*
2  * Copyright (C) The Apache Software Foundation. All rights reserved.
3  *
4  * This software is published under the terms of the Apache Software License
5  * version 1.1, a copy of which has been included with this distribution in
6  * the LICENSE.txt file.
7  */

8 package org.apache.avalon.excalibur.catalog;
9
10 import java.io.IOException JavaDoc;
11 import java.lang.Integer JavaDoc;
12 import java.net.MalformedURLException JavaDoc;
13 import java.net.URL JavaDoc;
14 import java.util.Enumeration JavaDoc;
15 import java.util.Vector JavaDoc;
16 import org.xml.sax.*;
17
18 /**
19  * <p>Parses XML Catalog files.</p>
20  *
21  * This class reads XML Catalog files, returning a stream of tokens. At present,
22  * it recognizes John Cowan's <a HREF="http://www.ccil.org/~cowan/XML/XCatalog.html">
23  * XML Catalogs</a> (formerly XCatalogs). In the future, additional XML Catalog
24  * formats may be supported.</p> <p>
25  *
26  * This code interrogates the following non-standard system properties:</p> <dl>
27  * <dt><b>xml.catalog.debug</b></dt> <dd><p>
28  *
29  * Sets the debug level. A value of 0 is assumed if the property is not set or
30  * is not a number.</p></dd></dl>
31  *
32  * @author Arbortext, Inc.
33  * @author <a HREF="mailto:nwalsh@arbortext.com">Norman Walsh</a>
34  * @version 1.0
35  * @see Catalog
36  */

37 public class XMLCatalogReader
38     implements DocumentHandler
39 {
40     /**
41      * Indicates that the catalog type is not XML
42      */

43     private final static int NOTXMLCATALOG = -1;
44
45     /**
46      * Indicates that the catalog type is unknown.
47      */

48     private final static int UNKNOWNCATALOG = 0;
49
50     /**
51      * Indicates that the catalog type is an XML Catalog (John Cowan's XCatalog)
52      */

53     private final static int XCATALOG = 1;
54
55     /**
56      * <p>
57      *
58      * The debug level</p> <p>
59      *
60      * In general, higher numbers produce more information:</p>
61      * <ul>
62      * <li> 0, no messages
63      * <li> 1, minimal messages (high-level status)
64      * <li> 2, detailed messages
65      * </ul>
66      *
67      */

68     public int debug = 0;
69
70     // These are class variables so that several methods can access them
71
/**
72      * The filename (URL) of the catalog being read
73      */

74     private String JavaDoc catfilename = null;
75
76     /**
77      * Indicates the catalog type.
78      */

79     private int catalogType = NOTXMLCATALOG;
80
81     /**
82      * <p>
83      *
84      * The list of entries scanned from the catalog.</p> <p>
85      *
86      * The SAX Parser is event-driven, but the Catalog class expects to iterate
87      * through the entries with <a HREF="#nextToken()">nextToken()</a> . So this
88      * class builds a vector of entries during the parse and returns them
89      * sequentially when <a HREF="#nextToken()">nextToken()</a> is called.</p>
90      *
91      * @see Catalog
92      */

93     private Vector JavaDoc catalogEntries = new Vector JavaDoc();
94
95     /**
96      * An enumerator for walking through the list of catalogEntries.
97      */

98     private Enumeration JavaDoc catalogEnum = null;
99
100     /**
101      * <p>
102      *
103      * The name of the parser class to load when parsing XML Catalogs.</p> <p>
104      *
105      * If a parser class is provided, subsequent attempts to parse Catalog files
106      * will begin by attemptiing an XML parse of the catalog file using a parser
107      * of this class. If the XML parse fails, the "default" text parse will be
108      * done instead.</p>
109      */

110     private String JavaDoc parserClass = null;
111
112     /**
113      * <p>
114      *
115      * Construct an XMLCatalogReader object.</p>
116      */

117     public XMLCatalogReader()
118     {
119         String JavaDoc property = System.getProperty( "xml.catalog.debug" );
120
121         if( property != null )
122         {
123             try
124             {
125                 debug = Integer.parseInt( property );
126             }
127             catch( NumberFormatException JavaDoc e )
128             {
129                 debug = 0;
130             }
131         }
132     }
133
134     /**
135      * <p>
136      *
137      * Attempt to parse an XML Catalog file.</p>
138      *
139      * @param fileUrl The URL or filename of the catalog file to process
140      * @throws SAXException Error parsing catalog file.
141      * @throws IOException Error reading catalog file.
142      * @throws NoXMLParserException No Parser class provided.
143      * @throws NotXMLCatalogException The Catalog appears not to be XML.
144      * @throws UnknownCatalogFormatException Unexpected XML catalog type.
145      * @throws ClassNotFoundException Parser class can't be found.
146      * @throws InstantiationException Parser class can't be instantiated.
147      * @throws IllegalAccessException Error instantiating parser class.
148      * @throws ClassCastException Parser class isn't a SAX Parser.
149      */

150     public void parseCatalog( String JavaDoc fileUrl )
151         throws SAXException, IOException JavaDoc,
152                NotXMLCatalogException, NoXMLParserException,
153                UnknownCatalogFormatException, ClassNotFoundException JavaDoc,
154                InstantiationException JavaDoc, IllegalAccessException JavaDoc,
155                ClassCastException JavaDoc
156     {
157         // Create an instance of the parser
158
if( parserClass == null )
159         {
160             throw new NoXMLParserException();
161         }
162
163         Parser parser = (Parser)Class.forName( parserClass ).newInstance();
164
165         catfilename = fileUrl;
166         parser.setDocumentHandler( this );
167         parser.parse( fileUrl );
168
169         if( catalogType == NOTXMLCATALOG )
170         {
171             // Why doesn't the attempt to parse this file throw a
172
// SAX Exception???
173
throw new NotXMLCatalogException();
174         }
175
176         if( catalogType == UNKNOWNCATALOG )
177         {
178             throw new UnknownCatalogFormatException();
179         }
180     }
181
182     /**
183      * <p>
184      *
185      * Get the next entry from the file</p>
186      *
187      * @return A CatalogEntry object for the next entry in the catalog
188      * @throws IOException Error reading catalog file
189      */

190     public CatalogEntry nextEntry()
191         throws IOException JavaDoc
192     {
193         if( catalogEnum == null )
194         {
195             catalogEnum = catalogEntries.elements();
196         }
197
198         if( catalogEnum.hasMoreElements() )
199         {
200             return (CatalogEntry)catalogEnum.nextElement();
201         }
202         else
203         {
204             return null;
205         }
206     }
207
208     /**
209      * <p>
210      *
211      * The SAX <code>startDocument</code> method. Does nothing.</p>
212      *
213      * @exception SAXException DOC: Insert Description of Exception
214      */

215     public void startDocument()
216         throws SAXException
217     {
218         return;
219     }
220
221     /**
222      * <p>
223      *
224      * The SAX <code>endDocument</code> method. Does nothing.</p>
225      *
226      * @exception SAXException DOC: Insert Description of Exception
227      */

228     public void endDocument()
229         throws SAXException
230     {
231         return;
232     }
233
234     /**
235      * <p>
236      *
237      * The SAX <code>startElement</code> method.</p> <p>
238      *
239      * This element attempts to identify the type of catalog by looking at the
240      * name of the first element encountered. If it recognizes the element, it
241      * sets the <code>catalogType</code> appropriately.</p> <p>
242      *
243      * After the catalog type has been identified, the appropriate entry parser
244      * is called for each subsequent element in the catalog.</p>
245      *
246      * @param name The name of the element.
247      * @param atts The list of attributes on the element.
248      * @exception SAXException DOC: Insert Description of Exception
249      */

250     public void startElement( String JavaDoc name, AttributeList atts )
251         throws SAXException
252     {
253
254         if( catalogType == UNKNOWNCATALOG || catalogType == NOTXMLCATALOG )
255         {
256             if( name.equals( "XMLCatalog" ) )
257             {
258                 catalogType = XCATALOG;
259                 return;
260             }
261         }
262
263         if( catalogType == XCATALOG )
264         {
265             xCatalogEntry( name, atts );
266         }
267     }
268
269     /**
270      * <p>
271      *
272      * The SAX <code>endElement</code> method. Does nothing.</p>
273      *
274      * @param name DOC: Insert Description of Parameter
275      * @exception SAXException DOC: Insert Description of Exception
276      */

277     public void endElement( String JavaDoc name )
278         throws SAXException
279     {
280         return;
281     }
282
283     /**
284      * <p>
285      *
286      * The SAX <code>characters</code> method. Does nothing.</p>
287      *
288      * @param ch DOC: Insert Description of Parameter
289      * @param start DOC: Insert Description of Parameter
290      * @param length DOC: Insert Description of Parameter
291      * @exception SAXException DOC: Insert Description of Exception
292      */

293     public void characters( char ch[], int start, int length )
294         throws SAXException
295     {
296         return;
297     }
298
299     /**
300      * <p>
301      *
302      * The SAX <code>ignorableWhitespace</code> method. Does nothing.</p>
303      *
304      * @param ch DOC: Insert Description of Parameter
305      * @param start DOC: Insert Description of Parameter
306      * @param length DOC: Insert Description of Parameter
307      * @exception SAXException DOC: Insert Description of Exception
308      */

309     public void ignorableWhitespace( char ch[], int start, int length )
310         throws SAXException
311     {
312         return;
313     }
314
315     /**
316      * <p>
317      *
318      * The SAX <code>processingInstruction</code> method. Does nothing.</p>
319      *
320      * @param target DOC: Insert Description of Parameter
321      * @param data DOC: Insert Description of Parameter
322      * @exception SAXException DOC: Insert Description of Exception
323      */

324     public void processingInstruction( String JavaDoc target, String JavaDoc data )
325         throws SAXException
326     {
327         return;
328     }
329
330     /**
331      * <p>
332      *
333      * Sets the parser class, enabling XML Catalog parsing.</p> <p>
334      *
335      * Sets the parser class that will be used for loading XML Catalogs. If this
336      * method is not called, all attempts to use the <code>XMLCatalogParser
337      * </code>will fail, throwing a <code>NoXMLParserException</code> .</p>
338      *
339      * @param parser The name of a class implementing the SAX Parser interface
340      * to be used for subsequent XML Catalog parsing.
341      * @see com.arbortext.catalog.NoXMLParserException
342      */

343     public void setParserClass( String JavaDoc parser )
344     {
345         parserClass = parser;
346     }
347
348     // ----------------------------------------------------------------------
349
// Implement the SAX DocumentHandler interface
350

351     /**
352      * <p>
353      *
354      * The SAX <code>setDocumentLocator</code> method. Does nothing.</p>
355      *
356      * @param locator The new DocumentLocator value
357      */

358     public void setDocumentLocator( Locator locator )
359     {
360         return;
361     }
362
363     // ----------------------------------------------------------------------
364

365     /*
366      * <p>Parse elements from John Cowan's XML Catalog doctype.</p>
367      *
368      * <p>Each recognized element is turned into an appropriate
369      * CatalogEntry and put onto the entries vector for later
370      * retrieval.</p>
371      *
372      * @param name The name of the element.
373      * @param atts The list of attributes on the element.
374      *
375      * @see CatalogEntry
376      */

377     private void xCatalogEntry( String JavaDoc name, AttributeList atts )
378     {
379         CatalogEntry ce = null;
380
381         try
382         {
383             if( name.equals( "Base" ) )
384             {
385                 ce = new CatalogEntry( CatalogEntry.BASE,
386                                        atts.getValue( "HRef" ) );
387                 debug( 3, "Base", atts.getValue( "HRef" ) );
388             }
389
390             if( name.equals( "Delegate" ) )
391             {
392                 ce = new CatalogEntry( CatalogEntry.DELEGATE,
393                                        CatalogReader.normalize( atts.getValue( "PublicId" ) ),
394                                        atts.getValue( "HRef" ) );
395                 debug( 3, "Delegate",
396                        CatalogReader.normalize( atts.getValue( "PublicId" ) ),
397                        atts.getValue( "HRef" ) );
398             }
399
400             if( name.equals( "Extend" ) )
401             {
402                 ce = new CatalogEntry( CatalogEntry.CATALOG,
403                                        atts.getValue( "HRef" ) );
404                 debug( 3, "Extend", atts.getValue( "HRef" ) );
405             }
406
407             if( name.equals( "Map" ) )
408             {
409                 ce = new CatalogEntry( CatalogEntry.PUBLIC,
410                                        CatalogReader.normalize( atts.getValue( "PublicId" ) ),
411                                        atts.getValue( "HRef" ) );
412                 debug( 3, "Map",
413                        CatalogReader.normalize( atts.getValue( "PublicId" ) ),
414                        atts.getValue( "HRef" ) );
415             }
416
417             if( name.equals( "Remap" ) )
418             {
419                 ce = new CatalogEntry( CatalogEntry.SYSTEM,
420                                        atts.getValue( "SystemId" ),
421                                        atts.getValue( "HRef" ) );
422                 debug( 3, "Remap",
423                        CatalogReader.normalize( atts.getValue( "SystemId" ) ),
424                        atts.getValue( "HRef" ) );
425             }
426
427             if( ce == null )
428             {
429                 // This is equivalent to an invalid catalog entry type
430
debug( 1, "Invalid catalog entry type", name );
431             }
432         }
433         catch( InvalidCatalogEntryTypeException icete )
434         {
435             debug( 1, "Invalid catalog entry type", name );
436         }
437         catch( InvalidCatalogEntryException icete )
438         {
439             debug( 1, "Invalid catalog entry", name );
440         }
441
442         if( ce != null )
443         {
444             catalogEntries.addElement( ce );
445         }
446     }
447
448     // -----------------------------------------------------------------
449

450     /**
451      * <p>
452      *
453      * Print debug message (if the debug level is high enough).</p>
454      *
455      * @param level The debug level of this message. This message will only be
456      * displayed if the current debug level is at least equal to this
457      * value.
458      * @param message The text of the message.
459      * @param token The catalog file token being processed.
460      */

461     private void debug( int level, String JavaDoc message, String JavaDoc token )
462     {
463         if( debug >= level )
464         {
465             System.out.println( message + ": " + token );
466         }
467     }
468
469     /**
470      * <p>
471      *
472      * Print debug message (if the debug level is high enough).</p>
473      *
474      * @param level The debug level of this message. This message will only be
475      * displayed if the current debug level is at least equal to this
476      * value.
477      * @param message The text of the message.
478      * @param token The catalog file token being processed.
479      * @param spec The argument to the token.
480      */

481     private void debug( int level, String JavaDoc message, String JavaDoc token, String JavaDoc spec )
482     {
483         if( debug >= level )
484         {
485             System.out.println( message + ": " + token + " " + spec );
486         }
487     }
488
489     /**
490      * <p>
491      *
492      * Print debug message (if the debug level is high enough).</p>
493      *
494      * @param level The debug level of this message. This message will only be
495      * displayed if the current debug level is at least equal to this
496      * value.
497      * @param message The text of the message.
498      * @param token The catalog file token being processed.
499      * @param spec1 The first argument to the token.
500      * @param spec2 The second argument to the token.
501      */

502     private void debug( int level, String JavaDoc message,
503                         String JavaDoc token, String JavaDoc spec1, String JavaDoc spec2 )
504     {
505         if( debug >= level )
506         {
507             System.out.println( message + ": " + token + " " + spec1 );
508             System.out.println( "\t" + spec2 );
509         }
510     }
511 }
512
Popular Tags