org.mifos.framework.persistence.Upgrade.java Source code

Java tutorial

Introduction

Here is the source code for org.mifos.framework.persistence.Upgrade.java

Source

/*
 * Copyright (c) 2005-2011 Grameen Foundation USA
 * All rights reserved.
 *
 * 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.
 *
 * See also http://www.apache.org/licenses/LICENSE-2.0.html for an
 * explanation of the license and how it is applied.
 */

package org.mifos.framework.persistence;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.mifos.framework.exceptions.SystemException;
import org.springframework.context.ApplicationContext;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

@SuppressWarnings("PMD.AbstractNaming")
public abstract class Upgrade {

    private static final Logger logger = LoggerFactory.getLogger(Upgrade.class);
    public static final String WRONG_CONSTRUCTOR = "This db version is higher than 174 so it needs to use the constructor with lookupValueKey parameter.";
    protected ApplicationContext upgradeContext;

    protected Logger getLogger() {
        return logger;
    }

    @SuppressWarnings("PMD.AbstractNaming")
    // Rationale: I will name abstract methods whatever.
    abstract public void upgrade(Connection connection) throws IOException, SQLException;

    @SuppressWarnings("PMD.OnlyOneReturn")
    // Rationale: There's no need to add a result variable just to return at a
    // single place in a 10 line method.
    public static boolean validateLookupValueKey(String format, String key) {
        if (StringUtils.isBlank(key)) {
            return false;
        }

        if (!key.startsWith(format, 0)) {
            return false;
        }

        return true;
    }

    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = {
            "OBL_UNSATISFIED_OBLIGATION" }, justification = "The statement is closed.")
    protected void insertMessage(Connection connection, int lookupId, Short localeToInsert, String message)
            throws SQLException {
        PreparedStatement statement = connection.prepareStatement(
                "insert into lookup_value_locale(" + "locale_id,lookup_id,lookup_value) " + "VALUES(?,?,?)");
        statement.setInt(1, localeToInsert);
        statement.setInt(2, lookupId);
        statement.setString(3, message);
        statement.executeUpdate();
        statement.close();
    }

    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = { "OBL_UNSATISFIED_OBLIGATION",
            "SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE" }, justification = "The statement is closed and the query cannot be static.")
    protected static void updateMessage(Connection connection, int lookupId, int locale, String newMessage)
            throws SQLException {
        PreparedStatement statement = connection.prepareStatement(
                "update lookup_value_locale set lookup_value = ? " + "where locale_id = ? and lookup_id = ?");
        statement.setString(1, newMessage);
        statement.setInt(2, locale);
        statement.setInt(3, lookupId);
        statement.executeUpdate();
        statement.close();
    }

    /**
     * This method is used for version 174 and lower (it was used in Upgrade169)
     * and must not be used after 174 because after 174, a lookup key is
     * required for a lookup value to be displayed. Prior to version 174 an
     * empty (" ") key was passed in because the key was unused.
     *
     * @deprecated
     */
    @Deprecated
    protected int insertLookupValue(Connection connection, int lookupEntity) throws SQLException {
        return insertLookupValue(connection, lookupEntity, " ");
    }

    /**
     * Add a new Lookup Value. A Lookup Value is a string key that is resolved
     * to a message by looking up the key value in a properties file. The
     * message can be overridden by a LookupValueLocale in the database that is
     * associated with a given LookupValue.
     *
     * @param connection
     *            the database connection to use
     * @param lookupEntity
     *            the primary key of the lookup entity that this key is
     *            associated with
     * @param lookupKey
     *            the string key to lookup in a properties file to get the
     *            message to display
     * @return the newly generated lookup id (primary key) for the lookup value
     *         just inserted
     * @throws SQLException
     */
    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = { "OBL_UNSATISFIED_OBLIGATION",
            "SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE" }, justification = "The statement is closed and the query cannot be static.")
    protected int insertLookupValue(Connection connection, int lookupEntity, String lookupKey) throws SQLException {
        /*
         * LOOKUP_ID is not AUTO_INCREMENT until database version 121. Although
         * we perhaps could try to work some magic with the upgrades, it seems
         * better to just insert in the racy way until then. Upgrades run
         * single-threaded before the application allows logins, so I think this
         * is fine.
         */
        int largestLookupId = largestLookupId(connection);

        int newLookupId = largestLookupId + 1;
        PreparedStatement statement = connection.prepareStatement(
                "insert into lookup_value(" + "lookup_id,entity_id,lookup_name) " + "value(?,?,?)");
        statement.setInt(1, newLookupId);
        statement.setInt(2, lookupEntity);
        statement.setString(3, lookupKey);

        statement.executeUpdate();
        statement.close();
        return newLookupId;
    }

    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = {
            "OBL_UNSATISFIED_OBLIGATION" }, justification = "The statement and results are closed.")
    @SuppressWarnings("PMD.CloseResource")
    protected int largestLookupId(Connection connection) throws SQLException {
        Statement statement = connection.createStatement();
        ResultSet results = statement.executeQuery("select max(lookup_id) from lookup_value");
        if (!results.next()) {
            throw new SystemException(SystemException.DEFAULT_KEY,
                    "Did not find an existing lookup_id in lookup_value table");
        }
        int largestLookupId = results.getInt(1);
        results.close();
        statement.close();
        return largestLookupId;
    }

    @SuppressWarnings("PMD.CloseResource")
    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = {
            "OBL_UNSATISFIED_OBLIGATION" }, justification = "The statement is closed.")
    protected void deleteFromLookupValueLocale(Connection connection, int lookupId) throws SQLException {
        PreparedStatement statement = connection
                .prepareStatement("delete from lookup_value_locale where lookup_id = ?");
        statement.setInt(1, lookupId);
        statement.executeUpdate();
        statement.close();
    }

    @SuppressWarnings("PMD.CloseResource")
    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = {
            "OBL_UNSATISFIED_OBLIGATION" }, justification = "The statement is closed.")
    protected void deleteFromLookupValue(Connection connection, int lookupId) throws SQLException {
        PreparedStatement statement = connection.prepareStatement("delete from lookup_value where lookup_id = ?");
        statement.setInt(1, lookupId);
        statement.executeUpdate();
        statement.close();
    }

    /**
     * @deprecated use {@link #addLookupEntity(Connection, String, String)} instead
     */
    @Deprecated
    @SuppressWarnings("PMD.CloseResource")
    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = {
            "OBL_UNSATISFIED_OBLIGATION" }, justification = "The statement is closed.")
    protected void addLookupEntity(Connection connection, int entityId, String name, String description)
            throws SQLException {
        PreparedStatement statement = connection
                .prepareStatement("insert into lookup_entity(entity_id,entity_name,description) values(?,?,?)");
        statement.setInt(1, entityId);
        statement.setString(2, name);
        statement.setString(3, description);
        statement.executeUpdate();
        statement.close();
    }

    @SuppressWarnings("PMD.CloseResource")
    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = {
            "OBL_UNSATISFIED_OBLIGATION" }, justification = "The statement is closed.")
    protected void removeLookupEntity(Connection connection, int entityId) throws SQLException {
        PreparedStatement statement = connection.prepareStatement("delete from lookup_entity where entity_id = ?");
        statement.setInt(1, entityId);
        statement.executeUpdate();
        statement.close();
    }

    @SuppressWarnings("PMD.CloseResource")
    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = { "OBL_UNSATISFIED_OBLIGATION",
            "SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE",
            "SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING" }, justification = "The statement is closed and the query cannot be static.")
    protected void execute(Connection connection, String sql) throws SQLException {
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.executeUpdate();
        statement.close();
    }

    /**
     * By default a single head office is present in a clean database, so no
     * offices have been created if there is only one office row present. This
     * test is being used to determine if the database has no user data in it.
     */
    protected boolean noOfficesHaveBeenCreatedByEndUsers(Connection connection) throws SQLException {
        return countRows(connection, "OFFICE") == 1;
    }

    @SuppressWarnings("PMD.CloseResource")
    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = { "OBL_UNSATISFIED_OBLIGATION",
            "SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE" }, justification = "The statement is closed and the query cannot be static.")
    private int countRows(Connection connection, String tableName) throws SQLException {

        int numFields = 0;
        Statement statement = connection.createStatement();
        try {
            ResultSet results = statement.executeQuery("select count(*) from " + tableName);
            if (!results.next()) {
                throw new SystemException(SystemException.DEFAULT_KEY, "Query failed on table: " + tableName);
            }
            numFields = results.getInt(1);

        } finally {
            statement.close();
        }
        return numFields;
    }

    @SuppressWarnings("PMD.CloseResource")
    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = {
            "OBL_UNSATISFIED_OBLIGATION" }, justification = "The statement is closed.")
    protected int addLookupEntity(Connection connection, String name, String description) throws SQLException {
        int newId = -1;
        PreparedStatement statement = connection.prepareStatement(
                "insert into lookup_entity(entity_id,entity_name,description) values(null,?,?)",
                PreparedStatement.RETURN_GENERATED_KEYS);
        statement.setString(1, name);
        statement.setString(2, description);
        statement.executeUpdate();
        ResultSet keys = statement.getGeneratedKeys();
        keys.next();
        newId = Integer.parseInt(keys.getString(1));
        statement.close();
        return newId;
    }

    public void setUpgradeContext(ApplicationContext upgradeContext) {
        this.upgradeContext = upgradeContext;
    }

}