Package org.apache.solr.common.util

Source Code of org.apache.solr.common.util.SystemIdResolver

/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.solr.common.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.apache.solr.common.ResourceLoader;

import org.xml.sax.InputSource;
import org.xml.sax.EntityResolver;
import org.xml.sax.ext.EntityResolver2;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
import javax.xml.transform.sax.SAXSource;
import javax.xml.stream.XMLResolver;
import javax.xml.stream.XMLStreamException;

/**
* This is a helper class to support resolving of XIncludes or other hrefs
* inside XML files on top of a {@link ResourceLoader}. Just plug this class
* on top of a {@link ResourceLoader} and pass it as {@link EntityResolver} to SAX parsers
* or via wrapper methods as {@link URIResolver} to XSL transformers or {@link XMLResolver} to STAX parsers.
* The resolver handles special SystemIds with an URI scheme of {@code solrres:} that point
* to resources. To produce such systemIds when you initially call the parser, use
* {@link #createSystemIdFromResourceName} which produces a SystemId that can
* be included along the InputStream coming from {@link ResourceLoader#openResource}.
* <p>In general create the {@link InputSource} to be passed to the parser like:</p>
* <pre class="prettyprint">
*  InputSource is = new InputSource(loader.openSchema(name));
*  is.setSystemId(SystemIdResolver.createSystemIdFromResourceName(name));
*  final DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
*  db.setEntityResolver(new SystemIdResolver(loader));
*  Document doc = db.parse(is);
* </pre>
*/
public final class SystemIdResolver implements EntityResolver, EntityResolver2 {
  private static final Logger log = LoggerFactory.getLogger(SystemIdResolver.class);

  public static final String RESOURCE_LOADER_URI_SCHEME = "solrres";
  public static final String RESOURCE_LOADER_AUTHORITY_ABSOLUTE = "@";

  private final ResourceLoader loader;

  public SystemIdResolver(ResourceLoader loader) {
    this.loader = loader;
  }
 
  public EntityResolver asEntityResolver() {
    return this;
  }
 
  public URIResolver asURIResolver() {
    return new URIResolver() {
      public Source resolve(String href, String base) throws TransformerException {
        try {
          final InputSource src = SystemIdResolver.this.resolveEntity(null, null, base, href);
          return (src == null) ? null : new SAXSource(src);
        } catch (IOException ioe) {
          throw new TransformerException("Cannot resolve entity", ioe);
        }
      }
    };
  }
 
  public XMLResolver asXMLResolver() {
    return new XMLResolver() {
      public Object resolveEntity(String publicId, String systemId, String baseURI, String namespace) throws XMLStreamException {
        try {
          final InputSource src = SystemIdResolver.this.resolveEntity(null, publicId, baseURI, systemId);
          return (src == null) ? null : src.getByteStream();
        } catch (IOException ioe) {
          throw new XMLStreamException("Cannot resolve entity", ioe);
        }
      }
    };
  }
 
  URI resolveRelativeURI(String baseURI, String systemId) throws IOException,URISyntaxException {
    URI uri;
   
    // special case for backwards compatibility: if relative systemId starts with "/" (we convert that to an absolute solrres:-URI)
    if (systemId.startsWith("/")) {
      uri = new URI(RESOURCE_LOADER_URI_SCHEME, RESOURCE_LOADER_AUTHORITY_ABSOLUTE, "/", null, null).resolve(systemId);
    } else {
      // simply parse as URI
      uri = new URI(systemId);
    }
   
    // do relative resolving
    if (baseURI != null ) {
      uri = new URI(baseURI).resolve(uri);
    }
   
    return uri;
  }
 
  // *** EntityResolver(2) methods:
 
  public InputSource getExternalSubset(String name, String baseURI) {
    return null;
  }
 
  public InputSource resolveEntity(String name, String publicId, String baseURI, String systemId) throws IOException {
    if (systemId == null)
      return null;
    try {
      final URI uri = resolveRelativeURI(baseURI, systemId);
     
      // check schema and resolve with ResourceLoader
      if (RESOURCE_LOADER_URI_SCHEME.equals(uri.getScheme())) {
        String path = uri.getPath(), authority = uri.getAuthority();
        if (!RESOURCE_LOADER_AUTHORITY_ABSOLUTE.equals(authority)) {
          path = path.substring(1);
        }
        try {
          final InputSource is = new InputSource(loader.openResource(path));
          is.setSystemId(uri.toASCIIString());
          is.setPublicId(publicId);
          return is;
        } catch (RuntimeException re) {
          // unfortunately XInclude fallback only works with IOException, but openResource() never throws that one
          throw (IOException) (new IOException(re.getMessage()).initCause(re));
        }
      } else {
        // resolve all other URIs using the standard resolver
        return null;
      }
    } catch (URISyntaxException use) {
      log.warn("An URI systax problem occurred during resolving SystemId, falling back to default resolver", use);
      return null;
    }
  }

  public InputSource resolveEntity(String publicId, String systemId) throws IOException {
    return resolveEntity(null, publicId, null, systemId);
  }
 
  public static String createSystemIdFromResourceName(String name) {
    name = name.replace(File.separatorChar, '/');
    final String authority;
    if (name.startsWith("/")) {
      // a hack to preserve absolute filenames and keep them absolute after resolving, we set the URI's authority to "@" on absolute filenames:
      authority = RESOURCE_LOADER_AUTHORITY_ABSOLUTE;
    } else {
      authority = null;
      name = "/" + name;
    }
    try {
      return new URI(RESOURCE_LOADER_URI_SCHEME, authority, name, null, null).toASCIIString();
    } catch (URISyntaxException use) {
      throw new IllegalArgumentException("Invalid syntax of Solr Resource URI", use);
    }
  }

}
TOP

Related Classes of org.apache.solr.common.util.SystemIdResolver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.