1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 // DOMCatalogReader.java - Read XML Catalog files
   6 
   7 /*
   8  * Copyright 2001-2004 The Apache Software Foundation or its licensors,
   9  * as applicable.
  10  *
  11  * Licensed under the Apache License, Version 2.0 (the "License");
  12  * you may not use this file except in compliance with the License.
  13  * You may obtain a copy of the License at
  14  *
  15  *      http://www.apache.org/licenses/LICENSE-2.0
  16  *
  17  * Unless required by applicable law or agreed to in writing, software
  18  * distributed under the License is distributed on an "AS IS" BASIS,
  19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  20  * See the License for the specific language governing permissions and
  21  * limitations under the License.
  22  */
  23 
  24 package com.sun.org.apache.xml.internal.resolver.readers;
  25 
  26 import com.sun.org.apache.xml.internal.resolver.Catalog;
  27 import com.sun.org.apache.xml.internal.resolver.CatalogException;
  28 import com.sun.org.apache.xml.internal.resolver.helpers.Namespaces;
  29 import java.io.IOException;
  30 import java.io.InputStream;
  31 import java.net.MalformedURLException;
  32 import java.net.URL;
  33 import java.net.URLConnection;
  34 import java.util.Hashtable;
  35 import javax.xml.parsers.DocumentBuilder;
  36 import javax.xml.parsers.DocumentBuilderFactory;
  37 import javax.xml.parsers.ParserConfigurationException;
  38 import org.w3c.dom.*;
  39 import org.xml.sax.SAXException;
  40 import sun.reflect.misc.ReflectUtil;
  41 
  42 /**
  43  * A DOM-based CatalogReader.
  44  *
  45  * <p>This class is used to read XML Catalogs using the DOM. This reader
  46  * has an advantage over the SAX-based reader that it can analyze the
  47  * DOM tree rather than simply a series of SAX events. It has the disadvantage
  48  * that it requires all of the code necessary to build and walk a DOM
  49  * tree.</p>
  50  *
  51  * <p>Since the choice of CatalogReaders (in the InputStream case) can only
  52  * be made on the basis of MIME type, the following problem occurs: only
  53  * one CatalogReader can exist for all XML mime types. In order to get
  54  * around this problem, the DOMCatalogReader relies on a set of external
  55  * CatalogParsers to actually build the catalog.</p>
  56  *
  57  * <p>The selection of CatalogParsers is made on the basis of the QName
  58  * of the root element of the document.</p>
  59  *

  60  *
  61  * @see Catalog
  62  * @see CatalogReader
  63  * @see SAXCatalogReader
  64  * @see TextCatalogReader
  65  * @see DOMCatalogParser
  66  *
  67  * @author Norman Walsh
  68  * <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
  69  *
  70  */
  71 public class DOMCatalogReader implements CatalogReader {
  72   /**
  73    * Mapping table from QNames to CatalogParser classes.
  74    *
  75    * <p>Each key in this hash table has the form "elementname"
  76    * or "{namespaceuri}elementname". The former is used if the
  77    * namespace URI is null.</p>
  78    */
  79   protected Hashtable namespaceMap = new Hashtable();
  80 
  81   /**
  82    * Add a new parser to the reader.
  83    *
  84    * <p>This method associates the specified parserClass with the
  85    * namespaceURI/rootElement names specified.</p>
  86    *
  87    * @param namespaceURI The namespace URI. <em>Not</em> the prefix.
  88    * @param rootElement The name of the root element.
  89    * @param parserClass The name of the parserClass to instantiate
  90    * for this kind of catalog.
  91    */
  92   public void setCatalogParser(String namespaceURI,
  93                                String rootElement,
  94                                String parserClass) {
  95     if (namespaceURI == null) {
  96       namespaceMap.put(rootElement, parserClass);
  97     } else {
  98       namespaceMap.put("{"+namespaceURI+"}"+rootElement, parserClass);
  99     }
 100   }
 101 
 102   /**
 103    * Get the name of the parser class for a given catalog type.
 104    *
 105    * <p>This method returns the parserClass associated with the
 106    * namespaceURI/rootElement names specified.</p>
 107    *
 108    * @param namespaceURI The namespace URI. <em>Not</em> the prefix.
 109    * @param rootElement The name of the root element.
 110    * @return The parser class.
 111    */
 112   public String getCatalogParser(String namespaceURI,
 113                                  String rootElement) {
 114     if (namespaceURI == null) {
 115       return (String) namespaceMap.get(rootElement);
 116     } else {
 117       return (String) namespaceMap.get("{"+namespaceURI+"}"+rootElement);
 118     }
 119   }
 120 
 121   /**
 122    * Null constructor; something for subclasses to call.
 123    */
 124   public DOMCatalogReader() { }
 125 
 126   /**
 127    * Read a catalog from an input stream.
 128    *
 129    * <p>This class reads a catalog from an input stream:</p>
 130    *
 131    * <ul>
 132    * <li>Based on the QName of the root element, it determines which
 133    * parser to instantiate for this catalog.</li>
 134    * <li>It constructs a DOM Document from the catalog and</li>
 135    * <li>For each child of the root node, it calls the parser's
 136    * parseCatalogEntry method. This method is expected to make
 137    * appropriate calls back into the catalog to add entries for the
 138    * entries in the catalog. It is free to do this in whatever manner
 139    * is appropriate (perhaps using just the node passed in, perhaps
 140    * wandering arbitrarily throughout the tree).</li>
 141    * </ul>
 142    *
 143    * @param catalog The catalog for which this reader is called.
 144    * @param is The input stream that is to be read.
 145    * @throws IOException if the URL cannot be read.
 146    * @throws UnknownCatalogFormatException if the catalog format is
 147    * not recognized.
 148    * @throws UnparseableCatalogException if the catalog cannot be parsed.
 149    * (For example, if it is supposed to be XML and isn't well-formed or
 150    * if the parser class cannot be instantiated.)
 151    */
 152   public void readCatalog(Catalog catalog, InputStream is)
 153     throws IOException, CatalogException {
 154 
 155     DocumentBuilderFactory factory = null;
 156     DocumentBuilder builder = null;
 157 
 158     factory = DocumentBuilderFactory.newInstance();
 159     factory.setNamespaceAware(false);
 160     factory.setValidating(false);
 161     try {
 162       builder = factory.newDocumentBuilder();
 163     } catch (ParserConfigurationException pce) {
 164       throw new CatalogException(CatalogException.UNPARSEABLE);
 165     }
 166 
 167     Document doc = null;
 168 
 169     try {
 170       doc = builder.parse(is);
 171     } catch (SAXException se) {
 172       throw new CatalogException(CatalogException.UNKNOWN_FORMAT);
 173     }
 174 
 175     Element root = doc.getDocumentElement();
 176 
 177     String namespaceURI = Namespaces.getNamespaceURI(root);
 178     String localName    = Namespaces.getLocalName(root);
 179 
 180     String domParserClass = getCatalogParser(namespaceURI,
 181                                              localName);
 182 
 183     if (domParserClass == null) {
 184       if (namespaceURI == null) {
 185         catalog.getCatalogManager().debug.message(1, "No Catalog parser for "
 186                                                   + localName);
 187       } else {
 188         catalog.getCatalogManager().debug.message(1, "No Catalog parser for "
 189                                                   + "{" + namespaceURI + "}"
 190                                                   + localName);
 191       }
 192       return;
 193     }
 194 
 195     DOMCatalogParser domParser = null;
 196 
 197     try {
 198       domParser = (DOMCatalogParser) ReflectUtil.forName(domParserClass).newInstance();
 199     } catch (ClassNotFoundException cnfe) {
 200       catalog.getCatalogManager().debug.message(1, "Cannot load XML Catalog Parser class", domParserClass);
 201       throw new CatalogException(CatalogException.UNPARSEABLE);
 202     } catch (InstantiationException ie) {
 203       catalog.getCatalogManager().debug.message(1, "Cannot instantiate XML Catalog Parser class", domParserClass);
 204       throw new CatalogException(CatalogException.UNPARSEABLE);
 205     } catch (IllegalAccessException iae) {
 206       catalog.getCatalogManager().debug.message(1, "Cannot access XML Catalog Parser class", domParserClass);
 207       throw new CatalogException(CatalogException.UNPARSEABLE);
 208     } catch (ClassCastException cce ) {
 209       catalog.getCatalogManager().debug.message(1, "Cannot cast XML Catalog Parser class", domParserClass);
 210       throw new CatalogException(CatalogException.UNPARSEABLE);
 211     }
 212 
 213     Node node = root.getFirstChild();
 214     while (node != null) {
 215       domParser.parseCatalogEntry(catalog, node);
 216       node = node.getNextSibling();
 217     }
 218   }
 219 
 220   /**
 221    * Read the catalog behind the specified URL.
 222    *
 223    * @see #readCatalog(Catalog, InputStream)
 224    *
 225    * @param catalog The catalog for which we are reading.
 226    * @param fileUrl The URL of the document that should be read.
 227    *
 228    * @throws MalformedURLException if the specified URL cannot be
 229    * turned into a URL object.
 230    * @throws IOException if the URL cannot be read.
 231    * @throws UnknownCatalogFormatException if the catalog format is
 232    * not recognized.
 233    * @throws UnparseableCatalogException if the catalog cannot be parsed.
 234    * (For example, if it is supposed to be XML and isn't well-formed.)
 235    */
 236   public void readCatalog(Catalog catalog, String fileUrl)
 237     throws MalformedURLException, IOException, CatalogException {
 238     URL url = new URL(fileUrl);
 239     URLConnection urlCon = url.openConnection();
 240     readCatalog(catalog, urlCon.getInputStream());
 241   }
 242 }
--- EOF ---