Package com.ibatis.sqlmap.engine.builder

Source Code of com.ibatis.sqlmap.engine.builder.XmlSqlMapParser

package com.ibatis.sqlmap.engine.builder;

import com.ibatis.sqlmap.client.SqlMapException;
import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.reflection.MetaClass;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import com.ibatis.common.util.NodeEvent;
import org.apache.ibatis.parsing.XNode;
import com.ibatis.common.util.NodeEventParser;

import java.io.Reader;
import java.util.*;

public class XmlSqlMapParser {

  private XmlSqlMapConfigParser configParser;
  private Ibatis2Configuration config;
  private Reader reader;
  private NodeEventParser parser;

  private CacheBuilder cacheBuilder;
  private List<String> flushCacheStatements;

  private ResultMap.Builder resultMapBuilder;
  private List<ResultMapping> resultMappingList;
  private Map<String, String> discriminatorSubMap;

  private Discriminator.Builder discriminatorBuilder;

  private ParameterMap.Builder parameterMapBuilder;
  private List<ParameterMapping> parameterMappingList;

  private String namespace;
  private List<String> groupByProperties;

  public XmlSqlMapParser(XmlSqlMapConfigParser configParser, Reader reader) {
    this.configParser = configParser;
    this.config = (Ibatis2Configuration) configParser.getConfiguration();
    this.reader = reader;
    this.parser = new NodeEventParser();
    this.parser.addNodeletHandler(this);
    this.parser.setVariables(config.getVariables());
    this.flushCacheStatements = new ArrayList<String>();
    this.parser.setEntityResolver(new SqlMapEntityResolver());
  }

  public void parse() {
    parser.parse(reader);
  }

  public XmlSqlMapConfigParser getConfigParser() {
    return configParser;
  }

  public String getNamespace() {
    return namespace;
  }

  public String applyNamespace(String id) {

    return id == null ? null : namespace == null ? id : namespace + "." + id;
  }

  @NodeEvent("/sqlMap")
  public void sqlMap(XNode context) throws Exception {
    this.namespace = context.getStringAttribute("namespace");
  }

  @NodeEvent("/sqlMap/typeAlias")
  public void sqlMaptypeAlias(XNode context) throws Exception {
    String alias = context.getStringAttribute("alias");
    String type = context.getStringAttribute("type");
    config.getTypeAliasRegistry().registerAlias(alias, type);
  }

  @NodeEvent("/sqlMap/cacheModel")
  public void sqlMapcacheModel(XNode context) throws Exception {
    String id = applyNamespace(context.getStringAttribute("id"));
    String type = context.getStringAttribute("type");
    Boolean readOnly = context.getBooleanAttribute("readOnly", true);
    Boolean serialize = context.getBooleanAttribute("serialize", true);
    Class clazz = config.getTypeAliasRegistry().resolveAlias(type);
    cacheBuilder = new CacheBuilder(id);
    cacheBuilder.addDecorator(clazz);

    //LOCAL_READ_WRITE (serializable=false, readOnly=false)
    //SHARED_READ_ONLY (serializable=false, readOnly=true)
    //SHARED_READ_WRITE (serializable=true, readOnly=false)
    if (serialize) {
      if (readOnly) {
        cacheBuilder.readWrite(false);
      } else {
        cacheBuilder.readWrite(true);
      }
    } else {
      if (readOnly) {
        cacheBuilder.readWrite(false);
      } else {
        cacheBuilder = null;
      }
    }
  }

  @NodeEvent("/sqlMap/cacheModel/property")
  public void sqlMapcacheModelproperty(XNode context) throws Exception {
    if (cacheBuilder != null) {
      String name = context.getStringAttribute("name");
      String value = context.getStringAttribute("value");
      if ("size".equals(name)) {
        cacheBuilder.size(Integer.parseInt(value));
      }
    }
  }

