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 2007/02/28 06:58:26 UTC

svn commit: r512614 [1/2] - in /ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine: builder/xml/ impl/ mapping/statement/

Author: cbegin
Date: Tue Feb 27 21:58:25 2007
New Revision: 512614

URL: http://svn.apache.org/viewvc?view=rev&rev=512614
Log:
Isolated all SQLMap configuration logic from the XML parser.  

Note: The ParserState class is the temporary home of this logic and the API is horrendous.  It is not meant to be usable, but this checkin is significant due to the complexity of separating this functionality.  It's ready for the next phase of refactorings to clean up the API. 

Added:
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/StatementProcessor.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/XMLStatementProcessor.java
Modified:
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/ParserState.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapClasspathEntityResolver.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapConfigParser.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapParser.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlStatementParser.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/impl/SqlMapExecutorDelegate.java
    ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/mapping/statement/SelectKeyStatement.java

Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/ParserState.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/ParserState.java?view=diff&rev=512614&r1=512613&r2=512614
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/ParserState.java (original)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/ParserState.java Tue Feb 27 21:58:25 2007
@@ -1,46 +1,46 @@
 package com.ibatis.sqlmap.engine.builder.xml;
 
-import com.ibatis.common.beans.Probe;
-import com.ibatis.common.beans.ProbeFactory;
+import com.ibatis.common.beans.*;
 import com.ibatis.common.resources.Resources;
+import com.ibatis.sqlmap.client.SqlMapException;
+import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;
+import com.ibatis.sqlmap.engine.accessplan.AccessPlanFactory;
 import com.ibatis.sqlmap.engine.cache.CacheModel;
 import com.ibatis.sqlmap.engine.cache.fifo.FifoCacheController;
 import com.ibatis.sqlmap.engine.cache.lru.LruCacheController;
 import com.ibatis.sqlmap.engine.cache.memory.MemoryCacheController;
-import com.ibatis.sqlmap.engine.datasource.DbcpDataSourceFactory;
-import com.ibatis.sqlmap.engine.datasource.JndiDataSourceFactory;
-import com.ibatis.sqlmap.engine.datasource.SimpleDataSourceFactory;
-import com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient;
-import com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate;
-import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl;
-import com.ibatis.sqlmap.engine.mapping.parameter.BasicParameterMap;
-import com.ibatis.sqlmap.engine.mapping.result.BasicResultMap;
-import com.ibatis.sqlmap.engine.mapping.result.Discriminator;
-import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement;
+import com.ibatis.sqlmap.engine.datasource.*;
+import com.ibatis.sqlmap.engine.impl.*;
+import com.ibatis.sqlmap.engine.mapping.parameter.*;
+import com.ibatis.sqlmap.engine.mapping.result.*;
+import com.ibatis.sqlmap.engine.mapping.statement.*;
+import com.ibatis.sqlmap.engine.mapping.sql.*;
+import com.ibatis.sqlmap.engine.mapping.sql.stat.StaticSql;
+import com.ibatis.sqlmap.engine.mapping.sql.simple.SimpleDynamicSql;
 import com.ibatis.sqlmap.engine.scope.ErrorContext;
+import com.ibatis.sqlmap.engine.transaction.*;
 import com.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig;
 import com.ibatis.sqlmap.engine.transaction.jdbc.JdbcTransactionConfig;
 import com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig;
 import com.ibatis.sqlmap.engine.type.*;
 
 import javax.sql.DataSource;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
+import java.util.*;
+import java.sql.ResultSet;
 
 /**
  * Variables the parser uses.  This "struct" like class is necessary because
  * that's what it is.  It's package scope to help protect the public fields from abuse.
- *
+ * <p/>
  * I'm favouring pragmatism in this case rather than OO dogma.
- *
+ * <p/>
  * The public methods are general utility methods that don't modify the state, but may
  * use the state.  They are tolerant of any and all values.
  */
 class ParserState {
 
   private static final Probe PROBE = ProbeFactory.getProbe();
+  private static final InlineParameterMapParser PARAM_PARSER = new InlineParameterMapParser();
 
   public ErrorContext errorContext = new ErrorContext();
   public String resource = "SQL Map Config XML File";
@@ -52,13 +52,14 @@
   //
   // SQL Map Config
   //
-  
-  public Properties globalProps;
+
+  public Properties globalProps = new Properties();
   public Properties txProps = new Properties();
   public Properties dsProps = new Properties();
+
   public boolean useStatementNamespaces;
   public Integer defaultStatementTimeout;
-  public DataSource dataSource;
+  private DataSource dataSource;
 
   //
   // SQL Map State
@@ -84,7 +85,7 @@
     delegate = new SqlMapExecutorDelegate();
     typeHandlerFactory = delegate.getTypeHandlerFactory();
     client = new SqlMapClientImpl(delegate);
-    useStatementNamespaces = false; 
+    useStatementNamespaces = false;
     registerDefaultTypeAliases();
   }
 
@@ -173,4 +174,782 @@
     typeHandlerFactory.putTypeAlias("xml", XmlTypeMarker.class.getName());
     typeHandlerFactory.putTypeAlias("xmlCollection", XmlCollectionTypeMarker.class.getName());
   }
