extends TabActivity {
+
+ private volatile H helper;
+ private volatile boolean created = false;
+ private volatile boolean destroyed = false;
+
+ /**
+ * Get a helper for this action.
+ */
+ public H getHelper() {
+ if (helper == null) {
+ if (!created) {
+ throw new IllegalStateException("A call has not been made to onCreate() yet so the helper is null");
+ } else if (destroyed) {
+ throw new IllegalStateException(
+ "A call to onDestroy has already been made and the helper cannot be used after that point");
+ } else {
+ throw new IllegalStateException("Helper is null for some unknown reason");
+ }
+ } else {
+ return helper;
+ }
+ }
+
+ /**
+ * Get a connection source for this action.
+ */
+ public ConnectionSource getConnectionSource() {
+ return getHelper().getConnectionSource();
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ if (helper == null) {
+ helper = getHelperInternal(this);
+ created = true;
+ }
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ releaseHelper(helper);
+ destroyed = true;
+ }
+
+ /**
+ * This is called internally by the class to populate the helper object instance. This should not be called directly
+ * by client code unless you know what you are doing. Use {@link #getHelper()} to get a helper instance. If you are
+ * managing your own helper creation, override this method to supply this activity with a helper instance.
+ *
+ *
+ * NOTE: If you override this method, you most likely will need to override the
+ * {@link #releaseHelper(OrmLiteSqliteOpenHelper)} method as well.
+ *
+ *
+ * @see OpenHelperManager#getHelper(Context)
+ */
+ protected H getHelperInternal(Context context) {
+ @SuppressWarnings({ "unchecked" })
+ H newHelper = (H) OpenHelperManager.getHelper(context);
+ return newHelper;
+ }
+
+ /**
+ * Release the helper instance created in {@link #getHelperInternal(Context)}. You most likely will not need to call
+ * this directly since {@link #onDestroy()} does it for you.
+ *
+ *
+ * NOTE: If you override this method, you most likely will need to override the
+ * {@link #getHelperInternal(Context)} method as well.
+ *
+ */
+ protected void releaseHelper(H helper) {
+ OpenHelperManager.releaseHelper();
+ this.helper = null;
+ }
+}
diff --git a/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLiteConfigUtil.java b/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLiteConfigUtil.java
new file mode 100644
index 0000000..52c4596
--- /dev/null
+++ b/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLiteConfigUtil.java
@@ -0,0 +1,339 @@
+package com.j256.ormlite.android.apptools;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.reflect.Field;
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import com.j256.ormlite.dao.DaoManager;
+import com.j256.ormlite.db.DatabaseType;
+import com.j256.ormlite.db.SqliteAndroidDatabaseType;
+import com.j256.ormlite.field.DatabaseField;
+import com.j256.ormlite.field.DatabaseFieldConfig;
+import com.j256.ormlite.field.ForeignCollectionField;
+import com.j256.ormlite.table.DatabaseTable;
+import com.j256.ormlite.table.DatabaseTableConfig;
+import com.j256.ormlite.table.DatabaseTableConfigLoader;
+
+/**
+ * Database configuration file helper class that is used to write a configuration file into the raw resource
+ * sub-directory to speed up DAO creation.
+ *
+ *
+ * With help from the user list and especially Ian Dees, we discovered that calls to annotation methods in Android are
+ * _very_ expensive because Method.equals() was doing a huge toString(). This was causing folks to see 2-3 seconds
+ * startup time when configuring 10-15 DAOs because of 1000s of calls to @DatabaseField methods. See this Android bug report.
+ *
+ *
+ *
+ * I added this utility class which writes a configuration file into the raw resource "res/raw" directory inside of your
+ * project containing the table and field names and associated details. This file can then be loaded into the
+ * {@link DaoManager} with the help of the
+ * {@link OrmLiteSqliteOpenHelper#OrmLiteSqliteOpenHelper(android.content.Context, String, android.database.sqlite.SQLiteDatabase.CursorFactory, int, int)}
+ * constructor. This means that you can configure your classes _without_ any runtime calls to annotations. It seems
+ * significantly faster.
+ *
+ *
+ *
+ * WARNING: Although this is fast, the big problem is that you have to remember to regenerate the config file
+ * whenever you edit one of your database classes. There is no way that I know of to do this automagically.
+ *
+ *
+ * @author graywatson
+ */
+public class OrmLiteConfigUtil {
+
+ /**
+ * Resource directory name that we are looking for.
+ */
+ protected static final String RESOURCE_DIR_NAME = "res";
+ /**
+ * Raw directory name that we are looking for.
+ */
+ protected static final String RAW_DIR_NAME = "raw";
+
+ /**
+ * Maximum recursion level while we are looking for source files.
+ */
+ protected static int maxFindSourceLevel = 20;
+
+ private static final DatabaseType databaseType = new SqliteAndroidDatabaseType();
+
+ /**
+ * A call through to {@link #writeConfigFile(String)} taking the file name from the single command line argument.
+ */
+ public static void main(String[] args) throws Exception {
+ if (args.length != 1) {
+ throw new IllegalArgumentException("Main can take a single file-name argument.");
+ }
+ writeConfigFile(args[0]);
+ }
+
+ /**
+ * Finds the annotated classes in the current directory or below and writes a configuration file to the file-name in
+ * the raw folder.
+ */
+ public static void writeConfigFile(String fileName) throws SQLException, IOException {
+ List> classList = new ArrayList>();
+ findAnnotatedClasses(classList, new File("."), 0);
+ writeConfigFile(fileName, classList.toArray(new Class[classList.size()]));
+ }
+
+ /**
+ * Writes a configuration fileName in the raw directory with the configuration for classes.
+ */
+ public static void writeConfigFile(String fileName, Class>[] classes) throws SQLException, IOException {
+ File rawDir = findRawDir(new File("."));
+ if (rawDir == null) {
+ System.err.println("Could not find " + RAW_DIR_NAME + " directory which is typically in the "
+ + RESOURCE_DIR_NAME + " directory");
+ } else {
+ File configFile = new File(rawDir, fileName);
+ writeConfigFile(configFile, classes);
+ }
+ }
+
+ /**
+ * Finds the annotated classes in the current directory or below and writes a configuration file.
+ */
+ public static void writeConfigFile(File configFile) throws SQLException, IOException {
+ writeConfigFile(configFile, new File("."));
+ }
+
+ /**
+ * Finds the annotated classes in the specified search directory or below and writes a configuration file.
+ */
+ public static void writeConfigFile(File configFile, File searchDir) throws SQLException, IOException {
+ List> classList = new ArrayList>();
+ findAnnotatedClasses(classList, searchDir, 0);
+ writeConfigFile(configFile, classList.toArray(new Class[classList.size()]));
+ }
+
+ /**
+ * Write a configuration file with the configuration for classes.
+ */
+ public static void writeConfigFile(File configFile, Class>[] classes) throws SQLException, IOException {
+ System.out.println("Writing configurations to " + configFile.getAbsolutePath());
+ writeConfigFile(new FileOutputStream(configFile), classes);
+ }
+
+ /**
+ * Write a configuration file to an output stream with the configuration for classes.
+ */
+ public static void writeConfigFile(OutputStream outputStream, File searchDir) throws SQLException, IOException {
+ List> classList = new ArrayList>();
+ findAnnotatedClasses(classList, searchDir, 0);
+ writeConfigFile(outputStream, classList.toArray(new Class[classList.size()]));
+ }
+
+ /**
+ * Write a configuration file to an output stream with the configuration for classes.
+ */
+ public static void writeConfigFile(OutputStream outputStream, Class>[] classes) throws SQLException, IOException {
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream), 4096);
+ try {
+ writeHeader(writer);
+ for (Class> clazz : classes) {
+ writeConfigForTable(writer, clazz);
+ }
+ // NOTE: done is here because this is public
+ System.out.println("Done.");
+ } finally {
+ writer.close();
+ }
+ }
+
+ /**
+ * Look for the resource-directory in the current directory or the directories above. Then look for the
+ * raw-directory underneath the resource-directory.
+ */
+ protected static File findRawDir(File dir) {
+ for (int i = 0; dir != null && i < 20; i++) {
+ File rawDir = findResRawDir(dir);
+ if (rawDir != null) {
+ return rawDir;
+ }
+ dir = dir.getParentFile();
+ }
+ return null;
+ }
+
+ private static void writeHeader(BufferedWriter writer) throws IOException {
+ writer.append('#');
+ writer.newLine();
+ writer.append("# generated on ").append(new SimpleDateFormat("yyyy/MM/dd hh:mm:ss").format(new Date()));
+ writer.newLine();
+ writer.append('#');
+ writer.newLine();
+ }
+
+ private static void findAnnotatedClasses(List> classList, File dir, int level) throws SQLException,
+ IOException {
+ for (File file : dir.listFiles()) {
+ if (file.isDirectory()) {
+ // recurse if we aren't deep enough
+ if (level < maxFindSourceLevel) {
+ findAnnotatedClasses(classList, file, level + 1);
+ }
+ continue;
+ }
+ // skip non .java files
+ if (!file.getName().endsWith(".java")) {
+ continue;
+ }
+ String packageName = getPackageOfClass(file);
+ if (packageName == null) {
+ System.err.println("Could not find package name for: " + file);
+ continue;
+ }
+ // get the filename and cut off the .java
+ String name = file.getName();
+ name = name.substring(0, name.length() - ".java".length());
+ String className = packageName + "." + name;
+ Class> clazz;
+ try {
+ clazz = Class.forName(className);
+ } catch (Throwable t) {
+ // amazingly, this sometimes throws an Error
+ System.err.println("Could not load class file for: " + file);
+ System.err.println(" " + t);
+ continue;
+ }
+ if (classHasAnnotations(clazz)) {
+ classList.add(clazz);
+ }
+ // handle inner classes
+ try {
+ for (Class> innerClazz : clazz.getDeclaredClasses()) {
+ if (classHasAnnotations(innerClazz)) {
+ classList.add(innerClazz);
+ }
+ }
+ } catch (Throwable t) {
+ // amazingly, this sometimes throws an Error
+ System.err.println("Could not load inner classes for: " + clazz);
+ System.err.println(" " + t);
+ continue;
+ }
+ }
+ }
+
+ private static void writeConfigForTable(BufferedWriter writer, Class> clazz) throws SQLException, IOException {
+ String tableName = DatabaseTableConfig.extractTableName(clazz);
+ List fieldConfigs = new ArrayList();
+ // walk up the classes finding the fields
+ try {
+ for (Class> working = clazz; working != null; working = working.getSuperclass()) {
+ for (Field field : working.getDeclaredFields()) {
+ DatabaseFieldConfig fieldConfig = DatabaseFieldConfig.fromField(databaseType, tableName, field);
+ if (fieldConfig != null) {
+ fieldConfigs.add(fieldConfig);
+ }
+ }
+ }
+ } catch (Error e) {
+ System.err.println("Skipping " + clazz + " because we got an error finding its definition: "
+ + e.getMessage());
+ return;
+ }
+ if (fieldConfigs.isEmpty()) {
+ System.out.println("Skipping " + clazz + " because no annotated fields found");
+ return;
+ }
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ DatabaseTableConfig> tableConfig = new DatabaseTableConfig(clazz, tableName, fieldConfigs);
+ DatabaseTableConfigLoader.write(writer, tableConfig);
+ writer.append("#################################");
+ writer.newLine();
+ System.out.println("Wrote config for " + clazz);
+ }
+
+ private static boolean classHasAnnotations(Class> clazz) {
+ while (clazz != null) {
+ if (clazz.getAnnotation(DatabaseTable.class) != null) {
+ return true;
+ }
+ Field[] fields;
+ try {
+ fields = clazz.getDeclaredFields();
+ } catch (Throwable t) {
+ // amazingly, this sometimes throws an Error
+ System.err.println("Could not load get delcared fields from: " + clazz);
+ System.err.println(" " + t);
+ return false;
+ }
+ for (Field field : fields) {
+ if (field.getAnnotation(DatabaseField.class) != null
+ || field.getAnnotation(ForeignCollectionField.class) != null) {
+ return true;
+ }
+ }
+ try {
+ clazz = clazz.getSuperclass();
+ } catch (Throwable t) {
+ // amazingly, this sometimes throws an Error
+ System.err.println("Could not get super class for: " + clazz);
+ System.err.println(" " + t);
+ return false;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the package name of a file that has one of the annotations we are looking for.
+ *
+ * @return Package prefix string or null or no annotations.
+ */
+ private static String getPackageOfClass(File file) throws IOException {
+ BufferedReader reader = new BufferedReader(new FileReader(file));
+ try {
+ while (true) {
+ String line = reader.readLine();
+ if (line == null) {
+ return null;
+ }
+ if (line.contains("package")) {
+ String[] parts = line.split("[ \t;]");
+ if (parts.length > 1 && parts[0].equals("package")) {
+ return parts[1];
+ }
+ }
+ }
+ } finally {
+ reader.close();
+ }
+ }
+
+ /**
+ * Look for the resource directory with raw beneath it.
+ */
+ private static File findResRawDir(File dir) {
+ for (File file : dir.listFiles()) {
+ if (file.getName().equals(RESOURCE_DIR_NAME) && file.isDirectory()) {
+ File[] rawFiles = file.listFiles(new FileFilter() {
+ public boolean accept(File file) {
+ return file.getName().equals(RAW_DIR_NAME) && file.isDirectory();
+ }
+ });
+ if (rawFiles.length == 1) {
+ return rawFiles[0];
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLiteCursorAdapter.java b/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLiteCursorAdapter.java
new file mode 100644
index 0000000..3e9954d
--- /dev/null
+++ b/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLiteCursorAdapter.java
@@ -0,0 +1,93 @@
+package com.j256.ormlite.android.apptools;
+
+import java.sql.SQLException;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.view.View;
+import android.widget.CursorAdapter;
+
+import com.j256.ormlite.android.AndroidDatabaseResults;
+import com.j256.ormlite.stmt.PreparedQuery;
+
+/**
+ * Cursor adapter base class.
+ *
+ * @author emmby
+ */
+public abstract class OrmLiteCursorAdapter extends CursorAdapter {
+
+ protected PreparedQuery preparedQuery;
+
+ public OrmLiteCursorAdapter(Context context) {
+ super(context, null, false);
+ }
+
+ /**
+ * Bind the view to a particular item.
+ */
+ public abstract void bindView(ViewType itemView, Context context, T item);
+
+ /**
+ * Final to prevent subclasses from accidentally overriding. Intentional overriding can be accomplished by
+ * overriding {@link #doBindView(View, Context, Cursor)}.
+ *
+ * @see CursorAdapter#bindView(View, Context, Cursor)
+ */
+ @Override
+ public final void bindView(View itemView, Context context, Cursor cursor) {
+ doBindView(itemView, context, cursor);
+ }
+
+ /**
+ * This is here to make sure that the user really wants to override it.
+ */
+ protected void doBindView(View itemView, Context context, Cursor cursor) {
+ try {
+ @SuppressWarnings("unchecked")
+ ViewType itemViewType = (ViewType) itemView;
+ bindView(itemViewType, context, cursorToObject(cursor));
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Returns a T object at the current position.
+ */
+ public T getTypedItem(int position) {
+ try {
+ return cursorToObject((Cursor) super.getItem(position));
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Map a single row to our cursor object.
+ */
+ protected T cursorToObject(Cursor cursor) throws SQLException {
+ return preparedQuery.mapRow(new AndroidDatabaseResults(cursor, null));
+ }
+
+ /**
+ * Show not be used. Instead use {@link #changeCursor(Cursor, PreparedQuery)}
+ */
+ @Override
+ public final void changeCursor(Cursor cursor) {
+ throw new UnsupportedOperationException(
+ "Please use OrmLiteCursorAdapter.changeCursor(Cursor,PreparedQuery) instead");
+ }
+
+ /**
+ * Change the cursor associated with the prepared query.
+ */
+ public void changeCursor(Cursor cursor, PreparedQuery preparedQuery) {
+ setPreparedQuery(preparedQuery);
+ super.changeCursor(cursor);
+ }
+
+ public void setPreparedQuery(PreparedQuery preparedQuery) {
+ this.preparedQuery = preparedQuery;
+ }
+}
diff --git a/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLiteCursorLoader.java b/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLiteCursorLoader.java
new file mode 100644
index 0000000..03ac9cf
--- /dev/null
+++ b/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLiteCursorLoader.java
@@ -0,0 +1,131 @@
+package com.j256.ormlite.android.apptools;
+
+import static com.j256.ormlite.stmt.StatementBuilder.StatementType.SELECT;
+
+import java.sql.SQLException;
+
+import android.content.AsyncTaskLoader;
+import android.content.Context;
+import android.database.Cursor;
+
+import com.j256.ormlite.android.AndroidCompiledStatement;
+import com.j256.ormlite.dao.Dao;
+import com.j256.ormlite.dao.Dao.DaoObserver;
+import com.j256.ormlite.stmt.PreparedQuery;
+import com.j256.ormlite.support.DatabaseConnection;
+
+/**
+ * Cursor loader supported by later Android APIs that allows asynchronous content loading.
+ *
+ *
+ * NOTE: This should be the same as {@link com.j256.ormlite.android.apptools.support.OrmLiteCursorLoader}
+ * but this should import the normal version of the {@link AsyncTaskLoader}, not the support version.
+ *
+ *
+ * @author emmby
+ */
+public class OrmLiteCursorLoader extends AsyncTaskLoader implements DaoObserver {
+
+ protected Dao dao;
+ protected PreparedQuery query;
+ protected Cursor cursor;
+
+ public OrmLiteCursorLoader(Context context, Dao dao, PreparedQuery query) {
+ super(context);
+ this.dao = dao;
+ this.query = query;
+ }
+
+ @Override
+ public Cursor loadInBackground() {
+ Cursor cursor;
+ try {
+ DatabaseConnection connection = dao.getConnectionSource().getReadOnlyConnection();
+ AndroidCompiledStatement statement = (AndroidCompiledStatement) query.compile(connection, SELECT);
+ cursor = statement.getCursor();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+
+ // fill the cursor with results
+ cursor.getCount();
+ return cursor;
+ }
+
+ @Override
+ public void deliverResult(Cursor newCursor) {
+ if (isReset()) {
+ // an async query came in while the loader is stopped
+ if (newCursor != null) {
+ newCursor.close();
+ }
+ return;
+ }
+
+ Cursor oldCursor = cursor;
+ cursor = newCursor;
+
+ if (isStarted()) {
+ super.deliverResult(newCursor);
+ }
+
+ // close the old cursor if necessary
+ if (oldCursor != null && oldCursor != newCursor && !oldCursor.isClosed()) {
+ oldCursor.close();
+ }
+ }
+
+ @Override
+ protected void onStartLoading() {
+ // start watching for dataset changes
+ dao.registerObserver(this);
+
+ if (cursor == null) {
+ forceLoad();
+ } else {
+ deliverResult(cursor);
+ if (takeContentChanged()) {
+ forceLoad();
+ }
+ }
+ }
+
+ @Override
+ protected void onStopLoading() {
+ cancelLoad();
+ }
+
+ @Override
+ public void onCanceled(Cursor cursor) {
+ if (cursor != null && !cursor.isClosed()) {
+ cursor.close();
+ }
+ }
+
+ @Override
+ protected void onReset() {
+ super.onReset();
+ onStopLoading();
+ if (cursor != null) {
+ if (!cursor.isClosed()) {
+ cursor.close();
+ }
+ cursor = null;
+ }
+
+ // stop watching for changes
+ dao.unregisterObserver(this);
+ }
+
+ public void onChange() {
+ onContentChanged();
+ }
+
+ public PreparedQuery getQuery() {
+ return query;
+ }
+
+ public void setQuery(PreparedQuery mQuery) {
+ this.query = mQuery;
+ }
+}
diff --git a/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLitePreparedQueryLoader.java b/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLitePreparedQueryLoader.java
new file mode 100644
index 0000000..4771537
--- /dev/null
+++ b/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLitePreparedQueryLoader.java
@@ -0,0 +1,55 @@
+package com.j256.ormlite.android.apptools;
+
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+import android.content.Context;
+import android.content.Loader;
+
+import com.j256.ormlite.dao.Dao;
+import com.j256.ormlite.stmt.PreparedQuery;
+
+/**
+ * A {@link Loader} implementation that queries specified {@link Dao} using a {@link PreparedQuery}.
+ *
+ * @author Egorand
+ */
+public class OrmLitePreparedQueryLoader extends BaseOrmLiteLoader {
+
+ private PreparedQuery preparedQuery;
+
+ public OrmLitePreparedQueryLoader(Context context) {
+ super(context);
+ }
+
+ public OrmLitePreparedQueryLoader(Context context, Dao dao, PreparedQuery preparedQuery) {
+ super(context, dao);
+ this.preparedQuery = preparedQuery;
+ }
+
+ @Override
+ public List loadInBackground() {
+ if (dao == null) {
+ throw new IllegalStateException("Dao is not initialized.");
+ }
+ if (preparedQuery == null) {
+ throw new IllegalStateException("PreparedQuery is not initialized.");
+ }
+ try {
+ return dao.query(preparedQuery);
+ } catch (SQLException e) {
+ // XXX: is this really the right thing to do? Maybe throw RuntimeException?
+ e.printStackTrace();
+ return Collections.emptyList();
+ }
+ }
+
+ public void setPreparedQuery(PreparedQuery preparedQuery) {
+ this.preparedQuery = preparedQuery;
+ }
+
+ public PreparedQuery getPreparedQuery() {
+ return preparedQuery;
+ }
+}
diff --git a/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLiteQueryForAllLoader.java b/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLiteQueryForAllLoader.java
new file mode 100644
index 0000000..6add86c
--- /dev/null
+++ b/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLiteQueryForAllLoader.java
@@ -0,0 +1,40 @@
+package com.j256.ormlite.android.apptools;
+
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+import android.content.Context;
+
+import com.j256.ormlite.dao.Dao;
+
+/**
+ * A Loader implementation that queries specified {@link com.j256.ormlite.dao.Dao} for all data, using the
+ * Dao.queryForAll() call.
+ *
+ * @author EgorAnd
+ */
+public class OrmLiteQueryForAllLoader extends BaseOrmLiteLoader {
+
+ public OrmLiteQueryForAllLoader(Context context) {
+ super(context);
+ }
+
+ public OrmLiteQueryForAllLoader(Context context, Dao dao) {
+ super(context, dao);
+ }
+
+ @Override
+ public List loadInBackground() {
+ if (dao == null) {
+ throw new IllegalStateException("Dao is not initialized.");
+ }
+ try {
+ return dao.queryForAll();
+ } catch (SQLException e) {
+ // XXX: is this really the right thing to do? Maybe throw RuntimeException?
+ e.printStackTrace();
+ return Collections.emptyList();
+ }
+ }
+}
diff --git a/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLiteSqliteOpenHelper.java b/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLiteSqliteOpenHelper.java
new file mode 100644
index 0000000..62a3f45
--- /dev/null
+++ b/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/OrmLiteSqliteOpenHelper.java
@@ -0,0 +1,326 @@
+package com.j256.ormlite.android.apptools;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.sql.SQLException;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDatabase.CursorFactory;
+import android.database.sqlite.SQLiteOpenHelper;
+
+import com.j256.ormlite.android.AndroidConnectionSource;
+import com.j256.ormlite.android.AndroidDatabaseConnection;
+import com.j256.ormlite.dao.Dao;
+import com.j256.ormlite.dao.DaoManager;
+import com.j256.ormlite.dao.RuntimeExceptionDao;
+import com.j256.ormlite.logger.Logger;
+import com.j256.ormlite.logger.LoggerFactory;
+import com.j256.ormlite.misc.IOUtils;
+import com.j256.ormlite.support.ConnectionSource;
+import com.j256.ormlite.support.DatabaseConnection;
+import com.j256.ormlite.table.DatabaseTableConfigLoader;
+
+/**
+ * SQLite database open helper which can be extended by your application to help manage when the application needs to
+ * create or upgrade its database.
+ *
+ * @author kevingalligan, graywatson
+ */
+public abstract class OrmLiteSqliteOpenHelper extends SQLiteOpenHelper {
+
+ protected static Logger logger = LoggerFactory.getLogger(OrmLiteSqliteOpenHelper.class);
+ protected AndroidConnectionSource connectionSource = new AndroidConnectionSource(this);
+
+ protected boolean cancelQueriesEnabled;
+ private volatile boolean isOpen = true;
+
+ /**
+ * @param context
+ * Associated content from the application. This is needed to locate the database.
+ * @param databaseName
+ * Name of the database we are opening.
+ * @param factory
+ * Cursor factory or null if none.
+ * @param databaseVersion
+ * Version of the database we are opening. This causes {@link #onUpgrade(SQLiteDatabase, int, int)} to be
+ * called if the stored database is a different version.
+ */
+ public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion) {
+ super(context, databaseName, factory, databaseVersion);
+ logger.trace("{}: constructed connectionSource {}", this, connectionSource);
+ }
+
+ /**
+ * Same as the other constructor with the addition of a file-id of the table config-file. See
+ * {@link OrmLiteConfigUtil} for details.
+ *
+ * @param context
+ * Associated content from the application. This is needed to locate the database.
+ * @param databaseName
+ * Name of the database we are opening.
+ * @param factory
+ * Cursor factory or null if none.
+ * @param databaseVersion
+ * Version of the database we are opening. This causes {@link #onUpgrade(SQLiteDatabase, int, int)} to be
+ * called if the stored database is a different version.
+ * @param configFileId
+ * file-id which probably should be a R.raw.ormlite_config.txt or some static value.
+ */
+ public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion,
+ int configFileId) {
+ this(context, databaseName, factory, databaseVersion, openFileId(context, configFileId));
+ }
+
+ /**
+ * Same as the other constructor with the addition of a config-file. See {@link OrmLiteConfigUtil} for details.
+ *
+ * @param context
+ * Associated content from the application. This is needed to locate the database.
+ * @param databaseName
+ * Name of the database we are opening.
+ * @param factory
+ * Cursor factory or null if none.
+ * @param databaseVersion
+ * Version of the database we are opening. This causes {@link #onUpgrade(SQLiteDatabase, int, int)} to be
+ * called if the stored database is a different version.
+ * @param configFile
+ * Configuration file to be loaded.
+ */
+ public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion,
+ File configFile) {
+ this(context, databaseName, factory, databaseVersion, openFile(configFile));
+ }
+
+ /**
+ * Same as the other constructor with the addition of a input stream to the table config-file. See
+ * {@link OrmLiteConfigUtil} for details.
+ *
+ * @param context
+ * Associated content from the application. This is needed to locate the database.
+ * @param databaseName
+ * Name of the database we are opening.
+ * @param factory
+ * Cursor factory or null if none.
+ * @param databaseVersion
+ * Version of the database we are opening. This causes {@link #onUpgrade(SQLiteDatabase, int, int)} to be
+ * called if the stored database is a different version.
+ * @param stream
+ * Stream opened to the configuration file to be loaded. It will be closed when this method returns.
+ */
+ public OrmLiteSqliteOpenHelper(Context context, String databaseName, CursorFactory factory, int databaseVersion,
+ InputStream stream) {
+ super(context, databaseName, factory, databaseVersion);
+ if (stream == null) {
+ return;
+ }
+
+ // if a config file-id was specified then load it into the DaoManager
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new InputStreamReader(stream), 4096);
+ stream = null;
+ DaoManager.addCachedDatabaseConfigs(DatabaseTableConfigLoader.loadDatabaseConfigFromReader(reader));
+ } catch (SQLException e) {
+ throw new IllegalStateException("Could not load object config file", e);
+ } finally {
+ IOUtils.closeQuietly(reader);
+ IOUtils.closeQuietly(stream);
+ }
+ }
+
+ /**
+ * What to do when your database needs to be created. Usually this entails creating the tables and loading any
+ * initial data.
+ *
+ *
+ * NOTE: You should use the connectionSource argument that is passed into this method call or the one
+ * returned by getConnectionSource(). If you use your own, a recursive call or other unexpected results may result.
+ *
+ *
+ * @param database
+ * Database being created.
+ * @param connectionSource
+ * To use get connections to the database to be created.
+ */
+ public abstract void onCreate(SQLiteDatabase database, ConnectionSource connectionSource);
+
+ /**
+ * What to do when your database needs to be updated. This could mean careful migration of old data to new data.
+ * Maybe adding or deleting database columns, etc..
+ *
+ *
+ * NOTE: You should use the connectionSource argument that is passed into this method call or the one
+ * returned by getConnectionSource(). If you use your own, a recursive call or other unexpected results may result.
+ *
+ *
+ * @param database
+ * Database being upgraded.
+ * @param connectionSource
+ * To use get connections to the database to be updated.
+ * @param oldVersion
+ * The version of the current database so we can know what to do to the database.
+ * @param newVersion
+ * The version that we are upgrading the database to.
+ */
+ public abstract void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion,
+ int newVersion);
+
+ /**
+ * Get the connection source associated with the helper.
+ */
+ public ConnectionSource getConnectionSource() {
+ if (!isOpen) {
+ // we don't throw this exception, but log it for debugging purposes
+ logger.warn(new IllegalStateException(), "Getting connectionSource was called after closed");
+ }
+ return connectionSource;
+ }
+
+ /**
+ * Satisfies the {@link SQLiteOpenHelper#onCreate(SQLiteDatabase)} interface method.
+ */
+ @Override
+ public final void onCreate(SQLiteDatabase db) {
+ ConnectionSource cs = getConnectionSource();
+ /*
+ * The method is called by Android database helper's get-database calls when Android detects that we need to
+ * create or update the database. So we have to use the database argument and save a connection to it on the
+ * AndroidConnectionSource, otherwise it will go recursive if the subclass calls getConnectionSource().
+ */
+ DatabaseConnection conn = cs.getSpecialConnection();
+ boolean clearSpecial = false;
+ if (conn == null) {
+ conn = new AndroidDatabaseConnection(db, true, cancelQueriesEnabled);
+ try {
+ cs.saveSpecialConnection(conn);
+ clearSpecial = true;
+ } catch (SQLException e) {
+ throw new IllegalStateException("Could not save special connection", e);
+ }
+ }
+ try {
+ onCreate(db, cs);
+ } finally {
+ if (clearSpecial) {
+ cs.clearSpecialConnection(conn);
+ }
+ }
+ }
+
+ /**
+ * Satisfies the {@link SQLiteOpenHelper#onUpgrade(SQLiteDatabase, int, int)} interface method.
+ */
+ @Override
+ public final void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ ConnectionSource cs = getConnectionSource();
+ /*
+ * The method is called by Android database helper's get-database calls when Android detects that we need to
+ * create or update the database. So we have to use the database argument and save a connection to it on the
+ * AndroidConnectionSource, otherwise it will go recursive if the subclass calls getConnectionSource().
+ */
+ DatabaseConnection conn = cs.getSpecialConnection();
+ boolean clearSpecial = false;
+ if (conn == null) {
+ conn = new AndroidDatabaseConnection(db, true, cancelQueriesEnabled);
+ try {
+ cs.saveSpecialConnection(conn);
+ clearSpecial = true;
+ } catch (SQLException e) {
+ throw new IllegalStateException("Could not save special connection", e);
+ }
+ }
+ try {
+ onUpgrade(db, cs, oldVersion, newVersion);
+ } finally {
+ if (clearSpecial) {
+ cs.clearSpecialConnection(conn);
+ }
+ }
+ }
+
+ /**
+ * Close any open connections.
+ */
+ @Override
+ public void close() {
+ super.close();
+ connectionSource.close();
+ /*
+ * We used to set connectionSource to null here but now we just set the closed flag and then log heavily if
+ * someone uses getConectionSource() after this point.
+ */
+ isOpen = false;
+ }
+
+ /**
+ * Return true if the helper is still open. Once {@link #close()} is called then this will return false.
+ */
+ public boolean isOpen() {
+ return isOpen;
+ }
+
+ /**
+ * Get a DAO for our class. This uses the {@link DaoManager} to cache the DAO for future gets.
+ *
+ *
+ * NOTE: This routing does not return Dao<T, ID> because of casting issues if we are assigning it to a custom DAO.
+ * Grumble.
+ *
+ */
+ public , T> D getDao(Class clazz) throws SQLException {
+ // special reflection fu is now handled internally by create dao calling the database type
+ Dao dao = DaoManager.createDao(getConnectionSource(), clazz);
+ @SuppressWarnings("unchecked")
+ D castDao = (D) dao;
+ return castDao;
+ }
+
+ /**
+ * Get a RuntimeExceptionDao for our class. This uses the {@link DaoManager} to cache the DAO for future gets.
+ *
+ *
+ * NOTE: This routing does not return RuntimeExceptionDao<T, ID> because of casting issues if we are assigning it to
+ * a custom DAO. Grumble.
+ *
+ */
+ public , T> D getRuntimeExceptionDao(Class clazz) {
+ try {
+ Dao dao = getDao(clazz);
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ D castDao = (D) new RuntimeExceptionDao(dao);
+ return castDao;
+ } catch (SQLException e) {
+ throw new RuntimeException("Could not create RuntimeExcepitionDao for class " + clazz, e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "@" + Integer.toHexString(super.hashCode());
+ }
+
+ private static InputStream openFileId(Context context, int fileId) {
+ InputStream stream = context.getResources().openRawResource(fileId);
+ if (stream == null) {
+ throw new IllegalStateException("Could not find object config file with id " + fileId);
+ }
+ return stream;
+ }
+
+ private static InputStream openFile(File configFile) {
+ try {
+ if (configFile == null) {
+ return null;
+ } else {
+ return new FileInputStream(configFile);
+ }
+ } catch (FileNotFoundException e) {
+ throw new IllegalArgumentException("Could not open config file " + configFile, e);
+ }
+ }
+}
diff --git a/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/support/OrmLiteCursorLoader.java b/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/support/OrmLiteCursorLoader.java
new file mode 100644
index 0000000..9bdf300
--- /dev/null
+++ b/MemeProject/app/src/main/java/com/j256/ormlite/android/apptools/support/OrmLiteCursorLoader.java
@@ -0,0 +1,131 @@
+package com.j256.ormlite.android.apptools.support;
+
+import static com.j256.ormlite.stmt.StatementBuilder.StatementType.SELECT;
+
+import java.sql.SQLException;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.support.v4.content.AsyncTaskLoader;
+
+import com.j256.ormlite.android.AndroidCompiledStatement;
+import com.j256.ormlite.dao.Dao;
+import com.j256.ormlite.dao.Dao.DaoObserver;
+import com.j256.ormlite.stmt.PreparedQuery;
+import com.j256.ormlite.support.DatabaseConnection;
+
+/**
+ * Cursor loader supported by later Android APIs that allows asynchronous content loading.
+ *
+ *
+ * NOTE: This should be the same as {@link com.j256.ormlite.android.apptools.OrmLiteCursorLoader} but this
+ * should import the support library version of the {@link AsyncTaskLoader}.
+ *
+ *
+ * @author emmby
+ */
+public class OrmLiteCursorLoader extends AsyncTaskLoader implements DaoObserver {
+
+ protected Dao dao;
+ protected PreparedQuery query;
+ protected Cursor cursor;
+
+ public OrmLiteCursorLoader(Context context, Dao dao, PreparedQuery query) {
+ super(context);
+ this.dao = dao;
+ this.query = query;
+ }
+
+ @Override
+ public Cursor loadInBackground() {
+ Cursor cursor;
+ try {
+ DatabaseConnection connection = dao.getConnectionSource().getReadOnlyConnection();
+ AndroidCompiledStatement statement = (AndroidCompiledStatement) query.compile(connection, SELECT);
+ cursor = statement.getCursor();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+
+ // fill the cursor with results
+ cursor.getCount();
+ return cursor;
+ }
+
+ @Override
+ public void deliverResult(Cursor newCursor) {
+ if (isReset()) {
+ // an async query came in while the loader is stopped
+ if (newCursor != null) {
+ newCursor.close();
+ }
+ return;
+ }
+
+ Cursor oldCursor = cursor;
+ cursor = newCursor;
+
+ if (isStarted()) {
+ super.deliverResult(newCursor);
+ }
+
+ // close the old cursor if necessary
+ if (oldCursor != null && oldCursor != newCursor && !oldCursor.isClosed()) {
+ oldCursor.close();
+ }
+ }
+
+ @Override
+ protected void onStartLoading() {
+ // start watching for dataset changes
+ dao.registerObserver(this);
+
+ if (cursor == null) {
+ forceLoad();
+ } else {
+ deliverResult(cursor);
+ if (takeContentChanged()) {
+ forceLoad();
+ }
+ }
+ }
+
+ @Override
+ protected void onStopLoading() {
+ cancelLoad();
+ }
+
+ @Override
+ public void onCanceled(Cursor cursor) {
+ if (cursor != null && !cursor.isClosed()) {
+ cursor.close();
+ }
+ }
+
+ @Override
+ protected void onReset() {
+ super.onReset();
+ onStopLoading();
+ if (cursor != null) {
+ if (!cursor.isClosed()) {
+ cursor.close();
+ }
+ cursor = null;
+ }
+
+ // stop watching for changes
+ dao.unregisterObserver(this);
+ }
+
+ public void onChange() {
+ onContentChanged();
+ }
+
+ public PreparedQuery getQuery() {
+ return query;
+ }
+
+ public void setQuery(PreparedQuery mQuery) {
+ this.query = mQuery;
+ }
+}
diff --git a/MemeProject/app/src/main/java/com/j256/ormlite/android/compat/ApiCompatibility.java b/MemeProject/app/src/main/java/com/j256/ormlite/android/compat/ApiCompatibility.java
new file mode 100644
index 0000000..6d76e18
--- /dev/null
+++ b/MemeProject/app/src/main/java/com/j256/ormlite/android/compat/ApiCompatibility.java
@@ -0,0 +1,34 @@
+package com.j256.ormlite.android.compat;
+
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+
+/**
+ * Compatibility interface to support various different versions of the Android API.
+ *
+ * @author graywatson
+ */
+public interface ApiCompatibility {
+
+ /**
+ * Perform a raw query on a database with an optional cancellation-hook.
+ */
+ public Cursor rawQuery(SQLiteDatabase db, String sql, String[] selectionArgs, CancellationHook cancellationHook);
+
+ /**
+ * Return a cancellation hook object that will be passed to the
+ * {@link #rawQuery(SQLiteDatabase, String, String[], CancellationHook)}. If not supported then this will return
+ * null.
+ */
+ public CancellationHook createCancellationHook();
+
+ /**
+ * Cancellation hook class returned by {@link ApiCompatibility#createCancellationHook()}.
+ */
+ public interface CancellationHook {
+ /**
+ * Cancel the associated query.
+ */
+ public void cancel();
+ }
+}
diff --git a/MemeProject/app/src/main/java/com/j256/ormlite/android/compat/ApiCompatibilityUtils.java b/MemeProject/app/src/main/java/com/j256/ormlite/android/compat/ApiCompatibilityUtils.java
new file mode 100644
index 0000000..25686dc
--- /dev/null
+++ b/MemeProject/app/src/main/java/com/j256/ormlite/android/compat/ApiCompatibilityUtils.java
@@ -0,0 +1,52 @@
+package com.j256.ormlite.android.compat;
+
+import android.os.Build;
+
+/**
+ * Utility class which loads the various classes based on which API version is being supported.
+ *
+ * @author graywatson
+ */
+@SuppressWarnings("unused")
+public class ApiCompatibilityUtils {
+
+ private static ApiCompatibility compatibility;
+
+ /**
+ * Copied from {@link Build.VERSION_CODES}. We don't use those codes because they won't be in certain versions of
+ * Build.
+ */
+ private static final int BASE = 1;
+ private static final int BASE_1_1 = 2;
+ private static final int CUPCAKE = 3;
+ private static final int DONUT = 4;
+ private static final int ECLAIR = 5;
+ private static final int ECLAIR_0_1 = 6;
+ private static final int ECLAIR_MR1 = 7;
+ private static final int FROYO = 8;
+ private static final int GINGERBREAD = 9;
+ private static final int GINGERBREAD_MR1 = 10;
+ private static final int HONEYCOMB = 11;
+ private static final int HONEYCOMB_MR1 = 12;
+ private static final int HONEYCOMB_MR2 = 13;
+ private static final int ICE_CREAM_SANDWICH = 14;
+ private static final int ICE_CREAM_SANDWICH_MR1 = 15;
+ private static final int JELLY_BEAN = 16;
+ private static final int JELLY_BEAN_MR1 = 17;
+ private static final int JELLY_BEAN_MR2 = 18;
+
+ static {
+ if (Build.VERSION.SDK_INT >= JELLY_BEAN) {
+ compatibility = new JellyBeanApiCompatibility();
+ } else {
+ compatibility = new BasicApiCompatibility();
+ }
+ }
+
+ /**
+ * Return the compatibility class that matches our build number.
+ */
+ public static ApiCompatibility getCompatibility() {
+ return compatibility;
+ }
+}
diff --git a/MemeProject/app/src/main/java/com/j256/ormlite/android/compat/BasicApiCompatibility.java b/MemeProject/app/src/main/java/com/j256/ormlite/android/compat/BasicApiCompatibility.java
new file mode 100644
index 0000000..27be2c7
--- /dev/null
+++ b/MemeProject/app/src/main/java/com/j256/ormlite/android/compat/BasicApiCompatibility.java
@@ -0,0 +1,21 @@
+package com.j256.ormlite.android.compat;
+
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+
+/**
+ * Basic class which provides no-op methods for all Android version.
+ *
+ * @author graywatson
+ */
+public class BasicApiCompatibility implements ApiCompatibility {
+
+ public Cursor rawQuery(SQLiteDatabase db, String sql, String[] selectionArgs, CancellationHook cancellationHook) {
+ // NOTE: cancellationHook will always be null
+ return db.rawQuery(sql, selectionArgs);
+ }
+
+ public CancellationHook createCancellationHook() {
+ return null;
+ }
+}
diff --git a/MemeProject/app/src/main/java/com/j256/ormlite/android/compat/JellyBeanApiCompatibility.java b/MemeProject/app/src/main/java/com/j256/ormlite/android/compat/JellyBeanApiCompatibility.java
new file mode 100644
index 0000000..982e7f1
--- /dev/null
+++ b/MemeProject/app/src/main/java/com/j256/ormlite/android/compat/JellyBeanApiCompatibility.java
@@ -0,0 +1,47 @@
+package com.j256.ormlite.android.compat;
+
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.CancellationSignal;
+
+/**
+ * Basic class which provides no-op methods for all Android version.
+ *
+ *
+ * NOTE: Will show as in error if compiled with previous Android versions.
+ *
+ *
+ * @author graywatson
+ */
+public class JellyBeanApiCompatibility extends BasicApiCompatibility {
+
+ @Override
+ public Cursor rawQuery(SQLiteDatabase db, String sql, String[] selectionArgs, CancellationHook cancellationHook) {
+ if (cancellationHook == null) {
+ return db.rawQuery(sql, selectionArgs);
+ } else {
+ return db.rawQuery(sql, selectionArgs, ((JellyBeanCancellationHook) cancellationHook).cancellationSignal);
+ }
+ }
+
+ @Override
+ public CancellationHook createCancellationHook() {
+ return new JellyBeanCancellationHook();
+ }
+
+ /**
+ * Hook object that supports canceling a running query.
+ */
+ protected static class JellyBeanCancellationHook implements CancellationHook {
+
+ private final CancellationSignal cancellationSignal;
+
+ public JellyBeanCancellationHook() {
+ this.cancellationSignal = new CancellationSignal();
+ }
+
+ public void cancel() {
+ cancellationSignal.cancel();
+ }
+ }
+}
diff --git a/MemeProject/app/src/main/java/com/j256/ormlite/core/LICENSE.txt b/MemeProject/app/src/main/java/com/j256/ormlite/core/LICENSE.txt
new file mode 100644
index 0000000..ff0417e
--- /dev/null
+++ b/MemeProject/app/src/main/java/com/j256/ormlite/core/LICENSE.txt
@@ -0,0 +1,17 @@
+Copyright 2010 to 2011 by Gray Watson
+
+This file is part of the ORMLite package.
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+The author may be contacted via http://ormlite.sourceforge.net/
diff --git a/MemeProject/app/src/main/java/com/j256/ormlite/core/README.txt b/MemeProject/app/src/main/java/com/j256/ormlite/core/README.txt
new file mode 100644
index 0000000..c7ec0db
--- /dev/null
+++ b/MemeProject/app/src/main/java/com/j256/ormlite/core/README.txt
@@ -0,0 +1,15 @@
+This package provides the core functionality for the JDBC and Android packages. Users
+that are connecting to SQL databases via JDBC connections will need to download the
+ormlite-jdbc package as well. Android users should download the ormlite-android package
+as well as this core package.
+
+For more information, see the online documentation on the home page:
+
+ http://ormlite.com/
+
+Sources can be found online via Github:
+
+ https://github.com/j256/ormlite-core
+
+Enjoy,
+Gray Watson
diff --git a/MemeProject/app/src/main/java/com/j256/ormlite/dao/BaseDaoImpl.java b/MemeProject/app/src/main/java/com/j256/ormlite/dao/BaseDaoImpl.java
new file mode 100644
index 0000000..f25cd6e
--- /dev/null
+++ b/MemeProject/app/src/main/java/com/j256/ormlite/dao/BaseDaoImpl.java
@@ -0,0 +1,1081 @@
+package com.j256.ormlite.dao;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.j256.ormlite.db.DatabaseType;
+import com.j256.ormlite.field.DataType;
+import com.j256.ormlite.field.DatabaseField;
+import com.j256.ormlite.field.FieldType;
+import com.j256.ormlite.misc.BaseDaoEnabled;
+import com.j256.ormlite.misc.SqlExceptionUtil;
+import com.j256.ormlite.stmt.DeleteBuilder;
+import com.j256.ormlite.stmt.GenericRowMapper;
+import com.j256.ormlite.stmt.PreparedDelete;
+import com.j256.ormlite.stmt.PreparedQuery;
+import com.j256.ormlite.stmt.PreparedUpdate;
+import com.j256.ormlite.stmt.QueryBuilder;
+import com.j256.ormlite.stmt.SelectArg;
+import com.j256.ormlite.stmt.SelectIterator;
+import com.j256.ormlite.stmt.StatementBuilder.StatementType;
+import com.j256.ormlite.stmt.StatementExecutor;
+import com.j256.ormlite.stmt.UpdateBuilder;
+import com.j256.ormlite.stmt.Where;
+import com.j256.ormlite.support.ConnectionSource;
+import com.j256.ormlite.support.DatabaseConnection;
+import com.j256.ormlite.support.DatabaseResults;
+import com.j256.ormlite.table.DatabaseTableConfig;
+import com.j256.ormlite.table.ObjectFactory;
+import com.j256.ormlite.table.TableInfo;
+
+/**
+ * Base class for the Database Access Objects that handle the reading and writing a class from the database.
+ *
+ *
+ * This class is also {@link Iterable} which means you can do a {@code for (T obj : dao)} type of loop code to iterate
+ * through the table of persisted objects. See {@link #iterator()}.
+ *
+ *
+ *
+ * NOTE: If you are using the Spring type wiring, {@link #initialize} should be called after all of the set
+ * methods. In Spring XML, init-method="initialize" should be used.
+ *
+ *
+ * @param
+ * The class that the code will be operating on.
+ * @param
+ * The class of the ID column associated with the class. The T class does not require an ID field. The class
+ * needs an ID parameter however so you can use Void or Object to satisfy the compiler.
+ * @author graywatson
+ */
+public abstract class BaseDaoImpl implements Dao {
+
+ private static final ThreadLocal>> daoConfigLevelLocal =
+ new ThreadLocal>>() {
+ @Override
+ protected List> initialValue() {
+ return new ArrayList>(10);
+ }
+ };
+ private static ReferenceObjectCache defaultObjectCache;
+ private static final Object constantObject = new Object();
+
+ protected StatementExecutor statementExecutor;
+ protected DatabaseType databaseType;
+ protected final Class dataClass;
+ protected DatabaseTableConfig tableConfig;
+ protected TableInfo tableInfo;
+ protected ConnectionSource connectionSource;
+ protected CloseableIterator lastIterator;
+ protected ObjectFactory objectFactory;
+
+ private boolean initialized;
+ private ObjectCache objectCache;
+ private Map daoObserverMap;
+
+ /**
+ * Construct our base DAO using Spring type wiring. The {@link ConnectionSource} must be set with the
+ * {@link #setConnectionSource} method afterwards and then the {@link #initialize()} method must be called. The
+ * dataClass provided must have its fields marked with {@link DatabaseField} annotations or the
+ * {@link #setTableConfig} method must be called before the {@link #initialize()} method is called.
+ *
+ *
+ * If you are using Spring then your should use: init-method="initialize"
+ *
+ *
+ * @param dataClass
+ * Class associated with this Dao. This must match the T class parameter.
+ */
+ protected BaseDaoImpl(Class dataClass) throws SQLException {
+ this(null, dataClass, null);
+ }
+
+ /**
+ * Construct our base DAO class. The dataClass provided must have its fields marked with {@link DatabaseField} or
+ * javax.persistance annotations.
+ *
+ * @param connectionSource
+ * Source of our database connections.
+ * @param dataClass
+ * Class associated with this Dao. This must match the T class parameter.
+ */
+ protected BaseDaoImpl(ConnectionSource connectionSource, Class dataClass) throws SQLException {
+ this(connectionSource, dataClass, null);
+ }
+
+ /**
+ * Construct our base DAO class.
+ *
+ * @param connectionSource
+ * Source of our database connections.
+ * @param tableConfig
+ * Hand or Spring wired table configuration information.
+ */
+ protected BaseDaoImpl(ConnectionSource connectionSource, DatabaseTableConfig tableConfig) throws SQLException {
+ this(connectionSource, tableConfig.getDataClass(), tableConfig);
+ }
+
+ private BaseDaoImpl(ConnectionSource connectionSource, Class dataClass, DatabaseTableConfig tableConfig)
+ throws SQLException {
+ this.dataClass = dataClass;
+ this.tableConfig = tableConfig;
+ if (connectionSource != null) {
+ this.connectionSource = connectionSource;
+ initialize();
+ }
+ }
+
+ /**
+ * Initialize the various DAO configurations after the various setters have been called.
+ */
+ public void initialize() throws SQLException {
+ if (initialized) {
+ // just skip it if already initialized
+ return;
+ }
+
+ if (connectionSource == null) {
+ throw new IllegalStateException("connectionSource was never set on " + getClass().getSimpleName());
+ }
+
+ databaseType = connectionSource.getDatabaseType();
+ if (databaseType == null) {
+ throw new IllegalStateException("connectionSource is getting a null DatabaseType in "
+ + getClass().getSimpleName());
+ }
+ if (tableConfig == null) {
+ tableInfo = new TableInfo(connectionSource, this, dataClass);
+ } else {
+ tableConfig.extractFieldTypes(connectionSource);
+ tableInfo = new TableInfo(databaseType, this, tableConfig);
+ }
+ statementExecutor = new StatementExecutor(databaseType, tableInfo, this);
+
+ /*
+ * This is a bit complex. Initially, when we were configuring the field types, external DAO information would be
+ * configured for auto-refresh, foreign BaseDaoEnabled classes, and foreign-collections. This would cause the
+ * system to go recursive and for class loops, a stack overflow.
+ *
+ * Then we fixed this by putting a level counter in the FieldType constructor that would stop the configurations
+ * when we reach some recursion level. But this created some bad problems because we were using the DaoManager
+ * to cache the created DAOs that had been constructed already limited by the level.
+ *
+ * What we do now is have a 2 phase initialization. The constructor initializes most of the fields but then we
+ * go back and call FieldType.configDaoInformation() after we are done. So for every DAO that is initialized
+ * here, we have to see if it is the top DAO. If not we save it for dao configuration later.
+ */
+ List> daoConfigList = daoConfigLevelLocal.get();
+ daoConfigList.add(this);
+ if (daoConfigList.size() > 1) {
+ // if we have recursed then just save the dao for later configuration
+ return;
+ }
+
+ try {
+ /*
+ * WARNING: We do _not_ use an iterator here because we may be adding to the list as we process it and we'll
+ * get exceptions otherwise. This is an ArrayList so the get(i) should be efficient.
+ *
+ * Also, do _not_ get a copy of daoConfigLevel.doArray because that array may be replaced by another, larger
+ * one during the recursion.
+ */
+ for (int i = 0; i < daoConfigList.size(); i++) {
+ BaseDaoImpl, ?> dao = daoConfigList.get(i);
+
+ /*
+ * Here's another complex bit. The first DAO that is being constructed as part of a DAO chain is not yet
+ * in the DaoManager cache. If we continue onward we might come back around and try to configure this
+ * DAO again. Forcing it into the cache here makes sure it won't be configured twice. This will cause it
+ * to be stuck in twice when it returns out to the DaoManager but that's a small price to pay. This also
+ * applies to self-referencing classes.
+ */
+ DaoManager.registerDao(connectionSource, dao);
+
+ try {
+ // config our fields which may go recursive
+ for (FieldType fieldType : dao.getTableInfo().getFieldTypes()) {
+ fieldType.configDaoInformation(connectionSource, dao.getDataClass());
+ }
+ } catch (SQLException e) {
+ // unregister the DAO we just pre-registered
+ DaoManager.unregisterDao(connectionSource, dao);
+ throw e;
+ }
+
+ // it's now been fully initialized
+ dao.initialized = true;
+ }
+ } finally {
+ // if we throw we want to clear our class hierarchy here
+ daoConfigList.clear();
+ daoConfigLevelLocal.remove();
+ }
+ }
+
+ public T queryForId(ID id) throws SQLException {
+ checkForInitialized();
+ DatabaseConnection connection = connectionSource.getReadOnlyConnection();
+ try {
+ return statementExecutor.queryForId(connection, id, objectCache);
+ } finally {
+ connectionSource.releaseConnection(connection);
+ }
+ }
+
+ public T queryForFirst(PreparedQuery preparedQuery) throws SQLException {
+ checkForInitialized();
+ DatabaseConnection connection = connectionSource.getReadOnlyConnection();
+ try {
+ return statementExecutor.queryForFirst(connection, preparedQuery, objectCache);
+ } finally {
+ connectionSource.releaseConnection(connection);
+ }
+ }
+
+ public List queryForAll() throws SQLException {
+ checkForInitialized();
+ return statementExecutor.queryForAll(connectionSource, objectCache);
+ }
+
+ public List queryForEq(String fieldName, Object value) throws SQLException {
+ return queryBuilder().where().eq(fieldName, value).query();
+ }
+
+ public QueryBuilder queryBuilder() {
+ checkForInitialized();
+ return new QueryBuilder(databaseType, tableInfo, this);
+ }
+
+ public UpdateBuilder updateBuilder() {
+ checkForInitialized();
+ return new UpdateBuilder(databaseType, tableInfo, this);
+ }
+
+ public DeleteBuilder deleteBuilder() {
+ checkForInitialized();
+ return new DeleteBuilder(databaseType, tableInfo, this);
+ }
+
+ public List query(PreparedQuery preparedQuery) throws SQLException {
+ checkForInitialized();
+ return statementExecutor.query(connectionSource, preparedQuery, objectCache);
+ }
+
+ public List queryForMatching(T matchObj) throws SQLException {
+ return queryForMatching(matchObj, false);
+ }
+
+ public List queryForMatchingArgs(T matchObj) throws SQLException {
+ return queryForMatching(matchObj, true);
+ }
+
+ public List queryForFieldValues(Map fieldValues) throws SQLException {
+ return queryForFieldValues(fieldValues, false);
+ }
+
+ public List queryForFieldValuesArgs(Map fieldValues) throws SQLException {
+ return queryForFieldValues(fieldValues, true);
+ }
+
+ public T queryForSameId(T data) throws SQLException {
+ checkForInitialized();
+ if (data == null) {
+ return null;
+ }
+ ID id = extractId(data);
+ if (id == null) {
+ return null;
+ } else {
+ return queryForId(id);
+ }
+ }
+
+ public int create(T data) throws SQLException {
+ checkForInitialized();
+ // ignore creating a null object
+ if (data == null) {
+ return 0;
+ }
+ if (data instanceof BaseDaoEnabled) {
+ @SuppressWarnings("unchecked")
+ BaseDaoEnabled daoEnabled = (BaseDaoEnabled) data;
+ daoEnabled.setDao(this);
+ }
+ DatabaseConnection connection = connectionSource.getReadWriteConnection();
+ try {
+ return statementExecutor.create(connection, data, objectCache);
+ } finally {
+ connectionSource.releaseConnection(connection);
+ }
+ }
+
+ public int create(final Collection datas) throws SQLException {
+ checkForInitialized();
+ for (T data : datas) {
+ if (data instanceof BaseDaoEnabled) {
+ @SuppressWarnings("unchecked")
+ BaseDaoEnabled daoEnabled = (BaseDaoEnabled) data;
+ daoEnabled.setDao(this);
+ }
+ }
+ /*
+ * This is a little strange in that we get the connection but then the call-batch-task saves another one. I
+ * thought that it was an ok thing to do otherwise it made the call-batch-tasks more complicated.
+ */
+ final DatabaseConnection connection = connectionSource.getReadWriteConnection();
+ try {
+ return callBatchTasks(new Callable() {
+ public Integer call() throws SQLException {
+ int modCount = 0;
+ for (T data : datas) {
+ modCount += statementExecutor.create(connection, data, objectCache);
+ }
+ return modCount;
+ }
+ });
+ } finally {
+ connectionSource.releaseConnection(connection);
+ }
+ }
+
+ public T createIfNotExists(T data) throws SQLException {
+ if (data == null) {
+ return null;
+ }
+ T existing = queryForSameId(data);
+ if (existing == null) {
+ create(data);
+ return data;
+ } else {
+ return existing;
+ }
+ }
+
+ public CreateOrUpdateStatus createOrUpdate(T data) throws SQLException {
+ if (data == null) {
+ return new CreateOrUpdateStatus(false, false, 0);
+ }
+ ID id = extractId(data);
+ // assume we need to create it if there is no id
+ if (id == null || !idExists(id)) {
+ int numRows = create(data);
+ return new CreateOrUpdateStatus(true, false, numRows);
+ } else {
+ int numRows = update(data);
+ return new CreateOrUpdateStatus(false, true, numRows);
+ }
+ }
+
+ public int update(T data) throws SQLException {
+ checkForInitialized();
+ // ignore updating a null object
+ if (data == null) {
+ return 0;
+ }
+ if (data instanceof BaseDaoEnabled) {
+ @SuppressWarnings("unchecked")
+ BaseDaoEnabled daoEnabled = (BaseDaoEnabled) data;
+ daoEnabled.setDao(this);
+ }
+ DatabaseConnection connection = connectionSource.getReadWriteConnection();
+ try {
+ return statementExecutor.update(connection, data, objectCache);
+ } finally {
+ connectionSource.releaseConnection(connection);
+ }
+ }
+
+ public int updateId(T data, ID newId) throws SQLException {
+ checkForInitialized();
+ // ignore updating a null object
+ if (data == null) {
+ return 0;
+ } else {
+ DatabaseConnection connection = connectionSource.getReadWriteConnection();
+ try {
+ return statementExecutor.updateId(connection, data, newId, objectCache);
+ } finally {
+ connectionSource.releaseConnection(connection);
+ }
+ }
+ }
+
+ public int update(PreparedUpdate preparedUpdate) throws SQLException {
+ checkForInitialized();
+ DatabaseConnection connection = connectionSource.getReadWriteConnection();
+ try {
+ return statementExecutor.update(connection, preparedUpdate);
+ } finally {
+ connectionSource.releaseConnection(connection);
+ }
+ }
+
+ public int refresh(T data) throws SQLException {
+ checkForInitialized();
+ // ignore refreshing a null object
+ if (data == null) {
+ return 0;
+ }
+ if (data instanceof BaseDaoEnabled) {
+ @SuppressWarnings("unchecked")
+ BaseDaoEnabled daoEnabled = (BaseDaoEnabled) data;
+ daoEnabled.setDao(this);
+ }
+ DatabaseConnection connection = connectionSource.getReadOnlyConnection();
+ try {
+ return statementExecutor.refresh(connection, data, objectCache);
+ } finally {
+ connectionSource.releaseConnection(connection);
+ }
+ }
+
+ public int delete(T data) throws SQLException {
+ checkForInitialized();
+ // ignore deleting a null object
+ if (data == null) {
+ return 0;
+ } else {
+ DatabaseConnection connection = connectionSource.getReadWriteConnection();
+ try {
+ return statementExecutor.delete(connection, data, objectCache);
+ } finally {
+ connectionSource.releaseConnection(connection);
+ }
+ }
+ }
+
+ public int deleteById(ID id) throws SQLException {
+ checkForInitialized();
+ // ignore deleting a null id
+ if (id == null) {
+ return 0;
+ } else {
+ DatabaseConnection connection = connectionSource.getReadWriteConnection();
+ try {
+ return statementExecutor.deleteById(connection, id, objectCache);
+ } finally {
+ connectionSource.releaseConnection(connection);
+ }
+ }
+ }
+
+ public int delete(Collection datas) throws SQLException {
+ checkForInitialized();
+ // ignore deleting a null object
+ if (datas == null || datas.isEmpty()) {
+ return 0;
+ } else {
+ DatabaseConnection connection = connectionSource.getReadWriteConnection();
+ try {
+ return statementExecutor.deleteObjects(connection, datas, objectCache);
+ } finally {
+ connectionSource.releaseConnection(connection);
+ }
+ }
+ }
+
+ public int deleteIds(Collection ids) throws SQLException {
+ checkForInitialized();
+ // ignore deleting a null object
+ if (ids == null || ids.isEmpty()) {
+ return 0;
+ } else {
+ DatabaseConnection connection = connectionSource.getReadWriteConnection();
+ try {
+ return statementExecutor.deleteIds(connection, ids, objectCache);
+ } finally {
+ connectionSource.releaseConnection(connection);
+ }
+ }
+ }
+
+ public int delete(PreparedDelete preparedDelete) throws SQLException {
+ checkForInitialized();
+ DatabaseConnection connection = connectionSource.getReadWriteConnection();
+ try {
+ return statementExecutor.delete(connection, preparedDelete);
+ } finally {
+ connectionSource.releaseConnection(connection);
+ }
+ }
+
+ public CloseableIterator iterator() {
+ return iterator(DatabaseConnection.DEFAULT_RESULT_FLAGS);
+ }
+
+ public CloseableIterator closeableIterator() {
+ return iterator(DatabaseConnection.DEFAULT_RESULT_FLAGS);
+ }
+
+ public CloseableIterator iterator(int resultFlags) {
+ checkForInitialized();
+ lastIterator = createIterator(resultFlags);
+ return lastIterator;
+ }
+
+ public CloseableWrappedIterable getWrappedIterable() {
+ checkForInitialized();
+ return new CloseableWrappedIterableImpl(new CloseableIterable() {
+ public Iterator iterator() {
+ return closeableIterator();
+ }
+ public CloseableIterator closeableIterator() {
+ try {
+ return BaseDaoImpl.this.createIterator(DatabaseConnection.DEFAULT_RESULT_FLAGS);
+ } catch (Exception e) {
+ throw new IllegalStateException("Could not build iterator for " + dataClass, e);
+ }
+ }
+ });
+ }
+
+ public CloseableWrappedIterable getWrappedIterable(final PreparedQuery preparedQuery) {
+ checkForInitialized();
+ return new CloseableWrappedIterableImpl(new CloseableIterable() {
+ public Iterator iterator() {
+ return closeableIterator();
+ }
+ public CloseableIterator closeableIterator() {
+ try {
+ return BaseDaoImpl.this.createIterator(preparedQuery, DatabaseConnection.DEFAULT_RESULT_FLAGS);
+ } catch (Exception e) {
+ throw new IllegalStateException("Could not build prepared-query iterator for " + dataClass, e);
+ }
+ }
+ });
+ }
+
+ public void closeLastIterator() throws IOException {
+ if (lastIterator != null) {
+ lastIterator.close();
+ lastIterator = null;
+ }
+ }
+
+ public CloseableIterator iterator(PreparedQuery preparedQuery) throws SQLException {
+ return iterator(preparedQuery, DatabaseConnection.DEFAULT_RESULT_FLAGS);
+ }
+
+ public CloseableIterator iterator(PreparedQuery preparedQuery, int resultFlags) throws SQLException {
+ checkForInitialized();
+ lastIterator = createIterator(preparedQuery, resultFlags);
+ return lastIterator;
+ }
+
+ public GenericRawResults queryRaw(String query, String... arguments) throws SQLException {
+ checkForInitialized();
+ try {
+ return statementExecutor.queryRaw(connectionSource, query, arguments, objectCache);
+ } catch (SQLException e) {
+ throw SqlExceptionUtil.create("Could not perform raw query for " + query, e);
+ }
+ }
+
+ public GenericRawResults queryRaw(String query, RawRowMapper mapper, String... arguments)
+ throws SQLException {
+ checkForInitialized();
+ try {
+ return statementExecutor.queryRaw(connectionSource, query, mapper, arguments, objectCache);
+ } catch (SQLException e) {
+ throw SqlExceptionUtil.create("Could not perform raw query for " + query, e);
+ }
+ }
+
+ public GenericRawResults queryRaw(String query, DataType[] columnTypes, RawRowObjectMapper mapper,
+ String... arguments) throws SQLException {
+ checkForInitialized();
+ try {
+ return statementExecutor.queryRaw(connectionSource, query, columnTypes, mapper, arguments, objectCache);
+ } catch (SQLException e) {
+ throw SqlExceptionUtil.create("Could not perform raw query for " + query, e);
+ }
+ }
+
+ public GenericRawResults