From a2d60f98b1edd83b82370d3322802c18c0dddf84 Mon Sep 17 00:00:00 2001 From: Ricky Barrette Date: Fri, 21 Sep 2012 11:39:16 -0400 Subject: [PATCH] Started working on implementing a database for storing forum content. This will enable off line viewing of the forum. Signed-off-by: Ricky Barrette --- OSJ Forum/res/values/strings.xml | 1 + .../RickBarrette/osj/forum/Constraints.java | 5 + .../osj/forum/database/DatabaseListener.java | 39 ++ .../osj/forum/database/ForumDatabase.java | 362 ++++++++++++++++++ 4 files changed, 407 insertions(+) create mode 100644 OSJ Forum/src/org/RickBarrette/osj/forum/database/DatabaseListener.java create mode 100644 OSJ Forum/src/org/RickBarrette/osj/forum/database/ForumDatabase.java diff --git a/OSJ Forum/res/values/strings.xml b/OSJ Forum/res/values/strings.xml index 713aaae..babfe31 100644 --- a/OSJ Forum/res/values/strings.xml +++ b/OSJ Forum/res/values/strings.xml @@ -15,4 +15,5 @@ Test1 https://oceanstatejeepsters.ipower.com/forum/mobiquo/mobiquo.php Legal + Deleteing \ No newline at end of file diff --git a/OSJ Forum/src/org/RickBarrette/osj/forum/Constraints.java b/OSJ Forum/src/org/RickBarrette/osj/forum/Constraints.java index b2a7efb..126cba1 100644 --- a/OSJ Forum/src/org/RickBarrette/osj/forum/Constraints.java +++ b/OSJ Forum/src/org/RickBarrette/osj/forum/Constraints.java @@ -60,4 +60,9 @@ public class Constraints { * Set this boolean to true to enable wtf logging */ public static final boolean WTF = true; + + /** + * Clears the database everytime it is initialized + */ + public static final boolean DROP_TABLES_EVERY_TIME = false; } \ No newline at end of file diff --git a/OSJ Forum/src/org/RickBarrette/osj/forum/database/DatabaseListener.java b/OSJ Forum/src/org/RickBarrette/osj/forum/database/DatabaseListener.java new file mode 100644 index 0000000..9a900aa --- /dev/null +++ b/OSJ Forum/src/org/RickBarrette/osj/forum/database/DatabaseListener.java @@ -0,0 +1,39 @@ +/** + * DatabaseListener.java + * @date Sep 21, 2012 + * @author ricky barrette + * + * Copyright 2012 Richard Barrette + * + * 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 org.RickBarrette.osj.forum.database; + +/** + * This interface will be used to listen to see when the database events are complete + * + * @author ricky barrette + */ +public interface DatabaseListener { + + public void onDatabaseCreate(); + + public void onDatabaseUpgrade(); + + public void onDatabaseUpgradeComplete(); + + public void onRestoreComplete(); + + public void onDeletionComplete(); + +} \ No newline at end of file diff --git a/OSJ Forum/src/org/RickBarrette/osj/forum/database/ForumDatabase.java b/OSJ Forum/src/org/RickBarrette/osj/forum/database/ForumDatabase.java new file mode 100644 index 0000000..1e58895 --- /dev/null +++ b/OSJ Forum/src/org/RickBarrette/osj/forum/database/ForumDatabase.java @@ -0,0 +1,362 @@ +/** + * ForumDatabase.java + * @date Sep 21, 2012 + * @author ricky barrette + * + * Copyright 2012 Richard Barrette + * + * 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 org.RickBarrette.osj.forum.database; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; + +import org.RickBarrette.osj.forum.Constraints; +import org.RickBarrette.osj.forum.Log; +import org.RickBarrette.osj.forum.R; + +import android.app.ProgressDialog; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.os.Environment; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +/** + * This class will be the main interface between osj forum and it's database + * @author ricky barrette + */ +public class ForumDatabase { + + /** + * A helper class to manage database creation and version management. + * + * @author ricky barrette + */ + private class OpenHelper extends SQLiteOpenHelper { + + /** + * Creates a new OpenHelper + * + * @param context + * @author ricky barrette + */ + public OpenHelper(final Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + /** + * Creates the initial database structure + * + * @param db + * @author ricky barrette + */ + private void createDatabase(final SQLiteDatabase db) { + db.execSQL("CREATE TABLE " + TABLE + "("+KEY+" TEXT PRIMARY KEY, " + KEY_VALUE + " TEXT)"); + } + + /** + * called when the database is created for the first time. this will create our database + * (non-Javadoc) + * + * @see android.database.sqlite.SQLiteOpenHelper#onCreate(android.database.sqlite.SQLiteDatabase) + * @author ricky barrette + */ + @Override + public void onCreate(final SQLiteDatabase db) { + if (Constraints.DROP_TABLES_EVERY_TIME) + db.execSQL("DROP TABLE IF EXISTS " + TABLE); + createDatabase(db); + if(mListener != null) + mListener.onDatabaseCreate(); + } + + /** + * called when the database needs to be updated (non-Javadoc) + * + * @see android.database.sqlite.SQLiteOpenHelper#onUpgrade(android.database.sqlite.SQLiteDatabase, + * int, int) + * @author ricky barrette + */ + @Override + public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { + Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion); + + if (mListener != null) + mListener.onDatabaseUpgrade(); + + isUpgrading = true; + + // upgrade thread + new Thread(new Runnable() { + @Override + public void run() { + Looper.prepare(); + switch (oldVersion) { + case 1: + //Update stuff here, do not use breaks + } + } + }).start(); + } + } + + private static final String TAG = "ForumDatabase"; + private final Context mContext; + private SQLiteDatabase mDb; + private static DatabaseListener mListener; + public boolean isUpgrading = false; + private final static Handler mHandler; + protected static final int DELETIONCOMPLETE = 0; + + protected static final int DATABASEUPGRADECOMPLETE = 1; + + static { + mHandler = new Handler() { + @Override + public void handleMessage(final Message msg) { + if (mListener != null) + switch (msg.what) { + case DELETIONCOMPLETE: + mListener.onDeletionComplete(); + break; + case DATABASEUPGRADECOMPLETE: + mListener.onDatabaseUpgradeComplete(); + break; + } + } + }; + } + + /** + * Version of this database + */ + private final int DATABASE_VERSION = 1; + + /** + * Name of the database file + */ + private final String DATABASE_NAME = "osj_forum.db"; + + /* + * Database tables + */ + private final String TABLE = "table"; + private final String FORUM_TABLE = "forum_"; + private final String TOPIC_TABLE = "topic_"; + private final String THREAD_TABLE = "thread_"; + + /* + * Database keys + */ + private static final String KEY = "key"; + private static final String KEY_VALUE = "value"; + private static final String KEY_FORUM_ID = "forum_id"; + private static final String KEY_TOPICM_ID = "topic_id"; + private static final String KEY_THREAD_ID = "thread_id"; + + + /** + * Parses a string boolean from the database + * + * @param bool + * @return true or false + * @author ricky barrette + */ + public static boolean parseBoolean(final String bool) { + try { + return bool == null ? false : Integer.parseInt(bool) == 1 ? true : false; + } catch (final NumberFormatException e) { + return false; + } + } + + /** + * Creates a new ForumDatabase + * + * @param context + * @author ricky barrette + */ + public ForumDatabase(final Context context) { + this(context, null); + } + + /** + * Creates a new ForumDatabase + * + * @param context + * @param listener + * @author ricky barrette + */ + public ForumDatabase(final Context context, final DatabaseListener listener) { + mListener = listener; + mContext = context; + mDb = new OpenHelper(mContext).getWritableDatabase(); + } + + /** + * Backs up the database + * + * @return true if successful + * @author ricky barrette + */ + public boolean backup() { + final File dbFile = new File(Environment.getDataDirectory() + "/data/" + mContext.getPackageName() + "/databases/" + DATABASE_NAME); + + final File exportDir = new File(Environment.getExternalStorageDirectory(), "/" + mContext.getString(R.string.app_name)); + if (!exportDir.exists()) + exportDir.mkdirs(); + + final File file = new File(exportDir, dbFile.getName()); + + try { + file.createNewFile(); + copyFile(dbFile, file); + return true; + } catch (final IOException e) { + e.printStackTrace(); + return false; + } + } + + /** + * Copies a file + * + * @param src file + * @param dst file + * @throws IOException + * @author ricky barrette + */ + private void copyFile(final File src, final File dst) throws IOException { + final FileInputStream in = new FileInputStream(src); + final FileOutputStream out = new FileOutputStream(dst); + final FileChannel inChannel = in.getChannel(); + final FileChannel outChannel = out.getChannel(); + try { + inChannel.transferTo(0, inChannel.size(), outChannel); + } finally { + if (inChannel != null) + inChannel.close(); + if (outChannel != null) + outChannel.close(); + if (in != null) + in.close(); + if (out != null) + out.close(); + + } + } + + /** + * deletes a note by its row id + * + * @param id + * @author ricky barrette + */ + public void deleteTable(final long id) { + + final ProgressDialog progress = ProgressDialog.show(ForumDatabase.this.mContext, "", ForumDatabase.this.mContext.getText(R.string.deleteing), true, true); + + // table deleting thread + new Thread(new Runnable() { + @Override + public void run() { + Looper.prepare(); + + //Delete stuff here + + mHandler.sendEmptyMessage(DELETIONCOMPLETE); + progress.dismiss(); + } + }).start(); + } + + /** + * Restores the database from the sdcard + * + * @return true if successful + * @author ricky barrette + */ + public void restore() { + final File dbFile = new File(Environment.getDataDirectory() + "/data/" + mContext.getPackageName() + "/databases/" + DATABASE_NAME); + + final File exportDir = new File(Environment.getExternalStorageDirectory(), "/" + mContext.getString(R.string.app_name)); + if (!exportDir.exists()) + exportDir.mkdirs(); + + final File file = new File(exportDir, dbFile.getName()); + + try { + file.createNewFile(); + copyFile(file, dbFile); + } catch (final IOException e) { + e.printStackTrace(); + } + /* + * close and reopen the database to upgrade it. + */ + mDb.close(); + mDb = new OpenHelper(mContext).getWritableDatabase(); + if (mDb.isOpen() && !isUpgrading) + if (mListener != null) + mListener.onRestoreComplete(); + } + + + /** + * upserts a database table + * @param table + * @param info + * @throws NullPointerException + * @author ricky barrette + */ + public void upsertTable(final String table, final ContentValues info) throws NullPointerException { + if (info == null) + throw new NullPointerException("info was null"); + /* + * here we wanr to update the information values in the info table + */ + for (final Entry item : info.valueSet()) { + final ContentValues values = new ContentValues(); + values.put(KEY, item.getKey()); + try { + values.put(KEY_VALUE, (String) item.getValue()); + } catch (final ClassCastException e) { + try { + values.put(KEY_VALUE, (Boolean) item.getValue() ? 1 : 0); + } catch (final ClassCastException e1) { + values.put(KEY_VALUE, (Integer) item.getValue()); + } + } + + /* + * here we are going to try to update a row, if that fails we will + * insert a row insead + */ + if (!(mDb.update(table, values, null, null) > 0)) + mDb.insert(table, null, values); + } + } +} \ No newline at end of file