nz.co.gregs.dbvolution.actions.DBUpdateLargeObjects.java Source code

Java tutorial

Introduction

Here is the source code for nz.co.gregs.dbvolution.actions.DBUpdateLargeObjects.java

Source

/*
 * Copyright 2013 Gregory Graham.
 *
 * 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 nz.co.gregs.dbvolution.actions;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import nz.co.gregs.dbvolution.DBDatabase;
import nz.co.gregs.dbvolution.DBRow;
import nz.co.gregs.dbvolution.databases.DBStatement;
import nz.co.gregs.dbvolution.databases.definitions.DBDefinition;
import nz.co.gregs.dbvolution.datatypes.DBLargeObject;
import nz.co.gregs.dbvolution.datatypes.QueryableDatatype;
import nz.co.gregs.dbvolution.exceptions.DBRuntimeException;
import nz.co.gregs.dbvolution.internal.properties.PropertyWrapper;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Provides support for the abstract concept of updating rows with BLOB columns.
 *
 * <p>
 * The best way to use this is by using {@link DBUpdate#getUpdates(nz.co.gregs.dbvolution.DBRow...)
 * } to automatically use this action.
 *
 * @author Gregory Graham
 */
public class DBUpdateLargeObjects extends DBUpdate {

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

    /**
     * Creates a DBUpdateLargeObjects action for the supplied row.
     *
     * @param row the row to be updated
     */
    protected DBUpdateLargeObjects(DBRow row) {
        super(row);
    }

    @Override
    protected DBActionList execute(DBDatabase db) throws SQLException {
        DBRow row = getRow();
        DBActionList actions = new DBActionList();
        DBDefinition defn = db.getDefinition();
        DBStatement statement = db.getDBStatement();
        try {
            actions = new DBActionList();
            for (PropertyWrapper prop : getInterestingLargeObjects(row)) {
                final String col = prop.columnName();
                final DBLargeObject largeObject = (DBLargeObject) prop.getQueryableDatatype();

                if (largeObject.isNull()) {
                    setToNullUsingStringValue(defn, row, col, largeObject, db, statement);
                } else {
                    if (defn.prefersLargeObjectsSetAsCharacterStream()) {
                        setUsingCharacterStream(defn, row, col, largeObject, db, statement);
                    } else if (defn.prefersLargeObjectsSetAsBase64String()) {
                        setUsingBase64String(defn, row, col, largeObject, db, statement);
                    } else if (defn.prefersLargeObjectsSetAsBLOB()) {
                        setUsingBLOB(defn, row, col, largeObject, db, statement);
                    } else {
                        setUsingBinaryStream(defn, row, col, largeObject, db, statement);
                    }
                }
                DBUpdateLargeObjects update = new DBUpdateLargeObjects(row);
                actions.add(update);
                largeObject.setUnchanged();
            }
        } catch (IOException ex) {
            Logger.getLogger(DBUpdateLargeObjects.class.getName()).log(Level.SEVERE, null, ex);
            throw new DBRuntimeException("Can't Set LargeObject: IOError", ex);
        } finally {
            statement.close();
        }
        return actions;
    }

    private void setUsingStringValue(DBDefinition defn, DBRow row, final String col,
            final DBLargeObject largeObject, DBDatabase db, DBStatement statement) throws SQLException {
        String sqlString = defn.beginUpdateLine() + defn.formatTableName(row) + defn.beginSetClause()
                + defn.formatColumnName(col) + defn.getEqualsComparator() + "'" + largeObject.stringValue() + "'"
                + defn.beginWhereClause() + defn.formatColumnName(row.getPrimaryKeyColumnName())
                + defn.getEqualsComparator() + row.getPrimaryKey().toSQLString(db) + defn.endSQLStatement();
        //               db.printSQLIfRequested(sqlString);
        log.debug(sqlString);
        statement.execute(sqlString);
    }

    private void setToNullUsingStringValue(DBDefinition defn, DBRow row, final String col,
            final DBLargeObject largeObject, DBDatabase db, DBStatement statement) throws SQLException {
        String sqlString = defn.beginUpdateLine() + defn.formatTableName(row) + defn.beginSetClause()
                + defn.formatColumnName(col) + defn.getEqualsComparator() + defn.getNull() + defn.beginWhereClause()
                + defn.formatColumnName(row.getPrimaryKeyColumnName()) + defn.getEqualsComparator()
                + row.getPrimaryKey().toSQLString(db) + defn.endSQLStatement();
        //               db.printSQLIfRequested(sqlString);
        log.debug(sqlString);
        statement.execute(sqlString);
    }

    private void setUsingBinaryStream(DBDefinition defn, DBRow row, final String col,
            final DBLargeObject largeObject, DBDatabase db, DBStatement statement) throws SQLException {
        String sqlString = defn.beginUpdateLine() + defn.formatTableName(row) + defn.beginSetClause()
                + defn.formatColumnName(col) + defn.getEqualsComparator() + defn.getPreparedVariableSymbol()
                + defn.beginWhereClause() + defn.formatColumnName(row.getPrimaryKeyColumnName())
                + defn.getEqualsComparator() + row.getPrimaryKey().toSQLString(db) + defn.endSQLStatement();
        //               db.printSQLIfRequested(sqlString);
        log.debug(sqlString);
        PreparedStatement prep = statement.getConnection().prepareStatement(sqlString);
        try {
            try {
                prep.setBinaryStream(1, largeObject.getInputStream());
            } catch (SQLException exp) {
                try {
                    prep.setBinaryStream(1, largeObject.getInputStream(), largeObject.getSize());
                } catch (SQLException exp2) {
                    throw new DBRuntimeException(exp);
                }
            }
            prep.execute();
        } finally {
            prep.close();
        }
    }