+
+  //
+  // SQL Map Config methods
+  //
+
+  public void setGlobalProperties(String resource, String url) {
+    errorContext.setActivity("loading global properties");
+    try {
+      Properties props;
+      if (resource != null) {
+        errorContext.setResource(resource);
+        props = Resources.getResourceAsProperties(resource);
+      } else if (url != null) {
+        errorContext.setResource(url);
+        props = Resources.getUrlAsProperties(url);
+      } else {
+        throw new RuntimeException("The " + "properties" + " element requires either a resource or a url attribute.");
+      }
+
+      // Merge properties with those passed in programmatically
+      if (props != null) {
+        props.putAll(globalProps);
+        globalProps = props;
+      }
+    } catch (Exception e) {
+      throw new RuntimeException("Error loading properties.  Cause: " + e, e);
+    }
+  }
+
+  // TODO: Split into separate methods
+  public void setSettings(boolean classInfoCacheEnabled, boolean lazyLoadingEnabled, boolean statementCachingEnabled, boolean cacheModelsEnabled, boolean enhancementEnabled, boolean useStatementNamespaces, Integer maxTransactions, Integer maxRequests, Integer maxSessions, Integer defaultTimeout) {
+    errorContext.setActivity("loading settings properties");
+    ClassInfo.setCacheEnabled(classInfoCacheEnabled);
+    client.getDelegate().setLazyLoadingEnabled(lazyLoadingEnabled);
+    client.getDelegate().setStatementCacheEnabled(statementCachingEnabled);
+    client.getDelegate().setCacheModelsEnabled(cacheModelsEnabled);
+    try {
+      enhancementEnabled = enhancementEnabled && Resources.classForName("net.sf.cglib.proxy.InvocationHandler") != null;
+    } catch (ClassNotFoundException e) {
+      enhancementEnabled = false;
+    }
+    client.getDelegate().setEnhancementEnabled(enhancementEnabled);
+    this.useStatementNamespaces = useStatementNamespaces;
+
+    if (maxTransactions != null && maxTransactions.intValue() > 0) {
+      client.getDelegate().setMaxTransactions(maxTransactions.intValue());
+    }
+
+    if (maxRequests != null && maxRequests.intValue() > 0) {
+      client.getDelegate().setMaxRequests(maxRequests.intValue());
+    }
+
+    if (maxSessions != null && maxSessions.intValue() > 0) {
+      client.getDelegate().setMaxSessions(maxSessions.intValue());
+    }
+
+    AccessPlanFactory.setBytecodeEnhancementEnabled(client.getDelegate().isEnhancementEnabled());
+
+    if (defaultTimeout != null) {
+      try {
+        defaultStatementTimeout = defaultTimeout;
+      } catch (NumberFormatException e) {
+        throw new SqlMapException("Specified defaultStatementTimeout is not a valid integer");
+      }
+    }
+  }
+
+  public void addTypeAlias(String alias, String type) {
+    typeHandlerFactory.putTypeAlias(alias, type);
+  }
+
+  public void addGlobalTypeHandler(String javaType, String jdbcType, String callback) {
+    try {
+      errorContext.setActivity("building a building custom type handler");
+      TypeHandlerFactory typeHandlerFactory = client.getDelegate().getTypeHandlerFactory();
+
+      callback = typeHandlerFactory.resolveAlias(callback);
+      javaType = typeHandlerFactory.resolveAlias(javaType);
+
+      errorContext.setMoreInfo("Check the callback attribute '" + callback + "' (must be a classname).");
+
+      TypeHandler typeHandler;
+      Object impl = Resources.instantiate(callback);
+      if (impl instanceof TypeHandlerCallback) {
+        typeHandler = new CustomTypeHandler((TypeHandlerCallback) impl);
+      } else if (impl instanceof TypeHandler) {
+        typeHandler = (TypeHandler) impl;
+      } else {
+        throw new RuntimeException("The class '' is not a valid implementation of TypeHandler or TypeHandlerCallback");
+      }
+
+      errorContext.setMoreInfo("Check the javaType attribute '" + javaType + "' (must be a classname) or the jdbcType '" + jdbcType + "' (must be a JDBC type name).");
+      if (jdbcType != null && jdbcType.length() > 0) {
+        typeHandlerFactory.register(Resources.classForName(javaType), jdbcType, typeHandler);
+      } else {
+        typeHandlerFactory.register(Resources.classForName(javaType), typeHandler);
+      }
+    } catch (Exception e) {
+      throw new SqlMapException("Error registering occurred.  Cause: " + e, e);
+    }
+    errorContext.setMoreInfo(null);
+    errorContext.setObjectId(null);
+  }
+
+  //TODO: pass in datasource as a parameter to setTXMgr
+  public void setDataSource(String type, Properties props) {
+    type = typeHandlerFactory.resolveAlias(type);
+    try {
+      errorContext.setMoreInfo("Check the data source type or class.");
+      DataSourceFactory dsFactory = (DataSourceFactory) Resources.instantiate(type);
+      errorContext.setMoreInfo("Check the data source properties or configuration.");
+      dsFactory.initialize(props);
+      dataSource = dsFactory.getDataSource();
+      errorContext.setMoreInfo(null);
+    } catch (Exception e) {
+      if (e instanceof SqlMapException) {
+        throw (SqlMapException) e;
+      } else {
+        throw new SqlMapException("Error initializing DataSource.  Could not instantiate DataSourceFactory.  Cause: " + e, e);
+      }
+    }
+  }
+
+  public void setTransactionManager(String type, boolean commitRequired, Properties props) {
+    errorContext.setActivity("configuring the transaction manager");
+    type = typeHandlerFactory.resolveAlias(type);
+    TransactionManager txManager;
+    try {
+      errorContext.setMoreInfo("Check the transaction manager type or class.");
+      TransactionConfig config = (TransactionConfig) Resources.instantiate(type);
+      config.setDataSource(dataSource);
+      config.setMaximumConcurrentTransactions(client.getDelegate().getMaxTransactions());
+      errorContext.setMoreInfo("Check the transactio nmanager properties or configuration.");
+      config.initialize(props);
+      errorContext.setMoreInfo(null);
+      txManager = new TransactionManager(config);
+      txManager.setForceCommit(commitRequired);
+    } catch (Exception e) {
+      if (e instanceof SqlMapException) {
+        throw (SqlMapException) e;
+      } else {
+        throw new SqlMapException("Error initializing TransactionManager.  Could not instantiate TransactionConfig.  Cause: " + e, e);
+      }
+    }
+    client.getDelegate().setTxManager(txManager);
+  }
+
+  public void setResultObjectFactory(String type) {
+    errorContext.setActivity("configuring the Result Object Factory");
+    ResultObjectFactory rof;
+    try {
+      rof = (ResultObjectFactory) Resources.instantiate(type);
+      delegate.setResultObjectFactory(rof);
+    } catch (Exception e) {
+      throw new SqlMapException("Error instantiating resultObjectFactory: " + type, e);
+    }
+  }
+
+  // TODO - post processing sql map config
+  public void wireupCacheModels() {
+    Iterator cacheNames = client.getDelegate().getCacheModelNames();
+
+    while (cacheNames.hasNext()) {
+      String cacheName = (String) cacheNames.next();
+      CacheModel cacheModel = client.getDelegate().getCacheModel(cacheName);
+      Iterator statementNames = cacheModel.getFlushTriggerStatementNames();
+      while (statementNames.hasNext()) {
+        String statementName = (String) statementNames.next();
+        MappedStatement statement = client.getDelegate().getMappedStatement(statementName);
+        if (statement != null) {
+          statement.addExecuteListener(cacheModel);
+        } else {
+          throw new RuntimeException("Could not find statement named '" + statementName + "' for use as a flush trigger for the cache model named '" + cacheName + "'.");
+        }
+      }
+    }
+  }
+
+  //
+  // SQL Map methods
+  //
+
+  // TODO: post processing sql map
+
+  public void bindDelegateSubMaps() {
+    Iterator names = delegate.getResultMapNames();
+    while (names.hasNext()) {
+      String name = (String) names.next();
+      ResultMap rm = delegate.getResultMap(name);
+      Discriminator disc = rm.getDiscriminator();
+      if (disc != null) {
+        disc.bindSubMaps();
+      }
+    }
+  }
+
+  // TODO: pass into addCacheModel as parameter
+  public void setFlushInterval(int hours, int minutes, int seconds, int milliseconds) {
+    errorContext.setMoreInfo("Check the cache model flush interval.");
+    long t = 0;
+    t += milliseconds;
+    t += seconds * 1000;
+    t += minutes * 60 * 1000;
+    t += hours * 60 * 60 * 1000;
+    if (t < 1)
+      throw new RuntimeException("A flush interval must specify one or more of milliseconds, seconds, minutes or hours.");
+    cacheModel.setFlushInterval(t);
+  }
+
+  // TODO: remove in favour of working directly with cacheModel if possible
+  public void addFlushTriggerStatement(String statement) {
+    errorContext.setMoreInfo("Check the cache model flush on statement elements.");
+    cacheModel.addFlushTriggerStatement(statement);
+  }
+
+  public void addCacheModel(String id, String type, Boolean readOnly, Boolean serialize, Properties props) {
+    errorContext.setActivity("building a cache model");
+    type = typeHandlerFactory.resolveAlias(type);
+    if (readOnly != null) {
+      cacheModel.setReadOnly(readOnly.booleanValue());
+    } else {
+      cacheModel.setReadOnly(true);
+    }
+    if (serialize != null) {
+      cacheModel.setSerialize(serialize.booleanValue());
+    } else {
+      cacheModel.setSerialize(false);
+    }
+
+    errorContext.setObjectId(id + " cache model");
+
+    errorContext.setMoreInfo("Check the cache model type.");
+    cacheModel.setId(id);
+    cacheModel.setResource(errorContext.getResource());
+
+    try {
+      cacheModel.setControllerClassName(type);
+    } catch (Exception e) {
+      throw new RuntimeException("Error setting Cache Controller Class.  Cause: " + e, e);
+    }
+
+    errorContext.setMoreInfo("Check the cache model configuration.");
+    cacheModel.configure(props);
+
+    if (client.getDelegate().isCacheModelsEnabled()) {
+      client.getDelegate().addCacheModel(cacheModel);
+    }
+
+    errorContext.setMoreInfo(null);
+    errorContext.setObjectId(null);
+    cacheProps = null;
+    cacheModel = null;
+  }
+
+  // TODO: merge with addPArameterMap
+  public void finalizeParameterMap() {
+    parameterMap.setParameterMappingList(parameterMappingList);
+
+    client.getDelegate().addParameterMap(parameterMap);
+
+    errorContext.setMoreInfo(null);
+    errorContext.setObjectId(null);
+  }
+
+  // TODO: pass list into addParameterMap
+  public void addParameterMapping(String callback, String javaType, String resultMap, String propertyName, String jdbcType, String type, String nullValue, String mode, String numericScale) {
+    callback = typeHandlerFactory.resolveAlias(callback);
+    javaType = typeHandlerFactory.resolveAlias(javaType);
+    resultMap = applyNamespace(resultMap);
+
+    errorContext.setObjectId(propertyName + " mapping of the " + parameterMap.getId() + " parameter map");
+
+    TypeHandler handler;
+    if (callback != null) {
+      errorContext.setMoreInfo("Check the parameter mapping typeHandler attribute '" + callback + "' (must be a TypeHandler or TypeHandlerCallback implementation).");
+      try {
+        Object impl = Resources.instantiate(callback);
+        if (impl instanceof TypeHandlerCallback) {
+          handler = new CustomTypeHandler((TypeHandlerCallback) impl);
+        } else if (impl instanceof TypeHandler) {
+          handler = (TypeHandler) impl;
+        } else {
+          throw new RuntimeException("The class '" + callback + "' is not a valid implementation of TypeHandler or TypeHandlerCallback");
+        }
+      } catch (Exception e) {
+        throw new RuntimeException("Error occurred during custom type handler configuration.  Cause: " + e, e);
+      }
+    } else {
+      errorContext.setMoreInfo("Check the parameter mapping property type or name.");
+      handler = resolveTypeHandler(client.getDelegate().getTypeHandlerFactory(), parameterMap.getParameterClass(), propertyName, javaType, jdbcType);
+    }
+
+    BasicParameterMapping mapping = new BasicParameterMapping();
+    mapping.setPropertyName(propertyName);
+    mapping.setJdbcTypeName(jdbcType);
+    mapping.setTypeName(type);
+    mapping.setResultMapName(resultMap);
+    mapping.setNullValue(nullValue);
+    if (mode != null && mode.length() > 0) {
+      mapping.setMode(mode);
+    }
+    mapping.setTypeHandler(handler);
+    try {
+      if (javaType != null && javaType.length() > 0) {
+        mapping.setJavaType(Resources.classForName(javaType));
+      }
+    } catch (ClassNotFoundException e) {
+      throw new RuntimeException("Error setting javaType on parameter mapping.  Cause: " + e);
+    }
+
+    if (numericScale != null) {
+      try {
+        Integer scale = Integer.valueOf(numericScale);
+        if (scale.intValue() < 0) {
+          throw new RuntimeException("Error setting numericScale on parameter mapping.  Cause: scale must be greater than or equal to zero");
+        }
+
+        mapping.setNumericScale(scale);
+      } catch (NumberFormatException e) {
+        throw new RuntimeException("Error setting numericScale on parameter mapping.  Cause: " + numericScale + " is not a valid integer");
+      }
+    }
+
+    parameterMappingList.add(mapping);
+  }
+
+  public void addParameterMap(String id, String parameterClassName) {
+    errorContext.setActivity("building a parameter map");
+    parameterMap = new BasicParameterMap(client.getDelegate());
+
+    parameterClassName = typeHandlerFactory.resolveAlias(parameterClassName);
+
+    parameterMap.setId(id);
+    parameterMap.setResource(errorContext.getResource());
+
+    errorContext.setObjectId(id + " parameter map");
+
+    Class parameterClass;
+    try {
+      errorContext.setMoreInfo("Check the parameter class.");
+      parameterClass = Resources.classForName(parameterClassName);
+    } catch (Exception e) {
+      throw new SqlMapException("Error configuring ParameterMap.  Could not set ParameterClass.  Cause: " + e, e);
+    }
+
+    parameterMap.setParameterClass(parameterClass);
+
+    parameterMappingList = new ArrayList();
+
+    errorContext.setMoreInfo("Check the parameter mappings.");
+  }
+
+  // TODO: pass into addResultMap
+  public void addDiscriminator(String callback, String javaType, String jdbcType, String columnName, String nullValue, String columnIndex) {
+    callback = typeHandlerFactory.resolveAlias(callback);
+    javaType = typeHandlerFactory.resolveAlias(javaType);
+
+    TypeHandler handler;
+    if (callback != null) {
+      errorContext.setMoreInfo("Check the result mapping typeHandler attribute '" + callback + "' (must be a TypeHandlerCallback implementation).");
+      try {
+        Object impl = Resources.instantiate(callback);
+        if (impl instanceof TypeHandlerCallback) {
+          handler = new CustomTypeHandler((TypeHandlerCallback) impl);
+        } else if (impl instanceof TypeHandler) {
+          handler = (TypeHandler) impl;
+        } else {
+          throw new RuntimeException("The class '' is not a valid implementation of TypeHandler or TypeHandlerCallback");
+        }
+      } catch (Exception e) {
+        throw new RuntimeException("Error occurred during custom type handler configuration.  Cause: " + e, e);
+      }
+    } else {
+      errorContext.setMoreInfo("Check the result mapping property type or name.");
+      handler = resolveTypeHandler(client.getDelegate().getTypeHandlerFactory(), resultMap.getResultClass(), "", javaType, jdbcType, true);
+    }
+
+    BasicResultMapping mapping = new BasicResultMapping();
+    mapping.setColumnName(columnName);
+    mapping.setJdbcTypeName(jdbcType);
+    mapping.setTypeHandler(handler);
+    mapping.setNullValue(nullValue);
+
+    try {
+      if (javaType != null && javaType.length() > 0) {
+        mapping.setJavaType(Resources.classForName(javaType));
+      }
+    } catch (ClassNotFoundException e) {
+      throw new RuntimeException("Error setting javaType on result mapping.  Cause: " + e);
+    }
+
+    if (columnIndex != null && columnIndex.length() > 0) {
+      mapping.setColumnIndex(Integer.parseInt(columnIndex));
+    }
+
+    discriminator = new Discriminator(delegate, mapping);
+  }
+
+  // TODO: pass into addResultMap
+  public void addSubMap(String value, String resultMap) {
+    if (discriminator == null) {
+      throw new RuntimeException("The discriminator is null, but somehow a subMap was reached.  This is a bug.");
+    }
+    discriminator.addSubMap(value, applyNamespace(resultMap));
+  }
+
+  // TODO: pass into addResultMap
+  public void addResultMapping(String callback, String javaType, String propertyName, String jdbcType, String columnName, String nullValue, String statementName, String resultMapName, String columnIndex) {
+    callback = typeHandlerFactory.resolveAlias(callback);
+    javaType = typeHandlerFactory.resolveAlias(javaType);
+
+    errorContext.setObjectId(propertyName + " mapping of the " + resultMap.getId() + " result map");
+
+    TypeHandler handler;
+    if (callback != null) {
+      errorContext.setMoreInfo("Check the result mapping typeHandler attribute '" + callback + "' (must be a TypeHandler or TypeHandlerCallback implementation).");
+      try {
+        Object impl = Resources.instantiate(callback);
+        if (impl instanceof TypeHandlerCallback) {
+          handler = new CustomTypeHandler((TypeHandlerCallback) impl);
+        } else if (impl instanceof TypeHandler) {
+          handler = (TypeHandler) impl;
+        } else {
+          throw new RuntimeException("The class '" + callback + "' is not a valid implementation of TypeHandler or TypeHandlerCallback");
+        }
+      } catch (Exception e) {
+        throw new RuntimeException("Error occurred during custom type handler configuration.  Cause: " + e, e);
+      }
+    } else {
+      errorContext.setMoreInfo("Check the result mapping property type or name.");
+      handler = resolveTypeHandler(client.getDelegate().getTypeHandlerFactory(), resultMap.getResultClass(), propertyName, javaType, jdbcType, true);
+    }
+
+
+    BasicResultMapping mapping = new BasicResultMapping();
+    mapping.setPropertyName(propertyName);
+    mapping.setColumnName(columnName);
+    mapping.setJdbcTypeName(jdbcType);
+    mapping.setTypeHandler(handler);
+    mapping.setNullValue(nullValue);
+    mapping.setStatementName(statementName);
+    mapping.setNestedResultMapName(resultMapName);
+
+    if (resultMapName != null && resultMapName.length() > 0) {
+      resultMap.addNestedResultMappings(mapping);
+    }
+
+    try {
+      if (javaType != null && javaType.length() > 0) {
+        mapping.setJavaType(Resources.classForName(javaType));
+      }
+    } catch (ClassNotFoundException e) {
+      throw new RuntimeException("Error setting javaType on result mapping.  Cause: " + e);
+    }
+
+    if (columnIndex != null && columnIndex.length() > 0) {
+      mapping.setColumnIndex(Integer.parseInt(columnIndex));
+    } else {
+      resultMappingIndex++;
+      mapping.setColumnIndex(resultMappingIndex);
+    }
+
+    resultMappingList.add(mapping);
+  }
+
+  public void addResultMap(String id, String resultClassName, String xmlName, String groupBy, String extended) {
+    errorContext.setActivity("building a result map");
+
+    resultMap = new BasicResultMap(client.getDelegate());
+
+    resultClassName = typeHandlerFactory.resolveAlias(resultClassName);
+
+    errorContext.setObjectId(id + " result map");
+
+    resultMap.setId(id);
+    resultMap.setXmlName(xmlName);
+    resultMap.setResource(errorContext.getResource());
+
+    if (groupBy != null && groupBy.length() > 0) {
+      StringTokenizer parser = new StringTokenizer(groupBy, ", ", false);
+      while (parser.hasMoreTokens()) {
+        resultMap.addGroupByProperty(parser.nextToken());
+      }
+    }
+
+    Class resultClass;
+    try {
+      errorContext.setMoreInfo("Check the result class.");
+      resultClass = Resources.classForName(resultClassName);
+    } catch (Exception e) {
+      throw new RuntimeException("Error configuring Result.  Could not set ResultClass.  Cause: " + e, e);
+
+    }
+
+    resultMap.setResultClass(resultClass);
+
+    resultMappingList = new ArrayList();
+
+    errorContext.setMoreInfo("Check the extended result map.");
+    if (extended != null) {
+      BasicResultMap extendedResultMap = (BasicResultMap) client.getDelegate().getResultMap(extended);
+      ResultMapping[] resultMappings = extendedResultMap.getResultMappings();
+      for (int i = 0; i < resultMappings.length; i++) {
+        resultMappingList.add(resultMappings[i]);
+      }
+
+      List nestedResultMappings = extendedResultMap.getNestedResultMappings();
+      if (nestedResultMappings != null) {
+        Iterator iter = nestedResultMappings.iterator();
+        while (iter.hasNext()) {
+          resultMap.addNestedResultMappings((ResultMapping) iter.next());
+        }
+      }
+
+      if (groupBy == null || groupBy.length() == 0) {
+        if (extendedResultMap.hasGroupBy()) {
+          Iterator i = extendedResultMap.groupByProps();
+          while (i.hasNext()) {
+            resultMap.addGroupByProperty((String) i.next());
+          }
+        }
+      }
+    }
+
+    errorContext.setMoreInfo("Check the result mappings.");
+    resultMappingIndex = resultMappingList.size();
+  }
+
+  // TODO: pass into addResultMap
+  public void finalizeResultMap() {
+    if (resultMappingList.size() == 0) {
+      throw new RuntimeException("resultMap " + resultMap.getId() + " must have at least one result mapping");
+    }
+
+    resultMap.setResultMappingList(resultMappingList);
+
+    resultMap.setDiscriminator(discriminator);
+    discriminator = null;
+
+    client.getDelegate().addResultMap(resultMap);
+
+    errorContext.setMoreInfo(null);
+
+    errorContext.setObjectId(null);
+  }
+
+  //
+  // SQL Statement methods
+  //
+
+  public MappedStatement prepareGeneralStatement(StatementProcessor processor, GeneralStatement statement, String id, String resultMapName, String parameterMapName, String resultSetType, String fetchSize, String parameterClassName, String resultClassName, String allowRemapping, String xmlResultName, String timeout, String cacheModelName) {
+    errorContext.setActivity("parsing a mapped statement");
+    if (useStatementNamespaces) {
+      id = applyNamespace(id);
+    }
+
+    String[] additionalResultMapNames;
+
+    errorContext.setObjectId(id + " statement");
+
+    errorContext.setMoreInfo("Check the result map name.");
+    //BasicResultMap resultMap = null;
+    if (resultMapName != null) {
+      additionalResultMapNames = getAllButFirstToken(resultMapName);
+      resultMapName = getFirstToken(resultMapName);
+      statement.setResultMap((BasicResultMap) client.getDelegate().getResultMap(applyNamespace(resultMapName)));
+      for (int i = 0; i < additionalResultMapNames.length; i++) {
+        statement.addResultMap((BasicResultMap) client.getDelegate().getResultMap(applyNamespace(additionalResultMapNames[i])));
+      }
+    }
+
+    errorContext.setMoreInfo("Check the parameter map name.");
+
+    if (parameterMapName != null) {
+      statement.setParameterMap((BasicParameterMap) client.getDelegate().getParameterMap(parameterMapName));
+    }
+
+    statement.setId(id);
+    statement.setResource(errorContext.getResource());
+
+    if (resultSetType != null) {
+      if ("FORWARD_ONLY".equals(resultSetType)) {
+        statement.setResultSetType(new Integer(ResultSet.TYPE_FORWARD_ONLY));
+      } else if ("SCROLL_INSENSITIVE".equals(resultSetType)) {
+        statement.setResultSetType(new Integer(ResultSet.TYPE_SCROLL_INSENSITIVE));
+      } else if ("SCROLL_SENSITIVE".equals(resultSetType)) {
+        statement.setResultSetType(new Integer(ResultSet.TYPE_SCROLL_SENSITIVE));
+      }
+    }
+
+    if (fetchSize != null) {
+      statement.setFetchSize(new Integer(fetchSize));
+    }
+
+    // set parameter class either from attribute or from map (make sure to match)
+    ParameterMap parameterMap = statement.getParameterMap();
+    if (parameterMap == null) {
+      try {
+        if (parameterClassName != null) {
+          errorContext.setMoreInfo("Check the parameter class.");
+          parameterClassName = typeHandlerFactory.resolveAlias(parameterClassName);
+          Class parameterClass = Resources.classForName(parameterClassName);
+          statement.setParameterClass(parameterClass);
+        }
+      } catch (ClassNotFoundException e) {
+        throw new SqlMapException("Error.  Could not set parameter class.  Cause: " + e, e);
+      }
+    } else {
+      statement.setParameterClass(parameterMap.getParameterClass());
+    }
+
+    // process SQL statement, including inline parameter maps
+    errorContext.setMoreInfo("Check the SQL statement.");
+    processor.processStatement(statement);
+
+    // set up either null result map or automatic result mapping
+    BasicResultMap resultMap = (BasicResultMap) statement.getResultMap();
+    if (resultMap == null && resultClassName == null) {
+      statement.setResultMap(null);
+    } else if (resultMap == null) {
+      String firstResultClass = getFirstToken(resultClassName);
+      resultMap = buildAutoResultMap(allowRemapping, statement, firstResultClass, xmlResultName);
+      statement.setResultMap(resultMap);
+      String[] additionalResultClasses = getAllButFirstToken(resultClassName);
+      for (int i = 0; i < additionalResultClasses.length; i++) {
+        statement.addResultMap(buildAutoResultMap(allowRemapping, statement, additionalResultClasses[i], xmlResultName));
+      }
+
+    }
+
+    statement.setTimeout(defaultStatementTimeout);
+    if (timeout != null) {
+      try {
+        statement.setTimeout(Integer.valueOf(timeout));
+      } catch (NumberFormatException e) {
+        throw new SqlMapException("Specified timeout value for statement "
+            + statement.getId() + " is not a valid integer");
+      }
+    }
+
+    errorContext.setMoreInfo(null);
+    errorContext.setObjectId(null);
+
+    statement.setSqlMapClient(client);
+    if (cacheModelName != null && cacheModelName.length() > 0 && client.getDelegate().isCacheModelsEnabled()) {
+      CacheModel cacheModel = client.getDelegate().getCacheModel(cacheModelName);
+      return new CachingStatement(statement, cacheModel);
+    } else {
+      return statement;
+    }
+  }
+
+  public SelectKeyStatement prepareSelectKeyStatement(StatementProcessor processor, String resultClassName, String statementId, String keyPropName, boolean runAfterSQL, String type, Class parameterClass) {
+    errorContext.setActivity("parsing a select key");
+
+    SelectKeyStatement selectKeyStatement = new SelectKeyStatement();
+
+    resultClassName = typeHandlerFactory.resolveAlias(resultClassName);
+    Class resultClass = null;
+
+    // get parameter and result maps
+    selectKeyStatement.setSqlMapClient(client);
+
+    selectKeyStatement.setId(statementId + "-SelectKey");
+    selectKeyStatement.setResource(errorContext.getResource());
+    selectKeyStatement.setKeyProperty(keyPropName);
+
+    selectKeyStatement.setRunAfterSQL(runAfterSQL);
+    // process the type (pre or post) attribute
+    if (type != null) {
+      selectKeyStatement.setRunAfterSQL("post".equals(type));
+    }
+
+    try {
+      if (resultClassName != null) {
+        errorContext.setMoreInfo("Check the select key result class.");
+        resultClass = Resources.classForName(resultClassName);
+      } else {
+        if (keyPropName != null && parameterClass != null) {
+          resultClass = PROBE.getPropertyTypeForSetter(parameterClass, selectKeyStatement.getKeyProperty());
+        }
+      }
+    } catch (ClassNotFoundException e) {
+      throw new SqlMapException("Error.  Could not set result class.  Cause: " + e, e);
+    }
+
+    if (resultClass == null) {
+      resultClass = Object.class;
+    }
+
+    // process SQL statement, including inline parameter maps
+    errorContext.setMoreInfo("Check the select key SQL statement.");
+    processor.processStatement(selectKeyStatement);
+
+    BasicResultMap resultMap;
+    resultMap = new AutoResultMap(client.getDelegate(), false);
+    resultMap.setId(selectKeyStatement.getId() + "-AutoResultMap");
+    resultMap.setResultClass(resultClass);
+    resultMap.setResource(selectKeyStatement.getResource());
+    selectKeyStatement.setResultMap(resultMap);
+
+    errorContext.setMoreInfo(null);
+    return selectKeyStatement;
+  }
+
+  public void applyInlineParameterMap(GeneralStatement statement, String sqlStatement) {
+    String newSql = sqlStatement;
+
+    errorContext.setActivity("building an inline parameter map");
+
+    ParameterMap parameterMap = statement.getParameterMap();
+
+    errorContext.setMoreInfo("Check the inline parameters.");
+    if (parameterMap == null) {
+
+      BasicParameterMap map;
+      map = new BasicParameterMap(client.getDelegate());
+
+      map.setId(statement.getId() + "-InlineParameterMap");
+      map.setParameterClass(statement.getParameterClass());
+      map.setResource(statement.getResource());
+      statement.setParameterMap(map);
+
+      SqlText sqlText = PARAM_PARSER.parseInlineParameterMap(client.getDelegate().getTypeHandlerFactory(), newSql, statement.getParameterClass());
+      newSql = sqlText.getText();
+      List mappingList = Arrays.asList(sqlText.getParameterMappings());
+
+      map.setParameterMappingList(mappingList);
+
+    }
+
+    Sql sql;
+    if (SimpleDynamicSql.isSimpleDynamicSql(newSql)) {
+      sql = new SimpleDynamicSql(client.getDelegate(), newSql);
+    } else {
+      sql = new StaticSql(newSql);
+    }
+    statement.setSql(sql);
+
+  }
+
+  private BasicResultMap buildAutoResultMap(String allowRemapping, GeneralStatement statement, String firstResultClass, String xmlResultName) {
+    BasicResultMap resultMap;
+    resultMap = new AutoResultMap(client.getDelegate(), "true".equals(allowRemapping));
+    resultMap.setId(statement.getId() + "-AutoResultMap");
+    resultMap.setResultClass(resolveClass(firstResultClass));
+    resultMap.setXmlName(xmlResultName);
+    resultMap.setResource(statement.getResource());
+    return resultMap;
+  }
+
+  private Class resolveClass(String resultClassName) {
+    try {
+      if (resultClassName != null) {
+        errorContext.setMoreInfo("Check the result class.");
+        return Resources.classForName(typeHandlerFactory.resolveAlias(resultClassName));
+      } else {
+        return null;
+      }
+    } catch (ClassNotFoundException e) {
+      throw new SqlMapException("Error.  Could not set result class.  Cause: " + e, e);
+    }
+  }
+
+  private String getFirstToken(String s) {
+    return new StringTokenizer(s, ", ", false).nextToken();
+  }
+
+  private String[] getAllButFirstToken(String s) {
+    List strings = new ArrayList();
+    StringTokenizer parser = new StringTokenizer(s, ", ", false);
+    parser.nextToken();
+    while (parser.hasMoreTokens()) {
+      strings.add(parser.nextToken());
+    }
+    return (String[]) strings.toArray(new String[strings.size()]);
+  }
+
 }

Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapClasspathEntityResolver.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapClasspathEntityResolver.java?view=diff&rev=512614&r1=512613&r2=512614
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapClasspathEntityResolver.java (original)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapClasspathEntityResolver.java Tue Feb 27 21:58:25 2007
@@ -65,7 +65,7 @@
     InputSource source = null;
     try {
       String path = (String) doctypeMap.get(publicId);
-      source = getInputSource(path, source);      
+      source = getInputSource(path, source);
       if (source == null) {
         path = (String) doctypeMap.get(systemId);
         source = getInputSource(path, source);

Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapConfigParser.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapConfigParser.java?view=diff&rev=512614&r1=512613&r2=512614
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapConfigParser.java (original)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapConfigParser.java Tue Feb 27 21:58:25 2007
@@ -1,28 +1,15 @@
 package com.ibatis.sqlmap.engine.builder.xml;
 
-import com.ibatis.common.beans.ClassInfo;
 import com.ibatis.common.resources.Resources;
 import com.ibatis.common.xml.Nodelet;
 import com.ibatis.common.xml.NodeletParser;
 import com.ibatis.common.xml.NodeletUtils;
 import com.ibatis.sqlmap.client.SqlMapClient;
 import com.ibatis.sqlmap.client.SqlMapException;
-import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;
-import com.ibatis.sqlmap.engine.accessplan.AccessPlanFactory;
-import com.ibatis.sqlmap.engine.cache.CacheModel;
-import com.ibatis.sqlmap.engine.datasource.DataSourceFactory;
-import com.ibatis.sqlmap.engine.mapping.result.ResultObjectFactory;
-import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement;
-import com.ibatis.sqlmap.engine.transaction.TransactionConfig;
-import com.ibatis.sqlmap.engine.transaction.TransactionManager;
-import com.ibatis.sqlmap.engine.type.CustomTypeHandler;
-import com.ibatis.sqlmap.engine.type.TypeHandler;
-import com.ibatis.sqlmap.engine.type.TypeHandlerFactory;
 import org.w3c.dom.Node;
 
 import java.io.InputStream;
 import java.io.Reader;
-import java.util.Iterator;
 import java.util.Properties;
 
 public class SqlMapConfigParser {
@@ -48,14 +35,14 @@
   }
 
   public SqlMapClient parse(Reader reader, Properties props) {
-    state.globalProps = props;
+    if (props != null) state.globalProps = props;
     return parse(reader);
   }
 
   public SqlMapClient parse(Reader reader) {
     try {
       usingStreams = false;
-      
+
       parser.parse(reader);
       return state.client;
     } catch (Exception e) {
@@ -64,7 +51,7 @@
   }
 
   public SqlMapClient parse(InputStream inputStream, Properties props) {
-    state.globalProps = props;
+    if (props != null) state.globalProps = props;
     return parse(inputStream);
   }
 
@@ -82,22 +69,7 @@
   private void addSqlMapConfigNodelets() {
     parser.addNodelet("/sqlMapConfig/end()", new Nodelet() {
       public void process(Node node) throws Exception {
-        Iterator cacheNames = state.client.getDelegate().getCacheModelNames();
-
-        while (cacheNames.hasNext()) {
-          String cacheName = (String) cacheNames.next();
-          CacheModel cacheModel = state.client.getDelegate().getCacheModel(cacheName);
-          Iterator statementNames = cacheModel.getFlushTriggerStatementNames();
-          while (statementNames.hasNext()) {
-            String statementName = (String) statementNames.next();
-            MappedStatement statement = state.client.getDelegate().getMappedStatement(statementName);
-            if (statement != null) {
-              statement.addExecuteListener(cacheModel);
-            } else {
-              throw new RuntimeException("Could not find statement named '" + statementName + "' for use as a flush trigger for the cache model named '" + cacheName + "'.");
-            }
-          }
-        }
+        state.wireupCacheModels();
       }
     });
   }
@@ -105,33 +77,10 @@
   private void addGlobalPropNodelets() {
     parser.addNodelet("/sqlMapConfig/properties", new Nodelet() {
       public void process(Node node) throws Exception {
-        state.errorContext.setActivity("loading global properties");
-
         Properties attributes = NodeletUtils.parseAttributes(node, state.globalProps);
         String resource = attributes.getProperty("resource");
         String url = attributes.getProperty("url");
-
-        try {
-          Properties props = null;
-          if (resource != null) {
-            state.errorContext.setResource(resource);
-            props = Resources.getResourceAsProperties(resource);
-          } else if (url != null) {
-            state.errorContext.setResource(url);
-            props = Resources.getUrlAsProperties(url);
-          } else {
-            throw new RuntimeException("The " + "properties" + " element requires either a resource or a url attribute.");
-          }
-
-          if (state.globalProps == null) {
-            state.globalProps = props;
-          } else {
-            props.putAll(state.globalProps);
-            state.globalProps = props;
-          }
-        } catch (Exception e) {
-          throw new RuntimeException("Error loading properties.  Cause: " + e);
-        }
+        state.setGlobalProperties(resource, url);
       }
     });
   }
@@ -139,64 +88,41 @@
   private void addSettingsNodelets() {
     parser.addNodelet("/sqlMapConfig/settings", new Nodelet() {
       public void process(Node node) throws Exception {
-        state.errorContext.setActivity("loading settings properties");
-
         Properties attributes = NodeletUtils.parseAttributes(node, state.globalProps);
 
         String classInfoCacheEnabledAttr = attributes.getProperty("classInfoCacheEnabled");
         boolean classInfoCacheEnabled = (classInfoCacheEnabledAttr == null || "true".equals(classInfoCacheEnabledAttr));
-        ClassInfo.setCacheEnabled(classInfoCacheEnabled);
 
         String lazyLoadingEnabledAttr = attributes.getProperty("lazyLoadingEnabled");
         boolean lazyLoadingEnabled = (lazyLoadingEnabledAttr == null || "true".equals(lazyLoadingEnabledAttr));
-        state.client.getDelegate().setLazyLoadingEnabled(lazyLoadingEnabled);
 
         String statementCachingEnabledAttr = attributes.getProperty("statementCachingEnabled");
         boolean statementCachingEnabled = (statementCachingEnabledAttr == null || "true".equals(statementCachingEnabledAttr));
-        state.client.getDelegate().setStatementCacheEnabled(statementCachingEnabled);
 
         String cacheModelsEnabledAttr = attributes.getProperty("cacheModelsEnabled");
         boolean cacheModelsEnabled = (cacheModelsEnabledAttr == null || "true".equals(cacheModelsEnabledAttr));
-        state.client.getDelegate().setCacheModelsEnabled(cacheModelsEnabled);
 
         String enhancementEnabledAttr = attributes.getProperty("enhancementEnabled");
         boolean enhancementEnabled = (enhancementEnabledAttr == null || "true".equals(enhancementEnabledAttr));
-        try {
-          enhancementEnabled = enhancementEnabled && Resources.classForName("net.sf.cglib.proxy.InvocationHandler") != null;
-        } catch (ClassNotFoundException e) {
-          enhancementEnabled = false;
-        }
-        state.client.getDelegate().setEnhancementEnabled(enhancementEnabled);
+
 
         String useStatementNamespacesAttr = attributes.getProperty("useStatementNamespaces");
-        state.useStatementNamespaces = ("true".equals(useStatementNamespacesAttr));
+        boolean useStatementNamespaces = "true".equals(useStatementNamespacesAttr);
 
-        String maxTransactions = attributes.getProperty("maxTransactions");
-        if (maxTransactions != null && Integer.parseInt(maxTransactions) > 0) {
-          state.client.getDelegate().setMaxTransactions(Integer.parseInt(maxTransactions));
-        }
+        String maxTransactionsAttr = attributes.getProperty("maxTransactions");
+        Integer maxTransactions = maxTransactionsAttr == null ? null : new Integer((maxTransactionsAttr));
 
-        String maxRequests = attributes.getProperty("maxRequests");
-        if (maxRequests != null && Integer.parseInt(maxRequests) > 0) {
-          state.client.getDelegate().setMaxRequests(Integer.parseInt(maxRequests));
-        }
 
-        String maxSessions = attributes.getProperty("maxSessions");
-        if (maxSessions != null && Integer.parseInt(maxSessions) > 0) {
-          state.client.getDelegate().setMaxSessions(Integer.parseInt(maxSessions));
-        }
+        String maxRequestsAttr = attributes.getProperty("maxRequests");
+        Integer maxRequests = maxRequestsAttr == null ? null : new Integer(maxRequestsAttr);
 
-        AccessPlanFactory.setBytecodeEnhancementEnabled(state.client.getDelegate().isEnhancementEnabled());
-        
-        String defaultStatementTimeout = attributes.getProperty("defaultStatementTimeout");
-        if (defaultStatementTimeout != null) {
-          try {
-            Integer defaultTimeout = Integer.valueOf(defaultStatementTimeout);
-            state.defaultStatementTimeout = defaultTimeout;
-          } catch (NumberFormatException e) {
-            throw new SqlMapException("Specified defaultStatementTimeout is not a valid integer");
-          }
-        }
+        String maxSessionsAttr = attributes.getProperty("maxSessions");
+        Integer maxSessions = maxSessionsAttr == null ? null : new Integer(maxSessionsAttr);
+
+        String defaultTimeoutAttr = attributes.getProperty("defaultStatementTimeout");
+        Integer defaultTimeout = defaultTimeoutAttr == null ? null : Integer.valueOf(defaultTimeoutAttr);
+
+        state.setSettings(classInfoCacheEnabled, lazyLoadingEnabled, statementCachingEnabled, cacheModelsEnabled, enhancementEnabled, useStatementNamespaces, maxTransactions, maxRequests, maxSessions, defaultTimeout);
       }
     });
   }
@@ -207,7 +133,7 @@
         Properties prop = NodeletUtils.parseAttributes(node, state.globalProps);
         String alias = prop.getProperty("alias");
         String type = prop.getProperty("type");
-        state.typeHandlerFactory.putTypeAlias(alias, type);
+        state.addTypeAlias(alias, type);
       }
     });
   }
