org.jumpmind.symmetric.android.AndroidSqlTemplate.java Source code

Java tutorial

Introduction

Here is the source code for org.jumpmind.symmetric.android.AndroidSqlTemplate.java

Source

/**
 * Licensed to JumpMind Inc under one or more contributor
 * license agreements.  See the NOTICE file distributed
 * with this work for additional information regarding
 * copyright ownership.  JumpMind Inc licenses this file
 * to you under the GNU General Public License, version 3.0 (GPLv3)
 * (the "License"); you may not use this file except in compliance
 * with the License.
 *
 * You should have received a copy of the GNU General Public License,
 * version 3.0 (GPLv3) along with this library; if not, see
 * <http://www.gnu.org/licenses/>.
 *
 * 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 org.jumpmind.symmetric.android;

import java.sql.Timestamp;
import java.sql.Types;
import java.util.Date;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.NotImplementedException;
import org.jumpmind.db.model.TypeMap;
import org.jumpmind.db.sql.AbstractSqlTemplate;
import org.jumpmind.db.sql.ISqlReadCursor;
import org.jumpmind.db.sql.ISqlResultsListener;
import org.jumpmind.db.sql.ISqlRowMapper;
import org.jumpmind.db.sql.ISqlStatementSource;
import org.jumpmind.db.sql.ISqlTransaction;
import org.jumpmind.db.sql.ListSqlStatementSource;
import org.jumpmind.db.sql.Row;
import org.jumpmind.db.sql.UniqueKeyException;

import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class AndroidSqlTemplate extends AbstractSqlTemplate {

    protected SQLiteOpenHelper databaseHelper;
    protected Context androidContext;

    public AndroidSqlTemplate(SQLiteOpenHelper databaseHelper, Context androidContext) {
        this.databaseHelper = databaseHelper;
        this.androidContext = androidContext;
    }

    public SQLiteOpenHelper getDatabaseHelper() {
        return databaseHelper;
    }

    public byte[] queryForBlob(String sql, int jdbcTypeCode, String jdbcTypeName, Object... params) {
        return queryForBlob(sql, params);
    }

    public byte[] queryForBlob(String sql, Object... params) {
        return queryForObject(sql, byte[].class, params);
    }

    @Override
    public String queryForClob(String sql, Object... args) {
        return queryForClob(sql, Types.CLOB, TypeMap.CLOB, args);
    }

    public String queryForClob(String sql, int jdbcTypeCode, String jdbcTypeName, Object... params) {
        return queryForString(sql, params);
    }

    public <T> T queryForObject(String sql, Class<T> clazz, Object... params) {
        SQLiteDatabase database = databaseHelper.getWritableDatabase();
        try {
            return queryForObject(database, sql, clazz, params);
        } catch (Exception ex) {
            throw translate(ex);
        } finally {
            close(database);
        }
    }

    protected <T> T queryForObject(SQLiteDatabase database, String sql, Class<T> clazz, Object... params) {
        Cursor cursor = null;
        try {
            T result = null;
            cursor = database.rawQuery(sql, toStringArray(params));
            if (cursor.moveToFirst()) {
                result = get(cursor, clazz, 0);
            }
            return result;
        } catch (Exception ex) {
            throw translate(ex);
        } finally {
            close(cursor);
        }
    }

    public Map<String, Object> queryForMap(final String sql, final Object... args) {
        return queryForObject(sql, new ISqlRowMapper<Map<String, Object>>() {

            public Map<String, Object> mapRow(Row rs) {
                return rs;
            }
        }, args);
    }

    public <T> ISqlReadCursor<T> queryForCursor(String sql, ISqlRowMapper<T> mapper, Object[] params, int[] types) {
        return new AndroidSqlReadCursor<T>(sql, toStringArray(params), mapper, this);
    }

    public int update(boolean autoCommit, boolean failOnError, int commitRate, ISqlResultsListener resultsListener,
            String... sql) {
        return this.update(autoCommit, failOnError, true, true, commitRate, resultsListener,
                new ListSqlStatementSource(sql));
    }

    public int update(final boolean autoCommit, final boolean failOnError, boolean failOnDrops,
            boolean failOnSequenceCreate, final int commitRate, final ISqlResultsListener resultsListener,
            final ISqlStatementSource source) {
        int row = 0;
        SQLiteDatabase database = this.databaseHelper.getWritableDatabase();
        String currentStatement = null;
        try {
            if (!autoCommit) {
                database.beginTransaction();
            }

            for (String statement = source.readSqlStatement(); statement != null; statement = source
                    .readSqlStatement()) {
                currentStatement = statement;
                update(statement);
                row++;
                if (!autoCommit && row % commitRate == 0) {
                    database.setTransactionSuccessful();
                    database.endTransaction();
                    database.beginTransaction();
                }

                if (resultsListener != null) {
                    resultsListener.sqlApplied(statement, row, 0, row);
                }
            }

            if (!autoCommit) {
                database.setTransactionSuccessful();
            }
        } catch (RuntimeException ex) {
            if (resultsListener != null) {
                resultsListener.sqlErrored(currentStatement, translate(currentStatement, ex), row, false, false);
            }
            throw ex;
        } finally {
            if (!autoCommit) {
                database.endTransaction();
            }

            close(database);
        }

        return row;
    }

    public int update(boolean autoCommit, boolean failOnError, int commitRate, String... sql) {
        return update(autoCommit, failOnError, commitRate, (ISqlResultsListener) null, sql);
    }

    public int update(String sql, Object[] values, int[] types) {
        SQLiteDatabase database = this.databaseHelper.getWritableDatabase();
        try {
            return update(database, sql, values, types);
        } finally {
            close(database);
        }
    }

    protected int update(SQLiteDatabase database, String sql, Object[] values, int[] types) {
        try {
            if (values != null) {
                database.execSQL(sql, toStringArray(values));
            } else {
                database.execSQL(sql);
            }
            return queryForObject(database, "select changes()", Integer.class);
        } catch (Exception ex) {
            throw translate(ex);
        }
    }

    /**
     * Translate an array of {@link Object} to an array of {@link String} by
     * creating a new array of {@link String} and putting each of the objects
     * into the array by calling {@link Object#toString()}
     * 
     * @param orig
     *            the original array
     * @return a newly constructed string array
     */
    public static String[] toStringArray(Object[] orig) {
        String[] array = null;
        if (orig != null) {
            array = new String[orig.length];
            for (int i = 0; i < orig.length; i++) {
                if (orig[i] != null) {
                    if (orig[i] instanceof Date) {
                        array[i] = new Timestamp(((Date) orig[i]).getTime()).toString();
                    } else {
                        array[i] = orig[i].toString();
                    }
                }
            }
        }
        return array;
    }

    public void testConnection() {
        SQLiteDatabase database = this.databaseHelper.getWritableDatabase();
        close(database);
    }

    public boolean isUniqueKeyViolation(Throwable ex) {
        return ex instanceof SQLiteConstraintException || ex instanceof UniqueKeyException;
    }

    public boolean isForeignKeyViolation(Throwable ex) {
        return false;
    }

    @Override
    public ISqlTransaction startSqlTransaction(boolean autoCommit) {
        return new AndroidSqlTransaction(this, autoCommit);
    }

    public ISqlTransaction startSqlTransaction() {
        return startSqlTransaction(false);
    }

    public int getDatabaseMajorVersion() {
        SQLiteDatabase database = this.databaseHelper.getWritableDatabase();
        try {
            return database.getVersion();
        } catch (Exception ex) {
            throw translate(ex);
        } finally {
            close(database);
        }
    }

    public int getDatabaseMinorVersion() {
        return 0;
    }

    public String getDatabaseProductName() {
        return "sqlite";
    }

    public String getDatabaseProductVersion() {
        return Integer.toString(getDatabaseMajorVersion());
    }

    public String getDriverName() {
        return "android";
    }

    public String getDriverVersion() {
        try {
            return androidContext.getPackageManager().getPackageInfo(androidContext.getPackageName(),
                    0).versionName;
        } catch (NameNotFoundException e) {
            return "?";
        }
    }

    public Set<String> getSqlKeywords() {
        throw new NotImplementedException();
    }

    public boolean supportsGetGeneratedKeys() {
        return false;
    }

    public boolean isStoresUpperCaseIdentifiers() {
        return false;
    }

    public boolean isStoresLowerCaseIdentifiers() {
        return true;
    }

    public boolean isStoresMixedCaseQuotedIdentifiers() {
        return false;
    }

    public long insertWithGeneratedKey(String sql, String column, String sequenceName, Object[] params,
            int[] types) {
        SQLiteDatabase database = databaseHelper.getWritableDatabase();
        try {
            return insertWithGeneratedKey(database, sql, column, sequenceName, params, types);
        } finally {
            close(database);
        }
    }

    protected long insertWithGeneratedKey(SQLiteDatabase database, String sql, String column, String sequenceName,
            Object[] params, int[] types) {
        int updateCount = update(database, sql, params, types);
        if (updateCount > 0) {
            long rowId = queryForObject(database, "SELECT last_insert_rowid()", Integer.class);
            return rowId;
        } else {
            return -1;
        }
    }

    protected void close(SQLiteDatabase database) {
    }

    protected void close(Cursor cursor) {
        try {
            if (cursor != null) {
                cursor.close();
            }
        } catch (Exception ex) {
        }
    }

    @SuppressWarnings("unchecked")
    protected <T> T get(Cursor cursor, Class<T> clazz, int columnIndex) {
        Object result = null;
        if (clazz.equals(String.class)) {
            result = (String) cursor.getString(columnIndex);
        } else if (clazz.equals(Integer.class)) {
            result = (Integer) cursor.getInt(columnIndex);
        } else if (clazz.equals(Integer.class)) {
            result = (Double) cursor.getDouble(columnIndex);
        } else if (clazz.equals(Float.class)) {
            result = (Float) cursor.getFloat(columnIndex);
        } else if (clazz.equals(Long.class)) {
            result = (Long) cursor.getLong(columnIndex);
        } else if (clazz.equals(Date.class) || clazz.equals(Timestamp.class)) {
            String dateString = cursor.getString(columnIndex);
            if (dateString.contains("-")) {
                result = Timestamp.valueOf(dateString);
            } else {
                result = new Timestamp(Long.parseLong(dateString));
            }
        } else if (clazz.equals(Short.class)) {
            result = (Short) cursor.getShort(columnIndex);
        } else if (clazz.equals(byte[].class)) {
            result = (byte[]) cursor.getBlob(columnIndex);
        } else {
            throw new IllegalArgumentException("Unsupported class: " + clazz.getName());
        }
        return (T) result;
    }

}