1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 // BootstrapResolver.java - Resolve entities and URIs internally
   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.helpers;
  25 
  26 import java.util.Hashtable;
  27 import java.net.URL;
  28 import java.net.MalformedURLException;
  29 import java.io.InputStream;
  30 
  31 import javax.xml.transform.URIResolver;
  32 import javax.xml.transform.Source;
  33 import javax.xml.transform.sax.SAXSource;
  34 import javax.xml.transform.TransformerException;
  35 
  36 import org.xml.sax.EntityResolver;
  37 import org.xml.sax.InputSource;
  38 
  39 /**
  40  * A simple bootstrapping resolver.
  41  *
  42  * <p>This class is used as the entity resolver when reading XML Catalogs.
  43  * It searches for the OASIS XML Catalog DTD, Relax NG Grammar and W3C XML Schema
  44  * as resources (e.g., in the resolver jar file).</p>
  45  *
  46  * <p>If you have your own DTDs or schemas, you can extend this class and
  47  * set the BootstrapResolver in your CatalogManager.</p>
  48  *
  49  * @see com.sun.org.apache.xml.internal.resolver.CatalogManager
  50  *
  51  * @author Norman Walsh
  52  * <a href="mailto:Norman.Walsh@Sun.COM">Norman.Walsh@Sun.COM</a>
  53  *
  54  */
  55 public class BootstrapResolver implements EntityResolver, URIResolver {
  56   /** URI of the W3C XML Schema for OASIS XML Catalog files. */
  57   public static final String xmlCatalogXSD = "http://www.oasis-open.org/committees/entity/release/1.0/catalog.xsd";
  58 
  59   /** URI of the RELAX NG Grammar for OASIS XML Catalog files. */
  60   public static final String xmlCatalogRNG = "http://www.oasis-open.org/committees/entity/release/1.0/catalog.rng";
  61 
  62   /** Public identifier for OASIS XML Catalog files. */
  63   public static final String xmlCatalogPubId = "-//OASIS//DTD XML Catalogs V1.0//EN";
  64 
  65   /** System identifier for OASIS XML Catalog files. */
  66   public static final String xmlCatalogSysId = "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd";
  67 
  68   /** Private hash used for public identifiers. */
  69   private Hashtable publicMap = new Hashtable();
  70 
  71   /** Private hash used for system identifiers. */
  72   private Hashtable systemMap = new Hashtable();
  73 
  74   /** Private hash used for URIs. */
  75   private Hashtable uriMap = new Hashtable();
  76 
  77   /** Constructor. */
  78   public BootstrapResolver() {
  79     URL url = this.getClass().getResource("/com/sun/org/apache/xml/internal/resolver/etc/catalog.dtd");
  80     if (url != null) {
  81       publicMap.put(xmlCatalogPubId, url.toString());
  82       systemMap.put(xmlCatalogSysId, url.toString());
  83     }
  84 
  85     url = this.getClass().getResource("/com/sun/org/apache/xml/internal/resolver/etc/catalog.rng");
  86     if (url != null) {
  87       uriMap.put(xmlCatalogRNG, url.toString());
  88     }
  89 
  90     url = this.getClass().getResource("/com/sun/org/apache/xml/internal/resolver/etc/catalog.xsd");
  91     if (url != null) {
  92       uriMap.put(xmlCatalogXSD, url.toString());
  93     }
  94   }
  95 
  96   /** SAX resolveEntity API. */
  97   public InputSource resolveEntity (String publicId, String systemId) {
  98     String resolved = null;
  99 
 100     if (systemId != null && systemMap.containsKey(systemId)) {
 101       resolved = (String) systemMap.get(systemId);
 102     } else if (publicId != null && publicMap.containsKey(publicId)) {
 103       resolved = (String) publicMap.get(publicId);
 104     }
 105 
 106     if (resolved != null) {
 107       try {
 108         InputSource iSource = new InputSource(resolved);
 109         iSource.setPublicId(publicId);
 110 
 111         // Ideally this method would not attempt to open the
 112         // InputStream, but there is a bug (in Xerces, at least)
 113         // that causes the parser to mistakenly open the wrong
 114         // system identifier if the returned InputSource does
 115         // not have a byteStream.
 116         //
 117         // It could be argued that we still shouldn't do this here,
 118         // but since the purpose of calling the entityResolver is
 119         // almost certainly to open the input stream, it seems to
 120         // do little harm.
 121         //
 122         URL url = new URL(resolved);
 123         InputStream iStream = url.openStream();
 124         iSource.setByteStream(iStream);
 125 
 126         return iSource;
 127       } catch (Exception e) {
 128         // FIXME: silently fail?
 129         return null;
 130       }
 131     }
 132 
 133     return null;
 134   }
 135 
 136   /** Transformer resolve API. */
 137   public Source resolve(String href, String base)
 138     throws TransformerException {
 139 
 140     String uri = href;
 141     String fragment = null;
 142     int hashPos = href.indexOf("#");
 143     if (hashPos >= 0) {
 144       uri = href.substring(0, hashPos);
 145       fragment = href.substring(hashPos+1);
 146     }
 147 
 148     String result = null;
 149     if (href != null && uriMap.containsKey(href)) {
 150       result = (String) uriMap.get(href);
 151     }
 152 
 153     if (result == null) {
 154       try {
 155         URL url = null;
 156 
 157         if (base==null) {
 158           url = new URL(uri);
 159           result = url.toString();
 160         } else {
 161           URL baseURL = new URL(base);
 162           url = (href.length()==0 ? baseURL : new URL(baseURL, uri));
 163           result = url.toString();
 164         }
 165       } catch (java.net.MalformedURLException mue) {
 166         // try to make an absolute URI from the current base
 167         String absBase = makeAbsolute(base);
 168         if (!absBase.equals(base)) {
 169           // don't bother if the absBase isn't different!
 170           return resolve(href, absBase);
 171         } else {
 172           throw new TransformerException("Malformed URL "
 173                                          + href + "(base " + base + ")",
 174                                          mue);
 175         }
 176       }
 177     }
 178 
 179     SAXSource source = new SAXSource();
 180     source.setInputSource(new InputSource(result));
 181     return source;
 182   }
 183 
 184   /** Attempt to construct an absolute URI */
 185   private String makeAbsolute(String uri) {
 186     if (uri == null) {
 187       uri = "";
 188     }
 189 
 190     try {
 191       URL url = new URL(uri);
 192       return url.toString();
 193     } catch (MalformedURLException mue) {
 194       try {
 195         URL fileURL = FileURL.makeURL(uri);
 196         return fileURL.toString();
 197       } catch (MalformedURLException mue2) {
 198         // bail
 199         return uri;
 200       }
 201     }
 202   }
 203 }