package liquibase.parser.core.xml; import java.io.IOException; import java.io.InputStream; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.Source; import javax.xml.validation.SchemaFactory; import liquibase.changelog.ChangeLogParameters; import liquibase.exception.ChangeLogParseException; import liquibase.logging.LogFactory; import liquibase.parser.core.ParsedNode; import liquibase.resource.UtfBomStripperInputStream; import liquibase.resource.ResourceAccessor; import liquibase.util.StreamUtil; import liquibase.util.file.FilenameUtils; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; import org.xml.sax.SAXParseException; import org.xml.sax.XMLReader; public class XMLChangeLogSAXParser extends AbstractChangeLogParser { private SAXParserFactory saxParserFactory; public XMLChangeLogSAXParser() { saxParserFactory = SAXParserFactory.newInstance(); saxParserFactory.setValidating(true); saxParserFactory.setNamespaceAware(true); } @Override public int getPriority() { return PRIORITY_DEFAULT; } public static String getSchemaVersion() { return "3.6"; } @Override public boolean supports(String changeLogFile, ResourceAccessor resourceAccessor) { return changeLogFile.toLowerCase().endsWith("xml"); } protected SAXParserFactory getSaxParserFactory() { return saxParserFactory; } @Override protected ParsedNode parseToNode(String physicalChangeLogLocation, ChangeLogParameters changeLogParameters, ResourceAccessor resourceAccessor) throws ChangeLogParseException { InputStream inputStream = null; try { SAXParser parser = saxParserFactory.newSAXParser(); try { parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema"); } catch (SAXNotRecognizedException e) { //ok, parser must not support it } catch (SAXNotSupportedException e) { //ok, parser must not support it } XMLReader xmlReader = parser.getXMLReader(); LiquibaseEntityResolver resolver=new LiquibaseEntityResolver(this); resolver.useResoureAccessor(resourceAccessor,FilenameUtils.getFullPath(physicalChangeLogLocation)); xmlReader.setEntityResolver(resolver); xmlReader.setErrorHandler(new ErrorHandler() { @Override public void warning(SAXParseException exception) throws SAXException { LogFactory.getLogger().warning(exception.getMessage()); throw exception; } @Override public void error(SAXParseException exception) throws SAXException { LogFactory.getLogger().severe(exception.getMessage()); throw exception; } @Override public void fatalError(SAXParseException exception) throws SAXException { LogFactory.getLogger().severe(exception.getMessage()); throw exception; } }); inputStream = StreamUtil.singleInputStream(physicalChangeLogLocation, resourceAccessor); if (inputStream == null) { if (physicalChangeLogLocation.startsWith("WEB-INF/classes/")) { physicalChangeLogLocation = physicalChangeLogLocation.replaceFirst("WEB-INF/classes/", ""); inputStream = StreamUtil.singleInputStream(physicalChangeLogLocation, resourceAccessor); } if (inputStream == null) { throw new ChangeLogParseException(physicalChangeLogLocation + " does not exist"); } } XMLChangeLogSAXHandler contentHandler = new XMLChangeLogSAXHandler(physicalChangeLogLocation, resourceAccessor, changeLogParameters); xmlReader.setContentHandler(contentHandler); xmlReader.parse(new InputSource(new UtfBomStripperInputStream(inputStream))); return contentHandler.getDatabaseChangeLogTree(); } catch (ChangeLogParseException e) { throw e; } catch (IOException e) { throw new ChangeLogParseException("Error Reading Migration File: " + e.getMessage(), e); } catch (SAXParseException e) { throw new ChangeLogParseException("Error parsing line " + e.getLineNumber() + " column " + e.getColumnNumber() + " of " + physicalChangeLogLocation +": " + e.getMessage(), e); } catch (SAXException e) { Throwable parentCause = e.getException(); while (parentCause != null) { if (parentCause instanceof ChangeLogParseException) { throw ((ChangeLogParseException) parentCause); } parentCause = parentCause.getCause(); } String reason = e.getMessage(); String causeReason = null; if (e.getCause() != null) { causeReason = e.getCause().getMessage(); } // if (reason == null && causeReason==null) { // reason = "Unknown Reason"; // } if (reason == null) { if (causeReason != null) { reason = causeReason; } else { reason = "Unknown Reason"; } } throw new ChangeLogParseException("Invalid Migration File: " + reason, e); } catch (Exception e) { throw new ChangeLogParseException(e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { // probably ok } } } } }