You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ibatis.apache.org by cb...@apache.org on 2008/08/08 01:21:58 UTC

svn commit: r683745 [15/22] - in /ibatis/trunk/java/ibatis-3: ./ ibatis-3-compat/ ibatis-3-compat/src/ ibatis-3-compat/src/main/ ibatis-3-compat/src/main/java/ ibatis-3-compat/src/main/java/com/ ibatis-3-compat/src/main/java/com/ibatis/ ibatis-3-compat...

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/AdHocExecutor.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/AdHocExecutor.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/AdHocExecutor.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/AdHocExecutor.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,213 @@
+package org.apache.ibatis.adhoc;
+
+import org.apache.ibatis.type.*;
+
+import java.sql.*;
+import java.util.*;
+
+public class AdHocExecutor {
+
+  public static final int NO_GENERATED_KEY = Integer.MIN_VALUE + 1001;
+
+  private Connection connection;
+  private TypeHandlerRegistry typeHandlerRegistry;
+  private boolean forceGeneratedKeySupport = false;
+
+  public AdHocExecutor(Connection connection, boolean forceGeneratedKeySupport) {
+    this.connection = connection;
+    this.typeHandlerRegistry = new TypeHandlerRegistry();
+    this.forceGeneratedKeySupport = forceGeneratedKeySupport;
+  }
+
+  public AdHocExecutor(Connection connection) {
+    this(connection, false);
+  }
+
+  /**
+   * Executes a SELECT statement that returns one row.
+   *
+   * @param sql  The SQL
+   * @param args The arguments to be set on the statement.
+   * @return The number of rows impacted or BATCHED_RESULTS if the statements are being batched.
+   * @throws SQLException If more than one row is returned
+   */
+  public Map<String, Object> selectOne(String sql, Object... args) throws SQLException {
+    List<Map<String, Object>> results = selectAll(sql, args);
+    if (results.size() != 1) {
+      throw new SQLException("Statement returned " + results.size() + " results where exactly one (1) was expected.");
+    }
+    return results.get(0);
+  }
+
+  /**
+   * Executes a SELECT statement that returns multiple rows.
+   *
+   * @param sql  The SQL
+   * @param args The arguments to be set on the statement.
+   * @return The number of rows impacted or BATCHED_RESULTS if the statements are being batched.
+   * @throws SQLException If statement prepration or execution fails
+   */
+  public List<Map<String, Object>> selectAll(String sql, Object... args) throws SQLException {
+    PreparedStatement ps = connection.prepareStatement(sql);
+    try {
+      setParameters(ps, args);
+      ResultSet rs = ps.executeQuery();
+      return getResults(rs);
+    } finally {
+      try {
+        ps.close();
+      } catch (SQLException e) {
+        //ignore
+      }
+    }
+  }
+
+  /**
+   * Executes an INSERT statement.
+   *
+   * @param sql  The SQL
+   * @param args The arguments to be set on the statement.
+   * @return The number of rows impacted or BATCHED_RESULTS if the statements are being batched.
+   * @throws SQLException If statement prepration or execution fails
+   */
+  public int insert(String sql, Object... args) throws SQLException {
+    PreparedStatement ps;
+    if (forceGeneratedKeySupport || connection.getMetaData().supportsGetGeneratedKeys()) {
+      ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
+    } else {
+      ps = connection.prepareStatement(sql);
+    }
+
+    try {
+      setParameters(ps, args);
+      ps.executeUpdate();
+      if (forceGeneratedKeySupport || connection.getMetaData().supportsGetGeneratedKeys()) {
+        List<Map<String, Object>> keys = getResults(ps.getGeneratedKeys());
+        if (keys.size() == 1) {
+          Map<String, Object> key = keys.get(0);
+          Iterator i = key.values().iterator();
+          if (i.hasNext()) {
+            return Integer.parseInt(i.next().toString());
+          }
+        }
+      }
+      return NO_GENERATED_KEY;
+    } finally {
+      try {
+        ps.close();
+      } catch (SQLException e) {
+        //ignore
+      }
+    }
+  }
+
+  /**
+   * Executes an UPDATE statement.
+   *
+   * @param sql  The SQL
+   * @param args The arguments to be set on the statement.
+   * @return The number of rows impacted or BATCHED_RESULTS if the statements are being batched.
+   * @throws SQLException If statement prepration or execution fails
+   */
+  public int update(String sql, Object... args) throws SQLException {
+    PreparedStatement ps = connection.prepareStatement(sql);
+    try {
+      setParameters(ps, args);
+      return ps.executeUpdate();
+    } finally {
+      try {
+        ps.close();
+      } catch (SQLException e) {
+        //ignore
+      }
+    }
+  }
+
+  /**
+   * Executes a DELETE statement.
+   *
+   * @param sql  The SQL
+   * @param args The arguments to be set on the statement.
+   * @return The number of rows impacted or BATCHED_RESULTS if the statements are being batched.
+   * @throws SQLException If statement prepration or execution fails
+   */
+  public int delete(String sql, Object... args) throws SQLException {
+    return update(sql, args);
+  }
+
+  /**
+   * Executes any string as a JDBC Statement.
+   * Good for DDL
+   *
+   * @param sql The SQL
+   * @throws SQLException If statement prepration or execution fails
+   */
+  public void run(String sql) throws SQLException {
+    Statement stmt = connection.createStatement();
+    try {
+      stmt.execute(sql);
+    } finally {
+      try {
+        stmt.close();
+      } catch (SQLException e) {
+        //ignore
+      }
+    }
+  }
+
+  private void setParameters(PreparedStatement ps, Object... args) throws SQLException {
+    for (int i = 0, n = args.length; i < n; i++) {
+      if (args[i] == null) {
+        throw new SQLException("AdHocExecutor requires an instance of Null to represent typed null values for JDBC compatibility");
+      } else if (args[i] instanceof Null) {
+        ((Null) args[i]).getTypeHandler().setParameter(ps, i + 1, null, ((Null) args[i]).getJdbcType());
+      } else {
+        TypeHandler typeHandler = typeHandlerRegistry.getTypeHandler(args[i].getClass());
+        if (typeHandler == null) {
+          throw new SQLException("AdHocExecutor could not find a TypeHandler instance for " + args[i].getClass());
+        } else {
+          typeHandler.setParameter(ps, i + 1, args[i], null);
+        }
+      }
+    }
+  }
+
+  private List<Map<String, Object>> getResults(ResultSet rs) throws SQLException {
+    try {
+      List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
+      List<String> columns = new ArrayList<String>();
+      List<TypeHandler> typeHandlers = new ArrayList<TypeHandler>();
+      ResultSetMetaData rsmd = rs.getMetaData();
+      for (int i = 0, n = rsmd.getColumnCount(); i < n; i++) {
+        columns.add(rsmd.getColumnLabel(i + 1));
+        try {
+          Class type = Class.forName(rsmd.getColumnClassName(i + 1));
+          TypeHandler typeHandler = typeHandlerRegistry.getTypeHandler(type);
+          if (typeHandler == null) {
+            typeHandler = typeHandlerRegistry.getTypeHandler(Object.class);
+          }
+          typeHandlers.add(typeHandler);
+        } catch (Exception e) {
+          typeHandlers.add(typeHandlerRegistry.getTypeHandler(Object.class));
+        }
+      }
+      while (rs.next()) {
+        Map<String, Object> row = new HashMap<String, Object>();
+        for (int i = 0, n = columns.size(); i < n; i++) {
+          String name = columns.get(i);
+          TypeHandler handler = typeHandlers.get(i);
+          row.put(name, handler.getResult(rs, name));
+        }
+        list.add(row);
+      }
+      return list;
+    } finally {
+      try {
+        if (rs != null) rs.close();
+      } catch (Exception e) {
+        //ignore
+      }
+    }
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/Null.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/Null.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/Null.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/Null.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,48 @@
+package org.apache.ibatis.adhoc;
+
+import org.apache.ibatis.type.*;
+
+public enum Null {
+  BOOLEAN(new BooleanTypeHandler(), JdbcType.BOOLEAN),
+
+  BYTE(new ByteTypeHandler(), JdbcType.TINYINT),
+  SHORT(new ShortTypeHandler(), JdbcType.SMALLINT),
+  INTEGER(new IntegerTypeHandler(), JdbcType.INTEGER),
+  LONG(new LongTypeHandler(), JdbcType.BIGINT),
+  FLOAT(new FloatTypeHandler(), JdbcType.FLOAT),
+  DOUBLE(new DoubleTypeHandler(), JdbcType.DOUBLE),
+  BIGDECIMAL(new BigDecimalTypeHandler(), JdbcType.DECIMAL),
+
+  STRING(new StringTypeHandler(), JdbcType.VARCHAR),
+  CLOB(new ClobTypeHandler(), JdbcType.CLOB),
+  LONGVARCHAR(new ClobTypeHandler(), JdbcType.LONGVARCHAR),
+
+  BYTEARRAY(new ByteArrayTypeHandler(), JdbcType.LONGVARBINARY),
+  BLOB(new BlobTypeHandler(), JdbcType.BLOB),
+  LONGVARBINARY(new BlobTypeHandler(), JdbcType.LONGVARBINARY),
+
+  OBJECT(new ObjectTypeHandler(), JdbcType.OTHER),
+  OTHER(new ObjectTypeHandler(), JdbcType.OTHER),
+  TIMESTAMP(new DateTypeHandler(), JdbcType.TIMESTAMP),
+  DATE(new DateOnlyTypeHandler(), JdbcType.DATE),
+  TIME(new TimeOnlyTypeHandler(), JdbcType.TIME),
+  SQLTIMESTAMP(new SqlTimestampTypeHandler(), JdbcType.TIMESTAMP),
+  SQLDATE(new SqlDateTypeHandler(), JdbcType.DATE),
+  SQLTIME(new SqlTimeTypeHandler(), JdbcType.TIME);
+
+  private TypeHandler typeHandler;
+  private JdbcType jdbcType;
+
+  private Null(TypeHandler typeHandler, JdbcType jdbcType) {
+    this.typeHandler = typeHandler;
+    this.jdbcType = jdbcType;
+  }
+
+  public TypeHandler getTypeHandler() {
+    return typeHandler;
+  }
+
+  public JdbcType getJdbcType() {
+    return jdbcType;
+  }
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/BaseCache.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/BaseCache.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/BaseCache.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/BaseCache.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,34 @@
+package org.apache.ibatis.cache;
+
+/**
+ * Base Cache class implements a template method pattern for subclasses.
+ */
+public abstract class BaseCache implements Cache {
+
+  protected String id;
+
+  public String getId() {
+    return id;
+  }
+
+  public void setId(String id) {
+    this.id = id;
+  }
+
+  public boolean equals(Object o) {
+    if (getId() == null) throw new RuntimeException("Cache instances require an ID.");
+    if (this == o) return true;
+    if (!(o instanceof BaseCache)) return false;
+
+    BaseCache baseCache = (BaseCache) o;
+
+    if (!getId().equals(baseCache.getId())) return false;
+
+    return true;
+  }
+
+  public int hashCode() {
+    if (getId() == null) throw new RuntimeException("Cache instances require an ID.");
+    return getId().hashCode();
+  }
+}
\ No newline at end of file

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/Cache.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/Cache.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/Cache.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/Cache.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,75 @@
+package org.apache.ibatis.cache;
+
+import org.apache.ibatis.cache.decorators.*;
+import org.apache.ibatis.reflection.MetaObject;
+
+public interface Cache {
+
+  String getId();
+
+  int getSize();
+
+  void putObject(Object key, Object object);
+
+  Object getObject(Object key);
+
+  boolean hasKey(Object key);
+
+  Object removeObject(Object key);
+
+  void clear();
+
+  public class Builder {
+    private String id;
+    private Class implementation;
+    private Integer size;
+    private Long clearInterval;
+    private boolean readWrite;
+
+    public Builder(String id, Class implementation) {
+      this.id = id;
+      this.implementation = implementation;
+    }
+
+    public Builder size(Integer size) {
+      this.size = size;
+      return this;
+    }
+
+    public Builder clearInterval(Long clearInterval) {
+      this.clearInterval = clearInterval;
+      return this;
+    }
+
+    public Builder readWrite(boolean readWrite) {
+      this.readWrite = readWrite;
+      return this;
+    }
+
+    public Cache build() {
+      try {
+        // implementation...
+        Cache cache = (Cache) implementation.newInstance();
+        MetaObject metaCache = MetaObject.forObject(cache);
+        metaCache.setValue("id", id);
+        if (size != null && metaCache.hasSetter("size")) {
+          metaCache.setValue("size", size);
+        }
+        // decorators...
+        if (clearInterval != null) {
+          cache = new ScheduledCache(cache);
+          ((ScheduledCache) cache).setClearInterval(clearInterval);
+        }
+        if (readWrite) {
+          cache = new SerializedCache(cache);
+        }
+        cache = new LoggingCache(cache);
+        cache = new SynchronizedCache(cache);
+        return cache;
+      } catch (Exception e) {
+        throw new RuntimeException("Error building Cache class.  Cause: " + e, e);
+      }
+    }
+  }
+
+}
\ No newline at end of file

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/CacheKey.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/CacheKey.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/CacheKey.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/CacheKey.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,81 @@
+package org.apache.ibatis.cache;
+
+import java.util.*;
+
+public class CacheKey {
+
+  private static final int DEFAULT_MULTIPLYER = 37;
+  private static final int DEFAULT_HASHCODE = 17;
+
+  private int multiplier;
+  private int hashcode;
+  private long checksum;
+  private int count;
+  private List updateList;
+
+  public CacheKey() {
+    this.hashcode = DEFAULT_HASHCODE;
+    this.multiplier = DEFAULT_MULTIPLYER;
+    this.count = 0;
+    this.updateList = new ArrayList();
+  }
+
+  public CacheKey(Object[] objects) {
+    this();
+    updateAll(objects);
+  }
+
+  public void update(Object object) {
+    int baseHashCode = object == null ? 1 : object.hashCode();
+
+    count++;
+    checksum += baseHashCode;
+    baseHashCode *= count;
+
+    hashcode = multiplier * hashcode + baseHashCode;
+
+    updateList.add(object);
+  }
+
+  public void updateAll(Object[] objects) {
+    for (Object o : objects) {
+      update(o);
+    }
+  }
+
+  public boolean equals(Object object) {
+    if (this == object) return true;
+    if (!(object instanceof CacheKey)) return false;
+
+    final CacheKey cacheKey = (CacheKey) object;
+
+    if (hashcode != cacheKey.hashcode) return false;
+    if (checksum != cacheKey.checksum) return false;
+    if (count != cacheKey.count) return false;
+
+    for (int i = 0; i < updateList.size(); i++) {
+      Object thisObject = updateList.get(i);
+      Object thatObject = cacheKey.updateList.get(i);
+      if (thisObject == null) {
+        if (thatObject != null) return false;
+      } else {
+        if (!thisObject.equals(thatObject)) return false;
+      }
+    }
+    return true;
+  }
+
+  public int hashCode() {
+    return hashcode;
+  }
+
+  public String toString() {
+    StringBuffer returnValue = new StringBuffer().append(hashcode).append(':').append(checksum);
+    for (int i = 0; i < updateList.size(); i++) {
+      returnValue.append(':').append(updateList.get(i));
+    }
+
+    return returnValue.toString();
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/decorators/LoggingCache.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/decorators/LoggingCache.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/decorators/LoggingCache.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/decorators/LoggingCache.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,57 @@
+package org.apache.ibatis.cache.decorators;
+
+import org.apache.ibatis.cache.*;
+import org.apache.ibatis.logging.*;
+
+public class LoggingCache extends BaseCache {
+
+  private static final Log log = LogFactory.getLog(LoggingCache.class);
+
+  private Cache delegate;
+  protected int requests = 0;
+  protected int hits = 0;
+
+  public LoggingCache(Cache delegate) {
+    this.delegate = delegate;
+  }
+
+  public String getId() {
+    return delegate.getId();
+  }
+
+  public int getSize() {
+    return delegate.getSize();
+  }
+
+  public void putObject(Object key, Object object) {
+    delegate.putObject(key, object);
+  }
+
+  public Object getObject(Object key) {
+    requests++;
+    if (hasKey(key)) {
+      hits++;
+    }
+    if (log.isDebugEnabled()) {
+      log.debug("Cache Hit Ratio [" + getId() + "]: " + getHitRatio());
+    }
+    return delegate.getObject(key);
+  }
+
+  public boolean hasKey(Object key) {
+    return delegate.hasKey(key);
+  }
+
+  public Object removeObject(Object key) {
+    return delegate.removeObject(key);
+  }
+
+  public void clear() {
+    delegate.clear();
+  }
+
+  private double getHitRatio() {
+    return (double) hits / (double) requests;
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/decorators/ScheduledCache.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/decorators/ScheduledCache.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/decorators/ScheduledCache.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/decorators/ScheduledCache.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,76 @@
+package org.apache.ibatis.cache.decorators;
+
+import org.apache.ibatis.cache.*;
+
+public class ScheduledCache extends BaseCache {
+
+  private Cache delegate;
+  protected long clearInterval = 60 * 60 * 1000; // 1 hour
+  protected long lastClear = System.currentTimeMillis();
+
+  public ScheduledCache(Cache delegate) {
+    this.delegate = delegate;
+  }
+
+  public ScheduledCache(Cache delegate, int clearInterval) {
+    this.delegate = delegate;
+    this.clearInterval = clearInterval;
+  }
+
+  public long getClearInterval() {
+    return clearInterval;
+  }
+
+  public void setClearInterval(long clearInterval) {
+    this.clearInterval = clearInterval;
+  }
+
+  public String getId() {
+    return delegate.getId();
+  }
+
+  public int getSize() {
+    clearWhenStale();
+    return delegate.getSize();
+  }
+
+  public void putObject(Object key, Object object) {
+    clearWhenStale();
+    delegate.putObject(key, object);
+  }
+
+  public Object getObject(Object key) {
+    if (clearWhenStale()) {
+      return null;
+    } else {
+      return delegate.getObject(key);
+    }
+  }
+
+  public boolean hasKey(Object key) {
+    if (clearWhenStale()) {
+      return false;
+    } else {
+      return delegate.hasKey(key);
+    }
+  }
+
+  public Object removeObject(Object key) {
+    clearWhenStale();
+    return delegate.removeObject(key);
+  }
+
+  public void clear() {
+    lastClear = System.currentTimeMillis();
+    delegate.clear();
+  }
+
+  private boolean clearWhenStale() {
+    if (System.currentTimeMillis() - lastClear > clearInterval) {
+      clear();
+      return true;
+    }
+    return false;
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/decorators/SerializedCache.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/decorators/SerializedCache.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/decorators/SerializedCache.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/decorators/SerializedCache.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,75 @@
+package org.apache.ibatis.cache.decorators;
+
+import org.apache.ibatis.cache.*;
+
+import java.io.*;
+
+public class SerializedCache extends BaseCache {
+
+  private Cache delegate;
+
+  public SerializedCache(Cache delegate) {
+    this.delegate = delegate;
+  }
+
+  public String getId() {
+    return delegate.getId();
+  }
+
+  public int getSize() {
+    return delegate.getSize();
+  }
+
+  public void putObject(Object key, Object object) {
+    if (object == null || object instanceof Serializable) {
+      delegate.putObject(key, serialize((Serializable) object));
+    } else {
+      throw new RuntimeException("SharedCache failed to make a copy of a non-serializable object: " + object);
+    }
+  }
+
+  public Object getObject(Object key) {
+    Object object = delegate.getObject(key);
+    return object == null ? null : deserialize((byte[]) object);
+  }
+
+  public boolean hasKey(Object key) {
+    return delegate.hasKey(key);
+  }
+
+  public Object removeObject(Object key) {
+    return delegate.removeObject(key);
+  }
+
+  public void clear() {
+    delegate.clear();
+  }
+
+  private byte[] serialize(Serializable value) {
+    try {
+      ByteArrayOutputStream bos = new ByteArrayOutputStream();
+      ObjectOutputStream oos = new ObjectOutputStream(bos);
+      oos.writeObject(value);
+      oos.flush();
+      oos.close();
+      return bos.toByteArray();
+    } catch (Exception e) {
+      throw new RuntimeException("Error serializing object.  Cause: " + e, e);
+    }
+  }
+
+  private Serializable deserialize(byte[] value) {
+    Serializable result;
+    try {
+      ByteArrayInputStream bis = new ByteArrayInputStream((byte[]) value);
+      ObjectInputStream ois = new ObjectInputStream(bis);
+      result = (Serializable) ois.readObject();
+      ois.close();
+    } catch (Exception e) {
+      throw new RuntimeException("Error deserializing object.  Cause: " + e, e);
+    }
+    return result;
+  }
+
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/decorators/SynchronizedCache.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/decorators/SynchronizedCache.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/decorators/SynchronizedCache.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/decorators/SynchronizedCache.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,41 @@
+package org.apache.ibatis.cache.decorators;
+
+import org.apache.ibatis.cache.*;
+
+public class SynchronizedCache extends BaseCache {
+
+  private Cache delegate;
+
+  public SynchronizedCache(Cache delegate) {
+    this.delegate = delegate;
+  }
+
+  public String getId() {
+    return delegate.getId();
+  }
+
+  public synchronized int getSize() {
+    return delegate.getSize();
+  }
+
+  public synchronized void putObject(Object key, Object object) {
+    delegate.putObject(key, object);
+  }
+
+  public synchronized Object getObject(Object key) {
+    return delegate.getObject(key);
+  }
+
+  public synchronized boolean hasKey(Object key) {
+    return delegate.hasKey(key);
+  }
+
+  public synchronized Object removeObject(Object key) {
+    return delegate.removeObject(key);
+  }
+
+  public synchronized void clear() {
+    delegate.clear();
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/FifoCache.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/FifoCache.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/FifoCache.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/FifoCache.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,51 @@
+package org.apache.ibatis.cache.impl;
+
+import org.apache.ibatis.cache.BaseCache;
+
+import java.util.*;
+
+/**
+ * FIFO (first in, first out) cache controller implementation
+ */
+public class FifoCache extends BaseCache {
+
+  private int size = 256;
+  private Map cache = new HashMap();
+  private List keyList = new LinkedList();
+
+  public int getSize() {
+    return size;
+  }
+
+  public void setSize(int size) {
+    this.size = size;
+  }
+
+  public void putObject(Object key, Object value) {
+    cache.put(key, value);
+    keyList.add(key);
+    if (keyList.size() > size) {
+      Object oldestKey = keyList.remove(0);
+      cache.remove(oldestKey);
+    }
+  }
+
+  public Object getObject(Object key) {
+    return cache.get(key);
+  }
+
+  public boolean hasKey(Object key) {
+    return cache.containsKey(key);
+  }
+
+  public Object removeObject(Object key) {
+    keyList.remove(key);
+    return cache.remove(key);
+  }
+
+  public void clear() {
+    cache.clear();
+    keyList.clear();
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/LruCache.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/LruCache.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/LruCache.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/LruCache.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,56 @@
+package org.apache.ibatis.cache.impl;
+
+import org.apache.ibatis.cache.BaseCache;
+
+import java.util.*;
+
+/**
+ * LRU (least recently used) cache controller implementation
+ */
+public class LruCache extends BaseCache {
+
+  private int size = 256;
+  private Map cache = new HashMap();
+  private List keyList = new LinkedList();
+
+  public int getSize() {
+    return size;
+  }
+
+  public void setSize(int size) {
+    this.size = size;
+  }
+
+  public void putObject(Object key, Object value) {
+    cache.put(key, value);
+    keyList.add(key);
+    if (keyList.size() > size) {
+      Object oldestKey = keyList.remove(0);
+      cache.remove(oldestKey);
+    }
+  }
+
+  public Object getObject(Object key) {
+    Object result = cache.get(key);
+    keyList.remove(key);
+    if (result != null) {
+      keyList.add(key);
+    }
+    return result;
+  }
+
+  public boolean hasKey(Object key) {
+    return cache.containsKey(key);
+  }
+
+  public Object removeObject(Object key) {
+    keyList.remove(key);
+    return cache.remove(key);
+  }
+
+  public void clear() {
+    cache.clear();
+    keyList.clear();
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/PerpetualCache.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/PerpetualCache.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/PerpetualCache.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/PerpetualCache.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,35 @@
+package org.apache.ibatis.cache.impl;
+
+import org.apache.ibatis.cache.BaseCache;
+
+import java.util.*;
+
+public class PerpetualCache extends BaseCache {
+
+  private Map cache = new HashMap();
+
+  public int getSize() {
+    return cache.size();
+  }
+
+  public void putObject(Object key, Object value) {
+    cache.put(key, value);
+  }
+
+  public Object getObject(Object key) {
+    return cache.get(key);
+  }
+
+  public boolean hasKey(Object key) {
+    return cache.containsKey(key);
+  }
+
+  public Object removeObject(Object key) {
+    return cache.remove(key);
+  }
+
+  public void clear() {
+    cache.clear();
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/SoftCache.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/SoftCache.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/SoftCache.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/SoftCache.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,39 @@
+package org.apache.ibatis.cache.impl;
+
+import org.apache.ibatis.cache.BaseCache;
+
+import javax.util.SoftHashMap;
+import java.util.Map;
+
+/**
+ * Weak Reference cache implementation
+ */
+public class SoftCache extends BaseCache {
+
+  private Map cache = new SoftHashMap();
+
+  public int getSize() {
+    return cache.size();
+  }
+
+  public void putObject(Object key, Object value) {
+    cache.put(key, value);
+  }
+
+  public Object getObject(Object key) {
+    return cache.get(key);
+  }
+
+  public boolean hasKey(Object key) {
+    return cache.containsKey(key);
+  }
+
+  public Object removeObject(Object key) {
+    return cache.remove(key);
+  }
+
+  public void clear() {
+    cache.clear();
+  }
+
+}
\ No newline at end of file

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/WeakCache.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/WeakCache.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/WeakCache.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/cache/impl/WeakCache.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,38 @@
+package org.apache.ibatis.cache.impl;
+
+import org.apache.ibatis.cache.BaseCache;
+
+import java.util.*;
+
+/**
+ * Weak Reference cache implementation
+ */
+public class WeakCache extends BaseCache {
+
+  private Map cache = new WeakHashMap();
+
+  public int getSize() {
+    return cache.size();
+  }
+
+  public void putObject(Object key, Object value) {
+    cache.put(key, value);
+  }
+
+  public Object getObject(Object key) {
+    return cache.get(key);
+  }
+
+  public boolean hasKey(Object key) {
+    return cache.containsKey(key);
+  }
+
+  public Object removeObject(Object key) {
+    return cache.remove(key);
+  }
+
+  public void clear() {
+    cache.clear();
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/BaseExecutor.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/BaseExecutor.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/BaseExecutor.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/BaseExecutor.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,186 @@
+package org.apache.ibatis.executor;
+
+import org.apache.ibatis.cache.CacheKey;
+import org.apache.ibatis.cache.impl.PerpetualCache;
+import org.apache.ibatis.executor.result.ResultHandler;
+import org.apache.ibatis.logging.*;
+import org.apache.ibatis.logging.jdbc.ConnectionLogger;
+import org.apache.ibatis.mapping.*;
+import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.type.TypeHandlerRegistry;
+
+import java.sql.*;
+import java.util.*;
+
+public abstract class BaseExecutor implements Executor {
+
+  private static final Log log = LogFactory.getLog(BaseExecutor.class);
+  private static final Object EXECUTION_PLACEHOLDER = new Object();
+
+  protected final Connection connection;
+
+  protected final List<DeferredLoad> deferredLoads;
+  protected final PerpetualCache localCache;
+
+  protected int queryStack = 0;
+
+  protected List<BatchResult> batchResults = new ArrayList<BatchResult>();
+
+  protected BaseExecutor(Connection connection) {
+    if (log.isDebugEnabled()) {
+      this.connection = ConnectionLogger.newInstance(connection);
+    } else {
+      this.connection = connection;
+    }
+    this.deferredLoads = new ArrayList<DeferredLoad>();
+    this.localCache = new PerpetualCache();
+  }
+
+  public Connection getConnection() {
+    return connection;
+  }
+
+  public void close() {
+    try {
+      connection.close();
+    } catch (SQLException e) {
+      // Ignore.  There's nothing that can be done at this point.
+    }
+  }
+
+  public int update(MappedStatement ms, Object parameter) throws SQLException {
+    localCache.clear();
+    return doUpdate(ms, parameter);
+  }
+
+  public List flushStatements() throws SQLException {
+    batchResults.addAll(doFlushStatements());
+    return batchResults;
+  }
+
+  public List query(MappedStatement ms, Object parameter, int offset, int limit, ResultHandler resultHandler) throws SQLException {
+    List list;
+    try {
+      queryStack++;
+      CacheKey key = createCacheKey(ms, parameter, offset, limit);
+      if (localCache.hasKey(key)) {
+        list = (List) localCache.getObject(key);
+      } else {
+        localCache.putObject(key, EXECUTION_PLACEHOLDER);
+        try {
+          list = doQuery(ms, parameter, offset, limit, resultHandler);
+        } finally {
+          localCache.removeObject(key);
+        }
+        localCache.putObject(key, list);
+      }
+    } finally {
+      queryStack--;
+    }
+    if (queryStack == 0) {
+      for (DeferredLoad deferredLoad : deferredLoads) {
+        deferredLoad.load();
+      }
+    }
+    return list;
+  }
+
+  public void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key) {
+    deferredLoads.add(new DeferredLoad(ms, resultObject, property, key));
+  }
+
+  public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, int offset, int limit) {
+    CacheKey cacheKey = new CacheKey();
+    cacheKey.update(ms.getId());
+    cacheKey.update(offset);
+    cacheKey.update(limit);
+    if (ms.getDynamicParameterMappings(parameterObject).size() > 0 && parameterObject != null) {
+      TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
+      if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
+        cacheKey.update(parameterObject);
+      } else {
+        MetaObject metaObject = MetaObject.forObject(parameterObject);
+        List<ParameterMapping> parameterMappings = ms.getDynamicParameterMappings(parameterObject);
+        for (ParameterMapping parameterMapping : parameterMappings) {
+          cacheKey.update(metaObject.getValue(parameterMapping.getProperty()));
+        }
+      }
+    }
+    return cacheKey;
+  }
+
+  public boolean isCached(MappedStatement ms, CacheKey key) {
+    return localCache.hasKey(key);
+  }
+
+  public void commit(boolean required) throws SQLException {
+    flushStatements();
+    if (required) {
+      connection.commit();
+    }
+  }
+
+  public void rollback(boolean required) throws SQLException {
+    if (required) {
+      connection.rollback();
+    }
+  }
+
+  protected abstract int doUpdate(MappedStatement ms, Object parameter)
+      throws SQLException;
+
+  protected abstract List<BatchResult> doFlushStatements()
+      throws SQLException;
+
+  protected abstract List doQuery(MappedStatement ms, Object parameter, int offset, int limit, ResultHandler resultHandler)
+      throws SQLException;
+
+  protected void closeStatement(Statement statement) {
+    if (statement != null) {
+      try {
+        statement.close();
+      } catch (SQLException e) {
+        // ignore
+      }
+    }
+  }
+
+  private class DeferredLoad {
+
+    MappedStatement mappedStatement;
+    private MetaObject resultObject;
+    private String property;
+    private CacheKey key;
+
+    public DeferredLoad(MappedStatement mappedStatement, MetaObject resultObject, String property, CacheKey key) {
+      this.mappedStatement = mappedStatement;
+      this.resultObject = resultObject;
+      this.property = property;
+      this.key = key;
+    }
+
+    public void load() {
+      Object value = null;
+      List list = (List) localCache.getObject(key);
+      Class targetType = resultObject.getSetterType(property);
+      if (Set.class.isAssignableFrom(targetType)) {
+        value = new HashSet(list);
+      } else if (Collection.class.isAssignableFrom(targetType)) {
+        value = list;
+      } else if (targetType.isArray()) {
+        Object array = java.lang.reflect.Array.newInstance(targetType.getComponentType(), list.size());
+        value = list.toArray((Object[]) array);
+      } else {
+        if (list.size() > 1) {
+          throw new RuntimeException("Statement returned more than one row, where no more than one was expected.");
+        } else if (list.size() == 1) {
+          value = list.get(0);
+        }
+      }
+      resultObject.setValue(property, value);
+    }
+
+  }
+
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/BatchExecutor.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/BatchExecutor.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/BatchExecutor.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/BatchExecutor.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,93 @@
+package org.apache.ibatis.executor;
+
+import org.apache.ibatis.mapping.Configuration;
+import org.apache.ibatis.executor.result.ResultHandler;
+import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.mapping.*;
+
+import java.sql.*;
+import java.util.*;
+
+public class BatchExecutor extends BaseExecutor {
+
+  public static final int BATCH_UPDATE_RETURN_VALUE = Integer.MIN_VALUE + 1002;
+
+  private final List<Statement> statementList = new ArrayList<Statement>();
+  private final List<BatchResult> batchResultList = new ArrayList<BatchResult>();
+  private String currentSql;
+
+  public BatchExecutor(Connection connection) {
+    super(connection);
+  }
+
+  public int doUpdate(MappedStatement ms, Object parameterObject)
+      throws SQLException {
+    Configuration configuration = ms.getConfiguration();
+    StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, Executor.NO_ROW_OFFSET, Executor.NO_ROW_LIMIT, null);
+    String sql = handler.getSql();
+    Statement stmt;
+    if (currentSql != null && sql.hashCode() == currentSql.hashCode() && sql.length() == currentSql.length()) {
+      int last = statementList.size() - 1;
+      stmt = statementList.get(last);
+    } else {
+      stmt = handler.prepare(connection);
+      currentSql = sql;
+      statementList.add(stmt);
+      batchResultList.add(new BatchResult(ms, sql, parameterObject));
+    }
+    handler.parameterize(stmt);
+    handler.batch(stmt);
+    return BATCH_UPDATE_RETURN_VALUE;
+  }
+
+  public List doQuery(MappedStatement ms, Object parameterObject, int rowOffset, int rowLimit, ResultHandler resultHandler)
+      throws SQLException {
+    flushStatements();
+    Configuration configuration = ms.getConfiguration();
+    StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, rowOffset, rowLimit, resultHandler);
+    Statement stmt = handler.prepare(connection);
+    handler.parameterize(stmt);
+    return handler.query(stmt, resultHandler);
+  }
+
+  public List<BatchResult> doFlushStatements() throws SQLException {
+    List<BatchResult> results = new ArrayList<BatchResult>();
+    try {
+      for (int i = 0, n = statementList.size(); i < n; i++) {
+        Statement stmt = statementList.get(i);
+        BatchResult batchResult = batchResultList.get(i);
+        try {
+          batchResult.setUpdateCounts(stmt.executeBatch());
+        } catch (BatchUpdateException e) {
+          StringBuffer message = new StringBuffer();
+          message.append(batchResult.getMappedStatement().getId())
+              .append(" (batch index #")
+              .append(i + 1)
+              .append(")")
+              .append(" failed.");
+          if (i > 0) {
+            message.append(" ")
+                .append(i)
+                .append(" prior sub executor(s) completed successfully, but will be rolled back.");
+          }
+          throw new BatchExecutorException(message.toString(), e, results, batchResult);
+        }
+        results.add(batchResult);
+      }
+      return results;
+    } finally {
+      for (Statement stmt : statementList) {
+        closeStatement(stmt);
+      }
+      currentSql = null;
+      statementList.clear();
+      batchResultList.clear();
+    }
+  }
+
+}
+
+
+
+
+

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/BatchExecutorException.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/BatchExecutorException.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/BatchExecutorException.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/BatchExecutorException.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,62 @@
+package org.apache.ibatis.executor;
+
+import java.sql.BatchUpdateException;
+import java.util.List;
+
+public class BatchExecutorException extends RuntimeException {
+
+  private final List successfulBatchResults;
+  private final BatchUpdateException batchUpdateException;
+  private final BatchResult batchResult;
+
+  public BatchExecutorException(String message, BatchUpdateException cause, List successfulBatchResults,
+                                BatchResult batchResult) {
+    super(message + " Cause: " + cause, cause);
+    this.batchUpdateException = cause;
+    this.successfulBatchResults = successfulBatchResults;
+    this.batchResult = batchResult;
+  }
+
+  /**
+   * Returns the BatchUpdateException that caused the nested executor
+   * to fail.  That exception contains an array of row counts
+   * that can be used to determine exactly which statemtn of the
+   * executor caused the failure (or failures).
+   *
+   * @return the root BatchUpdateException
+   */
+  public BatchUpdateException getBatchUpdateException() {
+    return batchUpdateException;
+  }
+
+  /**
+   * Returns a list of BatchResult objects.  There will be one entry
+   * in the list for each successful sub-executor executed before the failing
+   * executor.
+   *
+   * @return the previously successful executor results (may be an empty list
+   *         if no executor has executed successfully)
+   */
+  public List getSuccessfulBatchResults() {
+    return successfulBatchResults;
+  }
+
+  /**
+   * Returns the SQL statement that caused the failure
+   * (not the parameterArray)
+   *
+   * @return the failing SQL string
+   */
+  public String getFailingSqlStatement() {
+    return batchResult.getSql();
+  }
+
+  /**
+   * Returns the statement id of the statement that caused the failure
+   *
+   * @return the statement id
+   */
+  public String getFailingStatementId() {
+    return batchResult.getMappedStatement().getId();
+  }
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/BatchResult.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/BatchResult.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/BatchResult.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/BatchResult.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,40 @@
+package org.apache.ibatis.executor;
+
+import org.apache.ibatis.mapping.MappedStatement;
+
+public class BatchResult {
+
+  private final MappedStatement mappedStatement;
+  private final String sql;
+  private final Object parameterObject;
+
+  private int[] updateCounts;
+
+  public BatchResult(MappedStatement mappedStatement, String sql, Object parameterObject) {
+    super();
+    this.mappedStatement = mappedStatement;
+    this.sql = sql;
+    this.parameterObject = parameterObject;
+  }
+
+  public MappedStatement getMappedStatement() {
+    return mappedStatement;
+  }
+
+  public String getSql() {
+    return sql;
+  }
+
+  public Object getParameterObject() {
+    return parameterObject;
+  }
+
+  public int[] getUpdateCounts() {
+    return updateCounts;
+  }
+
+  public void setUpdateCounts(int[] updateCounts) {
+    this.updateCounts = updateCounts;
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/CachingExecutor.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/CachingExecutor.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/CachingExecutor.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/CachingExecutor.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,116 @@
+package org.apache.ibatis.executor;
+
+import org.apache.ibatis.cache.*;
+import org.apache.ibatis.executor.result.ResultHandler;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.reflection.MetaObject;
+
+import java.sql.*;
+import java.util.*;
+
+public class CachingExecutor implements Executor {
+
+  private Executor delegate;
+
+  private Set<Cache> clearCaches;
+  private List<CacheEntry> cacheEntries;
+
+  public CachingExecutor(Executor delegate) {
+    this.delegate = delegate;
+  }
+
+  public Connection getConnection() {
+    return delegate.getConnection();
+  }
+
+  public void close() {
+    delegate.close();
+  }
+
+  public int update(MappedStatement ms, Object parameterObject) throws SQLException {
+    Cache cache = ms.getCache();
+    if (cache != null) {
+      if (clearCaches == null) {
+        clearCaches = new HashSet<Cache>();
+      }
+      clearCaches.add(cache);
+    }
+    return delegate.update(ms, parameterObject);
+  }
+
+  public List query(MappedStatement ms, Object parameterObject, int offset, int limit, ResultHandler resultHandler) throws SQLException {
+    Cache cache = ms.getCache();
+    if (cache != null) {
+      synchronized (cache) {
+        CacheKey key = createCacheKey(ms, parameterObject, offset, limit);
+        if (cache.hasKey(key)) {
+          return (List) cache.getObject(key);
+        } else {
+          List list = delegate.query(ms, parameterObject, offset, limit, resultHandler);
+          if (cacheEntries == null) {
+            cacheEntries = new ArrayList<CacheEntry>();
+          }
+          cacheEntries.add(new CacheEntry(cache, key, list));
+          return list;
+        }
+      }
+    } else {
+      return delegate.query(ms, parameterObject, offset, limit, resultHandler);
+    }
+  }
+
+  public List flushStatements() throws SQLException {
+    return delegate.flushStatements();
+  }
+
+  public void commit(boolean required) throws SQLException {
+    if (clearCaches != null) {
+      for (Cache cache : clearCaches) {
+        cache.clear();
+      }
+      clearCaches.clear();
+    }
+    if (cacheEntries != null) {
+      for (CacheEntry entry : cacheEntries) {
+        entry.commit();
+      }
+      cacheEntries.clear();
+    }
+    delegate.commit(required);
+  }
+
+  public void rollback(boolean required) throws SQLException {
+    if (clearCaches != null) clearCaches.clear();
+    if (cacheEntries != null) cacheEntries.clear();
+    delegate.rollback(required);
+  }
+
+  public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, int offset, int limit) {
+    return delegate.createCacheKey(ms, parameterObject, offset, limit);
+  }
+
+  public boolean isCached(MappedStatement ms, CacheKey key) {
+    throw new UnsupportedOperationException("The CachingExecutor should not be used by result loaders and thus isCached() should never be called.");
+  }
+
+  public void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key) {
+    throw new UnsupportedOperationException("The CachingExecutor should not be used by result loaders and thus deferLoad() should never be called.");
+  }
+
+  private static class CacheEntry {
+    private Cache cache;
+    private CacheKey key;
+    private Object value;
+
+    public CacheEntry(Cache cache, CacheKey key, Object value) {
+      this.cache = cache;
+      this.key = key;
+      this.value = value;
+    }
+
+    public void commit() {
+      cache.putObject(key, value);
+    }
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/ErrorContext.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/ErrorContext.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/ErrorContext.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/ErrorContext.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,84 @@
+package org.apache.ibatis.executor;
+
+public class ErrorContext {
+
+  private String resource;
+  private String activity;
+  private String objectId;
+  private String moreInfo;
+  private Throwable cause;
+
+  public void set(String resource, String activity, String objectId, String moreInfo) {
+    this.resource = resource;
+    this.activity = activity;
+    this.objectId = objectId;
+    this.moreInfo = moreInfo;
+  }
+
+  public void set(String activity, String objectId, String moreInfo) {
+    this.activity = activity;
+    this.objectId = objectId;
+    this.moreInfo = moreInfo;
+  }
+
+  public void set(String objectId, String moreInfo) {
+    this.objectId = objectId;
+    this.moreInfo = moreInfo;
+  }
+
+  public void set(String moreInfo) {
+    this.moreInfo = moreInfo;
+  }
+
+  public void set(Throwable cause) {
+    this.cause = cause;
+  }
+
+  public String toString() {
+    StringBuffer message = new StringBuffer();
+
+    // resource
+    if (resource != null) {
+      message.append("  \n*** The error occurred in ");
+      message.append(resource);
+      message.append(".");
+    }
+
+    // activity
+    if (activity != null) {
+      message.append("  \n*** The error occurred while ");
+      message.append(activity);
+      message.append(".");
+    }
+
+    // object
+    if (objectId != null) {
+      message.append("  \n*** Check ");
+      message.append(objectId);
+      message.append(".");
+    }
+
+    // more info
+    if (moreInfo != null) {
+      message.append("  \n*** ");
+      message.append(moreInfo);
+    }
+
+    // cause
+    if (cause != null) {
+      message.append("  \n*** Cause: ");
+      message.append(cause.toString());
+    }
+
+    return message.toString();
+  }
+
+  public void reset() {
+    resource = null;
+    activity = null;
+    objectId = null;
+    moreInfo = null;
+    cause = null;
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/Executor.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/Executor.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/Executor.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/Executor.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,37 @@
+package org.apache.ibatis.executor;
+
+import org.apache.ibatis.cache.CacheKey;
+import org.apache.ibatis.executor.result.ResultHandler;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.reflection.MetaObject;
+
+import java.sql.*;
+import java.util.List;
+
+public interface Executor {
+
+  int NO_ROW_OFFSET = 0;
+  int NO_ROW_LIMIT = Integer.MAX_VALUE;
+  ResultHandler NO_RESULT_HANDLER = null;
+
+  int update(MappedStatement ms, Object parameter) throws SQLException;
+
+  List query(MappedStatement ms, Object parameter, int offset, int limit, ResultHandler resultHandler) throws SQLException;
+
+  List<BatchResult> flushStatements() throws SQLException;
+
+  void commit(boolean required) throws SQLException;
+
+  void rollback(boolean required) throws SQLException;
+
+  CacheKey createCacheKey(MappedStatement ms, Object parameterObject, int offset, int limit);
+
+  boolean isCached(MappedStatement ms, CacheKey key);
+
+  void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key);
+
+  Connection getConnection();
+
+  void close();
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/ReuseExecutor.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/ReuseExecutor.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/ReuseExecutor.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/ReuseExecutor.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,68 @@
+package org.apache.ibatis.executor;
+
+import org.apache.ibatis.mapping.Configuration;
+import org.apache.ibatis.executor.result.ResultHandler;
+import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.mapping.*;
+
+import java.sql.*;
+import java.util.*;
+
+public class ReuseExecutor extends BaseExecutor {
+
+  private final Map<String, Statement> statementMap = new HashMap<String, Statement>();
+
+  public ReuseExecutor(Connection connection) {
+    super(connection);
+  }
+
+  public int doUpdate(MappedStatement ms, Object parameter)
+      throws SQLException {
+    Configuration configuration = ms.getConfiguration();
+    StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, Executor.NO_ROW_OFFSET, Executor.NO_ROW_LIMIT, null);
+    Statement stmt = prepareStatement(handler);
+    return handler.update(stmt);
+  }
+
+  public List doQuery(MappedStatement ms, Object parameter, int rowOffset, int rowLimit, ResultHandler resultHandler) throws SQLException {
+    Configuration configuration = ms.getConfiguration();
+    StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, rowOffset, rowLimit, resultHandler);
+    Statement stmt = prepareStatement(handler);
+    return handler.query(stmt, resultHandler);
+  }
+
+  public List doFlushStatements()
+      throws SQLException {
+    for (Statement stmt : statementMap.values()) {
+      closeStatement(stmt);
+    }
+    return Collections.EMPTY_LIST;
+  }
+
+  private Statement prepareStatement(StatementHandler handler)
+      throws SQLException {
+    Statement stmt;
+    String sql = handler.getSql();
+    if (hasStatementFor(sql)) {
+      stmt = getStatement(sql);
+    } else {
+      stmt = handler.prepare(connection);
+      putStatement(sql, stmt);
+    }
+    handler.parameterize(stmt);
+    return stmt;
+  }
+
+  private boolean hasStatementFor(String sql) {
+    return statementMap.keySet().contains(sql);
+  }
+
+  private Statement getStatement(String s) {
+    return statementMap.get(s);
+  }
+
+  private void putStatement(String sql, Statement stmt) {
+    statementMap.put(sql, stmt);
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/SimpleExecutor.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/SimpleExecutor.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/SimpleExecutor.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/SimpleExecutor.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,54 @@
+package org.apache.ibatis.executor;
+
+import org.apache.ibatis.mapping.Configuration;
+import org.apache.ibatis.executor.result.ResultHandler;
+import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.mapping.*;
+
+import java.sql.*;
+import java.util.*;
+
+public class SimpleExecutor extends BaseExecutor {
+
+  public SimpleExecutor(Connection connection) {
+    super(connection);
+  }
+
+  public int doUpdate(MappedStatement ms, Object parameter)
+      throws SQLException {
+    Statement stmt = null;
+    try {
+      Configuration configuration = ms.getConfiguration();
+      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, Executor.NO_ROW_OFFSET, Executor.NO_ROW_LIMIT, null);
+      stmt = prepareStatement(handler);
+      return handler.update(stmt);
+    } finally {
+      closeStatement(stmt);
+    }
+  }
+
+  public List doQuery(MappedStatement ms, Object parameter, int rowOffset, int rowLimit, ResultHandler resultHandler) throws SQLException {
+    Statement stmt = null;
+    try {
+      Configuration configuration = ms.getConfiguration();
+      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, rowOffset, rowLimit, resultHandler);
+      stmt = prepareStatement(handler);
+      return handler.query(stmt, resultHandler);
+    } finally {
+      closeStatement(stmt);
+    }
+  }
+
+  public List doFlushStatements()
+      throws SQLException {
+    return Collections.EMPTY_LIST;
+  }
+
+  private Statement prepareStatement(StatementHandler handler) throws SQLException {
+    Statement stmt;
+    stmt = handler.prepare(connection);
+    handler.parameterize(stmt);
+    return stmt;
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/loader/ResultLoader.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/loader/ResultLoader.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/loader/ResultLoader.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/loader/ResultLoader.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,57 @@
+package org.apache.ibatis.executor.loader;
+
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.mapping.MappedStatement;
+
+import java.sql.SQLException;
+import java.util.*;
+
+public class ResultLoader {
+
+  protected static final Class[] LIST_INTERFACES = new Class[]{List.class};
+  protected static final Class[] SET_INTERFACES = new Class[]{Set.class};
+
+  protected final Executor executor;
+  protected final MappedStatement mappedStatement;
+  protected final Object parameterObject;
+  protected final Class targetType;
+
+  protected boolean loaded;
+  protected Object resultObject;
+
+  public ResultLoader(Executor executor, MappedStatement mappedStatement, Object parameterObject, Class targetType) {
+    this.executor = executor;
+    this.mappedStatement = mappedStatement;
+    this.parameterObject = parameterObject;
+    this.targetType = targetType;
+  }
+
+  public Object loadResult() throws SQLException {
+    List list = executor.query(mappedStatement, parameterObject, Executor.NO_ROW_OFFSET, Executor.NO_ROW_LIMIT, Executor.NO_RESULT_HANDLER);
+    if (targetType != null && Set.class.isAssignableFrom(targetType)) {
+      resultObject = new HashSet(list);
+    } else if (targetType != null && Collection.class.isAssignableFrom(targetType)) {
+      resultObject = list;
+    } else if (targetType != null && targetType.isArray()) {
+      resultObject = listToArray(list, targetType.getComponentType());
+    } else {
+      if (list.size() > 1) {
+        throw new RuntimeException("Statement " + mappedStatement.getId() + " returned more than one row, where no more than one was expected.");
+      } else if (list.size() == 1) {
+        resultObject = list.get(0);
+      }
+    }
+    return resultObject;
+  }
+
+  public boolean wasNull() {
+    return resultObject == null;
+  }
+
+  private Object[] listToArray(List list, Class type) {
+    Object array = java.lang.reflect.Array.newInstance(type, list.size());
+    array = list.toArray((Object[]) array);
+    return (Object[]) array;
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/loader/ResultLoaderRegistry.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/loader/ResultLoaderRegistry.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/loader/ResultLoaderRegistry.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/loader/ResultLoaderRegistry.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,59 @@
+package org.apache.ibatis.executor.loader;
+
+import org.apache.ibatis.reflection.MetaObject;
+
+import java.io.Serializable;
+import java.sql.SQLException;
+import java.util.*;
+
+public class ResultLoaderRegistry implements Serializable {
+
+  private final Map<String, LoadPair> loaderMap = new HashMap<String, LoadPair>();
+
+  public void registerLoader(String property, MetaObject metaResultObject, ResultLoader resultLoader) {
+    // Converts property to method name strictly for performance.
+    String upperFirst = getUppercaseFirstProperty(property);
+    loaderMap.put(toGetter(upperFirst), new LoadPair(property, metaResultObject, resultLoader));
+    loaderMap.put(toSetter(upperFirst), new LoadPair(property, metaResultObject, resultLoader));
+  }
+
+  public boolean loadByMethod(String methodName) throws SQLException {
+    synchronized (loaderMap) {
+      ResultLoaderRegistry.LoadPair pair = loaderMap.remove(methodName.toUpperCase());
+      if (pair != null) {
+        pair.load();
+        return true;
+      }
+      return false;
+    }
+  }
+
+  private String toGetter(String first) {
+    return "GET" + first;
+  }
+
+  private String toSetter(String first) {
+    return "SET" + first;
+  }
+
+  private static String getUppercaseFirstProperty(String property) {
+    String[] parts = property.split("\\.");
+    return parts[0].toUpperCase();
+  }
+
+  private class LoadPair {
+    private String property;
+    private MetaObject metaResultObject;
+    private ResultLoader resultLoader;
+
+    private LoadPair(String property, MetaObject metaResultObject, ResultLoader resultLoader) {
+      this.property = property;
+      this.metaResultObject = metaResultObject;
+      this.resultLoader = resultLoader;
+    }
+
+    public void load() throws SQLException {
+      metaResultObject.setValue(property, resultLoader.loadResult());
+    }
+  }
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/loader/ResultObjectProxy.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/loader/ResultObjectProxy.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/loader/ResultObjectProxy.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/loader/ResultObjectProxy.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,47 @@
+package org.apache.ibatis.executor.loader;
+
+import net.sf.cglib.proxy.*;
+import org.apache.ibatis.reflection.*;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+public class ResultObjectProxy {
+
+  public static Object createProxy(Class type, Object target, ResultLoaderRegistry lazyLoader) {
+    return EnhancedResultObjectProxyImpl.createProxy(type, target, lazyLoader);
+  }
+
+  private static class EnhancedResultObjectProxyImpl implements InvocationHandler, Serializable {
+
+    private Object target;
+    private ResultLoaderRegistry lazyLoader;
+
+    private EnhancedResultObjectProxyImpl(Object target, ResultLoaderRegistry lazyLoader) {
+      this.target = target;
+      this.lazyLoader = lazyLoader;
+    }
+
+    public static Object createProxy(Class type, Object target, ResultLoaderRegistry lazyLoader) {
+      return Enhancer.create(type, new EnhancedResultObjectProxyImpl(target, lazyLoader));
+    }
+
+    public Object invoke(Object o, Method method, Object[] args) throws Throwable {
+      try {
+        Object value = method.invoke(target, args);
+        if (value == null) {
+          String methodName = method.getName();
+          if (PropertyNamer.isProperty(methodName)) {
+            if (lazyLoader.loadByMethod(methodName)) {
+              value = method.invoke(target, args);
+            }
+          }
+        }
+        return value;
+      } catch (Throwable t) {
+        throw ExceptionUtil.unwrapThrowable(t);
+      }
+    }
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/parameter/DefaultParameterHandler.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/parameter/DefaultParameterHandler.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/parameter/DefaultParameterHandler.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/parameter/DefaultParameterHandler.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,53 @@
+package org.apache.ibatis.executor.parameter;
+
+import org.apache.ibatis.mapping.*;
+import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.type.*;
+
+import java.sql.*;
+import java.util.List;
+
+public class DefaultParameterHandler implements ParameterHandler {
+
+  private final TypeHandlerRegistry typeHandlerRegistry;
+
+  private final MappedStatement mappedStatement;
+  private final Object parameterObject;
+
+  public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject) {
+    this.mappedStatement = mappedStatement;
+    this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
+    this.parameterObject = parameterObject;
+  }
+
+  public Object getParameterObject() {
+    return parameterObject;
+  }
+
+  public void setParameters(PreparedStatement ps)
+      throws SQLException {
+    List<ParameterMapping> parameterMappings = mappedStatement.getDynamicParameterMappings(parameterObject);
+    if (parameterMappings != null) {
+      MetaObject metaObject = parameterObject == null ? null : MetaObject.forObject(parameterObject);
+      for (int i = 0; i < parameterMappings.size(); i++) {
+        ParameterMapping parameterMapping = parameterMappings.get(i);
+        if (parameterMapping.getMode() != ParameterMode.OUT) {
+          Object value;
+          if (parameterObject == null) {
+            value = null;
+          } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
+            value = parameterObject;
+          } else {
+            value = metaObject == null ? null : metaObject.getValue(parameterMapping.getProperty());
+          }
+          TypeHandler typeHandler = parameterMapping.getTypeHandler();
+          if (typeHandler == null) {
+            throw new RuntimeException("There was no TypeHandler found for parameter " + parameterMapping.getProperty() + " of statement " + mappedStatement.getId());
+          }
+          typeHandler.setParameter(ps, i + 1, value, parameterMapping.getJdbcType());
+        }
+      }
+    }
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/parameter/ParameterHandler.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/parameter/ParameterHandler.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/parameter/ParameterHandler.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/parameter/ParameterHandler.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,12 @@
+package org.apache.ibatis.executor.parameter;
+
+import java.sql.*;
+
+public interface ParameterHandler {
+
+  Object getParameterObject();
+
+  void setParameters(PreparedStatement ps)
+      throws SQLException;
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/result/DefaultResultHandler.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/result/DefaultResultHandler.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/result/DefaultResultHandler.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/result/DefaultResultHandler.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,17 @@
+package org.apache.ibatis.executor.result;
+
+import java.util.*;
+
+public class DefaultResultHandler implements ResultHandler {
+
+  private final List list = new ArrayList();
+
+  public void handleResult(Object resultObject) {
+    list.add(resultObject);
+  }
+
+  public List getResultList() {
+    return list;
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/result/ResultHandler.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/result/ResultHandler.java?rev=683745&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/result/ResultHandler.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/result/ResultHandler.java Thu Aug  7 16:21:46 2008
@@ -0,0 +1,7 @@
+package org.apache.ibatis.executor.result;
+
+public interface ResultHandler {
+
+  void handleResult(Object resultObject);
+
+}