  @NodeEvent("/sqlMap/cacheModel/flushInterval")
  public void sqlMapcacheModelflushInterval(XNode context) throws Exception {
    if (cacheBuilder != null) {
      long clearInterval = 0L;
      clearInterval += context.getIntAttribute("milliseconds", 0);
      clearInterval += context.getIntAttribute("seconds", 0) * 1000L;
      clearInterval += context.getIntAttribute("minutes", 0) * 60L * 1000L;
      clearInterval += context.getIntAttribute("hours", 0) * 60L * 60L * 1000L;
      if (clearInterval < 1L) {
        throw new RuntimeException("A flush interval must specify one or more of milliseconds, seconds, minutes or hours.");
      }
      cacheBuilder.clearInterval(clearInterval);
    }
  }

  @NodeEvent("/sqlMap/cacheModel/flushOnExecute")
  public void sqlMapcacheModelflushOnExecute(XNode context) throws Exception {
    if (cacheBuilder != null) {
      String statement = context.getStringAttribute("statement");
      flushCacheStatements.add(statement);
    }
  }

  @NodeEvent("/sqlMap/cacheModel/end()")
  public void sqlMapcacheModelEnd(XNode context) throws Exception {
    if (cacheBuilder != null) {
      Cache cache = cacheBuilder.build();
      for (String sid : flushCacheStatements) {
        config.getFlushCachePlugin().addFlushOnExecute(sid, cache);
      }
      config.addCache(cache);
      flushCacheStatements = new ArrayList<String>();
    }
  }

  @NodeEvent("/sqlMap/resultMap")
  public void sqlMapresultMap(XNode context) throws Exception {
    String xmlName = context.getStringAttribute("xmlName");
    if (xmlName != null) {
      throw new UnsupportedOperationException("xmlName is not supported by iBATIS 3");
    }

    String id = applyNamespace(context.getStringAttribute("id"));
    String resultClassName = context.getStringAttribute("class");
    String extendedId = applyNamespace(context.getStringAttribute("extends"));

    String groupBy = context.getStringAttribute("groupBy");
    if (groupBy != null) {
      groupByProperties = Arrays.asList(groupBy.split(", "));
    }

    Class resultClass;
    try {
      resultClass = config.getTypeAliasRegistry().resolveAlias(resultClassName);
    } catch (Exception e) {
      throw new RuntimeException("Error configuring Result.  Could not set ResultClass.  Cause: " + e, e);
    }

    resultMappingList = new ArrayList<ResultMapping>();
    resultMapBuilder = new ResultMap.Builder(config, id, resultClass, resultMappingList);

    if (extendedId != null) {
      ResultMap extendedResultMap = config.getResultMap(extendedId);
      for (ResultMapping mapping : extendedResultMap.getResultMappings()) {
        resultMappingList.add(mapping);
      }
      resultMapBuilder.discriminator(extendedResultMap.getDiscriminator());
    }

  }

  @NodeEvent("/sqlMap/resultMap/discriminator")
  public void sqlMapresultMapdiscriminator(XNode context) throws Exception {
    String nullValue = context.getStringAttribute("nullValue");
    if (nullValue != null) {
      throw new UnsupportedOperationException("Null value subsitution is not supported by iBATIS 3.");
    }
    String columnIndexProp = context.getStringAttribute("columnIndex");
    if (columnIndexProp != null) {
      throw new UnsupportedOperationException("Numerical column indices are not supported.  Use the column name instead.");
    }

    String jdbcType = context.getStringAttribute("jdbcType");
    String javaType = context.getStringAttribute("javaType");
    String columnName = context.getStringAttribute("column");
    String callback = context.getStringAttribute("typeHandler");

    Class javaClass = null;
    try {
      if (javaType != null && javaType.length() > 0) {
        javaClass = config.getTypeAliasRegistry().resolveAlias(javaType);
      }
    } catch (Exception e) {
      throw new RuntimeException("Error setting java type on result discriminator mapping.  Cause: " + e);
    }

    JdbcType jdbcTypeEnum = null;
    if (jdbcType != null) {
      jdbcTypeEnum = JdbcType.valueOf(jdbcType);
    }

    TypeHandler typeHandler = null;
    if (javaClass != null) {
      typeHandler = config.getTypeHandlerRegistry().getTypeHandler(javaClass, jdbcTypeEnum);
    }
    try {
      if (callback != null && callback.length() > 0) {
        typeHandler = (TypeHandler) config.getTypeAliasRegistry().resolveAlias(callback).newInstance();
      }
    } catch (Exception e) {
      throw new RuntimeException("Error occurred during custom type handler configuration.  Cause: " + e, e);
    }


    ResultMapping.Builder resultMappingBuilder = new ResultMapping.Builder(config, columnName, columnName, typeHandler);
    resultMappingBuilder.javaType(javaClass);
    resultMappingBuilder.jdbcType(jdbcTypeEnum);
    ResultMapping resultMapping = resultMappingBuilder.build();

    discriminatorSubMap = new HashMap<String, String>();
    discriminatorBuilder = new Discriminator.Builder(config, resultMapping, discriminatorSubMap);

  }

