org.ambraproject.search.SavedSearchSenderImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.ambraproject.search.SavedSearchSenderImpl.java

Source

/*
 * Copyright (c) 2006-2013 by Public Library of Science
 * http://plos.org
 * http://ambraproject.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.ambraproject.search;

import org.ambraproject.models.Journal;
import org.ambraproject.models.SavedSearch;
import org.ambraproject.models.SavedSearchType;
import org.ambraproject.models.UserProfile;
import org.ambraproject.service.hibernate.HibernateServiceImpl;
import org.ambraproject.service.journal.JournalService;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import org.ambraproject.email.TemplateMailer;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Send saved searches
 *
 * @author Joe Osowski
 */
public class SavedSearchSenderImpl extends HibernateServiceImpl implements SavedSearchSender {
    private static final Logger log = LoggerFactory.getLogger(SavedSearchSenderImpl.class);

    protected static final String WEEKLY_FREQUENCY = "WEEKLY";
    protected static final String PRODUCTION_MODE = "PRODUCTION";
    protected static final String QA_MODE = "QA";

    protected JournalService journalService;
    protected TemplateMailer mailer;
    protected String mailFromAddress;
    protected String sendMode;
    protected String sendModeQAEMail;
    protected String alertHtmlEmail;
    protected String alertTextEmail;
    protected String savedSearchHtmlEmail;
    protected String savedSearchTextEmail;
    protected String imagePath;
    protected int resultLimit;

    /**
     * @inheritDoc
     */
    public void sendSavedSearch(SavedSearchJob searchJob) {

        log.debug("Received thread Name: {}", Thread.currentThread().getName());
        log.debug("Send emails for search ID: {}. {}", searchJob.getSavedSearchQueryID(), searchJob.getFrequency());

        final Map<String, Object> context = new HashMap<String, Object>();

        context.put("searchParameters", searchJob.getSearchParams());
        context.put("searchHitList", searchJob.getSearchHitList());
        context.put("startTime", searchJob.getStartDate());
        context.put("endTime", searchJob.getEndDate());
        context.put("imagePath", this.imagePath);
        context.put("resultLimit", this.resultLimit);

        //Create message
        Multipart content = createContent(context, searchJob.getType());

        List<Object[]> searchDetails = getSavedSearchDetails(searchJob.getSavedSearchQueryID(),
                searchJob.getFrequency());

        String fromAddress = this.mailFromAddress;

        for (int a = 0; a < searchDetails.size(); a++) {
            String toAddress = (String) searchDetails.get(a)[1];
            String subject;

            if (searchJob.getType().equals(SavedSearchType.USER_DEFINED)) {
                subject = "Search Alert - " + searchDetails.get(a)[2];

                log.debug("Job result count: {}", searchJob.getSearchHitList().size());

                //We might filter the search hitlist based on publish and the last time the search was run for each user 
                //here.  We track the last time a search was run in the user's savedSearch table, seemed like overkill to
                //to me though.

                //We might group email addresses and send batches of emails to java mail to send.  It's possible we'll
                //get a performance gain there if needed.  Would take a bit of refactoring to do though... TBD

                if (searchJob.getSearchHitList().size() > 0) {

                    log.debug("Sending mail: {}", toAddress);

                    mail(toAddress, fromAddress, subject, context, content);
                } else {
                    log.debug("Not sending mail: {}", toAddress);
                }
            } else {
                String[] journals = searchJob.getSearchParams().getFilterJournals();

                //Each alert can only be for one journal
                if (journals.length != 1) {
                    throw new RuntimeException(
                            "Journal alert defined for multiple journals or journal filter not defined");
                }

                Journal j = journalService.getJournal(journals[0]);
                subject = j.getTitle() + " Journal Alert";

                log.debug("Job Result count: {}", searchJob.getSearchHitList().size());
                log.debug("Sending mail: {}", toAddress);

                mail(toAddress, fromAddress, subject, context, content);
            }

            //When results are sent update the records to indicate
            markSearchRun((Long) searchDetails.get(a)[0], searchJob.getFrequency(), searchJob.getEndDate());
        }

        log.debug("Completed thread Name: {}", Thread.currentThread().getName());
        log.debug("Completed send request for search ID: {}. {}", searchJob.getSavedSearchQueryID(),
                searchJob.getFrequency());
    }

