package liquibase.parser.core.xml;
import org.xml.sax.InputSource;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Logger;
import liquibase.resource.ResourceAccessor;
import liquibase.util.file.FilenameUtils;
import org.xml.sax.SAXException;
import org.xml.sax.ext.EntityResolver2;
/**
* Finds the Liquibase schema from the classpath rather than fetching it over the Internet.
* Also resolve external entities using a resourceAccessor if it's provided
*/
public class LiquibaseEntityResolver implements EntityResolver2 {
private static final String SEARCH_PACKAGE = "liquibase/parser/core/xml/";
private ResourceAccessor resourceAccessor;
private String basePath;
final Logger logger = Logger.getLogger(getClass().getName());
public LiquibaseEntityResolver() {
}
/**
* Use the resource accessor to resolve external entities
* @param resourceAccessor Resource accessor to use
* @param basePath Base path to use in the resourceAccessor
*/
public void useResoureAccessor(ResourceAccessor resourceAccessor,String basePath) {
this.resourceAccessor=resourceAccessor;
this.basePath=basePath;
}
public InputSource resolveEntity(String name, String publicId, String baseURI, String systemId) throws SAXException, IOException {
InputSource resolved=null;
if(systemId!=null && systemId.toLowerCase().endsWith(".xsd")) {
resolved=tryResolveLiquibaseSchema(systemId, publicId);
}
if(resolved==null && resourceAccessor!=null && basePath!=null && systemId!=null) {
resolved=tryResolveFromResourceAccessor(systemId);
}
return resolved;
}
private InputSource tryResolveLiquibaseSchema(String systemId, String publicId) {
if (systemId != null) {
int iSlash = systemId.lastIndexOf('/');
if (iSlash >= 0) {
String xsdFile = systemId.substring(iSlash + 1);
try {
InputStream resourceAsStream = null;
if (Thread.currentThread().getContextClassLoader() != null) {
resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(SEARCH_PACKAGE + xsdFile);
}
if (resourceAsStream == null) {
resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(SEARCH_PACKAGE + xsdFile);
}
if (resourceAsStream == null) {
return null;
}
InputSource source = new InputSource(resourceAsStream);
source.setPublicId(publicId);
source.setSystemId(systemId);
return source;
} catch (Exception ex) {
return null; // We don't have the schema, try the network
}
}
}
return null;
}
private InputSource tryResolveFromResourceAccessor(String systemId) {
String path=FilenameUtils.concat(basePath, systemId);
try {
return new InputSource(resourceAccessor.getResourceAsStream(path));
}catch(Exception ex) {
return null;
}
}
public InputSource getExternalSubset(String name, String baseURI) throws SAXException, IOException {
return null;
}
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
logger.warning("Current XML parsers seems to not support EntityResolver2. External entities won't be correctly loaded");
return tryResolveLiquibaseSchema(systemId, publicId);
}
}