Package com.ibatis.sqlmap.engine.builder.xml

Source Code of com.ibatis.sqlmap.engine.builder.xml.SqlMapParser

package com.ibatis.sqlmap.engine.builder.xml;

import com.ibatis.common.logging.Log;
import com.ibatis.common.logging.LogFactory;
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.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.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Iterator;

public class SqlMapParser extends BaseParser {

  private static final Log log = LogFactory.getLog(SqlMapParser.class);

  protected final NodeletParser parser = new NodeletParser();

  public SqlMapParser(Variables vars) {
    super(vars);
    parser.setValidation(true);
    parser.setEntityResolver(new SqlMapClasspathEntityResolver());

    addSqlMapNodelets();
    addSqlNodelets();
    addTypeAliasNodelets();
    addCacheModelNodelets();
    addParameterMapNodelets();
    addResultMapNodelets();
    addStatementNodelets();

  }

  public void parse(Reader reader) throws NodeletException {
    parser.parse(reader);
  }

  private void addSqlMapNodelets() {
    parser.addNodelet("/sqlMap", new Nodelet() {
      public void process(Node node) throws Exception {
        Properties attributes = NodeletUtils.parseAttributes(node, vars.properties);
        vars.currentNamespace = attributes.getProperty("namespace");
      }
    });
    parser.addNodelet("/sqlMap/end()", new Nodelet() {
      public void process(Node node) throws Exception {
        Iterator names = vars.delegate.getResultMapNames();
        while (names.hasNext()) {
          String name = (String)names.next();
          ResultMap rm = vars.delegate.getResultMap(name);
          Discriminator disc = rm.getDiscriminator();
          if (disc != null) {
            disc.bindSubMaps();
          }
        }
      }
    });
  }

  private void addSqlNodelets() {
    parser.addNodelet("/sqlMap/sql", new Nodelet() {
      public void process(Node node) throws Exception {
        Properties attributes = NodeletUtils.parseAttributes(node, vars.properties);
        String id = attributes.getProperty("id");
        if (vars.useStatementNamespaces) {
          id = applyNamespace(id);
        }
        if (vars.sqlIncludes.containsKey(id)) {
          // To be upgraded to throwing of a RuntimeException later on
          log.warn("Duplicate <sql>-include '" + id + "' found.");
        }
        else  {
          vars.sqlIncludes.put(id, node);
        }
      }
    });
  }

  private void addTypeAliasNodelets() {
    parser.addNodelet("/sqlMap/typeAlias", new Nodelet() {
      public void process(Node node) throws Exception {
        Properties prop = NodeletUtils.parseAttributes(node, vars.properties);
        String alias = prop.getProperty("alias");
        String type = prop.getProperty("type");
        vars.typeHandlerFactory.putTypeAlias(alias, type);
      }
    });
  }