  @NodeEvent("/sqlMap/resultMap/discriminator/subMap")
  public void sqlMapresultMapdiscriminatorsubMap(XNode context) throws Exception {
    String value = context.getStringAttribute("value");
    String resultMap = context.getStringAttribute("resultMap");
    resultMap = applyNamespace(resultMap);
    discriminatorSubMap.put(value, resultMap);
  }

  @NodeEvent("/sqlMap/resultMap/discriminator/end()")
  public void sqlMapresultMapdiscriminatorEnd(XNode context) throws Exception {
    resultMapBuilder.discriminator(discriminatorBuilder.build());
  }


  @NodeEvent("/sqlMap/resultMap/result")
  public void sqlMapresultMapresult(XNode context) throws Exception {
    String nullValue = context.getStringAttribute("nullValue");
    if (nullValue != null) {
      throw new UnsupportedOperationException("Null value subsitution is not supported by iBATIS 3.");
    }
    String columnIndexProp = context.getStringAttribute("columnIndex");
    if (columnIndexProp != null) {
      throw new UnsupportedOperationException("Numerical column indices are not supported.  Use the column name instead.");
    }

    String propertyName = context.getStringAttribute("property");
    String jdbcType = context.getStringAttribute("jdbcType");
    String javaType = context.getStringAttribute("javaType");
    String columnName = context.getStringAttribute("column");

    String statementName = context.getStringAttribute("select");
    String resultMapName = context.getStringAttribute("resultMap");
    String callback = context.getStringAttribute("typeHandler");

    Class javaClass = null;
    try {
      if (javaType != null && javaType.length() > 0) {
        javaClass = config.getTypeAliasRegistry().resolveAlias(javaType);
      }
    } catch (Exception e) {
      throw new RuntimeException("Error setting java type on result discriminator mapping.  Cause: " + e);
    }
    if (javaClass == null
        && !Map.class.isAssignableFrom(resultMapBuilder.type())
        && !config.getTypeHandlerRegistry().hasTypeHandler(resultMapBuilder.type())) {
      javaClass = MetaClass.forClass(resultMapBuilder.type()).getSetterType(propertyName);
    }
    if (javaClass == null && statementName != null) {
      javaClass = List.class;
    }

    JdbcType jdbcTypeEnum = null;
    if (jdbcType != null) {
      jdbcTypeEnum = JdbcType.valueOf(jdbcType);
    }

    TypeHandler typeHandler = null;
    if (javaClass != null) {
      typeHandler = config.getTypeHandlerRegistry().getTypeHandler(javaClass, jdbcTypeEnum);
    }
    try {
      if (callback != null && callback.length() > 0) {
        Object o = config.getTypeAliasRegistry().resolveAlias(callback).newInstance();
        if (o instanceof TypeHandlerCallback) {
          typeHandler = new TypeHandlerCallbackAdapter((TypeHandlerCallback) o);
        }
      }
    } catch (Exception e) {
      throw new RuntimeException("Error occurred during custom type handler configuration.  Cause: " + e, e);
    }
    if (typeHandler == null && config.getTypeHandlerRegistry().hasTypeHandler(resultMapBuilder.type())) {
      typeHandler = config.getTypeHandlerRegistry().getTypeHandler(resultMapBuilder.type());
    }

    if (typeHandler == null) {
      Class resultClass = resultMapBuilder.type();
      if (resultClass != null && !Map.class.isAssignableFrom(resultClass)) {
        MetaClass metaResultClass = MetaClass.forClass(resultClass);
        Class resultType = null;
        if (metaResultClass.hasGetter(propertyName)) {
          resultType = metaResultClass.getGetterType(propertyName);
        } else if (metaResultClass.hasSetter(propertyName)) {
          resultType = metaResultClass.getSetterType(propertyName);
        }
        if (resultType != null) {
          typeHandler = config.getTypeHandlerRegistry().getTypeHandler(resultType);
        }
      } else {
        typeHandler = config.getTypeHandlerRegistry().getUnknownTypeHandler();
      }
    }

    List<ResultMapping> composites = parseCompositeColumnName(columnName);
    if (composites.size() > 0) {
      ResultMapping first = composites.get(0);
      columnName = first.getColumn();
    }

    ResultMapping.Builder resultMappingBuilder = new ResultMapping.Builder(config, propertyName, columnName, typeHandler);
    resultMappingBuilder.javaType(javaClass);
    resultMappingBuilder.nestedQueryId(statementName);
    resultMappingBuilder.nestedResultMapId(resultMapName);
    resultMappingBuilder.jdbcType(jdbcTypeEnum);
    resultMappingBuilder.composites(composites);
    if (groupByProperties != null && groupByProperties.contains(propertyName)) {
      List<ResultFlag> flags = new ArrayList<ResultFlag>();
      resultMappingBuilder.flags(flags);
    }
    resultMappingList.add(resultMappingBuilder.build());
  }

