1 package com.ibatis.sqlmap.engine.builder.xml; 2 3 import java.sql.ResultSet ; 4 import java.util.Arrays ; 5 import java.util.List ; 6 import java.util.Properties ; 7 8 import org.w3c.dom.CharacterData ; 9 import org.w3c.dom.Node ; 10 import org.w3c.dom.NodeList ; 11 12 import com.ibatis.common.beans.Probe; 13 import com.ibatis.common.beans.ProbeFactory; 14 import com.ibatis.common.exception.NestedRuntimeException; 15 import com.ibatis.common.resources.Resources; 16 import com.ibatis.common.xml.NodeletUtils; 17 import com.ibatis.sqlmap.client.SqlMapException; 18 import com.ibatis.sqlmap.engine.cache.CacheModel; 19 import com.ibatis.sqlmap.engine.mapping.parameter.BasicParameterMap; 20 import com.ibatis.sqlmap.engine.mapping.parameter.InlineParameterMapParser; 21 import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap; 22 import com.ibatis.sqlmap.engine.mapping.result.AutoResultMap; 23 import com.ibatis.sqlmap.engine.mapping.result.BasicResultMap; 24 import com.ibatis.sqlmap.engine.mapping.sql.Sql; 25 import com.ibatis.sqlmap.engine.mapping.sql.SqlText; 26 import com.ibatis.sqlmap.engine.mapping.sql.dynamic.DynamicSql; 27 import com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.DynamicParent; 28 import com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.DynamicTagHandler; 29 import com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.IterateTagHandler; 30 import com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.SqlTag; 31 import com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.SqlTagHandler; 32 import com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.SqlTagHandlerFactory; 33 import com.ibatis.sqlmap.engine.mapping.sql.simple.SimpleDynamicSql; 34 import com.ibatis.sqlmap.engine.mapping.sql.stat.StaticSql; 35 import com.ibatis.sqlmap.engine.mapping.statement.CachingStatement; 36 import com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement; 37 import com.ibatis.sqlmap.engine.mapping.statement.InsertStatement; 38 import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement; 39 import com.ibatis.sqlmap.engine.mapping.statement.SelectKeyStatement; 40 41 public class SqlStatementParser extends BaseParser { 42 43 private static final Probe PROBE = ProbeFactory.getProbe(); 44 45 private static final InlineParameterMapParser PARAM_PARSER = new InlineParameterMapParser(); 46 47 public SqlStatementParser(Variables vars) { 48 super(vars); 49 } 50 51 public MappedStatement parseGeneralStatement(Node node, GeneralStatement statement) { 52 vars.errorCtx.setActivity("parsing a mapped statement"); 53 54 Properties attributes = NodeletUtils.parseAttributes(node, vars.currentProperties); 56 String id = attributes.getProperty("id"); 57 58 if (vars.useStatementNamespaces) { 59 id = applyNamespace(id); 60 } 61 62 String parameterMapName = applyNamespace(attributes.getProperty("parameterMap")); 63 String parameterClassName = attributes.getProperty("parameterClass"); 64 String resultMapName = applyNamespace(attributes.getProperty("resultMap")); 65 String resultClassName = attributes.getProperty("resultClass"); 66 String cacheModelName = applyNamespace(attributes.getProperty("cacheModel")); 67 String xmlResultName = attributes.getProperty("xmlResultName"); 68 String resultSetType = attributes.getProperty("resultSetType"); 69 String fetchSize = attributes.getProperty("fetchSize"); 70 String allowRemapping = attributes.getProperty("remapResults"); 71 72 vars.errorCtx.setObjectId(id + " statement"); 73 74 parameterClassName = vars.typeHandlerFactory.resolveAlias(parameterClassName); 75 resultClassName = vars.typeHandlerFactory.resolveAlias(resultClassName); 76 77 Class parameterClass = null; 78 Class resultClass = null; 79 80 82 vars.errorCtx.setMoreInfo("Check the result map name."); 83 BasicResultMap resultMap = null; 84 if (resultMapName != null) { 85 resultMap = (BasicResultMap) vars.client.getDelegate().getResultMap(resultMapName); 86 } 87 88 vars.errorCtx.setMoreInfo("Check the parameter map name."); 89 BasicParameterMap parameterMap = null; 90 if (parameterMapName != null) { 91 parameterMap = (BasicParameterMap) vars.client.getDelegate().getParameterMap(parameterMapName); 92 } 93 94 statement.setId(id); 95 statement.setParameterMap(parameterMap); 96 statement.setResultMap(resultMap); 97 statement.setResource(vars.errorCtx.getResource()); 98 99 if (resultSetType != null) { 100 if ("FORWARD_ONLY".equals(resultSetType)) { 101 statement.setResultSetType(new Integer (ResultSet.TYPE_FORWARD_ONLY)); 102 } else if ("SCROLL_INSENSITIVE".equals(resultSetType)) { 103 statement.setResultSetType(new Integer (ResultSet.TYPE_SCROLL_INSENSITIVE)); 104 } else if ("SCROLL_SENSITIVE".equals(resultSetType)) { 105 statement.setResultSetType(new Integer (ResultSet.TYPE_SCROLL_SENSITIVE)); 106 } 107 } 108 109 if (fetchSize != null) { 110 statement.setFetchSize(new Integer (fetchSize)); 111 } 112 113 if (parameterMap == null) { 115 try { 116 if (parameterClassName != null) { 117 vars.errorCtx.setMoreInfo("Check the parameter class."); 118 parameterClass = Resources.classForName(parameterClassName); 119 statement.setParameterClass(parameterClass); 120 } 121 } catch (ClassNotFoundException e) { 122 throw new SqlMapException("Error. Could not set parameter class. Cause: " + e, e); 123 } 124 } else { 125 statement.setParameterClass(parameterMap.getParameterClass()); 126 } 127 128 try { 129 if (resultClassName != null) { 130 vars.errorCtx.setMoreInfo("Check the result class."); 131 resultClass = Resources.classForName(resultClassName); 132 } 133 } catch (ClassNotFoundException e) { 134 throw new SqlMapException("Error. Could not set result class. Cause: " + e, e); 135 } 136 137 vars.errorCtx.setMoreInfo("Check the SQL statement."); 139 processSqlStatement(node, statement); 140 141 if (resultMap == null && resultClass == null) { 143 statement.setResultMap(null); 144 } else if (resultMap == null) { 145 resultMap = new AutoResultMap(vars.client.getDelegate(), "true".equals(allowRemapping)); 146 resultMap.setId(statement.getId() + "-AutoResultMap"); 147 resultMap.setResultClass(resultClass); 148 resultMap.setXmlName(xmlResultName); 149 resultMap.setResource(statement.getResource()); 150 statement.setResultMap(resultMap); 151 152 } 153 154 vars.errorCtx.setMoreInfo(null); 155 vars.errorCtx.setObjectId(null); 156 157 statement.setSqlMapClient(vars.client); 158 if (cacheModelName != null && cacheModelName.length() > 0 && vars.client.getDelegate().isCacheModelsEnabled()) { 159 CacheModel cacheModel = vars.client.getDelegate().getCacheModel(cacheModelName); 160 return new CachingStatement(statement, cacheModel); 161 } else { 162 return statement; 163 } 164 165 } 166 167 private void processSqlStatement(Node n, GeneralStatement statement) { 168 vars.errorCtx.setActivity("processing an SQL statement"); 169 170 boolean isDynamic = false; 171 DynamicSql dynamic = new DynamicSql(vars.client.getDelegate()); 172 StringBuffer sqlBuffer = new StringBuffer (); 173 174 isDynamic = parseDynamicTags(n, dynamic, sqlBuffer, isDynamic, false); 175 if (statement instanceof InsertStatement) { 176 InsertStatement insertStatement = ((InsertStatement) statement); 177 SelectKeyStatement selectKeyStatement = findAndParseSelectKeyStatement(n, statement); 178 insertStatement.setSelectKeyStatement(selectKeyStatement); 179 } 180 181 String sqlStatement = sqlBuffer.toString(); 182 if (isDynamic) { 183 statement.setSql(dynamic); 184 } else { 185 applyInlineParameterMap(statement, sqlStatement); 186 } 187 188 } 189 190 private boolean parseDynamicTags(Node node, DynamicParent dynamic, StringBuffer sqlBuffer, boolean isDynamic, boolean postParseRequired) { 191 vars.errorCtx.setActivity("parsing dynamic SQL tags"); 192 193 NodeList children = node.getChildNodes(); 194 for (int i = 0; i < children.getLength(); i++) { 195 Node child = children.item(i); 196 String nodeName = child.getNodeName(); 197 if (child.getNodeType() == Node.CDATA_SECTION_NODE 198 || child.getNodeType() == Node.TEXT_NODE) { 199 200 String data = ((CharacterData ) child).getData(); 201 data = NodeletUtils.parsePropertyTokens(data, vars.properties); 202 203 SqlText sqlText; 204 205 if (postParseRequired) { 206 sqlText = new SqlText(); 207 sqlText.setPostParseRequired(postParseRequired); 208 sqlText.setText(data.toString()); 209 } else { 210 sqlText = PARAM_PARSER.parseInlineParameterMap(vars.client.getDelegate().getTypeHandlerFactory(), data.toString(), null); 211 sqlText.setPostParseRequired(postParseRequired); 212 } 213 214 dynamic.addChild(sqlText); 215 216 sqlBuffer.append(data); 217 } else if ("include".equals(nodeName)) { 218 Properties attributes = NodeletUtils.parseAttributes(child, vars.properties); 219 String refid = (String ) attributes.get("refid"); 220 Node includeNode = (Node ) vars.sqlIncludes.get(refid); 221 if (includeNode == null) { 222 String nsrefid = applyNamespace(refid); 223 includeNode = (Node ) vars.sqlIncludes.get(nsrefid); 224 if (includeNode == null) { 225 throw new NestedRuntimeException("Could not find SQL statement to include with refid '" + refid + "'"); 226 } 227 } 228 isDynamic = parseDynamicTags(includeNode, dynamic, sqlBuffer, isDynamic, false); 229 } else { 230 vars.errorCtx.setMoreInfo("Check the dynamic tags."); 231 232 SqlTagHandler handler = SqlTagHandlerFactory.getSqlTagHandler(nodeName); 233 if (handler != null) { 234 isDynamic = true; 235 236 SqlTag tag = new SqlTag(); 237 tag.setName(nodeName); 238 tag.setHandler(handler); 239 240 Properties attributes = NodeletUtils.parseAttributes(child, vars.properties); 241 242 tag.setPrependAttr(attributes.getProperty("prepend")); 243 tag.setPropertyAttr(attributes.getProperty("property")); 244 tag.setRemoveFirstPrepend(attributes.getProperty("removeFirstPrepend")); 245 246 tag.setOpenAttr(attributes.getProperty("open")); 247 tag.setCloseAttr(attributes.getProperty("close")); 248 249 tag.setComparePropertyAttr(attributes.getProperty("compareProperty")); 250 tag.setCompareValueAttr(attributes.getProperty("compareValue")); 251 tag.setConjunctionAttr(attributes.getProperty("conjunction")); 252 253 255 if(dynamic instanceof SqlTag) { 256 SqlTag parentSqlTag = (SqlTag)dynamic; 257 if(parentSqlTag.isPostParseRequired() || 258 tag.getHandler() instanceof IterateTagHandler) { 259 tag.setPostParseRequired(true); 260 } 261 } else if (dynamic instanceof DynamicSql) { 262 if(tag.getHandler() instanceof IterateTagHandler) { 263 tag.setPostParseRequired(true); 264 } 265 } 266 267 dynamic.addChild(tag); 268 269 if (child.hasChildNodes()) { 270 isDynamic = parseDynamicTags(child, tag, sqlBuffer, isDynamic, tag.isPostParseRequired()); 271 } 272 } 273 } 274 } 275 vars.errorCtx.setMoreInfo(null); 276 return isDynamic; 277 } 278 279 private SelectKeyStatement findAndParseSelectKeyStatement(Node n, GeneralStatement insertStatement) { 280 vars.errorCtx.setActivity("parsing select key tags"); 281 282 SelectKeyStatement selectKeyStatement = null; 283 284 boolean foundTextFirst = false; 285 286 NodeList children = n.getChildNodes(); 287 for (int i = 0; i < children.getLength(); i++) { 288 Node child = children.item(i); 289 if (child.getNodeType() == Node.CDATA_SECTION_NODE 290 || child.getNodeType() == Node.TEXT_NODE) { 291 String data = ((CharacterData ) child).getData(); 292 if (data.trim().length() > 0) { 293 foundTextFirst = true; 294 } 295 } else if (child.getNodeType() == Node.ELEMENT_NODE 296 && "selectKey".equals(child.getNodeName())) { 297 selectKeyStatement = parseSelectKey(child, insertStatement); 298 break; 299 } 300 } 301 if (selectKeyStatement != null) { 302 selectKeyStatement.setAfter(foundTextFirst); 303 } 304 vars.errorCtx.setMoreInfo(null); 305 return selectKeyStatement; 306 } 307 308 private SelectKeyStatement parseSelectKey(Node node, GeneralStatement insertStatement) { 309 vars.errorCtx.setActivity("parsing a select key"); 310 311 Properties attributes = NodeletUtils.parseAttributes(node, vars.properties); 313 String keyPropName = attributes.getProperty("keyProperty"); 314 String resultClassName = attributes.getProperty("resultClass"); 315 resultClassName = vars.typeHandlerFactory.resolveAlias(resultClassName); 316 Class resultClass = null; 317 318 SelectKeyStatement selectKeyStatement = new SelectKeyStatement(); 320 selectKeyStatement.setSqlMapClient(vars.client); 321 322 selectKeyStatement.setId(insertStatement.getId() + "-SelectKey"); 323 selectKeyStatement.setResource(vars.errorCtx.getResource()); 324 selectKeyStatement.setKeyProperty(keyPropName); 325 326 try { 327 if (resultClassName != null) { 328 vars.errorCtx.setMoreInfo("Check the select key result class."); 329 resultClass = Resources.classForName(resultClassName); 330 } else { 331 Class parameterClass = insertStatement.getParameterClass(); 332 if (keyPropName != null && parameterClass != null) { 333 resultClass = PROBE.getPropertyTypeForSetter(parameterClass, selectKeyStatement.getKeyProperty()); 334 } 335 } 336 } catch (ClassNotFoundException e) { 337 throw new SqlMapException("Error. Could not set result class. Cause: " + e, e); 338 } 339 340 if (resultClass == null) { 341 resultClass = Object .class; 342 } 343 344 vars.errorCtx.setMoreInfo("Check the select key SQL statement."); 346 processSqlStatement(node, selectKeyStatement); 347 348 BasicResultMap resultMap; 349 resultMap = new AutoResultMap(vars.client.getDelegate(), false); 350 resultMap.setId(selectKeyStatement.getId() + "-AutoResultMap"); 351 resultMap.setResultClass(resultClass); 352 resultMap.setResource(selectKeyStatement.getResource()); 353 selectKeyStatement.setResultMap(resultMap); 354 355 vars.errorCtx.setMoreInfo(null); 356 return selectKeyStatement; 357 } 358 359 private void applyInlineParameterMap(GeneralStatement statement, String sqlStatement) { 360 String newSql = sqlStatement; 361 362 vars.errorCtx.setActivity("building an inline parameter map"); 363 364 ParameterMap parameterMap = statement.getParameterMap(); 365 366 vars.errorCtx.setMoreInfo("Check the inline parameters."); 367 if (parameterMap == null) { 368 369 BasicParameterMap map; 370 map = new BasicParameterMap(vars.client.getDelegate()); 371 372 map.setId(statement.getId() + "-InlineParameterMap"); 373 map.setParameterClass(statement.getParameterClass()); 374 map.setResource(statement.getResource()); 375 statement.setParameterMap(map); 376 377 SqlText sqlText = PARAM_PARSER.parseInlineParameterMap(vars.client.getDelegate().getTypeHandlerFactory(), newSql, statement.getParameterClass()); 378 newSql = sqlText.getText(); 379 List mappingList = Arrays.asList(sqlText.getParameterMappings()); 380 381 map.setParameterMappingList(mappingList); 382 383 } 384 385 Sql sql = null; 386 if (SimpleDynamicSql.isSimpleDynamicSql(newSql)) { 387 sql = new SimpleDynamicSql(vars.client.getDelegate(), newSql); 388 } else { 389 sql = new StaticSql(newSql); 390 } 391 statement.setSql(sql); 392 393 } 394 395 } 396 | Popular Tags |