@@ -215,89 +141,38 @@
   private void addTypeHandlerNodelets() {
     parser.addNodelet("/sqlMapConfig/typeHandler", new Nodelet() {
       public void process(Node node) throws Exception {
-        state.errorContext.setActivity("building a building custom type handler");
-        try {
-          TypeHandlerFactory typeHandlerFactory = state.client.getDelegate().getTypeHandlerFactory();
-
-          Properties prop = NodeletUtils.parseAttributes(node, state.globalProps);
-
-          String jdbcType = prop.getProperty("jdbcType");
-          String javaType = prop.getProperty("javaType");
-          String callback = prop.getProperty("callback");
-          callback = typeHandlerFactory.resolveAlias(callback);
-          javaType = typeHandlerFactory.resolveAlias(javaType);
-
-          state.errorContext.setMoreInfo("Check the callback attribute '" + callback + "' (must be a classname).");
-
-          TypeHandler typeHandler;
-          Object impl = Resources.instantiate(callback);
-          if (impl instanceof TypeHandlerCallback) {
-            typeHandler = new CustomTypeHandler((TypeHandlerCallback) impl);
-          } else if (impl instanceof TypeHandler) {
-            typeHandler = (TypeHandler) impl;
-          } else {
-            throw new RuntimeException ("The class '' is not a valid implementation of TypeHandler or TypeHandlerCallback");
-          }
-
-          state.errorContext.setMoreInfo("Check the javaType attribute '" + javaType + "' (must be a classname) or the jdbcType '" + jdbcType + "' (must be a JDBC type name).");
-          if (jdbcType != null && jdbcType.length() > 0) {
-            typeHandlerFactory.register(Resources.classForName(javaType), jdbcType, typeHandler);
-          } else {
-            typeHandlerFactory.register(Resources.classForName(javaType), typeHandler);
-          }
-        } catch (Exception e) {
-          throw new SqlMapException("Error registering occurred.  Cause: " + e, e);
-        }
-        state.errorContext.setMoreInfo(null);
-        state.errorContext.setObjectId(null);
+        Properties prop = NodeletUtils.parseAttributes(node, state.globalProps);
+        String jdbcType = prop.getProperty("jdbcType");
+        String javaType = prop.getProperty("javaType");
+        String callback = prop.getProperty("callback");
+        state.addGlobalTypeHandler(javaType, jdbcType, callback);
       }
     });
   }
 
   private void addTransactionManagerNodelets() {
+    parser.addNodelet("/sqlMapConfig/transactionManager/property", new Nodelet() {
+      public void process(Node node) throws Exception {
+        Properties attributes = NodeletUtils.parseAttributes(node, state.globalProps);
+        String name = attributes.getProperty("name");
+        String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), state.globalProps);
+        state.txProps.setProperty(name, value);
+      }
+    });
     parser.addNodelet("/sqlMapConfig/transactionManager/end()", new Nodelet() {
       public void process(Node node) throws Exception {
-        state.errorContext.setActivity("configuring the transaction manager");
-
         Properties attributes = NodeletUtils.parseAttributes(node, state.globalProps);
-
-
         String type = attributes.getProperty("type");
-        type = state.typeHandlerFactory.resolveAlias(type);
-
-        TransactionManager txManager = null;
-        try {
-          state.errorContext.setMoreInfo("Check the transaction manager type or class.");
-          TransactionConfig config = (TransactionConfig) Resources.instantiate(type);
-          config.setDataSource(state.dataSource);
-          config.setMaximumConcurrentTransactions(state.client.getDelegate().getMaxTransactions());
-          state.errorContext.setMoreInfo("Check the transactio nmanager properties or configuration.");
-          config.initialize(state.txProps);
-          state.errorContext.setMoreInfo(null);
-          txManager = new TransactionManager(config);
-          txManager.setForceCommit("true".equals(attributes.getProperty("commitRequired")));
-        } catch (Exception e) {
-          if (e instanceof SqlMapException) {
-            throw (SqlMapException) e;
-          } else {
-            throw new SqlMapException("Error initializing TransactionManager.  Could not instantiate TransactionConfig.  Cause: " + e, e);
-          }
-        }
-
-        state.client.getDelegate().setTxManager(txManager);
+        boolean commitRequired = "true".equals(attributes.getProperty("commitRequired"));
+        state.setTransactionManager(type, commitRequired, state.txProps);
       }
     });
