summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Morgan <jesse@jesterpm.net>2014-05-23 13:05:19 -0700
committerJesse Morgan <jesse@jesterpm.net>2014-05-23 13:05:19 -0700
commit255b10334bcf190cf56c0d57791e39d5e808497b (patch)
tree403b64d7eea8f0809854bdacabd39efeabd6e89a
parent7b5467b0356f06fdc8c3c548bf71b5fe72668245 (diff)
Abstracting out Cassandra.
-rw-r--r--src/com/p4square/grow/backend/CassandraGrowData.java172
-rw-r--r--src/com/p4square/grow/backend/GrowBackend.java87
-rw-r--r--src/com/p4square/grow/backend/GrowData.java36
-rw-r--r--src/com/p4square/grow/backend/db/CassandraCollectionProvider.java10
-rw-r--r--src/com/p4square/grow/backend/db/CassandraProviderImpl.java10
-rw-r--r--src/com/p4square/grow/backend/resources/BannerResource.java16
-rw-r--r--src/com/p4square/grow/backend/resources/SurveyResource.java31
-rw-r--r--src/com/p4square/grow/backend/resources/SurveyResultsResource.java96
-rw-r--r--src/com/p4square/grow/backend/resources/TrainingRecordResource.java14
-rw-r--r--src/com/p4square/grow/backend/resources/TrainingResource.java69
-rw-r--r--src/com/p4square/grow/provider/DelegateCollectionProvider.java69
-rw-r--r--src/com/p4square/grow/provider/DelegateProvider.java6
-rw-r--r--src/com/p4square/grow/provider/JsonEncodedProvider.java4
-rw-r--r--src/com/p4square/grow/provider/ProvidesAssessments.java20
-rw-r--r--src/com/p4square/grow/provider/ProvidesStrings.java19
-rw-r--r--src/com/p4square/grow/provider/ProvidesTrainingRecords.java8
-rw-r--r--src/com/p4square/grow/provider/ProvidesVideos.java16
17 files changed, 519 insertions, 164 deletions
diff --git a/src/com/p4square/grow/backend/CassandraGrowData.java b/src/com/p4square/grow/backend/CassandraGrowData.java
new file mode 100644
index 0000000..22a7716
--- /dev/null
+++ b/src/com/p4square/grow/backend/CassandraGrowData.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2014 Jesse Morgan
+ */
+
+package com.p4square.grow.backend;
+
+import java.io.IOException;
+
+import com.p4square.grow.config.Config;
+
+import com.p4square.grow.backend.db.CassandraDatabase;
+import com.p4square.grow.backend.db.CassandraKey;
+import com.p4square.grow.backend.db.CassandraProviderImpl;
+import com.p4square.grow.backend.db.CassandraCollectionProvider;
+import com.p4square.grow.backend.db.CassandraTrainingRecordProvider;
+
+import com.p4square.grow.model.Message;
+import com.p4square.grow.model.MessageThread;
+import com.p4square.grow.model.Playlist;
+import com.p4square.grow.model.Question;
+import com.p4square.grow.model.TrainingRecord;
+import com.p4square.grow.model.UserRecord;
+
+import com.p4square.grow.provider.CollectionProvider;
+import com.p4square.grow.provider.DelegateCollectionProvider;
+import com.p4square.grow.provider.DelegateProvider;
+import com.p4square.grow.provider.Provider;
+
+/**
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+class CassandraGrowData implements GrowData {
+ private static final String DEFAULT_COLUMN = "value";
+
+ private final Config mConfig;
+ private final CassandraDatabase mDatabase;
+
+ private final Provider<String, UserRecord> mUserRecordProvider;
+
+ private final Provider<String, Question> mQuestionProvider;
+ private final CassandraTrainingRecordProvider mTrainingRecordProvider;
+ private final CollectionProvider<String, String, String> mVideoProvider;
+
+ private final CollectionProvider<String, String, MessageThread> mFeedThreadProvider;
+ private final CollectionProvider<String, String, Message> mFeedMessageProvider;
+
+ private final Provider<String, String> mStringProvider;
+
+ private final CollectionProvider<String, String, String> mAnswerProvider;
+
+ public CassandraGrowData(final Config config) {
+ mConfig = config;
+ mDatabase = new CassandraDatabase();
+
+ mUserRecordProvider = new DelegateProvider<String, CassandraKey, UserRecord>(
+ new CassandraProviderImpl<UserRecord>(mDatabase, UserRecord.class)) {
+ @Override
+ public CassandraKey makeKey(String userid) {
+ return new CassandraKey("accounts", userid, DEFAULT_COLUMN);
+ }
+ };
+
+ mQuestionProvider = new DelegateProvider<String, CassandraKey, Question>(
+ new CassandraProviderImpl<Question>(mDatabase, Question.class)) {
+ @Override
+ public CassandraKey makeKey(String questionId) {
+ return new CassandraKey("strings", "/questions/" + questionId, DEFAULT_COLUMN);
+ }
+ };
+
+ mFeedThreadProvider = new CassandraCollectionProvider<MessageThread>(mDatabase,
+ "feedthreads", MessageThread.class);
+ mFeedMessageProvider = new CassandraCollectionProvider<Message>(mDatabase,
+ "feedmessages", Message.class);
+
+ mTrainingRecordProvider = new CassandraTrainingRecordProvider(mDatabase);
+
+ mVideoProvider = new DelegateCollectionProvider<String, String, String, String, String>(
+ new CassandraCollectionProvider<String>(mDatabase, "strings", String.class)) {
+ @Override
+ public String makeCollectionKey(String key) {
+ return "/training/" + key;
+ }
+
+ @Override
+ public String makeKey(String key) {
+ return key;
+ }
+
+ @Override
+ public String unmakeKey(String key) {
+ return key;
+ }
+ };
+
+ mStringProvider = new DelegateProvider<String, CassandraKey, String>(
+ new CassandraProviderImpl<String>(mDatabase, String.class)) {
+ @Override
+ public CassandraKey makeKey(String id) {
+ return new CassandraKey("strings", id, DEFAULT_COLUMN);
+ }
+ };
+
+ mAnswerProvider = new CassandraCollectionProvider<String>(
+ mDatabase, "assessments", String.class);
+ }
+
+ @Override
+ public void start() throws Exception {
+ mDatabase.setClusterName(mConfig.getString("clusterName", "Dev Cluster"));
+ mDatabase.setKeyspaceName(mConfig.getString("keyspace", "GROW"));
+ mDatabase.init();
+ }
+
+ @Override
+ public void stop() throws Exception {
+ mDatabase.close();
+ }
+
+ /**
+ * @return the current database.
+ */
+ public CassandraDatabase getDatabase() {
+ return mDatabase;
+ }
+
+ @Override
+ public Provider<String, UserRecord> getUserRecordProvider() {
+ return mUserRecordProvider;
+ }
+
+ @Override
+ public Provider<String, Question> getQuestionProvider() {
+ return mQuestionProvider;
+ }
+
+ @Override
+ public Provider<String, TrainingRecord> getTrainingRecordProvider() {
+ return mTrainingRecordProvider;
+ }
+
+ @Override
+ public CollectionProvider<String, String, String> getVideoProvider() {
+ return mVideoProvider;
+ }
+
+ @Override
+ public Playlist getDefaultPlaylist() throws IOException {
+ return mTrainingRecordProvider.getDefaultPlaylist();
+ }
+
+ @Override
+ public CollectionProvider<String, String, MessageThread> getThreadProvider() {
+ return mFeedThreadProvider;
+ }
+
+ @Override
+ public CollectionProvider<String, String, Message> getMessageProvider() {
+ return mFeedMessageProvider;
+ }
+
+ @Override
+ public Provider<String, String> getStringProvider() {
+ return mStringProvider;
+ }
+
+ @Override
+ public CollectionProvider<String, String, String> getAnswerProvider() {
+ return mAnswerProvider;
+ }
+}
diff --git a/src/com/p4square/grow/backend/GrowBackend.java b/src/com/p4square/grow/backend/GrowBackend.java
index e747a1b..49d064c 100644
--- a/src/com/p4square/grow/backend/GrowBackend.java
+++ b/src/com/p4square/grow/backend/GrowBackend.java
@@ -18,12 +18,6 @@ import org.restlet.routing.Router;
import com.p4square.grow.config.Config;
-import com.p4square.grow.backend.db.CassandraDatabase;
-import com.p4square.grow.backend.db.CassandraKey;
-import com.p4square.grow.backend.db.CassandraProviderImpl;
-import com.p4square.grow.backend.db.CassandraCollectionProvider;
-import com.p4square.grow.backend.db.CassandraTrainingRecordProvider;
-
import com.p4square.grow.model.Message;
import com.p4square.grow.model.MessageThread;
import com.p4square.grow.model.Playlist;
@@ -32,7 +26,6 @@ import com.p4square.grow.model.TrainingRecord;
import com.p4square.grow.model.UserRecord;
import com.p4square.grow.provider.CollectionProvider;
-import com.p4square.grow.provider.DelegateProvider;
import com.p4square.grow.provider.Provider;
import com.p4square.grow.provider.ProvidesQuestions;
import com.p4square.grow.provider.ProvidesTrainingRecords;
@@ -54,23 +47,12 @@ import com.p4square.grow.backend.feed.TopicResource;
*
* @author Jesse Morgan <jesse@jesterpm.net>
*/
-public class GrowBackend extends Application
- implements ProvidesQuestions, ProvidesTrainingRecords, FeedDataProvider,
- ProvidesUserRecords {
- private static final String DEFAULT_COLUMN = "value";
+public class GrowBackend extends Application implements GrowData {
private final static Logger LOG = Logger.getLogger(GrowBackend.class);
private final Config mConfig;
- private final CassandraDatabase mDatabase;
-
- private final Provider<String, UserRecord> mUserRecordProvider;
-
- private final Provider<String, Question> mQuestionProvider;
- private final CassandraTrainingRecordProvider mTrainingRecordProvider;
-
- private final CollectionProvider<String, String, MessageThread> mFeedThreadProvider;
- private final CollectionProvider<String, String, Message> mFeedMessageProvider;
+ private final GrowData mGrowData;
public GrowBackend() {
this(new Config());
@@ -78,30 +60,8 @@ public class GrowBackend extends Application
public GrowBackend(Config config) {
mConfig = config;
- mDatabase = new CassandraDatabase();
-
- mUserRecordProvider = new DelegateProvider<String, CassandraKey, UserRecord>(
- new CassandraProviderImpl<UserRecord>(mDatabase, UserRecord.class)) {
- @Override
- public CassandraKey makeKey(String userid) {
- return new CassandraKey("accounts", userid, DEFAULT_COLUMN);
- }
- };
- mQuestionProvider = new DelegateProvider<String, CassandraKey, Question>(
- new CassandraProviderImpl<Question>(mDatabase, Question.class)) {
- @Override
- public CassandraKey makeKey(String questionId) {
- return new CassandraKey("strings", "/questions/" + questionId, DEFAULT_COLUMN);
- }
- };
-
- mFeedThreadProvider = new CassandraCollectionProvider<MessageThread>(mDatabase,
- "feedthreads", MessageThread.class);
- mFeedMessageProvider = new CassandraCollectionProvider<Message>(mDatabase,
- "feedmessages", Message.class);
-
- mTrainingRecordProvider = new CassandraTrainingRecordProvider(mDatabase);
+ mGrowData = new CassandraGrowData(config);
}
@Override
@@ -146,10 +106,7 @@ public class GrowBackend extends Application
public void start() throws Exception {
super.start();
- // Setup database
- mDatabase.setClusterName(mConfig.getString("clusterName", "Dev Cluster"));
- mDatabase.setKeyspaceName(mConfig.getString("keyspace", "GROW"));
- mDatabase.init();
+ mGrowData.start();
}
/**
@@ -158,48 +115,56 @@ public class GrowBackend extends Application
@Override
public void stop() throws Exception {
LOG.info("Shutting down...");
- mDatabase.close();
+ mGrowData.stop();
super.stop();
}
- /**
- * @return the current database.
- */
- public CassandraDatabase getDatabase() {
- return mDatabase;
- }
-
@Override
public Provider<String, UserRecord> getUserRecordProvider() {
- return mUserRecordProvider;
+ return mGrowData.getUserRecordProvider();
}
@Override
public Provider<String, Question> getQuestionProvider() {
- return mQuestionProvider;
+ return mGrowData.getQuestionProvider();
+ }
+
+ @Override
+ public CollectionProvider<String, String, String> getVideoProvider() {
+ return mGrowData.getVideoProvider();
}
@Override
public Provider<String, TrainingRecord> getTrainingRecordProvider() {
- return mTrainingRecordProvider;
+ return mGrowData.getTrainingRecordProvider();
}
/**
* @return the Default Playlist.
*/
public Playlist getDefaultPlaylist() throws IOException {
- return mTrainingRecordProvider.getDefaultPlaylist();
+ return mGrowData.getDefaultPlaylist();
}
@Override
public CollectionProvider<String, String, MessageThread> getThreadProvider() {
- return mFeedThreadProvider;
+ return mGrowData.getThreadProvider();
}
@Override
public CollectionProvider<String, String, Message> getMessageProvider() {
- return mFeedMessageProvider;
+ return mGrowData.getMessageProvider();
+ }
+
+ @Override
+ public Provider<String, String> getStringProvider() {
+ return mGrowData.getStringProvider();
+ }
+
+ @Override
+ public CollectionProvider<String, String, String> getAnswerProvider() {
+ return mGrowData.getAnswerProvider();
}
/**
diff --git a/src/com/p4square/grow/backend/GrowData.java b/src/com/p4square/grow/backend/GrowData.java
new file mode 100644
index 0000000..293bb88
--- /dev/null
+++ b/src/com/p4square/grow/backend/GrowData.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2014 Jesse Morgan
+ */
+
+package com.p4square.grow.backend;
+
+import com.p4square.grow.backend.feed.FeedDataProvider;
+import com.p4square.grow.model.Playlist;
+import com.p4square.grow.provider.ProvidesAssessments;
+import com.p4square.grow.provider.ProvidesQuestions;
+import com.p4square.grow.provider.ProvidesStrings;
+import com.p4square.grow.provider.ProvidesTrainingRecords;
+import com.p4square.grow.provider.ProvidesUserRecords;
+import com.p4square.grow.provider.ProvidesVideos;
+
+/**
+ * Aggregate of the data provider interfaces.
+ *
+ * Used by GrowBackend to swap out implementations of the providers.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+interface GrowData extends ProvidesQuestions, ProvidesTrainingRecords, ProvidesVideos,
+ FeedDataProvider, ProvidesUserRecords, ProvidesStrings,
+ ProvidesAssessments {
+
+ /**
+ * Start the data provider.
+ */
+ void start() throws Exception;
+
+ /**
+ * Stop the data provider.
+ */
+ void stop() throws Exception;
+}
diff --git a/src/com/p4square/grow/backend/db/CassandraCollectionProvider.java b/src/com/p4square/grow/backend/db/CassandraCollectionProvider.java
index 5e83247..bfcb48d 100644
--- a/src/com/p4square/grow/backend/db/CassandraCollectionProvider.java
+++ b/src/com/p4square/grow/backend/db/CassandraCollectionProvider.java
@@ -80,7 +80,11 @@ public class CassandraCollectionProvider<V> implements CollectionProvider<String
* @throws IOException if the object cannot be encoded.
*/
protected String encode(V obj) throws IOException {
- return JsonEncodedProvider.MAPPER.writeValueAsString(obj);
+ if (mClazz == String.class) {
+ return (String) obj;
+ } else {
+ return JsonEncodedProvider.MAPPER.writeValueAsString(obj);
+ }
}
/**
@@ -95,6 +99,10 @@ public class CassandraCollectionProvider<V> implements CollectionProvider<String
return null;
}
+ if (mClazz == String.class) {
+ return (V) blob;
+ }
+
V obj = JsonEncodedProvider.MAPPER.readValue(blob, mClazz);
return obj;
}
diff --git a/src/com/p4square/grow/backend/db/CassandraProviderImpl.java b/src/com/p4square/grow/backend/db/CassandraProviderImpl.java
index da5a9f2..9d896e7 100644
--- a/src/com/p4square/grow/backend/db/CassandraProviderImpl.java
+++ b/src/com/p4square/grow/backend/db/CassandraProviderImpl.java
@@ -26,12 +26,20 @@ public class CassandraProviderImpl<V> extends JsonEncodedProvider<V> implements
@Override
public V get(CassandraKey key) throws IOException {
String blob = mDb.getKey(key.getColumnFamily(), key.getId(), key.getColumn());
+ if (mClazz == String.class) {
+ return (V) blob;
+ }
return decode(blob);
}
@Override
public void put(CassandraKey key, V obj) throws IOException {
- String blob = encode(obj);
+ String blob;
+ if (mClazz == String.class) {
+ blob = (String) obj;
+ } else {
+ blob = encode(obj);
+ }
mDb.putKey(key.getColumnFamily(), key.getId(), key.getColumn(), blob);
}
}
diff --git a/src/com/p4square/grow/backend/resources/BannerResource.java b/src/com/p4square/grow/backend/resources/BannerResource.java
index 8519f64..2b9c8e6 100644
--- a/src/com/p4square/grow/backend/resources/BannerResource.java
+++ b/src/com/p4square/grow/backend/resources/BannerResource.java
@@ -17,9 +17,9 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.log4j.Logger;
import com.p4square.grow.backend.GrowBackend;
-import com.p4square.grow.backend.db.CassandraDatabase;
import com.p4square.grow.model.Banner;
import com.p4square.grow.provider.JsonEncodedProvider;
+import com.p4square.grow.provider.Provider;
/**
* Fetches or sets the banner string.
@@ -31,14 +31,14 @@ public class BannerResource extends ServerResource {
public static final ObjectMapper MAPPER = JsonEncodedProvider.MAPPER;
- private CassandraDatabase mDb;
+ private Provider<String, String> mStringProvider;
@Override
public void doInit() {
super.doInit();
final GrowBackend backend = (GrowBackend) getApplication();
- mDb = backend.getDatabase();
+ mStringProvider = backend.getStringProvider();
}
/**
@@ -46,7 +46,13 @@ public class BannerResource extends ServerResource {
*/
@Override
protected Representation get() {
- String result = mDb.getKey("strings", "banner");
+ String result = null;
+ try {
+ result = mStringProvider.get("banner");
+
+ } catch (IOException e) {
+ LOG.warn("Exception loading banner: " + e);
+ }
if (result == null || result.length() == 0) {
result = "{\"html\":null}";
@@ -67,7 +73,7 @@ public class BannerResource extends ServerResource {
Banner banner = representation.getObject();
- mDb.putKey("strings", "banner", MAPPER.writeValueAsString(banner));
+ mStringProvider.put("banner", MAPPER.writeValueAsString(banner));
setStatus(Status.SUCCESS_NO_CONTENT);
} catch (IOException e) {
diff --git a/src/com/p4square/grow/backend/resources/SurveyResource.java b/src/com/p4square/grow/backend/resources/SurveyResource.java
index 497978f..8723ee2 100644
--- a/src/com/p4square/grow/backend/resources/SurveyResource.java
+++ b/src/com/p4square/grow/backend/resources/SurveyResource.java
@@ -13,14 +13,17 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import org.restlet.data.MediaType;
import org.restlet.data.Status;
-import org.restlet.resource.ServerResource;
+import org.restlet.ext.jackson.JacksonRepresentation;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
+import org.restlet.resource.ServerResource;
import org.apache.log4j.Logger;
import com.p4square.grow.backend.GrowBackend;
-import com.p4square.grow.backend.db.CassandraDatabase;
+import com.p4square.grow.model.Question;
+import com.p4square.grow.provider.JsonEncodedProvider;
+import com.p4square.grow.provider.Provider;
/**
* This resource manages assessment questions.
@@ -30,9 +33,10 @@ import com.p4square.grow.backend.db.CassandraDatabase;
public class SurveyResource extends ServerResource {
private static final Logger LOG = Logger.getLogger(SurveyResource.class);
- private static final ObjectMapper MAPPER = new ObjectMapper();
+ private static final ObjectMapper MAPPER = JsonEncodedProvider.MAPPER;
- private CassandraDatabase mDb;
+ private Provider<String, Question> mQuestionProvider;
+ private Provider<String, String> mStringProvider;
private String mQuestionId;
@@ -41,7 +45,8 @@ public class SurveyResource extends ServerResource {
super.doInit();
final GrowBackend backend = (GrowBackend) getApplication();
- mDb = backend.getDatabase();
+ mQuestionProvider = backend.getQuestionProvider();
+ mStringProvider = backend.getStringProvider();
mQuestionId = getAttribute("questionId");
}
@@ -71,13 +76,22 @@ public class SurveyResource extends ServerResource {
if (mQuestionId != null) {
// Get a question by id
- result = mDb.getKey("strings", "/questions/" + mQuestionId);
+ Question question = null;
+ try {
+ question = mQuestionProvider.get(mQuestionId);
+ } catch (IOException e) {
+ LOG.error("IOException loading question: " + e);
+ }
- if (result == null) {
+ if (question == null) {
// 404
setStatus(Status.CLIENT_ERROR_NOT_FOUND);
return null;
}
+
+ JacksonRepresentation<Question> rep = new JacksonRepresentation<>(question);
+ rep.setObjectMapper(MAPPER);
+ return rep;
}
return new StringRepresentation(result);
@@ -85,7 +99,8 @@ public class SurveyResource extends ServerResource {
private Map<?, ?> getQuestionsSummary() {
try {
- String json = mDb.getKey("strings", "/questions");
+ // TODO: This could be better. Quick fix for provider support.
+ String json = mStringProvider.get("/questions");
if (json != null) {
return MAPPER.readValue(json, Map.class);
diff --git a/src/com/p4square/grow/backend/resources/SurveyResultsResource.java b/src/com/p4square/grow/backend/resources/SurveyResultsResource.java
index 404ccec..7c15cfd 100644
--- a/src/com/p4square/grow/backend/resources/SurveyResultsResource.java
+++ b/src/com/p4square/grow/backend/resources/SurveyResultsResource.java
@@ -4,12 +4,10 @@
package com.p4square.grow.backend.resources;
+import java.io.IOException;
import java.util.Map;
import java.util.HashMap;
-import com.netflix.astyanax.model.Column;
-import com.netflix.astyanax.model.ColumnList;
-
import com.fasterxml.jackson.databind.ObjectMapper;
import org.restlet.data.MediaType;
@@ -21,12 +19,12 @@ import org.restlet.resource.ServerResource;
import org.apache.log4j.Logger;
import com.p4square.grow.backend.GrowBackend;
-import com.p4square.grow.backend.db.CassandraDatabase;
import com.p4square.grow.model.Answer;
import com.p4square.grow.model.Question;
import com.p4square.grow.model.RecordedAnswer;
import com.p4square.grow.model.Score;
import com.p4square.grow.model.UserRecord;
+import com.p4square.grow.provider.CollectionProvider;
import com.p4square.grow.provider.Provider;
@@ -44,7 +42,7 @@ public class SurveyResultsResource extends ServerResource {
ASSESSMENT, ANSWER
}
- private CassandraDatabase mDb;
+ private CollectionProvider<String, String, String> mAnswerProvider;
private Provider<String, Question> mQuestionProvider;
private Provider<String, UserRecord> mUserRecordProvider;
@@ -57,7 +55,7 @@ public class SurveyResultsResource extends ServerResource {
super.doInit();
final GrowBackend backend = (GrowBackend) getApplication();
- mDb = backend.getDatabase();
+ mAnswerProvider = backend.getAnswerProvider();
mQuestionProvider = backend.getQuestionProvider();
mUserRecordProvider = backend.getUserRecordProvider();
@@ -75,27 +73,33 @@ public class SurveyResultsResource extends ServerResource {
*/
@Override
protected Representation get() {
- String result = null;
-
- switch (mRequestType) {
- case ANSWER:
- result = mDb.getKey("assessments", mUserId, mQuestionId);
- break;
+ try {
+ String result = null;
+
+ switch (mRequestType) {
+ case ANSWER:
+ result = mAnswerProvider.get(mUserId, mQuestionId);
+ break;
+
+ case ASSESSMENT:
+ result = mAnswerProvider.get(mUserId, "summary");
+ if (result == null || result.length() == 0) {
+ result = buildAssessment();
+ }
+ break;
+ }
- case ASSESSMENT:
- result = mDb.getKey("assessments", mUserId, "summary");
- if (result == null) {
- result = buildAssessment();
- }
- break;
- }
+ if (result == null) {
+ setStatus(Status.CLIENT_ERROR_NOT_FOUND);
+ return null;
+ }
- if (result == null) {
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
+ return new StringRepresentation(result);
+ } catch (IOException e) {
+ LOG.error("IOException getting answer: ", e);
+ setStatus(Status.SERVER_ERROR_INTERNAL);
return null;
}
-
- return new StringRepresentation(result);
}
/**
@@ -108,9 +112,9 @@ public class SurveyResultsResource extends ServerResource {
switch (mRequestType) {
case ANSWER:
try {
- mDb.putKey("assessments", mUserId, mQuestionId, entity.getText());
- mDb.putKey("assessments", mUserId, "lastAnswered", mQuestionId);
- mDb.deleteKey("assessments", mUserId, "summary");
+ mAnswerProvider.put(mUserId, mQuestionId, entity.getText());
+ mAnswerProvider.put(mUserId, "lastAnswered", mQuestionId);
+ mAnswerProvider.put(mUserId, "summary", null);
success = true;
} catch (Exception e) {
@@ -143,8 +147,8 @@ public class SurveyResultsResource extends ServerResource {
switch (mRequestType) {
case ANSWER:
try {
- mDb.deleteKey("assessments", mUserId, mQuestionId);
- mDb.deleteKey("assessments", mUserId, "summary");
+ mAnswerProvider.put(mUserId, mQuestionId, null);
+ mAnswerProvider.put(mUserId, "summary", null);
success = true;
} catch (Exception e) {
@@ -154,7 +158,9 @@ public class SurveyResultsResource extends ServerResource {
case ASSESSMENT:
try {
- mDb.deleteRow("assessments", mUserId);
+ mAnswerProvider.put(mUserId, "summary", null);
+ mAnswerProvider.put(mUserId, "lastAnswered", null);
+ // TODO Delete answers
UserRecord record = mUserRecordProvider.get(mUserId);
if (record != null) {
@@ -188,48 +194,48 @@ public class SurveyResultsResource extends ServerResource {
/**
* This method compiles assessment results.
*/
- private String buildAssessment() {
+ private String buildAssessment() throws IOException {
StringBuilder sb = new StringBuilder("{ ");
// Last question answered
- final String lastAnswered = mDb.getKey("assessments", mUserId, "lastAnswered");
- if (lastAnswered != null) {
- sb.append("\"lastAnswered\": \"" + lastAnswered + "\"");
+ final String lastAnswered = mAnswerProvider.get(mUserId, "lastAnswered");
+ if (lastAnswered != null && lastAnswered.length() > 0) {
+ sb.append("\"lastAnswered\": \"" + lastAnswered + "\", ");
}
// Compute score
- ColumnList<String> row = mDb.getRow("assessments", mUserId);
- if (!row.isEmpty()) {
+ Map<String, String> row = mAnswerProvider.query(mUserId);
+ if (row.size() > 0) {
Score score = new Score();
boolean scoringDone = false;
int totalAnswers = 0;
- for (Column<String> c : row) {
- if (c.getName().equals("lastAnswered") || c.getName().equals("summary")) {
+ for (Map.Entry<String, String> c : row.entrySet()) {
+ if (c.getKey().equals("lastAnswered") || c.getKey().equals("summary")) {
continue;
}
try {
- Question question = mQuestionProvider.get(c.getName());
- RecordedAnswer userAnswer = MAPPER.readValue(c.getStringValue(), RecordedAnswer.class);
+ Question question = mQuestionProvider.get(c.getKey());
+ RecordedAnswer userAnswer = MAPPER.readValue(c.getValue(), RecordedAnswer.class);
if (question == null) {
- LOG.warn("Answer for unknown question: " + c.getName());
+ LOG.warn("Answer for unknown question: " + c.getKey());
continue;
}
- LOG.debug("Scoring questionId: " + c.getName());
+ LOG.debug("Scoring questionId: " + c.getKey());
scoringDone = !question.scoreAnswer(score, userAnswer);
} catch (Exception e) {
LOG.error("Failed to score question: {userid: \"" + mUserId +
- "\", questionid:\"" + c.getName() +
- "\", userAnswer:\"" + c.getStringValue() + "\"}", e);
+ "\", questionid:\"" + c.getKey() +
+ "\", userAnswer:\"" + c.getValue() + "\"}", e);
}
totalAnswers++;
}
- sb.append(", \"score\":" + score.getScore());
+ sb.append("\"score\":" + score.getScore());
sb.append(", \"sum\":" + score.getSum());
sb.append(", \"count\":" + score.getCount());
sb.append(", \"totalAnswers\":" + totalAnswers);
@@ -240,7 +246,7 @@ public class SurveyResultsResource extends ServerResource {
String summary = sb.toString();
// Persist summary
- mDb.putKey("assessments", mUserId, "summary", summary);
+ mAnswerProvider.put(mUserId, "summary", summary);
return summary;
}
diff --git a/src/com/p4square/grow/backend/resources/TrainingRecordResource.java b/src/com/p4square/grow/backend/resources/TrainingRecordResource.java
index 3d9d67f..b316b75 100644
--- a/src/com/p4square/grow/backend/resources/TrainingRecordResource.java
+++ b/src/com/p4square/grow/backend/resources/TrainingRecordResource.java
@@ -11,9 +11,6 @@ import java.util.List;
import java.util.Map;
import java.util.HashMap;
-import com.netflix.astyanax.model.Column;
-import com.netflix.astyanax.model.ColumnList;
-
import com.fasterxml.jackson.databind.ObjectMapper;
import org.restlet.data.MediaType;
@@ -27,16 +24,17 @@ import org.restlet.ext.jackson.JacksonRepresentation;
import org.apache.log4j.Logger;
import com.p4square.grow.backend.GrowBackend;
-import com.p4square.grow.backend.db.CassandraDatabase;
import com.p4square.grow.model.Chapter;
import com.p4square.grow.model.Playlist;
import com.p4square.grow.model.VideoRecord;
import com.p4square.grow.model.TrainingRecord;
+import com.p4square.grow.provider.CollectionProvider;
+import com.p4square.grow.provider.JsonEncodedProvider;
import com.p4square.grow.provider.Provider;
+import com.p4square.grow.provider.ProvidesAssessments;
import com.p4square.grow.provider.ProvidesTrainingRecords;
-import com.p4square.grow.provider.JsonEncodedProvider;
import com.p4square.grow.model.Score;
@@ -52,8 +50,8 @@ public class TrainingRecordResource extends ServerResource {
SUMMARY, VIDEO
}
- private CassandraDatabase mDb;
private Provider<String, TrainingRecord> mTrainingRecordProvider;
+ private CollectionProvider<String, String, String> mAnswerProvider;
private RequestType mRequestType;
private String mUserId;
@@ -64,8 +62,8 @@ public class TrainingRecordResource extends ServerResource {
public void doInit() {
super.doInit();
- mDb = ((GrowBackend) getApplication()).getDatabase();
mTrainingRecordProvider = ((ProvidesTrainingRecords) getApplication()).getTrainingRecordProvider();
+ mAnswerProvider = ((ProvidesAssessments) getApplication()).getAnswerProvider();
mUserId = getAttribute("userId");
mVideoId = getAttribute("videoId");
@@ -184,7 +182,7 @@ public class TrainingRecordResource extends ServerResource {
double assessedScore = 0;
try {
- String summaryString = mDb.getKey("assessments", userId, "summary");
+ String summaryString = mAnswerProvider.get(userId, "summary");
if (summaryString == null) {
LOG.warn("Asked to create training record for unassessed user " + userId);
return;
diff --git a/src/com/p4square/grow/backend/resources/TrainingResource.java b/src/com/p4square/grow/backend/resources/TrainingResource.java
index 85d08c1..6efdfab 100644
--- a/src/com/p4square/grow/backend/resources/TrainingResource.java
+++ b/src/com/p4square/grow/backend/resources/TrainingResource.java
@@ -4,8 +4,8 @@
package com.p4square.grow.backend.resources;
-import com.netflix.astyanax.model.Column;
-import com.netflix.astyanax.model.ColumnList;
+import java.io.IOException;
+import java.util.Map;
import org.restlet.data.Status;
import org.restlet.resource.ServerResource;
@@ -17,16 +17,16 @@ import org.apache.log4j.Logger;
import com.p4square.grow.backend.GrowBackend;
import com.p4square.grow.backend.db.CassandraDatabase;
+import com.p4square.grow.provider.CollectionProvider;
/**
* This resource returns a listing of training items for a particular level.
*
* @author Jesse Morgan <jesse@jesterpm.net>
*/
public class TrainingResource extends ServerResource {
- private final static Logger cLog = Logger.getLogger(TrainingResource.class);
+ private final static Logger LOG = Logger.getLogger(TrainingResource.class);
- private GrowBackend mBackend;
- private CassandraDatabase mDb;
+ private CollectionProvider<String, String, String> mVideoProvider;
private String mLevel;
private String mVideoId;
@@ -35,8 +35,8 @@ public class TrainingResource extends ServerResource {
public void doInit() {
super.doInit();
- mBackend = (GrowBackend) getApplication();
- mDb = mBackend.getDatabase();
+ GrowBackend backend = (GrowBackend) getApplication();
+ mVideoProvider = backend.getVideoProvider();
mLevel = getAttribute("level");
mVideoId = getAttribute("videoId");
@@ -54,35 +54,44 @@ public class TrainingResource extends ServerResource {
return null;
}
- if (mVideoId == null) {
- // Get all videos
- ColumnList<String> row = mDb.getRow("strings", "/training/" + mLevel);
- if (!row.isEmpty()) {
- StringBuilder sb = new StringBuilder("{ \"level\": \"" + mLevel + "\"");
- sb.append(", \"videos\": [");
- boolean first = true;
- for (Column<String> c : row) {
- if (!first) {
- sb.append(", ");
+ try {
+ if (mVideoId == null) {
+ // Get all videos
+ // TODO: This could be improved, but this is the quickest way to get
+ // providers working.
+ Map<String, String> videos = mVideoProvider.query(mLevel);
+ if (videos.size() > 0) {
+ StringBuilder sb = new StringBuilder("{ \"level\": \"" + mLevel + "\"");
+ sb.append(", \"videos\": [");
+ boolean first = true;
+ for (String value : videos.values()) {
+ if (!first) {
+ sb.append(", ");
+ }
+ sb.append(value);
+ first = false;
}
- sb.append(c.getStringValue());
- first = false;
+ sb.append("] }");
+ result = sb.toString();
}
- sb.append("] }");
- result = sb.toString();
+
+ } else {
+ // Get single video
+ result = mVideoProvider.get(mLevel, mVideoId);
}
- } else {
- // Get single video
- result = mDb.getKey("strings", "/training/" + mLevel, mVideoId);
- }
+ if (result == null) {
+ // 404
+ setStatus(Status.CLIENT_ERROR_NOT_FOUND);
+ return null;
+ }
- if (result == null) {
- // 404
- setStatus(Status.CLIENT_ERROR_NOT_FOUND);
+ return new StringRepresentation(result);
+
+ } catch (IOException e) {
+ LOG.error("IOException fetch video: " + e.getMessage(), e);
+ setStatus(Status.SERVER_ERROR_INTERNAL);
return null;
}
-
- return new StringRepresentation(result);
}
}
diff --git a/src/com/p4square/grow/provider/DelegateCollectionProvider.java b/src/com/p4square/grow/provider/DelegateCollectionProvider.java
new file mode 100644
index 0000000..e17af87
--- /dev/null
+++ b/src/com/p4square/grow/provider/DelegateCollectionProvider.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2014 Jesse Morgan
+ */
+
+package com.p4square.grow.provider;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public abstract class DelegateCollectionProvider<C, DC, K, DK, V>
+ implements CollectionProvider<C, K, V> {
+
+ private CollectionProvider<DC, DK, V> mProvider;
+
+ public DelegateCollectionProvider(final CollectionProvider<DC, DK, V> provider) {
+ mProvider = provider;
+ }
+
+ public V get(C collection, K key) throws IOException {
+ return mProvider.get(makeCollectionKey(collection), makeKey(key));
+ }
+
+ public Map<K, V> query(C collection) throws IOException {
+ return query(collection, -1);
+ }
+
+ public Map<K, V> query(C collection, int limit) throws IOException {
+ Map<DK, V> delegateResult = mProvider.query(makeCollectionKey(collection), limit);
+ Map<K, V> result = new HashMap<>();
+ for (Map.Entry<DK, V> entry : delegateResult.entrySet()) {
+ result.put(unmakeKey(entry.getKey()), entry.getValue());
+ }
+
+ return result;
+ }
+
+ public void put(C collection, K key, V obj) throws IOException {
+ mProvider.put(makeCollectionKey(collection), makeKey(key), obj);
+ }
+
+ /**
+ * Make a collection key for the delegated provider.
+ *
+ * @param input The pre-transform key.
+ * @return the post-transform key.
+ */
+ protected abstract DC makeCollectionKey(final C input);
+
+ /**
+ * Make a key for the delegated provider.
+ *
+ * @param input The pre-transform key.
+ * @return the post-transform key.
+ */
+ protected abstract DK makeKey(final K input);
+
+ /**
+ * Transform a key for the delegated provider to an input key.
+ *
+ * @param input The post-transform key.
+ * @return the pre-transform key.
+ */
+ protected abstract K unmakeKey(final DK input);
+}
diff --git a/src/com/p4square/grow/provider/DelegateProvider.java b/src/com/p4square/grow/provider/DelegateProvider.java
index 66c5666..42dcc63 100644
--- a/src/com/p4square/grow/provider/DelegateProvider.java
+++ b/src/com/p4square/grow/provider/DelegateProvider.java
@@ -31,10 +31,10 @@ public abstract class DelegateProvider<K, D, V> implements Provider<K, V> {
}
/**
- * Make a Key for questionId.
+ * Make a Key for the delegated provider.
*
- * @param questionId The question id.
- * @return a key for questionId.
+ * @param input The pre-transform key.
+ * @return the post-transform key.
*/
protected abstract D makeKey(final K input);
}
diff --git a/src/com/p4square/grow/provider/JsonEncodedProvider.java b/src/com/p4square/grow/provider/JsonEncodedProvider.java
index 7ae3f71..7651443 100644
--- a/src/com/p4square/grow/provider/JsonEncodedProvider.java
+++ b/src/com/p4square/grow/provider/JsonEncodedProvider.java
@@ -25,8 +25,8 @@ public abstract class JsonEncodedProvider<V> {
MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
- private final Class<V> mClazz;
- private final JavaType mType;
+ protected final Class<V> mClazz;
+ protected final JavaType mType;
public JsonEncodedProvider(Class<V> clazz) {
mClazz = clazz;
diff --git a/src/com/p4square/grow/provider/ProvidesAssessments.java b/src/com/p4square/grow/provider/ProvidesAssessments.java
new file mode 100644
index 0000000..62ba8f6
--- /dev/null
+++ b/src/com/p4square/grow/provider/ProvidesAssessments.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2014 Jesse Morgan
+ */
+
+package com.p4square.grow.provider;
+
+import com.p4square.grow.model.RecordedAnswer;
+
+/**
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public interface ProvidesAssessments {
+ /**
+ * Provides a collection of user assessments.
+ * The collection key is the user id.
+ * The key is the question id.
+ */
+ CollectionProvider<String, String, String> getAnswerProvider();
+}
diff --git a/src/com/p4square/grow/provider/ProvidesStrings.java b/src/com/p4square/grow/provider/ProvidesStrings.java
new file mode 100644
index 0000000..5d9976e
--- /dev/null
+++ b/src/com/p4square/grow/provider/ProvidesStrings.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2014 Jesse Morgan
+ */
+
+package com.p4square.grow.provider;
+
+/**
+ * Indicates the ability to provide a String provider.
+ *
+ * Strings are typically configuration settings stored as a String.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public interface ProvidesStrings {
+ /**
+ * @return A Provider of Questions keyed by question id.
+ */
+ Provider<String, String> getStringProvider();
+} \ No newline at end of file
diff --git a/src/com/p4square/grow/provider/ProvidesTrainingRecords.java b/src/com/p4square/grow/provider/ProvidesTrainingRecords.java
index 27ffa3e..586e649 100644
--- a/src/com/p4square/grow/provider/ProvidesTrainingRecords.java
+++ b/src/com/p4square/grow/provider/ProvidesTrainingRecords.java
@@ -4,7 +4,10 @@
package com.p4square.grow.provider;
+import java.io.IOException;
+
import com.p4square.grow.model.TrainingRecord;
+import com.p4square.grow.model.Playlist;
/**
* Indicates the ability to provide a TrainingRecord Provider.
@@ -16,4 +19,9 @@ public interface ProvidesTrainingRecords {
* @return A Provider of Questions keyed by question id.
*/
Provider<String, TrainingRecord> getTrainingRecordProvider();
+
+ /**
+ * @return the Default Playlist.
+ */
+ Playlist getDefaultPlaylist() throws IOException;
}
diff --git a/src/com/p4square/grow/provider/ProvidesVideos.java b/src/com/p4square/grow/provider/ProvidesVideos.java
new file mode 100644
index 0000000..3d055d3
--- /dev/null
+++ b/src/com/p4square/grow/provider/ProvidesVideos.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2014 Jesse Morgan
+ */
+
+package com.p4square.grow.provider;
+
+/**
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public interface ProvidesVideos {
+ /**
+ * @return A Provider of Questions keyed by question id.
+ */
+ CollectionProvider<String, String, String> getVideoProvider();
+}