View Javadoc
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 }