  private List<ResultMapping> parseCompositeColumnName(String columnName) {
    List<ResultMapping> composites = new ArrayList<ResultMapping>();
    if (columnName != null) {
      if (columnName.indexOf('=') > -1
          || columnName.indexOf(',') > -1) {
        StringTokenizer parser = new StringTokenizer(columnName, "{}=, ", false);
        while (parser.hasMoreTokens()) {
          String property = parser.nextToken();
          String column = parser.nextToken();
          ResultMapping.Builder complexBuilder = new ResultMapping.Builder(config, property, column, config.getTypeHandlerRegistry().getUnknownTypeHandler());
          composites.add(complexBuilder.build());
        }
      }
    }
    return composites;
  }

  @NodeEvent("/sqlMap/resultMap/end()")
  public void sqlMapresultMapend(XNode context) throws Exception {
    config.addResultMap(resultMapBuilder.build());
  }

  @NodeEvent("/sqlMap/parameterMap")
  public void sqlMapparameterMap(XNode context) throws Exception {
    String id = applyNamespace(context.getStringAttribute("id"));
    String parameterClassName = context.getStringAttribute("class");
    Class parameterClass = config.getTypeAliasRegistry().resolveAlias(parameterClassName);
    parameterMappingList = new ArrayList<ParameterMapping>();
    parameterMapBuilder = new ParameterMap.Builder(config, id, parameterClass, parameterMappingList);
  }

