package com.mongodb.socialite.content; import com.mongodb.*; import com.mongodb.socialite.MongoBackedService; import com.mongodb.socialite.api.*; import com.mongodb.socialite.configuration.DefaultContentServiceConfiguration; import com.mongodb.socialite.services.ContentService; import com.mongodb.socialite.services.ServiceImplementation; import com.mongodb.socialite.util.SortOrder; import com.yammer.dropwizard.config.Configuration; import java.util.ArrayList; import java.util.Collections; import java.util.List; @ServiceImplementation( name = "DefaultContentService", configClass = DefaultContentServiceConfiguration.class) public class DefaultContentService extends MongoBackedService implements ContentService{ private DBCollection content = null; private ContentValidator contentValidator = null; private final DefaultContentServiceConfiguration config; public DefaultContentService(final MongoClientURI dbUri, final DefaultContentServiceConfiguration svcConfig ) { super(dbUri, svcConfig); this.config = svcConfig; this.content = this.database.getCollection(config.content_collection_name); this.content.createIndex( new BasicDBObject( Content.AUTHOR_KEY,1).append(Content.ID_KEY,1)); this.contentValidator = new BasicContentValidator(); } @Override public List<Content> getContentFor(User author, ContentId anchor, int limit) { // Special case going backward from head yields nothing if(limit == 0 || (anchor == null && limit < 0)){ return Collections.emptyList(); } DBCursor contentCursor = null; SortOrder order = null; if(anchor == null){ contentCursor = this.content.find(byUserId(author)); order = SortOrder.DESCENDING; } else if(limit > 0){ contentCursor = this.content.find(byUserAfterContentId(author, anchor)); order = SortOrder.DESCENDING; } else{ contentCursor = this.content.find(byUserBeforeContentId(author, anchor)); order = SortOrder.ASCENDING; } return getFromCursor(contentCursor, order, Math.abs(limit)); } @Override public List<Content> getContentFor(List<User> authors, ContentId anchor, int limit) { // If no authors then no content ! if(authors == null || authors.isEmpty()){ return Collections.emptyList(); } // Special case going backward from head yields nothing if(anchor == null && limit < 0){ return Collections.emptyList(); } DBCursor contentCursor = null; SortOrder order = null; if(anchor == null){ contentCursor = this.content.find(byUserList(authors)); order = SortOrder.DESCENDING; } else if(limit > 0){ contentCursor = this.content.find(byUserListAfterContentId(authors, anchor)); order = SortOrder.DESCENDING; } else{ contentCursor = this.content.find(byUserListBeforeContentId(authors, anchor)); order = SortOrder.ASCENDING; } return getFromCursor(contentCursor, order, Math.abs(limit)); } @Override public Content getContentById(final ContentId id) { DBObject target = this.content.findOne(byContentId(id)); if( target == null ) throw new ServiceException( ContentError.CONTENT_NOT_FOUND).set("contentId", id); return new Content(target); } @Override public void publishContent(User user, Content content) { this.contentValidator.validateContent(content); this.content.insert(content.toDBObject()); } @Override public Configuration getConfiguration() { return this.config; } private static List<Content> getFromCursor(DBCursor results, SortOrder order, int limit) { List<Content> contentList = new ArrayList<Content>(); // Setup the cursor with options results.sort( new BasicDBObject(Content.ID_KEY, order.getValue())); results.limit(-limit); // Wind out the cursor and build a result list while(results.hasNext()) { final DBObject obj = results.next(); final Content content = new Content(obj); contentList.add(content); } // For ascending queries, normalize return order // so that latest content is always first if(order == SortOrder.ASCENDING){ Collections.reverse(contentList); } return contentList; } private static BasicDBObject byContentId(ContentId id) { return new BasicDBObject(Content.ID_KEY, id.getId()); } private static BasicDBObject byUserAfterContentId(User author, ContentId id) { return new BasicDBObject(Content.AUTHOR_KEY, author.getUserId()). append(Content.ID_KEY, new BasicDBObject("$lt", id.getId())); } private static BasicDBObject byUserBeforeContentId(User author, ContentId id) { return new BasicDBObject(Content.AUTHOR_KEY, author.getUserId()). append(Content.ID_KEY, new BasicDBObject("$gt", id.getId())); } private static BasicDBObject byUserId(User author) { return new BasicDBObject(Content.AUTHOR_KEY, author.getUserId()); } private static BasicDBObject byUserList(List<User> authors) { BasicDBList id_list = new BasicDBList(); for( User author : authors ) id_list.add( author.getUserId() ); BasicDBObject in = new BasicDBObject("$in", id_list); return new BasicDBObject(Content.AUTHOR_KEY, in); } private static BasicDBObject byUserListAfterContentId(List<User> authors, ContentId id) { BasicDBList id_list = new BasicDBList(); for( User author : authors ) id_list.add( author.getUserId() ); BasicDBObject in = new BasicDBObject("$in", id_list); return new BasicDBObject(Content.AUTHOR_KEY, in). append(Content.ID_KEY, new BasicDBObject("$lt", id.getId())); } private static BasicDBObject byUserListBeforeContentId(List<User> authors, ContentId id) { BasicDBList id_list = new BasicDBList(); for( User author : authors ) id_list.add( author.getUserId() ); BasicDBObject in = new BasicDBObject("$in", id_list); return new BasicDBObject(Content.AUTHOR_KEY, in). append(Content.ID_KEY, new BasicDBObject("$gt", id.getId())); } }