package com.delect.motiver.server.dao;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.Transaction;
import org.datanucleus.store.appengine.query.JDOCursorHelper;
import com.delect.motiver.server.PMF;
import com.delect.motiver.server.dao.helper.MealSearchParams;
import com.delect.motiver.server.jdo.FoodNameCount;
import com.delect.motiver.server.jdo.UserOpenid;
import com.delect.motiver.server.jdo.nutrition.FoodJDO;
import com.delect.motiver.server.jdo.nutrition.FoodName;
import com.delect.motiver.server.jdo.nutrition.MealJDO;
import com.delect.motiver.server.jdo.nutrition.TimeJDO;
import com.delect.motiver.server.service.MyServiceImpl;
import com.delect.motiver.server.util.DateUtils;
import com.delect.motiver.shared.Constants;
import com.google.appengine.api.datastore.Cursor;
import com.google.appengine.api.datastore.Key;
import com.prodeagle.java.counters.Counter;
public class NutritionDAO {
/**
* Logger for this class
*/
private static final Logger logger = Logger.getLogger(NutritionDAO.class.getName());
private static NutritionDAO dao;
public static NutritionDAO getInstance() {
if(dao == null) {
dao = new NutritionDAO();
}
return dao;
}
@SuppressWarnings("unchecked")
public List<TimeJDO> getTimes(Date date, String uid) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading times ("+uid+", "+date+")");
}
//prodeagle counter
Counter.increment("DAO.Times");
List<TimeJDO> list = new ArrayList<TimeJDO>();
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
//strip time
final Date dStart = DateUtils.stripTime(date, true);
final Date dEnd = DateUtils.stripTime(date, false);
Query q = pm.newQuery(TimeJDO.class);
q.setFilter("openId == openIdParam && date >= dateStartParam && date <= dateEndParam");
q.declareParameters("java.lang.String openIdParam, java.util.Date dateStartParam, java.util.Date dateEndParam");
List<TimeJDO> times = (List<TimeJDO>) q.execute(uid, dStart, dEnd);
for(TimeJDO jdo : times) {
TimeJDO t = pm.detachCopy(jdo);
t.setMealsKeys(jdo.getMealsKeys());
t.setFoodsKeys(jdo.getFoodsKeys());
list.add(t);
}
} catch (Exception e) {
throw e;
}
finally {
if (!pm.isClosed()) {
pm.close();
}
}
return list;
}
@SuppressWarnings("unchecked")
public List<Long> getMeals(MealSearchParams params) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading meals: "+params);
}
List<Long> list = new ArrayList<Long>();
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
int c = 0;
while(true){
int offset = params.offset + c;
int limit = offset + (params.limit - c);
if(limit - offset > 100) {
limit = offset + 100;
}
limit++;
Query q = pm.newQuery(MealJDO.class);
q.setOrdering("name ASC");
StringBuilder builder = MyServiceImpl.getStringBuilder();
if(params.uid != null) {
builder.append("openId == openIdParam && ");
}
if(params.timeId != null) {
builder.append("timeId == timeParam");
}
else {
builder.append("timeId == null");
}
if(params.minCopyCount > 0) {
builder.append(" && copyCount >= copyCountParam");
q.setOrdering("copyCount DESC");
}
q.setFilter(builder.toString());
q.declareParameters("java.lang.String openIdParam, java.lang.Integer timeParam, java.lang.Integer copyCountParam");
q.setRange(offset, limit);
List<MealJDO> meals = (List<MealJDO>) q.execute(params.uid, params.timeId, params.minCopyCount);
//get meals
if(meals != null) {
for(MealJDO m : meals) {
//if limit reached -> add null value
if(list.size() >= params.limit) {
list.add(null);
break;
}
list.add(m.getId());
}
//if enough found or last query didn't return enough rows
if(list.size() >= params.limit || meals.size() < limit) {
break;
}
c+= 100;
}
else {
break;
}
}
} catch (Exception e) {
throw e;
}
finally {
if (!pm.isClosed()) {
pm.close();
}
}
return list;
}
public boolean removeTimes(Long[] keys, String uid) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Removing times: "+uid);
}
boolean ok = false;
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
for (Long key : keys) {
//try to update X times
int retries = Constants.LIMIT_UPDATE_RETRIES;
while (true) {
Transaction tx = pm.currentTransaction();
tx.begin();
try {
TimeJDO t = pm.getObjectById(TimeJDO.class, key);
if(t != null) {
pm.deletePersistent(t);
tx.commit();
ok = true;
break;
}
}
catch (Exception e) {
if (tx.isActive()) {
tx.rollback();
}
logger.log(Level.WARNING, "Error deleting time", e);
//retries used
if (retries == 0) {
throw e;
}
logger.log(Level.WARNING, " Retries left: "+retries);
--retries;
}
}
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error removing times", e);
}
finally {
if (!pm.isClosed()) {
pm.close();
}
}
return ok;
}
public void addTimes(List<TimeJDO> models) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Adding times: "+models);
}
PersistenceManager pm = PMF.get().getPersistenceManager();
Transaction tx = pm.currentTransaction();
try {
for(TimeJDO time : models) {
tx.begin();
pm.makePersistent(time);
tx.commit();
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error adding times", e);
}
finally {
if(tx.isActive()) {
tx.rollback();
}
if (!pm.isClosed()) {
pm.close();
}
}
}
public TimeJDO addMeals(Long timeId, List<MealJDO> models) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Adding meals to time: "+models);
}
TimeJDO t = null;
PersistenceManager pm = PMF.get().getPersistenceManager();
Transaction tx = null;
try {
//save meals
for(MealJDO meal : models) {
meal.setTime(timeId);
pm.makePersistent(meal);
}
pm.flush();
tx = pm.currentTransaction();
tx.begin();
TimeJDO jdo = pm.getObjectById(TimeJDO.class, timeId);
if(jdo != null) {
List<Key> arr = jdo.getMealsKeys();
for(MealJDO m : models) {
arr.add(m.getKey());
}
}
tx.commit();
//get detached copy
t = pm.detachCopy(jdo);
t.setMealsKeys(jdo.getMealsKeys());
t.setFoods(new ArrayList<FoodJDO>(pm.detachCopyAll(jdo.getFoods())));
} catch (Exception e) {
throw e;
}
finally {
if (!pm.isClosed()) {
pm.close();
}
}
return t;
}
public void addMeals(List<MealJDO> models) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Adding meals: "+models);
}
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
for(MealJDO meal : models) {
pm.makePersistent(meal);
}
} catch (Exception e) {
throw e;
}
finally {
if (!pm.isClosed()) {
pm.close();
}
}
}
public boolean removeMeal(MealJDO model) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Removing meal: "+model);
}
boolean ok = false;
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
//try to update X times
int retries = Constants.LIMIT_UPDATE_RETRIES;
while (true) {
Transaction tx = pm.currentTransaction();
tx.begin();
try {
MealJDO t = pm.getObjectById(MealJDO.class, model.getId());
if(t != null) {
pm.deletePersistent(t);
tx.commit();
ok = true;
break;
}
}
catch (Exception e) {
if (tx.isActive()) {
tx.rollback();
}
logger.log(Level.WARNING, "Error deleting meal", e);
//retries used
if (retries == 0) {
throw e;
}
logger.log(Level.WARNING, " Retries left: "+retries);
--retries;
}
}
} catch (Exception e) {
throw e;
}
finally {
if (!pm.isClosed()) {
pm.close();
}
}
return ok;
}
public boolean removeFood(FoodJDO model) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Removing food: "+model);
}
boolean ok = false;
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
//try to update X times
int retries = Constants.LIMIT_UPDATE_RETRIES;
while (true) {
Transaction tx = pm.currentTransaction();
tx.begin();
try {
FoodJDO t = pm.getObjectById(FoodJDO.class, model.getId());
if(t != null) {
pm.deletePersistent(t);
tx.commit();
ok = true;
break;
}
}
catch (Exception e) {
if (tx.isActive()) {
tx.rollback();
}
logger.log(Level.WARNING, "Error deleting food", e);
//retries used
if (retries == 0) {
throw e;
}
logger.log(Level.WARNING, " Retries left: "+retries);
--retries;
}
}
} catch (Exception e) {
throw e;
}
finally {
if (!pm.isClosed()) {
pm.close();
}
}
return ok;
}
public MealJDO getMeal(long mealId) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading meal for ID: "+mealId);
}
//prodeagle counter
Counter.increment("DAO.Meal");
MealJDO meal = null;
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
MealJDO jdo = pm.getObjectById(MealJDO.class, mealId);
if(jdo != null) {
meal = pm.detachCopy(jdo);
meal.setFoods(new ArrayList<FoodJDO>(pm.detachCopyAll(jdo.getFoods())));
}
} catch (Exception e) {
throw e;
}
finally {
if (!pm.isClosed()) {
pm.close();
}
}
return meal;
}
public TimeJDO getTime(long timeId) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading time for ID: "+timeId);
}
//prodeagle counter
Counter.increment("DAO.Time");
TimeJDO t = null;
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
t = pm.getObjectById(TimeJDO.class, timeId);
} catch (Exception e) {
throw e;
}
finally {
if (!pm.isClosed()) {
pm.close();
}
}
return t;
}
public void updateTime(TimeJDO time, boolean updateFoods) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Updating time: "+time);
}
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
//try to update X times
int retries = Constants.LIMIT_UPDATE_RETRIES;
while (true) {
Transaction tx = pm.currentTransaction();
tx.begin();
try {
TimeJDO t = pm.getObjectById(TimeJDO.class, time.getId());
if(t != null) {
t.update(time, false, updateFoods);
}
tx.commit();
time.getFoods();
break;
}
catch (Exception e) {
if (tx.isActive()) {
tx.rollback();
}
logger.log(Level.WARNING, "Error updating workout", e);
//retries used
if (retries == 0) {
throw e;
}
logger.log(Level.WARNING, " Retries left: "+retries);
--retries;
}
}
} catch (Exception e) {
throw e;
}
finally {
if (!pm.isClosed()) {
pm.close();
}
}
}
public void updateMeal(MealJDO meal, boolean updateFoods) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Updating meal: "+meal);
}
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
//try to update X times
int retries = Constants.LIMIT_UPDATE_RETRIES;
while (true) {
Transaction tx = pm.currentTransaction();
tx.begin();
try {
MealJDO t = pm.getObjectById(MealJDO.class, meal.getId());
if(t != null) {
int c = t.getCount();
t.update(meal, false, updateFoods);
//restore count
t.setCount(c);
pm.flush();
}
tx.commit();
meal.getFoods();
break;
}
catch (Exception e) {
if (tx.isActive()) {
tx.rollback();
}
logger.log(Level.WARNING, "Error updating workout", e);
//retries used
if (retries == 0) {
throw e;
}
logger.log(Level.WARNING, " Retries left: "+retries);
--retries;
}
}
} catch (Exception e) {
throw e;
}
finally {
if (!pm.isClosed()) {
pm.close();
}
}
}
public void incrementMealCount(MealJDO meal) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Incrementing count for: "+meal);
}
PersistenceManager pm = PMF.get().getPersistenceManager();
Transaction tx = pm.currentTransaction();
tx.begin();
try {
MealJDO t = pm.getObjectById(MealJDO.class, meal.getId());
if(t != null) {
t.setCount(t.getCount() + 1);
}
tx.commit();
meal.update(t, true, false);
} catch (Exception e) {
throw e;
}
finally {
if(tx.isActive()) {
tx.rollback();
}
if (!pm.isClosed()) {
pm.close();
}
}
}
@SuppressWarnings("unchecked")
public List<FoodName> getFoodNames(String locale) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading food names");
}
//prodeagle counter
Counter.increment("DAO.FoodNames");
PersistenceManager pm = PMF.get().getPersistenceManager();
List<FoodName> n = new ArrayList<FoodName>(1000);
try {
Cursor cursor = null;
Map<String, Object> extensionMap = new HashMap<String, Object>();
//get using cursors
while(true){
Query q = pm.newQuery(FoodName.class);
q.setFilter("locale == localeParam");
q.declareParameters("java.lang.String localeParam");
q.setRange(0, 700);
if(cursor != null) {
extensionMap.put(JDOCursorHelper.CURSOR_EXTENSION, cursor);
q.setExtensions(extensionMap);
}
List<FoodName> u = (List<FoodName>) q.execute(locale);
cursor = JDOCursorHelper.getCursor(u);
n.addAll(u);
if(u.size() == 0) {
break;
}
}
} catch (Exception e) {
throw e;
}
finally {
if (!pm.isClosed()) {
pm.close();
}
}
return n;
}
@SuppressWarnings("unchecked")
public int getFoodNameCount(UserOpenid user, Long id) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading food name ("+id+") count for "+user);
}
int count = -1;
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
Query qUse = pm.newQuery(FoodNameCount.class);
qUse.setFilter("nameId == nameIdParam && openId == openIdParam");
qUse.declareParameters("java.lang.Long nameIdParam, java.lang.String openIdParam");
qUse.setRange(0, 1);
List<FoodNameCount> valueCount = (List<FoodNameCount>) qUse.execute(id, user.getUid());
if(valueCount.size() > 0) {
count = valueCount.get(0).getCount();
}
if(count < 0) {
count = 0;
}
} catch (Exception e) {
throw e;
}
finally {
if (!pm.isClosed()) {
pm.close();
}
}
return count;
}
public void addFoodName(FoodName name) {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Adding food name: "+name);
}
//prodeagle counter
Counter.increment("DAO.FoodName.New");
PersistenceManager pm = PMF.get().getPersistenceManager();
Transaction tx = pm.currentTransaction();
tx.begin();
try {
pm.makePersistent(name);
tx.commit();
} catch (Exception e) {
logger.log(Level.SEVERE, "Error adding food name", e);
}
finally {
if(tx.isActive()) {
tx.rollback();
}
if (!pm.isClosed()) {
pm.close();
}
}
}
/**
* Returns foods based on given keys
* @param keys
* @return
*/
public List<FoodJDO> getFoods(List<Key> keys) {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading foods: "+keys);
}
if(keys.size() == 0) {
return null;
}
List<FoodJDO> list = null;
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
Query q = pm.newQuery("select from " + FoodJDO.class.getName() + " where id == :keys");
list = new ArrayList<FoodJDO>(pm.detachCopyAll((List<FoodJDO>)q.execute(keys)));
} catch (Exception e) {
logger.log(Level.SEVERE, "Error loading foods", e);
}
finally {
if (!pm.isClosed()) {
pm.close();
}
}
return list;
}
public void addFood(FoodJDO model) {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Adding/updating food: "+model);
}
PersistenceManager pm = PMF.get().getPersistenceManager();
Transaction tx = pm.currentTransaction();
tx.begin();
try {
pm.makePersistent(model);
tx.commit();
} catch (Exception e) {
logger.log(Level.SEVERE, "Error adding food", e);
}
finally {
if(tx.isActive()) {
tx.rollback();
}
if (!pm.isClosed()) {
pm.close();
}
}
}
public void updateFoodName(FoodName name) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Updating foodname: "+name);
}
PersistenceManager pm = PMF.get().getPersistenceManager();
Transaction tx = pm.currentTransaction();
tx.begin();
try {
FoodName t = pm.getObjectById(FoodName.class, name.getId());
if(t != null) {
t.update(name, false);
}
tx.commit();
} catch (Exception e) {
throw e;
}
finally {
if(tx.isActive()) {
tx.rollback();
}
if (!pm.isClosed()) {
pm.close();
}
}
}
public FoodName getFoodName(Long key) throws Exception {
if(logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, "Loading food name for ID: "+key);
}
Counter.increment("DAO.FoodName");
FoodName n = null;
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
n = pm.getObjectById(FoodName.class, key);
} catch (Exception e) {
throw e;
}
finally {
if (!pm.isClosed()) {
pm.close();
}
}
return n;
}
}