@Document(collectionName = "watchList") public class WatchedThread { @Id private String threadId; private Set<ProfileWatchOptions> watchers; @JsonIgnore private I10nLogger log = LoggerFactory.getLogger(WatchedThread.class); public WatchedThread() { watchers = new HashSet<>(); } public void addWatcher(final String profileId, final String frequency) { final ProfileWatchOptions toAdd = new ProfileWatchOptions(profileId, frequency); if (!watchers.contains(toAdd)) { watchers.add(toAdd); log.debug("logging.system.notification.userAddedWatching", profileId, threadId, frequency); } else { log.debug("logging.system.notification.userAlreadyWatching", profileId, threadId, frequency); } } public void removeWatcher(final String profileId, final String frequency) { if (watchers.remove(new ProfileWatchOptions(profileId, frequency))) { log.debug("logging.system.notification.userRemoveWatching", profileId, threadId, frequency); } else { log.debug("logging.system.notification.userUnableToRemove", profileId, threadId, frequency); } } public String getThreadId() { return threadId; } public void setThreadId(final String threadId) { this.threadId = threadId; } public Set<ProfileWatchOptions> getWatchers() { return watchers; } public void setWatchers(final Set<ProfileWatchOptions> watchers) { this.watchers = watchers; } @Override public String toString() { return "WatchedThreads{" + "threadId=" + threadId + ", watchers=" + watchers + '}'; } }
public class ContextPreferencesRepositoryImpl extends AbstractJongoRepository<ContextPreferences> implements ContextPreferencesRepository { private I10nLogger logger = LoggerFactory.getLogger(ContextPreferencesRepositoryImpl.class); @Override public Map<String, String> getEmailPreference(final String contextId) throws SocialException { try { String query = getQueryFor("social.system.preferences.emailPreferencesByContextId"); final HashMap tmp = getCollection().findOne(query, contextId).projection("{email:1,_id:0}").as(HashMap.class); if (tmp == null || !tmp.containsKey("email")) { throw new SocialException( "Current context " + contextId + "is missing email configuration"); } return (Map) tmp.get("email"); } catch (MongoException ex) { throw new SocialException("Unable to read email preferences for " + contextId); } } @Override public Map<String, Object> saveEmailConfig(final String contextId, Map<String, Object> emailPref) throws SocialException { try { String fQuery = getQueryFor("social.system.preferences.emailPreferencesByContextId"); String uQuery = getQueryFor("social.system.preferences.updateContextEmailPref"); checkCommandResult( getCollection() .update(fQuery, contextId) .with( uQuery, emailPref.get("host"), emailPref.get("encoding"), emailPref.get("port"), emailPref.get("auth"), emailPref.get("username"), emailPref.get("password"), emailPref.get("tls"), emailPref.get("replyTo"), emailPref.get("from"), emailPref.get("priority"), emailPref.get("subject"))); return emailPref; } catch (MongoDataException ex) { throw new SocialException("Unable to read email preferences for " + contextId); } } @Override public String findNotificationTemplate(final String contextId, final String notificationType) throws SocialException { try { String query = getQueryFor("social.system.preferences.notificationEmailByType"); Map qResult = getCollection() .findOne(query, contextId, notificationType.toUpperCase()) .projection("{\"templates.$\":1,_id:0}") .as(Map.class); if (qResult == null) { return null; } final List templates = (List) qResult.get("templates"); if (templates == null) { return null; } if (templates.isEmpty()) { throw new SocialException( "No template for type" + notificationType + " has been define for context " + "" + contextId); } else { if (templates.size() > 1) { logger.warn( "logging.system.notification.multipleTemplatesForType", notificationType, contextId); } return ((Map) templates.get(0)).get("template").toString(); } } catch (MongoException ex) { throw new SocialException( "Unable to get Notification Template for " + contextId + " of type" + notificationType); } } @Override public Map<String, Object> getContextPreferences(final String contextId) { try { final String byId = getQueryFor("social.system.preferences.emailPreferencesByContextId"); return getCollection() .findOne(byId, contextId) .projection("{preferences:1,_id:0}") .as(HashMap.class); } catch (MongoException ex) { return new HashMap<>(); } } @Override public Map<String, Object> getContextAllPreferences(final String contextId) { try { final String byId = getQueryFor("social.system.preferences.emailPreferencesByContextId"); return getCollection().findOne(byId, contextId).as(HashMap.class); } catch (MongoException ex) { return new HashMap<>(); } } @Override public boolean setContextPreferences( final Map<String, Object> preferences, final String contextId) { try { final String preferencesString = new ObjectMapper().writeValueAsString(preferences); final String byId = getQueryFor("social.system.preferences.emailPreferencesByContextId"); getCollection().update(byId, contextId).with("{$set: " + preferencesString + "}"); return true; } catch (MongoException | JsonProcessingException e) { logger.error("Unable to delete context Preferences", e); return false; } } @Override public boolean deleteContextPreferences(final String context, final List<String> preferences) { try { final String byId = getQueryFor("social.system.preferences.emailPreferencesByContextId"); String toUnset = ""; final Iterator<String> iter = preferences.iterator(); while (iter.hasNext()) { final String key = iter.next(); toUnset += "preferences." + key + ":1"; if (iter.hasNext()) { toUnset += ","; } } getCollection().update(byId, context).with("{$unset:{" + toUnset + "}}"); return true; } catch (MongoException e) { logger.error("Unable to delete context Preferences", e); return false; } } public void saveEmailPreference(final String contextId, Map<String, Object> emailPreferences) throws SocialException { try { String query = getQueryFor("social.system.preferences.savePreferencesByContextId"); String findQ = getQueryFor("social.system.preferences.emailPreferencesByContextId"); getCollection() .update(findQ, contextId) .upsert() .with( query, emailPreferences.get("host"), emailPreferences.get("encoding"), emailPreferences.get("port"), emailPreferences.get("auth"), emailPreferences.get("username"), emailPreferences.get("password"), emailPreferences.get("tls"), emailPreferences.get("replyTo"), emailPreferences.get("from"), emailPreferences.get("priority"), emailPreferences.get("subject")); } catch (MongoException ex) { throw new SocialException("Unable to read email preferences for " + contextId); } } @Override public void saveAllContextPreferences( final String contextId, final Map<String, Object> newPreferences) throws SocialException { try { checkCommandResult(getCollection().save(newPreferences)); } catch (MongoDataException ex) { throw new SocialException("Unable to save email Preferences"); } } @Override public boolean saveEmailTemplate(final String context, final String type, final String template) throws SocialException { try { String findQ = getQueryFor("social.system.preferences.byContextAndTemplateType"); String updateQ = getQueryFor("social.system.preferences.updateContextTemplateType"); final WriteResult r = getCollection().update(findQ, context, type.toUpperCase()).with(updateQ, template); checkCommandResult(r); return r.getN() == 1; } catch (MongoException | MongoDataException ex) { throw new SocialException("Unable to update Email template", ex); } } }
@SuppressWarnings("unchecked") public class UGCServiceImpl<T extends UGC> implements UGCService { private I10nLogger log = LoggerFactory.getLogger(UGCServiceImpl.class); private UGCRepository ugcRepository; private UgcPipeline pipeline; private Pattern invalidQueryKeys; private UgcFactory ugcFactory; private VirusScanner virusScanner; private Reactor reactor; private NotificationService notificationService; private List<String> arraySortFields; private TenantConfigurationService tenantConfigurationService; @Override @HasPermission(action = UGC_CREATE, type = SocialPermission.class) public UGC create( final String contextId, final String ugcParentId, final String targetId, final String textContent, final String subject, final Map attrs, final boolean isAnonymous) throws SocialException { log.debug("logging.ugc.creatingUgc", contextId, targetId, ugcParentId, subject, attrs); final UGC template = new UGC(subject, textContent, targetId); template.setAnonymousFlag(isAnonymous); T newUgc = (T) ugcFactory.newInstance(template); newUgc.setAttributes(attrs); try { if (ObjectId.isValid(ugcParentId)) { setupAncestors(newUgc, ugcParentId, contextId); } else { log.debug("logging.ugc.invalidParentId"); } if (StringUtils.isBlank(contextId)) { throw new IllegalArgumentException("context cannot be null"); } pipeline.processUgc(newUgc); ugcRepository.save(newUgc); final SocialEvent<T> event = new SocialEvent<>( newUgc, SocialSecurityUtils.getCurrentProfile().getId().toString(), UGCEvent.CREATE); event.setAttribute("baseUrl", calculateBaseUrl()); reactor.notify(UGCEvent.CREATE.getName(), Event.wrap(event)); setupAutoWatch(targetId, SocialSecurityUtils.getCurrentProfile(), contextId); log.info("logging.ugc.created", newUgc); return newUgc; } catch (MongoDataException ex) { log.error("logging.ugc.errorSaving", ex); throw new UGCException("Unable to Save UGC"); } } private String calculateBaseUrl() { HttpServletRequest request = RequestContext.getCurrent().getRequest(); return request.getScheme() + "://" + request.getServerName() + ("http".equals(request.getScheme()) && request.getServerPort() == 80 || "https".equals(request.getScheme()) && request.getServerPort() == 443 ? "" : ":" + request.getServerPort()) + request.getContextPath(); } public void setNotificationServiceImpl(NotificationService notificationService) { this.notificationService = notificationService; } private void setupAutoWatch( final String targetId, final Profile currentProfile, final String context) throws NotificationException { final Map<String, Object> profileMap = currentProfile.getAttributes(); if (profileMap.containsKey("defaultFrequency") && profileMap.containsKey("autoWatch")) { boolean autoWatch = currentProfile.getAttribute("autoWatch"); if (autoWatch) { notificationService.subscribeUser( currentProfile, context + "/" + targetId, (String) currentProfile.getAttribute("defaultFrequency")); } } else { log.debug("Profile don't have set either defaultFrequency or autoWatch attributes"); } } @Override @HasPermission(action = UGC_UPDATE, type = SocialPermission.class) public void setAttributes( @SecuredObject final String ugcId, final String contextId, final Map attributes) throws SocialException, UGCNotFound { log.debug("logging.ugc.addingAttributes", attributes, ugcId, contextId); try { T toUpdate = (T) ugcRepository.findUGC(contextId, ugcId); if (toUpdate == null) { throw new UGCNotFound("Unable to found ugc with id " + ugcId); } final Map attrs = toUpdate.getAttributes(); attrs.putAll(attrs); ugcRepository.setAttributes(ugcId, contextId, attrs); final SocialEvent<T> event = new SocialEvent<T>( ugcId, attributes, SocialSecurityUtils.getCurrentProfile().getId().toString(), UGCEvent.UPDATE_ATTRIBUTES); event.setAttribute("baseUrl", calculateBaseUrl()); reactor.notify(UGCEvent.UPDATE_ATTRIBUTES.getName(), Event.wrap(event)); } catch (MongoDataException ex) { log.debug("logging.ugc.unableToAddAttrs", ex, attributes, ugcId, contextId); throw new UGCException("Unable to add Attributes to UGC", ex); } } @Override @HasPermission(action = UGC_UPDATE, type = SocialPermission.class) public void deleteAttribute( @SecuredObject final String ugcId, final String[] attributesName, final String contextId) throws SocialException { log.debug("logging.ugc.deleteAttributes", attributesName, ugcId); try { ugcRepository.deleteAttribute(ugcId, contextId, attributesName); final SocialEvent<T> event = new SocialEvent<T>( ugcId, SocialSecurityUtils.getCurrentProfile().getId().toString(), UGCEvent.DELETE_ATTRIBUTES); event.setAttribute("baseUrl", calculateBaseUrl()); reactor.notify(UGCEvent.DELETE_ATTRIBUTES.getName(), Event.wrap(event)); } catch (MongoDataException ex) { log.debug("logging.ugc.unableToDelAttrs", ex, attributesName, ugcId); throw new UGCException("Unable to delete attribute for ugc", ex); } } @Override @HasPermission(action = UGC_DELETE, type = SocialPermission.class) public boolean deleteUgc(final String ugcId, final String contextId) throws SocialException { log.debug("logging.ugc.deleteUgc", ugcId); try { ugcRepository.deleteUgc(ugcId, contextId); final SocialEvent<T> event = new SocialEvent<T>( ugcId, SocialSecurityUtils.getCurrentProfile().getId().toString(), UGCEvent.DELETE); event.setAttribute("baseUrl", calculateBaseUrl()); reactor.notify(UGCEvent.DELETE.getName(), Event.wrap(event)); } catch (MongoDataException ex) { log.error("logging.ugc.deleteUgcError", ex, ugcId, contextId); throw new UGCException("Unable to delete UGC", ex); } return false; } @Override @HasPermission(action = UGC_UPDATE, type = SocialPermission.class) public UGC update( @SecuredObject final String ugcId, final String body, final String subject, final String contextId, final Map attributes) throws SocialException, UGCNotFound { log.debug("logging.ugc.updateUgc", ugcId); try { final Profile currentProfile = SocialSecurityUtils.getCurrentProfile(); boolean moderateByMail = Boolean.parseBoolean( tenantConfigurationService.getProperty(contextId, "moderateByMailEnable").toString()); if (!ObjectId.isValid(ugcId)) { throw new IllegalArgumentException("Given UGC Id is not valid"); } T toUpdate = (T) ugcRepository.findUGC(contextId, ugcId); if (toUpdate == null) { throw new IllegalArgumentException("UGC with Id " + ugcId + " does not exists"); } if (StringUtils.isNotBlank(body)) { toUpdate.setBody(body); } if (StringUtils.isNotBlank(subject)) { toUpdate.setBody(subject); } pipeline.processUgc(toUpdate); if (moderateByMail && !SocialSecurityUtils.isProfileModeratorOrAdmin(currentProfile, contextId)) { if (toUpdate instanceof SocialUgc) { ((SocialUgc) toUpdate).setModerationStatus(ModerationStatus.UNMODERATED); } } ugcRepository.update(ugcId, toUpdate, false, false); final SocialEvent<T> event = new SocialEvent<>( toUpdate, SocialSecurityUtils.getCurrentProfile().getId().toString(), UGCEvent.UPDATE); event.setAttribute("baseUrl", calculateBaseUrl()); reactor.notify(UGCEvent.UPDATE.getName(), Event.wrap(event)); if (attributes != null && !attributes.isEmpty()) { toUpdate.getAttributes().putAll(attributes); // ToDo This should be one query, problem is with deep attributes !! setAttributes(toUpdate.getId().toString(), contextId, toUpdate.getAttributes()); reactor.notify(UGCEvent.UPDATE_ATTRIBUTES, Event.wrap(attributes)); } log.info("logging.ugc.updatedUgc", ugcId); return toUpdate; } catch (MongoDataException ex) { log.error("logging.ugc.unableToUpdateUgc", ex); throw new UGCException("Unable to removeWatcher UGC", ex); } } @Override @HasPermission(action = UGC_READ, type = SocialPermission.class) public T read( final String ugcId, final boolean includeChildren, final int childCount, final String contextId) throws UGCException { try { if (includeChildren) { return getUgcTree(ugcId, childCount, contextId); } else { return (T) ugcRepository.findUGC(contextId, ugcId); } } catch (MongoDataException e) { log.error("logging.ugc.unableToRead"); throw new UGCException("Unable to find ugc by name"); } } @Override @HasPermission(action = UGC_READ, type = SocialPermission.class) public Iterable<T> readByTargetId(final String targetId, final String contextId) throws UGCException { log.debug("logging.ugc.findingByTarget", targetId, contextId); try { return buildUgcTreeList( IterableUtils.toList(ugcRepository.findByTargetId(targetId, contextId)), Integer.MAX_VALUE); } catch (MongoDataException ex) { log.error("logging.ugc.unableRead", ex); throw new UGCException("Unable to ", ex); } } @Override @HasPermission(action = UGC_READ, type = SocialPermission.class) public Iterable<T> search( final String contextId, final String query, final String sort, final int start, final int limit) throws UGCException { log.debug( "Finding all ugc of context {} with user query {} sorted by {} skipping {} and with a limit of {}", contextId, query, sort, start, limit); isQueryValid(query); try { return ugcRepository.findByUserQuery(contextId, query, sort, start, limit); } catch (MongoDataException ex) { log.error("Unable to find User with given query" + query + " sorted by " + sort, ex); throw new UGCException("Unable to find Ugc with user query ", ex); } } @Override @HasPermission(action = UGC_UPDATE, type = SocialPermission.class) public FileInfo addAttachment( @SecuredObject final String ugcId, final String contextId, final InputStream attachment, final String fileName, final String contentType) throws FileExistsException, UGCException { String internalFileName = File.separator + contextId + File.separator + ugcId + File.separator + fileName; try { checkForVirus(attachment); } catch (IOException | VirusScannerException ex) { log.error("logging.ugc.errorScanVirus", ex); return null; } try { UGC ugc = ugcRepository.findUGC(contextId, ugcId); if (ugc == null) { throw new IllegalUgcException("UGC with given Id does not exist"); } FileInfo info = ugcRepository.saveFile(attachment, internalFileName, contentType); try { info.setFileName(new URLCodec().decode(fileName)); } catch (DecoderException e) { info.setFileName(fileName); } info.setAttribute("owner", ugcId); ugc.getAttachments().add(info); ugcRepository.update(ugcId, ugc); reactor.notify( UGCEvent.ADD_ATTACHMENT.getName(), Event.wrap( new SocialEvent<>( ugcId, new InputStream[] {new CloseShieldInputStream(attachment)}))); return info; } catch (MongoDataException e) { log.error("logging.ugc.unableToSaveAttachment", e, internalFileName); throw new UGCException("Unable to save File to UGC"); } } private void checkForVirus(final InputStream attachment) throws IOException { virusScanner.scan(new CloseShieldInputStream(attachment)); } @Override @HasPermission(action = UGC_UPDATE, type = SocialPermission.class) public void removeAttachment( @SecuredObject final String ugcId, final String contextId, final String attachmentId) throws UGCException, FileNotFoundException { try { UGC ugc = ugcRepository.findUGC(contextId, ugcId); if (ugc == null) { throw new IllegalUgcException("UGC with given Id does not exist"); } if (!ObjectId.isValid(attachmentId)) { throw new IllegalArgumentException("Given Attachment id is not valid"); } ObjectId attachmentOid = new ObjectId(attachmentId); FileInfo info = ugcRepository.getFileInfo(attachmentOid); if (!info.getStoreName().startsWith(File.separator + contextId)) { throw new IllegalSocialQueryException( "Given Attachment does not belong to the given context"); } ugc.getAttachments().remove(info); ugcRepository.deleteFile(attachmentOid); ugcRepository.update(ugcId, ugc); reactor.notify( UGCEvent.DELETE_ATTACHMENT.getName(), Event.wrap(new SocialEvent<>(ugcId, attachmentId, UGCEvent.DELETE_ATTACHMENT))); } catch (MongoDataException e) { log.error("logging.ugc.attachmentToRemove", e, attachmentId); throw new UGCException("Unable to save File to UGC"); } } @Override @HasPermission(action = UGC_UPDATE, type = SocialPermission.class) public FileInfo updateAttachment( @SecuredObject final String ugcId, final String contextId, final String attachmentId, final InputStream newAttachment) throws UGCException, FileNotFoundException { if (!ObjectId.isValid(ugcId)) { throw new IllegalArgumentException("Given Ugc Id is not valid"); } if (!ObjectId.isValid(attachmentId)) { throw new IllegalArgumentException("Given UGC Id is not valid"); } try { T ugc = (T) ugcRepository.findUGC(contextId, ugcId); if (ugc == null) { throw new IllegalUgcException("Given UGC Id does not exists"); } FileInfo oldInfo = ugcRepository.getFileInfo(attachmentId); ugc.getAttachments().remove(oldInfo); FileInfo newInfo = ugcRepository.updateFile( new ObjectId(attachmentId), newAttachment, oldInfo.getFileName(), oldInfo.getContentType(), true); ugc.getAttachments().add(newInfo); ugcRepository.update(ugcId, ugc); reactor.notify( UGCEvent.DELETE_ATTACHMENT.getName(), Event.wrap(new SocialEvent<>(ugcId, attachmentId, UGCEvent.DELETE_ATTACHMENT))); reactor.notify( UGCEvent.ADD_ATTACHMENT.getName(), Event.wrap( new SocialEvent<>( ugcId, new InputStream[] {new CloseShieldInputStream(newAttachment)}), UGCEvent.ADD_ATTACHMENT)); return newInfo; } catch (MongoDataException e) { log.error("logging.ugc.attachmentError"); throw new UGCException("Unable to removeWatcher Attachment"); } catch (FileExistsException e) { log.error("logging.ugc.attachmentNotFound", attachmentId); throw new UGCException("Unable to find attachment with given id", e); } } @Override @HasPermission(action = UGC_READ, type = SocialPermission.class) public FileInfo readAttachment( final String ugcId, final String contextId, final String attachmentId) throws FileNotFoundException, UGCException { if (!ObjectId.isValid(ugcId)) { throw new IllegalArgumentException("Given Ugc Id is not valid"); } if (!ObjectId.isValid(attachmentId)) { throw new IllegalArgumentException("Given attachment Id is not valid"); } try { UGC ugc = ugcRepository.findUGC(contextId, ugcId); if (ugc == null) { throw new IllegalUgcException("UGC with given Id does not exist"); } ObjectId attachmentOid = new ObjectId(attachmentId); FileInfo info = ugcRepository.readFile(attachmentOid); if (!info.getStoreName().startsWith(File.separator + contextId)) { throw new IllegalSocialQueryException( "Given Attachment does not belong to the given context"); } return info; } catch (MongoDataException ex) { log.error("logging.ugc.attachmentNotFound", ex, attachmentId); throw new UGCException("Unable to read file", ex); } } @Override @HasPermission(action = UGC_READ, type = SocialPermission.class) public List<T> read( final String targetId, final String contextId, final int start, final int limit, final List sortOrder, final int upToLevel, final int childrenPerLevel) throws UGCException { try { List<T> list = IterableUtils.toList( ugcRepository.findByTargetId( targetId, contextId, start, limit, sortOrder, upToLevel)); list = sortByArrays(list, sortOrder); return buildUgcTreeList(list, childrenPerLevel); } catch (MongoDataException e) { log.error("logging.ugc.unableToRead"); throw new UGCException("Unable to find ugc by target"); } } private List<T> sortByArrays( final List<T> list, final List<DefaultKeyValue<String, Boolean>> sortOrder) { if (sortOrder == null || list == null) { return list; } for (final DefaultKeyValue<String, Boolean> sort : sortOrder) { if (arraySortFields.contains(sort.getKey())) { Collections.sort( list, new Comparator<T>() { @Override public int compare(final T o1, final T o2) { try { Collection<Object> arrayToCompare1 = (Collection<Object>) PropertyUtils.getProperty(o1, sort.getKey()); Collection<Object> arrayToCompare2 = (Collection<Object>) PropertyUtils.getProperty(o2, sort.getKey()); int orderOfSort = sort.getValue() ? 1 : -1; // true ASC,false DESC // I'm sorry for this:D if (arrayToCompare1.size() < arrayToCompare2.size()) { return -1 * orderOfSort; } else if (arrayToCompare1.size() > arrayToCompare2.size()) { return 1 * orderOfSort; } else { return 0; } } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException | ClassCastException e) { log.error("Unable to sort by " + sort.getKey(), e); return 0; } } }); } } return list; } @Override @HasPermission(action = UGC_READ, type = SocialPermission.class) public List<T> readChildren( final String ugcId, final String targetId, final String contextId, final int start, final int limit, final List sortOrder, final int upToLevel, final int childrenPerLevel) throws UGCException, UGCNotFound { log.debug("logging.ugc.readChildren", ugcId, contextId, limit, start); try { return buildUgcTreeList( IterableUtils.toList( ugcRepository.findChildren( ugcId, targetId, contextId, start, limit, sortOrder, upToLevel)), childrenPerLevel); } catch (MongoDataException ex) { log.error("logging.ugc.unableToRead", ex); throw new UGCException("Unable to ", ex); } } @Override @HasPermission(action = UGC_READ, type = SocialPermission.class) public UGC read(final String ugcId, final String contextId) throws UGCException { try { return ugcRepository.findUGC(contextId, ugcId); } catch (MongoDataException e) { log.error("logging.ugc.unableToReadP", e, ugcId, contextId); throw new UGCException("Unable to find UGC with given ID and context"); } } @Override @HasPermission(action = UGC_READ, type = SocialPermission.class) public long count(final String threadId, final String contextId) throws UGCException { try { return ugcRepository.countByTargetId(contextId, threadId, 0); } catch (MongoDataException e) { log.error("logging.ugc.unableToCount"); throw new UGCException("Unable to count UGC by target and context", e); } } @Override @HasPermission(action = UGC_READ, type = SocialPermission.class) public long countChildren(final String ugcId, final String contextId) throws UGCException { try { return ugcRepository.countChildrenOf(contextId, ugcId); } catch (MongoDataException ex) { log.error("logging.ugc.unableToCount", ex); throw new UGCException("Unable to count children of Ugc"); } } private void isQueryValid(final String query) { if (invalidQueryKeys.matcher(query).find()) { throw new IllegalSocialQueryException( "Given Query '" + query + "' contains invalid selectors"); } } /** * Given a list of results Builds A UGC Tree. * * <p>The main difference from {@link #buildUgcTree(java.util.List)} is that this method allows * for multiple Roots or not roots at all * * @param ugs List of the UGS to build the tree. * @param childrenPerLevel Levels of Children. * @return A List Ugcs (Roots) all roots have there children if any. */ protected List<T> buildUgcTreeList(List<T> ugs, final int childrenPerLevel) { if (ugs.isEmpty()) { return null; } ArrayList<T> toReturn = new ArrayList<>(); LinkedList<T> stack = new LinkedList<>(); stack.addAll(ugs); while (!stack.isEmpty()) { T tmp = stack.pop(); if (!findRelatives(ugs, tmp, childrenPerLevel)) { toReturn.add(tmp); } } return toReturn; } /** * Using <i>ugcToTest</i> goes though <i>ugs</i> one by one and checks if the element either it's * parent or one of it's children. * * @param ugs List of UGC to check against. * @param ugcToTest Ugc to check. * @param childrenPerLevel * @return True if a Parent or children is found. False if is a Root (not parents , or is a leaf). */ protected boolean findRelatives(List<T> ugs, T ugcToTest, final int childrenPerLevel) { for (T ug : ugs) { if (ugcToTest.isMyParent(ug)) { if (ug.getChildren().size() < childrenPerLevel) { ug.getChildren().add(ugcToTest); return true; } } if (ug.isMyChild(ugcToTest)) { if (ugcToTest.getChildren().size() < childrenPerLevel) { ugcToTest.getChildren().add(ug); return true; } } } return false; } /** * Generates the ancestors ordered list for the ugc. * * @param newUgc UGC to setup ancestors. * @param ugcParentId Parent Id. * @throws MongoDataException * @throws UGCException */ private void setupAncestors(final UGC newUgc, final String ugcParentId, final String contextId) throws MongoDataException, UGCException { UGC parent = ugcRepository.findUGC(contextId, ugcParentId); if (parent == null) { throw new UGCException("Parent UGC does not exist"); } ObjectId parentId = new ObjectId(ugcParentId); ArrayDeque<ObjectId> ancestors = parent.getAncestors().clone(); if (ancestors.isEmpty() || !ancestors.getLast().equals(parentId)) { ancestors.addLast(parentId); newUgc.setAncestors(ancestors); } } public void setReactor(Reactor reactor) { this.reactor = reactor; } public void setUGCRepositoryImpl(UGCRepository UGCRepositoryImpl) { ugcRepository = UGCRepositoryImpl; } public void setPipeline(UgcPipeline pipeline) { this.pipeline = pipeline; } public void setInvalidQueryKeys(final String invalidQueryKeysPattern) { invalidQueryKeys = Pattern.compile(invalidQueryKeysPattern, Pattern.CASE_INSENSITIVE | Pattern.DOTALL); } public void setArraySortFields(final String arraySortFields) { this.arraySortFields = Arrays.asList(arraySortFields.split(",")); } public void setSocialUgcFactory(UgcFactory ugcFactory) { this.ugcFactory = ugcFactory; } public void setVirusScanner(final VirusScanner virusScanner) { this.virusScanner = virusScanner; } /** * Given a list of results Builds A UGC Tree. * * <p><b>The first element of the list will be taken as the root of the tree</b> * * @param ugs Lis of the UGS to build the tree. First Element will be the root. * @return A Ugc with its children array filled (and its children...). */ protected T buildUgcTree(List<T> ugs) { if (ugs.isEmpty()) { return null; } LinkedList<T> stack = new LinkedList<>(); stack.addAll(ugs); T root = stack.pop(); root.setChildren(new ArrayDeque()); while (!stack.isEmpty()) { T tmp = stack.pop(); if (tmp.isMyParent(root)) { root.getChildren().add(tmp); } else { findMyParent(root.getChildren(), tmp); } } return root; } /** * Finds the parent of the orphanChild in the list of possible parents. It will also go * recursively to the children's children until there is nothing left. <b>Is possible that it will * never finds a parent (the orphanChild will be dispose silently</b> * * @param possibleParents Possible parent of orphanChild * @param orphanChild UGC to find it's parent. */ protected void findMyParent(final Collection<T> possibleParents, final UGC orphanChild) { for (T child : possibleParents) { if (orphanChild.isMyParent(child)) { child.getChildren().add(orphanChild); return; } } for (T child : possibleParents) { findMyParent(child.getChildren(), orphanChild); } } private T getUgcTree(final String ugcId, final int childCount, final String contextId) throws MongoDataException { List<T> list = ugcRepository.findChildrenOf(ugcId, childCount, contextId); return buildUgcTree(list); } public void setTenantConfigurationService( final TenantConfigurationService tenantConfigurationService) { this.tenantConfigurationService = tenantConfigurationService; } }