    protected void mail(String toAddress, String fromAddress, String subject, Map<String, Object> context,
            Multipart content) {

        //If sendMode empty, do nothing
        if (sendMode != null) {
            if (sendMode.toUpperCase().equals(PRODUCTION_MODE)) {
                mailer.mail(toAddress, fromAddress, subject, context, content);
                log.debug("Mail sent, mode: {}, address: {}", new Object[] { PRODUCTION_MODE, toAddress });
            }

            if (sendMode.toUpperCase().equals(QA_MODE)) {
                mailer.mail(sendModeQAEMail, fromAddress, "(" + toAddress + ")" + subject, context, content);
                log.debug("Mail sent, mode: {}, address: {}", new Object[] { QA_MODE, sendModeQAEMail });
            }

            //If sendMode does not match "production" or "QA", do nothing
        }
    }

    @SuppressWarnings("unchecked")
    protected void markSearchRun(Long savedSearchID, String frequency, Date endDate) {
        SavedSearch savedSearch = hibernateTemplate.get(SavedSearch.class, savedSearchID);

        if (savedSearch == null) {
            throw new RuntimeException("Could not find savedSearch: " + savedSearchID);
        }

        if (frequency.equals(WEEKLY_FREQUENCY)) {
            savedSearch.setLastWeeklySearchTime(endDate);
        } else {
            savedSearch.setLastMonthlySearchTime(endDate);
        }

        hibernateTemplate.update(savedSearch);

        log.debug("Updated Last {} saved Search time for Saved Search ID: {}", frequency, savedSearchID);
    }

    protected Multipart createContent(Map<String, Object> context, SavedSearchType type) {
        try {
            if (type.equals(SavedSearchType.JOURNAL_ALERT)) {
                return mailer.createContent(this.alertTextEmail, this.alertHtmlEmail, context);
            } else {
                return mailer.createContent(this.savedSearchTextEmail, this.savedSearchHtmlEmail, context);
            }
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        } catch (MessagingException ex) {
            throw new RuntimeException(ex);
        }
    }

    @SuppressWarnings("unchecked")
    protected List<Object[]> getSavedSearchDetails(Long savedSearchQueryID, String type) {
        SavedSearchRetriever.AlertType alertType = SavedSearchRetriever.AlertType.valueOf(type);

        DetachedCriteria criteria = DetachedCriteria.forClass(UserProfile.class)
                .setProjection(Projections.distinct(Projections.projectionList().add(Projections.property("ss.ID"))
                        .add(Projections.property("email")).add(Projections.property("ss.searchName"))))
                .createAlias("savedSearches", "ss").createAlias("ss.searchQuery", "q")
                .add(Restrictions.eq("q.ID", savedSearchQueryID));

        if (alertType == SavedSearchRetriever.AlertType.WEEKLY) {
            criteria.add(Restrictions.eq("ss.weekly", true));
        }

        if (alertType == SavedSearchRetriever.AlertType.MONTHLY) {
            criteria.add(Restrictions.eq("ss.monthly", true));
        }

        return (List<Object[]>) hibernateTemplate.findByCriteria(criteria);
    }

    @Required
    public void setMailer(TemplateMailer mailer) {
        this.mailer = mailer;
    }

    @Required
    public void setMailFromAddress(String mailFromAddress) {
        this.mailFromAddress = mailFromAddress;
    }

    @Required
    public void setImagePath(String imagePath) {
        this.imagePath = imagePath;
    }

    @Required
    public void setAlertHtmlEmail(String alertHtmlEmail) {
        this.alertHtmlEmail = alertHtmlEmail;
    }

    @Required
    public void setAlertTextEmail(String alertTextEmail) {
        this.alertTextEmail = alertTextEmail;
    }

    @Required
    public void setSavedSearchHtmlEmail(String savedSearchHtmlEmail) {
        this.savedSearchHtmlEmail = savedSearchHtmlEmail;
    }

    @Required
    public void setSavedSearchTextEmail(String savedSearchTextEmail) {
        this.savedSearchTextEmail = savedSearchTextEmail;
    }

    @Required
    public void setSendMode(String sendMode) {
        this.sendMode = sendMode;
    }

    @Required
    public void setSendModeQAEMail(String sendModeQAEMail) {
        this.sendModeQAEMail = sendModeQAEMail;
    }

    @Required
    public void setResultLimit(int resultLimit) {
        this.resultLimit = resultLimit;
    }

    @Required
    public void setJournalService(JournalService journalService) {
        this.journalService = journalService;
    }
}