Java tutorial
/******************************************************************************* * Copyright 2012, The Infinit.e Open Source Project. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package com.ikanow.infinit.e.api.social.sharing; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Scanner; import java.util.Set; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.log4j.Logger; import org.bson.types.ObjectId; import com.ikanow.infinit.e.api.utils.SocialUtils; import com.ikanow.infinit.e.api.utils.MimeUtils; import com.ikanow.infinit.e.api.utils.RESTTools; import com.ikanow.infinit.e.data_model.api.ResponsePojo; import com.ikanow.infinit.e.data_model.api.ResponsePojo.ResponseObject; import com.ikanow.infinit.e.data_model.api.social.sharing.SharePojoApiMap; import com.ikanow.infinit.e.data_model.store.DbManager; import com.ikanow.infinit.e.data_model.store.MongoDbManager; import com.ikanow.infinit.e.data_model.store.custom.mapreduce.CustomMapReduceJobPojo; import com.ikanow.infinit.e.data_model.store.document.DocumentPojo; import com.ikanow.infinit.e.data_model.store.social.community.CommunityPojo; import com.ikanow.infinit.e.data_model.store.social.person.PersonCommunityPojo; import com.ikanow.infinit.e.data_model.store.social.person.PersonPojo; import com.ikanow.infinit.e.data_model.store.social.sharing.SharePojo; import com.ikanow.infinit.e.data_model.store.social.sharing.SharePojo.DocumentLocationPojo; import com.ikanow.infinit.e.data_model.store.social.sharing.SharePojo.ShareCommunityPojo; import com.ikanow.infinit.e.data_model.store.social.sharing.SharePojo.ShareOwnerPojo; import com.mongodb.BasicDBList; import com.mongodb.BasicDBObject; import com.mongodb.DBCursor; import com.mongodb.DBObject; import com.mongodb.WriteResult; import com.mongodb.gridfs.GridFSDBFile; import com.mongodb.gridfs.GridFSInputFile; public class ShareHandler { private static final Logger logger = Logger.getLogger(ShareHandler.class); /** * getShare * Retrieve an individual share by id * @param shareIdStr * @return */ public ResponsePojo getShare(String userIdStr, String shareIdStr, boolean returnContent) { ResponsePojo rp = new ResponsePojo(); BasicDBObject query = new BasicDBObject("_id", new ObjectId(shareIdStr)); HashSet<ObjectId> memberOf = null; if (!RESTTools.adminLookup(userIdStr)) { // (admins can see all shares) memberOf = SocialUtils.getUserCommunities(userIdStr); if (null != memberOf) { query.put("communities._id", new BasicDBObject("$in", memberOf)); } else { // (some error but we'll let this go if the share has no security) query.put("communities", new BasicDBObject("$exists", false)); } } try { BasicDBObject dbo = (BasicDBObject) DbManager.getSocial().getShare().findOne(query); if (null != dbo) { byte[] bytes = (byte[]) dbo.remove("binaryData"); SharePojo share = SharePojo.fromDb(dbo, SharePojo.class); share.setBinaryData(bytes); //new way of handling bytes, if has a binaryid, get bytes from there and set if (returnContent) { if (null != share.getBinaryId()) { share.setBinaryData(getGridFile(share.getBinaryId())); } //TESTED else if (null != share.getDocumentLocation()) { try { if ((null != share.getType()) && share.getType().equalsIgnoreCase("binary")) { File x = new File(share.getDocumentLocation().getCollection()); share.setBinaryData(FileUtils.readFileToByteArray(x)); } //TESTED else { // text share.setShare(getReferenceString(share)); } //TESTED } catch (Exception e) { rp.setResponse(new ResponseObject("Get Share", false, "Unable to get share reference: " + e.getMessage())); return rp; } //TESTED } // (else share.share already set) } else { // don't return content share.setShare(null); } //TESTED rp.setData(share, new SharePojoApiMap(memberOf)); rp.setResponse(new ResponseObject("Share", true, "Share returned successfully")); } else { rp.setResponse(new ResponseObject("Get Share", false, "Unable to get share, not found or no access permission")); } } catch (Exception e) { logger.error("Exception Message: " + e.getMessage(), e); rp.setResponse(new ResponseObject("Get Share", false, "Unable to get share: " + e.getMessage())); } return rp; } /** * searchShares * @param personIdStr * @param searchby * @param idStrList * @param sharetypes * @param skip * @param limit * @return */ //TODO (): be able to specify not returning content? public ResponsePojo searchShares(String personIdStr, String searchby, String idStrList, String sharetypes, String skip, String limit, boolean ignoreAdmin, boolean returnContent, boolean searchParent) { ResponsePojo rp = new ResponsePojo(); /////////////////////////////////////////////////////////////////////////////////////////////// // Sample search queries // share/search/ // share/search/?type=binary // share/search/?searchby=person&id=admin_infinite@ikanow.com // share/search/?searchby=community&id=4d88d0f1f9a624a4b0c8bd71,4d88d0f1f9a624a4b0c8bd72&type=dataset&skip=0&limit=10 /////////////////////////////////////////////////////////////////////////////////////////////// // Create Query Object BasicDBObject query = new BasicDBObject(); HashSet<ObjectId> memberOf = SocialUtils.getUserCommunities(personIdStr); // (need this to sanitize share communities even if searching explicitly by community) boolean bAdmin = false; if (!ignoreAdmin) { bAdmin = RESTTools.adminLookup(personIdStr); } // Community search, supports one or more communities._id values if ((searchby != null) && (searchby.equalsIgnoreCase("community") || searchby.equalsIgnoreCase("communities"))) { query = getCommunityQueryObject(query, idStrList, personIdStr, ignoreAdmin, bAdmin, memberOf, searchParent); //TESTED regex and list versions (single and multiple), no allowed commmunity versions } else if ((searchby != null) && searchby.equalsIgnoreCase("person")) { if ((ignoreAdmin || !bAdmin) || (null == idStrList)) { // not admin or no ids spec'd query.put("owner._id", new ObjectId(personIdStr)); } //TESTED else { // admin and spec'd - can either be an array of ids or an array of email addresses memberOf = null; // (also returns all the communities in the mapper below) // List of communities to search on String[] idStrArray = idStrList.split(","); List<ObjectId> peopleIds = new ArrayList<ObjectId>(); for (String idStr : idStrArray) { try { ObjectId id = new ObjectId(idStr); peopleIds.add(id); } catch (Exception e) { // Try as people's email addresses query.put("owner.email", new BasicDBObject("$in", idStrArray)); peopleIds.clear(); break; } //TESTED } if (peopleIds.size() > 0) { BasicDBObject communities = new BasicDBObject(); communities.append("$in", peopleIds); query.put("owner._id", communities); } //TESTED } //TESTED: nobody, ids, emails } else { // Defaults to all communities to which a user belongs (or everything for admins) if (ignoreAdmin || !bAdmin) { if (null != memberOf) { query.put("communities._id", new BasicDBObject("$in", memberOf)); } else { // (some error but we'll let this go if the share has no security) query.put("communities", new BasicDBObject("$exists", false)); } } else { memberOf = null; // (also returns all the communities in the mapper below) } } // Search on share type or types if (sharetypes != null && sharetypes.length() > 0) { if (sharetypes.split(",").length > 1) { BasicDBObject types = new BasicDBObject(); String[] typeArray = sharetypes.split(","); types.append("$in", typeArray); query.put("type", types); } else { query.put("type", sharetypes); } } //REMOVING BINARY, if you want to return it you can't do deserialize on it BasicDBObject removeFields = new BasicDBObject("binaryData", false); if (!returnContent) { removeFields.put("share", false); } try { DBCursor dbc = null; // Attempt to parse skip and limit into ints if they aren't null int numToSkip = 0; int limitToNum = 0; if (skip != null) try { numToSkip = Integer.parseInt(skip); } catch (Exception e) { } if (limit != null) try { limitToNum = Integer.parseInt(limit); } catch (Exception e) { } // Run find query based on whether or not to skip and limit the number of results to return if (skip != null && limit != null) { dbc = (DBCursor) DbManager.getSocial().getShare().find(query, removeFields).skip(numToSkip) .limit(limitToNum); } else if (skip != null && limit == null) { dbc = (DBCursor) DbManager.getSocial().getShare().find(query, removeFields).skip(numToSkip); } else if (skip == null && limit != null) { dbc = (DBCursor) DbManager.getSocial().getShare().find(query, removeFields).limit(limitToNum); } else { dbc = (DBCursor) DbManager.getSocial().getShare().find(query, removeFields); } List<SharePojo> shares = SharePojo.listFromDb(dbc, SharePojo.listType()); if (!shares.isEmpty()) { Iterator<SharePojo> shareIt = shares.iterator(); while (shareIt.hasNext()) { SharePojo share = shareIt.next(); if (null != share.getDocumentLocation()) { try { if ((null == share.getType()) || !share.getType().equalsIgnoreCase("binary")) { // (ignore binary references) share.setShare(this.getReferenceString(share)); } //TESTED } catch (Exception e) { // couldn't access data, just remove data from list share.setShare("{}"); } } } //TESTED rp.setData(shares, new SharePojoApiMap(memberOf)); rp.setResponse(new ResponseObject("Share", true, "Shares returned successfully")); } else { rp.setResponse(new ResponseObject("Share", true, "No shares matching search critera found.")); } } catch (Exception e) { logger.error("Exception Message: " + e.getMessage(), e); rp.setResponse(new ResponseObject("Share", false, "Unable to search for shares: " + e.getMessage())); } return rp; } private BasicDBObject getCommunityQueryObject(BasicDBObject query, String idStrList, String personIdStr, boolean ignoreAdmin, boolean bAdmin, HashSet<ObjectId> memberOf, boolean searchParent) { if (idStrList != null && idStrList.length() > 0) { idStrList = allowCommunityRegex(personIdStr, idStrList, true); // (allows regex, plus multiple communities) // List of communities to search on String[] idStrArray = idStrList.split(","); List<ObjectId> communityIds = new ArrayList<ObjectId>(); for (String idStr : idStrArray) { try { ObjectId id = new ObjectId(idStr); if (isMemberOwnerAdminOfCommunity(id, ignoreAdmin, bAdmin, memberOf)) { communityIds.add(id); } } catch (Exception ex) { } } if (communityIds.size() > 0) { if (searchParent) { //get the comm objects for these communities, so we can grab all their parents and add them to the query BasicDBObject communities = new BasicDBObject(); communities.append("$in", getParentIds(communityIds, personIdStr, ignoreAdmin, bAdmin, memberOf)); query.put("communities._id", communities); } else { //otherwise just use the given commids BasicDBObject communities = new BasicDBObject(); communities.append("$in", communityIds); query.put("communities._id", communities); } } else { // (some error but we'll let this go if the share has no security) query.put("communities", new BasicDBObject("$exists", false)); } } else { // (some error but we'll let this go if the share has no security) query.put("communities", new BasicDBObject("$exists", false)); } return query; } /** * Takes a list of communityIds and finds any parentsIds. * The parent id's will either be: * 1. in comm.parentTree, just append * 2. in comm.parentId, create parentTree and update comm, append * * @param child_shares * @return */ private List<ObjectId> getParentIds(List<ObjectId> children, String personIdStr, boolean ignoreAdmin, boolean bAdmin, HashSet<ObjectId> memberOf) { Set<ObjectId> communityIds = new HashSet<ObjectId>(); List<CommunityPojo> child_communities = CommunityPojo.listFromDb( MongoDbManager.getSocial().getCommunity() .find(new BasicDBObject("_id", new BasicDBObject(MongoDbManager.in_, children))), CommunityPojo.listType()); for (CommunityPojo child_comm : child_communities) { //this community has a parent if (child_comm.getParentId() != null) { if (child_comm.getParentTree() == null) { child_comm = SocialUtils.createParentTreeRecursion(child_comm, true); } } //parentTree should be populated now, add these comms to the set communityIds.add(child_comm.getId()); if (child_comm.getParentTree() != null) { communityIds.addAll(getAllowedParentComms(child_comm.getParentTree(), personIdStr, ignoreAdmin, bAdmin, memberOf)); } } return new ArrayList<ObjectId>(communityIds); } /** * Returns only the communities that a user is allowed to see. * * @param parentTree * @param personIdStr * @return */ private List<ObjectId> getAllowedParentComms(List<ObjectId> parentTree, String personIdStr, boolean ignoreAdmin, boolean bAdmin, HashSet<ObjectId> memberOf) { List<ObjectId> allowedParents = new ArrayList<ObjectId>(); for (ObjectId parent_id : parentTree) { if (isMemberOwnerAdminOfCommunity(parent_id, ignoreAdmin, bAdmin, memberOf)) { allowedParents.add(parent_id); } } return allowedParents; } /** * Return true if user is a (member of the community) or (admin is true and ignoreadmin is false) * * @param communityId * @param ignoreAdmin * @param bAdmin * @param memberOf * @return */ private boolean isMemberOwnerAdminOfCommunity(ObjectId communityId, boolean ignoreAdmin, boolean bAdmin, HashSet<ObjectId> memberOf) { try { if (ignoreAdmin || !bAdmin) { if ((null != memberOf) && (memberOf.contains(communityId))) { return true; } } else { // admin, allowed it return true; } } catch (Exception e) { } return false; } //TODO (???): have ability to enforce uniqueness on title/type //TODO (???): for updates, have the ability to fail if document has changed in meantime... /** * addBinary * @param ownerIdStr * @param type * @param title * @param description * @param mediatype * @param bytes * @return */ public ResponsePojo addBinary(String ownerIdStr, String type, String title, String description, String mediatype, byte[] bytes) { ResponsePojo rp = new ResponsePojo(); try { // Create a new SharePojo object SharePojo share = new SharePojo(); share.setCreated(new Date()); share.setModified(new Date()); share.setType(type); share.setTitle(title); share.setDescription(description); HashSet<ObjectId> endorsedSet = new HashSet<ObjectId>(); share.setEndorsed(endorsedSet); // (you're always endorsed within your personal community) endorsedSet.add(new ObjectId(ownerIdStr)); share.setMediaType(mediatype); ObjectId id = new ObjectId(); share.set_id(id); // Get ShareOwnerPojo object and personal community PersonPojo owner = getPerson(new ObjectId(ownerIdStr)); share.setOwner(getOwner(owner)); share.setCommunities(getPersonalCommunity(owner)); // Serialize the ID and Dates in the object to MongoDB format //Save the binary objects into separate db ObjectId gridid = saveGridFile(bytes); share.setBinaryId(gridid); // Save the document to the share collection DbManager.getSocial().getShare().save(share.toDb()); rp.setResponse( new ResponseObject("Share", true, "New binary share added successfully. ID in data field")); rp.setData(id.toString(), null); } catch (Exception e) { e.printStackTrace(); logger.error("Exception Message: " + e.getMessage(), e); rp.setResponse(new ResponseObject("Share", false, "Unable to add share: " + e.getMessage())); } return rp; } /** * updateBinary * @param ownerIdStr * @param shareIdStr * @param type * @param title * @param description * @param mediatype * @param bytes * @return */ public ResponsePojo updateBinary(String ownerIdStr, String shareIdStr, String type, String title, String description, String mediatype, byte[] bytes) { ResponsePojo rp = new ResponsePojo(); try { //get old share BasicDBObject query = new BasicDBObject("_id", new ObjectId(shareIdStr)); DBObject dboshare = DbManager.getSocial().getShare().findOne(query); if (dboshare != null) { //write everything but binary dboshare.removeField("binaryData"); SharePojo share = SharePojo.fromDb(dboshare, SharePojo.class); // Check ... am I the owner? ObjectId ownerId = new ObjectId(ownerIdStr); boolean bAdminOrModOfAllCommunities = RESTTools.adminLookup(ownerIdStr); if (!share.getOwner().get_id().equals(ownerId)) { // Then I have to be admin (except for one special case) if (!bAdminOrModOfAllCommunities) { // Special case: I am also community admin/moderator of every community to which this share belongs bAdminOrModOfAllCommunities = true; for (ShareCommunityPojo comm : share.getCommunities()) { if (!SocialUtils.isOwnerOrModerator(comm.get_id().toString(), ownerIdStr)) { bAdminOrModOfAllCommunities = false; } } //TESTED if (!bAdminOrModOfAllCommunities) { rp.setResponse(new ResponseObject("Update Share", false, "Unable to update share: you are not owner or admin")); return rp; } } } //end if not owner // Check: am I trying to update a reference or json? if (null == share.getBinaryId()) { rp.setResponse(new ResponseObject("Update Share", false, "Unable to update share: this is not a binary share")); return rp; } if (!bAdminOrModOfAllCommunities) { // quick check whether I'm admin on-request - if so can endorse bAdminOrModOfAllCommunities = RESTTools.adminLookup(ownerIdStr, false); } //TESTED // Remove endorsements unless I'm admin (if I'm not admin I must be owner...) if (!bAdminOrModOfAllCommunities) { // Now need to check if I'm admin/mod/content publisher for each community.. if (null == share.getEndorsed()) { // fill this with all allowed communities share.setEndorsed(new HashSet<ObjectId>()); share.getEndorsed().add(share.getOwner().get_id()); // (will be added later) for (ShareCommunityPojo comm : share.getCommunities()) { if (SocialUtils.isOwnerOrModeratorOrContentPublisher(comm.get_id().toString(), ownerIdStr)) { share.getEndorsed().add(comm.get_id()); } } } //TESTED else { for (ShareCommunityPojo comm : share.getCommunities()) { // (leave it as is except remove anything that I can't endorse) if (!SocialUtils.isOwnerOrModeratorOrContentPublisher(comm.get_id().toString(), ownerIdStr)) { share.getEndorsed().remove(comm.get_id()); } } } //TESTED } //TESTED else { if (null == share.getEndorsed()) { // fill this with all communities share.setEndorsed(new HashSet<ObjectId>()); share.getEndorsed().add(share.getOwner().get_id()); for (ShareCommunityPojo comm : share.getCommunities()) { share.getEndorsed().add(comm.get_id()); } } //(else just leave with the same set of endorsements as before) } //TESTED share.setModified(new Date()); share.setType(type); share.setTitle(title); share.setDescription(description); share.setMediaType(mediatype); share.setBinaryData(null); share.setBinaryId(updateGridFile(share.getBinaryId(), bytes)); DbManager.getSocial().getShare().update(query, share.toDb()); rp.setResponse(new ResponseObject("Update Share", true, "Binary share updated successfully")); } else { rp.setResponse(new ResponseObject("Update Share", false, "Shareid does not exist or you are not owner or admin")); } } catch (Exception e) { logger.error("Exception Message: " + e.getMessage(), e); rp.setResponse(new ResponseObject("Update Share", false, "Unable to update share: " + e.getMessage())); } return rp; } /** * saveJson (handles both add and update) * @param shareIdStr * @param type * @param title * @param description * @param json * @return */ public ResponsePojo saveJson(String ownerIdStr, String shareIdStr, String type, String title, String description, String json) { ResponsePojo rp = new ResponsePojo(); try { SharePojo share = null; BasicDBObject dbo = null; BasicDBObject query = null; // Retrieve the share to update (if it exists) if (shareIdStr != null && ObjectId.isValid(shareIdStr)) { query = new BasicDBObject(); query.put("_id", new ObjectId(shareIdStr)); dbo = (BasicDBObject) DbManager.getSocial().getShare().findOne(query); } else { shareIdStr = new ObjectId().toString(); } // Update existing share if (dbo != null) { // 1a) if I'm the owner then GOTO_UPDATE // 1b) if I'm the admin/mod // (NEW) if I am a content publisher for all communities for which this share is read/write share = SharePojo.fromDb(dbo, SharePojo.class); // Check ... am I the owner? ObjectId ownerId = new ObjectId(ownerIdStr); boolean bAdminOrModOfAllCommunities = RESTTools.adminLookup(ownerIdStr); if (!share.getOwner().get_id().equals(ownerId)) { // Then I have to be admin (except for one special case) if (!bAdminOrModOfAllCommunities) { // Special case #1: I am also community admin/moderator of every community to which this share belongs bAdminOrModOfAllCommunities = true; for (ShareCommunityPojo comm : share.getCommunities()) { if (!SocialUtils.isOwnerOrModerator(comm.get_id().toString(), ownerIdStr)) { bAdminOrModOfAllCommunities = false; } } //TESTED if (!bAdminOrModOfAllCommunities) { // Special case #2: I am a admin/mod/content publisher of *any* community that is read/write boolean readWriteCase = false; if (null != share.getReadWrite()) { // I need to be content publisher across all shares for (ObjectId readWriteCommId : share.getReadWrite()) { if (SocialUtils.isOwnerOrModeratorOrContentPublisher(readWriteCommId.toString(), ownerIdStr)) { readWriteCase = true; break; } } } //TESTED if (!readWriteCase) { rp.setResponse(new ResponseObject("Update Share", false, "Unable to update share: you are not owner or admin")); return rp; } } } } //end if not owner // Check: am I trying to update a reference or binary? if ((null != share.getDocumentLocation()) || (null != share.getBinaryId())) { rp.setResponse(new ResponseObject("Update Share", false, "Unable to update share: this is not a JSON share")); return rp; } if (!bAdminOrModOfAllCommunities) { // quick check whether I'm admin on-request - if so can endorse bAdminOrModOfAllCommunities = RESTTools.adminLookup(ownerIdStr, false); } //TESTED // Remove endorsements unless I'm admin (if I'm not admin I must be owner...) if (!bAdminOrModOfAllCommunities) { // Now need to check if I'm admin/mod/content publisher for each community.. if (null == share.getEndorsed()) { // fill this with all allowed communities share.setEndorsed(new HashSet<ObjectId>()); share.getEndorsed().add(share.getOwner().get_id()); // (will be added later) for (ShareCommunityPojo comm : share.getCommunities()) { if (SocialUtils.isOwnerOrModeratorOrContentPublisher(comm.get_id().toString(), ownerIdStr)) { share.getEndorsed().add(comm.get_id()); } } } //TESTED else { for (ShareCommunityPojo comm : share.getCommunities()) { // (leave it as is except remove anything that I can't endorse) if (!SocialUtils.isOwnerOrModeratorOrContentPublisher(comm.get_id().toString(), ownerIdStr)) { share.getEndorsed().remove(comm.get_id()); } } } //TESTED } //TESTED else { if (null == share.getEndorsed()) { // fill this with all communities share.setEndorsed(new HashSet<ObjectId>()); share.getEndorsed().add(share.getOwner().get_id()); for (ShareCommunityPojo comm : share.getCommunities()) { share.getEndorsed().add(comm.get_id()); } } //(else just leave with the same set of endorsements as before) } //TESTED share.setModified(new Date()); share.setType(type); share.setTitle(title); share.setDescription(description); share.setShare(json); // Save the document to the share collection DbManager.getSocial().getShare().update(query, share.toDb()); rp.setData(share, new SharePojoApiMap(null)); rp.setResponse(new ResponseObject("Share", true, "Share updated successfully.")); } // Create new share else { // Create a new SharePojo object share = new SharePojo(); share.set_id(new ObjectId(shareIdStr)); share.setCreated(new Date()); share.setModified(new Date()); share.setType(type); share.setTitle(title); share.setDescription(description); share.setShare(json); HashSet<ObjectId> endorsedSet = new HashSet<ObjectId>(); share.setEndorsed(endorsedSet); // (you're always endorsed within your own community) endorsedSet.add(new ObjectId(ownerIdStr)); // Get ShareOwnerPojo object and personal community PersonPojo owner = getPerson(new ObjectId(ownerIdStr)); share.setOwner(getOwner(owner)); share.setCommunities(getPersonalCommunity(owner)); // Serialize the ID and Dates in the object to MongoDB format // Save the document to the share collection DbManager.getSocial().getShare().save(share.toDb()); rp.setData(share, new SharePojoApiMap(null)); rp.setResponse(new ResponseObject("Share", true, "New share added successfully.")); } } catch (Exception e) { logger.error("Exception Message: " + e.getMessage(), e); rp.setResponse(new ResponseObject("Share", false, "Unable to update share: " + e.getMessage())); } return rp; } /** * addRef * @param ownerIdStr * @param type * @param idStr * @param description * @return */ public ResponsePojo addRef(String ownerIdStr, String type, String location, String idStr, String title, String description) { ResponsePojo rp = new ResponsePojo(); try { ObjectId shareId = new ObjectId(); // Create a new SharePojo object SharePojo share = new SharePojo(); share.set_id(shareId); share.setType(type); share.setTitle(title); share.setDescription(description); share.setCreated(new Date()); share.setModified(new Date()); // Create DocumentLocationPojo and add to the share DocumentLocationPojo documentLocation = new DocumentLocationPojo(); setRefLocation(location, documentLocation); share.setDocumentLocation(documentLocation); if (null == documentLocation.getDatabase()) { // (local file) // Check, need to be admin: if (!RESTTools.adminLookup(ownerIdStr, false)) { rp.setResponse(new ResponseObject("Share", false, "Permission denied: you need to be admin to create a local file ref")); return rp; } if ((null != type) && (type.equalsIgnoreCase("binary") || type.startsWith("binary:"))) { String[] binaryType = type.split(":", 2); if (binaryType.length > 1) { share.setMediaType(binaryType[1]); share.setType("binary"); } else { share.setMediaType(MimeUtils.getMimeType(FilenameUtils.getExtension(idStr))); } } documentLocation.setCollection(idStr); // collection==file, database==id==null } //TESTED else { documentLocation.set_id(new ObjectId(idStr)); } // Get ShareOwnerPojo object PersonPojo owner = getPerson(new ObjectId(ownerIdStr)); share.setOwner(getOwner(owner)); // Endorsements: HashSet<ObjectId> endorsedSet = new HashSet<ObjectId>(); share.setEndorsed(endorsedSet); // (you're always endorsed within your own community) endorsedSet.add(new ObjectId(ownerIdStr)); // Set Personal Community share.setCommunities(getPersonalCommunity(owner)); // Serialize the ID and Dates in the object to MongoDB format // Save the document to the share collection DbManager.getSocial().getShare().save(share.toDb()); rp.setResponse(new ResponseObject("Share", true, "New share added successfully. ID in data field.")); rp.setData(share.get_id().toString(), null); } catch (Exception e) { //logger.error("Exception Message: " + e.getMessage(), e); rp.setResponse(new ResponseObject("Share", false, "Unable to add new share: " + e.getMessage())); } return rp; } public ResponsePojo updateRef(String ownerIdStr, String shareIdStr, String type, String location, String idStr, String title, String description) { ResponsePojo rp = new ResponsePojo(); try { // Get Share Object from Collection BasicDBObject query = new BasicDBObject(); query.put("_id", new ObjectId(shareIdStr)); BasicDBObject dbo = (BasicDBObject) DbManager.getSocial().getShare().findOne(query); if (dbo != null) { SharePojo share = SharePojo.fromDb(dbo, SharePojo.class); // Check ... am I the owner? ObjectId ownerId = new ObjectId(ownerIdStr); boolean bAdminOrModOfAllCommunities = RESTTools.adminLookup(ownerIdStr); if (!share.getOwner().get_id().equals(ownerId)) { // Then I have to be admin (except for one special case) if (!bAdminOrModOfAllCommunities) { // Special case: I am also community admin/moderator of every community to which this share belongs bAdminOrModOfAllCommunities = true; for (ShareCommunityPojo comm : share.getCommunities()) { if (!SocialUtils.isOwnerOrModerator(comm.get_id().toString(), ownerIdStr)) { bAdminOrModOfAllCommunities = false; } } //TESTED if (!bAdminOrModOfAllCommunities) { rp.setResponse(new ResponseObject("Update Share", false, "Unable to update share: you are not owner or admin")); return rp; } } } //end if not owner // Check: am I trying to update a reference or json? if (null == share.getDocumentLocation()) { rp.setResponse(new ResponseObject("Update Share", false, "Unable to update share: this is not a reference share")); return rp; } if (!bAdminOrModOfAllCommunities) { // quick check whether I'm admin on-request - if so can endorse bAdminOrModOfAllCommunities = RESTTools.adminLookup(ownerIdStr, false); } //TESTED // Remove endorsements unless I'm admin (if I'm not admin I must be owner...) if (!bAdminOrModOfAllCommunities) { // Now need to check if I'm admin/mod/content publisher for each community.. if (null == share.getEndorsed()) { // fill this with all allowed communities share.setEndorsed(new HashSet<ObjectId>()); share.getEndorsed().add(share.getOwner().get_id()); // (will be added later) for (ShareCommunityPojo comm : share.getCommunities()) { if (SocialUtils.isOwnerOrModeratorOrContentPublisher(comm.get_id().toString(), ownerIdStr)) { share.getEndorsed().add(comm.get_id()); } } } //TESTED else { for (ShareCommunityPojo comm : share.getCommunities()) { // (leave it as is except remove anything that I can't endorse) if (!SocialUtils.isOwnerOrModeratorOrContentPublisher(comm.get_id().toString(), ownerIdStr)) { share.getEndorsed().remove(comm.get_id()); } } } //TESTED } //TESTED else { if (null == share.getEndorsed()) { // fill this with all communities share.setEndorsed(new HashSet<ObjectId>()); share.getEndorsed().add(share.getOwner().get_id()); for (ShareCommunityPojo comm : share.getCommunities()) { share.getEndorsed().add(comm.get_id()); } } //(else just leave with the same set of endorsements as before) } //TESTED share.setType(type); share.setTitle(title); share.setDescription(description); share.setModified(new Date()); // Create DocumentLocationPojo and add to the share DocumentLocationPojo documentLocation = new DocumentLocationPojo(); setRefLocation(location, documentLocation); share.setDocumentLocation(documentLocation); if (null == documentLocation.getDatabase()) { // (local file) // Check, need to be admin: if (!RESTTools.adminLookup(ownerIdStr, false)) { rp.setResponse(new ResponseObject("Share", false, "Permission denied: you need to be admin to update a local file ref")); return rp; } if ((null != type) && (type.equalsIgnoreCase("binary") || type.startsWith("binary:"))) { String[] binaryType = type.split(":", 2); if (binaryType.length > 1) { share.setMediaType(binaryType[1]); share.setType("binary"); } else { share.setMediaType(MimeUtils.getMimeType(FilenameUtils.getExtension(idStr))); } } documentLocation.setCollection(idStr); // collection==file, database==id==null } //TESTED else { documentLocation.set_id(new ObjectId(idStr)); } // Get ShareOwnerPojo object PersonPojo owner = getPerson(new ObjectId(ownerIdStr)); share.setOwner(getOwner(owner)); // Set Personal Community share.setCommunities(getPersonalCommunity(owner)); // Serialize the ID and Dates in the object to MongoDB format // Save the document to the share collection DbManager.getSocial().getShare().update(query, share.toDb()); rp.setResponse(new ResponseObject("Share", true, "Share updated successfully.")); } else { rp.setResponse(new ResponseObject("Share", false, "Unable to update share: only the owner of the share or admin can update it.")); return rp; } } catch (Exception e) { //logger.error("Exception Message: " + e.getMessage(), e); rp.setResponse(new ResponseObject("Share", false, "Unable to update share: " + e.getMessage())); } return rp; } /** * endorseShare * Endorse a share for use within a community (needs to be admin, community owner or moderator) * Can be used by applications * @param shareIdStr * @return */ public ResponsePojo endorseShare(String personIdStr, String communityIdStr, String shareIdStr, boolean isEndorsed) { ResponsePojo rp = new ResponsePojo(); try { communityIdStr = allowCommunityRegex(personIdStr, communityIdStr); ObjectId communityId = new ObjectId(communityIdStr); // Do I have permission to do any endorsing? // I can be: // Admin (or admin on request, regardless of enabled state) // Community owner // Community moderator boolean bAdmin = RESTTools.adminLookup(personIdStr, false); if (!bAdmin) { if (!SocialUtils.isOwnerOrModeratorOrContentPublisher(communityIdStr, personIdStr)) { rp.setResponse(new ResponseObject("Share", false, "Unable to endorse share: insufficient permissions")); return rp; } } //TESTED // Now check if the share is even in our community... BasicDBObject query = new BasicDBObject(SharePojo._id_, new ObjectId(shareIdStr)); query.put(ShareCommunityPojo.shareQuery_id_, communityId); BasicDBObject fields = new BasicDBObject(ShareOwnerPojo.shareQuery_id_, 1); fields.put(SharePojo.endorsed_, 1); BasicDBObject shareObj = (BasicDBObject) DbManager.getSocial().getShare().findOne(query, fields); SharePojo shareToEndorse = SharePojo.fromDb(shareObj, SharePojo.class); if (null == shareToEndorse) { rp.setResponse(new ResponseObject("Share", false, "Failed to locate share in community: " + shareIdStr + " vs " + communityIdStr)); return rp; } //TESTED // If we've got this far we're good to go BasicDBObject update = null; if ((null == shareToEndorse.getEndorsed()) && (null != shareToEndorse.getOwner())) { //Legacy case: create the owner's personal community in there update = new BasicDBObject(DbManager.addToSet_, new BasicDBObject(SharePojo.endorsed_, shareToEndorse.getOwner().get_id())); DbManager.getSocial().getShare().update(query, update, false, true); } //TESTED if (isEndorsed) { update = new BasicDBObject(DbManager.addToSet_, new BasicDBObject(SharePojo.endorsed_, communityId)); } //TESTED else { update = new BasicDBObject(DbManager.pull_, new BasicDBObject(SharePojo.endorsed_, communityId)); } //TESTED DbManager.getSocial().getShare().update(query, update, false, true); rp.setResponse(new ResponseObject("Share", true, "Share endorsed successfully.")); } catch (Exception e) { logger.error("Exception Message: " + e.getMessage(), e); rp.setResponse(new ResponseObject("Share", false, "Unable to endorse share: " + e.getMessage())); } return rp; }//TESTED /** * removeShare * Remove an individual share from the share collection, shares can only be removed by the * owner via the rest API (id retrieved via cookielookup). * @param shareIdStr * @return */ public ResponsePojo removeShare(String ownerIdStr, String shareIdStr) { ResponsePojo rp = new ResponsePojo(); // Query = share._id and share.shareOwner._id (unless admin) BasicDBObject query = new BasicDBObject(); query.put("_id", new ObjectId(shareIdStr)); mustBeOwnerOrAdmin(ownerIdStr, query); try { //first we must get the share to see if we need to remove the binary portion SharePojo sp = SharePojo.fromDb(DbManager.getSocial().getShare().findOne(query), SharePojo.class); WriteResult wr = DbManager.getSocial().getShare().remove(query); if (wr.getN() == 1) { //if remvoe was successful, attempt to remove the gridfs entry if (sp.getBinaryId() != null) { //remove gridfs DbManager.getSocial().getShareBinary().remove(sp.getBinaryId()); } rp.setResponse(new ResponseObject("Share", true, "Share removed from database successfully")); } else { rp.setResponse(new ResponseObject("Share", false, "Unable to remove share from database successfully (reason: share does not exist or user does not own the share).")); } } catch (Exception e) { logger.error("Exception Message: " + e.getMessage(), e); rp.setResponse(new ResponseObject("Share", false, "Unable to remove share: " + e.getMessage())); } return rp; } /** * addCommunity * @param shareIdStr * @param communityIdStr * @param comment * @return */ public ResponsePojo addCommunity(String ownerIdStr, String shareIdStr, String communityIdStr, String comment, boolean readWrite) { // First get the share document from the database (only works for the share owner) ResponsePojo rp = new ResponsePojo(); BasicDBObject query = new BasicDBObject(); query.put("_id", new ObjectId(shareIdStr)); mustBeOwnerOrAdmin(ownerIdStr, query); try { communityIdStr = allowCommunityRegex(ownerIdStr, communityIdStr); BasicDBObject dbo = (BasicDBObject) DbManager.getSocial().getShare().findOne(query); if (dbo != null) { SharePojo share = SharePojo.fromDb(dbo, SharePojo.class); // Read write: if (null == share.getReadWrite()) { share.setReadWrite(new HashSet<ObjectId>()); } ObjectId communityId = new ObjectId(communityIdStr); boolean changedReadWriteAccess = false; if (readWrite) { // set read-write up changedReadWriteAccess = share.getReadWrite().add(communityId); } else { changedReadWriteAccess = share.getReadWrite().remove(communityId); } // Check to see if the community is already in share.communities List<ShareCommunityPojo> communities = share.getCommunities(); if (null == communities) { communities = new ArrayList<ShareCommunityPojo>(); } Boolean addCommunity = true; for (ShareCommunityPojo scp : communities) { if (scp.get_id().toString().equalsIgnoreCase(communityIdStr)) addCommunity = false; } // Add new community to communities (or change its read/write permissions) if (addCommunity || changedReadWriteAccess) { if (addCommunity) { ShareCommunityPojo cp = new ShareCommunityPojo(); cp.set_id(new ObjectId(communityIdStr)); cp.setName(getCommunity(new ObjectId(communityIdStr)).getName()); cp.setComment(comment); communities.add(cp); // Endorse if applicable... if (null == share.getEndorsed()) { // legacy case share.setEndorsed(new HashSet<ObjectId>()); share.getEndorsed().add(share.getOwner().get_id()); // user's personal community always endorsed } //TESTED boolean bAdmin = RESTTools.adminLookup(ownerIdStr, false); // (can be admin-on-request and not enabled, the bar for endorsing is pretty low) if (bAdmin || SocialUtils.isOwnerOrModeratorOrContentPublisher(communityIdStr, ownerIdStr)) { share.getEndorsed().add(cp.get_id()); } //TESTED - adding as admin/community owner, not adding if not } share.setModified(new Date()); DbManager.getSocial().getShare().update(query, share.toDb()); rp.setResponse(new ResponseObject("Share", true, "Community successfully added to the share")); } // Community already in share.communities else { rp.setResponse( new ResponseObject("Share", false, "Community has already been added to the share")); } } else { rp.setResponse(new ResponseObject("Share", false, "Unable to add community to share.")); } } catch (Exception e) { logger.error("Exception Message: " + e.getMessage(), e); rp.setResponse( new ResponseObject("Share", false, "Unable to add community to share: " + e.getMessage())); } return rp; } /** * removeCommunity * @param ownerIdStr * @param shareIdStr * @param communityIdStr * @return */ public ResponsePojo removeCommunity(String ownerIdStr, String shareIdStr, String communityIdStr) { // First get the share document from the database (only works for the share owner) ResponsePojo rp = new ResponsePojo(); BasicDBObject query = new BasicDBObject(); query.put("_id", new ObjectId(shareIdStr)); mustBeOwnerOrAdmin(ownerIdStr, query); try { communityIdStr = allowCommunityRegex(ownerIdStr, communityIdStr); BasicDBObject dbo = (BasicDBObject) DbManager.getSocial().getShare().findOne(query); if (dbo != null) { SharePojo share = SharePojo.fromDb(dbo, SharePojo.class); List<ShareCommunityPojo> communities = share.getCommunities(); // Check to see if the community is already in share.communities boolean removeCommunity = false; for (ShareCommunityPojo scp : communities) { if (scp.get_id().toString().equalsIgnoreCase(communityIdStr)) { //Also remove endorsements... if (null != share.getEndorsed()) { share.getEndorsed().remove(scp.get_id()); } //TESTED // Also remove readWrite... if (null != share.getReadWrite()) { share.getReadWrite().remove(scp.get_id()); } removeCommunity = true; communities.remove(scp); share.setModified(new Date()); DbManager.getSocial().getShare().update(query, share.toDb()); rp.setResponse( new ResponseObject("Share", true, "Community successfully removed from the share")); break; } } if (!removeCommunity) { rp.setResponse(new ResponseObject("Share", false, "Unable to remove community (does not exist in share)")); } } else { rp.setResponse(new ResponseObject("Share", false, "Unable to remove community from share.")); } } catch (Exception e) { logger.error("Exception Message: " + e.getMessage(), e); rp.setResponse( new ResponseObject("Share", false, "Unable to remove community from share: " + e.getMessage())); } return rp; } ////////////////////////////////////////////////////////////////////////// //////////////////////// Private Helper Functions //////////////////////// ////////////////////////////////////////////////////////////////////////// /** * getPerson * @param idStr * @return */ private static PersonPojo getPerson(ObjectId id) { // BasicDBObject query = new BasicDBObject(); query.put("_id", id); PersonPojo person = null; try { DBObject dbo = DbManager.getSocial().getPerson().findOne(query); if (dbo != null) { // Get GsonBuilder object with MongoDb de/serializers registered person = PersonPojo.fromDb(dbo, PersonPojo.class); } } catch (Exception e) { } return person; } /** * getShareOwner * @param ownerId * @return */ private ShareOwnerPojo getOwner(PersonPojo owner) { // Set ShareOwner ShareOwnerPojo shareOwner = new ShareOwnerPojo(); shareOwner.set_id(owner.get_id()); shareOwner.setDisplayName(owner.getDisplayName()); shareOwner.setEmail(owner.getEmail()); return shareOwner; } /** * getPersonalCommunity * @param owner * @return */ private List<ShareCommunityPojo> getPersonalCommunity(PersonPojo owner) { ShareCommunityPojo cp = new ShareCommunityPojo(); for (PersonCommunityPojo pc : owner.getCommunities()) { if (pc.get_id().equals(owner.get_id())) { cp.set_id(pc.get_id()); cp.setComment(null); cp.setName(pc.getName()); } } // Add the owner's personal community List<ShareCommunityPojo> communities = new ArrayList<ShareCommunityPojo>(); communities.add(cp); return communities; } /** * getCommunity * @param idStr * @return */ private static CommunityPojo getCommunity(ObjectId id) { // BasicDBObject query = new BasicDBObject(); query.put("_id", id); CommunityPojo community = null; try { DBObject dbo = DbManager.getSocial().getCommunity().findOne(query); if (dbo != null) { // Get GsonBuilder object with MongoDb de/serializers registered community = CommunityPojo.fromDb(dbo, CommunityPojo.class); } } catch (Exception e) { } return community; } /** * Finds the gridfile given by id and returns the bytes * * @param id the object id of the gridfile to lookup (stored in sharepojo) * @return bytes of file stored in gridfile */ private byte[] getGridFile(ObjectId id) { ByteArrayOutputStream out = new ByteArrayOutputStream(); try { GridFSDBFile file = DbManager.getSocial().getShareBinary().find(id); file.writeTo(out); byte[] toReturn = out.toByteArray(); out.close(); return toReturn; } catch (Exception ex) { } return null; } @SuppressWarnings("unused") private ByteArrayOutputStream getGridStream(ObjectId id) { ByteArrayOutputStream out = new ByteArrayOutputStream(); try { GridFSDBFile file = DbManager.getSocial().getShareBinary().find(id); file.writeTo(out); } catch (Exception ex) { } return out; } /** * Saves bytes into a new gridfile * * @param bytes * @return the id of the gridfile */ private ObjectId saveGridFile(byte[] bytes) { try { GridFSInputFile file = DbManager.getSocial().getShareBinary().createFile(bytes); file.save(); return (ObjectId) file.getId(); } catch (Exception ex) { } return null; } /** * Updates a gridfile with new data, if binaryId is null * the old gridfile did not exist, just create a new one. * * If it is not null, will remove and create a new entry. * * @param binaryId * @param bytes * @return */ private ObjectId updateGridFile(ObjectId binaryId, byte[] bytes) { try { //create new file GridFSInputFile file = DbManager.getSocial().getShareBinary().createFile(bytes); file.save(); //remove old file if exists (this way if file throws an exception we don't lose the old file) if (binaryId != null) DbManager.getSocial().getShareBinary().remove(binaryId); return (ObjectId) file.getId(); } catch (Exception ex) { } return binaryId; } static private void mustBeOwnerOrAdmin(String userIdStr, BasicDBObject query) { if (!RESTTools.adminLookup(userIdStr)) { query.put("owner._id", new ObjectId(userIdStr)); } } // Utility: make life easier in terms of adding/update/inviting/leaving from the command line private static String allowCommunityRegex(String userIdStr, String communityIdStr) { return allowCommunityRegex(userIdStr, communityIdStr, false); } private static String allowCommunityRegex(String userIdStr, String communityIdStr, boolean bAllowMulti) { if (communityIdStr.startsWith("*")) { String[] communityIdStrs = SocialUtils.getCommunityIds(userIdStr, communityIdStr); if (1 == communityIdStrs.length) { communityIdStr = communityIdStrs[0]; } else if ((bAllowMulti) && (communityIdStrs.length > 1)) { StringBuffer sb = new StringBuffer(); for (String str : communityIdStrs) { if (sb.length() > 0) { sb.append(','); } sb.append(str); } return sb.toString(); } else { throw new RuntimeException("Invalid community pattern"); } } return communityIdStr; } ////////////////////////////////////////////////// // Ref utils private void setRefLocation(String type, DocumentLocationPojo documentLocation) { if (type.equalsIgnoreCase("doc_metadata.metadata")) { documentLocation.setDatabase("doc_metadata"); documentLocation.setCollection("metadata"); } else if (type.equalsIgnoreCase("local.file")) { documentLocation.setDatabase(null); documentLocation.setCollection(null); } else if (type.equalsIgnoreCase("custommr.customlookup")) { documentLocation.setDatabase("custommr"); documentLocation.setCollection("customlookup"); } else if (type.equalsIgnoreCase("feature.entity")) { documentLocation.setDatabase("feature"); documentLocation.setCollection("entity"); } else if (type.equalsIgnoreCase("feature.association")) { documentLocation.setDatabase("feature"); documentLocation.setCollection("association"); } else { throw new RuntimeException("Invalid share reference: " + type); } }//TESTED (all 4 types) private String getReferenceString(SharePojo share) { // FILE: if (null == share.getDocumentLocation().get_id()) { // local file based reference FileInputStream fin = null; Scanner s = null; try { File f = new File(share.getDocumentLocation().getCollection()); fin = new FileInputStream(f); s = new Scanner(fin, "UTF-8"); return (s.useDelimiter("\n").next()); } catch (Exception e) { return null; } finally { try { if (null != fin) fin.close(); if (null != s) s.close(); } catch (Exception e) { } // (probably just never opened) } } // DB: // Carry on, this is a database object HashSet<String> shareIdStrs = new HashSet<String>(); for (ShareCommunityPojo commIds : share.getCommunities()) { shareIdStrs.add(commIds.get_id().toString()); } String retVal = null; BasicDBObject query = new BasicDBObject(DocumentPojo._id_, share.getDocumentLocation().get_id()); // (same for all artifacts) String dbName = share.getDocumentLocation().getDatabase(); String collectionName = share.getDocumentLocation().getCollection(); BasicDBObject returnVal = (BasicDBObject) MongoDbManager.getCollection(dbName, collectionName) .findOne(query); try { BasicDBList communities = null; boolean bCustomJob = dbName.equals("custommr"); // (a bit different) boolean bFoundOverlap = false; if (!bCustomJob) { ObjectId communityId = (ObjectId) returnVal.get(DocumentPojo.communityId_); // (same for other artifacts) bFoundOverlap = shareIdStrs.contains(communityId.toString()); } else { communities = (BasicDBList) returnVal.get("communityIds"); // (shared across multiple json types) for (Object commIdObj : communities) { ObjectId commId = (ObjectId) commIdObj; if (shareIdStrs.contains(commId.toString())) { bFoundOverlap = true; break; } } } if (!bFoundOverlap) { throw new RuntimeException(""); // (turned into the common message below) } if (!bCustomJob) { // everything but custom jobs Date modifiedTime = returnVal.getDate(DocumentPojo.modified_); // (same for other artifacts) if (null != modifiedTime) { share.setModified(modifiedTime); } retVal = returnVal.toString(); } else { // custom jobs String database = returnVal.getString(CustomMapReduceJobPojo.outputDatabase_); if (null == database) { database = dbName; } Date modifiedTime = returnVal.getDate(CustomMapReduceJobPojo.lastCompletionTime_); if (null != modifiedTime) { share.setModified(modifiedTime); } String collection = returnVal.getString(CustomMapReduceJobPojo.outputCollection_); BasicDBObject returnVal2 = (BasicDBObject) MongoDbManager.getCollection(database, collection) .findOne(); retVal = returnVal2.toString(); } } catch (Exception e) { throw new RuntimeException("Document not found or permission issue (no overlapping communities)"); } return retVal; }//TESTED (normal + custom) public ResponsePojo createOrUpdateShare(String cookieLookup, SharePojo share, boolean readWrite, boolean returnContent) { ResponsePojo rp = null; String share_id = null; //need to get previous share so we can add in any previous fields if (share.get_id() != null) { share_id = share.get_id().toString(); ResponsePojo rp1 = getShare(cookieLookup, share_id, true); if (rp1.getResponse().isSuccess()) { SharePojo previous_share = (SharePojo) rp1.getData(); if (share.getType() == null) share.setType(previous_share.getType()); if (share.getTitle() == null) share.setTitle(previous_share.getTitle()); if (share.getDescription() == null) share.setDescription(previous_share.getDescription()); if (share.getCommunities() == null) share.setCommunities(previous_share.getCommunities()); if (share.getShare() == null) share.setShare(previous_share.getShare()); if (share.getDocumentLocation() == null) share.setDocumentLocation(previous_share.getDocumentLocation()); if (share.getBinaryData() == null) share.setBinaryData(previous_share.getBinaryData()); if (share.getBinaryId() == null) share.setBinaryId(previous_share.getBinaryId()); } else { //couldn't get previous share, return error return rp1; } } //STEP 1, call appropriate update/add function if (share.getBinaryData() != null) { //binary if (share_id == null) rp = addBinary(cookieLookup, share.getType(), share.getTitle(), share.getDescription(), share.getMediaType(), share.getBinaryData()); else rp = updateBinary(cookieLookup, share_id, share.getType(), share.getTitle(), share.getDescription(), share.getMediaType(), share.getBinaryData()); if (!rp.getResponse().isSuccess()) return rp; else { String saved_share_id = share_id; if (rp.getData() != null) saved_share_id = (String) rp.getData(); rp = getShare(cookieLookup, saved_share_id, false); if (!rp.getResponse().isSuccess()) return rp; } } else if (share.getDocumentLocation() != null) { //ref if (share_id == null) rp = addRef(cookieLookup, share.getType(), share.getDocumentLocation().getDatabase() + "." + share.getDocumentLocation().getCollection(), share.getDocumentLocation().get_id().toString(), share.getTitle(), share.getDescription()); else rp = updateRef(cookieLookup, share_id, share.getType(), share.getDocumentLocation().getDatabase() + "." + share.getDocumentLocation().getCollection(), share.getDocumentLocation().get_id().toString(), share.getTitle(), share.getDescription()); if (!rp.getResponse().isSuccess()) return rp; else { String saved_share_id = share_id; if (rp.getData() != null) saved_share_id = (String) rp.getData(); rp = getShare(cookieLookup, saved_share_id, false); if (!rp.getResponse().isSuccess()) return rp; } } else { //json rp = saveJson(cookieLookup, share_id, share.getType(), share.getTitle(), share.getDescription(), share.getShare()); if (!rp.getResponse().isSuccess()) return rp; } SharePojo saved_share = (SharePojo) rp.getData(); //STEP 2, handle comms (loop over passed in comms, adding any that dont exist, remove any leftovers StringBuilder sb = new StringBuilder(); List<ShareCommunityPojo> existingComms = saved_share.getCommunities(); for (ShareCommunityPojo scp : share.getCommunities()) { boolean found = false; for (ShareCommunityPojo scp_existing : existingComms) { if (scp_existing.get_id().equals(scp.get_id())) { existingComms.remove(scp_existing); found = true; break; } } if (!found) { rp = addCommunity(cookieLookup, saved_share.get_id().toString(), scp.get_id().toString(), scp.getComment(), readWrite); if (!rp.getResponse().isSuccess()) sb.append(scp.get_id().toString() + " "); } } for (ShareCommunityPojo scp : existingComms) { rp = removeCommunity(cookieLookup, saved_share.get_id().toString(), scp.get_id().toString()); if (!rp.getResponse().isSuccess()) sb.append(scp.get_id().toString() + " "); } //have to get share now to see it with updated comms rp = getShare(cookieLookup, saved_share.get_id().toString(), returnContent); if (sb.length() > 0) rp.getResponse().setMessage("Error adding/removing some of the communities: " + sb.toString()); return rp; } }