-    parser.addNodelet("/sqlMapConfig/transactionManager/property", new Nodelet() {
+    parser.addNodelet("/sqlMapConfig/transactionManager/dataSource/property", new Nodelet() {
       public void process(Node node) throws Exception {
         Properties attributes = NodeletUtils.parseAttributes(node, state.globalProps);
         String name = attributes.getProperty("name");
         String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), state.globalProps);
-        state.txProps.setProperty(name, value);
-      }
-    });
-    parser.addNodelet("/sqlMapConfig/transactionManager/dataSource", new Nodelet() {
-      public void process(Node node) throws Exception {
-        state.dsProps = new Properties();
+        state.dsProps.setProperty(name, value);
       }
     });
     parser.addNodelet("/sqlMapConfig/transactionManager/dataSource/end()", new Nodelet() {
@@ -307,34 +182,14 @@
         Properties attributes = NodeletUtils.parseAttributes(node, state.globalProps);
 
         String type = attributes.getProperty("type");
-        type = state.typeHandlerFactory.resolveAlias(type);
+        Properties props = state.dsProps;
 
-        try {
-          state.errorContext.setMoreInfo("Check the data source type or class.");
-          DataSourceFactory dsFactory = (DataSourceFactory) Resources.instantiate(type);
-          state.errorContext.setMoreInfo("Check the data source properties or configuration.");
-          dsFactory.initialize(state.dsProps);
-          state.dataSource = dsFactory.getDataSource();
-          state.errorContext.setMoreInfo(null);
-        } catch (Exception e) {
-          if (e instanceof SqlMapException) {
-            throw (SqlMapException) e;
-          } else {
-            throw new SqlMapException("Error initializing DataSource.  Could not instantiate DataSourceFactory.  Cause: " + e, e);
-          }
-        }
-      }
-    });
-    parser.addNodelet("/sqlMapConfig/transactionManager/dataSource/property", new Nodelet() {
-      public void process(Node node) throws Exception {
-        Properties attributes = NodeletUtils.parseAttributes(node, state.globalProps);
-        String name = attributes.getProperty("name");
-        String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), state.globalProps);
-        state.dsProps.setProperty(name, value);
+        state.setDataSource(type, props);
       }
     });
   }
 
