From 9cb019f5ca8959b84dc2e77b7af60216ddb4744c Mon Sep 17 00:00:00 2001 From: "Markus M. May" Date: Thu, 4 Jan 2018 22:22:08 +0100 Subject: [PATCH] #557 - showoff of possible refactorings - see REFACTOR.md for additonal details --- .../androidaps/Services/DataService.java | 9 +- .../androidaps/db/DatabaseHelper.java | 4 +- .../info/nightscout/androidaps/db/Food.java | 28 ++- .../nightscout/androidaps/db/FoodDao.java | 161 ++++++++++++++ .../nightscout/androidaps/db/FoodHelper.java | 208 ------------------ .../androidaps/plugins/Food/FoodFragment.java | 6 +- .../info/nightscout/utils/JsonHelper.java | 49 +++++ 7 files changed, 249 insertions(+), 216 deletions(-) create mode 100644 app/src/main/java/info/nightscout/androidaps/db/FoodDao.java delete mode 100644 app/src/main/java/info/nightscout/androidaps/db/FoodHelper.java create mode 100644 app/src/main/java/info/nightscout/utils/JsonHelper.java diff --git a/app/src/main/java/info/nightscout/androidaps/Services/DataService.java b/app/src/main/java/info/nightscout/androidaps/Services/DataService.java index b242c4c099..570aab6ffc 100644 --- a/app/src/main/java/info/nightscout/androidaps/Services/DataService.java +++ b/app/src/main/java/info/nightscout/androidaps/Services/DataService.java @@ -12,6 +12,8 @@ import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.sql.SQLException; + import info.nightscout.androidaps.Config; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; @@ -518,7 +520,12 @@ public class DataService extends IntentService { } private void handleRemovedFoodRecord(String _id) { - MainApp.getDbHelper().foodHelper.deleteFoodById(_id); + + try { + MainApp.getDbHelper().foodHelper.getDao().deleteByNSId(_id); + } catch (SQLException e) { + log.error("Unhandled exception", e); + } } public void handleAddChangeFoodRecord(JSONObject trJson) throws JSONException { diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java index 082f872d20..79b06e5977 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java +++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java @@ -68,7 +68,6 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { public static final String DATABASE_DBREQUESTS = "DBRequests"; public static final String DATABASE_CAREPORTALEVENTS = "CareportalEvents"; public static final String DATABASE_PROFILESWITCHES = "ProfileSwitches"; - public static final String DATABASE_FOODS = "Foods"; private static final int DATABASE_VERSION = 8; @@ -95,11 +94,12 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { private static final ScheduledExecutorService profileSwitchEventWorker = Executors.newSingleThreadScheduledExecutor(); private static ScheduledFuture scheduledProfileSwitchEventPost = null; - public FoodHelper foodHelper = new FoodHelper(this); + public FoodHelper foodHelper; public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); onCreate(getWritableDatabase(), getConnectionSource()); + foodHelper = new FoodHelper(getConnectionSource()); //onUpgrade(getWritableDatabase(), getConnectionSource(), 1,1); } diff --git a/app/src/main/java/info/nightscout/androidaps/db/Food.java b/app/src/main/java/info/nightscout/androidaps/db/Food.java index cb856df073..f3f7071cb5 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/Food.java +++ b/app/src/main/java/info/nightscout/androidaps/db/Food.java @@ -3,20 +3,25 @@ package info.nightscout.androidaps.db; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; +import org.json.JSONException; +import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Objects; +import info.nightscout.utils.JsonHelper; + /** * Created by mike on 20.09.2017. */ - -@DatabaseTable(tableName = DatabaseHelper.DATABASE_FOODS) +@DatabaseTable(tableName = Food.TABLE_FOODS) public class Food { private static Logger log = LoggerFactory.getLogger(Food.class); + public static final String TABLE_FOODS = "Foods"; + @DatabaseField(id = true) public long key; @@ -64,6 +69,25 @@ public class Food { key = System.currentTimeMillis(); } + public static Food createFromJson(JSONObject json) throws JSONException { + Food food = new Food(); + if ("food".equals(JsonHelper.safeGetString(json, "type"))) { + food._id = JsonHelper.safeGetString(json, "_id"); + food.category = JsonHelper.safeGetString(json, "category"); + food.subcategory = JsonHelper.safeGetString(json, "subcategory"); + food.name = JsonHelper.safeGetString(json, "name"); + food.units = JsonHelper.safeGetString(json, "unit"); + food.portion = JsonHelper.safeGetDouble(json, "portion"); + food.carbs = JsonHelper.safeGetInt(json, "carbs"); + food.gi = JsonHelper.safeGetInt(json, "gi"); + food.energy = JsonHelper.safeGetInt(json, "energy"); + food.protein = JsonHelper.safeGetInt(json, "protein"); + food.fat = JsonHelper.safeGetInt(json, "fat"); + } + + return food; + } + public boolean isEqual(Food other) { if (portion != other.portion) return false; diff --git a/app/src/main/java/info/nightscout/androidaps/db/FoodDao.java b/app/src/main/java/info/nightscout/androidaps/db/FoodDao.java new file mode 100644 index 0000000000..18e543149c --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/db/FoodDao.java @@ -0,0 +1,161 @@ +package info.nightscout.androidaps.db; + +import android.content.Context; + +import com.j256.ormlite.android.apptools.OpenHelperManager; +import com.j256.ormlite.dao.BaseDaoImpl; +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.stmt.PreparedQuery; +import com.j256.ormlite.stmt.QueryBuilder; +import com.j256.ormlite.support.ConnectionSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by triplem on 04.01.18. + */ + +public class FoodDao extends BaseDaoImpl { + + private static final Logger log = LoggerFactory.getLogger(FoodDao.class); + + public FoodDao(ConnectionSource source) throws SQLException { + super(source, Food.class); + } + + /** + * Static instantiation methods. The database connection is accessed via + * the OpenHelperManager which keeps a count of the number of objects + * using the connection. Thus every call to connect() must be matched by + * a call to release() once the session is done. + */ + public static FoodDao connect(Context context) { + return with(OpenHelperManager.getHelper(context, DatabaseHelper.class) + .getConnectionSource()); + } + + public static FoodDao with(ConnectionSource connection) { + try { + return (FoodDao) DaoManager.createDao(connection, Food.class); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + /** + * Releasing the DAO flags the connection manager that the DAO is no + * longer using the connection. When the connection count is zero, the + * connection manager will close the database. + */ + public void release() { + OpenHelperManager.releaseHelper(); + } + + /** + * + * @return + * + * @deprecated should use queryForAll instead, which is a standard method of the ORMLite DAO + */ + public List getFoodData() { + try { + QueryBuilder queryBuilder = this.queryBuilder(); + PreparedQuery preparedQuery = queryBuilder.prepare(); + return this.query(preparedQuery); + } catch (SQLException e) { + log.error("Unhandled exception", e); + } + + return new ArrayList<>(); + } + + public boolean createOrUpdateByNS(Food food) { + try { + // find by NS _id + if (food._id != null) { + Food old = this.findByNSId(food._id); + + if (old != null) { + if (!old.isEqual(food)) { + this.delete(old); // need to delete/create because date may change too + old.copyFrom(food); + this.create(old); + log.debug("FOOD: Updating record by _id: " + old.toString()); + FoodHelper.scheduleFoodChange(); + return true; + } else { + return false; + } + } + } + this.createOrUpdate(food); + log.debug("FOOD: New record: " + food.toString()); + FoodHelper.scheduleFoodChange(); + return true; + } catch (SQLException e) { + log.error("Unhandled exception", e); + } + return false; + } + + /** + * deletes an entry by its NS Id. + * + * Basically a convenience method for findByNSId and deleteFood. + * + * should be moved to a Service + * + * @param _id + */ + public void deleteByNSId(String _id) throws SQLException { + Food stored = findByNSId(_id); + if (stored != null) { + log.debug("FOOD: Removing Food record from database: " + stored.toString()); + this.deleteFood(stored); + } + } + + /** + * deletes the food and sends the foodChange Event + * + * should be moved ot a Service + * + * @param food + */ + public void deleteFood(Food food) { + try { + this.delete(food); + FoodHelper.scheduleFoodChange(); + } catch (SQLException e) { + log.error("Unhandled exception", e); + } + } + + /** + * finds food by its NS Id. + * + * @param _id + * @return + */ + public Food findByNSId(String _id) { + try { + List list = this.queryForEq("_id", _id); + + if (list.size() == 1) { // really? if there are more then one result, then we do not return anything... + return list.get(0); + } + } catch (SQLException e) { + log.error("Unhandled exception", e); + } + return null; + } + + + +} + diff --git a/app/src/main/java/info/nightscout/androidaps/db/FoodHelper.java b/app/src/main/java/info/nightscout/androidaps/db/FoodHelper.java deleted file mode 100644 index a933c2166e..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/db/FoodHelper.java +++ /dev/null @@ -1,208 +0,0 @@ -package info.nightscout.androidaps.db; - -import com.j256.ormlite.android.AndroidConnectionSource; -import com.j256.ormlite.dao.Dao; -import com.j256.ormlite.stmt.PreparedQuery; -import com.j256.ormlite.stmt.QueryBuilder; -import com.j256.ormlite.stmt.Where; -import com.j256.ormlite.table.TableUtils; - -import org.json.JSONException; -import org.json.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -import info.nightscout.androidaps.MainApp; -import info.nightscout.androidaps.events.EventFoodDatabaseChanged; - -/** - * Created by mike on 24.09.2017. - */ - -public class FoodHelper { - private static Logger log = LoggerFactory.getLogger(FoodHelper.class); - - DatabaseHelper databaseHelper; - - private static final ScheduledExecutorService foodEventWorker = Executors.newSingleThreadScheduledExecutor(); - private static ScheduledFuture scheduledFoodEventPost = null; - - public FoodHelper(DatabaseHelper databaseHelper) { - this.databaseHelper = databaseHelper; - } - - private Dao getDaoFood() throws SQLException { - return databaseHelper.getDao(Food.class); - } - - public void resetFood() { - try { - TableUtils.dropTable(databaseHelper.getConnectionSource(), Food.class, true); - TableUtils.createTableIfNotExists(databaseHelper.getConnectionSource(), Food.class); - } catch (SQLException e) { - log.error("Unhandled exception", e); - } - scheduleFoodChange(); - } - - public List getFoodData() { - try { - Dao daoFood = getDaoFood(); - List foods; - QueryBuilder queryBuilder = daoFood.queryBuilder(); - PreparedQuery preparedQuery = queryBuilder.prepare(); - foods = daoFood.query(preparedQuery); - return foods; - } catch (SQLException e) { - log.error("Unhandled exception", e); - } - return new ArrayList<>(); - } - - public boolean createOrUpdate(Food food) { - try { - // find by NS _id - if (food._id != null && !food._id.equals("")) { - Food old; - - QueryBuilder queryBuilder = getDaoFood().queryBuilder(); - Where where = queryBuilder.where(); - where.eq("_id", food._id); - PreparedQuery preparedQuery = queryBuilder.prepare(); - List found = getDaoFood().query(preparedQuery); - if (found.size() > 0) { - old = found.get(0); - if (!old.isEqual(food)) { - getDaoFood().delete(old); // need to delete/create because date may change too - old.copyFrom(food); - getDaoFood().create(old); - log.debug("FOOD: Updating record by _id: " + old.toString()); - scheduleFoodChange(); - return true; - } else { - return false; - } - } else { - getDaoFood().createOrUpdate(food); - log.debug("FOOD: New record: " + food.toString()); - scheduleFoodChange(); - return true; - } - } - } catch (SQLException e) { - log.error("Unhandled exception", e); - } - return false; - } - - public void delete(Food food) { - try { - getDaoFood().delete(food); - scheduleFoodChange(); - } catch (SQLException e) { - log.error("Unhandled exception", e); - } - } - - public static void scheduleFoodChange() { - class PostRunnable implements Runnable { - public void run() { - log.debug("Firing EventFoodChange"); - MainApp.bus().post(new EventFoodDatabaseChanged()); - scheduledFoodEventPost = null; - } - } - // prepare task for execution in 1 sec - // cancel waiting task to prevent sending multiple posts - if (scheduledFoodEventPost != null) - scheduledFoodEventPost.cancel(false); - Runnable task = new PostRunnable(); - final int sec = 1; - scheduledFoodEventPost = foodEventWorker.schedule(task, sec, TimeUnit.SECONDS); - - } - - /* - { - "_id": "551ee3ad368e06e80856e6a9", - "type": "food", - "category": "Zakladni", - "subcategory": "Napoje", - "name": "Mleko", - "portion": 250, - "carbs": 12, - "gi": 1, - "created_at": "2015-04-14T06:59:16.500Z", - "unit": "ml" - } - */ - public void createFoodFromJsonIfNotExists(JSONObject trJson) { - try { - Food food = new Food(); - if (trJson.has("type") && trJson.getString("type").equals("food")) { - if (trJson.has("_id")) - food._id = trJson.getString("_id"); - if (trJson.has("category")) - food.category = trJson.getString("category"); - if (trJson.has("subcategory")) - food.subcategory = trJson.getString("subcategory"); - if (trJson.has("name")) - food.name = trJson.getString("name"); - if (trJson.has("unit")) - food.units = trJson.getString("unit"); - if (trJson.has("portion")) - food.portion = trJson.getDouble("portion"); - if (trJson.has("carbs")) - food.carbs = trJson.getInt("carbs"); - if (trJson.has("gi")) - food.gi = trJson.getInt("gi"); - if (trJson.has("energy")) - food.energy = trJson.getInt("energy"); - if (trJson.has("protein")) - food.protein = trJson.getInt("protein"); - if (trJson.has("fat")) - food.fat = trJson.getInt("fat"); - } - createOrUpdate(food); - } catch (JSONException e) { - log.error("Unhandled exception", e); - } - } - - public void deleteFoodById(String _id) { - Food stored = findFoodById(_id); - if (stored != null) { - log.debug("FOOD: Removing Food record from database: " + stored.toString()); - delete(stored); - scheduleFoodChange(); - } - } - - public Food findFoodById(String _id) { - try { - QueryBuilder queryBuilder = getDaoFood().queryBuilder(); - Where where = queryBuilder.where(); - where.eq("_id", _id); - PreparedQuery preparedQuery = queryBuilder.prepare(); - List list = getDaoFood().query(preparedQuery); - - if (list.size() == 1) { - return list.get(0); - } else { - return null; - } - } catch (SQLException e) { - log.error("Unhandled exception", e); - } - return null; - } - -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Food/FoodFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Food/FoodFragment.java index a5c00aab7f..3f11663c43 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Food/FoodFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Food/FoodFragment.java @@ -121,7 +121,7 @@ public class FoodFragment extends SubscriberFragment { } }); - RecyclerViewAdapter adapter = new RecyclerViewAdapter(MainApp.getDbHelper().foodHelper.getFoodData()); + RecyclerViewAdapter adapter = new RecyclerViewAdapter(MainApp.getDbHelper().foodHelper.getDao().getFoodData()); recyclerView.setAdapter(adapter); loadData(); @@ -144,7 +144,7 @@ public class FoodFragment extends SubscriberFragment { } void loadData() { - unfiltered = MainApp.getDbHelper().foodHelper.getFoodData(); + unfiltered = MainApp.getDbHelper().foodHelper.getDao().getFoodData(); } void fillCategories() { @@ -299,7 +299,7 @@ public class FoodFragment extends SubscriberFragment { if (_id != null && !_id.equals("")) { NSUpload.removeFoodFromNS(_id); } - MainApp.getDbHelper().foodHelper.delete(food); + MainApp.getDbHelper().foodHelper.getDao().deleteFood(food); } }); builder.setNegativeButton(MainApp.sResources.getString(R.string.cancel), null); diff --git a/app/src/main/java/info/nightscout/utils/JsonHelper.java b/app/src/main/java/info/nightscout/utils/JsonHelper.java new file mode 100644 index 0000000000..5068b08671 --- /dev/null +++ b/app/src/main/java/info/nightscout/utils/JsonHelper.java @@ -0,0 +1,49 @@ +package info.nightscout.utils; + +import org.json.JSONException; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * JSonHelper is a Helper class which contains several methods to safely get data from the ggiven JSONObject. + * + * Created by triplem on 04.01.18. + */ + +public class JsonHelper { + + private static final Logger log = LoggerFactory.getLogger(JsonHelper.class); + + private JsonHelper() {}; + + public static String safeGetString(JSONObject json, String fieldName) throws JSONException { + String result = null; + + if (json.has(fieldName)) { + result = json.getString(fieldName); + } + + return result; + } + + public static double safeGetDouble(JSONObject json, String fieldName) throws JSONException { + double result = 0d; + + if (json.has(fieldName)) { + result = json.getDouble(fieldName); + } + + return result; + } + + public static int safeGetInt(JSONObject json, String fieldName) throws JSONException { + int result = 0; + + if (json.has(fieldName)) { + result = json.getInt(fieldName); + } + + return result; + } +}