diff options
Diffstat (limited to 'src/com/p4square/grow/backend')
25 files changed, 0 insertions, 3313 deletions
diff --git a/src/com/p4square/grow/backend/BackendVerifier.java b/src/com/p4square/grow/backend/BackendVerifier.java deleted file mode 100644 index 83160a9..0000000 --- a/src/com/p4square/grow/backend/BackendVerifier.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2014 Jesse Morgan - */ - -package com.p4square.grow.backend; - -import java.io.IOException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import org.apache.commons.codec.binary.Hex; - -import org.restlet.security.SecretVerifier; - -import com.p4square.grow.model.UserRecord; -import com.p4square.grow.provider.Provider; - -/** - * Verify the given credentials against the users with backend access. - */ -public class BackendVerifier extends SecretVerifier { - - private final Provider<String, UserRecord> mUserProvider; - - public BackendVerifier(Provider<String, UserRecord> userProvider) { - mUserProvider = userProvider; - } - - @Override - public int verify(String identifier, char[] secret) { - if (identifier == null) { - throw new IllegalArgumentException("Null identifier"); - } - - if (secret == null) { - throw new IllegalArgumentException("Null secret"); - } - - // Does the user exist? - UserRecord user; - try { - user = mUserProvider.get(identifier); - if (user == null) { - return RESULT_UNKNOWN; - } - - } catch (IOException e) { - return RESULT_UNKNOWN; - } - - // Does the user have a backend password? - String storedHash = user.getBackendPasswordHash(); - if (storedHash == null) { - // This user doesn't have access - return RESULT_INVALID; - } - - // Validate the password. - try { - String hashedInput = hashPassword(secret); - if (hashedInput.equals(storedHash)) { - return RESULT_VALID; - } - - } catch (NoSuchAlgorithmException e) { - return RESULT_UNSUPPORTED; - } - - // If all else fails, fail. - return RESULT_INVALID; - } - - /** - * Hash the given secret. - */ - public static String hashPassword(char[] secret) throws NoSuchAlgorithmException { - MessageDigest md = MessageDigest.getInstance("SHA-1"); - - // Convert the char[] to byte[] - // FIXME This approach is incorrectly truncating multibyte - // characters. - byte[] b = new byte[secret.length]; - for (int i = 0; i < secret.length; i++) { - b[i] = (byte) secret[i]; - } - - md.update(b); - - byte[] hash = md.digest(); - return new String(Hex.encodeHex(hash)); - } -} diff --git a/src/com/p4square/grow/backend/CassandraGrowData.java b/src/com/p4square/grow/backend/CassandraGrowData.java deleted file mode 100644 index 22a7716..0000000 --- a/src/com/p4square/grow/backend/CassandraGrowData.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * 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/DynamoGrowData.java b/src/com/p4square/grow/backend/DynamoGrowData.java deleted file mode 100644 index 3b38eac..0000000 --- a/src/com/p4square/grow/backend/DynamoGrowData.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright 2014 Jesse Morgan - */ - -package com.p4square.grow.backend; - -import java.io.IOException; - -import com.amazonaws.auth.AWSCredentials; - -import com.p4square.grow.backend.dynamo.DynamoDatabase; -import com.p4square.grow.backend.dynamo.DynamoKey; -import com.p4square.grow.backend.dynamo.DynamoProviderImpl; -import com.p4square.grow.backend.dynamo.DynamoCollectionProviderImpl; - -import com.p4square.grow.config.Config; - -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; -import com.p4square.grow.provider.JsonEncodedProvider; - -/** - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -class DynamoGrowData implements GrowData { - private static final String DEFAULT_COLUMN = "value"; - private static final String DEFAULT_PLAYLIST_KEY = "/training/defaultplaylist"; - - private final Config mConfig; - private final DynamoDatabase mDatabase; - - private final Provider<String, UserRecord> mUserRecordProvider; - - private final Provider<String, Question> mQuestionProvider; - private final Provider<String, TrainingRecord> 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 DynamoGrowData(final Config config) { - mConfig = config; - - mDatabase = new DynamoDatabase(config); - - mUserRecordProvider = new DelegateProvider<String, DynamoKey, UserRecord>( - new DynamoProviderImpl<UserRecord>(mDatabase, UserRecord.class)) { - @Override - public DynamoKey makeKey(String userid) { - return DynamoKey.newAttributeKey("accounts", userid, DEFAULT_COLUMN); - } - }; - - mQuestionProvider = new DelegateProvider<String, DynamoKey, Question>( - new DynamoProviderImpl<Question>(mDatabase, Question.class)) { - @Override - public DynamoKey makeKey(String questionId) { - return DynamoKey.newAttributeKey("strings", - "/questions/" + questionId, - DEFAULT_COLUMN); - } - }; - - mFeedThreadProvider = new DynamoCollectionProviderImpl<MessageThread>( - mDatabase, "feedthreads", MessageThread.class); - mFeedMessageProvider = new DynamoCollectionProviderImpl<Message>( - mDatabase, "feedmessages", Message.class); - - mTrainingRecordProvider = new DelegateProvider<String, DynamoKey, TrainingRecord>( - new DynamoProviderImpl<TrainingRecord>(mDatabase, TrainingRecord.class)) { - @Override - public DynamoKey makeKey(String userId) { - return DynamoKey.newAttributeKey("training", - userId, - DEFAULT_COLUMN); - } - }; - - mVideoProvider = new DelegateCollectionProvider<String, String, String, String, String>( - new DynamoCollectionProviderImpl<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, DynamoKey, String>( - new DynamoProviderImpl<String>(mDatabase, String.class)) { - @Override - public DynamoKey makeKey(String id) { - return DynamoKey.newAttributeKey("strings", id, DEFAULT_COLUMN); - } - }; - - mAnswerProvider = new DynamoCollectionProviderImpl<String>( - mDatabase, "assessments", String.class); - } - - @Override - public void start() throws Exception { - } - - @Override - public void stop() throws Exception { - } - - @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 { - String blob = mStringProvider.get(DEFAULT_PLAYLIST_KEY); - if (blob == null) { - return null; - } - - return JsonEncodedProvider.MAPPER.readValue(blob, Playlist.class); - } - - @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 deleted file mode 100644 index 4091138..0000000 --- a/src/com/p4square/grow/backend/GrowBackend.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright 2012 Jesse Morgan - */ - -package com.p4square.grow.backend; - -import java.io.IOException; - -import com.codahale.metrics.MetricRegistry; - -import org.apache.log4j.Logger; - -import org.restlet.Application; -import org.restlet.Component; -import org.restlet.Restlet; -import org.restlet.data.Protocol; -import org.restlet.data.Reference; -import org.restlet.resource.Directory; -import org.restlet.routing.Router; - -import com.p4square.grow.config.Config; - -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.Provider; -import com.p4square.grow.provider.ProvidesQuestions; -import com.p4square.grow.provider.ProvidesTrainingRecords; -import com.p4square.grow.provider.ProvidesUserRecords; - -import com.p4square.grow.backend.resources.AccountResource; -import com.p4square.grow.backend.resources.BannerResource; -import com.p4square.grow.backend.resources.SurveyResource; -import com.p4square.grow.backend.resources.SurveyResultsResource; -import com.p4square.grow.backend.resources.TrainingRecordResource; -import com.p4square.grow.backend.resources.TrainingResource; - -import com.p4square.grow.backend.feed.FeedDataProvider; -import com.p4square.grow.backend.feed.ThreadResource; -import com.p4square.grow.backend.feed.TopicResource; - -import com.p4square.restlet.metrics.MetricRouter; - -/** - * Main class for the backend application. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class GrowBackend extends Application implements GrowData { - - private final static Logger LOG = Logger.getLogger(GrowBackend.class); - - private final MetricRegistry mMetricRegistry; - - private final Config mConfig; - private final GrowData mGrowData; - - public GrowBackend() { - this(new Config(), new MetricRegistry()); - } - - public GrowBackend(Config config, MetricRegistry metricRegistry) { - mConfig = config; - - mMetricRegistry = metricRegistry; - - mGrowData = new DynamoGrowData(config); - } - - public MetricRegistry getMetrics() { - return mMetricRegistry; - } - - @Override - public Restlet createInboundRoot() { - Router router = new MetricRouter(getContext(), mMetricRegistry); - - // Account API - router.attach("/accounts/{userId}", AccountResource.class); - - // Survey API - router.attach("/assessment/question/{questionId}", SurveyResource.class); - - router.attach("/accounts/{userId}/assessment", SurveyResultsResource.class); - router.attach("/accounts/{userId}/assessment/answers/{questionId}", - SurveyResultsResource.class); - - // Training API - router.attach("/training/{level}", TrainingResource.class); - router.attach("/training/{level}/videos/{videoId}", TrainingResource.class); - - router.attach("/accounts/{userId}/training", TrainingRecordResource.class); - router.attach("/accounts/{userId}/training/videos/{videoId}", - TrainingRecordResource.class); - - // Misc. - router.attach("/banner", BannerResource.class); - - // Feed - router.attach("/feed/{topic}", TopicResource.class); - router.attach("/feed/{topic}/{thread}", ThreadResource.class); - //router.attach("/feed/{topic/{thread}/{message}", MessageResource.class); - - router.attachDefault(new Directory(getContext(), new Reference(getClass().getResource("apiinfo.html")))); - - return router; - } - - /** - * Open the database. - */ - @Override - public void start() throws Exception { - super.start(); - - mGrowData.start(); - } - - /** - * Close the database. - */ - @Override - public void stop() throws Exception { - LOG.info("Shutting down..."); - mGrowData.stop(); - - super.stop(); - } - - @Override - public Provider<String, UserRecord> getUserRecordProvider() { - return mGrowData.getUserRecordProvider(); - } - - @Override - public Provider<String, Question> getQuestionProvider() { - return mGrowData.getQuestionProvider(); - } - - @Override - public CollectionProvider<String, String, String> getVideoProvider() { - return mGrowData.getVideoProvider(); - } - - @Override - public Provider<String, TrainingRecord> getTrainingRecordProvider() { - return mGrowData.getTrainingRecordProvider(); - } - - /** - * @return the Default Playlist. - */ - public Playlist getDefaultPlaylist() throws IOException { - return mGrowData.getDefaultPlaylist(); - } - - @Override - public CollectionProvider<String, String, MessageThread> getThreadProvider() { - return mGrowData.getThreadProvider(); - } - - @Override - public CollectionProvider<String, String, Message> getMessageProvider() { - return mGrowData.getMessageProvider(); - } - - @Override - public Provider<String, String> getStringProvider() { - return mGrowData.getStringProvider(); - } - - @Override - public CollectionProvider<String, String, String> getAnswerProvider() { - return mGrowData.getAnswerProvider(); - } - - /** - * Stand-alone main for testing. - */ - public static void main(String[] args) throws Exception { - // Start the HTTP Server - final Component component = new Component(); - component.getServers().add(Protocol.HTTP, 9095); - component.getClients().add(Protocol.HTTP); - component.getDefaultHost().attach(new GrowBackend()); - - // Setup shutdown hook - Runtime.getRuntime().addShutdownHook(new Thread() { - public void run() { - try { - component.stop(); - } catch (Exception e) { - LOG.error("Exception during cleanup", e); - } - } - }); - - LOG.info("Starting server..."); - - try { - component.start(); - } catch (Exception e) { - LOG.fatal("Could not start: " + e.getMessage(), e); - } - } -} diff --git a/src/com/p4square/grow/backend/GrowData.java b/src/com/p4square/grow/backend/GrowData.java deleted file mode 100644 index 293bb88..0000000 --- a/src/com/p4square/grow/backend/GrowData.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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/apiinfo.html b/src/com/p4square/grow/backend/apiinfo.html deleted file mode 100644 index a3637c9..0000000 --- a/src/com/p4square/grow/backend/apiinfo.html +++ /dev/null @@ -1,41 +0,0 @@ -<html> -<head> -<title>API Info</title> -</head> -<body> -<dl> -<dt>/backend/accounts/{userId}</dt> -<dd>GET information about <em>userId</em> or PUT new information.</dd> - -<dt>/backend/assessment/question/{questionId}</dt> -<dd>GET information about <em>questionId</em>. Special <em>questionId</em>s: first identifies first question. count returns total number of questions.</dd> - -<dt>/backend/accounts/{userId}/assessment</dt> -<dd>GET the assessment summary for <em>userId</em> or DELETE <em>userId</em>'s assessment.</dd> - -<dt>/backend/accounts/{userId}/assessment/answers/{questionId}</dt> -<dd>GET <em>userId</em>'s answer to <em>questionId</em>, PUT a new answer, or DELETE an answer.</dd> - -<dt>/backend/training/{level}</dt> -<dd>GET all video information for <em>level</em>.</dd> - -<dt>/backend/training/{level}/videos/{videoId}</dt> -<dd>GET video information for <em>videoId</em> in <em>level</em>.</dd> - -<dt>/backend/accounts/{userId}/training</dt> -<dd>GET training record summary for <em>userId</em>.</dd> - -<dt>/backend/accounts/{userId}/training/videos/{videoId}</dt> -<dd>GET training record for <em>userId</em> and <em>videoId</em> or PUT a new record.</dd> - -<dt>/backend/banner</dt> -<dd>GET the info banner or PUT new banner info.</dd> - -<dt>/backend/feed/{topic}</dt> -<dd>Get all threads for forum <em>topic</em>.</dd> - -<dt>/backend/feed/{topic}/{thread}</dt> -<dd>Get all responses to question <em>thread</em> on forum <em>topic</em>.</dd> -</dl> -</body> -</html> diff --git a/src/com/p4square/grow/backend/db/CassandraCollectionProvider.java b/src/com/p4square/grow/backend/db/CassandraCollectionProvider.java deleted file mode 100644 index bfcb48d..0000000 --- a/src/com/p4square/grow/backend/db/CassandraCollectionProvider.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.grow.backend.db; - -import java.io.IOException; - -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; - -import com.netflix.astyanax.model.Column; -import com.netflix.astyanax.model.ColumnList; - -import com.p4square.grow.provider.CollectionProvider; -import com.p4square.grow.provider.JsonEncodedProvider; - -/** - * CollectionProvider implementation backed by a Cassandra ColumnFamily. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class CassandraCollectionProvider<V> implements CollectionProvider<String, String, V> { - private final CassandraDatabase mDb; - private final String mCF; - private final Class<V> mClazz; - - public CassandraCollectionProvider(CassandraDatabase db, String columnFamily, Class<V> clazz) { - mDb = db; - mCF = columnFamily; - mClazz = clazz; - } - - @Override - public V get(String collection, String key) throws IOException { - String blob = mDb.getKey(mCF, collection, key); - return decode(blob); - } - - @Override - public Map<String, V> query(String collection) throws IOException { - return query(collection, -1); - } - - @Override - public Map<String, V> query(String collection, int limit) throws IOException { - Map<String, V> result = new LinkedHashMap<>(); - - ColumnList<String> row = mDb.getRow(mCF, collection); - if (!row.isEmpty()) { - int count = 0; - for (Column<String> c : row) { - if (limit >= 0 && ++count > limit) { - break; // Limit reached. - } - - String key = c.getName(); - String blob = c.getStringValue(); - V obj = decode(blob); - - result.put(key, obj); - } - } - - return Collections.unmodifiableMap(result); - } - - @Override - public void put(String collection, String key, V obj) throws IOException { - String blob = encode(obj); - mDb.putKey(mCF, collection, key, blob); - } - - /** - * Encode the object as JSON. - * - * @param obj The object to encode. - * @return The JSON encoding of obj. - * @throws IOException if the object cannot be encoded. - */ - protected String encode(V obj) throws IOException { - if (mClazz == String.class) { - return (String) obj; - } else { - return JsonEncodedProvider.MAPPER.writeValueAsString(obj); - } - } - - /** - * Decode the JSON string as an object. - * - * @param blob The JSON data to decode. - * @return The decoded object or null if blob is null. - * @throws IOException If an object cannot be decoded. - */ - protected V decode(String blob) throws IOException { - if (blob == null) { - 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/CassandraDatabase.java b/src/com/p4square/grow/backend/db/CassandraDatabase.java deleted file mode 100644 index b8cb6df..0000000 --- a/src/com/p4square/grow/backend/db/CassandraDatabase.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.grow.backend.db; - -import com.netflix.astyanax.AstyanaxContext; -import com.netflix.astyanax.connectionpool.exceptions.ConnectionException; -import com.netflix.astyanax.connectionpool.impl.ConnectionPoolConfigurationImpl; -import com.netflix.astyanax.connectionpool.impl.CountingConnectionPoolMonitor; -import com.netflix.astyanax.connectionpool.NodeDiscoveryType; -import com.netflix.astyanax.connectionpool.OperationResult; -import com.netflix.astyanax.impl.AstyanaxConfigurationImpl; -import com.netflix.astyanax.Keyspace; -import com.netflix.astyanax.ColumnMutation; -import com.netflix.astyanax.model.Column; -import com.netflix.astyanax.model.ColumnFamily; -import com.netflix.astyanax.model.ColumnList; -import com.netflix.astyanax.ColumnListMutation; -import com.netflix.astyanax.MutationBatch; -import com.netflix.astyanax.serializers.StringSerializer; -import com.netflix.astyanax.thrift.ThriftFamilyFactory; - -import org.apache.log4j.Logger; - -/** - * Cassandra Database Abstraction for the Backend. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class CassandraDatabase { - private static Logger cLog = Logger.getLogger(CassandraDatabase.class); - - // Configuration fields. - private String mClusterName; - private String mKeyspaceName; - private String mSeedEndpoint = "127.0.0.1:9160"; - private int mPort = 9160; - - private AstyanaxContext<Keyspace> mContext; - private Keyspace mKeyspace; - - /** - * Connect to Cassandra. - * - * Cluster and Keyspace must be set before calling init(). - */ - public void init() { - mContext = new AstyanaxContext.Builder() - .forCluster(mClusterName) - .forKeyspace(mKeyspaceName) - .withAstyanaxConfiguration(new AstyanaxConfigurationImpl() - .setDiscoveryType(NodeDiscoveryType.RING_DESCRIBE) - ) - .withConnectionPoolConfiguration(new ConnectionPoolConfigurationImpl("MyConnectionPool") - .setPort(mPort) - .setMaxConnsPerHost(1) - .setSeeds(mSeedEndpoint) - ) - .withConnectionPoolMonitor(new CountingConnectionPoolMonitor()) - .buildKeyspace(ThriftFamilyFactory.getInstance()); - - mContext.start(); - mKeyspace = mContext.getClient(); - } - - /** - * Close the database connection. - */ - public void close() { - mContext.shutdown(); - } - - /** - * Set the cluster name to connect to. - */ - public void setClusterName(final String cluster) { - mClusterName = cluster; - } - - /** - * Set the name of the keyspace to open. - */ - public void setKeyspaceName(final String keyspace) { - mKeyspaceName = keyspace; - } - - /** - * Change the seed endpoint. - * The default is 127.0.0.1:9160. - */ - public void setSeedEndpoint(final String endpoint) { - mSeedEndpoint = endpoint; - } - - /** - * Change the port to connect to. - * The default is 9160. - */ - public void setPort(final int port) { - mPort = port; - } - - /** - * @return The entire row associated with this key. - */ - public ColumnList<String> getRow(final String cfName, final String key) { - try { - ColumnFamily<String, String> cf = new ColumnFamily(cfName, - StringSerializer.get(), - StringSerializer.get()); - - OperationResult<ColumnList<String>> result = - mKeyspace.prepareQuery(cf) - .getKey(key) - .execute(); - - return result.getResult(); - - } catch (ConnectionException e) { - cLog.error("getRow failed due to Connection Exception", e); - throw new RuntimeException(e); - } - } - - /** - * @return The value associated with the given key. - */ - public String getKey(final String cfName, final String key) { - return getKey(cfName, key, "value"); - } - - /** - * @return The value associated with the given key, column pair. - */ - public String getKey(final String cfName, final String key, final String column) { - final ColumnList<String> row = getRow(cfName, key); - - if (row != null) { - final Column rowColumn = row.getColumnByName(column); - if (rowColumn != null) { - return rowColumn.getStringValue(); - } - } - - return null; - } - - /** - * Assign value to key. - */ - public void putKey(final String cfName, final String key, final String value) { - putKey(cfName, key, "value", value); - } - - /** - * Assign value to the key, column pair. - */ - public void putKey(final String cfName, final String key, - final String column, final String value) { - - ColumnFamily<String, String> cf = new ColumnFamily(cfName, - StringSerializer.get(), - StringSerializer.get()); - - MutationBatch m = mKeyspace.prepareMutationBatch(); - m.withRow(cf, key).putColumn(column, value); - - try { - m.execute(); - } catch (ConnectionException e) { - cLog.error("putKey failed due to Connection Exception", e); - throw new RuntimeException(e); - } - } - - /** - * Remove a key, column pair. - */ - public void deleteKey(final String cfName, final String key, final String column) { - ColumnFamily<String, String> cf = new ColumnFamily(cfName, - StringSerializer.get(), - StringSerializer.get()); - - try { - ColumnMutation m = mKeyspace.prepareColumnMutation(cf, key, column); - m.deleteColumn().execute(); - } catch (ConnectionException e) { - cLog.error("deleteKey failed due to Connection Exception", e); - throw new RuntimeException(e); - } - } - - /** - * Remove a row - */ - public void deleteRow(final String cfName, final String key) { - ColumnFamily<String, String> cf = new ColumnFamily(cfName, - StringSerializer.get(), - StringSerializer.get()); - - try { - MutationBatch batch = mKeyspace.prepareMutationBatch(); - ColumnListMutation<String> cfm = batch.withRow(cf, key).delete(); - batch.execute(); - - } catch (ConnectionException e) { - cLog.error("deleteRow failed due to Connection Exception", e); - throw new RuntimeException(e); - } - } -} diff --git a/src/com/p4square/grow/backend/db/CassandraKey.java b/src/com/p4square/grow/backend/db/CassandraKey.java deleted file mode 100644 index 853fe96..0000000 --- a/src/com/p4square/grow/backend/db/CassandraKey.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.grow.backend.db; - -/** - * CassandraKey represents a Cassandra key / column pair. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class CassandraKey { - private final String mColumnFamily; - private final String mId; - private final String mColumn; - - public CassandraKey(String columnFamily, String id, String column) { - mColumnFamily = columnFamily; - mId = id; - mColumn = column; - } - - public String getColumnFamily() { - return mColumnFamily; - } - - public String getId() { - return mId; - } - - public String getColumn() { - return mColumn; - } -} diff --git a/src/com/p4square/grow/backend/db/CassandraProviderImpl.java b/src/com/p4square/grow/backend/db/CassandraProviderImpl.java deleted file mode 100644 index da5a9f2..0000000 --- a/src/com/p4square/grow/backend/db/CassandraProviderImpl.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.grow.backend.db; - -import java.io.IOException; - -import com.p4square.grow.provider.Provider; -import com.p4square.grow.provider.JsonEncodedProvider; - -/** - * Provider implementation backed by a Cassandra ColumnFamily. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class CassandraProviderImpl<V> extends JsonEncodedProvider<V> implements Provider<CassandraKey, V> { - private final CassandraDatabase mDb; - - public CassandraProviderImpl(CassandraDatabase db, Class<V> clazz) { - super(clazz); - - mDb = db; - } - - @Override - public V get(CassandraKey key) throws IOException { - String blob = mDb.getKey(key.getColumnFamily(), key.getId(), key.getColumn()); - return decode(blob); - } - - @Override - public void put(CassandraKey key, V obj) throws IOException { - String blob = encode(obj); - mDb.putKey(key.getColumnFamily(), key.getId(), key.getColumn(), blob); - } -} diff --git a/src/com/p4square/grow/backend/db/CassandraTrainingRecordProvider.java b/src/com/p4square/grow/backend/db/CassandraTrainingRecordProvider.java deleted file mode 100644 index 4face52..0000000 --- a/src/com/p4square/grow/backend/db/CassandraTrainingRecordProvider.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.grow.backend.db; - -import java.io.IOException; - -import com.p4square.grow.model.Playlist; -import com.p4square.grow.model.TrainingRecord; - -import com.p4square.grow.provider.JsonEncodedProvider; -import com.p4square.grow.provider.Provider; - -/** - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class CassandraTrainingRecordProvider implements Provider<String, TrainingRecord> { - private static final CassandraKey DEFAULT_PLAYLIST_KEY = new CassandraKey("strings", "defaultPlaylist", "value"); - - private static final String COLUMN_FAMILY = "training"; - private static final String PLAYLIST_KEY = "playlist"; - private static final String LAST_VIDEO_KEY = "lastVideo"; - - private final CassandraDatabase mDb; - private final Provider<CassandraKey, Playlist> mPlaylistProvider; - - public CassandraTrainingRecordProvider(CassandraDatabase db) { - mDb = db; - mPlaylistProvider = new CassandraProviderImpl<>(db, Playlist.class); - } - - @Override - public TrainingRecord get(String userid) throws IOException { - Playlist playlist = mPlaylistProvider.get(new CassandraKey(COLUMN_FAMILY, userid, PLAYLIST_KEY)); - - if (playlist == null) { - // We consider no playlist to mean no record whatsoever. - return null; - } - - TrainingRecord r = new TrainingRecord(); - r.setPlaylist(playlist); - r.setLastVideo(mDb.getKey(COLUMN_FAMILY, userid, LAST_VIDEO_KEY)); - - return r; - } - - @Override - public void put(String userid, TrainingRecord record) throws IOException { - String lastVideo = record.getLastVideo(); - Playlist playlist = record.getPlaylist(); - - mDb.putKey(COLUMN_FAMILY, userid, LAST_VIDEO_KEY, lastVideo); - mPlaylistProvider.put(new CassandraKey(COLUMN_FAMILY, userid, PLAYLIST_KEY), playlist); - } - - /** - * @return the default playlist stored in the database. - */ - public Playlist getDefaultPlaylist() throws IOException { - Playlist playlist = mPlaylistProvider.get(DEFAULT_PLAYLIST_KEY); - - if (playlist == null) { - playlist = new Playlist(); - } - - return playlist; - } -} diff --git a/src/com/p4square/grow/backend/dynamo/DbTool.java b/src/com/p4square/grow/backend/dynamo/DbTool.java deleted file mode 100644 index 374fa83..0000000 --- a/src/com/p4square/grow/backend/dynamo/DbTool.java +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Copyright 2014 Jesse Morgan - */ - -package com.p4square.grow.backend.dynamo; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; - -import com.p4square.grow.backend.dynamo.DynamoDatabase; -import com.p4square.grow.backend.dynamo.DynamoKey; -import com.p4square.grow.config.Config; -import com.p4square.grow.model.UserRecord; -import com.p4square.grow.provider.Provider; - -/** - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class DbTool { - private static final FilenameFilter JSON_FILTER = new JsonFilter(); - - private static Config mConfig; - private static DynamoDatabase mDatabase; - - public static void usage() { - System.out.println("java com.p4square.grow.backend.dynamo.DbTool <command>...\n"); - System.out.println("Commands:"); - System.out.println("\t--domain <domain> Set config domain"); - System.out.println("\t--dev Set config domain to dev"); - System.out.println("\t--config <file> Merge in config file"); - System.out.println("\t--list List all tables"); - System.out.println("\t--create <table> <reads> <writes> Create a table"); - System.out.println("\t--update <table> <reads> <writes> Update table throughput"); - System.out.println("\t--drop <table> Delete a table"); - System.out.println("\t--get <table> <key> <attribute> Get a value"); - System.out.println("\t--put <table> <key> <attribute> <value> Put a value"); - System.out.println("\t--delete <table> <key> <attribute> Delete a value"); - System.out.println("\t--scan <table> List all rows"); - System.out.println("\t--scanf <table> <attribute> List all rows"); - System.out.println(); - System.out.println("Bootstrap Commands:"); - System.out.println("\t--bootstrap <data> Create all tables and import all data"); - System.out.println("\t--loadStrings <data> Load all videos and questions"); - System.out.println("\t--destroy Drop all tables"); - System.out.println("\t--addadmin <user> <pass> Add a backend account"); - System.out.println("\t--import <table> <file> Backfill a table"); - } - - public static void main(String... args) { - if (args.length == 0) { - usage(); - System.exit(1); - } - - mConfig = new Config(); - - try { - mConfig.updateConfig(DbTool.class.getResourceAsStream("/grow.properties")); - - int offset = 0; - while (offset < args.length) { - if ("--domain".equals(args[offset])) { - mConfig.setDomain(args[offset + 1]); - mDatabase = null; - offset += 2; - - } else if ("--dev".equals(args[offset])) { - mConfig.setDomain("dev"); - mDatabase = null; - offset += 1; - - } else if ("--config".equals(args[offset])) { - mConfig.updateConfig(args[offset + 1]); - mDatabase = null; - offset += 2; - - } else if ("--list".equals(args[offset])) { - //offset = list(args, ++offset); - - } else if ("--create".equals(args[offset])) { - offset = create(args, ++offset); - - } else if ("--update".equals(args[offset])) { - offset = update(args, ++offset); - - } else if ("--drop".equals(args[offset])) { - offset = drop(args, ++offset); - - } else if ("--get".equals(args[offset])) { - offset = get(args, ++offset); - - } else if ("--put".equals(args[offset])) { - offset = put(args, ++offset); - - } else if ("--delete".equals(args[offset])) { - offset = delete(args, ++offset); - - } else if ("--scan".equals(args[offset])) { - offset = scan(args, ++offset); - - } else if ("--scanf".equals(args[offset])) { - offset = scanf(args, ++offset); - - /* Bootstrap Commands */ - } else if ("--bootstrap".equals(args[offset])) { - if ("dev".equals(mConfig.getDomain())) { - offset = bootstrapDevTables(args, ++offset); - } else { - offset = bootstrapTables(args, ++offset); - } - offset = loadStrings(args, offset); - - } else if ("--loadStrings".equals(args[offset])) { - offset = loadStrings(args, ++offset); - - } else if ("--destroy".equals(args[offset])) { - offset = destroy(args, ++offset); - - } else if ("--addadmin".equals(args[offset])) { - offset = addAdmin(args, ++offset); - - } else if ("--import".equals(args[offset])) { - offset = importTable(args, ++offset); - - } else { - throw new IllegalArgumentException("Unknown command " + args[offset]); - } - } - } catch (Exception e) { - e.printStackTrace(); - System.exit(2); - } - } - - private static DynamoDatabase getDatabase() { - if (mDatabase == null) { - mDatabase = new DynamoDatabase(mConfig); - } - - return mDatabase; - } - - private static int create(String[] args, int offset) { - String name = args[offset++]; - long reads = Long.parseLong(args[offset++]); - long writes = Long.parseLong(args[offset++]); - - DynamoDatabase db = getDatabase(); - - db.createTable(name, reads, writes); - - return offset; - } - - private static int update(String[] args, int offset) { - String name = args[offset++]; - long reads = Long.parseLong(args[offset++]); - long writes = Long.parseLong(args[offset++]); - - DynamoDatabase db = getDatabase(); - - db.updateTable(name, reads, writes); - - return offset; - } - - private static int drop(String[] args, int offset) { - String name = args[offset++]; - - DynamoDatabase db = getDatabase(); - - db.deleteTable(name); - - return offset; - } - - private static int get(String[] args, int offset) { - String table = args[offset++]; - String key = args[offset++]; - String attribute = args[offset++]; - - DynamoDatabase db = getDatabase(); - - String value = db.getAttribute(DynamoKey.newAttributeKey(table, key, attribute)); - - if (value == null) { - value = "<null>"; - } - - System.out.printf("%s %s:%s\n%s\n\n", table, key, attribute, value); - - return offset; - } - - private static int put(String[] args, int offset) { - String table = args[offset++]; - String key = args[offset++]; - String attribute = args[offset++]; - String value = args[offset++]; - - DynamoDatabase db = getDatabase(); - - db.putAttribute(DynamoKey.newAttributeKey(table, key, attribute), value); - - return offset; - } - - private static int delete(String[] args, int offset) { - String table = args[offset++]; - String key = args[offset++]; - String attribute = args[offset++]; - - DynamoDatabase db = getDatabase(); - - db.deleteAttribute(DynamoKey.newAttributeKey(table, key, attribute)); - - System.out.printf("Deleted %s %s:%s\n\n", table, key, attribute); - - return offset; - } - - private static int scan(String[] args, int offset) { - String table = args[offset++]; - - DynamoKey key = DynamoKey.newKey(table, null); - - doScan(key); - - return offset; - } - - private static int scanf(String[] args, int offset) { - String table = args[offset++]; - String attribute = args[offset++]; - - DynamoKey key = DynamoKey.newAttributeKey(table, null, attribute); - - doScan(key); - - return offset; - } - - private static void doScan(DynamoKey key) { - DynamoDatabase db = getDatabase(); - - String attributeFilter = key.getAttribute(); - - while (key != null) { - Map<DynamoKey, Map<String, String>> result = db.getAll(key); - - key = null; // If there are no results, exit - - for (Map.Entry<DynamoKey, Map<String, String>> entry : result.entrySet()) { - key = entry.getKey(); // Save the last key - - for (Map.Entry<String, String> attribute : entry.getValue().entrySet()) { - if (attributeFilter == null || attributeFilter.equals(attribute.getKey())) { - String keyString = key.getHashKey(); - if (key.getRangeKey() != null) { - keyString += "(" + key.getRangeKey() + ")"; - } - System.out.printf("%s %s:%s\n%s\n\n", - key.getTable(), keyString, attribute.getKey(), - attribute.getValue()); - } - } - } - } - } - - - private static int bootstrapTables(String[] args, int offset) { - DynamoDatabase db = getDatabase(); - - db.createTable("strings", 5, 1); - db.createTable("accounts", 5, 1); - db.createTable("assessments", 5, 5); - db.createTable("training", 5, 5); - db.createTable("feedthreads", 5, 1); - db.createTable("feedmessages", 5, 1); - - return offset; - } - - private static int bootstrapDevTables(String[] args, int offset) { - DynamoDatabase db = getDatabase(); - - db.createTable("strings", 1, 1); - db.createTable("accounts", 1, 1); - db.createTable("assessments", 1, 1); - db.createTable("training", 1, 1); - db.createTable("feedthreads", 1, 1); - db.createTable("feedmessages", 1, 1); - - return offset; - } - - private static int loadStrings(String[] args, int offset) throws IOException { - String data = args[offset++]; - File baseDir = new File(data); - - DynamoDatabase db = getDatabase(); - - insertQuestions(baseDir); - insertVideos(baseDir); - insertDefaultPlaylist(baseDir); - - return offset; - } - - private static int destroy(String[] args, int offset) { - DynamoDatabase db = getDatabase(); - - final String[] tables = { "strings", - "accounts", - "assessments", - "training", - "feedthreads", - "feedmessages" - }; - - for (String table : tables) { - try { - db.deleteTable(table); - } catch (Exception e) { - System.err.println("Deleting " + table + ": " + e.getMessage()); - } - } - - return offset; - } - - private static int addAdmin(String[] args, int offset) throws IOException { - String user = args[offset++]; - String pass = args[offset++]; - - DynamoDatabase db = getDatabase(); - - UserRecord record = new UserRecord(); - record.setId(user); - record.setBackendPassword(pass); - - Provider<DynamoKey, UserRecord> provider = new DynamoProviderImpl(db, UserRecord.class); - provider.put(DynamoKey.newAttributeKey("accounts", user, "value"), record); - - return offset; - } - - private static int importTable(String[] args, int offset) throws IOException { - String table = args[offset++]; - String filename = args[offset++]; - - DynamoDatabase db = getDatabase(); - - List<String> lines = Files.readAllLines(new File(filename).toPath(), - StandardCharsets.UTF_8); - - int count = 0; - - String key = null; - Map<String, String> attributes = new HashMap<>(); - for (String line : lines) { - if (line.length() == 0) { - if (attributes.size() > 0) { - db.putKey(DynamoKey.newKey(table, key), attributes); - count++; - - if (count % 50 == 0) { - System.out.printf("Imported %d records into %s...\n", count, table); - } - } - key = null; - attributes = new HashMap<>(); - continue; - } - - if (key == null) { - key = line; - continue; - } - - int space = line.indexOf(' '); - String attribute = line.substring(0, space); - String value = line.substring(space + 1); - - attributes.put(attribute, value); - } - - // Finish up the remaining attributes. - if (key != null && attributes.size() > 0) { - db.putKey(DynamoKey.newKey(table, key), attributes); - count++; - } - - System.out.printf("Imported %d records into %s.\n", count, table); - - return offset; - } - - private static void insertQuestions(File baseDir) throws IOException { - DynamoDatabase db = getDatabase(); - File questions = new File(baseDir, "questions"); - - File[] files = questions.listFiles(JSON_FILTER); - Arrays.sort(files); - - for (File file : files) { - String filename = file.getName(); - String questionId = filename.substring(0, filename.lastIndexOf('.')); - - byte[] encoded = Files.readAllBytes(file.toPath()); - String value = new String(encoded, StandardCharsets.UTF_8); - db.putAttribute(DynamoKey.newAttributeKey("strings", - "/questions/" + questionId, "value"), value); - System.out.println("Inserted /questions/" + questionId); - } - - String filename = files[0].getName(); - String first = filename.substring(0, filename.lastIndexOf('.')); - int count = files.length; - String summary = "{\"first\": \"" + first + "\", \"count\": " + count + "}"; - db.putAttribute(DynamoKey.newAttributeKey("strings", "/questions", "value"), summary); - System.out.println("Inserted /questions"); - } - - private static void insertVideos(File baseDir) throws IOException { - DynamoDatabase db = getDatabase(); - File videos = new File(baseDir, "videos"); - - for (File topic : videos.listFiles()) { - if (!topic.isDirectory()) { - continue; - } - - String topicName = topic.getName(); - - Map<String, String> attributes = new HashMap<>(); - File[] files = topic.listFiles(JSON_FILTER); - for (File file : files) { - String filename = file.getName(); - String videoId = filename.substring(0, filename.lastIndexOf('.')); - - byte[] encoded = Files.readAllBytes(file.toPath()); - String value = new String(encoded, StandardCharsets.UTF_8); - - attributes.put(videoId, value); - System.out.println("Found /training/" + topicName + ":" + videoId); - } - - db.putKey(DynamoKey.newKey("strings", - "/training/" + topicName), attributes); - System.out.println("Inserted /training/" + topicName); - } - } - - private static void insertDefaultPlaylist(File baseDir) throws IOException { - DynamoDatabase db = getDatabase(); - File file = new File(baseDir, "videos/playlist.json"); - - byte[] encoded = Files.readAllBytes(file.toPath()); - String value = new String(encoded, StandardCharsets.UTF_8); - db.putAttribute(DynamoKey.newAttributeKey("strings", - "/training/defaultplaylist", "value"), value); - System.out.println("Inserted /training/defaultplaylist"); - } - - private static class JsonFilter implements FilenameFilter { - @Override - public boolean accept(File dir, String name) { - return name.endsWith(".json"); - } - } -} diff --git a/src/com/p4square/grow/backend/dynamo/DynamoCollectionProviderImpl.java b/src/com/p4square/grow/backend/dynamo/DynamoCollectionProviderImpl.java deleted file mode 100644 index b53e9f7..0000000 --- a/src/com/p4square/grow/backend/dynamo/DynamoCollectionProviderImpl.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2014 Jesse Morgan - */ - -package com.p4square.grow.backend.dynamo; - -import java.io.IOException; - -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; - -import com.p4square.grow.provider.CollectionProvider; -import com.p4square.grow.provider.JsonEncodedProvider; - -/** - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class DynamoCollectionProviderImpl<V> implements CollectionProvider<String, String, V> { - private final DynamoDatabase mDb; - private final String mTable; - private final Class<V> mClazz; - - public DynamoCollectionProviderImpl(DynamoDatabase db, String table, Class<V> clazz) { - mDb = db; - mTable = table; - mClazz = clazz; - } - - @Override - public V get(String collection, String key) throws IOException { - String blob = mDb.getAttribute(DynamoKey.newAttributeKey(mTable, collection, key)); - return decode(blob); - } - - @Override - public Map<String, V> query(String collection) throws IOException { - return query(collection, -1); - } - - @Override - public Map<String, V> query(String collection, int limit) throws IOException { - Map<String, V> result = new LinkedHashMap<>(); - - Map<String, String> row = mDb.getKey(DynamoKey.newKey(mTable, collection)); - if (row.size() > 0) { - int count = 0; - for (Map.Entry<String, String> c : row.entrySet()) { - if (limit >= 0 && ++count > limit) { - break; // Limit reached. - } - - String key = c.getKey(); - String blob = c.getValue(); - V obj = decode(blob); - - result.put(key, obj); - } - } - - return Collections.unmodifiableMap(result); - } - - @Override - public void put(String collection, String key, V obj) throws IOException { - if (obj == null) { - mDb.deleteAttribute(DynamoKey.newAttributeKey(mTable, collection, key)); - } else { - String blob = encode(obj); - mDb.putAttribute(DynamoKey.newAttributeKey(mTable, collection, key), blob); - } - } - - /** - * Encode the object as JSON. - * - * @param obj The object to encode. - * @return The JSON encoding of obj. - * @throws IOException if the object cannot be encoded. - */ - protected String encode(V obj) throws IOException { - if (mClazz == String.class) { - return (String) obj; - } else { - return JsonEncodedProvider.MAPPER.writeValueAsString(obj); - } - } - - /** - * Decode the JSON string as an object. - * - * @param blob The JSON data to decode. - * @return The decoded object or null if blob is null. - * @throws IOException If an object cannot be decoded. - */ - protected V decode(String blob) throws IOException { - if (blob == null) { - 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/dynamo/DynamoDatabase.java b/src/com/p4square/grow/backend/dynamo/DynamoDatabase.java deleted file mode 100644 index 68a165d..0000000 --- a/src/com/p4square/grow/backend/dynamo/DynamoDatabase.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright 2014 Jesse Morgan - */ - -package com.p4square.grow.backend.dynamo; - -import java.util.Arrays; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; - -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; -import com.amazonaws.regions.Region; -import com.amazonaws.regions.Regions; -import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient; -import com.amazonaws.services.dynamodbv2.model.AttributeAction; -import com.amazonaws.services.dynamodbv2.model.AttributeDefinition; -import com.amazonaws.services.dynamodbv2.model.AttributeValue; -import com.amazonaws.services.dynamodbv2.model.AttributeValueUpdate; -import com.amazonaws.services.dynamodbv2.model.CreateTableRequest; -import com.amazonaws.services.dynamodbv2.model.CreateTableResult; -import com.amazonaws.services.dynamodbv2.model.DeleteItemRequest; -import com.amazonaws.services.dynamodbv2.model.DeleteItemResult; -import com.amazonaws.services.dynamodbv2.model.DeleteTableRequest; -import com.amazonaws.services.dynamodbv2.model.DeleteTableResult; -import com.amazonaws.services.dynamodbv2.model.GetItemRequest; -import com.amazonaws.services.dynamodbv2.model.GetItemResult; -import com.amazonaws.services.dynamodbv2.model.KeySchemaElement; -import com.amazonaws.services.dynamodbv2.model.KeyType; -import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput; -import com.amazonaws.services.dynamodbv2.model.PutItemRequest; -import com.amazonaws.services.dynamodbv2.model.PutItemResult; -import com.amazonaws.services.dynamodbv2.model.ScanRequest; -import com.amazonaws.services.dynamodbv2.model.ScanResult; -import com.amazonaws.services.dynamodbv2.model.UpdateItemRequest; -import com.amazonaws.services.dynamodbv2.model.UpdateItemResult; -import com.amazonaws.services.dynamodbv2.model.UpdateTableRequest; -import com.amazonaws.services.dynamodbv2.model.UpdateTableResult; - -import com.p4square.grow.config.Config; - -/** - * A wrapper around the Dynamo API. - */ -public class DynamoDatabase { - private final AmazonDynamoDBClient mClient; - private final String mTablePrefix; - - public DynamoDatabase(final Config config) { - AWSCredentials creds; - - String awsAccessKey = config.getString("awsAccessKey"); - if (awsAccessKey != null) { - creds = new AWSCredentials() { - @Override - public String getAWSAccessKeyId() { - return config.getString("awsAccessKey"); - } - @Override - public String getAWSSecretKey() { - return config.getString("awsSecretKey"); - } - }; - } else { - creds = new DefaultAWSCredentialsProviderChain().getCredentials(); - } - - mClient = new AmazonDynamoDBClient(creds); - - String endpoint = config.getString("dynamoEndpoint"); - if (endpoint != null) { - mClient.setEndpoint(endpoint); - } - - String region = config.getString("awsRegion"); - if (region != null) { - mClient.setRegion(Region.getRegion(Regions.fromName(region))); - } - - mTablePrefix = config.getString("dynamoTablePrefix", ""); - } - - public void createTable(String name, long reads, long writes) { - ArrayList<AttributeDefinition> attributeDefinitions = new ArrayList<>(); - attributeDefinitions.add(new AttributeDefinition() - .withAttributeName("id") - .withAttributeType("S")); - - ArrayList<KeySchemaElement> ks = new ArrayList<>(); - ks.add(new KeySchemaElement().withAttributeName("id").withKeyType(KeyType.HASH)); - - ProvisionedThroughput provisionedThroughput = new ProvisionedThroughput() - .withReadCapacityUnits(reads) - .withWriteCapacityUnits(writes); - - CreateTableRequest request = new CreateTableRequest() - .withTableName(mTablePrefix + name) - .withAttributeDefinitions(attributeDefinitions) - .withKeySchema(ks) - .withProvisionedThroughput(provisionedThroughput); - - CreateTableResult result = mClient.createTable(request); - } - - public void updateTable(String name, long reads, long writes) { - ProvisionedThroughput provisionedThroughput = new ProvisionedThroughput() - .withReadCapacityUnits(reads) - .withWriteCapacityUnits(writes); - - UpdateTableRequest request = new UpdateTableRequest() - .withTableName(mTablePrefix + name) - .withProvisionedThroughput(provisionedThroughput); - - UpdateTableResult result = mClient.updateTable(request); - } - - public void deleteTable(String name) { - DeleteTableRequest deleteTableRequest = new DeleteTableRequest() - .withTableName(mTablePrefix + name); - - DeleteTableResult result = mClient.deleteTable(deleteTableRequest); - } - - /** - * Get all rows from a table. - * - * The key parameter must specify a table. If hash/range key is specified, - * the scan will begin after that key. - * - * @param key Previous key to start with. - * @return An ordered map of all results. - */ - public Map<DynamoKey, Map<String, String>> getAll(final DynamoKey key) { - ScanRequest scanRequest = new ScanRequest().withTableName(mTablePrefix + key.getTable()); - - if (key.getHashKey() != null) { - scanRequest.setExclusiveStartKey(generateKey(key)); - } - - ScanResult scanResult = mClient.scan(scanRequest); - - Map<DynamoKey, Map<String, String>> result = new LinkedHashMap<>(); - for (Map<String, AttributeValue> map : scanResult.getItems()) { - String id = null; - String range = null; - Map<String, String> row = new LinkedHashMap<>(); - for (Map.Entry<String, AttributeValue> entry : map.entrySet()) { - if ("id".equals(entry.getKey())) { - id = entry.getValue().getS(); - } else if ("range".equals(entry.getKey())) { - range = entry.getValue().getS(); - } else { - row.put(entry.getKey(), entry.getValue().getS()); - } - } - result.put(DynamoKey.newRangeKey(key.getTable(), id, range), row); - } - - return result; - } - - public Map<String, String> getKey(final DynamoKey key) { - GetItemRequest getItemRequest = new GetItemRequest() - .withTableName(mTablePrefix + key.getTable()) - .withKey(generateKey(key)); - - GetItemResult getItemResult = mClient.getItem(getItemRequest); - Map<String, AttributeValue> map = getItemResult.getItem(); - - Map<String, String> result = new LinkedHashMap<>(); - if (map != null) { - for (Map.Entry<String, AttributeValue> entry : map.entrySet()) { - if (!"id".equals(entry.getKey())) { - result.put(entry.getKey(), entry.getValue().getS()); - } - } - } - - return result; - } - - public String getAttribute(final DynamoKey key) { - checkAttributeKey(key); - - GetItemRequest getItemRequest = new GetItemRequest() - .withTableName(mTablePrefix + key.getTable()) - .withKey(generateKey(key)) - .withAttributesToGet(key.getAttribute()); - - GetItemResult result = mClient.getItem(getItemRequest); - Map<String, AttributeValue> map = result.getItem(); - - if (map == null) { - return null; - } - - AttributeValue value = map.get(key.getAttribute()); - if (value != null) { - return value.getS(); - - } else { - return null; - } - } - - /** - * Set all attributes for the given key. - * - * @param key The key. - * @param values Map of attributes to values. - */ - public void putKey(final DynamoKey key, final Map<String, String> values) { - Map<String, AttributeValue> item = new HashMap<>(); - for (Map.Entry<String, String> entry : values.entrySet()) { - item.put(entry.getKey(), new AttributeValue().withS(entry.getValue())); - } - - // Set the Key - item.putAll(generateKey(key)); - - PutItemRequest putItemRequest = new PutItemRequest() - .withTableName(mTablePrefix + key.getTable()) - .withItem(item); - - PutItemResult result = mClient.putItem(putItemRequest); - } - - /** - * Set the particular attributes of the given key. - * - * @param key The key. - * @param value The new value. - */ - public void putAttribute(final DynamoKey key, final String value) { - checkAttributeKey(key); - - Map<String, AttributeValueUpdate> updateItem = new HashMap<>(); - updateItem.put(key.getAttribute(), - new AttributeValueUpdate() - .withAction(AttributeAction.PUT) - .withValue(new AttributeValue().withS(value))); - - UpdateItemRequest updateItemRequest = new UpdateItemRequest() - .withTableName(mTablePrefix + key.getTable()) - .withKey(generateKey(key)) - .withAttributeUpdates(updateItem); - // TODO: Check conditions. - - UpdateItemResult result = mClient.updateItem(updateItemRequest); - } - - /** - * Delete the given key. - * - * @param key The key. - */ - public void deleteKey(final DynamoKey key) { - DeleteItemRequest deleteItemRequest = new DeleteItemRequest() - .withTableName(mTablePrefix + key.getTable()) - .withKey(generateKey(key)); - - DeleteItemResult result = mClient.deleteItem(deleteItemRequest); - } - - /** - * Delete an attribute from the given key. - * - * @param key The key. - */ - public void deleteAttribute(final DynamoKey key) { - checkAttributeKey(key); - - Map<String, AttributeValueUpdate> updateItem = new HashMap<>(); - updateItem.put(key.getAttribute(), - new AttributeValueUpdate().withAction(AttributeAction.DELETE)); - - UpdateItemRequest updateItemRequest = new UpdateItemRequest() - .withTableName(mTablePrefix + key.getTable()) - .withKey(generateKey(key)) - .withAttributeUpdates(updateItem); - - UpdateItemResult result = mClient.updateItem(updateItemRequest); - } - - /** - * Generate a DynamoDB Key Map from the DynamoKey. - */ - private Map<String, AttributeValue> generateKey(final DynamoKey key) { - HashMap<String, AttributeValue> keyMap = new HashMap<>(); - keyMap.put("id", new AttributeValue().withS(key.getHashKey())); - - String range = key.getRangeKey(); - if (range != null) { - keyMap.put("range", new AttributeValue().withS(range)); - } - - return keyMap; - } - - private void checkAttributeKey(DynamoKey key) { - if (null == key.getAttribute()) { - throw new IllegalArgumentException("Attribute must be non-null"); - } - } -} diff --git a/src/com/p4square/grow/backend/dynamo/DynamoKey.java b/src/com/p4square/grow/backend/dynamo/DynamoKey.java deleted file mode 100644 index 5cdbacd..0000000 --- a/src/com/p4square/grow/backend/dynamo/DynamoKey.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2014 Jesse Morgan - */ - -package com.p4square.grow.backend.dynamo; - -/** - * DynamoKey represents a table, hash key, and range key tupl. - */ -public class DynamoKey { - private final String mTable; - private final String mHashKey; - private final String mRangeKey; - private final String mAttribute; - - public static DynamoKey newKey(final String table, final String hashKey) { - return new DynamoKey(table, hashKey, null, null); - } - - public static DynamoKey newRangeKey(final String table, final String hashKey, - final String rangeKey) { - - return new DynamoKey(table, hashKey, rangeKey, null); - } - - public static DynamoKey newAttributeKey(final String table, final String hashKey, - final String attribute) { - - return new DynamoKey(table, hashKey, null, attribute); - } - - public DynamoKey(final String table, final String hashKey, final String rangeKey, - final String attribute) { - - mTable = table; - mHashKey = hashKey; - mRangeKey = rangeKey; - mAttribute = attribute; - } - - public String getTable() { - return mTable; - } - - public String getHashKey() { - return mHashKey; - } - - public String getRangeKey() { - return mRangeKey; - } - - public String getAttribute() { - return mAttribute; - } -} diff --git a/src/com/p4square/grow/backend/dynamo/DynamoProviderImpl.java b/src/com/p4square/grow/backend/dynamo/DynamoProviderImpl.java deleted file mode 100644 index 93a535f..0000000 --- a/src/com/p4square/grow/backend/dynamo/DynamoProviderImpl.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.grow.backend.dynamo; - -import java.io.IOException; - -import com.p4square.grow.provider.Provider; -import com.p4square.grow.provider.JsonEncodedProvider; - -/** - * Provider implementation backed by a DynamoDB Table. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class DynamoProviderImpl<V> extends JsonEncodedProvider<V> implements Provider<DynamoKey, V> { - private final DynamoDatabase mDb; - - public DynamoProviderImpl(DynamoDatabase db, Class<V> clazz) { - super(clazz); - - mDb = db; - } - - @Override - public V get(DynamoKey key) throws IOException { - String blob = mDb.getAttribute(key); - return decode(blob); - } - - @Override - public void put(DynamoKey key, V obj) throws IOException { - String blob = encode(obj); - mDb.putAttribute(key, blob); - } -} diff --git a/src/com/p4square/grow/backend/feed/FeedDataProvider.java b/src/com/p4square/grow/backend/feed/FeedDataProvider.java deleted file mode 100644 index 6f090c0..0000000 --- a/src/com/p4square/grow/backend/feed/FeedDataProvider.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.grow.backend.feed; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; - -import com.p4square.grow.model.MessageThread; -import com.p4square.grow.model.Message; -import com.p4square.grow.provider.CollectionProvider; - -/** - * Implementing this interface indicates you can provide a data source for the Feed. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public interface FeedDataProvider { - public static final Collection<String> TOPICS = Collections.unmodifiableCollection( - Arrays.asList(new String[] { "seeker", "believer", "disciple", "teacher", "leader" })); - - /** - * @return a CollectionProvider of Threads. - */ - CollectionProvider<String, String, MessageThread> getThreadProvider(); - - /** - * @return a CollectionProvider of Messages. - */ - CollectionProvider<String, String, Message> getMessageProvider(); -} diff --git a/src/com/p4square/grow/backend/feed/ThreadResource.java b/src/com/p4square/grow/backend/feed/ThreadResource.java deleted file mode 100644 index e8f46c2..0000000 --- a/src/com/p4square/grow/backend/feed/ThreadResource.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.grow.backend.feed; - -import java.io.IOException; - -import java.util.Date; -import java.util.Map; - -import org.restlet.data.Status; -import org.restlet.resource.ServerResource; -import org.restlet.representation.Representation; - -import org.restlet.ext.jackson.JacksonRepresentation; - -import org.apache.log4j.Logger; - -import com.p4square.grow.model.Message; - -/** - * ThreadResource manages the messages that make up a thread. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class ThreadResource extends ServerResource { - private static final Logger LOG = Logger.getLogger(ThreadResource.class); - - private FeedDataProvider mBackend; - private String mTopic; - private String mThreadId; - - @Override - public void doInit() { - super.doInit(); - - mBackend = (FeedDataProvider) getApplication(); - mTopic = getAttribute("topic"); - mThreadId = getAttribute("thread"); - } - - /** - * GET a list of messages in a thread. - */ - @Override - protected Representation get() { - // If the topic or threadId are missing, return a 404. - if (mTopic == null || mTopic.length() == 0 || - mThreadId == null || mThreadId.length() == 0) { - setStatus(Status.CLIENT_ERROR_NOT_FOUND); - return null; - } - - // TODO: Support limit query parameter. - - try { - String collectionKey = mTopic + "/" + mThreadId; - Map<String, Message> messages = mBackend.getMessageProvider().query(collectionKey); - return new JacksonRepresentation(messages.values()); - - } catch (IOException e) { - LOG.error("Unexpected exception: " + e.getMessage(), e); - setStatus(Status.SERVER_ERROR_INTERNAL); - return null; - } - } - - /** - * POST a new message to the thread. - */ - @Override - protected Representation post(Representation entity) { - // If the topic and thread are not provided, respond with not allowed. - // TODO: Check if the thread exists. - if (mTopic == null || !mBackend.TOPICS.contains(mTopic) || - mThreadId == null || mThreadId.length() == 0) { - setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED); - return null; - } - - try { - JacksonRepresentation<Message> jsonRep = new JacksonRepresentation<Message>(entity, Message.class); - Message message = jsonRep.getObject(); - - // Force the thread id and message to be what we expect. - message.setThreadId(mThreadId); - message.setId(Message.generateId()); - - if (message.getCreated() == null) { - message.setCreated(new Date()); - } - - String collectionKey = mTopic + "/" + mThreadId; - mBackend.getMessageProvider().put(collectionKey, message.getId(), message); - - setLocationRef(mThreadId + "/" + message.getId()); - return new JacksonRepresentation(message); - - } catch (IOException e) { - LOG.error("Unexpected exception: " + e.getMessage(), e); - setStatus(Status.SERVER_ERROR_INTERNAL); - return null; - } - } -} diff --git a/src/com/p4square/grow/backend/feed/TopicResource.java b/src/com/p4square/grow/backend/feed/TopicResource.java deleted file mode 100644 index 24b6a92..0000000 --- a/src/com/p4square/grow/backend/feed/TopicResource.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.grow.backend.feed; - -import java.io.IOException; - -import java.util.Date; -import java.util.Map; - -import org.restlet.data.Status; -import org.restlet.resource.ServerResource; -import org.restlet.representation.Representation; - -import org.restlet.ext.jackson.JacksonRepresentation; - -import org.apache.log4j.Logger; - -import com.p4square.grow.model.Message; -import com.p4square.grow.model.MessageThread; - -/** - * TopicResource manages the threads contained in a topic. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class TopicResource extends ServerResource { - private static final Logger LOG = Logger.getLogger(TopicResource.class); - - private FeedDataProvider mBackend; - private String mTopic; - - @Override - public void doInit() { - super.doInit(); - - mBackend = (FeedDataProvider) getApplication(); - mTopic = getAttribute("topic"); - } - - /** - * GET a list of threads in the topic. - */ - @Override - protected Representation get() { - // If no topic is provided, return a list of topics. - if (mTopic == null || mTopic.length() == 0) { - return new JacksonRepresentation(FeedDataProvider.TOPICS); - } - - // Parse limit query parameter. - int limit = -1; - String limitString = getQueryValue("limit"); - if (limitString != null) { - try { - limit = Integer.parseInt(limitString); - } catch (NumberFormatException e) { - setStatus(Status.CLIENT_ERROR_BAD_REQUEST); - return null; - } - } - - try { - Map<String, MessageThread> threads = mBackend.getThreadProvider().query(mTopic, limit); - return new JacksonRepresentation(threads.values()); - - } catch (IOException e) { - LOG.error("Unexpected exception: " + e.getMessage(), e); - setStatus(Status.SERVER_ERROR_INTERNAL); - return null; - } - } - - /** - * POST a new thread to the topic. - */ - @Override - protected Representation post(Representation entity) { - // If no topic is provided, respond with not allowed. - if (mTopic == null || !mBackend.TOPICS.contains(mTopic)) { - setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED); - return null; - } - - try { - // Deserialize the incoming message. - JacksonRepresentation<MessageThread> jsonRep = - new JacksonRepresentation<MessageThread>(entity, MessageThread.class); - - // Get the message from the request. - // Throw away the wrapping MessageThread because we'll create our own later. - Message message = jsonRep.getObject().getMessage(); - if (message.getCreated() == null) { - message.setCreated(new Date()); - } - - // Create the new thread. - MessageThread newThread = MessageThread.createNew(); - - // Force the thread id and message to be what we expect. - message.setId(Message.generateId()); - message.setThreadId(newThread.getId()); - newThread.setMessage(message); - - mBackend.getThreadProvider().put(mTopic, newThread.getId(), newThread); - - setLocationRef(mTopic + "/" + newThread.getId()); - return new JacksonRepresentation(newThread); - - } catch (IOException e) { - LOG.error("Unexpected exception: " + e.getMessage(), e); - setStatus(Status.SERVER_ERROR_INTERNAL); - return null; - } - } -} diff --git a/src/com/p4square/grow/backend/resources/AccountResource.java b/src/com/p4square/grow/backend/resources/AccountResource.java deleted file mode 100644 index 2ac7061..0000000 --- a/src/com/p4square/grow/backend/resources/AccountResource.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.grow.backend.resources; - -import java.io.IOException; - -import org.restlet.data.Status; -import org.restlet.resource.ServerResource; -import org.restlet.representation.Representation; - -import org.restlet.ext.jackson.JacksonRepresentation; - -import org.apache.log4j.Logger; - -import com.p4square.grow.model.UserRecord; -import com.p4square.grow.provider.Provider; -import com.p4square.grow.provider.ProvidesUserRecords; -import com.p4square.grow.provider.JsonEncodedProvider; - -/** - * Stores a document about a user. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class AccountResource extends ServerResource { - private static final Logger LOG = Logger.getLogger(AccountResource.class); - - private Provider<String, UserRecord> mUserRecordProvider; - - private String mUserId; - - @Override - public void doInit() { - super.doInit(); - - final ProvidesUserRecords backend = (ProvidesUserRecords) getApplication(); - mUserRecordProvider = backend.getUserRecordProvider(); - - mUserId = getAttribute("userId"); - } - - /** - * Handle GET Requests. - */ - @Override - protected Representation get() { - try { - UserRecord result = mUserRecordProvider.get(mUserId); - - if (result == null) { - setStatus(Status.CLIENT_ERROR_NOT_FOUND); - return null; - } - - JacksonRepresentation<UserRecord> rep = new JacksonRepresentation<UserRecord>(result); - rep.setObjectMapper(JsonEncodedProvider.MAPPER); - return rep; - - } catch (IOException e) { - setStatus(Status.SERVER_ERROR_INTERNAL); - return null; - } - } - - /** - * Handle PUT requests - */ - @Override - protected Representation put(Representation entity) { - try { - JacksonRepresentation<UserRecord> representation = - new JacksonRepresentation<>(entity, UserRecord.class); - representation.setObjectMapper(JsonEncodedProvider.MAPPER); - UserRecord record = representation.getObject(); - - mUserRecordProvider.put(mUserId, record); - setStatus(Status.SUCCESS_NO_CONTENT); - - } catch (IOException e) { - setStatus(Status.SERVER_ERROR_INTERNAL); - } - - return null; - } -} diff --git a/src/com/p4square/grow/backend/resources/BannerResource.java b/src/com/p4square/grow/backend/resources/BannerResource.java deleted file mode 100644 index 2b9c8e6..0000000 --- a/src/com/p4square/grow/backend/resources/BannerResource.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.grow.backend.resources; - -import java.io.IOException; - -import org.restlet.data.Status; -import org.restlet.ext.jackson.JacksonRepresentation; -import org.restlet.representation.Representation; -import org.restlet.representation.StringRepresentation; -import org.restlet.resource.ServerResource; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import org.apache.log4j.Logger; - -import com.p4square.grow.backend.GrowBackend; -import com.p4square.grow.model.Banner; -import com.p4square.grow.provider.JsonEncodedProvider; -import com.p4square.grow.provider.Provider; - -/** - * Fetches or sets the banner string. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class BannerResource extends ServerResource { - private static final Logger LOG = Logger.getLogger(BannerResource.class); - - public static final ObjectMapper MAPPER = JsonEncodedProvider.MAPPER; - - private Provider<String, String> mStringProvider; - - @Override - public void doInit() { - super.doInit(); - - final GrowBackend backend = (GrowBackend) getApplication(); - mStringProvider = backend.getStringProvider(); - } - - /** - * Handle GET Requests. - */ - @Override - protected Representation get() { - 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}"; - } - - return new StringRepresentation(result); - } - - /** - * Handle PUT requests - */ - @Override - protected Representation put(Representation entity) { - try { - JacksonRepresentation<Banner> representation = - new JacksonRepresentation<>(entity, Banner.class); - representation.setObjectMapper(MAPPER); - - Banner banner = representation.getObject(); - - mStringProvider.put("banner", MAPPER.writeValueAsString(banner)); - setStatus(Status.SUCCESS_NO_CONTENT); - - } catch (IOException e) { - setStatus(Status.SERVER_ERROR_INTERNAL); - } - - return null; - } -} diff --git a/src/com/p4square/grow/backend/resources/SurveyResource.java b/src/com/p4square/grow/backend/resources/SurveyResource.java deleted file mode 100644 index 8723ee2..0000000 --- a/src/com/p4square/grow/backend/resources/SurveyResource.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.grow.backend.resources; - -import java.io.IOException; - -import java.util.Map; -import java.util.HashMap; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import org.restlet.data.MediaType; -import org.restlet.data.Status; -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.model.Question; -import com.p4square.grow.provider.JsonEncodedProvider; -import com.p4square.grow.provider.Provider; - -/** - * This resource manages assessment questions. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class SurveyResource extends ServerResource { - private static final Logger LOG = Logger.getLogger(SurveyResource.class); - - private static final ObjectMapper MAPPER = JsonEncodedProvider.MAPPER; - - private Provider<String, Question> mQuestionProvider; - private Provider<String, String> mStringProvider; - - private String mQuestionId; - - @Override - public void doInit() { - super.doInit(); - - final GrowBackend backend = (GrowBackend) getApplication(); - mQuestionProvider = backend.getQuestionProvider(); - mStringProvider = backend.getStringProvider(); - - mQuestionId = getAttribute("questionId"); - } - - /** - * Handle GET Requests. - */ - @Override - protected Representation get() { - String result = "{}"; - - if (mQuestionId == null) { - // TODO: List all question ids - - } else if (mQuestionId.equals("first")) { - // Get the first question id from db? - Map<?, ?> questionSummary = getQuestionsSummary(); - mQuestionId = (String) questionSummary.get("first"); - - } else if (mQuestionId.equals("count")) { - // Get the first question id from db? - Map<?, ?> questionSummary = getQuestionsSummary(); - - return new StringRepresentation("{\"count\":" + - String.valueOf((Integer) questionSummary.get("count")) + "}"); - } - - if (mQuestionId != null) { - // Get a question by id - Question question = null; - try { - question = mQuestionProvider.get(mQuestionId); - } catch (IOException e) { - LOG.error("IOException loading question: " + e); - } - - 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); - } - - private Map<?, ?> getQuestionsSummary() { - try { - // TODO: This could be better. Quick fix for provider support. - String json = mStringProvider.get("/questions"); - - if (json != null) { - return MAPPER.readValue(json, Map.class); - } - - } catch (IOException e) { - LOG.info("Exception reading questions summary.", e); - } - - return null; - } -} diff --git a/src/com/p4square/grow/backend/resources/SurveyResultsResource.java b/src/com/p4square/grow/backend/resources/SurveyResultsResource.java deleted file mode 100644 index 7c15cfd..0000000 --- a/src/com/p4square/grow/backend/resources/SurveyResultsResource.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.grow.backend.resources; - -import java.io.IOException; -import java.util.Map; -import java.util.HashMap; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import org.restlet.data.MediaType; -import org.restlet.data.Status; -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.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; - - -/** - * Store the user's answers to the assessment and generate their score. - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class SurveyResultsResource extends ServerResource { - private static final Logger LOG = Logger.getLogger(SurveyResultsResource.class); - - private static final ObjectMapper MAPPER = new ObjectMapper(); - - static enum RequestType { - ASSESSMENT, ANSWER - } - - private CollectionProvider<String, String, String> mAnswerProvider; - private Provider<String, Question> mQuestionProvider; - private Provider<String, UserRecord> mUserRecordProvider; - - private RequestType mRequestType; - private String mUserId; - private String mQuestionId; - - @Override - public void doInit() { - super.doInit(); - - final GrowBackend backend = (GrowBackend) getApplication(); - mAnswerProvider = backend.getAnswerProvider(); - mQuestionProvider = backend.getQuestionProvider(); - mUserRecordProvider = backend.getUserRecordProvider(); - - mUserId = getAttribute("userId"); - mQuestionId = getAttribute("questionId"); - - mRequestType = RequestType.ASSESSMENT; - if (mQuestionId != null) { - mRequestType = RequestType.ANSWER; - } - } - - /** - * Handle GET Requests. - */ - @Override - protected Representation get() { - 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; - } - - if (result == null) { - setStatus(Status.CLIENT_ERROR_NOT_FOUND); - return null; - } - - return new StringRepresentation(result); - } catch (IOException e) { - LOG.error("IOException getting answer: ", e); - setStatus(Status.SERVER_ERROR_INTERNAL); - return null; - } - } - - /** - * Handle PUT requests - */ - @Override - protected Representation put(Representation entity) { - boolean success = false; - - switch (mRequestType) { - case ANSWER: - try { - mAnswerProvider.put(mUserId, mQuestionId, entity.getText()); - mAnswerProvider.put(mUserId, "lastAnswered", mQuestionId); - mAnswerProvider.put(mUserId, "summary", null); - success = true; - - } catch (Exception e) { - LOG.warn("Caught exception putting answer: " + e.getMessage(), e); - } - break; - - default: - setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED); - return null; - } - - if (success) { - setStatus(Status.SUCCESS_NO_CONTENT); - - } else { - setStatus(Status.SERVER_ERROR_INTERNAL); - } - - return null; - } - - /** - * Clear assessment results. - */ - @Override - protected Representation delete() { - boolean success = false; - - switch (mRequestType) { - case ANSWER: - try { - mAnswerProvider.put(mUserId, mQuestionId, null); - mAnswerProvider.put(mUserId, "summary", null); - success = true; - - } catch (Exception e) { - LOG.warn("Caught exception putting answer: " + e.getMessage(), e); - } - break; - - case ASSESSMENT: - try { - mAnswerProvider.put(mUserId, "summary", null); - mAnswerProvider.put(mUserId, "lastAnswered", null); - // TODO Delete answers - - UserRecord record = mUserRecordProvider.get(mUserId); - if (record != null) { - record.setLanding("assessment"); - mUserRecordProvider.put(mUserId, record); - } - - success = true; - - } catch (Exception e) { - LOG.warn("Caught exception putting answer: " + e.getMessage(), e); - } - break; - - default: - setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED); - return null; - } - - if (success) { - setStatus(Status.SUCCESS_NO_CONTENT); - - } else { - setStatus(Status.SERVER_ERROR_INTERNAL); - } - - return null; - - } - - /** - * This method compiles assessment results. - */ - private String buildAssessment() throws IOException { - StringBuilder sb = new StringBuilder("{ "); - - // Last question answered - final String lastAnswered = mAnswerProvider.get(mUserId, "lastAnswered"); - if (lastAnswered != null && lastAnswered.length() > 0) { - sb.append("\"lastAnswered\": \"" + lastAnswered + "\", "); - } - - // Compute score - Map<String, String> row = mAnswerProvider.query(mUserId); - if (row.size() > 0) { - Score score = new Score(); - boolean scoringDone = false; - int totalAnswers = 0; - for (Map.Entry<String, String> c : row.entrySet()) { - if (c.getKey().equals("lastAnswered") || c.getKey().equals("summary")) { - continue; - } - - try { - Question question = mQuestionProvider.get(c.getKey()); - RecordedAnswer userAnswer = MAPPER.readValue(c.getValue(), RecordedAnswer.class); - - if (question == null) { - LOG.warn("Answer for unknown question: " + c.getKey()); - continue; - } - - LOG.debug("Scoring questionId: " + c.getKey()); - scoringDone = !question.scoreAnswer(score, userAnswer); - - } catch (Exception e) { - LOG.error("Failed to score question: {userid: \"" + mUserId + - "\", questionid:\"" + c.getKey() + - "\", userAnswer:\"" + c.getValue() + "\"}", e); - } - - totalAnswers++; - } - - sb.append("\"score\":" + score.getScore()); - sb.append(", \"sum\":" + score.getSum()); - sb.append(", \"count\":" + score.getCount()); - sb.append(", \"totalAnswers\":" + totalAnswers); - sb.append(", \"result\":\"" + score.toString() + "\""); - } - - sb.append(" }"); - String summary = sb.toString(); - - // Persist 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 deleted file mode 100644 index 51ba56a..0000000 --- a/src/com/p4square/grow/backend/resources/TrainingRecordResource.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.grow.backend.resources; - -import java.io.IOException; - -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.HashMap; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import org.restlet.data.MediaType; -import org.restlet.data.Status; -import org.restlet.resource.ServerResource; -import org.restlet.representation.Representation; -import org.restlet.representation.StringRepresentation; - -import org.restlet.ext.jackson.JacksonRepresentation; - -import org.apache.log4j.Logger; - -import com.p4square.grow.backend.GrowBackend; - -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.model.Score; - -/** - * - * @author Jesse Morgan <jesse@jesterpm.net> - */ -public class TrainingRecordResource extends ServerResource { - private static final Logger LOG = Logger.getLogger(TrainingRecordResource.class); - private static final ObjectMapper MAPPER = JsonEncodedProvider.MAPPER; - - static enum RequestType { - SUMMARY, VIDEO - } - - private Provider<String, TrainingRecord> mTrainingRecordProvider; - private CollectionProvider<String, String, String> mAnswerProvider; - - private RequestType mRequestType; - private String mUserId; - private String mVideoId; - private TrainingRecord mRecord; - - @Override - public void doInit() { - super.doInit(); - - mTrainingRecordProvider = ((ProvidesTrainingRecords) getApplication()).getTrainingRecordProvider(); - mAnswerProvider = ((ProvidesAssessments) getApplication()).getAnswerProvider(); - - mUserId = getAttribute("userId"); - mVideoId = getAttribute("videoId"); - - try { - Playlist defaultPlaylist = ((ProvidesTrainingRecords) getApplication()).getDefaultPlaylist(); - - mRecord = mTrainingRecordProvider.get(mUserId); - if (mRecord == null) { - mRecord = new TrainingRecord(); - mRecord.setPlaylist(defaultPlaylist); - skipAssessedChapters(mUserId, mRecord); - } else { - // Merge the playlist with the most recent version. - mRecord.getPlaylist().merge(defaultPlaylist); - } - - } catch (IOException e) { - LOG.error("IOException loading TrainingRecord: " + e.getMessage(), e); - mRecord = null; - } - - mRequestType = RequestType.SUMMARY; - if (mVideoId != null) { - mRequestType = RequestType.VIDEO; - } - } - - /** - * Handle GET Requests. - */ - @Override - protected Representation get() { - JacksonRepresentation<?> rep = null; - - if (mRecord == null) { - setStatus(Status.SERVER_ERROR_INTERNAL); - return null; - } - - switch (mRequestType) { - case VIDEO: - VideoRecord video = mRecord.getPlaylist().find(mVideoId); - if (video == null) { - break; // Fall through and return 404 - } - rep = new JacksonRepresentation<VideoRecord>(video); - break; - - case SUMMARY: - rep = new JacksonRepresentation<TrainingRecord>(mRecord); - break; - } - - if (rep == null) { - setStatus(Status.CLIENT_ERROR_NOT_FOUND); - return null; - - } else { - rep.setObjectMapper(JsonEncodedProvider.MAPPER); - return rep; - } - } - - /** - * Handle PUT requests - */ - @Override - protected Representation put(Representation entity) { - if (mRecord == null) { - setStatus(Status.SERVER_ERROR_INTERNAL); - return null; - } - - switch (mRequestType) { - case VIDEO: - try { - JacksonRepresentation<VideoRecord> representation = - new JacksonRepresentation<>(entity, VideoRecord.class); - representation.setObjectMapper(JsonEncodedProvider.MAPPER); - VideoRecord update = representation.getObject(); - VideoRecord video = mRecord.getPlaylist().find(mVideoId); - - if (video == null) { - // TODO: Video isn't on their playlist... - LOG.warn("Skipping video completion for video missing from playlist."); - - } else if (update.getComplete() && !video.getComplete()) { - // Video was newly completed - video.complete(); - mRecord.setLastVideo(mVideoId); - - mTrainingRecordProvider.put(mUserId, mRecord); - } - - setStatus(Status.SUCCESS_NO_CONTENT); - - } catch (Exception e) { - LOG.warn("Caught exception updating training record: " + e.getMessage(), e); - setStatus(Status.SERVER_ERROR_INTERNAL); - } - break; - - default: - setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED); - } - - return null; - } - - private Score getAssessedScore(String userId) throws IOException { - // Get the user's score. - Score assessedScore = new Score(0, 0); - - String summaryString = mAnswerProvider.get(userId, "summary"); - if (summaryString == null) { - throw new IOException("Asked to create training record for unassessed user " + userId); - } - - Map<?,?> summary = MAPPER.readValue(summaryString, Map.class); - - if (summary.containsKey("sum") && summary.containsKey("count")) { - double sum = (Double) summary.get("sum"); - int count = (Integer) summary.get("count"); - assessedScore = new Score(sum, count); - } - - return assessedScore; - } - - /** - * Mark the chapters which the user assessed through as not required. - */ - private void skipAssessedChapters(String userId, TrainingRecord record) { - // Get the user's score. - Score assessedScore = new Score(0, 0); - - try { - assessedScore = getAssessedScore(userId); - } catch (IOException e) { - LOG.error("IOException fetching assessment record for " + userId, e); - return; - } - - // Mark the correct videos as not required. - Playlist playlist = record.getPlaylist(); - - for (Map.Entry<String, Chapter> entry : playlist.getChaptersMap().entrySet()) { - String chapterId = entry.getKey(); - Chapter chapter = entry.getValue(); - boolean required; - - if ("introduction".equals(chapter)) { - // Introduction chapter is always required - required = true; - - } else { - // Chapter required if the floor of the score is <= the chapter's numeric value. - required = assessedScore.floor() <= Score.numericScore(chapterId); - } - - if (!required) { - for (VideoRecord video : chapter.getVideos().values()) { - video.setRequired(required); - } - } - } - } -} diff --git a/src/com/p4square/grow/backend/resources/TrainingResource.java b/src/com/p4square/grow/backend/resources/TrainingResource.java deleted file mode 100644 index 6efdfab..0000000 --- a/src/com/p4square/grow/backend/resources/TrainingResource.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2013 Jesse Morgan - */ - -package com.p4square.grow.backend.resources; - -import java.io.IOException; -import java.util.Map; - -import org.restlet.data.Status; -import org.restlet.resource.ServerResource; -import org.restlet.representation.Representation; -import org.restlet.representation.StringRepresentation; - -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 LOG = Logger.getLogger(TrainingResource.class); - - private CollectionProvider<String, String, String> mVideoProvider; - - private String mLevel; - private String mVideoId; - - @Override - public void doInit() { - super.doInit(); - - GrowBackend backend = (GrowBackend) getApplication(); - mVideoProvider = backend.getVideoProvider(); - - mLevel = getAttribute("level"); - mVideoId = getAttribute("videoId"); - } - - /** - * Handle GET Requests. - */ - @Override - protected Representation get() { - String result = null; - - if (mLevel == null) { - setStatus(Status.CLIENT_ERROR_NOT_FOUND); - return null; - } - - 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("] }"); - result = sb.toString(); - } - - } else { - // Get single video - result = mVideoProvider.get(mLevel, mVideoId); - } - - if (result == null) { - // 404 - setStatus(Status.CLIENT_ERROR_NOT_FOUND); - return null; - } - - return new StringRepresentation(result); - - } catch (IOException e) { - LOG.error("IOException fetch video: " + e.getMessage(), e); - setStatus(Status.SERVER_ERROR_INTERNAL); - return null; - } - } -} |