View Javadoc
1   /*
2    * Copyright 2004-2023 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.ibatis.sqlmap.engine.builder.xml;
17  
18  import com.ibatis.common.resources.Resources;
19  import com.ibatis.common.xml.NodeletUtils;
20  import com.ibatis.sqlmap.client.SqlMapException;
21  import com.ibatis.sqlmap.engine.config.MappedStatementConfig;
22  import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement;
23  
24  import java.util.Properties;
25  
26  import org.w3c.dom.CharacterData;
27  import org.w3c.dom.Node;
28  import org.w3c.dom.NodeList;
29  
30  /**
31   * The Class SqlStatementParser.
32   */
33  public class SqlStatementParser {
34  
35    /** The state. */
36    private XmlParserState state;
37  
38    /**
39     * Instantiates a new sql statement parser.
40     *
41     * @param config
42     *          the config
43     */
44    public SqlStatementParser(XmlParserState config) {
45      this.state = config;
46    }
47  
48    /**
49     * Parses the general statement.
50     *
51     * @param node
52     *          the node
53     * @param statement
54     *          the statement
55     */
56    public void parseGeneralStatement(Node node, MappedStatement statement) {
57  
58      // get attributes
59      Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
60      String id = attributes.getProperty("id");
61      String parameterMapName = state.applyNamespace(attributes.getProperty("parameterMap"));
62      String parameterClassName = attributes.getProperty("parameterClass");
63      String resultMapName = attributes.getProperty("resultMap");
64      String resultClassName = attributes.getProperty("resultClass");
65      String cacheModelName = state.applyNamespace(attributes.getProperty("cacheModel"));
66      String xmlResultName = attributes.getProperty("xmlResultName");
67      String resultSetType = attributes.getProperty("resultSetType");
68      String fetchSize = attributes.getProperty("fetchSize");
69      String allowRemapping = attributes.getProperty("remapResults");
70      String timeout = attributes.getProperty("timeout");
71  
72      if (state.isUseStatementNamespaces()) {
73        id = state.applyNamespace(id);
74      }
75      String[] additionalResultMapNames = null;
76      if (resultMapName != null) {
77        additionalResultMapNames = state.getAllButFirstToken(resultMapName);
78        resultMapName = state.getFirstToken(resultMapName);
79        resultMapName = state.applyNamespace(resultMapName);
80        for (int i = 0; i < additionalResultMapNames.length; i++) {
81          additionalResultMapNames[i] = state.applyNamespace(additionalResultMapNames[i]);
82        }
83      }
84  
85      String[] additionalResultClassNames = null;
86      if (resultClassName != null) {
87        additionalResultClassNames = state.getAllButFirstToken(resultClassName);
88        resultClassName = state.getFirstToken(resultClassName);
89      }
90      Class[] additionalResultClasses = null;
91      if (additionalResultClassNames != null) {
92        additionalResultClasses = new Class[additionalResultClassNames.length];
93        for (int i = 0; i < additionalResultClassNames.length; i++) {
94          additionalResultClasses[i] = resolveClass(additionalResultClassNames[i]);
95        }
96      }
97  
98      state.getConfig().getErrorContext().setMoreInfo("Check the parameter class.");
99      Class parameterClass = resolveClass(parameterClassName);
100 
101     state.getConfig().getErrorContext().setMoreInfo("Check the result class.");
102     Class resultClass = resolveClass(resultClassName);
103 
104     Integer timeoutInt = timeout == null ? null : Integer.valueOf(timeout);
105     Integer fetchSizeInt = fetchSize == null ? null : Integer.valueOf(fetchSize);
106     boolean allowRemappingBool = "true".equals(allowRemapping);
107 
108     MappedStatementConfig statementConf = state.getConfig().newMappedStatementConfig(id, statement,
109         new XMLSqlSource(state, node), parameterMapName, parameterClass, resultMapName, additionalResultMapNames,
110         resultClass, additionalResultClasses, resultSetType, fetchSizeInt, allowRemappingBool, timeoutInt,
111         cacheModelName, xmlResultName);
112 
113     findAndParseSelectKey(node, statementConf);
114   }
115 
116   /**
117    * Resolve class.
118    *
119    * @param resultClassName
120    *          the result class name
121    *
122    * @return the class
123    */
124   private Class resolveClass(String resultClassName) {
125     try {
126       if (resultClassName != null) {
127         return Resources.classForName(state.getConfig().getTypeHandlerFactory().resolveAlias(resultClassName));
128       } else {
129         return null;
130       }
131     } catch (ClassNotFoundException e) {
132       throw new SqlMapException("Error.  Could not initialize class.  Cause: " + e, e);
133     }
134   }
135 
136   /**
137    * Find and parse select key.
138    *
139    * @param node
140    *          the node
141    * @param config
142    *          the config
143    */
144   private void findAndParseSelectKey(Node node, MappedStatementConfig config) {
145     state.getConfig().getErrorContext().setActivity("parsing select key tags");
146     boolean foundSQLFirst = false;
147     NodeList children = node.getChildNodes();
148     for (int i = 0; i < children.getLength(); i++) {
149       Node child = children.item(i);
150       if (child.getNodeType() == Node.CDATA_SECTION_NODE || child.getNodeType() == Node.TEXT_NODE) {
151         String data = ((CharacterData) child).getData();
152         if (data.trim().length() > 0) {
153           foundSQLFirst = true;
154         }
155       } else if (child.getNodeType() == Node.ELEMENT_NODE && "selectKey".equals(child.getNodeName())) {
156         Properties attributes = NodeletUtils.parseAttributes(child, state.getGlobalProps());
157         String keyPropName = attributes.getProperty("keyProperty");
158         String resultClassName = attributes.getProperty("resultClass");
159         String type = attributes.getProperty("type");
160         config.setSelectKeyStatement(new XMLSqlSource(state, child), resultClassName, keyPropName, foundSQLFirst, type);
161         break;
162       }
163     }
164     state.getConfig().getErrorContext().setMoreInfo(null);
165 
166   }
167 
168 }