Java tutorial
/* * Copyright 2011 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package com.pacoapp.paco.model; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.JsonParseException; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.node.ArrayNode; import org.codehaus.jackson.type.TypeReference; import org.joda.time.DateMidnight; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.util.Log; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.pacoapp.paco.PacoConstants; import com.pacoapp.paco.UserPreferences; import com.pacoapp.paco.shared.model2.ActionTrigger; import com.pacoapp.paco.shared.model2.EventInterface; import com.pacoapp.paco.shared.model2.EventStore; import com.pacoapp.paco.shared.model2.ExperimentDAO; import com.pacoapp.paco.shared.model2.ExperimentGroup; import com.pacoapp.paco.shared.model2.ExperimentValidator; import com.pacoapp.paco.shared.model2.Input2; import com.pacoapp.paco.shared.model2.InterruptCue; import com.pacoapp.paco.shared.model2.JsonConverter; import com.pacoapp.paco.shared.model2.PacoAction; import com.pacoapp.paco.shared.model2.PacoNotificationAction; import com.pacoapp.paco.shared.model2.Schedule; import com.pacoapp.paco.shared.model2.ScheduleTrigger; import com.pacoapp.paco.shared.model2.ValidationMessage; import com.pacoapp.paco.shared.scheduling.ActionScheduleGenerator; import com.pacoapp.paco.shared.util.TimeUtil; public class ExperimentProviderUtil implements EventStore { private Context context; private ContentResolver contentResolver; public static final String AUTHORITY = "com.google.android.apps.paco.ExperimentProvider"; private static final String PUBLIC_EXPERIMENTS_FILENAME = "experiments"; private static final String MY_EXPERIMENTS_FILENAME = "my_experiments"; DateTimeFormatter endDateFormatter = DateTimeFormat.forPattern(TimeUtil.DATE_FORMAT); public ExperimentProviderUtil(Context context) { super(); this.context = context; if (context == null) { throw new IllegalArgumentException("Need a context to instantiate experimentproviderutil"); } this.contentResolver = context.getContentResolver(); } public List<Experiment> getJoinedExperiments() { List<Experiment> cachedExperiments = JoinedExperimentCache.getInstance().getExperiments(); if (cachedExperiments.size() > 0) { return cachedExperiments; } final List<Experiment> foundExperiments = findExperimentsBy(null, ExperimentColumns.JOINED_EXPERIMENTS_CONTENT_URI); if (foundExperiments != null && foundExperiments.size() > 0) { JoinedExperimentCache.getInstance().insertExperiments(foundExperiments); } return foundExperiments; } public List<Long> getJoinedExperimentServerIds() { List<Experiment> joinedExperiments = getJoinedExperiments(); List<Experiment> stillRunningExperiments = Lists.newArrayList(); DateMidnight tonightMidnight = new DateMidnight().plusDays(1); DateTime now = DateTime.now(); for (Experiment experiment : joinedExperiments) { final ExperimentDAO experimentDAO = experiment.getExperimentDAO(); if (experimentDAO != null && !ActionScheduleGenerator.isOver(now, experimentDAO)) { stillRunningExperiments.add(experiment); } } List<Long> experimentIds = Lists.transform(stillRunningExperiments, new Function<Experiment, Long>() { public Long apply(Experiment experiment) { return experiment.getServerId(); } }); return experimentIds; } private boolean isJoinedExperimentAndroidId(long id) { String select = ExperimentColumns._ID + "=" + id; Cursor cursor = null; try { cursor = contentResolver.query(ExperimentColumns.CONTENT_URI, null, select, null, null); if (cursor != null && cursor.moveToNext()) { return true; } } catch (RuntimeException e) { Log.w(ExperimentProvider.TAG, "Caught unexpected exception.", e); } finally { if (cursor != null) { cursor.close(); } } return false; } public List<Experiment> getExperimentsByServerId(long id) { List<Experiment> cachedExperiments = JoinedExperimentCache.getInstance().getExperimentsByServerId(id); if (cachedExperiments.size() > 0) { return cachedExperiments; } String select = ExperimentColumns.SERVER_ID + "=" + id; final List<Experiment> foundExperiments = findExperimentsBy(select, ExperimentColumns.CONTENT_URI); if (foundExperiments != null && foundExperiments.size() > 0) { JoinedExperimentCache.getInstance().insertExperiments(foundExperiments); } return foundExperiments; } public Experiment getExperimentByServerId(long id) { Experiment cachedExperiment = JoinedExperimentCache.getInstance().getExperimentByServerId(id); if (cachedExperiment != null) { return cachedExperiment; } String select = ExperimentColumns.SERVER_ID + "=" + id; final Experiment foundExperiment = findExperimentBy(select, ExperimentColumns.CONTENT_URI); if (foundExperiment != null) { JoinedExperimentCache.getInstance().insertExperiment(foundExperiment); } return foundExperiment; } private Uri insertExperiment(Experiment experiment) { final Uri returnedUri = contentResolver.insert(ExperimentColumns.CONTENT_URI, createContentValues(experiment)); long rowId = Long.parseLong(returnedUri.getLastPathSegment()); experiment.setId(rowId); JoinedExperimentCache.getInstance().insertExperiment(experiment); return returnedUri; } /** * This operation takes a default experiment from the server, * and clones it to created an experiment record that represents * an experiment the user has joined. This ensures that even if the * experiment is no longer available on the server, or is updated for * future users, it remains the same for this user by default. * Future work could ask them if they want to upgrade their * joined experiment to a new version of the experiment on the * server, but that is out of scope for now. * @param experiment * @return */ public Uri insertFullJoinedExperiment(Experiment experiment) { setJoinDateOnSchedules(experiment); return insertExperiment(experiment); } private void setJoinDateOnSchedules(Experiment experiment) { long joinDateMillis = getJoinDateMillis(experiment); for (ExperimentGroup experimentGroup : experiment.getExperimentDAO().getGroups()) { List<ActionTrigger> actionTriggers = experimentGroup.getActionTriggers(); for (ActionTrigger actionTrigger : actionTriggers) { if (actionTrigger instanceof ScheduleTrigger) { ScheduleTrigger scheduleTrigger = (ScheduleTrigger) actionTrigger; List<Schedule> schedules = scheduleTrigger.getSchedules(); for (Schedule schedule : schedules) { schedule.setJoinDateMillis(joinDateMillis); } } } } } private Long getJoinDateMillis(Experiment experiment) { return TimeUtil.unformatDateWithZone(experiment.getJoinDate()).getMillis(); } // For testing public Uri insertFullJoinedExperiment(String contentAsString) throws JsonParseException, JsonMappingException, IOException { Experiment experiment = getSingleExperimentFromJson(contentAsString); experiment.setJoinDate(TimeUtil.formatDateWithZone(new DateTime())); return insertFullJoinedExperiment(experiment); } /** * This uses the Android ContentProvider id for the joined experiment * @param experimentId */ public void deleteExperiment(long experimentId) { if (isJoinedExperimentAndroidId(experimentId)) { String[] selectionArgs = new String[] { Long.toString(experimentId) }; contentResolver.delete(ExperimentColumns.CONTENT_URI, "_id = ?", selectionArgs); JoinedExperimentCache.getInstance().deleteExperiment(experimentId); } } /** * This is used by refresh downloaders only * * @param contentAsString * @throws JsonParseException * @throws JsonMappingException * @throws IOException */ public void updateExistingExperiments(String contentAsString) throws JsonParseException, JsonMappingException, IOException { Map<String, Object> results = fromEntitiesJson(contentAsString); List<Experiment> experimentList = (List<Experiment>) results.get("results"); updateExistingExperiments(experimentList, false); } /** * Used when refreshing experiment list from the server. * If the experiment server id is already in the database, * then update it, otherwise, add it. * @param experimentList * @param shouldOverrideExistingSettings downloaded (refreshed experiments should not override certain * local properties. Locally modified experiments should override local properties, e.g., logActions. */ public void updateExistingExperiments(List<Experiment> newExperimentDefinitions, Boolean shouldOverrideExistingSettings) { for (Experiment experiment : newExperimentDefinitions) { List<Experiment> existingList = getExperimentsByServerId(experiment.getServerId()); if (existingList.size() == 0) { continue; } for (Experiment existingExperiment : existingList) { // should become only 1 element if we prevent joining experiments multiple times copyAllPropertiesToExistingJoinedExperiment(experiment, existingExperiment, shouldOverrideExistingSettings); updateJoinedExperiment(existingExperiment); } } } private void copyAllPropertiesToExistingJoinedExperiment(Experiment newExperiment, Experiment existingExperiment, Boolean shouldOverrideExistingSettings) { UserPreferences userPrefs = new UserPreferences(context); if (shouldOverrideExistingSettings || !userPrefs.experimentEdited(existingExperiment.getId())) { ExperimentDAO newExperimentDAO = newExperiment.getExperimentDAO(); ExperimentDAO existingDAO = existingExperiment.getExperimentDAO(); // TODO preserve any modified schedule settings if it is user-editable and different from the new existingExperiment.setExperimentDAO(newExperimentDAO); } } public void updateJoinedExperiment(Experiment experiment) { long t1 = System.currentTimeMillis(); int count = contentResolver.update(ExperimentColumns.JOINED_EXPERIMENTS_CONTENT_URI, createContentValues(experiment), ExperimentColumns._ID + "=" + experiment.getId(), null); JoinedExperimentCache.getInstance().insertExperiment(experiment); Log.i(ExperimentProviderUtil.class.getSimpleName(), " updated " + count + " rows. Time: " + (System.currentTimeMillis() - t1)); } public void deleteAllExperiments() { contentResolver.delete(ExperimentColumns.JOINED_EXPERIMENTS_CONTENT_URI, null, null); JoinedExperimentCache.getInstance().deleteAllExperiments(); } private Experiment findExperimentBy(String select, Uri contentUri) { Cursor cursor = null; try { cursor = contentResolver.query(contentUri, null, select, null, null); if (cursor != null && cursor.moveToNext()) { Experiment experiment = createExperiment(cursor); return experiment; } } catch (RuntimeException e) { Log.w(ExperimentProvider.TAG, "Caught unexpected exception.", e); } finally { if (cursor != null) { cursor.close(); } } return null; } private List<Experiment> findExperimentsBy(String select, Uri contentUri) { List<Experiment> experiments = new ArrayList<Experiment>(); Cursor cursor = null; try { cursor = contentResolver.query(contentUri, null, select, null, null); if (cursor != null) { while (cursor.moveToNext()) { Experiment experiment = createExperiment(cursor); experiments.add(experiment); } } } catch (RuntimeException e) { Log.w(ExperimentProvider.TAG, "Caught unexpected exception.", e); } finally { if (cursor != null) { cursor.close(); } } return experiments; } /** This converts the old version of json (db == 22) to the new model * * @param experimentDAO * @param jsonOfExperiment * @throws JsonProcessingException * @throws IOException */ public static void copyAllPropertiesFromJsonToExperimentDAO(ExperimentDAO experimentDAO, String jsonOfExperiment) throws JsonProcessingException, IOException { ObjectMapper mapper = JsonConverter.getObjectMapper(); JsonNode rootNode = mapper.readTree(jsonOfExperiment); if (rootNode.has("id")) { experimentDAO.setId(rootNode.path("id").getLongValue()); } if (rootNode.has("title")) { experimentDAO.setTitle(rootNode.path("title").getTextValue()); } if (rootNode.has("description")) { experimentDAO.setCreator(rootNode.path("description").getTextValue()); } if (rootNode.has("creator")) { experimentDAO.setCreator(rootNode.path("creator").getTextValue()); experimentDAO.setContactEmail(rootNode.path("creator").getTextValue()); } if (rootNode.has("contactEmail")) { experimentDAO.setContactEmail(rootNode.path("contactEmail").getTextValue()); } if (!rootNode.has("creator") && !rootNode.has("contactEmail")) { experimentDAO.setContactEmail(rootNode.path("").getTextValue()); } if (rootNode.has("modifyDate")) { experimentDAO.setModifyDate(rootNode.path("modifyDate").getTextValue()); } if (rootNode.has("version")) { experimentDAO.setVersion(rootNode.path("version").getIntValue()); } if (rootNode.has("joinDate")) { experimentDAO.setJoinDate(rootNode.path("joinDate").getTextValue()); } if (rootNode.has("informedConsentForm")) { experimentDAO.setInformedConsentForm(rootNode.path("informedConsent").getTextValue()); } if (rootNode.has("recordPhoneDetails")) { experimentDAO.setRecordPhoneDetails(rootNode.path("recordPhoneDetails").getBooleanValue()); } if (rootNode.has("deleted")) { experimentDAO.setDeleted(rootNode.path("deleted").getBooleanValue()); } if (rootNode.has("extraDataCollectionDeclarations")) { List<Integer> edcd = Lists.newArrayList(); List<JsonNode> edcdNodes = rootNode.findValues("extraDataCollectionDeclarations"); for (JsonNode edcdNode : edcdNodes) { edcd.add(edcdNode.getIntValue()); } experimentDAO.setExtraDataCollectionDeclarations(edcd); } List<String> admins = Lists.newArrayList(); List<JsonNode> adminNodes = rootNode.findValues("admins"); for (JsonNode adminNode : adminNodes) { admins.add(adminNode.getTextValue()); } experimentDAO.setAdmins(admins); if (rootNode.has("published")) { experimentDAO.setPublished(rootNode.path("published").getBooleanValue()); } List<String> publishedList = Lists.newArrayList(); List<JsonNode> publishedListNodes = rootNode.findValues("publishedUsers"); for (JsonNode publishedListNode : publishedListNodes) { publishedList.add(publishedListNode.getTextValue()); } experimentDAO.setPublishedUsers(publishedList); ExperimentGroup defaultExperimentGroup = new ExperimentGroup(); defaultExperimentGroup.setName("default"); experimentDAO.getGroups().add(defaultExperimentGroup); if (rootNode.has("endDate")) { defaultExperimentGroup.setEndDate(rootNode.path("endDate").getTextValue()); } if (rootNode.has("startDate")) { defaultExperimentGroup.setEndDate(rootNode.path("startDate").getTextValue()); } if (rootNode.has("fixedDuration")) { defaultExperimentGroup.setFixedDuration(rootNode.path("fixedDuration").getBooleanValue()); } // experimentDAO.setWebRecommended(experiment.isWebRecommended()); // maybe blow up on webrecommended to let them know to unjoin and rejoin // TODO figure out how to handle this. if (rootNode.has("customRendering")) { defaultExperimentGroup.setCustomRendering(rootNode.path("customRendering").getBooleanValue()); } if (rootNode.has("customRenderingCode")) { defaultExperimentGroup.setCustomRenderingCode(rootNode.path("customRenderingCode").getTextValue()); } if (rootNode.has("feedbackType")) { //see feedback section below defaultExperimentGroup.setFeedbackType(rootNode.path("feedbackType").getIntValue()); } if (rootNode.has("logActions")) { defaultExperimentGroup.setLogActions(rootNode.path("logActions").getBooleanValue()); } if (rootNode.has("logShutdown")) { defaultExperimentGroup.setLogShutdown(rootNode.path("logShutdown").getBooleanValue()); } if (rootNode.has("backgroundListen")) { defaultExperimentGroup.setBackgroundListen(rootNode.path("backgroundListen").getBooleanValue()); } if (rootNode.has("backgroundListenSourceIdentifier")) { defaultExperimentGroup.setBackgroundListenSourceIdentifier( rootNode.path("backgroundListenSourceIdentifier").getTextValue()); } if (rootNode.has("inputs")) { List<Input2> inputs = Lists.newArrayList(); ArrayNode inputsNode = (ArrayNode) rootNode.path("inputs"); for (int i = 0; i < inputsNode.size(); i++) { JsonNode inputNode = inputsNode.get(i); Input2 input = new Input2(); inputs.add(input); if (inputNode.has("name")) { input.setName(inputNode.path("name").getTextValue()); } if (inputNode.has("required")) { input.setRequired(inputNode.path("required").getBooleanValue()); } if (inputNode.has("mandatory")) { input.setRequired(inputNode.path("mandatory").getBooleanValue()); } if (inputNode.has("conditional")) { input.setConditional(inputNode.path("conditional").getBooleanValue()); } if (inputNode.has("conditionExpression")) { input.setConditionExpression(inputNode.path("conditionExpression").getTextValue()); } if (inputNode.has("responseType")) { input.setResponseType(inputNode.path("responseType").getTextValue()); } if (inputNode.has("text")) { input.setText(inputNode.path("text").getTextValue()); } if (inputNode.has("likertSteps")) { input.setLikertSteps(inputNode.path("likertSteps").getIntValue()); } if (inputNode.has("leftSideLabel")) { input.setLeftSideLabel(inputNode.path("leftSideLabel").getTextValue()); } if (inputNode.has("rightSideLabel")) { input.setRightSideLabel(inputNode.path("rightSideLabel").getTextValue()); } if (inputNode.has("multiselect")) { input.setMultiselect(inputNode.path("multiselect").getBooleanValue()); } List<String> listChoices = Lists.newArrayList(); ArrayNode listChoicesNode = (ArrayNode) inputNode.path("listChoices"); for (int l = 0; l < listChoicesNode.size(); l++) { JsonNode listChoiceNode = listChoicesNode.get(l); listChoices.add(listChoiceNode.getTextValue()); } input.setListChoices(listChoices); } defaultExperimentGroup.setInputs(inputs); } //signaling mechanisms if (rootNode.has("signalingMechanisms")) { List<ActionTrigger> actionTriggers = defaultExperimentGroup.getActionTriggers(); ArrayNode signalingMechanismNodes = (ArrayNode) rootNode.path("signalingMechanisms"); for (int k = 0; k < signalingMechanismNodes.size(); k++) { JsonNode signalingMechanismNode = signalingMechanismNodes.get(k); if (signalingMechanismNode.has("type")) { String type = signalingMechanismNode.path("type").getTextValue(); PacoNotificationAction defaultAction = new PacoNotificationAction(); defaultAction.setActionCode(PacoAction.NOTIFICATION_TO_PARTICIPATE_ACTION_CODE); defaultAction.setId(1l); if (type.equals("signalSchedule")) { com.pacoapp.paco.shared.model2.ScheduleTrigger trigger = new com.pacoapp.paco.shared.model2.ScheduleTrigger(); trigger.setId(1l); trigger.getActions().add(defaultAction); com.pacoapp.paco.shared.model2.Schedule schedule = new com.pacoapp.paco.shared.model2.Schedule(); schedule.setId(1l); defaultAction.setSnoozeCount(signalingMechanismNode.path("snoozeCount").getIntValue()); defaultAction.setSnoozeTime(signalingMechanismNode.path("snoozeTime").getIntValue()); defaultAction.setTimeout(signalingMechanismNode.path("timeout").getIntValue()); schedule.setScheduleType(signalingMechanismNode.path("scheduleType").getIntValue()); schedule.setEsmFrequency(signalingMechanismNode.path("esmFrequency").getIntValue()); schedule.setEsmPeriodInDays(signalingMechanismNode.path("esmPeriodInDays").getIntValue()); schedule.setEsmStartHour(signalingMechanismNode.path("esmStartHour").getLongValue()); schedule.setEsmEndHour(signalingMechanismNode.path("esmEndHour").getLongValue()); schedule.setRepeatRate(signalingMechanismNode.path("repeatRate").getIntValue()); schedule.setWeekDaysScheduled( signalingMechanismNode.path("weekdaysScheduled").getIntValue()); schedule.setNthOfMonth(signalingMechanismNode.path("nthOfMonth").getIntValue()); schedule.setByDayOfMonth(signalingMechanismNode.path("byDayOfMonth").getBooleanValue()); schedule.setDayOfMonth(signalingMechanismNode.path("dayOfMonth").getIntValue()); schedule.setEsmWeekends(signalingMechanismNode.path("esmWeekends").getBooleanValue()); schedule.setMinimumBuffer(signalingMechanismNode.path("minimumBuffer").getIntValue()); schedule.setUserEditable(signalingMechanismNode.path("userEditable").getBooleanValue()); schedule.setOnlyEditableOnJoin( signalingMechanismNode.path("onlyEditableOnJoin").getBooleanValue()); List<com.pacoapp.paco.shared.model2.SignalTime> signalTimes = schedule.getSignalTimes(); if (signalingMechanismNode.has("signalTimes")) { ArrayNode signalTimeNodes = (ArrayNode) signalingMechanismNode.path("signalTimes"); for (int l = 0; l < signalTimeNodes.size(); l++) { JsonNode signalTimeNode = signalTimeNodes.get(l); com.pacoapp.paco.shared.model2.SignalTime newSt = new com.pacoapp.paco.shared.model2.SignalTime(); newSt.setType(signalTimeNode.path("type").getIntValue()); newSt.setFixedTimeMillisFromMidnight( signalTimeNode.path("fixedTimeMillisFromMidnight").getIntValue()); newSt.setBasis(signalTimeNode.path("basis").getIntValue()); newSt.setOffsetTimeMillis(signalTimeNode.path("offsetTimeMillis").getIntValue()); newSt.setLabel(signalTimeNode.path("label").getTextValue()); newSt.setMissedBasisBehavior( signalTimeNode.path("missedBasisBehavior").getIntValue()); schedule.getSignalTimes().add(newSt); } } trigger.getSchedules().add(schedule); actionTriggers.add(trigger); } else if (type.equals("trigger")) { com.pacoapp.paco.shared.model2.InterruptTrigger trigger = new com.pacoapp.paco.shared.model2.InterruptTrigger(); trigger.setId(1l); trigger.getActions().add(defaultAction); defaultAction.setSnoozeCount(signalingMechanismNode.path("snoozeCount").getIntValue()); defaultAction.setSnoozeTime(signalingMechanismNode.path("snoozeTime").getIntValue()); defaultAction.setTimeout(signalingMechanismNode.path("timeout").getIntValue()); trigger.setMinimumBuffer(signalingMechanismNode.path("minimumBuffer").getIntValue()); InterruptCue cue = new InterruptCue(); cue.setId(1l); if (signalingMechanismNode.has("eventCode")) { cue.setCueCode(signalingMechanismNode.path("eventCode").getIntValue()); } if (signalingMechanismNode.has("delay")) { defaultAction.setDelay(signalingMechanismNode.path("delay").getIntValue()); } if (signalingMechanismNode.has("sourceIdentifier")) { cue.setCueSource(signalingMechanismNode.path("sourceIdentifier").getTextValue()); } trigger.getCues().add(cue); actionTriggers.add(trigger); } } } } com.pacoapp.paco.shared.model2.Feedback f = new com.pacoapp.paco.shared.model2.Feedback(); if (rootNode.has("feedback")) { ArrayNode feedbackNodes = (ArrayNode) rootNode.path("feedback"); JsonNode feedbackNode = feedbackNodes.get(0); if (feedbackNode.has("text")) { f.setText(feedbackNode.path("text").getTextValue()); } } if (rootNode.has("feedbackType")) { f.setType(rootNode.path("feedbackType").getIntValue()); } defaultExperimentGroup.setFeedback(f); ExperimentValidator validator = new ExperimentValidator(); experimentDAO.validateWith(validator); List<ValidationMessage> results = validator.getResults(); if (!results.isEmpty()) { if (results.size() == 1 && results.get(0).getMsg().equals("admins should be a valid list of email addresses")) { return; // OK to not have admins } else { Log.e(PacoConstants.TAG, "error migrating experiment: " + experimentDAO.getId() + ":\n" + Joiner.on(",").join(results)); } } } static Experiment createExperiment(Cursor cursor) { int idIndex = cursor.getColumnIndex(ExperimentColumns._ID); int jsonIndex = cursor.getColumnIndex(ExperimentColumns.JSON); if (!cursor.isNull(jsonIndex)) { String jsonOfExperiment = cursor.getString(jsonIndex); try { long t1 = System.currentTimeMillis(); Experiment experiment = ExperimentProviderUtil.getSingleExperimentFromJson(jsonOfExperiment); if (experiment.getId() == null) { if (!cursor.isNull(idIndex)) { experiment.setId(cursor.getLong(idIndex)); } } Log.e(PacoConstants.TAG, "time to de-jsonify experiment (bytes: " + jsonOfExperiment.getBytes().length + ") : " + (System.currentTimeMillis() - t1)); return experiment; } catch (JsonParseException e) { e.printStackTrace(); } catch (JsonMappingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } return null; } static ContentValues createContentValues(Experiment experiment) { ContentValues values = new ContentValues(); // Values id < 0 indicate no id is available: if (experiment.getId() != null) { values.put(ExperimentColumns._ID, experiment.getId()); } if (experiment.getServerId() != null) { values.put(ExperimentColumns.SERVER_ID, experiment.getServerId()); } if (experiment.getExperimentDAO().getTitle() != null) { values.put(ExperimentColumns.TITLE, experiment.getExperimentDAO().getTitle()); } if (experiment.getJoinDate() != null) { values.put(ExperimentColumns.JOIN_DATE, experiment.getJoinDate()); } else if (experiment.getExperimentDAO().getJoinDate() != null) { values.put(ExperimentColumns.JOIN_DATE, experiment.getExperimentDAO().getJoinDate()); } long t1 = System.currentTimeMillis(); String json = getJson(experiment); Log.e(PacoConstants.TAG, "time to jsonify experiment (bytes: " + json.getBytes().length + "): " + (System.currentTimeMillis() - t1)); values.put(ExperimentColumns.JSON, json); return values; } // Visible for testing public List<String> getJsonList(List<Experiment> experiments) { List<String> experimentJsons = Lists.newArrayList(); for (Experiment experiment : experiments) { experimentJsons.add(getJson(experiment)); } return experimentJsons; } public static String getJson(Experiment experiment) { ObjectMapper mapper = JsonConverter.getObjectMapper(); try { return mapper.writeValueAsString(experiment); } catch (JsonGenerationException e) { Log.e(PacoConstants.TAG, "Json generation error " + e); } catch (JsonMappingException e) { Log.e(PacoConstants.TAG, "JsonMapping error getting experiment json: " + e.getMessage()); } catch (IOException e) { Log.e(PacoConstants.TAG, "IO error getting experiment: " + e.getMessage()); } return null; } public static String getJson(List<Experiment> experiments) { ObjectMapper mapper = JsonConverter.getObjectMapper(); try { return mapper.writeValueAsString(experiments); } catch (JsonGenerationException e) { Log.e(PacoConstants.TAG, "Json generation error " + e); } catch (JsonMappingException e) { Log.e(PacoConstants.TAG, "JsonMapping error getting experiment json: " + e.getMessage()); } catch (IOException e) { Log.e(PacoConstants.TAG, "IO error getting experiment: " + e.getMessage()); } return null; } public void loadEventsForExperiment(Experiment experiment) { List<Event> eventSingleEntryList = findEventsBy(EventColumns.EXPERIMENT_ID + "=" + experiment.getId(), EventColumns._ID + " DESC"); experiment.setEvents(eventSingleEntryList); } public List<Event> loadEventsForExperimentByServerId(Long serverId) { return findEventsBy(EventColumns.EXPERIMENT_SERVER_ID + " = " + Long.toString(serverId), EventColumns._ID + " DESC"); } public Uri insertEvent(Event event) { Uri uri = contentResolver.insert(EventColumns.CONTENT_URI, createContentValues(event)); long rowId = Long.parseLong(uri.getLastPathSegment()); event.setId(rowId); for (Output response : event.getResponses()) { response.setEventId(rowId); insertResponse(response); } return uri; } public void insertEvent(EventInterface eventI) { if (eventI instanceof Event) { Event event = (Event) eventI; insertEvent(event); } } private ContentValues createContentValues(Event event) { ContentValues values = new ContentValues(); if (event.getId() >= 0) { values.put(EventColumns._ID, event.getId()); } if (event.getExperimentId() >= 0) { values.put(EventColumns.EXPERIMENT_ID, event.getExperimentId()); } if (event.getExperimentServerId() >= 0) { values.put(EventColumns.EXPERIMENT_SERVER_ID, event.getExperimentServerId()); } if (event.getExperimentVersion() != null) { values.put(EventColumns.EXPERIMENT_VERSION, event.getExperimentVersion()); } if (event.getExperimentName() != null) { values.put(EventColumns.EXPERIMENT_NAME, event.getExperimentName()); } if (event.getScheduledTime() != null) { values.put(EventColumns.SCHEDULE_TIME, event.getScheduledTime().getMillis()); } if (event.getResponseTime() != null) { values.put(EventColumns.RESPONSE_TIME, event.getResponseTime().getMillis()); } if (event.getExperimentGroupName() != null) { values.put(EventColumns.GROUP_NAME, event.getExperimentGroupName()); } if (event.getActionTriggerId() != null) { values.put(EventColumns.ACTION_TRIGGER_ID, event.getActionTriggerId()); } if (event.getActionTriggerSpecId() != null) { values.put(EventColumns.ACTION_TRIGGER_SPEC_ID, event.getActionTriggerSpecId()); } if (event.getActionId() != null) { values.put(EventColumns.ACTION_ID, event.getActionId()); } values.put(EventColumns.UPLOADED, event.isUploaded() ? 1 : 0); return values; } private Uri insertResponse(Output response) { return contentResolver.insert(OutputColumns.CONTENT_URI, createContentValues(response)); } private ContentValues createContentValues(Output response) { ContentValues values = new ContentValues(); if (response.getId() >= 0) { values.put(OutputColumns._ID, response.getId()); } if (response.getEventId() >= 0) { values.put(OutputColumns.EVENT_ID, response.getEventId()); } if (response.getAnswer() != null) { values.put(OutputColumns.ANSWER, response.getAnswer()); } if (response.getName() != null) { values.put(OutputColumns.NAME, response.getName()); } return values; } private Event findEventBy(String select, String[] selectionArgs, String sortOrder) { Cursor cursor = null; try { cursor = contentResolver.query(EventColumns.CONTENT_URI, null, select, selectionArgs, sortOrder); if (cursor != null && cursor.moveToNext()) { Event event = createEvent(cursor); event.setResponses(findResponsesFor(event)); return event; } } catch (RuntimeException e) { Log.w(ExperimentProvider.TAG, "Caught unexpected exception.", e); } finally { if (cursor != null) { cursor.close(); } } return null; } private List<Event> findEventsBy(String select, String sortOrder) { List<Event> events = new ArrayList<Event>(); Cursor cursor = null; try { cursor = contentResolver.query(EventColumns.CONTENT_URI, null, select, null, sortOrder); if (cursor != null) { while (cursor.moveToNext()) { Event event = createEvent(cursor); event.setResponses(findResponsesFor(event)); events.add(event); } } return events; } catch (RuntimeException e) { Log.w(ExperimentProvider.TAG, "Caught unexpected exception.", e); } finally { if (cursor != null) { cursor.close(); } } return events; } private List<Output> findResponsesFor(Event event) { List<Output> responses = new ArrayList<Output>(); Cursor cursor = null; try { cursor = contentResolver.query(OutputColumns.CONTENT_URI, null, OutputColumns.EVENT_ID + "=" + event.getId(), null, OutputColumns.INPUT_SERVER_ID + " ASC"); // TODO (bobevans) module the conditional questions, this ordering should be OK to get questions in order. if (cursor != null) { while (cursor.moveToNext()) { responses.add(createResponse(cursor)); } } } catch (RuntimeException e) { Log.w(ExperimentProvider.TAG, "Caught unexpected exception.", e); } finally { if (cursor != null) { cursor.close(); } } return responses; } private Event createEvent(Cursor cursor) { int idIndex = cursor.getColumnIndexOrThrow(EventColumns._ID); int experimentIdIndex = cursor.getColumnIndexOrThrow(EventColumns.EXPERIMENT_ID); int experimentServerIdIndex = cursor.getColumnIndex(EventColumns.EXPERIMENT_SERVER_ID); int experimentVersionIndex = cursor.getColumnIndex(EventColumns.EXPERIMENT_VERSION); int experimentNameIndex = cursor.getColumnIndex(EventColumns.EXPERIMENT_NAME); int scheduleTimeIndex = cursor.getColumnIndex(EventColumns.SCHEDULE_TIME); int responseTimeIndex = cursor.getColumnIndex(EventColumns.RESPONSE_TIME); int uploadedIndex = cursor.getColumnIndex(EventColumns.UPLOADED); int groupNameIndex = cursor.getColumnIndex(EventColumns.GROUP_NAME); int actionTriggerIndex = cursor.getColumnIndex(EventColumns.ACTION_TRIGGER_ID); int actionTriggerSpecIndex = cursor.getColumnIndex(EventColumns.ACTION_TRIGGER_SPEC_ID); int actionIdIndex = cursor.getColumnIndex(EventColumns.ACTION_ID); Event event = new Event(); if (!cursor.isNull(idIndex)) { event.setId(cursor.getLong(idIndex)); } if (!cursor.isNull(experimentIdIndex)) { event.setExperimentId(cursor.getLong(experimentIdIndex)); } if (!cursor.isNull(experimentServerIdIndex)) { event.setServerExperimentId(cursor.getLong(experimentServerIdIndex)); } if (!cursor.isNull(experimentVersionIndex)) { event.setExperimentVersion(cursor.getInt(experimentVersionIndex)); } if (!cursor.isNull(experimentNameIndex)) { event.setExperimentName(cursor.getString(experimentNameIndex)); } if (!cursor.isNull(responseTimeIndex)) { event.setResponseTime(new DateTime(cursor.getLong(responseTimeIndex))); } if (!cursor.isNull(scheduleTimeIndex)) { event.setScheduledTime(new DateTime(cursor.getLong(scheduleTimeIndex))); } if (!cursor.isNull(uploadedIndex)) { event.setUploaded(cursor.getInt(uploadedIndex) == 1); } if (!cursor.isNull(groupNameIndex)) { event.setExperimentGroupName(cursor.getString(groupNameIndex)); } if (!cursor.isNull(actionTriggerIndex)) { event.setActionTriggerId(cursor.getLong(actionTriggerIndex)); } if (!cursor.isNull(actionTriggerSpecIndex)) { event.setActionTriggerSpecId(cursor.getLong(actionTriggerSpecIndex)); } if (!cursor.isNull(actionIdIndex)) { event.setActionId(cursor.getLong(actionIdIndex)); } return event; } private Output createResponse(Cursor cursor) { int idIndex = cursor.getColumnIndexOrThrow(OutputColumns._ID); int eventIdIndex = cursor.getColumnIndexOrThrow(OutputColumns.EVENT_ID); int inputServeridIndex = cursor.getColumnIndex(OutputColumns.INPUT_SERVER_ID); int answerIndex = cursor.getColumnIndex(OutputColumns.ANSWER); int nameIndex = cursor.getColumnIndex(OutputColumns.NAME); Output input = new Output(); if (!cursor.isNull(idIndex)) { input.setId(cursor.getLong(idIndex)); } if (!cursor.isNull(eventIdIndex)) { input.setEventId(cursor.getLong(eventIdIndex)); } if (!cursor.isNull(inputServeridIndex)) { input.setInputServerId(cursor.getLong(inputServeridIndex)); } if (!cursor.isNull(nameIndex)) { input.setName(cursor.getString(nameIndex)); } if (!cursor.isNull(answerIndex)) { input.setAnswer(cursor.getString(answerIndex)); } return input; } public void updateEvent(EventInterface eventI) { if (eventI instanceof Event) { Event event = (Event) eventI; contentResolver.update(EventColumns.CONTENT_URI, createContentValues(event), "_id=" + event.getId(), null); } else { throw new IllegalArgumentException("I only know how to deal with Android objects!"); } } public List<Event> getEventsNeedingUpload() { String select = EventColumns.UPLOADED + " != 1"; return findEventsBy(select, null); } public List<Event> getAllEvents() { return findEventsBy(null, null); } public NotificationHolder getNotificationForSource(long experimentId, String source) { String[] selectionArgs = new String[] { Long.toString(experimentId), source }; String selectionClause = NotificationHolderColumns.EXPERIMENT_ID + " = ? and " + NotificationHolderColumns.NOTIFICATION_SOURCE + " = ?"; Cursor cursor = null; try { cursor = contentResolver.query(NotificationHolderColumns.CONTENT_URI, null, selectionClause, selectionArgs, null); if (cursor.moveToFirst()) { return createNotification(cursor); } } finally { if (cursor != null) { cursor.close(); } } return null; } public NotificationHolder getNotificationForAction(long experimentId, Long actionId) { String[] selectionArgs = new String[] { Long.toString(experimentId), Long.toString(actionId) }; String selectionClause = NotificationHolderColumns.EXPERIMENT_ID + " = ? and " + NotificationHolderColumns.ACTION_ID + " = ?"; Cursor cursor = null; try { cursor = contentResolver.query(NotificationHolderColumns.CONTENT_URI, null, selectionClause, selectionArgs, null); if (cursor.moveToFirst()) { return createNotification(cursor); } } finally { if (cursor != null) { cursor.close(); } } return null; } public List<NotificationHolder> getNotificationsFor(long experimentId, String experimentGroupName) { List<NotificationHolder> holders = new ArrayList<NotificationHolder>(); String[] selectionArgs = new String[] { Long.toString(experimentId), experimentGroupName }; String selectionClause = NotificationHolderColumns.EXPERIMENT_ID + " = ? and " + NotificationHolderColumns.EXPERIMENT_GROUP_NAME + " = ?"; Cursor cursor = null; try { cursor = contentResolver.query(NotificationHolderColumns.CONTENT_URI, null, selectionClause, selectionArgs, null); while (cursor.moveToNext()) { holders.add(createNotification(cursor)); } } finally { if (cursor != null) { cursor.close(); } } return holders; } private NotificationHolder createNotification(Cursor cursor) { int idIndex = cursor.getColumnIndexOrThrow(NotificationHolderColumns._ID); int experimentIdIndex = cursor.getColumnIndexOrThrow(NotificationHolderColumns.EXPERIMENT_ID); int alarmIdIndex = cursor.getColumnIndexOrThrow(NotificationHolderColumns.ALARM_TIME); int noticeCountIdIndex = cursor.getColumnIndexOrThrow(NotificationHolderColumns.NOTICE_COUNT); int timeoutMillisIdIndex = cursor.getColumnIndexOrThrow(NotificationHolderColumns.TIMEOUT_MILLIS); int notificationSourceIndex = cursor.getColumnIndexOrThrow(NotificationHolderColumns.NOTIFICATION_SOURCE); int customMessageIndex = cursor.getColumnIndexOrThrow(NotificationHolderColumns.CUSTOM_MESSAGE); int snoozeCountIndex = cursor.getColumnIndexOrThrow(NotificationHolderColumns.SNOOZE_COUNT); int snoozeTimeIndex = cursor.getColumnIndexOrThrow(NotificationHolderColumns.SNOOZE_TIME); int groupNameIndexIndex = cursor.getColumnIndexOrThrow(NotificationHolderColumns.EXPERIMENT_GROUP_NAME); int actionTriggerIdIndex = cursor.getColumnIndexOrThrow(NotificationHolderColumns.ACTION_TRIGGER_ID); int actionTriggerSpecIdIndex = cursor .getColumnIndexOrThrow(NotificationHolderColumns.ACTION_TRIGGER_SPEC_ID); int actionIdIndex = cursor.getColumnIndexOrThrow(NotificationHolderColumns.ACTION_ID); NotificationHolder notification = new NotificationHolder(); if (!cursor.isNull(idIndex)) { notification.setId(cursor.getLong(idIndex)); } if (!cursor.isNull(experimentIdIndex)) { notification.setExperimentId(cursor.getLong(experimentIdIndex)); } if (!cursor.isNull(alarmIdIndex)) { notification.setAlarmTime(cursor.getLong(alarmIdIndex)); } if (!cursor.isNull(noticeCountIdIndex)) { notification.setNoticeCount(cursor.getInt(noticeCountIdIndex)); } if (!cursor.isNull(timeoutMillisIdIndex)) { notification.setTimeoutMillis(cursor.getLong(timeoutMillisIdIndex)); } if (!cursor.isNull(notificationSourceIndex)) { notification.setNotificationSource(cursor.getString(notificationSourceIndex)); } if (!cursor.isNull(customMessageIndex)) { notification.setMessage(cursor.getString(customMessageIndex)); } if (!cursor.isNull(snoozeCountIndex)) { notification.setSnoozeCount(cursor.getInt(snoozeCountIndex)); } if (!cursor.isNull(snoozeTimeIndex)) { notification.setSnoozeTime(cursor.getInt(snoozeTimeIndex)); } if (!cursor.isNull(groupNameIndexIndex)) { notification.setExperimentGroupName(cursor.getString(groupNameIndexIndex)); } if (!cursor.isNull(actionTriggerIdIndex)) { notification.setActionTriggerId(cursor.getLong(actionTriggerIdIndex)); } if (!cursor.isNull(actionTriggerSpecIdIndex)) { notification.setActionTriggerSpecId(cursor.getLong(actionTriggerSpecIdIndex)); } if (!cursor.isNull(actionIdIndex)) { notification.setActionId(cursor.getLong(actionIdIndex)); } return notification; } public Uri insertNotification(NotificationHolder notification) { Uri uri = contentResolver.insert(NotificationHolderColumns.CONTENT_URI, createContentValues(notification)); long rowId = Long.parseLong(uri.getLastPathSegment()); notification.setId(rowId); return uri; } public NotificationHolder getNotificationById(long notificationId) { String[] selectionArgs = new String[] { Long.toString(notificationId) }; String selectionClause = NotificationHolderColumns._ID + " = ?"; Cursor cursor = null; try { cursor = contentResolver.query(NotificationHolderColumns.CONTENT_URI, null, selectionClause, selectionArgs, null); if (cursor.moveToFirst()) { return createNotification(cursor); } } finally { if (cursor != null) { cursor.close(); } } return null; } public void deleteNotification(long notificationId) { NotificationHolder holder = getNotificationById(notificationId); if (holder != null) { Log.i(PacoConstants.TAG, "found notificationHolder: " + holder.getId()); deleteNotification(holder); } } private void deleteNotification(NotificationHolder holder) { if (holder != null) { String[] selectionArgs = new String[] { Long.toString(holder.getId()) }; String selectionClause = NotificationHolderColumns._ID + " = ?"; int res = contentResolver.delete(NotificationHolderColumns.CONTENT_URI, selectionClause, selectionArgs); Log.i(PacoConstants.TAG, "resultof deleting notificationHolder: " + holder.getId() + " = " + res); } } public int deleteNotificationsForExperiment(Long experimentId) { if (experimentId == null) { return 0; } String[] selectionArgs = new String[] { Long.toString(experimentId) }; String selectionClause = NotificationHolderColumns.EXPERIMENT_ID + " = ?"; return contentResolver.delete(NotificationHolderColumns.CONTENT_URI, selectionClause, selectionArgs); } public int updateNotification(NotificationHolder notification) { String[] selectionArgs = new String[] { Long.toString(notification.getId()) }; String selectionClause = NotificationHolderColumns._ID + " = ?"; return contentResolver.update(NotificationHolderColumns.CONTENT_URI, createContentValues(notification), selectionClause, selectionArgs); } private ContentValues createContentValues(NotificationHolder notification) { ContentValues values = new ContentValues(); if (notification.getId() != null) { values.put(NotificationHolderColumns._ID, notification.getId()); } if (notification.getAlarmTime() != null) { values.put(NotificationHolderColumns.ALARM_TIME, notification.getAlarmTime()); } if (notification.getExperimentId() != null) { values.put(NotificationHolderColumns.EXPERIMENT_ID, notification.getExperimentId()); } if (notification.getNoticeCount() != null) { values.put(NotificationHolderColumns.NOTICE_COUNT, notification.getNoticeCount()); } if (notification.getTimeoutMillis() != null) { values.put(NotificationHolderColumns.TIMEOUT_MILLIS, notification.getTimeoutMillis()); } if (notification.getNotificationSource() != null) { values.put(NotificationHolderColumns.NOTIFICATION_SOURCE, notification.getNotificationSource()); } if (notification.getMessage() != null) { values.put(NotificationHolderColumns.CUSTOM_MESSAGE, notification.getMessage()); } if (notification.getSnoozeCount() != null) { values.put(NotificationHolderColumns.SNOOZE_COUNT, notification.getSnoozeCount()); } if (notification.getSnoozeTime() != null) { values.put(NotificationHolderColumns.SNOOZE_TIME, notification.getSnoozeTime()); } if (notification.getExperimentGroupName() != null) { values.put(NotificationHolderColumns.EXPERIMENT_GROUP_NAME, notification.getExperimentGroupName()); } if (notification.getActionTriggerId() != null) { values.put(NotificationHolderColumns.ACTION_TRIGGER_ID, notification.getActionTriggerId()); } if (notification.getActionTriggerSpecId() != null) { values.put(NotificationHolderColumns.ACTION_TRIGGER_SPEC_ID, notification.getActionTriggerSpecId()); } if (notification.getActionId() != null) { values.put(NotificationHolderColumns.ACTION_ID, notification.getActionId()); } return values; } public List<NotificationHolder> getNotificationsStillActive(DateTime now) { List<NotificationHolder> notifs = new ArrayList<NotificationHolder>(); Cursor cursor = null; try { cursor = contentResolver.query(NotificationHolderColumns.CONTENT_URI, null, null, null, null); while (cursor.moveToNext()) { NotificationHolder notif = createNotification(cursor); if (notif.isActive(now)) { notifs.add(notif); } } } finally { if (cursor != null) { cursor.close(); } } return notifs; } public List<NotificationHolder> getAllNotifications() { List<NotificationHolder> notifs = new ArrayList<NotificationHolder>(); Cursor cursor = null; try { cursor = contentResolver.query(NotificationHolderColumns.CONTENT_URI, null, null, null, null); while (cursor.moveToNext()) { notifs.add(createNotification(cursor)); } } finally { if (cursor != null) { cursor.close(); } } return notifs; } public void saveMyExperimentsToDisk(String contentAsString) throws IOException { FileOutputStream fos = context.openFileOutput(MY_EXPERIMENTS_FILENAME, Context.MODE_PRIVATE); fos.write(contentAsString.getBytes()); fos.close(); } public List<Experiment> loadMyExperimentsFromDisk() { List<Experiment> experiments = null; try { experiments = createObjectsFromJsonStream(context.openFileInput(MY_EXPERIMENTS_FILENAME)); } catch (IOException e) { Log.i(PacoConstants.TAG, "IOException, experiments file does not exist. May be first launch."); } return ensureExperiments(experiments); } public void saveExperimentsToDisk(String contentAsString) throws IOException { FileOutputStream fos = context.openFileOutput(PUBLIC_EXPERIMENTS_FILENAME, Context.MODE_PRIVATE); fos.write(contentAsString.getBytes()); fos.close(); } public List<Experiment> loadExperimentsFromDisk(boolean myExperimentsFile) { String filename = null; if (myExperimentsFile) { filename = MY_EXPERIMENTS_FILENAME; } else { filename = PUBLIC_EXPERIMENTS_FILENAME; } List<Experiment> experiments = null; try { FileInputStream openFileInput = context.openFileInput(filename); experiments = createObjectsFromJsonStream(openFileInput); } catch (IOException e) { Log.i(PacoConstants.TAG, "IOException, experiments file does not exist. May be first launch."); } return ensureExperiments(experiments); } public static void deleteExperimentCachesOnDisk(Context context2) { context2.deleteFile(MY_EXPERIMENTS_FILENAME); context2.deleteFile(PUBLIC_EXPERIMENTS_FILENAME); } public void addExperimentToExperimentsOnDisk(String contentAsString) { List<Experiment> existing = loadExperimentsFromDisk(false); List<Experiment> newEx; try { newEx = (List<Experiment>) fromDownloadedEntitiesJson(contentAsString).get("results"); existing.addAll(newEx); String newJson = getJson(existing); if (newJson != null) { saveExperimentsToDisk(newJson); } } catch (JsonParseException e) { } catch (JsonMappingException e) { } catch (IOException e) { } } private List<Experiment> ensureExperiments(List<Experiment> experiments) { if (experiments != null) { return experiments; } return new ArrayList<Experiment>(); } private List<Experiment> createObjectsFromJsonStream(FileInputStream fis) throws IOException, JsonParseException, JsonMappingException { try { ObjectMapper mapper = JsonConverter.getObjectMapper(); return mapper.readValue(fis, new TypeReference<List<Experiment>>() { }); } catch (Exception e) { e.printStackTrace(); } return Lists.newArrayList(); } private List<Experiment> createObjectsFromJsonStream(String fis) throws IOException, JsonParseException, JsonMappingException { try { ObjectMapper mapper = JsonConverter.getObjectMapper(); return mapper.readValue(fis, new TypeReference<List<Experiment>>() { }); } catch (Exception e) { e.printStackTrace(); } return Lists.newArrayList(); } public void loadLastEventForExperiment(Experiment experiment) { String select = EventColumns.EXPERIMENT_ID + "=" + experiment.getId(); String sortOrder = EventColumns._ID + " DESC"; List<Event> events = new ArrayList<Event>(); Cursor cursor = null; try { cursor = contentResolver.query(EventColumns.CONTENT_URI, null, select, null, sortOrder); if (cursor != null) { if (cursor.moveToFirst()) { Event event = createEvent(cursor); event.setResponses(findResponsesFor(event)); events.add(event); } } experiment.setEvents(events); } catch (RuntimeException e) { Log.w(ExperimentProvider.TAG, "Caught unexpected exception.", e); } finally { if (cursor != null) { cursor.close(); } } } public Experiment getExperimentFromDisk(Uri uri, boolean myExperimentsFile) { return getExperimentFromDisk(getExperimentServerIdFromUri(uri), myExperimentsFile); } public Long getExperimentServerIdFromUri(Uri uri) { return new Long(uri.getLastPathSegment()); } public Experiment getExperimentFromDisk(Long experimentServerId, boolean myExperimentsFile) { List<Experiment> experiments = loadExperimentsFromDisk(myExperimentsFile); for (Experiment experiment : experiments) { if (experiment.getServerId().equals(experimentServerId)) { return experiment; } } return null; } public static Map<String, Object> fromEntitiesJson(String resultsJson) throws JsonParseException, JsonMappingException, IOException { ObjectMapper mapper = JsonConverter.getObjectMapper(); Map<String, Object> resultObjects = mapper.readValue(resultsJson, new TypeReference<Map<String, Object>>() { }); Object experimentResults = resultObjects.get("results"); String experimentJson = mapper.writeValueAsString(experimentResults); List<ExperimentDAO> experimentDAOs = mapper.readValue(experimentJson, new TypeReference<List<ExperimentDAO>>() { }); List<Experiment> experiments = Lists.newArrayList(); for (ExperimentDAO experimentDAO : experimentDAOs) { Experiment newExperiment = new Experiment(); newExperiment.setExperimentDAO(experimentDAO); newExperiment.setServerId(experimentDAO.getId()); experiments.add(newExperiment); } resultObjects.put("results", experiments); return resultObjects; } /** * this one wraps the downlaoded DAOs with Android Experiment objects * @param resultsJson * @return * @throws JsonParseException * @throws JsonMappingException * @throws IOException */ public static Map<String, Object> fromDownloadedEntitiesJson(String resultsJson) throws JsonParseException, JsonMappingException, IOException { ObjectMapper mapper = JsonConverter.getObjectMapper(); Map<String, Object> resultObjects = mapper.readValue(resultsJson, new TypeReference<Map<String, Object>>() { }); Object experimentResults = resultObjects.get("results"); String experimentJson = mapper.writeValueAsString(experimentResults); List<ExperimentDAO> experiments = mapper.readValue(experimentJson, new TypeReference<List<ExperimentDAO>>() { }); List<Experiment> experimentsWithDAOs = Lists.newArrayList(); for (ExperimentDAO experimentDAO : experiments) { Experiment experiment = new Experiment(); experiment.setExperimentDAO(experimentDAO); experimentsWithDAOs.add(experiment); } resultObjects.put("results", experimentsWithDAOs); return resultObjects; } public static List<Experiment> getExperimentsFromJson(String contentAsString) throws JsonParseException, JsonMappingException, IOException { Map<String, Object> results = fromDownloadedEntitiesJson(contentAsString); return (List<Experiment>) results.get("results"); } public static Experiment getSingleExperimentFromJson(String contentAsString) throws JsonParseException, JsonMappingException, IOException { ObjectMapper mapper = JsonConverter.getObjectMapper(); return mapper.readValue(contentAsString, Experiment.class); } @Override public EventInterface getEvent(Long experimentServerId, DateTime scheduledTime, String groupName, Long actionTriggerId, Long scheduleId) { if (scheduledTime == null) { return null; } String selectionClause = EventColumns.EXPERIMENT_SERVER_ID + " = ? " + " AND " + EventColumns.SCHEDULE_TIME + " = ? " + " AND " + EventColumns.GROUP_NAME + " = ? " + " AND " + EventColumns.ACTION_TRIGGER_ID + " = ? " + " AND " + EventColumns.ACTION_TRIGGER_SPEC_ID + " = ? "; String[] selectionArgs = new String[] { Long.toString(experimentServerId), Long.toString(scheduledTime.getMillis()), groupName, Long.toString(actionTriggerId), Long.toString(scheduleId) }; Event event = findEventBy(selectionClause, selectionArgs, EventColumns._ID + " DESC"); if (event != null) { Log.i(PacoConstants.TAG, "Found event for experimentId: " + experimentServerId + ", st = " + scheduledTime); } else { Log.i(PacoConstants.TAG, "DID NOT Find event for experimentId: " + experimentServerId + ", st = " + scheduledTime); } return event; } public List<NotificationHolder> getAllNotificationsFor(Long experimentId) { List<NotificationHolder> holders = new ArrayList<NotificationHolder>(); String[] selectionArgs = new String[] { Long.toString(experimentId) }; String selectionClause = NotificationHolderColumns.EXPERIMENT_ID + " = ?"; Cursor cursor = null; try { cursor = contentResolver.query(NotificationHolderColumns.CONTENT_URI, null, selectionClause, selectionArgs, null); while (cursor.moveToNext()) { holders.add(createNotification(cursor)); } } finally { if (cursor != null) { cursor.close(); } } return holders; } public List<NotificationHolder> getAllNotificationsFor(Long experimentId, String groupName) { List<NotificationHolder> holders = new ArrayList<NotificationHolder>(); String[] selectionArgs = new String[] { Long.toString(experimentId), groupName }; String selectionClause = NotificationHolderColumns.EXPERIMENT_ID + " = ? and " + NotificationHolderColumns.EXPERIMENT_GROUP_NAME + " = ?"; Cursor cursor = null; try { cursor = contentResolver.query(NotificationHolderColumns.CONTENT_URI, null, selectionClause, selectionArgs, null); while (cursor.moveToNext()) { holders.add(createNotification(cursor)); } } finally { if (cursor != null) { cursor.close(); } } return holders; } public void loadEventsForExperimentGroup(Experiment experiment, ExperimentGroup experimentGroup) { final Long id = experiment.getId(); final String name = experimentGroup.getName(); experiment.setEvents(loadEventsForExperimentGroup(id, name)); } public List<Event> loadEventsForExperimentGroup(final Long experimentId, final String experimentGroupName) { String[] args = new String[] { Long.toString(experimentId), experimentGroupName }; final String select = EventColumns.EXPERIMENT_ID + " = ? and " + EventColumns.GROUP_NAME + " = ?"; return findEventsBy(select, args, EventColumns._ID + " DESC"); } private List<Event> findEventsBy(String select, String[] args, String sortOrder) { List<Event> events = new ArrayList<Event>(); Cursor cursor = null; try { cursor = contentResolver.query(EventColumns.CONTENT_URI, null, select, args, sortOrder); if (cursor != null) { while (cursor.moveToNext()) { Event event = createEvent(cursor); event.setResponses(findResponsesFor(event)); events.add(event); } } return events; } catch (RuntimeException e) { Log.w(ExperimentProvider.TAG, "Caught unexpected exception.", e); } finally { if (cursor != null) { cursor.close(); } } return events; } }