001: package com.ibatis.sqlmap.engine.mapping.parameter;
002:
003: import com.ibatis.common.beans.Probe;
004: import com.ibatis.common.beans.ProbeFactory;
005: import com.ibatis.common.resources.Resources;
006: import com.ibatis.sqlmap.client.SqlMapException;
007: import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;
008: import com.ibatis.sqlmap.engine.mapping.sql.SqlText;
009: import com.ibatis.sqlmap.engine.type.CustomTypeHandler;
010: import com.ibatis.sqlmap.engine.type.DomTypeMarker;
011: import com.ibatis.sqlmap.engine.type.TypeHandler;
012: import com.ibatis.sqlmap.engine.type.TypeHandlerFactory;
013:
014: import java.util.ArrayList;
015: import java.util.List;
016: import java.util.StringTokenizer;
017:
018: public class InlineParameterMapParser {
019:
020: private static final Probe PROBE = ProbeFactory.getProbe();
021: private static final String PARAMETER_TOKEN = "#";
022: private static final String PARAM_DELIM = ":";
023:
024: public SqlText parseInlineParameterMap(
025: TypeHandlerFactory typeHandlerFactory, String sqlStatement) {
026: return parseInlineParameterMap(typeHandlerFactory,
027: sqlStatement, null);
028: }
029:
030: public SqlText parseInlineParameterMap(
031: TypeHandlerFactory typeHandlerFactory, String sqlStatement,
032: Class parameterClass) {
033:
034: String newSql = sqlStatement;
035:
036: List mappingList = new ArrayList();
037:
038: StringTokenizer parser = new StringTokenizer(sqlStatement,
039: PARAMETER_TOKEN, true);
040: StringBuffer newSqlBuffer = new StringBuffer();
041:
042: String token = null;
043: String lastToken = null;
044: while (parser.hasMoreTokens()) {
045: token = parser.nextToken();
046: if (PARAMETER_TOKEN.equals(lastToken)) {
047: if (PARAMETER_TOKEN.equals(token)) {
048: newSqlBuffer.append(PARAMETER_TOKEN);
049: token = null;
050: } else {
051: ParameterMapping mapping = null;
052: if (token.indexOf(PARAM_DELIM) > -1) {
053: mapping = oldParseMapping(token,
054: parameterClass, typeHandlerFactory);
055: } else {
056: mapping = newParseMapping(token,
057: parameterClass, typeHandlerFactory);
058: }
059:
060: mappingList.add(mapping);
061: newSqlBuffer.append("?");
062: token = parser.nextToken();
063: if (!PARAMETER_TOKEN.equals(token)) {
064: throw new SqlMapException(
065: "Unterminated inline parameter in mapped statement ("
066: + "statement.getId()" + ").");
067: }
068: token = null;
069: }
070: } else {
071: if (!PARAMETER_TOKEN.equals(token)) {
072: newSqlBuffer.append(token);
073: }
074: }
075:
076: lastToken = token;
077: }
078:
079: newSql = newSqlBuffer.toString();
080:
081: ParameterMapping[] mappingArray = (ParameterMapping[]) mappingList
082: .toArray(new ParameterMapping[mappingList.size()]);
083:
084: SqlText sqlText = new SqlText();
085: sqlText.setText(newSql);
086: sqlText.setParameterMappings(mappingArray);
087: return sqlText;
088: }
089:
090: private ParameterMapping newParseMapping(String token,
091: Class parameterClass, TypeHandlerFactory typeHandlerFactory) {
092: BasicParameterMapping mapping = new BasicParameterMapping();
093:
094: // #propertyName,javaType=string,jdbcType=VARCHAR,mode=IN,nullValue=N/A,handler=string,numericScale=2#
095:
096: StringTokenizer paramParser = new StringTokenizer(token, "=,",
097: false);
098: mapping.setPropertyName(paramParser.nextToken());
099:
100: while (paramParser.hasMoreTokens()) {
101: String field = paramParser.nextToken();
102: if (paramParser.hasMoreTokens()) {
103: String value = paramParser.nextToken();
104: if ("javaType".equals(field)) {
105: value = typeHandlerFactory.resolveAlias(value);
106: mapping.setJavaTypeName(value);
107: } else if ("jdbcType".equals(field)) {
108: mapping.setJdbcTypeName(value);
109: } else if ("mode".equals(field)) {
110: mapping.setMode(value);
111: } else if ("nullValue".equals(field)) {
112: mapping.setNullValue(value);
113: } else if ("handler".equals(field)) {
114: try {
115: value = typeHandlerFactory.resolveAlias(value);
116: Object impl = Resources.classForName(value)
117: .newInstance();
118: if (impl instanceof TypeHandlerCallback) {
119: mapping
120: .setTypeHandler(new CustomTypeHandler(
121: (TypeHandlerCallback) impl));
122: } else if (impl instanceof TypeHandler) {
123: mapping.setTypeHandler((TypeHandler) impl);
124: } else {
125: throw new SqlMapException(
126: "The class "
127: + value
128: + " is not a valid implementation of TypeHandler or TypeHandlerCallback");
129: }
130: } catch (Exception e) {
131: throw new SqlMapException(
132: "Error loading class specified by handler field in "
133: + token + ". Cause: " + e, e);
134: }
135: } else if ("numericScale".equals(field)) {
136: try {
137: Integer numericScale = Integer.valueOf(value);
138: if (numericScale.intValue() < 0) {
139: throw new SqlMapException(
140: "Value specified for numericScale must be greater than or equal to zero");
141: }
142: mapping.setNumericScale(numericScale);
143: } catch (NumberFormatException e) {
144: throw new SqlMapException(
145: "Value specified for numericScale is not a valid Integer");
146: }
147: } else {
148: throw new SqlMapException(
149: "Unrecognized parameter mapping field: '"
150: + field + "' in " + token);
151: }
152: } else {
153: throw new SqlMapException(
154: "Incorrect inline parameter map format (missmatched name=value pairs): "
155: + token);
156: }
157: }
158:
159: if (mapping.getTypeHandler() == null) {
160: TypeHandler handler;
161: if (parameterClass == null) {
162: handler = typeHandlerFactory.getUnkownTypeHandler();
163: } else {
164: handler = resolveTypeHandler(typeHandlerFactory,
165: parameterClass, mapping.getPropertyName(),
166: mapping.getJavaTypeName(), mapping
167: .getJdbcTypeName());
168: }
169: mapping.setTypeHandler(handler);
170: }
171:
172: return mapping;
173: }
174:
175: private ParameterMapping oldParseMapping(String token,
176: Class parameterClass, TypeHandlerFactory typeHandlerFactory) {
177: BasicParameterMapping mapping = new BasicParameterMapping();
178: if (token.indexOf(PARAM_DELIM) > -1) {
179: StringTokenizer paramParser = new StringTokenizer(token,
180: PARAM_DELIM, true);
181: int n1 = paramParser.countTokens();
182: if (n1 == 3) {
183: String name = paramParser.nextToken();
184: paramParser.nextToken(); //ignore ":"
185: String type = paramParser.nextToken();
186: mapping.setPropertyName(name);
187: mapping.setJdbcTypeName(type);
188: TypeHandler handler;
189: if (parameterClass == null) {
190: handler = typeHandlerFactory.getUnkownTypeHandler();
191: } else {
192: handler = resolveTypeHandler(typeHandlerFactory,
193: parameterClass, name, null, type);
194: }
195: mapping.setTypeHandler(handler);
196: return mapping;
197: } else if (n1 >= 5) {
198: String name = paramParser.nextToken();
199: paramParser.nextToken(); //ignore ":"
200: String type = paramParser.nextToken();
201: paramParser.nextToken(); //ignore ":"
202: String nullValue = paramParser.nextToken();
203: while (paramParser.hasMoreTokens()) {
204: nullValue = nullValue + paramParser.nextToken();
205: }
206: mapping.setPropertyName(name);
207: mapping.setJdbcTypeName(type);
208: mapping.setNullValue(nullValue);
209: TypeHandler handler;
210: if (parameterClass == null) {
211: handler = typeHandlerFactory.getUnkownTypeHandler();
212: } else {
213: handler = resolveTypeHandler(typeHandlerFactory,
214: parameterClass, name, null, type);
215: }
216: mapping.setTypeHandler(handler);
217: return mapping;
218: } else {
219: throw new SqlMapException(
220: "Incorrect inline parameter map format: "
221: + token);
222: }
223: } else {
224: mapping.setPropertyName(token);
225: TypeHandler handler;
226: if (parameterClass == null) {
227: handler = typeHandlerFactory.getUnkownTypeHandler();
228: } else {
229: handler = resolveTypeHandler(typeHandlerFactory,
230: parameterClass, token, null, null);
231: }
232: mapping.setTypeHandler(handler);
233: return mapping;
234: }
235: }
236:
237: private TypeHandler resolveTypeHandler(
238: TypeHandlerFactory typeHandlerFactory, Class clazz,
239: String propertyName, String javaType, String jdbcType) {
240: TypeHandler handler = null;
241: if (clazz == null) {
242: // Unknown
243: handler = typeHandlerFactory.getUnkownTypeHandler();
244: } else if (DomTypeMarker.class.isAssignableFrom(clazz)) {
245: // DOM
246: handler = typeHandlerFactory.getTypeHandler(String.class,
247: jdbcType);
248: } else if (java.util.Map.class.isAssignableFrom(clazz)) {
249: // Map
250: if (javaType == null) {
251: handler = typeHandlerFactory.getUnkownTypeHandler(); //BUG 1012591 - typeHandlerFactory.getTypeHandler(java.lang.Object.class, jdbcType);
252: } else {
253: try {
254: javaType = typeHandlerFactory
255: .resolveAlias(javaType);
256: Class javaClass = Resources.classForName(javaType);
257: handler = typeHandlerFactory.getTypeHandler(
258: javaClass, jdbcType);
259: } catch (Exception e) {
260: throw new SqlMapException(
261: "Error. Could not set TypeHandler. Cause: "
262: + e, e);
263: }
264: }
265: } else if (typeHandlerFactory.getTypeHandler(clazz, jdbcType) != null) {
266: // Primitive
267: handler = typeHandlerFactory
268: .getTypeHandler(clazz, jdbcType);
269: } else {
270: // JavaBean
271: if (javaType == null) {
272:
273: Class type = PROBE.getPropertyTypeForGetter(clazz,
274: propertyName);
275: handler = typeHandlerFactory.getTypeHandler(type,
276: jdbcType);
277:
278: } else {
279: try {
280: javaType = typeHandlerFactory
281: .resolveAlias(javaType);
282: Class javaClass = Resources.classForName(javaType);
283: handler = typeHandlerFactory.getTypeHandler(
284: javaClass, jdbcType);
285: } catch (Exception e) {
286: throw new SqlMapException(
287: "Error. Could not set TypeHandler. Cause: "
288: + e, e);
289: }
290: }
291: }
292: return handler;
293: }
294:
295: }
|