/*
* eXist Open Source Native XML Database
* Copyright (C) 2001-2010 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* $Id$
*/
package org.exist.validation.resolver;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.xerces.util.XMLCatalogResolver;
import org.apache.xerces.xni.XMLResourceIdentifier;
import org.apache.xerces.xni.XNIException;
import org.apache.xerces.xni.parser.XMLInputSource;
import org.exist.util.FileUtils;
import org.w3c.dom.ls.LSInput;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Wrapper around xerces2's
* <a href="http://xerces.apache.org/xerces2-j/javadocs/xerces2/org/apache/xerces/util/XMLCatalogResolver.html"
* >XMLCatalogresolver</a>
*
* @author Dannes Wessels (dizzzz@exist-db.org)
*/
public class eXistXMLCatalogResolver extends XMLCatalogResolver {
public eXistXMLCatalogResolver() {
super();
LOG.debug("Initializing");
}
public eXistXMLCatalogResolver(java.lang.String[] catalogs) {
super(catalogs);
LOG.debug("Initializing using catalogs");
}
eXistXMLCatalogResolver(java.lang.String[] catalogs, boolean preferPublic) {
super(catalogs, preferPublic);
LOG.debug("Initializing using catalogs, preferPublic=" + preferPublic);
}
private final static Logger LOG = LogManager.getLogger(eXistXMLCatalogResolver.class);
/**
* Constructs a catalog resolver with the given list of entry files.
*
* @param catalogs List of Strings
* <p>
* TODO: check for non-String and NULL values.
*/
public void setCatalogs(List<String> catalogs) {
if (catalogs != null && catalogs.size() > 0) {
final String[] allCatalogs = new String[catalogs.size()];
int counter = 0;
for (String element : catalogs) {
allCatalogs[counter] = element;
counter++;
}
super.setCatalogList(allCatalogs);
}
}
/**
* @see org.apache.xerces.util.XMLCatalogResolver#resolveEntity(String, String)
*/
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
LOG.debug("Resolving publicId='" + publicId + "', systemId='" + systemId + "'");
InputSource retValue = super.resolveEntity(publicId, systemId);
if (retValue == null) {
retValue = resolveEntityFallback(publicId, systemId);
}
LOG.debug("Resolved " + (retValue != null));
if (retValue != null) {
LOG.debug("PublicId='" + retValue.getPublicId() + "' SystemId=" + retValue.getSystemId());
}
return retValue;
}
/**
* moved from Collection.resolveEntity() revision 6144
*/
private InputSource resolveEntityFallback(String publicId, String systemId) throws SAXException, IOException {
//if resolution failed and publicId == null,
// try to make absolute file names relative and retry
LOG.debug("Resolve failed, fallback scenario");
if (publicId != null) {
return null;
}
final URL url = new URL(systemId);
if ("file".equals(url.getProtocol())) {
final String path = url.getPath();
final Path f = Paths.get(path).normalize();
if (!Files.isReadable(f)) {
return resolveEntity(null, FileUtils.fileName(f));
} else {
return new InputSource(f.toAbsolutePath().toString());
}
} else {
return new InputSource(url.openStream()); //TODO(AR) stream is never closed!
}
}
/**
* @see org.apache.xerces.util.XMLCatalogResolver#resolveResource(String, String, String, String, String)
*/
public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) {
LOG.debug("Resolving type='" + type + "', namespaceURI='" + namespaceURI + "', publicId='" + publicId + "', systemId='" + systemId + "', baseURI='" + baseURI + "'");
final LSInput retValue = super.resolveResource(type, namespaceURI, publicId, systemId, baseURI);
LOG.debug("Resolved " + (retValue != null));
if (retValue != null) {
LOG.debug("PublicId='" + retValue.getPublicId() + "' SystemId='"
+ retValue.getSystemId() + "' BaseURI='" + retValue.getBaseURI() + "'");
}
return retValue;
}
/**
* @see org.apache.xerces.util.XMLCatalogResolver#resolveEntity(String, String, String, String)
*/
public InputSource resolveEntity(String name, String publicId, String baseURI, String systemId) throws SAXException, IOException {
LOG.debug("Resolving name='" + name + "', publicId='" + publicId + "', baseURI='" + baseURI + "', systemId='" + systemId + "'");
final InputSource retValue = super.resolveEntity(name, publicId, baseURI, systemId);
LOG.debug("Resolved " + (retValue != null));
if (retValue != null) {
LOG.debug("PublicId='" + retValue.getPublicId() + "' SystemId='"
+ retValue.getSystemId() + "'");
}
return retValue;
}
/**
* @see org.apache.xerces.util.XMLCatalogResolver#resolveIdentifier(XMLResourceIdentifier)
*/
public String resolveIdentifier(XMLResourceIdentifier xri) throws IOException, XNIException {
if (xri.getExpandedSystemId() == null && xri.getLiteralSystemId() == null &&
xri.getNamespace() == null && xri.getPublicId() == null) {
// quick fail
return null;
}
if (LOG.isDebugEnabled()) {
LOG.debug("Resolving XMLResourceIdentifier: " + getXriDetails(xri));
}
final String retValue = super.resolveIdentifier(xri);
LOG.debug("Resolved " + (retValue != null));
if (retValue != null) {
LOG.debug("Identifier='" + retValue + "'");
}
return retValue;
}
/**
* @see org.apache.xerces.util.XMLCatalogResolver#resolveEntity(XMLResourceIdentifier)
*/
public XMLInputSource resolveEntity(XMLResourceIdentifier xri) throws XNIException, IOException {
if (xri.getExpandedSystemId() == null && xri.getLiteralSystemId() == null &&
xri.getNamespace() == null && xri.getPublicId() == null) {
// quick fail
return null;
}
if (LOG.isDebugEnabled()) {
LOG.debug("Resolving XMLResourceIdentifier: " + getXriDetails(xri));
}
final XMLInputSource retValue = super.resolveEntity(xri);
LOG.debug("Resolved " + (retValue != null));
if (retValue != null) {
LOG.debug("PublicId='" + retValue.getPublicId() + "' SystemId='"
+ retValue.getSystemId() + "' BaseSystemId=" + retValue.getBaseSystemId());
}
return retValue;
}
/**
* @see org.apache.xerces.util.XMLCatalogResolver#getExternalSubset(String, String)
*/
public InputSource getExternalSubset(String name, String baseURI) throws SAXException, IOException {
LOG.debug("name='" + name + "' baseURI='" + baseURI + "'");
return super.getExternalSubset(name, baseURI);
}
private String getXriDetails(XMLResourceIdentifier xrid) {
return "PublicId='" + xrid.getPublicId() + "' " + "BaseSystemId='" + xrid.getBaseSystemId() + "' " + "ExpandedSystemId='" + xrid.getExpandedSystemId() + "' " + "LiteralSystemId='" + xrid.getLiteralSystemId() + "' " + "Namespace='" + xrid.getNamespace() + "' ";
}
}