+
   protected void addSqlMapNodelets() {
     parser.addNodelet("/sqlMapConfig/sqlMap", new Nodelet() {
       public void process(Node node) throws Exception {
@@ -379,19 +234,10 @@
   private void addResultObjectFactoryNodelets() {
     parser.addNodelet("/sqlMapConfig/resultObjectFactory", new Nodelet() {
       public void process(Node node) throws Exception {
-        state.errorContext.setActivity("configuring the Result Object Factory");
-
         Properties attributes = NodeletUtils.parseAttributes(node, state.globalProps);
-
         String type = attributes.getProperty("type");
 
-        ResultObjectFactory rof;
-        try {
-          rof = (ResultObjectFactory) Resources.instantiate(type);
-          state.delegate.setResultObjectFactory(rof);
-        } catch (Exception e) {
-          throw new SqlMapException("Error instantiating resultObjectFactory: " + type, e);
-        }
+        state.setResultObjectFactory(type);
       }
     });
     parser.addNodelet("/sqlMapConfig/resultObjectFactory/property", new Nodelet() {
@@ -403,5 +249,5 @@
       }
     });
   }
-  
+
 }

Modified: ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapParser.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapParser.java?view=diff&rev=512614&r1=512613&r2=512614
==============================================================================
--- ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapParser.java (original)
+++ ibatis/trunk/java/mapper/mapper2/src/com/ibatis/sqlmap/engine/builder/xml/SqlMapParser.java Tue Feb 27 21:58:25 2007
@@ -1,24 +1,17 @@
 package com.ibatis.sqlmap.engine.builder.xml;
 
-import com.ibatis.common.resources.Resources;
 import com.ibatis.common.xml.Nodelet;
 import com.ibatis.common.xml.NodeletException;
 import com.ibatis.common.xml.NodeletParser;
 import com.ibatis.common.xml.NodeletUtils;
 import com.ibatis.sqlmap.client.SqlMapException;
-import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;
 import com.ibatis.sqlmap.engine.cache.CacheModel;
-import com.ibatis.sqlmap.engine.mapping.parameter.BasicParameterMap;
-import com.ibatis.sqlmap.engine.mapping.parameter.BasicParameterMapping;
-import com.ibatis.sqlmap.engine.mapping.result.*;
 import com.ibatis.sqlmap.engine.mapping.statement.*;
-import com.ibatis.sqlmap.engine.type.CustomTypeHandler;
-import com.ibatis.sqlmap.engine.type.TypeHandler;
 import org.w3c.dom.Node;
 
 import java.io.InputStream;
 import java.io.Reader;
-import java.util.*;
+import java.util.Properties;
 
 public class SqlMapParser {
 
@@ -57,19 +50,12 @@
     });
     parser.addNodelet("/sqlMap/end()", new Nodelet() {
       public void process(Node node) throws Exception {
-        Iterator names = state.delegate.getResultMapNames();
-        while (names.hasNext()) {
-          String name = (String)names.next();
-          ResultMap rm = state.delegate.getResultMap(name);
-          Discriminator disc = rm.getDiscriminator();
-          if (disc != null) {
-            disc.bindSubMaps();
-          }
-        }
+        state.bindDelegateSubMaps();
       }
     });
   }
 
