1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.builder.xml;
17
18 import java.util.List;
19 import java.util.Locale;
20
21 import org.apache.ibatis.builder.BaseBuilder;
22 import org.apache.ibatis.builder.MapperBuilderAssistant;
23 import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
24 import org.apache.ibatis.executor.keygen.KeyGenerator;
25 import org.apache.ibatis.executor.keygen.NoKeyGenerator;
26 import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
27 import org.apache.ibatis.mapping.MappedStatement;
28 import org.apache.ibatis.mapping.ResultSetType;
29 import org.apache.ibatis.mapping.SqlCommandType;
30 import org.apache.ibatis.mapping.SqlSource;
31 import org.apache.ibatis.mapping.StatementType;
32 import org.apache.ibatis.parsing.XNode;
33 import org.apache.ibatis.scripting.LanguageDriver;
34 import org.apache.ibatis.session.Configuration;
35
36
37
38
39 public class XMLStatementBuilder extends BaseBuilder {
40
41 private MapperBuilderAssistant builderAssistant;
42 private XNode context;
43 private String requiredDatabaseId;
44
45 public XMLStatementBuilder(Configuration configuration, MapperBuilderAssistant builderAssistant, XNode context) {
46 this(configuration, builderAssistant, context, null);
47 }
48
49 public XMLStatementBuilder(Configuration configuration, MapperBuilderAssistant builderAssistant, XNode context, String databaseId) {
50 super(configuration);
51 this.builderAssistant = builderAssistant;
52 this.context = context;
53 this.requiredDatabaseId = databaseId;
54 }
55
56 public void parseStatementNode() {
57 String id = context.getStringAttribute("id");
58 String databaseId = context.getStringAttribute("databaseId");
59
60 if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
61 return;
62 }
63
64 Integer fetchSize = context.getIntAttribute("fetchSize");
65 Integer timeout = context.getIntAttribute("timeout");
66 String parameterMap = context.getStringAttribute("parameterMap");
67 String parameterType = context.getStringAttribute("parameterType");
68 Class<?> parameterTypeClass = resolveClass(parameterType);
69 String resultMap = context.getStringAttribute("resultMap");
70 String resultType = context.getStringAttribute("resultType");
71 String lang = context.getStringAttribute("lang");
72 LanguageDriver langDriver = getLanguageDriver(lang);
73
74 Class<?> resultTypeClass = resolveClass(resultType);
75 String resultSetType = context.getStringAttribute("resultSetType");
76 StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
77 ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
78
79 String nodeName = context.getNode().getNodeName();
80 SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
81 boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
82 boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
83 boolean useCache = context.getBooleanAttribute("useCache", isSelect);
84 boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);
85
86
87 XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
88 includeParser.applyIncludes(context.getNode());
89
90
91 processSelectKeyNodes(id, parameterTypeClass, langDriver);
92
93
94 SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
95 String resultSets = context.getStringAttribute("resultSets");
96 String keyProperty = context.getStringAttribute("keyProperty");
97 String keyColumn = context.getStringAttribute("keyColumn");
98 KeyGenerator keyGenerator;
99 String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
100 keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
101 if (configuration.hasKeyGenerator(keyStatementId)) {
102 keyGenerator = configuration.getKeyGenerator(keyStatementId);
103 } else {
104 keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
105 configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
106 ? new Jdbc3KeyGenerator() : new NoKeyGenerator();
107 }
108
109 builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
110 fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
111 resultSetTypeEnum, flushCache, useCache, resultOrdered,
112 keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
113 }
114
115 private void processSelectKeyNodes(String id, Class<?> parameterTypeClass, LanguageDriver langDriver) {
116 List<XNode> selectKeyNodes = context.evalNodes("selectKey");
117 if (configuration.getDatabaseId() != null) {
118 parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, configuration.getDatabaseId());
119 }
120 parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, null);
121 removeSelectKeyNodes(selectKeyNodes);
122 }
123
124 private void parseSelectKeyNodes(String parentId, List<XNode> list, Class<?> parameterTypeClass, LanguageDriver langDriver, String skRequiredDatabaseId) {
125 for (XNode nodeToHandle : list) {
126 String id = parentId + SelectKeyGenerator.SELECT_KEY_SUFFIX;
127 String databaseId = nodeToHandle.getStringAttribute("databaseId");
128 if (databaseIdMatchesCurrent(id, databaseId, skRequiredDatabaseId)) {
129 parseSelectKeyNode(id, nodeToHandle, parameterTypeClass, langDriver, databaseId);
130 }
131 }
132 }
133
134 private void parseSelectKeyNode(String id, XNode nodeToHandle, Class<?> parameterTypeClass, LanguageDriver langDriver, String databaseId) {
135 String resultType = nodeToHandle.getStringAttribute("resultType");
136 Class<?> resultTypeClass = resolveClass(resultType);
137 StatementType statementType = StatementType.valueOf(nodeToHandle.getStringAttribute("statementType", StatementType.PREPARED.toString()));
138 String keyProperty = nodeToHandle.getStringAttribute("keyProperty");
139 String keyColumn = nodeToHandle.getStringAttribute("keyColumn");
140 boolean executeBefore = "BEFORE".equals(nodeToHandle.getStringAttribute("order", "AFTER"));
141
142
143 boolean useCache = false;
144 boolean resultOrdered = false;
145 KeyGenerator keyGenerator = new NoKeyGenerator();
146 Integer fetchSize = null;
147 Integer timeout = null;
148 boolean flushCache = false;
149 String parameterMap = null;
150 String resultMap = null;
151 ResultSetType resultSetTypeEnum = null;
152
153 SqlSource sqlSource = langDriver.createSqlSource(configuration, nodeToHandle, parameterTypeClass);
154 SqlCommandType sqlCommandType = SqlCommandType.SELECT;
155
156 builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
157 fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
158 resultSetTypeEnum, flushCache, useCache, resultOrdered,
159 keyGenerator, keyProperty, keyColumn, databaseId, langDriver, null);
160
161 id = builderAssistant.applyCurrentNamespace(id, false);
162
163 MappedStatement keyStatement = configuration.getMappedStatement(id, false);
164 configuration.addKeyGenerator(id, new SelectKeyGenerator(keyStatement, executeBefore));
165 }
166
167 private void removeSelectKeyNodes(List<XNode> selectKeyNodes) {
168 for (XNode nodeToHandle : selectKeyNodes) {
169 nodeToHandle.getParent().getNode().removeChild(nodeToHandle.getNode());
170 }
171 }
172
173 private boolean databaseIdMatchesCurrent(String id, String databaseId, String requiredDatabaseId) {
174 if (requiredDatabaseId != null) {
175 if (!requiredDatabaseId.equals(databaseId)) {
176 return false;
177 }
178 } else {
179 if (databaseId != null) {
180 return false;
181 }
182
183 id = builderAssistant.applyCurrentNamespace(id, false);
184 if (this.configuration.hasStatement(id, false)) {
185 MappedStatement previous = this.configuration.getMappedStatement(id, false);
186 if (previous.getDatabaseId() != null) {
187 return false;
188 }
189 }
190 }
191 return true;
192 }
193
194 private LanguageDriver getLanguageDriver(String lang) {
195 Class<?> langClass = null;
196 if (lang != null) {
197 langClass = resolveClass(lang);
198 }
199 return builderAssistant.getLanguageDriver(langClass);
200 }
201
202 }