Added: 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java?rev=683745&view=auto
==============================================================================
--- 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java
 (added)
+++ 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java
 Thu Aug  7 16:21:46 2008
@@ -0,0 +1,472 @@
+package org.apache.ibatis.executor.resultset;
+
+import org.apache.ibatis.cache.CacheKey;
+import org.apache.ibatis.mapping.Configuration;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.executor.loader.*;
+import org.apache.ibatis.executor.parameter.ParameterHandler;
+import org.apache.ibatis.executor.result.*;
+import org.apache.ibatis.mapping.*;
+import org.apache.ibatis.reflection.*;
+import org.apache.ibatis.type.*;
+
+import java.sql.*;
+import java.util.*;
+
+public class DefaultResultSetHandler implements ResultSetHandler {
+
+  private static final Object NO_VALUE = new Object();
+
+  private final Executor executor;
+  private final ObjectFactory objectFactory;
+  private final TypeHandlerRegistry typeHandlerRegistry;
+  private final MappedStatement mappedStatement;
+  private final int rowOffset;
+  private final int rowLimit;
+  private final Object parameterObject;
+
+  private final Map nestedResultObjects;
+  private CacheKey currentNestedKey;
+
+  private ResultHandler resultHandler;
+
+  private Reference<Boolean> foundValues;
+
+  public DefaultResultSetHandler(Executor executor, MappedStatement 
mappedStatement, ParameterHandler parameterHandler, int rowOffset, int 
rowLimit, ResultHandler resultHandler) {
+    this.executor = executor;
+    this.objectFactory = mappedStatement.getConfiguration().getObjectFactory();
+    this.typeHandlerRegistry = 
mappedStatement.getConfiguration().getTypeHandlerRegistry();
+    this.mappedStatement = mappedStatement;
+    this.rowOffset = rowOffset;
+    this.rowLimit = rowLimit;
+    this.parameterObject = parameterHandler.getParameterObject();
+    this.nestedResultObjects = new HashMap();
+    this.resultHandler = resultHandler;
+    this.foundValues = new Reference<Boolean>(false);
+  }
+
+  public List handleResultSets(Statement statement) throws SQLException {
+    List<List> resultsList = new ArrayList<List>();
+    ResultSet rs = getFirstResultSet(statement);
+    if (rs != null) {
+      try {
+        for (int i = 0, n = mappedStatement.getResultMaps().size(); i < n; 
i++) {
+          ResultMap resultMap = mappedStatement.getResultMaps().get(i);
+          if (resultHandler == null) {
+            DefaultResultHandler defaultResultHandler = new 
DefaultResultHandler();
+            handleResults(rs, resultMap, defaultResultHandler, rowOffset, 
rowLimit);
+            resultsList.add(defaultResultHandler.getResultList());
+          } else {
+            handleResults(rs, resultMap, resultHandler, rowOffset, rowLimit);
+          }
+          if (moveToNextResultsSafely(statement)) {
+            rs = statement.getResultSet();
+            nestedResultObjects.clear();
+          } else {
+            break;
+          }
+        }
+      } finally {
+        closeResultSet(rs);
+      }
+    }
+    if (resultsList.size() == 1) {
+      return resultsList.get(0);
+    } else {
+      return resultsList;
+    }
+  }
+
+  public void handleOutputParameters(CallableStatement callableStatement) 
throws SQLException {
+    ParameterMap parameterMap = mappedStatement.getParameterMap();
+    MetaObject metaParam = MetaObject.forObject(parameterObject);
+    List<ParameterMapping> parameterMappings = 
mappedStatement.getDynamicParameterMappings(parameterObject);
+    for (int i = 0; i < parameterMappings.size(); i++) {
+      ParameterMapping parameterMapping = parameterMappings.get(i);
+      if (parameterMapping.getMode() == ParameterMode.OUT || 
parameterMapping.getMode() == ParameterMode.INOUT) {
+        if 
("java.sql.ResultSet".equalsIgnoreCase(parameterMapping.getJavaType().getName()))
 {
+          // TODO: We need an easy way to unit test this without installing 
Oracle.
+          // Mocks are obvious, but will they be effective enough?  DBunit?
+          ResultSet rs = (ResultSet) callableStatement.getObject(i + 1);
+          ResultMap resultMap = 
mappedStatement.getConfiguration().getResultMap(parameterMapping.getResultMapId());
+          if (resultMap == null) {
+            throw new RuntimeException("Parameter requires ResultMap for 
output types of java.sql.ResultSet");
+          } else {
+            DefaultResultHandler resultHandler = new DefaultResultHandler();
+            handleResults(rs, resultMap, resultHandler, 
Executor.NO_ROW_OFFSET, Executor.NO_ROW_LIMIT);
+            metaParam.setValue(parameterMapping.getProperty(), 
resultHandler.getResultList());
+          }
+          rs.close();
+        } else {
+          metaParam.setValue(parameterMapping.getProperty(), 
parameterMapping.getTypeHandler().getResult(callableStatement, i + 1));
+        }
+      }
+    }
+  }
+
+  private void handleResults(ResultSet rs, ResultMap resultMap, ResultHandler 
resultHandler, int skipResults, int maxResults) throws SQLException {
+    if (resultMap != null) {
+      skipResults(rs, skipResults);
+      int resultsFetched = 0;
+      while ((maxResults == Executor.NO_ROW_LIMIT || resultsFetched < 
maxResults) && rs.next()) {
+        currentNestedKey = null;
+        ResultMap rm = resolveSubMap(rs, resultMap);
+        Object resultObject = loadResultObject(rs, rm);
+        if (resultObject != NO_VALUE) {
+          if (resultObject instanceof PlatformTypeHolder) {
+            resultObject = ((PlatformTypeHolder) resultObject).get(null);
+          }
+          resultHandler.handleResult(resultObject);
+        }
+        resultsFetched++;
+      }
+    }
+  }
+
+  private Object loadResultObject(ResultSet rs, ResultMap rm) throws 
SQLException {
+    if (rm.getType() == null) {
+      throw new RuntimeException("The result class was null when trying to get 
results for ResultMap.");
+    }
+
+    Object resultObject = createResultObject(rs, rm);
+    ResultLoaderRegistry lazyLoader = null;
+    if (this.mappedStatement.getConfiguration().isEnhancementEnabled()) {
+      lazyLoader = new ResultLoaderRegistry();
+      resultObject = ResultObjectProxy.createProxy(rm.getType(), resultObject, 
lazyLoader);
+    }
+
+    // Rethink this implementation of foundValues.  It's the only volatile 
state on the class...
+    foundValues = new Reference<Boolean>(false);
+    List<ResultMapping> appliedResultMappings = new ArrayList<ResultMapping>();
+    resultObject = mapResults(rs, rm, lazyLoader, resultObject, 
appliedResultMappings);
+    resultObject = processNestedJoinResults(rs, appliedResultMappings, 
resultObject);
+    return resultObject;
+  }
+
+  private Object mapResults(ResultSet rs, ResultMap rm, ResultLoaderRegistry 
lazyLoader, Object resultObject, List<ResultMapping> appliedResultMappings) 
throws SQLException {
+    MetaObject metaResultObject = MetaObject.forObject(resultObject);
+    Set<String> propSet = new HashSet<String>();
+    Set<String> colSet = new HashSet<String>();
+    Map<String, ResultMapping> autoMappings = new HashMap<String, 
ResultMapping>();
+    ResultSetMetaData rsmd = rs.getMetaData();
+    for (int i = 1, n = rsmd.getColumnCount(); i <= n; i++) {
+      boolean useLabel = mappedStatement.getConfiguration().isUseColumnLabel();
+      String columnLabel = (useLabel ? rsmd.getColumnLabel(i) : 
rsmd.getColumnName(i));
+      columnLabel.toUpperCase();
+      String propName = metaResultObject.findProperty(columnLabel);
+      colSet.add(columnLabel);
+      if (propName != null) {
+        propSet.add(propName);
+        Class javaType = metaResultObject.getSetterType(propName);
+        TypeHandler typeHandler = typeHandlerRegistry.getTypeHandler(javaType);
+        ResultMapping resultMapping = new ResultMapping.Builder(propName, 
columnLabel, typeHandler)
+            .javaType(javaType).build();
+        autoMappings.put(propName, resultMapping);
+      }
+    }
+    // Map results/ignore missing
+    for (ResultMapping resultMapping : rm.getPropertyResultMappings()) {
+      String propName = resultMapping.getProperty();
+      String colName = resultMapping.getColumn();
+      colName = colName == null ? null : colName.toUpperCase();
+      autoMappings.remove(propName);
+      if (colName == null || colSet.contains(colName)) {
+        resultObject = processResult(rs, rm, resultMapping, lazyLoader, 
resultObject);
+        appliedResultMappings.add(resultMapping);
+      }
+    }
+    // Automap remaining results
+    for (String key : autoMappings.keySet()) {
+      ResultMapping autoMapping = autoMappings.get(key);
+      resultObject = processResult(rs, rm, autoMapping, lazyLoader, 
resultObject);
+      appliedResultMappings.add(autoMapping);
+    }
+    return resultObject;
+  }
+
+  private Object createResultObject(ResultSet rs, ResultMap rm) throws 
SQLException {
+    if (PlatformTypeHolder.isPlatformType(rm.getType())) {
+      return new PlatformTypeHolder();
+    }
+    Object resultObject;
+    if (rm.getConstructorResultMappings().size() > 0) {
+      Map<String, Object> constructorArgs = new HashMap<String, Object>();
+      List<Class> argTypes = new ArrayList<Class>();
+      List<Object> argValues = new ArrayList<Object>();
+      for (ResultMapping resultMapping : rm.getConstructorResultMappings()) {
+        processResult(rs, rm, resultMapping, null, constructorArgs);
+        argTypes.add(resultMapping.getJavaType());
+        argValues.add(constructorArgs.get(resultMapping.getProperty()));
+      }
+      resultObject = objectFactory.create(rm.getType(), argTypes, argValues);
+    } else {
+      resultObject = objectFactory.create(rm.getType());
+    }
+    return resultObject;
+  }
+
+  private Object processNestedSelectResult(MappedStatement nestedQuery, 
ResultMap rm, ResultMapping resultMapping, ResultLoaderRegistry lazyLoader, 
Object parameterObject, Object resultObject) {
+    MetaObject metaResultObject = MetaObject.forObject(resultObject);
+    Object value = null;
+    try {
+      if (parameterObject != null) {
+        CacheKey key = executor.createCacheKey(nestedQuery, parameterObject, 
Executor.NO_ROW_OFFSET, Executor.NO_ROW_LIMIT);
+        if (executor.isCached(nestedQuery, key)) {
+          executor.deferLoad(nestedQuery, metaResultObject, 
resultMapping.getProperty(), key);
+        } else {
+          ResultLoader resultLoader = new ResultLoader(executor, nestedQuery, 
parameterObject, resultMapping.getJavaType());
+          if (lazyLoader == null) {
+            value = resultLoader.loadResult();
+          } else {
+            lazyLoader.registerLoader(resultMapping.getProperty(), 
metaResultObject, resultLoader);
+          }
+        }
+      }
+    } catch (Exception e) {
+      throw new RuntimeException("Error setting nested bean property.  Cause: 
" + e, e);
+    }
+    if (typeHandlerRegistry.hasTypeHandler(rm.getType())) {
+      resultObject = value;
+    } else if (value != null) {
+      metaResultObject.setValue(resultMapping.getProperty(), value);
+    }
+    return resultObject;
+  }
+
+  private Object processResult(ResultSet rs, ResultMap rm, ResultMapping 
resultMapping, ResultLoaderRegistry lazyLoader, Object resultObject) throws 
SQLException {
+    if (resultMapping.getNestedQueryId() != null) {
+      Configuration configuration = mappedStatement.getConfiguration();
+      MappedStatement nestedQuery = 
configuration.getMappedStatement(resultMapping.getNestedQueryId());
+      Class parameterType = nestedQuery.getParameterMap().getType();
+      Object parameterObject = prepareNestedParameterObject(rs, resultMapping, 
parameterType);
+      resultObject = processNestedSelectResult(nestedQuery, rm, resultMapping, 
lazyLoader, parameterObject, resultObject);
+    } else if (resultMapping.getNestedResultMapId() == null) {
+      resultObject = processSimpleResult(rs, rm, resultMapping, resultObject);
+    }
+    return resultObject;
+  }
+
+  private Object processSimpleResult(ResultSet rs, ResultMap rm, ResultMapping 
resultMapping, Object resultObject) throws SQLException {
+    MetaObject metaResultObject = MetaObject.forObject(resultObject);
+    Object value = getPrimitiveResultMappingValue(rs, resultMapping);
+    if (typeHandlerRegistry.hasTypeHandler(rm.getType())) {
+      resultObject = value;
+    } else if (value != null) {
+      metaResultObject.setValue(resultMapping.getProperty(), value);
+    }
+    foundValues.set(value != null || foundValues.get());
+    return resultObject;
+  }
+
+  private Object processNestedJoinResults(ResultSet rs, List<ResultMapping> 
resultMappings, Object resultObject) {
+    CacheKey previousKey = currentNestedKey;
+    try {
+      currentNestedKey = createUniqueResultKey(resultMappings, resultObject, 
currentNestedKey);
+      if (nestedResultObjects.containsKey(currentNestedKey)) {
+        // Unique key is already known, so get the existing result object and 
process additional results.
+        resultObject = NO_VALUE;
+      } else if (currentNestedKey != null) {
+        // Unique key is NOT known, so create a new result object and then 
process additional results.
+        nestedResultObjects.put(currentNestedKey, resultObject);
+      }
+      Object knownResultObject = nestedResultObjects.get(currentNestedKey);
+      if (knownResultObject != null && knownResultObject != NO_VALUE) {
+        for (ResultMapping resultMapping : resultMappings) {
+          Configuration configuration = mappedStatement.getConfiguration();
+          ResultMap nestedResultMap = 
configuration.getResultMap(resultMapping.getNestedResultMapId());
+          if (nestedResultMap != null) {
+            try {
+
+              // get the discriminated submap if it exists
+              nestedResultMap = resolveSubMap(rs, nestedResultMap);
+
+              Class type = resultMapping.getJavaType();
+              String propertyName = resultMapping.getProperty();
+
+              MetaObject metaObject = MetaObject.forObject(knownResultObject);
+              Object obj = metaObject.getValue(propertyName);
+              if (obj == null) {
+                if (type == null) {
+                  type = metaObject.getSetterType(propertyName);
+                }
+
+                try {
+                  // create the object if is it a Collection.  If not a 
Collection
+                  // then we will just set the property to the object created
+                  // in processing the nested result map
+                  if (Collection.class.isAssignableFrom(type)) {
+                    obj = objectFactory.create(type);
+                    metaObject.setValue(propertyName, obj);
+                  }
+                } catch (Exception e) {
+                  throw new RuntimeException("Error instantiating collection 
property for result '" + resultMapping.getProperty() + "'.  Cause: " + e, e);
+                }
+              }
+
+              Object o = loadResultObject(rs, nestedResultMap);
+              if (o != null && o != NO_VALUE) {
+                if (obj != null && obj instanceof Collection) {
+                  if (foundValues.get()) {
+                    ((Collection) obj).add(o);
+                  }
+                } else {
+                  metaObject.setValue(propertyName, o);
+                }
+              }
+            } catch (SQLException e) {
+              throw new RuntimeException("Error getting nested result map 
values for '" + resultMapping.getProperty() + "'.  Cause: " + e, e);
+            }
+          }
+        }
+      }
+    } finally {
+      currentNestedKey = previousKey;
+    }
+    return resultObject;
+  }
+
+  private Object prepareNestedParameterObject(ResultSet rs, ResultMapping 
resultMapping, Class parameterType) throws SQLException {
+    Object parameterObject;
+    if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
+      TypeHandler th = typeHandlerRegistry.getTypeHandler(parameterType);
+      parameterObject = th.getResult(rs, resultMapping.getColumn());
+    } else {
+      if (parameterType == null) {
+        parameterObject = new HashMap();
+      } else {
+        parameterObject = objectFactory.create(parameterType);
+      }
+      if (resultMapping.isCompositeResult()) {
+        MetaObject metaObject = MetaObject.forObject(parameterObject);
+        for (ResultMapping innerResultMapping : resultMapping.getComposites()) 
{
+          Class propType = 
metaObject.getSetterType(innerResultMapping.getProperty());
+          TypeHandler typeHandler = 
typeHandlerRegistry.getTypeHandler(propType);
+          Object propValue = typeHandler.getResult(rs, 
innerResultMapping.getColumn());
+          metaObject.setValue(innerResultMapping.getProperty(), propValue);
+        }
+      } else {
+        String columnName = resultMapping.getColumn();
+        TypeHandler typeHandler = 
typeHandlerRegistry.getTypeHandler(parameterType);
+        if (typeHandler == null) {
+          typeHandler = typeHandlerRegistry.getUnkownTypeHandler();
+        }
+        parameterObject = typeHandler.getResult(rs, columnName);
+      }
+    }
+    return parameterObject;
+  }
+
+  //////////////////////////////////////////
+  // UTILITY METHODS
+  //////////////////////////////////////////
+
+  private ResultMap resolveSubMap(ResultSet rs, ResultMap rm) throws 
SQLException {
+    ResultMap subMap = rm;
+    Discriminator discriminator = rm.getDiscriminator();
+    if (discriminator != null) {
+      ResultMapping resultMapping = discriminator.getResultMapping();
+      Object value = getPrimitiveResultMappingValue(rs, resultMapping);
+      String subMapId = discriminator.getMapIdFor(String.valueOf(value));
+      subMap = mappedStatement.getConfiguration().getResultMap(subMapId);
+
+      if (subMap == null) {
+        subMap = rm;
+      } else if (subMap != rm) {
+        subMap = resolveSubMap(rs, subMap);
+      }
+    }
+    return subMap;
+  }
+
+  private Object getPrimitiveResultMappingValue(ResultSet rs, ResultMapping 
resultMapping) throws SQLException {
+    Object value;
+    TypeHandler typeHandler = resultMapping.getTypeHandler();
+    if (typeHandler != null) {
+      value = typeHandler.getResult(rs, resultMapping.getColumn());
+    } else {
+      throw new RuntimeException("No type handler could be found to map the 
property '" + resultMapping.getProperty() + "' to the column '" + 
resultMapping.getColumn() + "'.  One or both of the types, or the combination 
of types is not supported.");
+    }
+    return value;
+  }
+
+  private CacheKey createUniqueResultKey(List<ResultMapping> resultMappings, 
Object resultObject, CacheKey parentCacheKey) {
+    if (resultObject == null) {
+      return null;
+    } else {
+      MetaObject metaResultObject = MetaObject.forObject(resultObject);
+      CacheKey cacheKey = new CacheKey();
+      cacheKey.update(parentCacheKey);
+      boolean updated = false;
+      if (typeHandlerRegistry.hasTypeHandler(resultObject.getClass())) {
+        cacheKey.update(resultObject);
+      } else {
+        for (ResultMapping resultMapping : resultMappings) {
+          if (resultMapping.getNestedQueryId() == null) {
+            String propName = resultMapping.getProperty();
+            if (propName != null) {
+              cacheKey.update(metaResultObject.getValue(propName));
+              updated = true;
+            }
+          }
+        }
+      }
+      return updated ? cacheKey : null;
+    }
+  }
+
+  private ResultSet getFirstResultSet(Statement statement) throws SQLException 
{
+    ResultSet rs = null;
+    boolean hasMoreResults = true;
+    while (hasMoreResults) {
+      rs = statement.getResultSet();
+      if (rs != null) {
+        break;
+      }
+      // This is the messed up JDBC approach for determining if there are more 
results
+      hasMoreResults = !((!moveToNextResultsSafely(statement)) && 
(statement.getUpdateCount() == -1));
+    }
+    return rs;
+  }
+
+  private boolean moveToNextResultsSafely(Statement statement) throws 
SQLException {
+    if (mappedStatement.getConfiguration().isMultipleResultSetsEnabled()) {
+      return statement.getMoreResults();
+    }
+    return false;
+  }
+
+  private void skipResults(ResultSet rs, int skipResults) throws SQLException {
+    if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
+      if (skipResults > 0) {
+        rs.absolute(skipResults);
+      }
+    } else {
+      for (int i = 0; i < skipResults; i++) {
+        if (!rs.next()) break;
+      }
+    }
+  }
+
+  private void closeResultSet(ResultSet rs) {
+    if (rs != null) {
+      try {
+        rs.close();
+      } catch (SQLException e) {
+        // ignore
+      }
+    }
+  }
+
+  private static class Reference<T> {
+    private T value;
+    private Reference(T value) {
+      this.value = value;
+    }
+    public T get() {
+      return value;
+    }
+    public void set(T value) {
+      this.value = value;
+    }
+  }
+}

Added: 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/PlatformTypeHolder.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/PlatformTypeHolder.java?rev=683745&view=auto
==============================================================================
--- 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/PlatformTypeHolder.java
 (added)
+++ 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/PlatformTypeHolder.java
 Thu Aug  7 16:21:46 2008
@@ -0,0 +1,128 @@
+package org.apache.ibatis.executor.resultset;
+
+import java.math.BigDecimal;
+import java.util.*;
+
+public class PlatformTypeHolder implements Map {
+
+  private static final Set<Class> platformTypes = new HashSet<Class>() {
+    {
+      add(byte[].class);
+      add(byte.class);
+      add(short.class);
+      add(int.class);
+      add(long.class);
+      add(float.class);
+      add(double.class);
+      add(boolean.class);
+      add(Byte.class);
+      add(Short.class);
+      add(Integer.class);
+      add(Long.class);
+      add(Float.class);
+      add(Double.class);
+      add(Boolean.class);
+
+      add(String.class);
+      add(BigDecimal.class);
+      add(Date.class);
+      add(Object.class);
+
+      add(java.sql.Date.class);
+      add(java.sql.Time.class);
+      add(java.sql.Timestamp.class);
+    }
+  };
+
+  private Object key;
+  private Object value;
+
+  public static boolean isPlatformType(Class type) {
+    return platformTypes.contains(type);
+  }
+
+  public int size() {
+    return 1;
+  }
+
+  public boolean isEmpty() {
+    return key == null && value == null;
+  }
+
+  public boolean containsKey(Object other) {
+    return key == null ? other == null : key.equals(other);
+  }
+
+  public boolean containsValue(Object other) {
+    return value == null ? other == null : value.equals(other);
+  }
+
+  public Object get(Object key) {
+    return value;
+  }
+
+  public Object put(Object key, Object value) {
+    Object old = this.value;
+    this.key = key;
+    this.value = value;
+    return old;
+  }
+
+  public Object remove(Object key) {
+    Object old = this.value;
+    this.key = null;
+    this.value = null;
+    return old;
+  }
+
+  public void putAll(Map t) {
+    for (Map.Entry e : (Set<Map.Entry>) t.entrySet()) {
+      this.key = e.getKey();
+      this.value = e.getValue();
+    }
+  }
+
+  public void clear() {
+    this.key = null;
+    this.value = null;
+  }
+
+  public Set keySet() {
+    return new HashSet() {
+      {
+        add(key);
+      }
+    };
+  }
+
+  public Collection values() {
+    return new ArrayList() {
+      {
+        add(value);
+      }
+    };
+  }
+
+  public Set entrySet() {
+    final Map.Entry entry = new Map.Entry() {
+      public Object getKey() {
+        return key;
+      }
+
+      public Object getValue() {
+        return value;
+      }
+
+      public Object setValue(Object v) {
+        Object old = value;
+        value = v;
+        return old;
+      }
+    };
+    return new HashSet() {
+      {
+        add(entry);
+      }
+    };
+  }
+}

Added: 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/ResultSetHandler.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/ResultSetHandler.java?rev=683745&view=auto
==============================================================================
--- 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/ResultSetHandler.java
 (added)
+++ 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/resultset/ResultSetHandler.java
 Thu Aug  7 16:21:46 2008
@@ -0,0 +1,12 @@
+package org.apache.ibatis.executor.resultset;
+
+import java.sql.*;
+import java.util.List;
+
+public interface ResultSetHandler {
+
+  List handleResultSets(Statement stmt) throws SQLException;
+
+  void handleOutputParameters(CallableStatement cs) throws SQLException;
+
+}

Added: 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/BaseStatementHandler.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/BaseStatementHandler.java?rev=683745&view=auto
==============================================================================
--- 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/BaseStatementHandler.java
 (added)
+++ 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/BaseStatementHandler.java
 Thu Aug  7 16:21:46 2008
@@ -0,0 +1,126 @@
+package org.apache.ibatis.executor.statement;
+
+import org.apache.ibatis.mapping.Configuration;
+import org.apache.ibatis.executor.*;
+import org.apache.ibatis.executor.parameter.ParameterHandler;
+import org.apache.ibatis.executor.result.ResultHandler;
+import org.apache.ibatis.executor.resultset.ResultSetHandler;
+import org.apache.ibatis.mapping.*;
+import org.apache.ibatis.reflection.ObjectFactory;
+import org.apache.ibatis.type.TypeHandlerRegistry;
+
+import java.sql.*;
+
+public abstract class BaseStatementHandler implements StatementHandler {
+
+  protected final ErrorContext errorContext;
+  protected final ObjectFactory objectFactory;
+  protected final TypeHandlerRegistry typeHandlerRegistry;
+  protected final ResultSetHandler resultSetHandler;
+  protected final ParameterHandler parameterHandler;
+
+  protected final Executor executor;
+  protected final MappedStatement mappedStatement;
+  protected final Object parameterObject;
+  protected final int rowOffset;
+  protected final int rowLimit;
+  protected final String sql;
+
+  protected BaseStatementHandler(Executor executor, MappedStatement 
mappedStatement, Object parameterObject, int rowOffset, int rowLimit, 
ResultHandler resultHandler) {
+    this.executor = executor;
+    this.mappedStatement = mappedStatement;
+    this.parameterObject = parameterObject;
+    this.rowOffset = rowOffset;
+    this.rowLimit = rowLimit;
+
+    Configuration configuration = mappedStatement.getConfiguration();
+    this.errorContext = new ErrorContext();
+    this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
+    this.objectFactory = configuration.getObjectFactory();
+    this.parameterHandler = configuration.newParameterHandler(mappedStatement, 
parameterObject);
+    this.resultSetHandler = configuration.newResultSetHandler(executor, 
mappedStatement, rowOffset, rowLimit, parameterHandler, resultHandler);
+
+    this.sql = mappedStatement.getSql(parameterObject);
+  }
+
+  public String getSql() {
+    return sql;
+  }
+
+  public ParameterHandler getParameterHandler() {
+    return parameterHandler;
+  }
+
+  public Statement prepare(Connection connection)
+      throws SQLException {
+    Statement statement = null;
+    try {
+      statement = instantiateStatement(connection);
+      setStatementTimeout(statement);
+      setFetchSize(statement);
+      return statement;
+    } catch (SQLException e) {
+      closeStatement(statement);
+      throw e;
+    } catch (Exception e) {
+      closeStatement(statement);
+      throw new RuntimeException("Error preparing statement.  Cause: " + e, e);
+    }
+  }
+
+  protected abstract Statement instantiateStatement(Connection connection)
+      throws SQLException;
+
+
+  protected Integer processGeneratedKeys(MappedStatement ms, Statement stmt, 
Object parameter) throws SQLException {
+    if (ms.getConfiguration().isGeneratedKeysEnabled()) {
+      ResultSet rs = stmt.getGeneratedKeys();
+      try {
+        while (rs.next()) {
+          Object object = rs.getObject(1);
+          if (object != null) {
+            return Integer.parseInt(object.toString());
+          }
+        }
+      } finally {
+        try {
+          if (rs != null) rs.close();
+        } catch (Exception e) {
+          //ignore
+        }
+      }
+    }
+    return null;
+  }
+
+  protected void setStatementTimeout(Statement stmt)
+      throws SQLException {
+    Integer timeout = mappedStatement.getTimeout();
+    Integer defaultTimeout = 
mappedStatement.getConfiguration().getDefaultStatementTimeout();
+    if (timeout != null) {
+      stmt.setQueryTimeout(timeout);
+    } else if (defaultTimeout != null) {
+      stmt.setQueryTimeout(defaultTimeout);
+    }
+  }
+
+  protected void setFetchSize(Statement stmt)
+      throws SQLException {
+    Integer fetchSize = mappedStatement.getFetchSize();
+    if (fetchSize != null) {
+      stmt.setFetchSize(fetchSize);
+    }
+  }
+
+  protected void closeStatement(Statement statement) {
+    try {
+      if (statement != null) {
+        statement.close();
+      }
+    } catch (SQLException e) {
+      //ignore
+    }
+
+  }
+
+}

Added: 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/CallableStatementHandler.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/CallableStatementHandler.java?rev=683745&view=auto
==============================================================================
--- 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/CallableStatementHandler.java
 (added)
+++ 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/CallableStatementHandler.java
 Thu Aug  7 16:21:46 2008
@@ -0,0 +1,72 @@
+package org.apache.ibatis.executor.statement;
+
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.executor.result.ResultHandler;
+import org.apache.ibatis.mapping.*;
+import org.apache.ibatis.type.JdbcType;
+
+import java.sql.*;
+import java.util.List;
+
+public class CallableStatementHandler extends BaseStatementHandler {
+
+  public CallableStatementHandler(Executor executor, MappedStatement 
mappedStatement, Object parameter, int rowOffset, int rowLimit, ResultHandler 
resultHandler) {
+    super(executor, mappedStatement, parameter, rowOffset, rowLimit, 
resultHandler);
+  }
+
+  public int update(Statement statement)
+      throws SQLException {
+    CallableStatement cs = (CallableStatement) statement;
+    cs.execute();
+    int rows = cs.getUpdateCount();
+    resultSetHandler.handleOutputParameters(cs);
+    return rows;
+  }
+
+  public void batch(Statement statement)
+      throws SQLException {
+    CallableStatement cs = (CallableStatement) statement;
+    cs.addBatch();
+  }
+
+  public List query(Statement statement, ResultHandler resultHandler)
+      throws SQLException {
+    CallableStatement cs = (CallableStatement) statement;
+    cs.execute();
+    resultSetHandler.handleOutputParameters(cs);
+    return resultSetHandler.handleResultSets(cs);
+  }
+
+  protected Statement instantiateStatement(Connection connection) throws 
SQLException {
+    if (mappedStatement.getResultSetType() != null) {
+      return connection.prepareCall(sql, 
mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
+    } else {
+      return connection.prepareCall(sql);
+    }
+  }
+
+  public void parameterize(Statement statement) throws SQLException {
+    registerOutputParameters((CallableStatement) statement, mappedStatement);
+    parameterHandler.setParameters((CallableStatement) statement);
+  }
+
+  private void registerOutputParameters(CallableStatement cs, MappedStatement 
ms) throws SQLException {
+    List<ParameterMapping> parameterMappings = 
ms.getDynamicParameterMappings(parameterObject);
+    for (int i = 0, n = parameterMappings.size(); i < n; i++) {
+      ParameterMapping parameterMapping = parameterMappings.get(i);
+      if (parameterMapping.getMode() == ParameterMode.OUT || 
parameterMapping.getMode() == ParameterMode.INOUT) {
+        if (null == parameterMapping.getJdbcType()) {
+          throw new SQLException("The JDBC Type must be specified for output 
parameterArray.  Paramter: " + parameterMapping.getProperty());
+        } else {
+          if (parameterMapping.getNumericScale() != null && 
(parameterMapping.getJdbcType() == JdbcType.NUMERIC || 
parameterMapping.getJdbcType() == JdbcType.DECIMAL)) {
+            cs.registerOutParameter(i + 1, 
parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getNumericScale());
+          } else {
+            //cs.registerOutParameter(i + 1, 
parameter.getJdbcType().TYPE_CODE, parameter.getJdbcType().toString());
+            cs.registerOutParameter(i + 1, 
parameterMapping.getJdbcType().TYPE_CODE);
+          }
+        }
+      }
+    }
+  }
+
+}

Added: 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/PreparedStatementHandler.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/PreparedStatementHandler.java?rev=683745&view=auto
==============================================================================
--- 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/PreparedStatementHandler.java
 (added)
+++ 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/PreparedStatementHandler.java
 Thu Aug  7 16:21:46 2008
@@ -0,0 +1,55 @@
+package org.apache.ibatis.executor.statement;
+
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.executor.result.ResultHandler;
+import org.apache.ibatis.mapping.MappedStatement;
+
+import java.sql.*;
+import java.util.List;
+
+public class PreparedStatementHandler extends BaseStatementHandler {
+
+  public PreparedStatementHandler(Executor executor, MappedStatement 
mappedStatement, Object parameter, int rowOffset, int rowLimit, ResultHandler 
resultHandler) {
+    super(executor, mappedStatement, parameter, rowOffset, rowLimit, 
resultHandler);
+  }
+
+  public int update(Statement statement)
+      throws SQLException {
+    PreparedStatement ps = (PreparedStatement) statement;
+    ps.execute();
+    int result = ps.getUpdateCount();
+    if (mappedStatement.getConfiguration().isGeneratedKeysEnabled()) {
+      result = processGeneratedKeys(mappedStatement, ps, parameterObject);
+    }
+    return result;
+  }
+
+  public void batch(Statement statement)
+      throws SQLException {
+    PreparedStatement ps = (PreparedStatement) statement;
+    ps.addBatch();
+  }
+
+  public List query(Statement statement, ResultHandler resultHandler)
+      throws SQLException {
+    PreparedStatement ps = (PreparedStatement) statement;
+    ps.execute();
+    return resultSetHandler.handleResultSets(ps);
+  }
+
+  protected Statement instantiateStatement(Connection connection) throws 
SQLException {
+    if (mappedStatement.getConfiguration().isGeneratedKeysEnabled()) {
+      return connection.prepareStatement(sql, 
PreparedStatement.RETURN_GENERATED_KEYS);
+    } else if (mappedStatement.getResultSetType() != null) {
+      return connection.prepareStatement(sql, 
mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
+    } else {
+      return connection.prepareStatement(sql);
+    }
+  }
+
+  public void parameterize(Statement statement)
+      throws SQLException {
+    parameterHandler.setParameters((PreparedStatement) statement);
+  }
+
+}

Added: 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/RoutingStatementHandler.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/RoutingStatementHandler.java?rev=683745&view=auto
==============================================================================
--- 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/RoutingStatementHandler.java
 (added)
+++ 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/RoutingStatementHandler.java
 Thu Aug  7 16:21:46 2008
@@ -0,0 +1,60 @@
+package org.apache.ibatis.executor.statement;
+
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.executor.parameter.ParameterHandler;
+import org.apache.ibatis.executor.result.ResultHandler;
+import org.apache.ibatis.mapping.MappedStatement;
+
+import java.sql.*;
+import java.util.List;
+
+public class RoutingStatementHandler implements StatementHandler {
+
+  private final StatementHandler delegate;
+
+  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object 
parameter, int rowOffset, int rowLimit, ResultHandler resultHandler) {
+
+    switch (ms.getStatementType()) {
+      case STATEMENT:
+        delegate = new SimpleStatementHandler(executor, ms, parameter, 
rowOffset, rowLimit, resultHandler);
+        break;
+      case PREPARED:
+        delegate = new PreparedStatementHandler(executor, ms, parameter, 
rowOffset, rowLimit, resultHandler);
+        break;
+      case CALLABLE:
+        delegate = new CallableStatementHandler(executor, ms, parameter, 
rowOffset, rowLimit, resultHandler);
+        break;
+      default:
+        throw new RuntimeException("Unknown statement type: " + 
ms.getStatementType());
+    }
+
+  }
+
+  public Statement prepare(Connection connection) throws SQLException {
+    return delegate.prepare(connection);
+  }
+
+  public void parameterize(Statement statement) throws SQLException {
+    delegate.parameterize(statement);
+  }
+
+  public void batch(Statement statement) throws SQLException {
+    delegate.batch(statement);
+  }
+
+  public int update(Statement statement) throws SQLException {
+    return delegate.update(statement);
+  }
+
+  public List query(Statement statement, ResultHandler resultHandler) throws 
SQLException {
+    return delegate.query(statement, resultHandler);
+  }
+
+  public String getSql() {
+    return delegate.getSql();
+  }
+
+  public ParameterHandler getParameterHandler() {
+    return delegate.getParameterHandler();
+  }
+}

Added: 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/SimpleStatementHandler.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/SimpleStatementHandler.java?rev=683745&view=auto
==============================================================================
--- 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/SimpleStatementHandler.java
 (added)
+++ 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/SimpleStatementHandler.java
 Thu Aug  7 16:21:46 2008
@@ -0,0 +1,53 @@
+package org.apache.ibatis.executor.statement;
+
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.executor.result.ResultHandler;
+import org.apache.ibatis.mapping.MappedStatement;
+
+import java.sql.*;
+import java.util.List;
+
+public class SimpleStatementHandler extends BaseStatementHandler {
+
+  public SimpleStatementHandler(Executor executor, MappedStatement 
mappedStatement, Object parameter, int rowOffset, int rowLimit, ResultHandler 
resultHandler) {
+    super(executor, mappedStatement, parameter, rowOffset, rowLimit, 
resultHandler);
+  }
+
+  public int update(Statement statement)
+      throws SQLException {
+    if (mappedStatement.getConfiguration().isGeneratedKeysEnabled()) {
+      statement.execute(mappedStatement.getSql(parameterObject), 
Statement.RETURN_GENERATED_KEYS);
+    } else {
+      statement.execute(mappedStatement.getSql(parameterObject));
+    }
+    int result = statement.getUpdateCount();
+    if (mappedStatement.getConfiguration().isGeneratedKeysEnabled()) {
+      result = processGeneratedKeys(mappedStatement, statement, 
parameterObject);
+    }
+    return result;
+  }
+
+  public void batch(Statement statement)
+      throws SQLException {
+    statement.addBatch(mappedStatement.getSql(parameterObject));
+  }
+
+  public List query(Statement statement, ResultHandler resultHandler)
+      throws SQLException {
+    statement.execute(mappedStatement.getSql(parameterObject));
+    return resultSetHandler.handleResultSets(statement);
+  }
+
+  protected Statement instantiateStatement(Connection connection) throws 
SQLException {
+    if (mappedStatement.getResultSetType() != null) {
+      return 
connection.createStatement(mappedStatement.getResultSetType().getValue(), 
ResultSet.CONCUR_READ_ONLY);
+    } else {
+      return connection.createStatement();
+    }
+  }
+
+  public void parameterize(Statement statement) throws SQLException {
+    // N/A
+  }
+
+}

Added: 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/StatementHandler.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/StatementHandler.java?rev=683745&view=auto
==============================================================================
--- 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/StatementHandler.java
 (added)
+++ 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/executor/statement/StatementHandler.java
 Thu Aug  7 16:21:46 2008
@@ -0,0 +1,30 @@
+package org.apache.ibatis.executor.statement;
+
+import org.apache.ibatis.executor.parameter.ParameterHandler;
+import org.apache.ibatis.executor.result.ResultHandler;
+
+import java.sql.*;
+import java.util.List;
+
+public interface StatementHandler {
+
+  Statement prepare(Connection connection)
+      throws SQLException;
+
+  void parameterize(Statement statement)
+      throws SQLException;
+
+  void batch(Statement statement)
+      throws SQLException;
+
+  int update(Statement statement)
+      throws SQLException;
+
+  List query(Statement statement, ResultHandler resultHandler)
+      throws SQLException;
+
+  String getSql();
+
+  ParameterHandler getParameterHandler();
+
+}

Added: 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/io/Resources.java
URL: 
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/io/Resources.java?rev=683745&view=auto
==============================================================================
--- 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/io/Resources.java
 (added)
+++ 
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/io/Resources.java
 Thu Aug  7 16:21:46 2008
@@ -0,0 +1,264 @@
+package org.apache.ibatis.io;
+
+import java.io.*;
+import java.net.*;
+import java.nio.charset.Charset;
+import java.util.Properties;
+
+/**
+ * A class to simplify access to resources through the classloader.
+ */
+public class Resources {
+
+  private static ClassLoader defaultClassLoader;
+
+  /**
+   * Charset to use when calling getResourceAsReader.
+   * null means use the system default.
+   */
+  private static Charset charset;
+
+  private Resources() {
+  }
+
+  /**
+   * Returns the default classloader (may be null).
+   *
+   * @return The default classloader
+   */
+  public static ClassLoader getDefaultClassLoader() {
+    return defaultClassLoader;
+  }
+
+  /**
+   * Sets the default classloader
+   *
+   * @param defaultClassLoader - the new default ClassLoader
+   */
+  public static void setDefaultClassLoader(ClassLoader defaultClassLoader) {
+    Resources.defaultClassLoader = defaultClassLoader;
+  }
+
+  /**
+   * Returns the URL of the resource on the classpath
+   *
+   * @param resource The resource to find
+   * @return The resource
+   * @throws java.io.IOException If the resource cannot be found or read
+   */
+  public static URL getResourceURL(String resource) throws IOException {
+    return getResourceURL(getClassLoader(), resource);
+  }
+
+  /**
+   * Returns the URL of the resource on the classpath
+   *
+   * @param loader   The classloader used to fetch the resource
+   * @param resource The resource to find
+   * @return The resource
+   * @throws java.io.IOException If the resource cannot be found or read
+   */
+  public static URL getResourceURL(ClassLoader loader, String resource) throws 
IOException {
+    URL url = null;
+    if (loader != null) url = loader.getResource(resource);
+    if (url == null) url = ClassLoader.getSystemResource(resource);
+    if (url == null) throw new IOException("Could not find resource " + 
resource);
+    return url;
+  }
+
+  /**
+   * Returns a resource on the classpath as a Stream object
+   *
+   * @param resource The resource to find
+   * @return The resource
+   * @throws java.io.IOException If the resource cannot be found or read
+   */
+  public static InputStream getResourceAsStream(String resource) throws 
IOException {
+    return getResourceAsStream(getClassLoader(), resource);
+  }
+
+  /**
+   * Returns a resource on the classpath as a Stream object
+   *
+   * @param loader   The classloader used to fetch the resource
+   * @param resource The resource to find
+   * @return The resource
+   * @throws java.io.IOException If the resource cannot be found or read
+   */
+  public static InputStream getResourceAsStream(ClassLoader loader, String 
resource) throws IOException {
+    InputStream in = null;
+    if (loader != null) in = loader.getResourceAsStream(resource);
+    if (in == null) in = ClassLoader.getSystemResourceAsStream(resource);
+    if (in == null) throw new IOException("Could not find resource " + 
resource);
+    return in;
+  }
+
+  /**
+   * Returns a resource on the classpath as a Properties object
+   *
+   * @param resource The resource to find
+   * @return The resource
+   * @throws java.io.IOException If the resource cannot be found or read
+   */
+  public static Properties getResourceAsProperties(String resource)
+      throws IOException {
+    Properties props = new Properties();
+    InputStream in = getResourceAsStream(resource);
+    props.load(in);
+    in.close();
+    return props;
+  }
+
+  /**
+   * Returns a resource on the classpath as a Properties object
+   *
+   * @param loader   The classloader used to fetch the resource
+   * @param resource The resource to find
+   * @return The resource
+   * @throws java.io.IOException If the resource cannot be found or read
+   */
+  public static Properties getResourceAsProperties(ClassLoader loader, String 
resource)
+      throws IOException {
+    Properties props = new Properties();
+    InputStream in = getResourceAsStream(loader, resource);
+    props.load(in);
+    in.close();
+    return props;
+  }
+
+  /**
+   * Returns a resource on the classpath as a Reader object
+   *
+   * @param resource The resource to find
+   * @return The resource
+   * @throws java.io.IOException If the resource cannot be found or read
+   */
+  public static Reader getResourceAsReader(String resource) throws IOException 
{
+    Reader reader;
+    if (charset == null) {
+      reader = new InputStreamReader(getResourceAsStream(resource));
+    } else {
+      reader = new InputStreamReader(getResourceAsStream(resource), charset);
+    }
+
+    return reader;
+  }
+
+  /**
+   * Returns a resource on the classpath as a Reader object
+   *
+   * @param loader   The classloader used to fetch the resource
+   * @param resource The resource to find
+   * @return The resource
+   * @throws java.io.IOException If the resource cannot be found or read
+   */
+  public static Reader getResourceAsReader(ClassLoader loader, String 
resource) throws IOException {
+    Reader reader;
+    if (charset == null) {
+      reader = new InputStreamReader(getResourceAsStream(loader, resource));
+    } else {
+      reader = new InputStreamReader(getResourceAsStream(loader, resource), 
charset);
+    }
+
+    return reader;
+  }
+
+  /**
+   * Returns a resource on the classpath as a File object
+   *
+   * @param resource The resource to find
+   * @return The resource
+   * @throws java.io.IOException If the resource cannot be found or read
+   */
+  public static File getResourceAsFile(String resource) throws IOException {
+    return new File(getResourceURL(resource).getFile());
+  }
+
+  /**
+   * Returns a resource on the classpath as a File object
+   *
+   * @param loader   - the classloader used to fetch the resource
+   * @param resource - the resource to find
+   * @return The resource
+   * @throws java.io.IOException If the resource cannot be found or read
+   */
+  public static File getResourceAsFile(ClassLoader loader, String resource) 
throws IOException {
+    return new File(getResourceURL(loader, resource).getFile());
+  }
+
+  /**
+   * Gets a URL as an input stream
+   *
+   * @param urlString - the URL to get
+   * @return An input stream with the data from the URL
+   * @throws java.io.IOException If the resource cannot be found or read
+   */
+  public static InputStream getUrlAsStream(String urlString) throws 
IOException {
+    URL url = new URL(urlString);
+    URLConnection conn = url.openConnection();
+    return conn.getInputStream();
+  }
+
+  /**
+   * Gets a URL as a Reader
+   *
+   * @param urlString - the URL to get
+   * @return A Reader with the data from the URL
+   * @throws java.io.IOException If the resource cannot be found or read
+   */
+  public static Reader getUrlAsReader(String urlString) throws IOException {
+    return new InputStreamReader(getUrlAsStream(urlString));
+  }
+
+  /**
+   * Gets a URL as a Properties object
+   *
+   * @param urlString - the URL to get
+   * @return A Properties object with the data from the URL
+   * @throws java.io.IOException If the resource cannot be found or read
+   */
+  public static Properties getUrlAsProperties(String urlString) throws 
IOException {
+    Properties props = new Properties();
+    InputStream in = getUrlAsStream(urlString);
+    props.load(in);
+    in.close();
+    return props;
+  }
+
+  /**
+   * Loads a class
+   *
+   * @param className - the class to fetch
+   * @return The loaded class
+   * @throws ClassNotFoundException If the class cannot be found (duh!)
+   */
+  public static Class classForName(String className) throws 
ClassNotFoundException {
+    Class clazz = null;
+    try {
+      clazz = getClassLoader().loadClass(className);
+    } catch (Exception e) {
+      // Ignore.  Failsafe below.
+    }
+    if (clazz == null) {
+      clazz = Class.forName(className);
+    }
+    return clazz;
+  }
+
+  private static ClassLoader getClassLoader() {
+    if (defaultClassLoader != null) {
+      return defaultClassLoader;
+    } else {
+      return Thread.currentThread().getContextClassLoader();
+    }
+  }
+
+  public static Charset getCharset() {
+    return charset;
+  }
+
+  public static void setCharset(Charset charset) {
+    Resources.charset = charset;
+  }
+
+}


Reply via email to