+
   private void addSqlNodelets() {
     parser.addNodelet("/sqlMap/sql", new Nodelet() {
       public void process(Node node) throws Exception {
@@ -80,9 +66,8 @@
         }
         if (state.sqlIncludes.containsKey(id)) {
           throw new SqlMapException("Duplicate <sql>-include '" + id + "' found.");
-        }
-        else  {
-        	state.sqlIncludes.put(id, node);
+        } else {
+          state.sqlIncludes.put(id, node);
         }
       }
     });
@@ -94,7 +79,7 @@
         Properties prop = NodeletUtils.parseAttributes(node, state.globalProps);
         String alias = prop.getProperty("alias");
         String type = prop.getProperty("type");
-        state.typeHandlerFactory.putTypeAlias(alias, type);
+        state.addTypeAlias(alias, type);
       }
     });
   }
@@ -108,50 +93,14 @@
     });
     parser.addNodelet("/sqlMap/cacheModel/end()", new Nodelet() {
       public void process(Node node) throws Exception {
-        state.errorContext.setActivity("building a cache model");
-
         Properties attributes = NodeletUtils.parseAttributes(node, state.globalProps);
         String id = state.applyNamespace(attributes.getProperty("id"));
         String type = attributes.getProperty("type");
-        type = state.typeHandlerFactory.resolveAlias(type);
-
-        String readOnly = attributes.getProperty("readOnly");
-        if (readOnly != null && readOnly.length() > 0) {
-          state.cacheModel.setReadOnly("true".equals(readOnly));
-        } else {
-          state.cacheModel.setReadOnly(true);
-        }
-
-        String serialize = attributes.getProperty("serialize");
-        if (serialize != null && serialize.length() > 0) {
-          state.cacheModel.setSerialize("true".equals(serialize));
-        } else {
-          state.cacheModel.setSerialize(false);
-        }
-
-        state.errorContext.setObjectId(id + " cache model");
-
-        state.errorContext.setMoreInfo("Check the cache model type.");
-        state.cacheModel.setId(id);
-        state.cacheModel.setResource(state.errorContext.getResource());
-
-        try {
-          state.cacheModel.setControllerClassName(type);
-        } catch (Exception e) {
-          throw new RuntimeException("Error setting Cache Controller Class.  Cause: " + e, e);
-        }
-
-        state.errorContext.setMoreInfo("Check the cache model configuration.");
-        state.cacheModel.configure(state.cacheProps);
-
-        if (state.client.getDelegate().isCacheModelsEnabled()) {
-          state.client.getDelegate().addCacheModel(state.cacheModel);
-        }
-
-        state.errorContext.setMoreInfo(null);
-        state.errorContext.setObjectId(null);
-        state.cacheProps = null;
-        state.cacheModel = null;
+        String readOnlyAttr = attributes.getProperty("readOnly");
+        Boolean readOnly = readOnlyAttr == null || readOnlyAttr.length() <= 0 ? null : new Boolean("true".equals(readOnlyAttr));
+        String serializeAttr = attributes.getProperty("serialize");
+        Boolean serialize = serializeAttr == null || serializeAttr.length() <= 0 ? null : new Boolean("true".equals(serializeAttr));
+        state.addCacheModel(id, type, readOnly, serialize, state.cacheProps);
       }
     });
     parser.addNodelet("/sqlMap/cacheModel/property", new Nodelet() {
@@ -165,27 +114,20 @@
     });
     parser.addNodelet("/sqlMap/cacheModel/flushOnExecute", new Nodelet() {
       public void process(Node node) throws Exception {
-        state.errorContext.setMoreInfo("Check the cache model flush on statement elements.");
         Properties childAttributes = NodeletUtils.parseAttributes(node, state.globalProps);
-        state.cacheModel.addFlushTriggerStatement(childAttributes.getProperty("statement"));
+        String statement = childAttributes.getProperty("statement");
+        state.addFlushTriggerStatement(statement);
       }
     });
     parser.addNodelet("/sqlMap/cacheModel/flushInterval", new Nodelet() {
       public void process(Node node) throws Exception {
         Properties childAttributes = NodeletUtils.parseAttributes(node, state.globalProps);
-        long t = 0;
         try {
-          state.errorContext.setMoreInfo("Check the cache model flush interval.");
-          String milliseconds = childAttributes.getProperty("milliseconds");
-          String seconds = childAttributes.getProperty("seconds");
-          String minutes = childAttributes.getProperty("minutes");
-          String hours = childAttributes.getProperty("hours");
-          if (milliseconds != null) t += Integer.parseInt(milliseconds);
-          if (seconds != null) t += Integer.parseInt(seconds) * 1000;
-          if (minutes != null) t += Integer.parseInt(minutes) * 60 * 1000;
-          if (hours != null) t += Integer.parseInt(hours) * 60 * 60 * 1000;
-          if (t < 1) throw new RuntimeException("A flush interval must specify one or more of milliseconds, seconds, minutes or hours.");
-          state.cacheModel.setFlushInterval(t);
+          int milliseconds = childAttributes.getProperty("milliseconds") == null ? 0 : Integer.parseInt(childAttributes.getProperty("milliseconds"));
+          int seconds = childAttributes.getProperty("seconds") == null ? 0 : Integer.parseInt(childAttributes.getProperty("seconds"));
+          int minutes = childAttributes.getProperty("minutes") == null ? 0 : Integer.parseInt(childAttributes.getProperty("minutes"));
+          int hours = childAttributes.getProperty("hours") == null ? 0 : Integer.parseInt(childAttributes.getProperty("hours"));
+          state.setFlushInterval(hours, minutes, seconds, milliseconds);
         } catch (NumberFormatException e) {
           throw new RuntimeException("Error building cache '" + state.cacheModel.getId() + "' in '" + "resourceNAME" + "'.  Flush interval milliseconds must be a valid long integer value.  Cause: " + e, e);
         }
@@ -193,48 +135,21 @@
     });
   }
 
