1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.ibatis.sqlmap.engine.builder.xml;
17
18 import com.ibatis.common.resources.Resources;
19 import com.ibatis.common.xml.NodeletParser;
20 import com.ibatis.common.xml.NodeletUtils;
21 import com.ibatis.sqlmap.client.SqlMapClient;
22 import com.ibatis.sqlmap.client.SqlMapException;
23 import com.ibatis.sqlmap.engine.config.SqlMapConfiguration;
24 import com.ibatis.sqlmap.engine.datasource.DataSourceFactory;
25 import com.ibatis.sqlmap.engine.mapping.result.ResultObjectFactory;
26 import com.ibatis.sqlmap.engine.transaction.TransactionConfig;
27 import com.ibatis.sqlmap.engine.transaction.TransactionManager;
28
29 import java.io.InputStream;
30 import java.io.Reader;
31 import java.util.Properties;
32
33
34
35
36 public class SqlMapConfigParser {
37
38
39 protected final NodeletParser parser = new NodeletParser();
40
41
42 private XmlParserState state = new XmlParserState();
43
44
45 private boolean usingStreams = false;
46
47
48
49
50 public SqlMapConfigParser() {
51 parser.setValidation(true);
52 parser.setEntityResolver(new SqlMapClasspathEntityResolver());
53
54 addSqlMapConfigNodelets();
55 addGlobalPropNodelets();
56 addSettingsNodelets();
57 addTypeAliasNodelets();
58 addTypeHandlerNodelets();
59 addTransactionManagerNodelets();
60 addSqlMapNodelets();
61 addResultObjectFactoryNodelets();
62
63 }
64
65
66
67
68
69
70
71
72
73
74
75 public SqlMapClient parse(Reader reader, Properties props) {
76 if (props != null) {
77 state.setGlobalProps(props);
78 }
79 return parse(reader);
80 }
81
82
83
84
85
86
87
88
89
90 public SqlMapClient parse(Reader reader) {
91 try {
92 usingStreams = false;
93
94 parser.parse(reader);
95 return state.getConfig().getClient();
96 } catch (Exception e) {
97 throw new RuntimeException("Error occurred. Cause: " + e, e);
98 }
99 }
100
101
102
103
104
105
106
107
108
109
110
111 public SqlMapClient parse(InputStream inputStream, Properties props) {
112 if (props != null) {
113 state.setGlobalProps(props);
114 }
115 return parse(inputStream);
116 }
117
118
119
120
121
122
123
124
125
126 public SqlMapClient parse(InputStream inputStream) {
127 try {
128 usingStreams = true;
129
130 parser.parse(inputStream);
131 return state.getConfig().getClient();
132 } catch (Exception e) {
133 throw new RuntimeException("Error occurred. Cause: " + e, e);
134 }
135 }
136
137
138
139
140 private void addSqlMapConfigNodelets() {
141 parser.addNodelet("/sqlMapConfig/end()", node -> state.getConfig().finalizeSqlMapConfig());
142 }
143
144
145
146
147 private void addGlobalPropNodelets() {
148 parser.addNodelet("/sqlMapConfig/properties", node -> {
149 Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
150 String resource = attributes.getProperty("resource");
151 String url = attributes.getProperty("url");
152 state.setGlobalProperties(resource, url);
153 });
154 }
155
156
157
158
159 private void addSettingsNodelets() {
160 parser.addNodelet("/sqlMapConfig/settings", node -> {
161 Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
162 SqlMapConfiguration config = state.getConfig();
163
164 String classInfoCacheEnabledAttr = attributes.getProperty("classInfoCacheEnabled");
165 boolean classInfoCacheEnabled = classInfoCacheEnabledAttr == null || "true".equals(classInfoCacheEnabledAttr);
166 config.setClassInfoCacheEnabled(classInfoCacheEnabled);
167
168 String lazyLoadingEnabledAttr = attributes.getProperty("lazyLoadingEnabled");
169 boolean lazyLoadingEnabled = lazyLoadingEnabledAttr == null || "true".equals(lazyLoadingEnabledAttr);
170 config.setLazyLoadingEnabled(lazyLoadingEnabled);
171
172 String statementCachingEnabledAttr = attributes.getProperty("statementCachingEnabled");
173 boolean statementCachingEnabled = statementCachingEnabledAttr == null
174 || "true".equals(statementCachingEnabledAttr);
175 config.setStatementCachingEnabled(statementCachingEnabled);
176
177 String cacheModelsEnabledAttr = attributes.getProperty("cacheModelsEnabled");
178 boolean cacheModelsEnabled = cacheModelsEnabledAttr == null || "true".equals(cacheModelsEnabledAttr);
179 config.setCacheModelsEnabled(cacheModelsEnabled);
180
181 String enhancementEnabledAttr = attributes.getProperty("enhancementEnabled");
182 boolean enhancementEnabled = enhancementEnabledAttr == null || "true".equals(enhancementEnabledAttr);
183 config.setEnhancementEnabled(enhancementEnabled);
184
185 String useColumnLabelAttr = attributes.getProperty("useColumnLabel");
186 boolean useColumnLabel = useColumnLabelAttr == null || "true".equals(useColumnLabelAttr);
187 config.setUseColumnLabel(useColumnLabel);
188
189 String forceMultipleResultSetSupportAttr = attributes.getProperty("forceMultipleResultSetSupport");
190 boolean forceMultipleResultSetSupport = "true".equals(forceMultipleResultSetSupportAttr);
191 config.setForceMultipleResultSetSupport(forceMultipleResultSetSupport);
192
193 String defaultTimeoutAttr = attributes.getProperty("defaultStatementTimeout");
194 Integer defaultTimeout = defaultTimeoutAttr == null ? null : Integer.valueOf(defaultTimeoutAttr);
195 config.setDefaultStatementTimeout(defaultTimeout);
196
197 String useStatementNamespacesAttr = attributes.getProperty("useStatementNamespaces");
198 boolean useStatementNamespaces = "true".equals(useStatementNamespacesAttr);
199 state.setUseStatementNamespaces(useStatementNamespaces);
200 });
201 }
202
203
204
205
206 private void addTypeAliasNodelets() {
207 parser.addNodelet("/sqlMapConfig/typeAlias", node -> {
208 Properties prop = NodeletUtils.parseAttributes(node, state.getGlobalProps());
209 String alias = prop.getProperty("alias");
210 String type = prop.getProperty("type");
211 state.getConfig().getTypeHandlerFactory().putTypeAlias(alias, type);
212 });
213 }
214
215
216
217
218 private void addTypeHandlerNodelets() {
219 parser.addNodelet("/sqlMapConfig/typeHandler", node -> {
220 Properties prop = NodeletUtils.parseAttributes(node, state.getGlobalProps());
221 String jdbcType = prop.getProperty("jdbcType");
222 String javaType = prop.getProperty("javaType");
223 String callback = prop.getProperty("callback");
224
225 javaType = state.getConfig().getTypeHandlerFactory().resolveAlias(javaType);
226 callback = state.getConfig().getTypeHandlerFactory().resolveAlias(callback);
227
228 state.getConfig().newTypeHandler(Resources.classForName(javaType), jdbcType, Resources.instantiate(callback));
229 });
230 }
231
232
233
234
235 private void addTransactionManagerNodelets() {
236 parser.addNodelet("/sqlMapConfig/transactionManager/property", node -> {
237 Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
238 String name = attributes.getProperty("name");
239 String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), state.getGlobalProps());
240 state.getTxProps().setProperty(name, value);
241 });
242 parser.addNodelet("/sqlMapConfig/transactionManager/end()", node -> {
243 Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
244 String type = attributes.getProperty("type");
245 boolean commitRequired = "true".equals(attributes.getProperty("commitRequired"));
246
247 state.getConfig().getErrorContext().setActivity("configuring the transaction manager");
248 type = state.getConfig().getTypeHandlerFactory().resolveAlias(type);
249 TransactionManager txManager;
250 try {
251 state.getConfig().getErrorContext().setMoreInfo("Check the transaction manager type or class.");
252 TransactionConfig config = (TransactionConfig) Resources.instantiate(type);
253 config.setDataSource(state.getDataSource());
254 state.getConfig().getErrorContext().setMoreInfo("Check the transaction manager properties or configuration.");
255 config.setProperties(state.getTxProps());
256 config.setForceCommit(commitRequired);
257 config.setDataSource(state.getDataSource());
258 state.getConfig().getErrorContext().setMoreInfo(null);
259 txManager = new TransactionManager(config);
260 } catch (Exception e) {
261 if (e instanceof SqlMapException) {
262 throw (SqlMapException) e;
263 }
264 throw new SqlMapException(
265 "Error initializing TransactionManager. Could not instantiate TransactionConfig. Cause: " + e, e);
266 }
267 state.getConfig().setTransactionManager(txManager);
268 });
269 parser.addNodelet("/sqlMapConfig/transactionManager/dataSource/property", node -> {
270 Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
271 String name = attributes.getProperty("name");
272 String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), state.getGlobalProps());
273 state.getDsProps().setProperty(name, value);
274 });
275 parser.addNodelet("/sqlMapConfig/transactionManager/dataSource/end()", node -> {
276 state.getConfig().getErrorContext().setActivity("configuring the data source");
277
278 Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
279
280 String type = attributes.getProperty("type");
281 Properties props = state.getDsProps();
282
283 type = state.getConfig().getTypeHandlerFactory().resolveAlias(type);
284 try {
285 state.getConfig().getErrorContext().setMoreInfo("Check the data source type or class.");
286 DataSourceFactory dsFactory = (DataSourceFactory) Resources.instantiate(type);
287 state.getConfig().getErrorContext().setMoreInfo("Check the data source properties or configuration.");
288 dsFactory.initialize(props);
289 state.setDataSource(dsFactory.getDataSource());
290 state.getConfig().getErrorContext().setMoreInfo(null);
291 } catch (Exception e) {
292 if (e instanceof SqlMapException) {
293 throw (SqlMapException) e;
294 }
295 throw new SqlMapException(
296 "Error initializing DataSource. Could not instantiate DataSourceFactory. Cause: " + e, e);
297 }
298 });
299 }
300
301
302
303
304 protected void addSqlMapNodelets() {
305 parser.addNodelet("/sqlMapConfig/sqlMap", node -> {
306 state.getConfig().getErrorContext().setActivity("loading the SQL Map resource");
307
308 Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
309
310 String resource = attributes.getProperty("resource");
311 String url = attributes.getProperty("url");
312
313 if (usingStreams) {
314 InputStream inputStream = null;
315 if (resource != null) {
316 state.getConfig().getErrorContext().setResource(resource);
317 inputStream = Resources.getResourceAsStream(resource);
318 } else if (url != null) {
319 state.getConfig().getErrorContext().setResource(url);
320 inputStream = Resources.getUrlAsStream(url);
321 } else {
322 throw new SqlMapException("The <sqlMap> element requires either a resource or a url attribute.");
323 }
324
325 new SqlMapParser(state).parse(inputStream);
326 } else {
327 Reader reader = null;
328 if (resource != null) {
329 state.getConfig().getErrorContext().setResource(resource);
330 reader = Resources.getResourceAsReader(resource);
331 } else if (url != null) {
332 state.getConfig().getErrorContext().setResource(url);
333 reader = Resources.getUrlAsReader(url);
334 } else {
335 throw new SqlMapException("The <sqlMap> element requires either a resource or a url attribute.");
336 }
337
338 new SqlMapParser(state).parse(reader);
339 }
340 });
341 }
342
343
344
345
346 private void addResultObjectFactoryNodelets() {
347 parser.addNodelet("/sqlMapConfig/resultObjectFactory", node -> {
348 Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
349 String type = attributes.getProperty("type");
350
351 state.getConfig().getErrorContext().setActivity("configuring the Result Object Factory");
352 ResultObjectFactory rof;
353 try {
354 rof = (ResultObjectFactory) Resources.instantiate(type);
355 state.getConfig().setResultObjectFactory(rof);
356 } catch (Exception e) {
357 throw new SqlMapException("Error instantiating resultObjectFactory: " + type, e);
358 }
359
360 });
361 parser.addNodelet("/sqlMapConfig/resultObjectFactory/property", node -> {
362 Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
363 String name = attributes.getProperty("name");
364 String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), state.getGlobalProps());
365 state.getConfig().getDelegate().getResultObjectFactory().setProperty(name, value);
366 });
367 }
368
369 }