com.nabla.wapp.server.database.UpdateStatement.java Source code

Java tutorial

Introduction

Here is the source code for com.nabla.wapp.server.database.UpdateStatement.java

Source

/**
* Copyright 2012 nabla
*
* 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.nabla.wapp.server.database;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.nabla.wapp.server.general.Assert;
import com.nabla.wapp.shared.database.IRecordField;
import com.nabla.wapp.shared.database.IRecordTable;
import com.nabla.wapp.shared.dispatch.DispatchException;
import com.nabla.wapp.shared.general.ArgumentList;
import com.nabla.wapp.shared.general.CommonServerErrors;
import com.nabla.wapp.shared.model.ValidationException;

public class UpdateStatement<T> extends SqlStatement {

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

    private final String sqlTemplate;
    private final List<IStatementParameter> parameters = new ArrayList<IStatementParameter>();
    private IStatementParameter recordId = null;
    private String uniqueFieldName = null; // null if n/a

    public UpdateStatement(final Class<T> recordClass) {
        final IRecordTable table = commonConstructor(recordClass);
        Assert.state(recordId != null);
        Assert.notNull(table);
        // build SQL template
        sqlTemplate = "UPDATE " + table.name() + " SET {0} WHERE " + recordId.getName() + "=?;";
    }

    public UpdateStatement(final Class<T> recordClass, final String sqlTemplate) {
        commonConstructor(recordClass);
        Assert.state(recordId != null);
        this.sqlTemplate = sqlTemplate;
    }

    @SuppressWarnings("unchecked")
    private IRecordTable commonConstructor(final Class clazz) {
        if (clazz == null)
            return null;
        final IRecordTable t = (IRecordTable) clazz.getAnnotation(IRecordTable.class);
        for (Field field : clazz.getDeclaredFields()) {
            final IRecordField definition = field.getAnnotation(IRecordField.class);
            if (definition == null)
                continue;
            if (definition.id())
                recordId = createParameter(field);
            else {
                if (definition.unique())
                    uniqueFieldName = field.getName();
                parameters.add(createParameter(field));
            }
        }
        final IRecordTable tt = commonConstructor(clazz.getSuperclass());
        return (t == null) ? tt : t;
    }

    public void execute(final Connection conn, final T record)
            throws SQLException, DispatchException, ValidationException {
        Assert.argumentNotNull(conn);

        final List<IStatementParameter> parametersToUpdate = new ArrayList<IStatementParameter>();
        final ArgumentList updates = new ArgumentList();
        for (IStatementParameter parameter : parameters) {
            if (!parameter.include(record))
                continue;
            parametersToUpdate.add(parameter);
            updates.add(parameter.getName() + "=?");
        }
        if (parametersToUpdate.isEmpty()) {
            if (log.isDebugEnabled())
                log.debug("no values to update");
            return;
        }
        final String sql = MessageFormat.format(sqlTemplate, updates.toString());
        if (log.isDebugEnabled())
            log.debug("SQL=" + sql);
        final PreparedStatement stmt = conn.prepareStatement(sql);
        try {
            int i = 1;
            for (IStatementParameter parameter : parametersToUpdate)
                parameter.write(stmt, i++, record);
            recordId.write(stmt, i++, record);
            if (stmt.executeUpdate() != 1)
                throw new DispatchException(CommonServerErrors.RECORD_HAS_BEEN_REMOVED);
        } catch (final SQLException e) {
            if (uniqueFieldName != null && SQLState.valueOf(e) == SQLState.INTEGRITY_CONSTRAINT_VIOLATION) {
                if (log.isErrorEnabled())
                    log.error("SQL error " + e.getErrorCode() + "-" + e.getSQLState(), e);
                throw new ValidationException(uniqueFieldName, CommonServerErrors.DUPLICATE_ENTRY);
            }
            throw e;
        } finally {
            Database.close(stmt);
        }
    }

}