+
   private void addParameterMapNodelets() {
     parser.addNodelet("/sqlMap/parameterMap/end()", new Nodelet() {
       public void process(Node node) throws Exception {
 
-        state.parameterMap.setParameterMappingList(state.parameterMappingList);
-
-        state.client.getDelegate().addParameterMap(state.parameterMap);
-
-        state.errorContext.setMoreInfo(null);
-        state.errorContext.setObjectId(null);
+        state.finalizeParameterMap();
       }
     });
     parser.addNodelet("/sqlMap/parameterMap", new Nodelet() {
       public void process(Node node) throws Exception {
-        state.errorContext.setActivity("building a parameter map");
-
-        state.parameterMap = new BasicParameterMap(state.client.getDelegate());
-
         Properties attributes = NodeletUtils.parseAttributes(node, state.globalProps);
         String id = state.applyNamespace(attributes.getProperty("id"));
         String parameterClassName = attributes.getProperty("class");
-        parameterClassName = state.typeHandlerFactory.resolveAlias(parameterClassName);
 
-        state.parameterMap.setId(id);
-        state.parameterMap.setResource(state.errorContext.getResource());
-
-        state.errorContext.setObjectId(id + " parameter map");
-
-        Class parameterClass = null;
-        try {
-          state.errorContext.setMoreInfo("Check the parameter class.");
-          parameterClass = Resources.classForName(parameterClassName);
-        } catch (Exception e) {
-          //TODO: Why is this commented out?
-          //throw new SqlMapException("Error configuring ParameterMap.  Could not set ParameterClass.  Cause: " + e, e);
-        }
-
-        state.parameterMap.setParameterClass(parameterClass);
-
-        state.parameterMappingList = new ArrayList();
-
-        state.errorContext.setMoreInfo("Check the parameter mappings.");
+        state.addParameterMap(id, parameterClassName);
       }
     });
     parser.addNodelet("/sqlMap/parameterMap/parameter", new Nodelet() {
@@ -242,7 +157,7 @@
         Properties childAttributes = NodeletUtils.parseAttributes(node, state.globalProps);
         String propertyName = childAttributes.getProperty("property");
         String jdbcType = childAttributes.getProperty("jdbcType");
-        String type     = childAttributes.getProperty("typeName");
+        String type = childAttributes.getProperty("typeName");
         String javaType = childAttributes.getProperty("javaType");
         String resultMap = childAttributes.getProperty("resultMap");
         String nullValue = childAttributes.getProperty("nullValue");
@@ -250,158 +165,28 @@
         String callback = childAttributes.getProperty("typeHandler");
         String numericScale = childAttributes.getProperty("numericScale");
 
-        callback = state.typeHandlerFactory.resolveAlias(callback);
-        javaType = state.typeHandlerFactory.resolveAlias(javaType);
-        resultMap = state.applyNamespace( resultMap );
-
-        state.errorContext.setObjectId(propertyName + " mapping of the " + state.parameterMap.getId() + " parameter map");
-
-        TypeHandler handler = null;
-        if (callback != null) {
-          state.errorContext.setMoreInfo("Check the parameter mapping typeHandler attribute '" + callback + "' (must be a TypeHandler or TypeHandlerCallback implementation).");
-          try {
-            Object impl = Resources.instantiate(callback);
-            if (impl instanceof TypeHandlerCallback) {
-              handler = new CustomTypeHandler((TypeHandlerCallback) impl);
-            } else if (impl instanceof TypeHandler) {
-              handler = (TypeHandler) impl;
-            } else {
-              throw new RuntimeException ("The class '"+callback+"' is not a valid implementation of TypeHandler or TypeHandlerCallback");
-            }
-          } catch (Exception e) {
-            throw new RuntimeException("Error occurred during custom type handler configuration.  Cause: " + e, e);
-          }
-        } else {
-          state.errorContext.setMoreInfo("Check the parameter mapping property type or name.");
-          handler = state.resolveTypeHandler(state.client.getDelegate().getTypeHandlerFactory(), state.parameterMap.getParameterClass(), propertyName, javaType, jdbcType);
-        }
-
-        BasicParameterMapping mapping = new BasicParameterMapping();
-        mapping.setPropertyName(propertyName);
-        mapping.setJdbcTypeName(jdbcType);
-        mapping.setTypeName(type);
-        mapping.setResultMapName( resultMap );
-        mapping.setNullValue(nullValue);
-        if (mode != null && mode.length() > 0) {
-          mapping.setMode(mode);
-        }
-        mapping.setTypeHandler(handler);
-        try {
-          if (javaType != null && javaType.length() > 0) {
-            mapping.setJavaType(Resources.classForName(javaType));
-          }
-        } catch (ClassNotFoundException e) {
-          throw new RuntimeException("Error setting javaType on parameter mapping.  Cause: " + e);
-        }
-        
-        if (numericScale != null) {
-          try {
-            Integer scale = Integer.valueOf(numericScale);
-            if (scale.intValue() < 0) {
-              throw new RuntimeException("Error setting numericScale on parameter mapping.  Cause: scale must be greater than or equal to zero");
-            }
-            
-            mapping.setNumericScale(scale);
-          } catch (NumberFormatException e) {
-            throw new RuntimeException("Error setting numericScale on parameter mapping.  Cause: " + numericScale + " is not a valid integer");
-          }
-        }
-
-        state.parameterMappingList.add(mapping);
+        state.addParameterMapping(callback, javaType, resultMap, propertyName, jdbcType, type, nullValue, mode, numericScale);
 
       }
     });
   }
 
