package com.ciandt.techgallery.service.impl; import com.ciandt.techgallery.Constants; import com.ciandt.techgallery.persistence.dao.CronJobDAO; import com.ciandt.techgallery.persistence.dao.EndorsementDAO; import com.ciandt.techgallery.persistence.dao.TechGalleryUserDAO; import com.ciandt.techgallery.persistence.dao.TechnologyCommentDAO; import com.ciandt.techgallery.persistence.dao.TechnologyDAO; import com.ciandt.techgallery.persistence.dao.TechnologyRecommendationDAO; import com.ciandt.techgallery.persistence.dao.impl.CronJobDAOImpl; import com.ciandt.techgallery.persistence.dao.impl.EndorsementDAOImpl; import com.ciandt.techgallery.persistence.dao.impl.TechGalleryUserDAOImpl; import com.ciandt.techgallery.persistence.dao.impl.TechnologyCommentDAOImpl; import com.ciandt.techgallery.persistence.dao.impl.TechnologyDAOImpl; import com.ciandt.techgallery.persistence.dao.impl.TechnologyRecommendationDAOImpl; import com.ciandt.techgallery.persistence.model.CronJob; import com.ciandt.techgallery.persistence.model.Endorsement; import com.ciandt.techgallery.persistence.model.TechGalleryUser; import com.ciandt.techgallery.persistence.model.Technology; import com.ciandt.techgallery.persistence.model.TechnologyComment; import com.ciandt.techgallery.persistence.model.TechnologyRecommendation; import com.ciandt.techgallery.service.CronService; import com.ciandt.techgallery.service.EmailService; import com.ciandt.techgallery.service.TechnologyActivitiesService; import com.ciandt.techgallery.service.email.EmailConfig; import com.ciandt.techgallery.service.enums.CronStatus; import com.ciandt.techgallery.service.enums.EmailTypeEnum; import com.ciandt.techgallery.service.model.email.TechGalleryActivitiesEmailTemplateTO; import com.ciandt.techgallery.service.model.email.TechnologyActivitiesEmailTemplateTO; import com.ciandt.techgallery.servlets.CronActivityResumeServlet; import com.ciandt.techgallery.utils.timezone.TimezoneManager; import com.ciant.techgallery.transaction.Transactional; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; @Transactional public class CronServiceImpl implements CronService { /* * Attributes -------------------------------------------- */ public static final Logger _LOG = Logger.getLogger(CronActivityResumeServlet.class.getName()); private static CronServiceImpl instance; private EmailService emailService = EmailServiceImpl.getInstance(); private TechnologyActivitiesService technologyActivitiesService = TechnologyActivitiesServiceImpl.getInstance(); private CronJobDAO cronJobsDao = CronJobDAOImpl.getInstance(); private TechnologyRecommendationDAO technologyRecommendationDao = TechnologyRecommendationDAOImpl.getInstance(); private TechnologyCommentDAO technologyCommentDao = TechnologyCommentDAOImpl.getInstance(); private TechGalleryUserDAO techGalleryUserDao = TechGalleryUserDAOImpl.getInstance(); private TechnologyDAO technologyDao = TechnologyDAOImpl.getInstance(); private EndorsementDAO endorsementDao = EndorsementDAOImpl.getInstance(); /* * Constructors -------------------------------------------- */ private CronServiceImpl() {} /** * Singleton method for the service. * * @author <a href="mailto:joaom@ciandt.com"> João Felipe de Medeiros Moreira </a> * @since 09/10/2015 * * @return EmailServiceImpl instance. */ public static CronServiceImpl getInstance() { if (instance == null) { instance = new CronServiceImpl(); } return instance; } /** * Push one email to email queue for each follower user in each technology that have followers. */ public void sendEmailtoFollowers() { CronJob cronJob = new CronJob(); cronJob.setName(Constants.CRON_MAIL_ACTIVITY_JOB); cronJob.setStartTimestamp(new Date()); try { List<TechGalleryUser> followers = techGalleryUserDao.findAllFollowers(); if (followers != null && followers.size() > 0) { for (TechGalleryUser follower : followers) { // Set user's timezone offset. To be used in converted dates. TimezoneManager.getInstance().setOffset(follower.getTimezoneOffset()); // TO used in mustache template TechGalleryActivitiesEmailTemplateTO techGalleryActivitiesTo = new TechGalleryActivitiesEmailTemplateTO(); techGalleryActivitiesTo.setTimestamp(new Date()); techGalleryActivitiesTo.setFollower(follower); techGalleryActivitiesTo.setAppName(Constants.APP_NAME); List<TechnologyActivitiesEmailTemplateTO> techActivitiesToList = new ArrayList<TechnologyActivitiesEmailTemplateTO>(); for (String id : follower.getFollowedTechnologyIds()) { Technology technology = technologyDao.findById(id); Date lastCronJobExecDate = findLastExecutedCronJob(Constants.CRON_MAIL_ACTIVITY_JOB); findNewActivitiesInATechnology(techActivitiesToList, follower, technology, lastCronJobExecDate); } techGalleryActivitiesTo.setTechnologyActivitiesTo(techActivitiesToList); // Push email to queue if has new activities if (!techActivitiesToList.isEmpty()) { EmailConfig email = new EmailConfig(EmailTypeEnum.DAILY_RESUME, EmailTypeEnum.DAILY_RESUME.getSubject() + techGalleryActivitiesTo.getFormattedTimestamp(), techGalleryActivitiesTo, follower.getEmail()); emailService.push(email); } } } cronJob.setEndTimestamp(new Date()); cronJob.setCronStatus(CronStatus.SUCCESS); } catch (Exception e) { _LOG.info(e.getMessage()); cronJob.setEndTimestamp(new Date()); cronJob.setCronStatus(CronStatus.FAILURE); cronJob.setDescription(e.getMessage()); } cronJobsDao.add(cronJob); } private void findNewActivitiesInATechnology( List<TechnologyActivitiesEmailTemplateTO> techActivitiesToList, TechGalleryUser follower, Technology technology, Date lastCronJobExecDate) { // Find new Activities in a technology List<TechnologyRecommendation> dailyRecommendations = technologyRecommendationDao .findAllRecommendationsStartingFrom(technology, lastCronJobExecDate); dailyRecommendations = removeUserRecommendations(follower, dailyRecommendations); List<TechnologyComment> dailyComments = technologyCommentDao.findAllCommentsStartingFrom(technology, lastCronJobExecDate); dailyComments = removeUserComments(follower, dailyComments); // Remove Recommendations' comments. For avoid duplication if (!dailyRecommendations.isEmpty()) { for (TechnologyRecommendation recommendation : dailyRecommendations) { if (!dailyComments.isEmpty()) { dailyComments.remove(recommendation.getComment().get()); } } } if (!dailyRecommendations.isEmpty() || !dailyComments.isEmpty()) { // Create a TO to each technology TechnologyActivitiesEmailTemplateTO techActivitiesTo = technologyActivitiesService .createTechnologyActivitiesTo(technology, dailyRecommendations, dailyComments); techActivitiesToList.add(techActivitiesTo); } } private List<TechnologyComment> removeUserComments(TechGalleryUser follower, List<TechnologyComment> dailyComments) { List<TechnologyComment> dailyCommentsWithoutUser = new ArrayList<TechnologyComment>(); if (dailyComments != null) { for (TechnologyComment technologyComment : dailyComments) { if (!technologyComment.getAuthor().get().equals(follower)) { dailyCommentsWithoutUser.add(technologyComment); } } } return dailyCommentsWithoutUser; } private List<TechnologyRecommendation> removeUserRecommendations(TechGalleryUser follower, List<TechnologyRecommendation> dailyRecommendations) { List<TechnologyRecommendation> dailyRecommendationsWithoutUser = new ArrayList<TechnologyRecommendation>(); if (dailyRecommendations != null) { for (TechnologyRecommendation technologyRecommendation : dailyRecommendations) { if (!technologyRecommendation.getRecommender().get().equals(follower)) { dailyRecommendationsWithoutUser.add(technologyRecommendation); } } } return dailyRecommendationsWithoutUser; } private Date findLastExecutedCronJob(String cronJob) { Date lastCronJobExecDate; CronJob lastCronJob = cronJobsDao.findLastExecutedCronJob(cronJob); if (lastCronJob != null) { lastCronJobExecDate = lastCronJob.getStartTimestamp(); } else { Calendar cal = Calendar.getInstance(); cal.add(Calendar.DAY_OF_MONTH, -1); lastCronJobExecDate = cal.getTime(); } return lastCronJobExecDate; } @Override public void sendEmailToEndorseds() { CronJob cronJob = new CronJob(); cronJob.setName(Constants.CRON_MAIL_ENDORSEMENT_JOB); cronJob.setStartTimestamp(new Date()); Date lastExecutedCronJob = findLastExecutedCronJob(Constants.CRON_MAIL_ENDORSEMENT_JOB); try { List<TechGalleryUser> usersList = techGalleryUserDao.findAll(); for (TechGalleryUser techGalleryUser : usersList) { List<Endorsement> endorsementsList = endorsementDao.findAllEndorsementsStartingFrom(techGalleryUser, lastExecutedCronJob); if (endorsementsList != null) { TechGalleryActivitiesEmailTemplateTO activities = new TechGalleryActivitiesEmailTemplateTO(Constants.APP_NAME, null, new ArrayList<TechnologyActivitiesEmailTemplateTO>()); // group and define user's activities setUserActivities(endorsementsList, activities); // Push email to queue if has new activities if (!activities.getTechnologyActivitiesTo().isEmpty()) { EmailConfig email = new EmailConfig(EmailTypeEnum.ENDORSED, EmailTypeEnum.ENDORSED.getSubject() + activities.getFormattedTimestamp(), activities, techGalleryUser.getEmail()); emailService.push(email); } } } cronJob.setEndTimestamp(new Date()); cronJob.setCronStatus(CronStatus.SUCCESS); } catch (Exception e) { _LOG.log(Level.SEVERE, "Cron exception: ", e); cronJob.setEndTimestamp(new Date()); cronJob.setCronStatus(CronStatus.FAILURE); cronJob.setDescription(e.getMessage()); } cronJobsDao.add(cronJob); } /** * Method that groups endorsements by technologies. * * @param endorsementsList list of endorsements. * @return map with grouped endorsements. */ private Map<String, List<Endorsement>> groupEndorsementsByTechnology( List<Endorsement> endorsementsList) { Map<String, List<Endorsement>> groupedEndorsements = new HashMap<String, List<Endorsement>>(); for (Endorsement endorsement : endorsementsList) { String key = endorsement.getTechnologyEntity().getName(); List<Endorsement> group = groupedEndorsements.get(key); if (group == null) { group = new ArrayList<Endorsement>(); groupedEndorsements.put(key, group); } group.add(endorsement); } return groupedEndorsements; } /** * Method that set the user activities by grouping endorsements by technology. * * @param endorsementsList list of user endorsements. * @param activities activities for the email. */ private void setUserActivities(List<Endorsement> endorsementsList, TechGalleryActivitiesEmailTemplateTO activities) { Map<String, List<Endorsement>> groupedEndorsements = groupEndorsementsByTechnology(endorsementsList); _LOG.info("Technology hashmap size: " + groupedEndorsements.size()); for (Map.Entry<String, List<Endorsement>> entry : groupedEndorsements.entrySet()) { List<Endorsement> technologyEndorsements = entry.getValue(); if (technologyEndorsements != null && technologyEndorsements.size() > 0) { TechnologyActivitiesEmailTemplateTO endorsementActivity; Endorsement endorsement = technologyEndorsements.get(0); endorsementActivity = new TechnologyActivitiesEmailTemplateTO( endorsement.getEndorserEntity().getName(), endorsement.getTechnologyEntity(), Constants.EMAIL_CONTEXT_SINGLE, null, null, null); if (technologyEndorsements.size() > 1) { endorsementActivity.setContext(Constants.EMAIL_CONTEXT_PLURAL); _LOG.info("Endorsement for Technology: " + entry.getKey() + " qty: " + technologyEndorsements.size()); for (int i = 1; i < technologyEndorsements.size(); i++) { endorsement = technologyEndorsements.get(i); if (i == technologyEndorsements.size() - 1) { endorsementActivity.addEndorser(endorsement.getEndorserEntity().getName(), true); } else { endorsementActivity.addEndorser(endorsement.getEndorserEntity().getName(), false); } } } activities.getTechnologyActivitiesTo().add(endorsementActivity); } } } }