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

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

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

import com.ibatis.common.beans.Probe;
import com.ibatis.common.beans.ProbeFactory;
import com.ibatis.common.resources.Resources;
import com.ibatis.common.xml.NodeletUtils;
import com.ibatis.sqlmap.client.SqlMapException;
import com.ibatis.sqlmap.engine.cache.CacheModel;
import com.ibatis.sqlmap.engine.mapping.parameter.BasicParameterMap;
import com.ibatis.sqlmap.engine.mapping.parameter.InlineParameterMapParser;
import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap;
import com.ibatis.sqlmap.engine.mapping.result.AutoResultMap;
import com.ibatis.sqlmap.engine.mapping.result.BasicResultMap;
import com.ibatis.sqlmap.engine.mapping.sql.Sql;
import com.ibatis.sqlmap.engine.mapping.sql.SqlText;
import com.ibatis.sqlmap.engine.mapping.sql.dynamic.DynamicSql;
import com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.*;
import com.ibatis.sqlmap.engine.mapping.sql.simple.SimpleDynamicSql;
import com.ibatis.sqlmap.engine.mapping.sql.stat.StaticSql;
import com.ibatis.sqlmap.engine.mapping.statement.*;
import org.w3c.dom.CharacterData;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.sql.ResultSet;
import java.util.*;

public class SqlStatementParser extends BaseParser {

  private static final Probe PROBE = ProbeFactory.getProbe();

  private static final InlineParameterMapParser PARAM_PARSER = new InlineParameterMapParser();

  public SqlStatementParser(Variables vars) {
    super(vars);
  }

