jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogUriResolverImpl.java
changeset 40607 951ac908273b
parent 40606 eb2c81860c86
parent 40585 620845c802cd
child 40608 a71210c0d980
equal deleted inserted replaced
40606:eb2c81860c86 40607:951ac908273b
     1 /*
       
     2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 package javax.xml.catalog;
       
    26 
       
    27 import com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl;
       
    28 import java.io.StringReader;
       
    29 import java.net.URL;
       
    30 import java.util.Iterator;
       
    31 import javax.xml.parsers.ParserConfigurationException;
       
    32 import javax.xml.parsers.SAXParserFactory;
       
    33 import javax.xml.transform.Source;
       
    34 import javax.xml.transform.sax.SAXSource;
       
    35 import org.xml.sax.InputSource;
       
    36 import org.xml.sax.SAXException;
       
    37 import org.xml.sax.XMLReader;
       
    38 
       
    39 /**
       
    40  * A SAX EntityResolver/JAXP URIResolver that uses catalogs.
       
    41  * <p>
       
    42  * This class implements both a SAX EntityResolver and a JAXP URIResolver.
       
    43  *
       
    44  *
       
    45  * @since 9
       
    46  */
       
    47 final class CatalogUriResolverImpl implements CatalogUriResolver {
       
    48 
       
    49     Catalog catalog;
       
    50     CatalogResolverImpl entityResolver;
       
    51 
       
    52     /**
       
    53      * Construct an instance of the CatalogResolver from a Catalog.
       
    54      *
       
    55      * @param catalog A Catalog.
       
    56      */
       
    57     public CatalogUriResolverImpl(Catalog catalog) {
       
    58         this.catalog = catalog;
       
    59     }
       
    60 
       
    61     @Override
       
    62     public Source resolve(String href, String base) {
       
    63         href = Util.getNotNullOrEmpty(href);
       
    64         base = Util.getNotNullOrEmpty(base);
       
    65 
       
    66         if (href == null) return null;
       
    67 
       
    68         String result = null;
       
    69         CatalogImpl c = (CatalogImpl)catalog;
       
    70         String uri = Normalizer.normalizeURI(href);
       
    71         //check whether uri is an urn
       
    72         if (uri != null && uri.startsWith(Util.URN)) {
       
    73             String publicId = Normalizer.decodeURN(uri);
       
    74             if (publicId != null) {
       
    75                 result = Util.resolve(c, publicId, null);
       
    76             }
       
    77         }
       
    78 
       
    79         //if no match with a public id, continue search for an URI
       
    80         if (result == null) {
       
    81             //remove fragment if any.
       
    82             int hashPos = uri.indexOf("#");
       
    83             if (hashPos >= 0) {
       
    84                 uri = uri.substring(0, hashPos);
       
    85             }
       
    86 
       
    87             //search the current catalog
       
    88             result = resolve(c, uri);
       
    89         }
       
    90 
       
    91         //Report error or return the URI as is when no match is found
       
    92         if (result == null) {
       
    93             GroupEntry.ResolveType resolveType = c.getResolve();
       
    94             switch (resolveType) {
       
    95                 case IGNORE:
       
    96                     return new SAXSource(new InputSource(new StringReader("")));
       
    97                 case STRICT:
       
    98                     CatalogMessages.reportError(CatalogMessages.ERR_NO_URI_MATCH,
       
    99                             new Object[]{href, base});
       
   100             }
       
   101             try {
       
   102                 URL url = null;
       
   103 
       
   104                 if (base == null) {
       
   105                     url = new URL(uri);
       
   106                     result = url.toString();
       
   107                 } else {
       
   108                     URL baseURL = new URL(base);
       
   109                     url = (href.length() == 0 ? baseURL : new URL(baseURL, uri));
       
   110                     result = url.toString();
       
   111                 }
       
   112             } catch (java.net.MalformedURLException mue) {
       
   113                     CatalogMessages.reportError(CatalogMessages.ERR_CREATING_URI,
       
   114                             new Object[]{href, base});
       
   115             }
       
   116         }
       
   117 
       
   118         SAXSource source = new SAXSource();
       
   119         source.setInputSource(new InputSource(result));
       
   120         setEntityResolver(source);
       
   121         return source;
       
   122     }
       
   123 
       
   124     /**
       
   125      * Resolves the publicId or systemId to one specified in the catalog.
       
   126      * @param catalog the catalog
       
   127      * @param href an href attribute, which may be relative or absolute
       
   128      * @return the resolved systemId if a match is found, null otherwise
       
   129      */
       
   130     String resolve(CatalogImpl catalog, String href) {
       
   131         String result = null;
       
   132 
       
   133         //search the current catalog
       
   134         catalog.reset();
       
   135         if (href != null) {
       
   136             result = catalog.matchURI(href);
       
   137         }
       
   138 
       
   139         //mark the catalog as having been searched before trying alternatives
       
   140         catalog.markAsSearched();
       
   141 
       
   142         //search alternative catalogs
       
   143         if (result == null) {
       
   144             Iterator<Catalog> iter = catalog.catalogs().iterator();
       
   145             while (iter.hasNext()) {
       
   146                 result = resolve((CatalogImpl)iter.next(), href);
       
   147                 if (result != null) {
       
   148                     break;
       
   149                 }
       
   150             }
       
   151         }
       
   152 
       
   153         return result;
       
   154     }
       
   155 
       
   156     /**
       
   157      * Establish an entityResolver for newly resolved URIs.
       
   158      * <p>
       
   159      * This is called from the URIResolver to set an EntityResolver on the SAX
       
   160      * parser to be used for new XML documents that are encountered as a result
       
   161      * of the document() function, xsl:import, or xsl:include. This is done
       
   162      * because the XSLT processor calls out to the SAXParserFactory itself to
       
   163      * create a new SAXParser to parse the new document. The new parser does not
       
   164      * automatically inherit the EntityResolver of the original (although
       
   165      * arguably it should). Quote from JAXP specification on Class
       
   166      * SAXTransformerFactory:
       
   167      * <p>
       
   168      * {@code If an application wants to set the ErrorHandler or EntityResolver
       
   169      * for an XMLReader used during a transformation, it should use a URIResolver
       
   170      * to return the SAXSource which provides (with getXMLReader) a reference to
       
   171      * the XMLReader}
       
   172      *
       
   173      */
       
   174     private void setEntityResolver(SAXSource source) {
       
   175         XMLReader reader = source.getXMLReader();
       
   176         if (reader == null) {
       
   177             SAXParserFactory spFactory = new SAXParserFactoryImpl();
       
   178             spFactory.setNamespaceAware(true);
       
   179             try {
       
   180                 reader = spFactory.newSAXParser().getXMLReader();
       
   181             } catch (ParserConfigurationException | SAXException ex) {
       
   182                 CatalogMessages.reportRunTimeError(CatalogMessages.ERR_PARSER_CONF, ex);
       
   183             }
       
   184         }
       
   185         if (entityResolver != null) {
       
   186             entityResolver = new CatalogResolverImpl(catalog);
       
   187         }
       
   188         reader.setEntityResolver(entityResolver);
       
   189         source.setXMLReader(reader);
       
   190     }
       
   191 }