/src/main/java/com/google/ie/business/service/impl/IdeaServiceImpl.java

http://thoughtsite.googlecode.com/ · Java · 987 lines · 660 code · 84 blank · 243 comment · 146 complexity · 1972b874933bef23a7b2315dae144883 MD5 · raw file

  1. /* Copyright 2010 Google Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS.
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License
  14. */
  15. package com.google.ie.business.service.impl;
  16. import com.google.ie.business.dao.AdminRequestDao;
  17. import com.google.ie.business.dao.IdeaDao;
  18. import com.google.ie.business.dao.impl.DaoConstants;
  19. import com.google.ie.business.domain.AdminRequest;
  20. import com.google.ie.business.domain.EntityIndex;
  21. import com.google.ie.business.domain.Idea;
  22. import com.google.ie.business.domain.Project;
  23. import com.google.ie.business.domain.Tag;
  24. import com.google.ie.business.domain.User;
  25. import com.google.ie.business.service.EntityIndexService;
  26. import com.google.ie.business.service.IdeaService;
  27. import com.google.ie.business.service.ProjectService;
  28. import com.google.ie.business.service.ServiceConstants;
  29. import com.google.ie.business.service.ShardedCounterService;
  30. import com.google.ie.business.service.TagService;
  31. import com.google.ie.business.service.UserService;
  32. import com.google.ie.common.audit.AuditManager;
  33. import com.google.ie.common.cache.CacheConstants;
  34. import com.google.ie.common.cache.CacheHelper;
  35. import com.google.ie.common.constants.IdeaExchangeConstants;
  36. import com.google.ie.common.constants.IdeaExchangeErrorCodes;
  37. import com.google.ie.common.exception.SystemException;
  38. import com.google.ie.common.objectionable.ObjectionableManager;
  39. import com.google.ie.common.taskqueue.IndexQueueUpdater;
  40. import com.google.ie.common.taskqueue.TagWeightUpdationManager;
  41. import com.google.ie.dto.RetrievalInfo;
  42. import org.apache.commons.lang.StringUtils;
  43. import org.apache.log4j.Logger;
  44. import org.springframework.beans.factory.annotation.Autowired;
  45. import org.springframework.stereotype.Service;
  46. import org.springframework.transaction.annotation.Propagation;
  47. import org.springframework.transaction.annotation.Transactional;
  48. import java.util.ArrayList;
  49. import java.util.Date;
  50. import java.util.HashMap;
  51. import java.util.HashSet;
  52. import java.util.Iterator;
  53. import java.util.LinkedList;
  54. import java.util.List;
  55. import java.util.Map;
  56. import java.util.Set;
  57. /**
  58. * A service implementation of the IdeaService
  59. *
  60. * @author Charanjeet singh
  61. */
  62. @Service
  63. public class IdeaServiceImpl implements IdeaService {
  64. private static Logger logger = Logger.getLogger(IdeaServiceImpl.class);
  65. private static boolean isDebug = logger.isDebugEnabled();
  66. /* Default number of recent ideas to be fetched */
  67. private static final int DEFAULT_NO_OF_RECENT_IDEAS = 3;
  68. /* Default number of popular ideas to be fetched */
  69. private static final int DEFAULT_NO_OF_POPULAR_IDEAS = 3;
  70. @Autowired
  71. private IdeaDao ideaDao;
  72. @Autowired
  73. private EntityIndexService entityIndexService;
  74. @Autowired
  75. private AuditManager auditManager;
  76. @Autowired
  77. private TagService tagService;
  78. @Autowired
  79. private TagWeightUpdationManager weightUpdationManager;
  80. @Autowired
  81. private UserService userService;
  82. @Autowired
  83. private ShardedCounterService shardedCounterService;
  84. @Autowired
  85. private AdminRequestDao adminRequestDao;
  86. @Autowired
  87. private ProjectService projectService;
  88. @Autowired
  89. private IndexQueueUpdater indexQueueUpdater;
  90. public IndexQueueUpdater getIndexQueueUpdater() {
  91. return indexQueueUpdater;
  92. }
  93. public void setIndexQueueUpdater(IndexQueueUpdater indexQueueUpdater) {
  94. this.indexQueueUpdater = indexQueueUpdater;
  95. }
  96. public IdeaServiceImpl() {
  97. }
  98. @Override
  99. public Idea saveIdea(Idea idea, User user) {
  100. user = userService.getUserById(user.getId());
  101. if (user != null) {
  102. if (idea != null && !StringUtils.isBlank(idea.getTitle()) &&
  103. !StringUtils.isBlank(user.getUserKey())) {
  104. if (isDebug) {
  105. logger.debug("Idea title=" + idea.getTitle() + " ,user key="
  106. + user.getUserKey());
  107. }
  108. Idea savedIdea = saveIdeaLocal(idea, user);
  109. return savedIdea;
  110. }
  111. }
  112. return null;
  113. }
  114. @Override
  115. public void deleteIdea(String key, User user) {
  116. Idea idea = new Idea();
  117. idea = ideaDao.findEntityByPrimaryKey(idea.getClass(), key);
  118. if (idea != null &&
  119. user != null && !StringUtils.isBlank(user.getUserKey())) {
  120. // Soft delete the idea.
  121. idea.setStatus(Idea.STATUS_DELETED);
  122. ideaDao.saveIdea(idea);
  123. }
  124. }
  125. /**
  126. * Saves an idea.
  127. *
  128. * @param idea Idea to be saved.
  129. * @return Returns the saved idea object.
  130. */
  131. private Idea saveIdeaLocal(Idea idea, User user) {
  132. if (!StringUtils.isBlank(idea.getStatus())
  133. && idea.getStatus().equals(Idea.STATUS_PUBLISHED)) {
  134. throw new SystemException(IdeaExchangeErrorCodes.INVALID_PUBLISH,
  135. IdeaExchangeConstants.Messages.INVALID_PUBLISH);
  136. }
  137. /* Handle tags. */
  138. String tagString = idea.getTags();
  139. if (!StringUtils.isBlank(tagString)) {
  140. logger.debug("Submitted tags=" + tagString);
  141. idea.setTags(formatTagString(tagString));
  142. }
  143. /* Update the status and save in data store */
  144. idea.setCreatorKey(user.getUserKey());
  145. idea.setStatus(Idea.STATUS_SAVED);
  146. idea.setLastUpdated(new Date(System.currentTimeMillis()));
  147. idea = getIdeaDao().saveIdea(idea);
  148. if (idea != null && !StringUtils.isBlank(idea.getKey())) {
  149. /* Add saved idea key into users ideaKeys set. */
  150. addIdeaKeyToUser(idea, user);
  151. logger.info("Idea with title='" + idea.getTitle() + "', saved successfully");
  152. }
  153. return idea;
  154. }
  155. @Override
  156. @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
  157. public Idea publishIdea(Idea idea, User user) {
  158. if (user != null) {
  159. /*
  160. * boolean specifying whether the idea to be published was earlier
  161. * marked as objectionable.If true no points would be added to the
  162. * user
  163. */
  164. boolean wasObjectionable = false;
  165. if (!StringUtils.isBlank(idea.getKey())) {
  166. /* If the idea is already published,throw exception */
  167. if (Idea.STATUS_PUBLISHED.equals(idea.getStatus())) {
  168. throw new SystemException(IdeaExchangeErrorCodes.INVALID_PUBLISH,
  169. IdeaExchangeConstants.Messages.INVALID_PUBLISH);
  170. }
  171. /*
  172. * If the idea was earlier objectionable,set the boolean to
  173. * true.
  174. */
  175. if (Idea.STATUS_OBJECTIONABLE.equalsIgnoreCase(idea.getStatus())) {
  176. wasObjectionable = true;
  177. }
  178. }
  179. if (!StringUtils.isBlank(idea.getTitle()) &&
  180. !StringUtils.isBlank(user.getUserKey())) {
  181. if (isDebug) {
  182. logger.debug("User key=" + user.getUserKey() + " ,idea title="
  183. + idea.getTitle());
  184. }
  185. String tagString = idea.getTags();
  186. if (!StringUtils.isBlank(tagString)) {
  187. if (isDebug) {
  188. logger.debug("Submitted tags=" + tagString);
  189. }
  190. idea.setTags(formatTagString(tagString));
  191. }
  192. idea.setCreatorKey(user.getUserKey());
  193. idea.setStatus(Idea.STATUS_PUBLISHED);
  194. idea.setLastUpdated(new Date(System.currentTimeMillis()));
  195. idea.setPublishDate(new Date(System.currentTimeMillis()));
  196. /* Persist idea object. */
  197. idea = publishIdeaLocal(idea);
  198. if (idea != null && !StringUtils.isBlank(idea.getKey())) {
  199. return performAfterPublish(idea, user, wasObjectionable);
  200. }
  201. }
  202. }
  203. return null;
  204. }
  205. @SuppressWarnings("unchecked")
  206. @Override
  207. public LinkedList<Idea> getRecentIdeas() {
  208. /* Check the cache for the data */
  209. LinkedList<Idea> listOfRecentIdeas = (LinkedList<Idea>) CacheHelper.getObject(
  210. CacheConstants.IDEA_NAMESPACE,
  211. CacheConstants.RECENT_IDEAS);
  212. if (listOfRecentIdeas != null && listOfRecentIdeas.size() > ServiceConstants.ZERO) {
  213. logger.info("Recent ideas successfully fetched from cache");
  214. return listOfRecentIdeas;
  215. }
  216. /* If not found in cache then retrieve from data store. */
  217. RetrievalInfo retrievalInfo = new RetrievalInfo();
  218. retrievalInfo.setNoOfRecords(DEFAULT_NO_OF_RECENT_IDEAS);
  219. retrievalInfo.setOrderBy(ServiceConstants.DEFAULT_IDEA_ORDERING_FIELD);
  220. retrievalInfo.setOrderType(ServiceConstants.ORDERING_TYPE_FOR_RECENT_IDEAS);
  221. /* Fetch the ideas and create a linked list from the fetched data */
  222. listOfRecentIdeas = createLinkedListFromTheFetchedData(getIdeas(retrievalInfo));
  223. /* If the list contains data, add it to the cache */
  224. if (listOfRecentIdeas.size() > ServiceConstants.ZERO) {
  225. CacheHelper.putObject(CacheConstants.IDEA_NAMESPACE, CacheConstants.RECENT_IDEAS,
  226. listOfRecentIdeas, CacheConstants.RECENT_IDEAS_EXPIRATION_DELAY);
  227. logger.info("Recent ideas successfully added to the cache");
  228. }
  229. return listOfRecentIdeas;
  230. }
  231. /**
  232. * It performs all other activity, which are needed after publishing the
  233. * idea.
  234. *
  235. * @param idea The published {@link Idea} object.
  236. * @param user The {@link User} who has published the idea.
  237. * @param wasObjectionale whether the idea was earlier an objectionable one
  238. * @return Idea object.
  239. */
  240. private Idea performAfterPublish(Idea idea, User user, boolean wasObjectionale) {
  241. logger.info("Idea with title=" + idea.getTitle() + ", saved successfully");
  242. /* If the idea is a new one add points to the user */
  243. if (!wasObjectionale) {
  244. /* Add saved idea key into users ideaKeys set. */
  245. user = addIdeaKeyToUser(idea, user);
  246. addPointsToUserOnIdeaPublish(user.getUserKey(), idea);
  247. }
  248. /* Place object into cache. */
  249. CacheHelper.putObject(CacheConstants.IDEA_NAMESPACE, idea.getKey(), idea);
  250. /* Place object into cache for recent ideas. */
  251. addIdeaToListInCache(idea, CacheConstants.RECENT_IDEAS,
  252. DEFAULT_NO_OF_RECENT_IDEAS, CacheConstants.RECENT_IDEAS_EXPIRATION_DELAY);
  253. String tagStr = idea.getTags();
  254. /* Increment Tags weights asynchronously. */
  255. if (tagStr != null && !tagStr.equals(""))
  256. getWeightUpdationManager().incrementWeight(tagStr);
  257. /* Audit the published activity. */
  258. getAuditManager().audit(user.getUserKey(), idea.getKey(), idea.getClass().getName(),
  259. ServiceConstants.AUDIT_ACTION_TYPE_PUBLISH_IDEA);
  260. /* Check idea for objectionable. */
  261. ObjectionableManager.checkObjectionable(idea.getKey());
  262. return idea;
  263. }
  264. @SuppressWarnings("unchecked")
  265. public void addIdeaToListInCache(Idea originalIdea, String keyOfTheList,
  266. int noOfIdeas, int expiryDelay) {
  267. LinkedList<Idea> listOfIdeas = (LinkedList<Idea>) CacheHelper.getObject(
  268. CacheConstants.IDEA_NAMESPACE,
  269. keyOfTheList);
  270. if (listOfIdeas != null) {
  271. if (listOfIdeas.size() >= noOfIdeas) {
  272. /* Remove the last element which is also the oldest */
  273. listOfIdeas.pollLast();
  274. }
  275. } else {
  276. listOfIdeas = new LinkedList<Idea>();
  277. }
  278. /* Create a new idea object to contain the required data only */
  279. Idea ideaWithTheRequiredDataOnly = new Idea();
  280. ideaWithTheRequiredDataOnly.setTitle(StringUtils.abbreviate(originalIdea.getTitle(),
  281. ServiceConstants.FIFTY));
  282. /* Limit the description to hundred characters */
  283. ideaWithTheRequiredDataOnly.setDescription(StringUtils.abbreviate(originalIdea
  284. .getDescription(), ServiceConstants.HUNDRED));
  285. ideaWithTheRequiredDataOnly.setKey(originalIdea.getKey());
  286. /* Add the idea to the head of the list */
  287. listOfIdeas.addFirst(ideaWithTheRequiredDataOnly);
  288. /* Put the updated list back to the cache */
  289. CacheHelper.putObject(CacheConstants.IDEA_NAMESPACE,
  290. keyOfTheList, listOfIdeas, expiryDelay);
  291. }
  292. /**
  293. * Update sharded counters for the users reputation point calculation.
  294. *
  295. * @param user
  296. * @param idea
  297. * @return
  298. */
  299. private void addPointsToUserOnIdeaPublish(String userKey, Idea idea) {
  300. int points = 0;
  301. if (!StringUtils.isBlank(idea.getTitle())) {
  302. points = points + IdeaExchangeConstants.REPUTATION_POINTS_TITLE;
  303. }
  304. if (!StringUtils.isBlank(idea.getDescription())) {
  305. points = points + IdeaExchangeConstants.REPUTATION_POINTS_DESCRIPTION;
  306. }
  307. if (!StringUtils.isBlank(idea.getMonetization())) {
  308. points = points + IdeaExchangeConstants.REPUTATION_POINTS_MONETIZATION;
  309. }
  310. if (!StringUtils.isBlank(idea.getCompetition())) {
  311. points = points + IdeaExchangeConstants.REPUTATION_POINTS_COMPETITION;
  312. }
  313. if (!StringUtils.isBlank(idea.getTargetAudience())) {
  314. points = points + IdeaExchangeConstants.REPUTATION_POINTS_TARGET_AUDIENCE;
  315. }
  316. updateShardedCounter(userKey, points);
  317. }
  318. /**
  319. * Update counter.
  320. *
  321. * @param user
  322. * @param points
  323. */
  324. @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
  325. private void updateShardedCounter(String userKey, int points) {
  326. shardedCounterService.updateTotalPoints(userKey, points);
  327. }
  328. /**
  329. * Adds the {@link Idea } key to user's idea key set on save and publish
  330. * idea.
  331. *
  332. * @param idea The saved/published {@link Idea} object.
  333. * @param user The {@link User} who has saved/published the idea.
  334. * @return User object.
  335. */
  336. private User addIdeaKeyToUser(Idea idea, User user) {
  337. if (idea.getKey() != null) {
  338. user.getIdeaKeys().add(idea.getKey());
  339. userService.saveUser(user);
  340. }
  341. return user;
  342. }
  343. @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
  344. public Idea publishIdeaLocal(Idea idea) {
  345. // Persist idea object.
  346. idea = getIdeaDao().saveIdea(idea);
  347. if (idea != null) {
  348. /*
  349. * Index the entity.Create an EntityIndex object for the entity
  350. * to be indexed and then queue the job to task queue
  351. */
  352. EntityIndex entityIndex = entityIndexService.createEntityIndex(idea.getKey());
  353. getIndexQueueUpdater().indexEntity(entityIndex.getKey());
  354. }
  355. return idea;
  356. }
  357. /**
  358. * Formats the tag string submitted by application user for display on view.
  359. *
  360. * @param tagString String having tags submitted by application user.
  361. * @return formated comma separate tags string.
  362. */
  363. protected final String formatTagString(String tagString) {
  364. String[] tags = tagString.trim().split("[\\s,]");
  365. StringBuilder sb = new StringBuilder();
  366. for (int i = 0; i < tags.length; i++) {
  367. String tmpString = tags[i].trim().toLowerCase();
  368. if (!tmpString.equals(""))
  369. sb.append(tmpString + ",");
  370. if (i == tags.length - 1)
  371. sb.deleteCharAt(sb.length() - 1);
  372. }
  373. return sb.toString();
  374. }
  375. @Override
  376. public Idea getIdeaDetails(Idea idea) {
  377. if (idea != null && !StringUtils.isBlank(idea.getKey())) {
  378. if (isDebug) {
  379. logger.debug("Retrieving idea details for the idea with key=" + idea.getKey());
  380. }
  381. return ideaDao.getIdea(idea);
  382. }
  383. return null;
  384. }
  385. @Override
  386. public List<Idea> getIdeas(RetrievalInfo retrievalInfo) {
  387. /*
  388. * Retrieve ideas based on the retrieval information. If retrievalInfo
  389. * object is null then use default parameter information.
  390. */
  391. retrievalInfo = prepareRetrievalInfoForQuery(retrievalInfo);
  392. /* Prepare the Set of status */
  393. Set<String> statusOfIdeas = new HashSet<String>();
  394. statusOfIdeas.add(Idea.STATUS_PUBLISHED);
  395. statusOfIdeas.add(Idea.STATUS_DUPLICATE);
  396. return ideaDao.getIdeas(retrievalInfo, statusOfIdeas);
  397. }
  398. @Override
  399. public boolean addSummary(String key, String summary, User user) {
  400. Idea idea = new Idea();
  401. idea = ideaDao.findEntityByPrimaryKey(idea.getClass(), key);
  402. if (idea == null || user == null
  403. || StringUtils.isBlank(idea.getKey())
  404. || StringUtils.isBlank(user.getUserKey())
  405. || StringUtils.isBlank(idea.getStatus())
  406. || !(idea.getStatus().equals(Idea.STATUS_PUBLISHED))
  407. || StringUtils.isBlank(idea.getCreatorKey())
  408. || !(idea.getCreatorKey().equals(user.getUserKey()))) {
  409. throw new SystemException(IdeaExchangeErrorCodes.INVALID_IDEA_SUMMARY,
  410. IdeaExchangeConstants.Messages.INVALID_IDEA_SUMMARY);
  411. }
  412. // Allow user to add Idea summary only once.
  413. if (StringUtils.isBlank(idea.getIdeaSummary())) {
  414. idea.setIdeaSummary(summary);
  415. getIdeaDao().saveIdea(idea);
  416. return true;
  417. }
  418. return false;
  419. }
  420. /* Returns the ideas saved or published by user */
  421. @Override
  422. public List<Idea> getIdeasForUser(User user, RetrievalInfo retrievalInfo) {
  423. if (user == null || StringUtils.isBlank(user.getUserKey())) {
  424. return null;
  425. }
  426. if (isDebug) {
  427. logger.debug("Retrieving ideas for the user with key=" + user.getUserKey());
  428. }
  429. /*
  430. * Retrieve user's ideas based on the retrieval information. In case of
  431. * listing user's ideas, ordering will be done on the field
  432. * 'lastUpdated'.
  433. */
  434. if (retrievalInfo == null) {
  435. retrievalInfo = new RetrievalInfo();
  436. }
  437. retrievalInfo.setOrderBy(DaoConstants.IDEA_ORDERING_FIELD_LAST_UPDATE_DATE);
  438. // Prepare retrieval parameters to fetch users idea.
  439. retrievalInfo = prepareRetrievalInfoForQuery(retrievalInfo);
  440. /* Prepare the Set of status */
  441. Set<String> statusOfIdeas = new HashSet<String>();
  442. statusOfIdeas.add(Idea.STATUS_SAVED);
  443. statusOfIdeas.add(Idea.STATUS_PUBLISHED);
  444. statusOfIdeas.add(Idea.STATUS_OBJECTIONABLE);
  445. statusOfIdeas.add(Idea.STATUS_DUPLICATE);
  446. return ideaDao.getUserIdeas(user, statusOfIdeas, retrievalInfo);
  447. }
  448. @Override
  449. public boolean updateStatus(Idea idea) {
  450. if (idea == null || StringUtils.isBlank(idea.getKey())) {
  451. return false;
  452. }
  453. if (isDebug) {
  454. logger.debug("updating status of idea for the key=" + idea.getKey());
  455. }
  456. return ideaDao.updateStatus(idea);
  457. }
  458. @Override
  459. public boolean updateIdeaVotes(Idea idea) {
  460. boolean flag = false;
  461. if (idea != null && !StringUtils.isBlank(idea.getKey())) {
  462. if (isDebug) {
  463. logger.debug("updating status of idea for the key=" + idea.getKey());
  464. }
  465. flag = ideaDao.updateIdeaPoints(idea);
  466. }
  467. return flag;
  468. }
  469. @Override
  470. public List<Idea> getIdeasByTagName(String tagName, RetrievalInfo retrievalInfo) {
  471. /*
  472. * If the tagname param is not null and is not empty then fetch the Tag
  473. * object through tag service
  474. */
  475. if (tagName != null && tagName.length() > ServiceConstants.ZERO) {
  476. Tag tag = tagService.getTagByName(tagName);
  477. /* If tag is not null then get the key of the tag */
  478. if (tag != null) {
  479. String tagKey = tag.getKey();
  480. /*
  481. * If the tag key contains value then fetch the
  482. * list of ideas associated with the tag key
  483. */
  484. if (tagKey.length() > ServiceConstants.ZERO) {
  485. retrievalInfo = prepareRetrievalInfoForQuery(retrievalInfo);
  486. Set<String> statusOfIdeas = new HashSet<String>();
  487. statusOfIdeas.add(Idea.STATUS_PUBLISHED);
  488. statusOfIdeas.add(Idea.STATUS_DUPLICATE);
  489. List<Idea> ideaList = ideaDao.getIdeasByTagKey(tagKey, statusOfIdeas,
  490. retrievalInfo);
  491. return ideaList;
  492. }
  493. }
  494. }
  495. return null;
  496. }
  497. @SuppressWarnings("unchecked")
  498. @Override
  499. public LinkedList<Idea> getPopularIdeas() {
  500. /* First check the cache for the data */
  501. LinkedList<Idea> popularIdeas = (LinkedList<Idea>) CacheHelper.getObject(
  502. CacheConstants.IDEA_NAMESPACE,
  503. CacheConstants.POPULAR_IDEAS);
  504. if (popularIdeas != null && popularIdeas.size() > ServiceConstants.ZERO) {
  505. logger.info("Popular ideas successfully fetched from cache");
  506. return popularIdeas;
  507. }
  508. /* If not in cache ,fetch from data store */
  509. RetrievalInfo retrievalInfo = new RetrievalInfo();
  510. /* Set the RetrievalInfo object to contain query parameters */
  511. retrievalInfo.setNoOfRecords(DEFAULT_NO_OF_POPULAR_IDEAS);
  512. retrievalInfo.setOrderBy(ServiceConstants.IDEA_ORDERING_FIELD_TOTAL_POSITIVE_VOTES);
  513. retrievalInfo.setOrderType(ServiceConstants.ORDERING_DESCENDING);
  514. /* Create the set of status conditions to be matched in the query */
  515. Set<String> statusOfIdeas = new HashSet<String>();
  516. statusOfIdeas.add(Idea.STATUS_PUBLISHED);
  517. /*
  518. * Fetch the ideas from the datastore and create a linked list from the
  519. * fetched ideas
  520. */
  521. popularIdeas = createLinkedListFromTheFetchedData(ideaDao.getIdeas(retrievalInfo,
  522. statusOfIdeas));
  523. if (popularIdeas.size() > ServiceConstants.ZERO) {
  524. /* Put popular ideas into cache */
  525. CacheHelper.putObject(CacheConstants.IDEA_NAMESPACE, CacheConstants.POPULAR_IDEAS,
  526. popularIdeas, CacheConstants.POPULAR_IDEAS_EXPIRATION_DELAY);
  527. logger.info("Popular ideas successfully added to the cache");
  528. }
  529. return popularIdeas;
  530. }
  531. /**
  532. * Prepares the {@link RetrievalInfo} object with values to be used as query
  533. * parameters.
  534. * Checks the received RetrievalInfo object attributes for valid
  535. * data.Updates the attributes if they contain garbage values.If the
  536. * received {@link RetrievalInfo} object is null,sets it to a new instance
  537. * with its attributes set to default values.
  538. *
  539. * @param retrievalInfo the {@link RetrievalInfo} object containing the
  540. * values to be used as query parameters
  541. * @return the {@link RetrievalInfo} object containing the query parameters
  542. */
  543. private RetrievalInfo prepareRetrievalInfoForQuery(RetrievalInfo retrievalInfo) {
  544. if (retrievalInfo == null) {
  545. retrievalInfo = new RetrievalInfo();
  546. retrievalInfo.setStartIndex(ServiceConstants.ZERO);
  547. retrievalInfo.setNoOfRecords(ServiceConstants.IDEAS_LIST_DEFAULT_SIZE);
  548. retrievalInfo.setOrderType(ServiceConstants.DEFAULT_IDEA_ORDERING_TYPE);
  549. retrievalInfo.setOrderBy(ServiceConstants.DEFAULT_IDEA_ORDERING_FIELD);
  550. } else {
  551. // Handle garbage values if any.
  552. String orderBY = retrievalInfo.getOrderBy();
  553. String orderType = retrievalInfo.getOrderType();
  554. if (retrievalInfo.getStartIndex() < ServiceConstants.ZERO)
  555. retrievalInfo.setStartIndex(ServiceConstants.ZERO);
  556. if (retrievalInfo.getNoOfRecords() <= ServiceConstants.ZERO)
  557. retrievalInfo.setNoOfRecords(ServiceConstants.IDEAS_LIST_DEFAULT_SIZE);
  558. if (orderType == null || !((orderType.equals(DaoConstants.ORDERING_ASCENDING)
  559. || orderType.equals(DaoConstants.ORDERING_DESCENDING))))
  560. retrievalInfo.setOrderType(ServiceConstants.DEFAULT_IDEA_ORDERING_TYPE);
  561. if (orderBY == null
  562. || !((orderBY.equals(DaoConstants.IDEA_ORDERING_FIELD_LAST_UPDATE_DATE)
  563. || orderBY.equals(DaoConstants.IDEA_ORDERING_FIELD_PUBLISH_DATE)
  564. || orderBY.equals(DaoConstants.IDEA_ORDERING_FIELD_VOTE)))) {
  565. retrievalInfo.setOrderBy(ServiceConstants.DEFAULT_IDEA_ORDERING_FIELD);
  566. }
  567. }
  568. return retrievalInfo;
  569. }
  570. /**
  571. * Create a linked list from the list of ideas received.Removes the data not
  572. * required on the homepage.This method is intended to create
  573. * list for Recent ideas and Popular ideas method
  574. *
  575. * @param ideas list of ideas
  576. * @return a {@link LinkedList} object containing the ideas
  577. */
  578. private LinkedList<Idea> createLinkedListFromTheFetchedData(List<Idea> ideas) {
  579. LinkedList<Idea> linkedList = new LinkedList<Idea>();
  580. Iterator<Idea> iterator = ideas.iterator();
  581. Idea originalIdea = null;
  582. Idea ideaWithTheRequiredDataOnly = null;
  583. while (iterator.hasNext()) {
  584. originalIdea = iterator.next();
  585. if (originalIdea.getStatus().equals(Idea.STATUS_OBJECTIONABLE))
  586. continue;
  587. ideaWithTheRequiredDataOnly = new Idea();
  588. ideaWithTheRequiredDataOnly.setTitle(StringUtils.abbreviate(originalIdea.getTitle()
  589. , ServiceConstants.FIFTY));
  590. /* Limit the description to hundred characters */
  591. ideaWithTheRequiredDataOnly.setDescription(StringUtils.abbreviate(originalIdea
  592. .getDescription(), ServiceConstants.HUNDRED));
  593. ideaWithTheRequiredDataOnly.setKey(originalIdea.getKey());
  594. /* Add the idea to the linked list */
  595. linkedList.add(ideaWithTheRequiredDataOnly);
  596. }
  597. return linkedList;
  598. }
  599. @Override
  600. public String flagObjectionableIdea(String ideaKey, User user) {
  601. String status = IdeaExchangeConstants.FAIL;
  602. /* Get title of the idea */
  603. Idea idea = this.getIdeaByKey(ideaKey);
  604. if (idea != null
  605. && isFlagTypeAllreadyExist(idea.getFlagType(), Idea.FLAG_TYPE_OBJECTIONABLE)) {
  606. status = IdeaExchangeConstants.IDEA_ALLREADY_FLAGED;
  607. return status;
  608. }
  609. /*
  610. * Create an admin request to handle the objectionabe flag request for
  611. * idea
  612. */
  613. AdminRequest adminRequest = new AdminRequest();
  614. adminRequest.setEntityKey(ideaKey);
  615. adminRequest.setEntityType(Idea.class.getSimpleName());
  616. adminRequest.setRequesterkey(user.getUserKey());
  617. adminRequest.setRequestType(AdminRequest.REQUEST_OBJECTIONABLE);
  618. adminRequest.setCreatedOn(new Date());
  619. adminRequest.setStatus(AdminRequest.STATUS_PENDING);
  620. if (!StringUtils.isBlank(user.getEmailId())) {
  621. adminRequest.setRequesterEmail(user.getEmailId());
  622. }
  623. /* Get Idea to get title and update FlagType of the entity */
  624. if (idea != null && !StringUtils.isBlank(idea.getKey())) {
  625. adminRequest.setEntityTitle(idea.getTitle());
  626. idea.getFlagType().add(Idea.FLAG_TYPE_OBJECTIONABLE);
  627. ideaDao.saveIdea(idea);
  628. } else {
  629. throw new SystemException(IdeaExchangeErrorCodes.IDEA_NULL_EXCEPTION,
  630. "There is no idea that belongs to the given key in data store");
  631. }
  632. if (adminRequestDao.saveRequest(adminRequest)) {
  633. status = IdeaExchangeConstants.SUCCESS;
  634. }
  635. return status;
  636. }
  637. @Override
  638. public String flagDuplicateIdea(String ideaKey, String originalIdeakey, User user) {
  639. String status = IdeaExchangeConstants.FAIL;
  640. /* Get title of the idea */
  641. Idea idea = this.getIdeaByKey(ideaKey);
  642. if (idea != null && isFlagTypeAllreadyExist(idea.getFlagType(), Idea.FLAG_TYPE_DUPLICATE)) {
  643. status = IdeaExchangeConstants.IDEA_ALLREADY_MARKED_DUPLICATE;
  644. return status;
  645. }
  646. /*
  647. * Create an admin request to handle the duplicate flag request for
  648. * idea.
  649. */
  650. AdminRequest adminRequest = new AdminRequest();
  651. adminRequest.setEntityKey(ideaKey);
  652. adminRequest.setEntityType(Idea.class.getSimpleName());
  653. adminRequest.setRequesterkey(user.getUserKey());
  654. if (!StringUtils.isBlank(user.getEmailId())) {
  655. adminRequest.setRequesterEmail(user.getEmailId());
  656. }
  657. adminRequest.setRequestType(AdminRequest.REQUEST_DUPLICATE);
  658. adminRequest.setCreatedOn(new Date());
  659. /* Creating string for other information set of AdminRequest */
  660. StringBuilder otherInfoString = new StringBuilder();
  661. otherInfoString.append(AdminRequest.INFO_ORIGINAL_IDEA_KEY);
  662. otherInfoString.append(AdminRequest.INFO_SEPARATOR);
  663. otherInfoString.append(originalIdeakey);
  664. Set<String> otherInfo = new HashSet<String>();
  665. otherInfo.add(otherInfoString.toString());
  666. adminRequest.setOtherInfo(otherInfo);
  667. adminRequest.setStatus(AdminRequest.STATUS_PENDING);
  668. /* Mark Idea as duplicate and save into data store. */
  669. if (idea != null && !StringUtils.isBlank(idea.getKey())) {
  670. adminRequest.setEntityTitle(idea.getTitle());
  671. idea.getFlagType().add(Idea.FLAG_TYPE_DUPLICATE);
  672. idea.setOriginalIdeaKey(originalIdeakey);
  673. ideaDao.saveIdea(idea);
  674. } else {
  675. throw new SystemException(IdeaExchangeErrorCodes.IDEA_NULL_EXCEPTION,
  676. "There is no idea that belongs to the given key in data store");
  677. }
  678. /* Save admin request */
  679. if (adminRequestDao.saveRequest(adminRequest)) {
  680. status = IdeaExchangeConstants.SUCCESS;
  681. }
  682. return status;
  683. }
  684. /**
  685. * check for flag type.
  686. *
  687. * @param flagTypes Type of flags associated with idea for Example
  688. * Objectionable,Duplicate.
  689. * @param flagTypeToCheck Type of flags associated with the idea.
  690. * @return True if flag already exist in set of flagTypes.
  691. */
  692. private boolean isFlagTypeAllreadyExist(Set<String> flagTypes, String flagTypeToCheck) {
  693. for (String flagType : flagTypes) {
  694. if (flagType != null && flagType.equalsIgnoreCase(flagTypeToCheck)) {
  695. return true;
  696. }
  697. }
  698. return false;
  699. }
  700. @Override
  701. public Idea updateIdea(Idea idea) {
  702. return ideaDao.saveIdea(idea);
  703. }
  704. @SuppressWarnings("unchecked")
  705. @Override
  706. public LinkedList<Idea> getRecentlyPickedIdeas() {
  707. /* First check the cache for the data */
  708. LinkedList<Idea> recentlyPickedIdeas = (LinkedList<Idea>) CacheHelper.getObject(
  709. CacheConstants.IDEA_NAMESPACE,
  710. CacheConstants.RECENTLY_PICKED_IDEAS);
  711. if (recentlyPickedIdeas != null && recentlyPickedIdeas.size() > ServiceConstants.ZERO) {
  712. logger.info("Recently picked ideas successfully fetched from cache");
  713. return recentlyPickedIdeas;
  714. }
  715. /*
  716. * Get the recently created projects.Iterate through the list and fetch
  717. * key of idea related to the project
  718. */
  719. List<Project> recentProjects = projectService.getRecentProjects();
  720. List<Idea> ideas = new ArrayList<Idea>();
  721. Iterator<Project> iterator = recentProjects.iterator();
  722. Set<String> setOfIdeaKeys = new HashSet<String>();
  723. while (iterator.hasNext()) {
  724. String ideaKey = iterator.next().getIdeaKey();
  725. if (!setOfIdeaKeys.contains(ideaKey)) {
  726. setOfIdeaKeys.add(ideaKey);
  727. ideas.add(getIdeaByKey(ideaKey));
  728. }
  729. }
  730. recentlyPickedIdeas = createLinkedListFromTheFetchedData(ideas);
  731. if (recentlyPickedIdeas.size() > ServiceConstants.ZERO) {
  732. /* Put the recently picked ideas into the cache */
  733. CacheHelper.putObject(CacheConstants.IDEA_NAMESPACE,
  734. CacheConstants.RECENTLY_PICKED_IDEAS,
  735. recentlyPickedIdeas,
  736. CacheConstants.RECENTLY_PICKED_IDEAS_EXPIRATION_DELAY);
  737. logger.info("Recently picked ideas successfully added to the cache");
  738. }
  739. return recentlyPickedIdeas;
  740. }
  741. @SuppressWarnings("unchecked")
  742. @Override
  743. public void removeIdeaFromAllListsInCache(String ideaKey) {
  744. /*
  745. * Create a map containing all list names as keys and the corressponding
  746. * expiration delays as values
  747. */
  748. Map<String, Integer> map = new HashMap<String, Integer>();
  749. /* Recent ideas list */
  750. map.put(CacheConstants.RECENT_IDEAS, CacheConstants.RECENT_IDEAS_EXPIRATION_DELAY);
  751. /* Recently picked ideas list */
  752. map.put(CacheConstants.RECENTLY_PICKED_IDEAS,
  753. CacheConstants.RECENTLY_PICKED_IDEAS_EXPIRATION_DELAY);
  754. /* Popular ideas list */
  755. map.put(CacheConstants.POPULAR_IDEAS, CacheConstants.POPULAR_IDEAS_EXPIRATION_DELAY);
  756. Iterator<String> iterator = map.keySet().iterator();
  757. LinkedList<Idea> listOfIdeas = null;
  758. String keyOfTheList = null;
  759. while (iterator.hasNext()) {
  760. keyOfTheList = iterator.next();
  761. /* Fetch the list */
  762. listOfIdeas = (LinkedList<Idea>) CacheHelper.getObject(
  763. CacheConstants.IDEA_NAMESPACE,
  764. keyOfTheList);
  765. /* If the list is not null check and remove the idea */
  766. if (listOfIdeas != null) {
  767. removeIdeaFromList(listOfIdeas, ideaKey, keyOfTheList, map.get(keyOfTheList));
  768. }
  769. }
  770. /* First check in Recent ideas list and remove if available */
  771. }
  772. /**
  773. * Remove idea from the list
  774. *
  775. * @param ideas the list of the ideas
  776. * @param ideaKey the key of the idea to be removed
  777. * @param keyOfTheList the key of the ideas list as used in the cache
  778. * @param expiryDelay the expiry delay for the list in cache
  779. */
  780. private void removeIdeaFromList(LinkedList<Idea> ideas, String ideaKey, String keyOfTheList,
  781. int expiryDelay) {
  782. Iterator<Idea> iterator = ideas.iterator();
  783. Idea idea = null;
  784. Idea ideaToBeRemoved = null;
  785. while (iterator.hasNext()) {
  786. idea = iterator.next();
  787. if (ideaKey.equalsIgnoreCase(idea.getKey())) {
  788. ideaToBeRemoved = idea;
  789. break;
  790. }
  791. }
  792. if (ideaToBeRemoved != null) {
  793. ideas.remove(ideaToBeRemoved);
  794. /* Put the updated list back to the cache */
  795. CacheHelper.putObject(CacheConstants.IDEA_NAMESPACE,
  796. keyOfTheList, ideas, expiryDelay);
  797. }
  798. }
  799. /**
  800. * Returns the IdeaDao type implementation
  801. *
  802. * @return Returns the TagService
  803. */
  804. public IdeaDao getIdeaDao() {
  805. return ideaDao;
  806. }
  807. /**
  808. * Sets the IdeaDao type implementation.
  809. *
  810. * @param val The IdeaDao object
  811. */
  812. public void setIdeaDao(IdeaDao val) {
  813. this.ideaDao = val;
  814. }
  815. /**
  816. * Sets the AuditManager.
  817. *
  818. * @param auditManager the auditManager to set
  819. */
  820. public void setAuditManager(AuditManager auditManager) {
  821. this.auditManager = auditManager;
  822. }
  823. /**
  824. * @return the auditManager
  825. */
  826. public AuditManager getAuditManager() {
  827. return auditManager;
  828. }
  829. @Override
  830. public Idea getIdeaByKey(String key) {
  831. return ideaDao.findEntityByPrimaryKey(Idea.class, key);
  832. }
  833. public TagService getTagService() {
  834. return tagService;
  835. }
  836. public void setTagService(TagService tagService) {
  837. this.tagService = tagService;
  838. }
  839. /**
  840. * @param weightUpdationManager the weightUpdationManager to set
  841. */
  842. public void setWeightUpdationManager(TagWeightUpdationManager weightUpdationManager) {
  843. this.weightUpdationManager = weightUpdationManager;
  844. }
  845. /**
  846. * @return the weightUpdationManager
  847. */
  848. public TagWeightUpdationManager getWeightUpdationManager() {
  849. return weightUpdationManager;
  850. }
  851. /**
  852. * @param userService the userService to set
  853. */
  854. public void setUserService(UserService userService) {
  855. this.userService = userService;
  856. }
  857. /**
  858. * @return the userService
  859. */
  860. public UserService getUserService() {
  861. return userService;
  862. }
  863. public EntityIndexService getEntityIndexService() {
  864. return entityIndexService;
  865. }
  866. public void setEntityIndexService(EntityIndexService entityIndexService) {
  867. this.entityIndexService = entityIndexService;
  868. }
  869. /**
  870. * @param shardedCounterService the shardedCounterService to set
  871. */
  872. public void setShardedCounterService(ShardedCounterService shardedCounterService) {
  873. this.shardedCounterService = shardedCounterService;
  874. }
  875. /**
  876. * @return the shardedCounterService
  877. */
  878. public ShardedCounterService getShardedCounterService() {
  879. return shardedCounterService;
  880. }
  881. /**
  882. * @return the adminRequestDao
  883. */
  884. public AdminRequestDao getAdminRequestDao() {
  885. return adminRequestDao;
  886. }
  887. /**
  888. * @param adminRequestDao the adminRequestDao to set
  889. */
  890. public void setAdminRequestDao(AdminRequestDao adminRequestDao) {
  891. this.adminRequestDao = adminRequestDao;
  892. }
  893. @Override
  894. public List<Idea> getIdeasByCategory(String categoryKey, RetrievalInfo retrievalInfo) {
  895. if (categoryKey != null && categoryKey.length() > ServiceConstants.ZERO) {
  896. retrievalInfo = prepareRetrievalInfoForQuery(retrievalInfo);
  897. List<Idea> ideaList = ideaDao.getIdeasByCategoryKey(categoryKey, Idea.STATUS_PUBLISHED,
  898. retrievalInfo);
  899. return ideaList;
  900. }
  901. return null;
  902. }
  903. }