001// Copyright 2011 Leo Przybylski. All rights reserved. 002// 003// Redistribution and use in source and binary forms, with or without modification, are 004// permitted provided that the following conditions are met: 005// 006// 1. Redistributions of source code must retain the above copyright notice, this list of 007// conditions and the following disclaimer. 008// 009// 2. Redistributions in binary form must reproduce the above copyright notice, this list 010// of conditions and the following disclaimer in the documentation and/or other materials 011// provided with the distribution. 012// 013// THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY EXPRESS OR IMPLIED 014// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 015// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR 016// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 017// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 018// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 019// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 020// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 021// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 022// 023// The views and conclusions contained in the software and documentation are those of the 024// authors and should not be interpreted as representing official policies, either expressed 025// or implied, of Leo Przybylski. 026package org.kualigan.tools.liquibase; 027 028import java.io.IOException; 029import java.io.InputStream; 030 031import javax.xml.parsers.SAXParser; 032import javax.xml.parsers.SAXParserFactory; 033 034import liquibase.changelog.ChangeLogParameters; 035import liquibase.changelog.DatabaseChangeLog; 036import liquibase.exception.ChangeLogParseException; 037import liquibase.logging.LogFactory; 038import liquibase.parser.ChangeLogParser; 039import liquibase.parser.core.xml.*; 040import liquibase.resource.ResourceAccessor; 041import liquibase.util.file.FilenameUtils; 042 043import org.xml.sax.ErrorHandler; 044import org.xml.sax.InputSource; 045import org.xml.sax.SAXException; 046import org.xml.sax.SAXNotRecognizedException; 047import org.xml.sax.SAXNotSupportedException; 048import org.xml.sax.SAXParseException; 049import org.xml.sax.XMLReader; 050 051public class XMLChangeLogParser extends liquibase.parser.core.xml.XMLChangeLogSAXParser { 052 053 public static String getSchemaVersion() { 054 return "2.0"; 055 } 056 057 public DatabaseChangeLog parse(String physicalChangeLogLocation, ChangeLogParameters changeLogParameters, ResourceAccessor resourceAccessor) throws ChangeLogParseException { 058 059 InputStream inputStream = null; 060 try { 061 062 SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); 063 try { 064 parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema"); 065 } catch (SAXNotRecognizedException e) { 066 //ok, parser must not support it 067 } catch (SAXNotSupportedException e) { 068 //ok, parser must not support it 069 } 070 071 XMLReader xmlReader = parser.getXMLReader(); 072 LiquibaseEntityResolver resolver=new LiquibaseEntityResolver(); 073 resolver.useResoureAccessor(resourceAccessor,FilenameUtils.getFullPath(physicalChangeLogLocation)); 074 xmlReader.setEntityResolver(resolver); 075 xmlReader.setErrorHandler(new ErrorHandler() { 076 public void warning(SAXParseException exception) throws SAXException { 077 LogFactory.getLogger().warning(exception.getMessage()); 078 throw exception; 079 } 080 081 public void error(SAXParseException exception) throws SAXException { 082 LogFactory.getLogger().severe(exception.getMessage()); 083 throw exception; 084 } 085 086 public void fatalError(SAXParseException exception) throws SAXException { 087 LogFactory.getLogger().severe(exception.getMessage()); 088 throw exception; 089 } 090 }); 091 092 inputStream = resourceAccessor.getResourceAsStream(physicalChangeLogLocation); 093 if (inputStream == null) { 094 throw new ChangeLogParseException(physicalChangeLogLocation + " does not exist"); 095 } 096 097 XMLChangeLogSAXHandler contentHandler = new XMLChangeLogSAXHandler(physicalChangeLogLocation, resourceAccessor, changeLogParameters); 098 xmlReader.setContentHandler(contentHandler); 099 xmlReader.parse(new InputSource(inputStream)); 100 101 return contentHandler.getDatabaseChangeLog(); 102 } catch (ChangeLogParseException e) { 103 throw e; 104 } catch (IOException e) { 105 throw new ChangeLogParseException("Error Reading Migration File: " + e.getMessage(), e); 106 } catch (SAXParseException e) { 107 throw new ChangeLogParseException("Error parsing line " + e.getLineNumber() + " column " + e.getColumnNumber() + " of " + physicalChangeLogLocation +": " + e.getMessage(), e); 108 } catch (SAXException e) { 109 Throwable parentCause = e.getException(); 110 while (parentCause != null) { 111 if (parentCause instanceof ChangeLogParseException) { 112 throw ((ChangeLogParseException) parentCause); 113 } 114 parentCause = parentCause.getCause(); 115 } 116 String reason = e.getMessage(); 117 String causeReason = null; 118 if (e.getCause() != null) { 119 causeReason = e.getCause().getMessage(); 120 } 121 122// if (reason == null && causeReason==null) { 123// reason = "Unknown Reason"; 124// } 125 if (reason == null) { 126 if (causeReason != null) { 127 reason = causeReason; 128 } else { 129 reason = "Unknown Reason"; 130 } 131 } 132 133 throw new ChangeLogParseException("Invalid Migration File: " + reason, e); 134 } catch (Exception e) { 135 throw new ChangeLogParseException(e); 136 } finally { 137 if (inputStream != null) { 138 try { 139 inputStream.close(); 140 } catch (IOException e) { 141 // probably ok 142 } 143 } 144 } 145 } 146}