    private void setUsingBLOB(DBDefinition defn, DBRow row, String col, DBLargeObject largeObject, DBDatabase db,
            DBStatement statement) throws SQLException {
        String sqlString = defn.beginUpdateLine() + defn.formatTableName(row) + defn.beginSetClause()
                + defn.formatColumnName(col) + defn.getEqualsComparator() + defn.getPreparedVariableSymbol()
                + defn.beginWhereClause() + defn.formatColumnName(row.getPrimaryKeyColumnName())
                + defn.getEqualsComparator() + row.getPrimaryKey().toSQLString(db) + defn.endSQLStatement();
        //               db.printSQLIfRequested(sqlString);
        log.debug(sqlString);
        PreparedStatement prep = statement.getConnection().prepareStatement(sqlString);
        try {
            prep.setBlob(1, largeObject.getInputStream(), largeObject.getSize());
            prep.execute();
        } finally {
            prep.close();
        }
    }

    private void setUsingBase64String(DBDefinition defn, DBRow row, final String col,
            final DBLargeObject largeObject, DBDatabase db, DBStatement statement)
            throws SQLException, IOException {
        String sqlString = defn.beginUpdateLine() + defn.formatTableName(row) + defn.beginSetClause()
                + defn.formatColumnName(col) + defn.getEqualsComparator() + defn.getPreparedVariableSymbol()
                + defn.beginWhereClause() + defn.formatColumnName(row.getPrimaryKeyColumnName())
                + defn.getEqualsComparator() + row.getPrimaryKey().toSQLString(db) + defn.endSQLStatement();
        //               db.printSQLIfRequested(sqlString);
        log.debug(sqlString);
        PreparedStatement prep = statement.getConnection().prepareStatement(sqlString);
        try {
            InputStream inputStream = largeObject.getInputStream();

            InputStream input = new BufferedInputStream(inputStream);
            try {
                List<byte[]> byteArrays = new ArrayList<byte[]>();

                int totalBytesRead = 0;
                byte[] resultSetBytes;
                resultSetBytes = new byte[100000];
                int bytesRead = input.read(resultSetBytes);
                while (bytesRead > 0) {
                    totalBytesRead += bytesRead;
                    byteArrays.add(resultSetBytes);
                    resultSetBytes = new byte[100000];
                    bytesRead = input.read(resultSetBytes);
                }
                byte[] bytes = new byte[totalBytesRead];
                int bytesAdded = 0;
                for (byte[] someBytes : byteArrays) {
                    System.arraycopy(someBytes, 0, bytes, bytesAdded,
                            Math.min(someBytes.length, bytes.length - bytesAdded));
                    bytesAdded += someBytes.length;
                }
                String b64encoded = Base64.encodeBase64String(bytes);
                //System.out.println("BYTES TO WRITE: " + Arrays.toString(bytes));
                prep.setString(1, b64encoded);
                prep.execute();
            } finally {
                input.close();
            }
        } finally {
            prep.close();
        }
    }

    private void setUsingCharacterStream(DBDefinition defn, DBRow row, final String col,
            final DBLargeObject largeObject, DBDatabase db, DBStatement statement) throws SQLException {
        String sqlString = defn.beginUpdateLine() + defn.formatTableName(row) + defn.beginSetClause()
                + defn.formatColumnName(col) + defn.getEqualsComparator() + defn.getPreparedVariableSymbol()
                + defn.beginWhereClause() + defn.formatColumnName(row.getPrimaryKeyColumnName())
                + defn.getEqualsComparator() + row.getPrimaryKey().toSQLString(db) + defn.endSQLStatement();
        //               db.printSQLIfRequested(sqlString);
        log.info(sqlString);
        PreparedStatement prep = statement.getConnection().prepareStatement(sqlString);
        try {
            prep.setCharacterStream(1, new InputStreamReader(largeObject.getInputStream()));
            prep.execute();
        } finally {
            prep.close();
        }
    }

    @Override
    public List<String> getSQLStatements(DBDatabase db) {
        DBRow row = getRow();
        List<String> strs = new ArrayList<String>();
        strs.add(db.getDefinition().startMultilineComment() + " SAVE BINARY DATA"
                + db.getDefinition().endMultilineComment());
        return strs;
    }

    /**
     * Finds all the DBLargeObject fields that this action will need to update.
     *
     * @param row the row to be updated
     * @return a list of the interesting DBLargeObjects.
     */
    protected List<PropertyWrapper> getInterestingLargeObjects(DBRow row) {
        return getChangedLargeObjects(row);
    }

    @Override
    protected DBActionList getRevertDBActionList() {
        return new DBActionList();
    }

    @Override
    protected DBActionList getActions() {
        return new DBActionList(new DBUpdateLargeObjects(getRow()));
    }

    private List<PropertyWrapper> getChangedLargeObjects(DBRow row) {
        List<PropertyWrapper> changed = new ArrayList<PropertyWrapper>();
        if (row.hasLargeObjects()) {
            for (QueryableDatatype qdt : row.getLargeObjects()) {
                if (qdt instanceof DBLargeObject) {
                    DBLargeObject large = (DBLargeObject) qdt;
                    if (large.hasChanged()) {
                        changed.add(row.getPropertyWrapperOf(qdt));
                    }
                }
            }
        }
        return changed;
    }
}