  private void addCacheModelNodelets() {
    parser.addNodelet("/sqlMap/cacheModel", new Nodelet() {
      public void process(Node node) throws Exception {
        vars.currentCacheModel = new CacheModel();
        vars.currentProperties = new Properties();
      }
    });
    parser.addNodelet("/sqlMap/cacheModel/end()", new Nodelet() {
      public void process(Node node) throws Exception {
        vars.errorCtx.setActivity("building a cache model");

        Properties attributes = NodeletUtils.parseAttributes(node, vars.properties);
        String id = applyNamespace(attributes.getProperty("id"));
        String type = attributes.getProperty("type");
        type = vars.typeHandlerFactory.resolveAlias(type);

        String readOnly = attributes.getProperty("readOnly");
        if (readOnly != null && readOnly.length() > 0) {
          vars.currentCacheModel.setReadOnly("true".equals(readOnly));
        } else {
          vars.currentCacheModel.setReadOnly(true);
        }

        String serialize = attributes.getProperty("serialize");
        if (serialize != null && serialize.length() > 0) {
          vars.currentCacheModel.setSerialize("true".equals(serialize));
        } else {
          vars.currentCacheModel.setSerialize(false);
        }

        vars.errorCtx.setObjectId(id + " cache model");

        vars.errorCtx.setMoreInfo("Check the cache model type.");
        vars.currentCacheModel.setId(id);
        vars.currentCacheModel.setResource(vars.errorCtx.getResource());

        try {
          vars.currentCacheModel.setControllerClassName(type);
        } catch (Exception e) {
          throw new RuntimeException("Error setting Cache Controller Class.  Cause: " + e, e);
        }

        vars.errorCtx.setMoreInfo("Check the cache model configuration.");
        vars.currentCacheModel.configure(vars.currentProperties);

        if (vars.client.getDelegate().isCacheModelsEnabled()) {
          vars.client.getDelegate().addCacheModel(vars.currentCacheModel);
        }

        vars.errorCtx.setMoreInfo(null);
        vars.errorCtx.setObjectId(null);
        vars.currentProperties = null;
        vars.currentCacheModel = null;
      }
    });
    parser.addNodelet("/sqlMap/cacheModel/property", new Nodelet() {
      public void process(Node node) throws Exception {
        vars.errorCtx.setMoreInfo("Check the cache model properties.");
        Properties attributes = NodeletUtils.parseAttributes(node, vars.properties);
        String name = attributes.getProperty("name");
        String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), vars.properties);
        vars.currentProperties.put(name, value);
      }
    });
    parser.addNodelet("/sqlMap/cacheModel/flushOnExecute", new Nodelet() {
      public void process(Node node) throws Exception {
        vars.errorCtx.setMoreInfo("Check the cache model flush on statement elements.");
        Properties childAttributes = NodeletUtils.parseAttributes(node, vars.properties);
        vars.currentCacheModel.addFlushTriggerStatement(childAttributes.getProperty("statement"));
      }
    });
    parser.addNodelet("/sqlMap/cacheModel/flushInterval", new Nodelet() {
      public void process(Node node) throws Exception {
        Properties childAttributes = NodeletUtils.parseAttributes(node, vars.properties);
        long t = 0;
        try {
          vars.errorCtx.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.");
          vars.currentCacheModel.setFlushInterval(t);
        } catch (NumberFormatException e) {
          throw new RuntimeException("Error building cache '" + vars.currentCacheModel.getId() + "' in '" + "resourceNAME" + "'.  Flush interval milliseconds must be a valid long integer value.  Cause: " + e, e);
        }
      }
    });
  }

  private void addParameterMapNodelets() {
    parser.addNodelet("/sqlMap/parameterMap/end()", new Nodelet() {
      public void process(Node node) throws Exception {

        vars.currentParameterMap.setParameterMappingList(vars.parameterMappingList);

        vars.client.getDelegate().addParameterMap(vars.currentParameterMap);

        vars.errorCtx.setMoreInfo(null);
        vars.errorCtx.setObjectId(null);
      }
    });
    parser.addNodelet("/sqlMap/parameterMap", new Nodelet() {
      public void process(Node node) throws Exception {
        vars.errorCtx.setActivity("building a parameter map");

        vars.currentParameterMap = new BasicParameterMap(vars.client.getDelegate());

        Properties attributes = NodeletUtils.parseAttributes(node, vars.properties);
        String id = applyNamespace(attributes.getProperty("id"));
        String parameterClassName = attributes.getProperty("class");
        parameterClassName = vars.typeHandlerFactory.resolveAlias(parameterClassName);

        vars.currentParameterMap.setId(id);
        vars.currentParameterMap.setResource(vars.errorCtx.getResource());

        vars.errorCtx.setObjectId(id + " parameter map");

        Class parameterClass = null;
        try {
          vars.errorCtx.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);
        }

        vars.currentParameterMap.setParameterClass(parameterClass);

        vars.parameterMappingList = new ArrayList();

        vars.errorCtx.setMoreInfo("Check the parameter mappings.");
      }
    });
    parser.addNodelet("/sqlMap/parameterMap/parameter", new Nodelet() {
      public void process(Node node) throws Exception {
        Properties childAttributes = NodeletUtils.parseAttributes(node, vars.properties);
        String propertyName = childAttributes.getProperty("property");
        String jdbcType = childAttributes.getProperty("jdbcType");
        String type     = childAttributes.getProperty("typeName");
        String javaType = childAttributes.getProperty("javaType");
        String resultMap = childAttributes.getProperty("resultMap");
        String nullValue = childAttributes.getProperty("nullValue");
        String mode = childAttributes.getProperty("mode");
        String callback = childAttributes.getProperty("typeHandler");
        String numericScale = childAttributes.getProperty("numericScale");

        callback = vars.typeHandlerFactory.resolveAlias(callback);
        javaType = vars.typeHandlerFactory.resolveAlias(javaType);
        resultMap = applyNamespace( resultMap );

        vars.errorCtx.setObjectId(propertyName + " mapping of the " + vars.currentParameterMap.getId() + " parameter map");

        TypeHandler handler = null;
        if (callback != null) {
          vars.errorCtx.setMoreInfo("Check the parameter mapping typeHandler attribute '" + callback + "' (must be a TypeHandler or TypeHandlerCallback implementation).");
          try {
            Object impl = Resources.classForName(callback).newInstance();
            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 {
          vars.errorCtx.setMoreInfo("Check the parameter mapping property type or name.");
          handler = resolveTypeHandler(vars.client.getDelegate().getTypeHandlerFactory(), vars.currentParameterMap.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");
          }
        }

        vars.parameterMappingList.add(mapping);

      }
    });
  }

  private void addResultMapNodelets() {
    parser.addNodelet("/sqlMap/resultMap/end()", new Nodelet() {
      public void process(Node node) throws Exception {
        vars.currentResultMap.setResultMappingList(vars.resultMappingList);

        vars.currentResultMap.setDiscriminator(vars.discriminator);
        vars.discriminator = null;

        vars.client.getDelegate().addResultMap(vars.currentResultMap);

        vars.errorCtx.setMoreInfo(null);

        vars.errorCtx.setObjectId(null);
      }
    });
    parser.addNodelet("/sqlMap/resultMap", new Nodelet() {
      public void process(Node node) throws Exception {
        vars.errorCtx.setActivity("building a result map");

        vars.currentResultMap = new BasicResultMap(vars.client.getDelegate());

        Properties attributes = NodeletUtils.parseAttributes(node, vars.properties);
        String id = applyNamespace(attributes.getProperty("id"));
        String resultClassName = attributes.getProperty("class");
        String extended = applyNamespace(attributes.getProperty("extends"));
        String xmlName = attributes.getProperty("xmlName");
        String groupBy = attributes.getProperty("groupBy");
        resultClassName = vars.typeHandlerFactory.resolveAlias(resultClassName);

        vars.errorCtx.setObjectId(id + " result map");

        vars.currentResultMap.setId(id);
        vars.currentResultMap.setXmlName(xmlName);
        vars.currentResultMap.setResource(vars.errorCtx.getResource());

        if (groupBy != null && groupBy.length() > 0) {
          StringTokenizer parser = new StringTokenizer(groupBy, ", ", false);
          while (parser.hasMoreTokens()) {
            vars.currentResultMap.addGroupByProperty(parser.nextToken());
          }
        }

        Class resultClass = null;
        try {
          vars.errorCtx.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);

        }

        vars.currentResultMap.setResultClass(resultClass);

        vars.resultMappingList = new ArrayList();

        vars.errorCtx.setMoreInfo("Check the extended result map.");
        if (extended != null) {
          BasicResultMap extendedResultMap = (BasicResultMap) vars.client.getDelegate().getResultMap(extended);
          ResultMapping[] resultMappings = extendedResultMap.getResultMappings();
          for (int i = 0; i < resultMappings.length; i++) {
            vars.resultMappingList.add(resultMappings[i]);
          }

          List nestedResultMappings = extendedResultMap.getNestedResultMappings();
          if (nestedResultMappings != null) {
            Iterator iter = nestedResultMappings.iterator();
            while (iter.hasNext()) {
              vars.currentResultMap.addNestedResultMappings((ResultMapping) iter.next());
            }
          }
         
          if (groupBy == null || groupBy.length() == 0) {
            if (extendedResultMap.hasGroupBy()) {
              Iterator i = extendedResultMap.groupByProps();
              while (i.hasNext()) {
                vars.currentResultMap.addGroupByProperty((String) i.next());
              }
            }
          }
        }

        vars.errorCtx.setMoreInfo("Check the result mappings.");
        vars.resultMappingIndex = vars.resultMappingList.size();

      }
    });
    parser.addNodelet("/sqlMap/resultMap/result", new Nodelet() {
      public void process(Node node) throws Exception {
        Properties childAttributes = NodeletUtils.parseAttributes(node, vars.properties);
        String propertyName = childAttributes.getProperty("property");
        String nullValue = childAttributes.getProperty("nullValue");
        String jdbcType = childAttributes.getProperty("jdbcType");
        String javaType = childAttributes.getProperty("javaType");
        String columnName = childAttributes.getProperty("column");
        String columnIndex = childAttributes.getProperty("columnIndex");
        String statementName = childAttributes.getProperty("select");
        String resultMapName = childAttributes.getProperty("resultMap");
        String callback = childAttributes.getProperty("typeHandler");

        callback = vars.typeHandlerFactory.resolveAlias(callback);
        javaType = vars.typeHandlerFactory.resolveAlias(javaType);

        vars.errorCtx.setObjectId(propertyName + " mapping of the " + vars.currentResultMap.getId() + " result map");

        TypeHandler handler = null;
        if (callback != null) {
          vars.errorCtx.setMoreInfo("Check the result mapping typeHandler attribute '" + callback + "' (must be a TypeHandler or TypeHandlerCallback implementation).");
          try {
            Object impl = Resources.classForName(callback).newInstance();
            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 {
          vars.errorCtx.setMoreInfo("Check the result mapping property type or name.");
          handler = resolveTypeHandler(vars.client.getDelegate().getTypeHandlerFactory(), vars.currentResultMap.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) {
          vars.currentResultMap.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 {
          vars.resultMappingIndex++;
          mapping.setColumnIndex(vars.resultMappingIndex);
        }

        vars.resultMappingList.add(mapping);
      }
    });

    parser.addNodelet("/sqlMap/resultMap/discriminator/subMap", new Nodelet() {
      public void process(Node node) throws Exception {
        if (vars.discriminator == null) {
          throw new RuntimeException ("The discriminator is null, but somehow a subMap was reached.  This is a bug.");
        }
        Properties childAttributes = NodeletUtils.parseAttributes(node, vars.properties);
        String value = childAttributes.getProperty("value");
        String resultMap = childAttributes.getProperty("resultMap");
        vars.discriminator.addSubMap(value, applyNamespace(resultMap));
      }
    });

    parser.addNodelet("/sqlMap/resultMap/discriminator", new Nodelet() {
      public void process(Node node) throws Exception {
        Properties childAttributes = NodeletUtils.parseAttributes(node, vars.properties);
        String nullValue = childAttributes.getProperty("nullValue");
        String jdbcType = childAttributes.getProperty("jdbcType");
        String javaType = childAttributes.getProperty("javaType");
        String columnName = childAttributes.getProperty("column");
        String columnIndex = childAttributes.getProperty("columnIndex");
        String callback = childAttributes.getProperty("typeHandler");

        callback = vars.typeHandlerFactory.resolveAlias(callback);
        javaType = vars.typeHandlerFactory.resolveAlias(javaType);

        TypeHandler handler = null;
        if (callback != null) {
          vars.errorCtx.setMoreInfo("Check the result mapping typeHandler attribute '" + callback + "' (must be a TypeHandlerCallback implementation).");
          try {
            Object impl = Resources.classForName(callback).newInstance();
            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 {
          vars.errorCtx.setMoreInfo("Check the result mapping property type or name.");
          handler = resolveTypeHandler(vars.client.getDelegate().getTypeHandlerFactory(), vars.currentResultMap.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));
        }

        vars.discriminator = new Discriminator (vars.delegate, mapping);
      }
    });
  }

  protected void addStatementNodelets() {
    parser.addNodelet("/sqlMap/statement", new Nodelet() {
      public void process(Node node) throws Exception {
        vars.currentStatement = new SqlStatementParser(vars).parseGeneralStatement(node, new GeneralStatement());
        vars.delegate.addMappedStatement(vars.currentStatement);
      }
    });
    parser.addNodelet("/sqlMap/insert", new Nodelet() {
      public void process(Node node) throws Exception {
        vars.currentStatement = new SqlStatementParser(vars).parseGeneralStatement(node, new InsertStatement());
        vars.delegate.addMappedStatement(vars.currentStatement);
      }
    });
    parser.addNodelet("/sqlMap/update", new Nodelet() {
      public void process(Node node) throws Exception {
        vars.currentStatement = new SqlStatementParser(vars).parseGeneralStatement(node, new UpdateStatement());
        vars.delegate.addMappedStatement(vars.currentStatement);
      }
    });
    parser.addNodelet("/sqlMap/delete", new Nodelet() {
      public void process(Node node) throws Exception {
        vars.currentStatement = new SqlStatementParser(vars).parseGeneralStatement(node, new DeleteStatement());
        vars.delegate.addMappedStatement(vars.currentStatement);
      }
    });
    parser.addNodelet("/sqlMap/select", new Nodelet() {
      public void process(Node node) throws Exception {
        vars.currentStatement = new SqlStatementParser(vars).parseGeneralStatement(node, new SelectStatement());
        vars.delegate.addMappedStatement(vars.currentStatement);
      }
    });
    parser.addNodelet("/sqlMap/procedure", new Nodelet() {
      public void process(Node node) throws Exception {
        vars.currentStatement = new SqlStatementParser(vars).parseGeneralStatement(node, new ProcedureStatement());
        vars.delegate.addMappedStatement(vars.currentStatement);
      }
    });
  }


}
TOP

Related Classes of com.ibatis.sqlmap.engine.builder.xml.SqlMapParser

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.