View Javadoc
1   /**
2    *    Copyright 2009-2015 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    *       http://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 org.apache.ibatis.executor.keygen;
17  
18  import java.sql.ResultSet;
19  import java.sql.ResultSetMetaData;
20  import java.sql.SQLException;
21  import java.sql.Statement;
22  import java.util.*;
23  
24  import org.apache.ibatis.executor.Executor;
25  import org.apache.ibatis.executor.ExecutorException;
26  import org.apache.ibatis.mapping.MappedStatement;
27  import org.apache.ibatis.reflection.MetaObject;
28  import org.apache.ibatis.session.Configuration;
29  import org.apache.ibatis.type.JdbcType;
30  import org.apache.ibatis.type.TypeHandler;
31  import org.apache.ibatis.type.TypeHandlerRegistry;
32  
33  /**
34   * @author Clinton Begin
35   */
36  public class Jdbc3KeyGenerator implements KeyGenerator {
37  
38    @Override
39    public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
40      // do nothing
41    }
42  
43    @Override
44    public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
45      processBatch(ms, stmt, getParameters(parameter));
46    }
47  
48    public void processBatch(MappedStatement ms, Statement stmt, Collection<Object> parameters) {
49      ResultSet rs = null;
50      try {
51        rs = stmt.getGeneratedKeys();
52        final Configuration configuration = ms.getConfiguration();
53        final TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
54        final String[] keyProperties = ms.getKeyProperties();
55        final ResultSetMetaData rsmd = rs.getMetaData();
56        TypeHandler<?>[] typeHandlers = null;
57        if (keyProperties != null && rsmd.getColumnCount() >= keyProperties.length) {
58          for (Object parameter : parameters) {
59            // there should be one row for each statement (also one for each parameter)
60            if (!rs.next()) {
61              break;
62            }
63            final MetaObject metaParam = configuration.newMetaObject(parameter);
64            if (typeHandlers == null) {
65              typeHandlers = getTypeHandlers(typeHandlerRegistry, metaParam, keyProperties, rsmd);
66            }
67            populateKeys(rs, metaParam, keyProperties, typeHandlers);
68          }
69        }
70      } catch (Exception e) {
71        throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e, e);
72      } finally {
73        if (rs != null) {
74          try {
75            rs.close();
76          } catch (Exception e) {
77            // ignore
78          }
79        }
80      }
81    }
82  
83    private Collection<Object> getParameters(Object parameter) {
84      Collection<Object> parameters = null;
85      if (parameter instanceof Collection) {
86        parameters = (Collection) parameter;
87      } else if (parameter instanceof Map) {
88        Map parameterMap = (Map) parameter;
89        if (parameterMap.containsKey("collection")) {
90          parameters = (Collection) parameterMap.get("collection");
91        } else if (parameterMap.containsKey("list")) {
92          parameters = (List) parameterMap.get("list");
93        } else if (parameterMap.containsKey("array")) {
94          parameters = Arrays.asList((Object[]) parameterMap.get("array"));
95        }
96      }
97      if (parameters == null) {
98        parameters = new ArrayList<Object>();
99        parameters.add(parameter);
100     }
101     return parameters;
102   }
103 
104   private TypeHandler<?>[] getTypeHandlers(TypeHandlerRegistry typeHandlerRegistry, MetaObject metaParam, String[] keyProperties, ResultSetMetaData rsmd) throws SQLException {
105     TypeHandler<?>[] typeHandlers = new TypeHandler<?>[keyProperties.length];
106     for (int i = 0; i < keyProperties.length; i++) {
107       if (metaParam.hasSetter(keyProperties[i])) {
108         Class<?> keyPropertyType = metaParam.getSetterType(keyProperties[i]);
109         TypeHandler<?> th = typeHandlerRegistry.getTypeHandler(keyPropertyType, JdbcType.forCode(rsmd.getColumnType(i + 1)));
110         typeHandlers[i] = th;
111       }
112     }
113     return typeHandlers;
114   }
115 
116   private void populateKeys(ResultSet rs, MetaObject metaParam, String[] keyProperties, TypeHandler<?>[] typeHandlers) throws SQLException {
117     for (int i = 0; i < keyProperties.length; i++) {
118       TypeHandler<?> th = typeHandlers[i];
119       if (th != null) {
120         Object value = th.getResult(rs, i + 1);
121         metaParam.setValue(keyProperties[i], value);
122       }
123     }
124   }
125 
126 }