1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mybatis.generator.config.xml;
17
18 import static org.mybatis.generator.internal.util.messages.Messages.getString;
19
20 import java.io.BufferedReader;
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.Reader;
25 import java.nio.file.Files;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.Properties;
30 import javax.xml.XMLConstants;
31 import javax.xml.parsers.DocumentBuilder;
32 import javax.xml.parsers.DocumentBuilderFactory;
33 import javax.xml.parsers.ParserConfigurationException;
34
35 import org.jspecify.annotations.Nullable;
36 import org.mybatis.generator.codegen.XmlConstants;
37 import org.mybatis.generator.config.Configuration;
38 import org.mybatis.generator.exception.XMLParserException;
39 import org.w3c.dom.Document;
40 import org.w3c.dom.DocumentType;
41 import org.w3c.dom.Element;
42 import org.w3c.dom.Node;
43 import org.xml.sax.InputSource;
44 import org.xml.sax.SAXException;
45 import org.xml.sax.SAXParseException;
46
47 public class ConfigurationParser {
48 private final List<String> warnings = new ArrayList<>();
49 private final List<String> parseErrors = new ArrayList<>();
50 private final @Nullable Properties extraProperties;
51
52 public ConfigurationParser() {
53 this(null);
54 }
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 public ConfigurationParser(@Nullable Properties extraProperties) {
76 this.extraProperties = extraProperties;
77 }
78
79 public List<String> getWarnings() {
80 return Collections.unmodifiableList(warnings);
81 }
82
83 public Configuration parseConfiguration(File inputFile) throws IOException, XMLParserException {
84 try (BufferedReader fr = Files.newBufferedReader(inputFile.toPath())) {
85 return parseConfiguration(fr);
86 }
87 }
88
89 public Configuration parseConfiguration(Reader reader) throws IOException, XMLParserException {
90 InputSource is = new InputSource(reader);
91 return parseConfiguration(is);
92 }
93
94 public Configuration parseConfiguration(InputStream inputStream) throws IOException, XMLParserException {
95 InputSource is = new InputSource(inputStream);
96 return parseConfiguration(is);
97 }
98
99 private Configuration parseConfiguration(InputSource inputSource) throws IOException, XMLParserException {
100 parseErrors.clear();
101 warnings.clear();
102
103 try {
104 Document document = basicParse(inputSource);
105
106 if (document == null || !parseErrors.isEmpty()) {
107 throw new XMLParserException(getString("RuntimeError.31"), parseErrors);
108 }
109
110 Configuration config;
111 Element rootNode = document.getDocumentElement();
112 DocumentType docType = document.getDoctype();
113 if (rootNode.getNodeType() == Node.ELEMENT_NODE
114 && docType.getPublicId().equals(XmlConstants.MYBATIS_GENERATOR_CONFIG_PUBLIC_ID)) {
115 config = parseMyBatisGeneratorConfiguration(rootNode);
116 } else {
117 throw new XMLParserException(getString("RuntimeError.5"));
118 }
119
120 if (!parseErrors.isEmpty()) {
121 throw new XMLParserException(getString("RuntimeError.31"), parseErrors);
122 }
123
124 return config;
125 } catch (ParserConfigurationException e) {
126 throw new XMLParserException(e.getMessage(), e, parseErrors);
127 }
128 }
129
130 private @Nullable Document basicParse(InputSource inputSource) throws IOException, ParserConfigurationException,
131 XMLParserException {
132 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
133 factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
134 factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
135 factory.setValidating(true);
136
137 factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
138 DocumentBuilder builder = factory.newDocumentBuilder();
139 builder.setEntityResolver(new ParserEntityResolver());
140
141 ParserErrorHandler handler = new ParserErrorHandler(warnings, parseErrors);
142 builder.setErrorHandler(handler);
143
144 Document document = null;
145 try {
146 document = builder.parse(inputSource);
147 } catch (SAXParseException e) {
148 throw new XMLParserException(e.getMessage(), e, parseErrors);
149 } catch (SAXException e) {
150 parseErrors.add(e.getMessage());
151 if (e.getException() != null) {
152 parseErrors.add(e.getException().getMessage());
153 }
154 }
155
156 return document;
157 }
158
159 private Configuration parseMyBatisGeneratorConfiguration(Element rootNode) throws XMLParserException {
160 MyBatisGeneratorConfigurationParser parser = new MyBatisGeneratorConfigurationParser(extraProperties, warnings);
161 return parser.parseConfiguration(rootNode);
162 }
163 }