PageRenderTime 98ms CodeModel.GetById 13ms app.highlight 77ms RepoModel.GetById 1ms app.codeStats 0ms

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