  public MappedStatement parseGeneralStatement(Node node, GeneralStatement statement) {
    vars.errorCtx.setActivity("parsing a mapped statement");

    // get attributes
    Properties attributes = NodeletUtils.parseAttributes(node, vars.currentProperties);
    String id = attributes.getProperty("id");

    if (vars.useStatementNamespaces) {
      id = applyNamespace(id);
    }

    String parameterMapName = applyNamespace(attributes.getProperty("parameterMap"));
    String parameterClassName = attributes.getProperty("parameterClass");
    String resultMapName = attributes.getProperty("resultMap");
    String resultClassName = attributes.getProperty("resultClass");
    String cacheModelName = applyNamespace(attributes.getProperty("cacheModel"));
    String xmlResultName = attributes.getProperty("xmlResultName");
    String resultSetType = attributes.getProperty("resultSetType");
    String fetchSize = attributes.getProperty("fetchSize");
    String allowRemapping = attributes.getProperty("remapResults");
    String timeout = attributes.getProperty("timeout");

    String[] additionalResultMapNames;
    List additionalResultMaps = new ArrayList();

    vars.errorCtx.setObjectId(id + " statement");


    // get parameter and result maps

    vars.errorCtx.setMoreInfo("Check the result map name.");
    //BasicResultMap resultMap = null;
    if (resultMapName != null) {
      additionalResultMapNames = getAllButFirstToken(resultMapName);
      resultMapName = getFirstToken (resultMapName);
      statement.setResultMap((BasicResultMap) vars.client.getDelegate().getResultMap(applyNamespace(resultMapName)));
      for (int i=0; i < additionalResultMapNames.length; i++) {
        statement.addResultMap((BasicResultMap) vars.client.getDelegate().getResultMap(applyNamespace(additionalResultMapNames[i])));
      }
    }

    vars.errorCtx.setMoreInfo("Check the parameter map name.");

    if (parameterMapName != null) {
      statement.setParameterMap((BasicParameterMap) vars.client.getDelegate().getParameterMap(parameterMapName));
    }

    statement.setId(id);
    statement.setResource(vars.errorCtx.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) {
          vars.errorCtx.setMoreInfo("Check the parameter class.");
          parameterClassName = vars.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
    vars.errorCtx.setMoreInfo("Check the SQL statement.");
    processSqlStatement(node, 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(vars.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");
      }
    }

    vars.errorCtx.setMoreInfo(null);
    vars.errorCtx.setObjectId(null);

    statement.setSqlMapClient(vars.client);
    if (cacheModelName != null && cacheModelName.length() > 0 && vars.client.getDelegate().isCacheModelsEnabled()) {
      CacheModel cacheModel = vars.client.getDelegate().getCacheModel(cacheModelName);
      return new CachingStatement(statement, cacheModel);
    } else {
      return statement;
    }

  }

  private BasicResultMap buildAutoResultMap(String allowRemapping, GeneralStatement statement, String firstResultClass, String xmlResultName) {
    BasicResultMap resultMap;
    resultMap = new AutoResultMap(vars.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) {
        vars.errorCtx.setMoreInfo("Check the result class.");
        return Resources.classForName(vars.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()]);
  }

  private void processSqlStatement(Node n, GeneralStatement statement) {
    vars.errorCtx.setActivity("processing an SQL statement");

    boolean isDynamic = false;
    DynamicSql dynamic = new DynamicSql(vars.client.getDelegate());
    StringBuffer sqlBuffer = new StringBuffer();

    isDynamic = parseDynamicTags(n, dynamic, sqlBuffer, isDynamic, false);
    if (statement instanceof InsertStatement) {
      InsertStatement insertStatement = ((InsertStatement) statement);
      SelectKeyStatement selectKeyStatement = findAndParseSelectKeyStatement(n, statement);
      insertStatement.setSelectKeyStatement(selectKeyStatement);
    }

    String sqlStatement = sqlBuffer.toString();
    if (isDynamic) {
      statement.setSql(dynamic);
    } else {
      applyInlineParameterMap(statement, sqlStatement);
    }

  }

  private boolean parseDynamicTags(Node node, DynamicParent dynamic, StringBuffer sqlBuffer, boolean isDynamic, boolean postParseRequired) {
    vars.errorCtx.setActivity("parsing dynamic SQL tags");

    NodeList children = node.getChildNodes();
    for (int i = 0; i < children.getLength(); i++) {
      Node child = children.item(i);
      String nodeName = child.getNodeName();
      if (child.getNodeType() == Node.CDATA_SECTION_NODE
          || child.getNodeType() == Node.TEXT_NODE) {

        String data = ((CharacterData) child).getData();
        data = NodeletUtils.parsePropertyTokens(data, vars.properties);

        SqlText sqlText;

        if (postParseRequired) {
          sqlText = new SqlText();
          sqlText.setPostParseRequired(postParseRequired);
          sqlText.setText(data);
        } else {
          sqlText = PARAM_PARSER.parseInlineParameterMap(vars.client.getDelegate().getTypeHandlerFactory(), data, null);
          sqlText.setPostParseRequired(postParseRequired);
        }

        dynamic.addChild(sqlText);

        sqlBuffer.append(data);
      } else if ("include".equals(nodeName)) {
        Properties attributes = NodeletUtils.parseAttributes(child, vars.properties);
        String refid = (String) attributes.get("refid");
        Node includeNode = (Node) vars.sqlIncludes.get(refid);
        if (includeNode == null) {
          String nsrefid = applyNamespace(refid);
          includeNode = (Node) vars.sqlIncludes.get(nsrefid);
          if (includeNode == null) {
            throw new RuntimeException("Could not find SQL statement to include with refid '" + refid + "'");
          }
        }
        isDynamic = parseDynamicTags(includeNode, dynamic, sqlBuffer, isDynamic, false);
      } else {
        vars.errorCtx.setMoreInfo("Check the dynamic tags.");

        SqlTagHandler handler = SqlTagHandlerFactory.getSqlTagHandler(nodeName);
        if (handler != null) {
          isDynamic = true;

          SqlTag tag = new SqlTag();
          tag.setName(nodeName);
          tag.setHandler(handler);

          Properties attributes = NodeletUtils.parseAttributes(child, vars.properties);

          tag.setPrependAttr(attributes.getProperty("prepend"));
          tag.setPropertyAttr(attributes.getProperty("property"));
          tag.setRemoveFirstPrepend(attributes.getProperty("removeFirstPrepend"));

          tag.setOpenAttr(attributes.getProperty("open"));
          tag.setCloseAttr(attributes.getProperty("close"));

          tag.setComparePropertyAttr(attributes.getProperty("compareProperty"));
          tag.setCompareValueAttr(attributes.getProperty("compareValue"));
          tag.setConjunctionAttr(attributes.getProperty("conjunction"));

          // an iterate ancestor requires a post parse

          if(dynamic instanceof SqlTag) {
            SqlTag parentSqlTag = (SqlTag)dynamic;
            if(parentSqlTag.isPostParseRequired() ||
               tag.getHandler() instanceof IterateTagHandler) {
              tag.setPostParseRequired(true);
            }
          } else if (dynamic instanceof DynamicSql) {
              if(tag.getHandler() instanceof IterateTagHandler) {
                tag.setPostParseRequired(true);
              }
          }

          dynamic.addChild(tag);

          if (child.hasChildNodes()) {
            isDynamic = parseDynamicTags(child, tag, sqlBuffer, isDynamic, tag.isPostParseRequired());
          }
        }
      }
    }
    vars.errorCtx.setMoreInfo(null);
    return isDynamic;
  }

  private SelectKeyStatement findAndParseSelectKeyStatement(Node n, GeneralStatement insertStatement) {
    vars.errorCtx.setActivity("parsing select key tags");

    SelectKeyStatement selectKeyStatement = null;

    boolean foundTextFirst = false;
    boolean hasType = false;

    NodeList children = n.getChildNodes();
    for (int i = 0; i < children.getLength(); i++) {
      Node child = children.item(i);
      if (child.getNodeType() == Node.CDATA_SECTION_NODE
          || child.getNodeType() == Node.TEXT_NODE) {
        String data = ((CharacterData) child).getData();
        if (data.trim().length() > 0) {
          foundTextFirst = true;
        }
      } else if (child.getNodeType() == Node.ELEMENT_NODE
          && "selectKey".equals(child.getNodeName())) {
        selectKeyStatement = new SelectKeyStatement();
        hasType = parseSelectKey(child, insertStatement, selectKeyStatement);
        break;
      }
    }
    if (selectKeyStatement != null && !hasType) {
      selectKeyStatement.setAfter(foundTextFirst);
    }
    vars.errorCtx.setMoreInfo(null);
    return selectKeyStatement;
  }

  /**
   *
   * @param node
   * @param insertStatement
   * @param selectKeyStatement
   * @return true is the type (pre or post) was set from the configuration
   *   false if the type (pre or post) should be inferred from the position
   *   of the element in the text (the legacy behavior)
   */
  private boolean parseSelectKey(Node node, GeneralStatement insertStatement, SelectKeyStatement selectKeyStatement) {
    vars.errorCtx.setActivity("parsing a select key");

    // get attributes
    Properties attributes = NodeletUtils.parseAttributes(node, vars.properties);
    String keyPropName = attributes.getProperty("keyProperty");
    String resultClassName = attributes.getProperty("resultClass");
    resultClassName = vars.typeHandlerFactory.resolveAlias(resultClassName);
    Class resultClass = null;

    // get parameter and result maps
    selectKeyStatement.setSqlMapClient(vars.client);

    selectKeyStatement.setId(insertStatement.getId() + "-SelectKey");
    selectKeyStatement.setResource(vars.errorCtx.getResource());
    selectKeyStatement.setKeyProperty(keyPropName);

    // process the type (pre or post) attribute
    boolean hasType;
    String type = attributes.getProperty("type");
    if (type == null) {
      hasType = false;
    } else {
      hasType = true;
      selectKeyStatement.setAfter("post".equals(type));
    }

    try {
      if (resultClassName != null) {
        vars.errorCtx.setMoreInfo("Check the select key result class.");
        resultClass = Resources.classForName(resultClassName);
      } else {
        Class parameterClass = insertStatement.getParameterClass();
        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
    vars.errorCtx.setMoreInfo("Check the select key SQL statement.");
    processSqlStatement(node, selectKeyStatement);

    BasicResultMap resultMap;
    resultMap = new AutoResultMap(vars.client.getDelegate(), false);
    resultMap.setId(selectKeyStatement.getId() + "-AutoResultMap");
    resultMap.setResultClass(resultClass);
    resultMap.setResource(selectKeyStatement.getResource());
    selectKeyStatement.setResultMap(resultMap);

    vars.errorCtx.setMoreInfo(null);
    return hasType;
  }

  private void applyInlineParameterMap(GeneralStatement statement, String sqlStatement) {
    String newSql = sqlStatement;

    vars.errorCtx.setActivity("building an inline parameter map");

    ParameterMap parameterMap = statement.getParameterMap();

    vars.errorCtx.setMoreInfo("Check the inline parameters.");
    if (parameterMap == null) {

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

      map.setId(statement.getId() + "-InlineParameterMap");
      map.setParameterClass(statement.getParameterClass());
      map.setResource(statement.getResource());
      statement.setParameterMap(map);

      SqlText sqlText = PARAM_PARSER.parseInlineParameterMap(vars.client.getDelegate().getTypeHandlerFactory(), newSql, statement.getParameterClass());
      newSql = sqlText.getText();
      List mappingList = Arrays.asList(sqlText.getParameterMappings());

      map.setParameterMappingList(mappingList);

    }

    Sql sql = null;
    if (SimpleDynamicSql.isSimpleDynamicSql(newSql)) {
      sql = new SimpleDynamicSql(vars.client.getDelegate(), newSql);
    } else {
      sql = new StaticSql(newSql);
    }
    statement.setSql(sql);

  }

}
TOP

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

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.