summaryrefslogtreecommitdiff
path: root/src/main/java/com/p4square/grow/backend/feed
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/p4square/grow/backend/feed')
-rw-r--r--src/main/java/com/p4square/grow/backend/feed/FeedDataProvider.java33
-rw-r--r--src/main/java/com/p4square/grow/backend/feed/ThreadResource.java106
-rw-r--r--src/main/java/com/p4square/grow/backend/feed/TopicResource.java117
3 files changed, 256 insertions, 0 deletions
diff --git a/src/main/java/com/p4square/grow/backend/feed/FeedDataProvider.java b/src/main/java/com/p4square/grow/backend/feed/FeedDataProvider.java
new file mode 100644
index 0000000..6f090c0
--- /dev/null
+++ b/src/main/java/com/p4square/grow/backend/feed/FeedDataProvider.java
@@ -0,0 +1,33 @@
+/*
+ * 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/main/java/com/p4square/grow/backend/feed/ThreadResource.java b/src/main/java/com/p4square/grow/backend/feed/ThreadResource.java
new file mode 100644
index 0000000..e8f46c2
--- /dev/null
+++ b/src/main/java/com/p4square/grow/backend/feed/ThreadResource.java
@@ -0,0 +1,106 @@
+/*
+ * 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/main/java/com/p4square/grow/backend/feed/TopicResource.java b/src/main/java/com/p4square/grow/backend/feed/TopicResource.java
new file mode 100644
index 0000000..24b6a92
--- /dev/null
+++ b/src/main/java/com/p4square/grow/backend/feed/TopicResource.java
@@ -0,0 +1,117 @@
+/*
+ * 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;
+ }
+ }
+}