+
   private void addResultMapNodelets() {
     parser.addNodelet("/sqlMap/resultMap/end()", new Nodelet() {
       public void process(Node node) throws Exception {
-        
-        if (state.resultMappingList.size() == 0) {
-          throw new RuntimeException("resultMap " + state.resultMap.getId() + " must have at least one result mapping");
-        }
-        
-        state.resultMap.setResultMappingList(state.resultMappingList);
-
-        state.resultMap.setDiscriminator(state.discriminator);
-        state.discriminator = null;
-        
-        state.client.getDelegate().addResultMap(state.resultMap);
-
-        state.errorContext.setMoreInfo(null);
-
-        state.errorContext.setObjectId(null);
+        state.finalizeResultMap();
       }
     });
     parser.addNodelet("/sqlMap/resultMap", new Nodelet() {
       public void process(Node node) throws Exception {
-        state.errorContext.setActivity("building a result map");
-
-        state.resultMap = new BasicResultMap(state.client.getDelegate());
-
         Properties attributes = NodeletUtils.parseAttributes(node, state.globalProps);
         String id = state.applyNamespace(attributes.getProperty("id"));
         String resultClassName = attributes.getProperty("class");
         String extended = state.applyNamespace(attributes.getProperty("extends"));
         String xmlName = attributes.getProperty("xmlName");
         String groupBy = attributes.getProperty("groupBy");
-        resultClassName = state.typeHandlerFactory.resolveAlias(resultClassName);
-
-        state.errorContext.setObjectId(id + " result map");
-
-        state.resultMap.setId(id);
-        state.resultMap.setXmlName(xmlName);
-        state.resultMap.setResource(state.errorContext.getResource());
-
-        if (groupBy != null && groupBy.length() > 0) {
-          StringTokenizer parser = new StringTokenizer(groupBy, ", ", false);
-          while (parser.hasMoreTokens()) {
-            state.resultMap.addGroupByProperty(parser.nextToken());
-          }
-        }
-
-        Class resultClass = null;
-        try {
-          state.errorContext.setMoreInfo("Check the result class.");
-          resultClass = Resources.classForName(resultClassName);
-        } catch (Exception e) {
-          throw new RuntimeException("Error configuring Result.  Could not set ResultClass.  Cause: " + e, e);
-
-        }
-
-        state.resultMap.setResultClass(resultClass);
-
-        state.resultMappingList = new ArrayList();
-
-        state.errorContext.setMoreInfo("Check the extended result map.");
-        if (extended != null) {
-          BasicResultMap extendedResultMap = (BasicResultMap) state.client.getDelegate().getResultMap(extended);
-          ResultMapping[] resultMappings = extendedResultMap.getResultMappings();
-          for (int i = 0; i < resultMappings.length; i++) {
-            state.resultMappingList.add(resultMappings[i]);
-          }
-
-          List nestedResultMappings = extendedResultMap.getNestedResultMappings();
-          if (nestedResultMappings != null) {
-            Iterator iter = nestedResultMappings.iterator();
-            while (iter.hasNext()) {
-              state.resultMap.addNestedResultMappings((ResultMapping) iter.next());
-            }
-          }
-          
-          if (groupBy == null || groupBy.length() == 0) {
-            if (extendedResultMap.hasGroupBy()) {
-              Iterator i = extendedResultMap.groupByProps();
-              while (i.hasNext()) {
-                state.resultMap.addGroupByProperty((String) i.next());
-              }
-            }
-          }
-        }
-
-        state.errorContext.setMoreInfo("Check the result mappings.");
-        state.resultMappingIndex = state.resultMappingList.size();
-
+        state.addResultMap(id, resultClassName, xmlName, groupBy, extended);
       }
     });
     parser.addNodelet("/sqlMap/resultMap/result", new Nodelet() {
@@ -417,73 +202,16 @@
         String resultMapName = childAttributes.getProperty("resultMap");
         String callback = childAttributes.getProperty("typeHandler");
 
-        callback = state.typeHandlerFactory.resolveAlias(callback);
-        javaType = state.typeHandlerFactory.resolveAlias(javaType);
-
-        state.errorContext.setObjectId(propertyName + " mapping of the " + state.resultMap.getId() + " result map");
-
-        TypeHandler handler = null;
-        if (callback != null) {
-          state.errorContext.setMoreInfo("Check the result mapping typeHandler attribute '" + callback + "' (must be a TypeHandler or TypeHandlerCallback implementation).");
-          try {
-            Object impl = Resources.instantiate(callback);
-            if (impl instanceof TypeHandlerCallback) {
-              handler = new CustomTypeHandler((TypeHandlerCallback) impl);
-            } else if (impl instanceof TypeHandler) {
-              handler = (TypeHandler) impl;
-            } else {
-              throw new RuntimeException ("The class '"+callback+"' is not a valid implementation of TypeHandler or TypeHandlerCallback");
-            }
-          } catch (Exception e) {
-            throw new RuntimeException("Error occurred during custom type handler configuration.  Cause: " + e, e);
-          }
-        } else {
-          state.errorContext.setMoreInfo("Check the result mapping property type or name.");
-          handler = state.resolveTypeHandler(state.client.getDelegate().getTypeHandlerFactory(), state.resultMap.getResultClass(), propertyName, javaType, jdbcType, true);
-        }
-
-
-        BasicResultMapping mapping = new BasicResultMapping();
-        mapping.setPropertyName(propertyName);
-        mapping.setColumnName(columnName);
-        mapping.setJdbcTypeName(jdbcType);
-        mapping.setTypeHandler(handler);
-        mapping.setNullValue(nullValue);
-        mapping.setStatementName(statementName);
-        mapping.setNestedResultMapName(resultMapName);
-
-        if (resultMapName != null && resultMapName.length() > 0) {
-          state.resultMap.addNestedResultMappings(mapping);
-        }
-
-        try {
-          if (javaType != null && javaType.length() > 0) {
-            mapping.setJavaType(Resources.classForName(javaType));
-          }
-        } catch (ClassNotFoundException e) {
-          throw new RuntimeException("Error setting javaType on result mapping.  Cause: " + e);
-        }
-
-        if (columnIndex != null && columnIndex.length() > 0) {
-          mapping.setColumnIndex(Integer.parseInt(columnIndex));
-        } else {
-          state.resultMappingIndex++;
-          mapping.setColumnIndex(state.resultMappingIndex);
-        }
-
-        state.resultMappingList.add(mapping);
+        state.addResultMapping(callback, javaType, propertyName, jdbcType, columnName, nullValue, statementName, resultMapName, columnIndex);
       }
     });
 
     parser.addNodelet("/sqlMap/resultMap/discriminator/subMap", new Nodelet() {
       public void process(Node node) throws Exception {
-        if (state.discriminator == null) {
-          throw new RuntimeException ("The discriminator is null, but somehow a subMap was reached.  This is a bug.");
-        }
         Properties childAttributes = NodeletUtils.parseAttributes(node, state.globalProps);
         String value = childAttributes.getProperty("value");
         String resultMap = childAttributes.getProperty("resultMap");
-        state.discriminator.addSubMap(value, state.applyNamespace(resultMap));
+        state.addSubMap(value, resultMap);
       }
     });
 
@@ -497,48 +225,7 @@
         String columnIndex = childAttributes.getProperty("columnIndex");
         String callback = childAttributes.getProperty("typeHandler");
 
-        callback = state.typeHandlerFactory.resolveAlias(callback);
-        javaType = state.typeHandlerFactory.resolveAlias(javaType);
-
-        TypeHandler handler = null;
-        if (callback != null) {
-          state.errorContext.setMoreInfo("Check the result mapping typeHandler attribute '" + callback + "' (must be a TypeHandlerCallback implementation).");
-          try {
-            Object impl = Resources.instantiate(callback);
-            if (impl instanceof TypeHandlerCallback) {
-              handler = new CustomTypeHandler((TypeHandlerCallback) impl);
-            } else if (impl instanceof TypeHandler) {
-              handler = (TypeHandler) impl;
-            } else {
-              throw new RuntimeException ("The class '' is not a valid implementation of TypeHandler or TypeHandlerCallback");
-            }
-          } catch (Exception e) {
-            throw new RuntimeException("Error occurred during custom type handler configuration.  Cause: " + e, e);
-          }
-        } else {
-          state.errorContext.setMoreInfo("Check the result mapping property type or name.");
-          handler = state.resolveTypeHandler(state.client.getDelegate().getTypeHandlerFactory(), state.resultMap.getResultClass(), "", javaType, jdbcType, true);
-        }
-
-        BasicResultMapping mapping = new BasicResultMapping();
-        mapping.setColumnName(columnName);
-        mapping.setJdbcTypeName(jdbcType);
-        mapping.setTypeHandler(handler);
-        mapping.setNullValue(nullValue);
-
-        try {
-          if (javaType != null && javaType.length() > 0) {
-            mapping.setJavaType(Resources.classForName(javaType));
-          }
-        } catch (ClassNotFoundException e) {
-          throw new RuntimeException("Error setting javaType on result mapping.  Cause: " + e);
-        }
-
-        if (columnIndex != null && columnIndex.length() > 0) {
-          mapping.setColumnIndex(Integer.parseInt(columnIndex));
-        }
-
-        state.discriminator = new Discriminator (state.delegate, mapping);
+        state.addDiscriminator(callback, javaType, jdbcType, columnName, nullValue, columnIndex);
       }
     });
   }