forked from liquibase/liquibase
/
XMLChangeLogSAXParser.java
138 lines (119 loc) · 5.57 KB
/
XMLChangeLogSAXParser.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package liquibase.parser.core.xml;
import liquibase.Scope;
import liquibase.changelog.ChangeLogParameters;
import liquibase.exception.ChangeLogParseException;
import liquibase.parser.core.ParsedNode;
import liquibase.resource.ResourceAccessor;
import liquibase.util.BomAwareInputStream;
import liquibase.util.FileUtil;
import org.xml.sax.*;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.io.InputStream;
public class XMLChangeLogSAXParser extends AbstractChangeLogParser {
public static final String LIQUIBASE_SCHEMA_VERSION = "4.6";
private SAXParserFactory saxParserFactory;
private final LiquibaseEntityResolver resolver = new LiquibaseEntityResolver();
public XMLChangeLogSAXParser() {
saxParserFactory = SAXParserFactory.newInstance();
saxParserFactory.setValidating(true);
saxParserFactory.setNamespaceAware(true);
}
@Override
public int getPriority() {
return PRIORITY_DEFAULT;
}
public static String getSchemaVersion() {
return LIQUIBASE_SCHEMA_VERSION;
}
@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 {
try (InputStream inputStream = resourceAccessor.openStream(null, physicalChangeLogLocation)) {
SAXParser parser = saxParserFactory.newSAXParser();
trySetSchemaLanguageProperty(parser);
XMLReader xmlReader = parser.getXMLReader();
xmlReader.setEntityResolver(resolver);
xmlReader.setErrorHandler(new ErrorHandler() {
@Override
public void warning(SAXParseException exception) throws SAXException {
Scope.getCurrentScope().getLog(getClass()).warning(exception.getMessage());
throw exception;
}
@Override
public void error(SAXParseException exception) throws SAXException {
Scope.getCurrentScope().getLog(getClass()).severe(exception.getMessage());
throw exception;
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
Scope.getCurrentScope().getLog(getClass()).severe(exception.getMessage());
throw exception;
}
});
if (inputStream == null) {
if (physicalChangeLogLocation.startsWith("WEB-INF/classes/")) {
// Correct physicalChangeLogLocation and try again.
return parseToNode(
physicalChangeLogLocation.replaceFirst("WEB-INF/classes/", ""),
changeLogParameters, resourceAccessor);
} else {
throw new ChangeLogParseException(FileUtil.getFileNotFoundMessage(physicalChangeLogLocation));
}
}
XMLChangeLogSAXHandler contentHandler = new XMLChangeLogSAXHandler(physicalChangeLogLocation, resourceAccessor, changeLogParameters);
xmlReader.setContentHandler(contentHandler);
xmlReader.parse(new InputSource(new BomAwareInputStream(inputStream)));
return contentHandler.getDatabaseChangeLogTree();
} catch (ChangeLogParseException e) {
throw e;
} catch (IOException e) {
throw new ChangeLogParseException("Error Reading Changelog 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) {
if (causeReason != null) {
reason = causeReason;
} else {
reason = "Unknown Reason";
}
}
throw new ChangeLogParseException("Invalid Migration File: " + reason, e);
} catch (Exception e) {
throw new ChangeLogParseException(e);
}
}
/**
* Try to set the parser property "schemaLanguage", but do not mind if the parser does not understand it.
*
* @param parser the parser to configure
* @todo If we do not mind, why do we set it in the first place? Need to resarch in git...
*/
private void trySetSchemaLanguageProperty(SAXParser parser) {
try {
parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
} catch (SAXNotRecognizedException | SAXNotSupportedException ignored) {
//ok, parser need not support it
}
}
}