com.sf.ddao.factory.DefaultStatementFactory.java Source code

Java tutorial

Introduction

Here is the source code for com.sf.ddao.factory.DefaultStatementFactory.java

Source

/*
 * Copyright 2008 Pavel Syrtsov
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and limitations
 *  under the License.
 */

package com.sf.ddao.factory;

import com.sf.ddao.conn.ConnectionHandlerHelper;
import com.sf.ddao.factory.param.ParameterException;
import com.sf.ddao.factory.param.ParameterFactory;
import com.sf.ddao.factory.param.ParameterHandler;
import org.apache.commons.chain.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import java.lang.reflect.AnnotatedElement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * DefaultStatementFactory creates new prepared statment using simplified IBATIS like query syntax: <br/>
 * value reference can be put using number that reflect 0 based method argument number
 * that will be used as simle value
 * (and as such can not be java bean or any other non trivial object)
 * or it can be name of java bean property or Map object that is 1st argument in the
 * list of method arguments.
 * Query paramter can be added as inline value by enclosing it in '$' or
 * it can be added as bound value by enclosing it in '#'. Inline value will be injected in
 * query text before query will be passed to JDBC connection. Bound value will be bound to
 * prepared statement before it's execution.
 * <p/>
 * Created by Pavel Syrtsov
 * Date: Nov 3, 2007
 * Time: 9:24:44 PM
 */
@SuppressWarnings("UnusedDeclaration")
public class DefaultStatementFactory implements StatementFactory {
    public static final Logger log = LoggerFactory.getLogger(DefaultStatementFactory.class.getName());
    private List<ParameterHandler> inlineParametersList = new ArrayList<ParameterHandler>();
    private List<ParameterHandler> refParametersList = new ArrayList<ParameterHandler>();
    private List<String> stmtTokens = new ArrayList<String>();
    @Inject
    private ParameterFactory parameterFactory;

    public void init(AnnotatedElement element, String sql) throws StatementFactoryException {
        try {
            char lastChar = 0;
            boolean paramStarted = false;
            StringBuilder token = new StringBuilder(sql.length());
            StringBuilder param = new StringBuilder();
            for (char ch : sql.toCharArray()) {
                if (paramStarted) {
                    if (lastChar == ch) {
                        stmtTokens.add(token.toString());
                        token.delete(0, token.length());
                        if (ch == '$') {
                            addInlineParameter(element, param.toString());
                        } else {
                            addRefParameter(element, param.toString());
                        }
                        param.delete(0, param.length());
                        paramStarted = false;
                        continue;
                    }
                    param.append(ch);
                    continue;
                }
                if (ch == '#' || ch == '$') {
                    paramStarted = true;
                    lastChar = ch;
                    continue;
                }
                token.append(ch);
            }
            stmtTokens.add(token.toString());
        } catch (Exception e) {
            throw new StatementFactoryException("Failed to extract statement parameters for " + element, e);
        }
    }

    public void addRefParameter(AnnotatedElement element, String name) throws ParameterException {
        ParameterHandler parameter = parameterFactory.createStatementParameter(element, name, true);
        refParametersList.add(parameter);
        inlineParametersList.add(parameter);
    }

    public void addInlineParameter(AnnotatedElement element, String name) throws ParameterException {
        ParameterHandler parameter = parameterFactory.createStatementParameter(element, name, false);
        inlineParametersList.add(parameter);
    }

    public PreparedStatement createStatement(Context context, boolean returnGeneratedKeys)
            throws StatementFactoryException {
        String stmt = null;
        try {
            stmt = createText(context);
            log.debug("Created statement:{}, applying parameters: {}", stmt, refParametersList);
            final Connection connection = ConnectionHandlerHelper.getConnection(context);
            PreparedStatement preparedStatement;
            if (returnGeneratedKeys) {
                preparedStatement = connection.prepareStatement(stmt, Statement.RETURN_GENERATED_KEYS);
            } else {
                preparedStatement = connection.prepareStatement(stmt);
            }
            int i = 1;
            for (ParameterHandler parameter : refParametersList) {
                i += parameter.bindParam(preparedStatement, i, context);
            }
            return preparedStatement;
        } catch (Exception e) {
            if (stmt == null) {
                stmt = stmtTokens.toString();
            }
            throw new StatementFactoryException("Failed to prepare statement '" + stmt + "'", e);
        }
    }

    public String createText(Context context) throws SQLException {
        Iterator<String> iterator = stmtTokens.iterator();
        String stmt = iterator.next();
        if (iterator.hasNext()) {
            StringBuilder sb = new StringBuilder();
            sb.append(stmt);
            for (ParameterHandler parameter : inlineParametersList) {
                parameter.appendParam(context, sb);
                sb.append(iterator.next());
            }
            stmt = sb.toString();
        }
        return stmt;
    }

    public List<ParameterHandler> getInlineParametersList() {
        return inlineParametersList;
    }

    public List<ParameterHandler> getRefParametersList() {
        return refParametersList;
    }

    public List<String> getStmtTokens() {
        return stmtTokens;
    }

    public ParameterFactory getParameterFactory() {
        return parameterFactory;
    }
}