  @NodeEvent("/sqlMap/parameterMap/parameter")
  public void sqlMapparameterMapparameter(XNode context) throws Exception {
    String nullValue = context.getStringAttribute("nullValue");
    if (nullValue != null) {
      throw new UnsupportedOperationException("Null value subsitution is not supported by iBATIS 3.");
    }

    String propertyName = context.getStringAttribute("property");
    String jdbcType = context.getStringAttribute("jdbcType");
    String javaType = context.getStringAttribute("javaType");
    String resultMap = context.getStringAttribute("resultMap");
    String mode = context.getStringAttribute("mode");
    String callback = context.getStringAttribute("typeHandler");
    String numericScaleProp = context.getStringAttribute("numericScale");

    Class javaClass = null;
    try {
      if (javaType != null && javaType.length() > 0) {
        javaClass = config.getTypeAliasRegistry().resolveAlias(javaType);
      }
    } catch (Exception e) {
      throw new RuntimeException("Error setting javaType on parameter mapping.  Cause: " + e);
    }

    JdbcType jdbcTypeEnum = null;
    if (jdbcType != null) {
      jdbcTypeEnum = JdbcType.valueOf(jdbcType);
    }

    TypeHandler typeHandler = null;
    if (javaClass != null) {
      typeHandler = config.getTypeHandlerRegistry().getTypeHandler(javaClass, jdbcTypeEnum);
    }
    if (callback != null) {
      Object o = config.getTypeAliasRegistry().resolveAlias(callback).newInstance();
      if (o instanceof TypeHandlerCallback) {
        typeHandler = new TypeHandlerCallbackAdapter((TypeHandlerCallback) o);
      }
    }
    if (typeHandler == null && config.getTypeHandlerRegistry().hasTypeHandler(parameterMapBuilder.type())) {
      typeHandler = config.getTypeHandlerRegistry().getTypeHandler(parameterMapBuilder.type());
    }
    if (typeHandler == null) {
      Class parameterClass = parameterMapBuilder.type();
      if (parameterClass != null && !Map.class.isAssignableFrom(parameterClass)) {
        MetaClass metaParamClass = MetaClass.forClass(parameterClass);
        Class paramType = null;
        if (metaParamClass.hasGetter(propertyName)) {
          paramType = metaParamClass.getGetterType(propertyName);
        } else if (metaParamClass.hasSetter(propertyName)) {
          paramType = metaParamClass.getSetterType(propertyName);
        }
        if (paramType != null) {
          typeHandler = config.getTypeHandlerRegistry().getTypeHandler(paramType);
        }
      } else {
        typeHandler = config.getTypeHandlerRegistry().getUnknownTypeHandler();
      }
    }

    ParameterMode paramModeEnum = ParameterMode.IN;
    if (mode != null) {
      paramModeEnum = ParameterMode.valueOf(mode);
    }

    Integer numericScale = null;
    if (numericScaleProp != null) {
      numericScale = new Integer(numericScaleProp);
    }

    ParameterMapping.Builder parameterMappingBuilder = new ParameterMapping.Builder(config, propertyName, typeHandler);
    parameterMappingBuilder.javaType(javaClass);
    parameterMappingBuilder.jdbcType(jdbcTypeEnum);
    parameterMappingBuilder.mode(paramModeEnum);
    parameterMappingBuilder.numericScale(numericScale);
    parameterMappingBuilder.resultMapId(resultMap);

    parameterMappingList.add(parameterMappingBuilder.build());
  }


  @NodeEvent("/sqlMap/parameterMap/end()")
  public void sqlMapparameterMapend(XNode context) throws Exception {
    config.addParameterMap(parameterMapBuilder.build());
  }

  @NodeEvent("/sqlMap/sql")
  public void sqlMapsql(XNode context) throws Exception {
    String id = context.getStringAttribute("id");
    if (configParser.isUseStatementNamespaces()) {
      id = applyNamespace(id);
    }
    if (configParser.hasSqlFragment(id)) {
      throw new SqlMapException("Duplicate <sql>-include '" + id + "' found.");
    } else {
      configParser.addSqlFragment(id, context);
    }
  }

  @NodeEvent("/sqlMap/statement")
  public void sqlMapstatement(XNode context) throws Exception {
    new XmlSqlStatementParser(this).parseGeneralStatement(context);
  }

  @NodeEvent("/sqlMap/select")
  public void sqlMapselect(XNode context) throws Exception {
    new XmlSqlStatementParser(this).parseGeneralStatement(context);
  }

  @NodeEvent("/sqlMap/insert")
  public void sqlMapinsert(XNode context) throws Exception {
    new XmlSqlStatementParser(this).parseGeneralStatement(context);
  }

  @NodeEvent("/sqlMap/update")
  public void sqlMapupdate(XNode context) throws Exception {
    new XmlSqlStatementParser(this).parseGeneralStatement(context);
  }

  @NodeEvent("/sqlMap/delete")
  public void sqlMapdelete(XNode context) throws Exception {
    new XmlSqlStatementParser(this).parseGeneralStatement(context);
  }

  @NodeEvent("/sqlMap/procedure")
  public void sqlMapprocedure(XNode context) throws Exception {
    new XmlSqlStatementParser(this).parseGeneralStatement(context);
  }

}
TOP

Related Classes of com.ibatis.sqlmap.engine.builder.XmlSqlMapParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.