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 final MapperBuilderAssistant builderAssistant;
42 private final XNode context;
43 private final 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 String nodeName = context.getNode().getNodeName();
65 SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
66 boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
67 boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
68 boolean useCache = context.getBooleanAttribute("useCache", isSelect);
69 boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);
70
71
72 XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
73 includeParser.applyIncludes(context.getNode());
74
75 String parameterType = context.getStringAttribute("parameterType");
76 Class<?> parameterTypeClass = resolveClass(parameterType);
77
78 String lang = context.getStringAttribute("lang");
79 LanguageDriver langDriver = getLanguageDriver(lang);
80
81
82 processSelectKeyNodes(id, parameterTypeClass, langDriver);
83
84
85 KeyGenerator keyGenerator;
86 String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
87 keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
88 if (configuration.hasKeyGenerator(keyStatementId)) {
89 keyGenerator = configuration.getKeyGenerator(keyStatementId);
90 } else {
91 keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
92 configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
93 ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
94 }
95
96 SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
97 StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
98 Integer fetchSize = context.getIntAttribute("fetchSize");
99 Integer timeout = context.getIntAttribute("timeout");
100 String parameterMap = context.getStringAttribute("parameterMap");
101 String resultType = context.getStringAttribute("resultType");
102 Class<?> resultTypeClass = resolveClass(resultType);
103 String resultMap = context.getStringAttribute("resultMap");
104 String resultSetType = context.getStringAttribute("resultSetType");
105 ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
106 if (resultSetTypeEnum == null) {
107 resultSetTypeEnum = configuration.getDefaultResultSetType();
108 }
109 String keyProperty = context.getStringAttribute("keyProperty");
110 String keyColumn = context.getStringAttribute("keyColumn");
111 String resultSets = context.getStringAttribute("resultSets");
112
113 builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
114 fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
115 resultSetTypeEnum, flushCache, useCache, resultOrdered,
116 keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
117 }
118
119 private void processSelectKeyNodes(String id, Class<?> parameterTypeClass, LanguageDriver langDriver) {
120 List<XNode> selectKeyNodes = context.evalNodes("selectKey");
121 if (configuration.getDatabaseId() != null) {
122 parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, configuration.getDatabaseId());
123 }
124 parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, null);
125 removeSelectKeyNodes(selectKeyNodes);
126 }
127
128 private void parseSelectKeyNodes(String parentId, List<XNode> list, Class<?> parameterTypeClass, LanguageDriver langDriver, String skRequiredDatabaseId) {
129 for (XNode nodeToHandle : list) {
130 String id = parentId + SelectKeyGenerator.SELECT_KEY_SUFFIX;
131 String databaseId = nodeToHandle.getStringAttribute("databaseId");
132 if (databaseIdMatchesCurrent(id, databaseId, skRequiredDatabaseId)) {
133 parseSelectKeyNode(id, nodeToHandle, parameterTypeClass, langDriver, databaseId);
134 }
135 }
136 }
137
138 private void parseSelectKeyNode(String id, XNode nodeToHandle, Class<?> parameterTypeClass, LanguageDriver langDriver, String databaseId) {
139 String resultType = nodeToHandle.getStringAttribute("resultType");
140 Class<?> resultTypeClass = resolveClass(resultType);
141 StatementType statementType = StatementType.valueOf(nodeToHandle.getStringAttribute("statementType", StatementType.PREPARED.toString()));
142 String keyProperty = nodeToHandle.getStringAttribute("keyProperty");
143 String keyColumn = nodeToHandle.getStringAttribute("keyColumn");
144 boolean executeBefore = "BEFORE".equals(nodeToHandle.getStringAttribute("order", "AFTER"));
145
146
147 boolean useCache = false;
148 boolean resultOrdered = false;
149 KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;
150 Integer fetchSize = null;
151 Integer timeout = null;
152 boolean flushCache = false;
153 String parameterMap = null;
154 String resultMap = null;
155 ResultSetType resultSetTypeEnum = null;
156
157 SqlSource sqlSource = langDriver.createSqlSource(configuration, nodeToHandle, parameterTypeClass);
158 SqlCommandType sqlCommandType = SqlCommandType.SELECT;
159
160 builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
161 fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
162 resultSetTypeEnum, flushCache, useCache, resultOrdered,
163 keyGenerator, keyProperty, keyColumn, databaseId, langDriver, null);
164
165 id = builderAssistant.applyCurrentNamespace(id, false);
166
167 MappedStatement keyStatement = configuration.getMappedStatement(id, false);
168 configuration.addKeyGenerator(id, new SelectKeyGenerator(keyStatement, executeBefore));
169 }
170
171 private void removeSelectKeyNodes(List<XNode> selectKeyNodes) {
172 for (XNode nodeToHandle : selectKeyNodes) {
173 nodeToHandle.getParent().getNode().removeChild(nodeToHandle.getNode());
174 }
175 }
176
177 private boolean databaseIdMatchesCurrent(String id, String databaseId, String requiredDatabaseId) {
178 if (requiredDatabaseId != null) {
179 return requiredDatabaseId.equals(databaseId);
180 }
181 if (databaseId != null) {
182 return false;
183 }
184 id = builderAssistant.applyCurrentNamespace(id, false);
185 if (!this.configuration.hasStatement(id, false)) {
186 return true;
187 }
188
189 MappedStatement previous = this.configuration.getMappedStatement(id, false);
190 return previous.getDatabaseId() == null;
191 }
192
193 private LanguageDriver getLanguageDriver(String lang) {
194 Class<? extends LanguageDriver> langClass = null;
195 if (lang != null) {
196 langClass = resolveClass(lang);
197 }
198 return configuration.getLanguageDriver(langClass);
199 }
200
201 }