com.redhat.rhn.taskomatic.task.ErrataMailer.java Source code

Java tutorial

Introduction

Here is the source code for com.redhat.rhn.taskomatic.task.ErrataMailer.java

Source

/**
 * Copyright (c) 2009--2014 Red Hat, Inc.
 *
 * This software is licensed to you under the GNU General Public License,
 * version 2 (GPLv2). There is NO WARRANTY for this software, express or
 * implied, including the implied warranties of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
 * along with this software; if not, see
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
 *
 * Red Hat trademarks are not licensed under GPLv2. No permission is
 * granted to use or replicate Red Hat trademarks that are incorporated
 * in this software or its documentation.
 */
package com.redhat.rhn.taskomatic.task;

import com.redhat.rhn.common.conf.Config;
import com.redhat.rhn.common.conf.ConfigDefaults;
import com.redhat.rhn.common.db.datasource.ModeFactory;
import com.redhat.rhn.common.db.datasource.SelectMode;
import com.redhat.rhn.common.db.datasource.WriteMode;
import com.redhat.rhn.common.hibernate.HibernateFactory;
import com.redhat.rhn.common.localization.LocalizationService;
import com.redhat.rhn.common.messaging.JavaMailException;
import com.redhat.rhn.common.messaging.Mail;
import com.redhat.rhn.common.messaging.SmtpMail;
import com.redhat.rhn.domain.errata.Errata;
import com.redhat.rhn.domain.errata.impl.PublishedErrata;
import com.redhat.rhn.domain.org.OrgFactory;

import org.apache.commons.lang.StringUtils;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * This is a port of the ErrataEngine taskomatic task
 *
 * @version $Rev.$
 */

public class ErrataMailer extends RhnJavaJob {

    /**
     * {@inheritDoc}
     */
    public void execute(JobExecutionContext context) throws JobExecutionException {

        List results = getErrataToProcess();
        if (results == null || results.size() == 0) {
            if (log.isDebugEnabled()) {
                log.debug("No errata found...exiting");
            }
        } else {
            if (log.isDebugEnabled()) {
                log.debug("=== Queued up " + results.size() + " errata");
            }
            for (Iterator iter = results.iterator(); iter.hasNext();) {
                Map row = (Map) iter.next();
                Long errataId = (Long) row.get("errata_id");
                Long orgId = (Long) row.get("org_id");
                Long channelId = (Long) row.get("channel_id");
                markErrataDone(errataId, orgId, channelId);
                if (log.isDebugEnabled()) {
                    log.debug("Processing errata " + errataId + " for org " + orgId);
                }
                try {
                    sendEmails(errataId, orgId, channelId);
                    if (log.isDebugEnabled()) {
                        log.debug("Finished errata " + errataId + " for org " + orgId);
                    }
                } catch (JavaMailException e) {
                    log.error("Error sending mail", e);
                }
            }
        }
    }

    protected List getErrataToProcess() {
        SelectMode select = ModeFactory.getMode(TaskConstants.MODE_NAME,
                TaskConstants.TASK_QUERY_ERRATAMAILER_FIND_ERRATA);
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("threshold", new Integer(1));
        List results = select.execute(params);
        return results;
    }

    private void markErrataDone(Long errataId, Long orgId, Long channelId) {
        HibernateFactory.getSession();
        WriteMode marker = ModeFactory.getWriteMode(TaskConstants.MODE_NAME,
                TaskConstants.TASK_QUERY_ERRATAMAILER_MARK_ERRATA_DONE);
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("org_id", orgId);
        params.put("errata_id", errataId);
        params.put("channel_id", channelId);
        int rowsUpdated = marker.executeUpdate(params);
        if (log.isDebugEnabled()) {
            log.debug("Marked " + rowsUpdated + " rows complete");
        }
    }

    private void sendEmails(Long errataId, Long orgId, Long channelId) {
        Errata errata = (Errata) HibernateFactory.getSession().load(PublishedErrata.class,
                new Long(errataId.longValue()));
        List orgServers = getOrgRelevantServers(errataId, orgId, channelId);

        if (orgServers == null || orgServers.size() == 0) {
            log.debug("No relevant servers found for erratum " + errata.getId() + " in channel " + channelId
                    + " for org " + orgId + " ... skipping.");
            return;
        }

        Map<Long, List> userMap = createUserEmailMap(orgServers);

        log.info("Found " + userMap.keySet().size() + " user(s) to notify about erratum " + errata.getId()
                + " in channel " + channelId + " for org " + orgId + ".");

        for (Long userId : userMap.keySet()) {
            Map userInfo = getUserInfo(userId);
            String email = (String) userInfo.get("email");
            String login = (String) userInfo.get("login");
            List servers = userMap.get(userId);
            log.info("Notification for user " + login + "(" + userId + ") about " + servers.size()
                    + " relevant server(s).");
            String emailBody = formatEmail(login, email, errata, servers);
            Mail mail = new SmtpMail();
            mail.setRecipient(email);
            mail.setHeader("X-RHN-Info", "Autogenerated mail for " + login);
            mail.setHeader("Precedence", "first-class");
            mail.setHeader("Errors-To", "rhn-bounce" + login + "-" + orgId.toString() + "@rhn.redhat.com");
            mail.setBody(emailBody);
            StringBuilder subject = new StringBuilder();
            subject.append(Config.get().getString("web.product_name") + " Errata Alert: ");
            subject.append(errata.getAdvisory()).append(" - ");
            subject.append(errata.getSynopsis());
            mail.setSubject(subject.toString());
            TaskHelper.sendMail(mail, log);
        }
    }

    private Map createUserEmailMap(List orgServersIn) {
        Map<Long, List> map = new HashMap<Long, List>();
        for (Iterator i = orgServersIn.iterator(); i.hasNext();) {
            Map row = (Map) i.next();
            Long userId = (Long) row.get("user_id");
            if (!map.containsKey(userId)) {
                map.put(userId, new ArrayList<Map>());
            }
            map.get(userId).add(row);
            i.remove();
        }
        return map;
    }

    private Map getUserInfo(Long userId) {
        SelectMode mode = ModeFactory.getMode(TaskConstants.MODE_NAME,
                TaskConstants.TASK_QUERY_ERRATAMAILER_GET_USERINFO);
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("user_id", userId);
        return (Map) mode.execute(params).get(0);
    }

    protected List getOrgRelevantServers(Long errataId, Long orgId, Long channelId) {
        SelectMode mode = ModeFactory.getMode(TaskConstants.MODE_NAME,
                TaskConstants.TASK_QUERY_ERRATAMAILER_GET_RELEVANT_SERVERS);
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("errata_id", errataId);
        params.put("org_id", orgId);
        params.put("channel_id", channelId);
        return mode.execute(params);
    }

    private String formatEmail(String login, String email, Errata errata, List servers) {
        StringBuilder body = new StringBuilder();

        //Build the hostname with protocol. Used to create urls for the email.
        String host;
        //The protocol from configuration.
        if (ConfigDefaults.get().isSSLAvailable()) {
            host = "https://";
        } else {
            host = "http://";
        }
        //Add the hostname
        host = host + ConfigDefaults.get().getHostname();

        //Build the email body
        body.append(getEmailBodySummary(errata, host));
        body.append("\n").append("\n");
        body.append(getEmailBodyAffectedSystems(host, servers));
        body.append("\n").append("\n");
        body.append(getEmailBodyPreferences(host, login, email));

        return body.toString();
    }

    private String getEmailBodySummary(Errata errata, String host) {
        LocalizationService ls = LocalizationService.getInstance();
        Object[] args = new Object[8];

        //Build the errata details url.
        StringBuilder buffy = new StringBuilder();
        buffy.append(host).append("/rhn/errata/details/Details.do?eid=");
        buffy.append(errata.getId().toString());
        args[0] = buffy.toString();

        //Add in the errata information.
        args[1] = errata.getAdvisoryType() == null ? "" : errata.getAdvisoryType();
        args[2] = errata.getAdvisory() == null ? "" : errata.getAdvisory();
        args[3] = errata.getSynopsis() == null ? "" : errata.getSynopsis();
        args[4] = errata.getTopic() == null ? "" : errata.getTopic();
        args[5] = errata.getDescription() == null ? "" : errata.getDescription();
        args[6] = errata.getNotes() == null ? "" : errata.getNotes();
        args[7] = errata.getRefersTo() == null ? "" : errata.getRefersTo();
        return ls.getMessage("email.errata.notification.body.summary", args);
    }

    private String getEmailBodyAffectedSystems(String host, List servers) {
        LocalizationService ls = LocalizationService.getInstance();

        //Render the header of the affected systems section along with helpful text.
        StringBuilder buffy = new StringBuilder();
        buffy.append(ls.getMessage("email.errata.notification.body.affectedheader"));
        buffy.append("\n").append("\n");

        //There is one sentence off on its own that deals with whether there are
        //multiple systems or just one, so this is a separate trans-unit.
        if (servers.size() == 1) {
            buffy.append(ls.getMessage("email.errata.notification.body.onesystem"));
        } else {
            buffy.append(ls.getMessage("email.errata.notification.body.numsystems",
                    new Object[] { String.valueOf(servers.size()) }));
        }
        buffy.append("\n").append("\n");

        //Now show the table of affected systems and the footer text
        Object[] args = new Object[2];

        //Create the data to show in the table
        //TODO: I'm just copying over code that was here before, but it
        //      seems to me that we should be printing another column to
        //      the table according to the String Resource bundle.
        StringWriter writer = new StringWriter();
        PrintWriter printWriter = new PrintWriter(writer, true);
        for (Iterator iter = servers.iterator(); iter.hasNext();) {
            Map row = (Map) iter.next();
            String release = (String) row.get("release");
            printWriter.print(release);
            for (int i = 0; i < (11 - release.length()); i++) {
                printWriter.print(' ');
            }
            String arch = (String) row.get("arch");
            printWriter.print(arch);
            for (int i = 0; i < (11 - arch.length()); i++) {
                printWriter.print(' ');
            }
            printWriter.println((String) row.get("name"));
        }
        printWriter.flush();
        args[0] = writer.toString();
        //URL for the system list
        args[1] = host + "/rhn/systems/Overview.do";
        buffy.append(ls.getMessage("email.errata.notification.body.affected", args));
        return buffy.toString();
    }

    private String getEmailBodyPreferences(String host, String login, String email) {
        LocalizationService ls = LocalizationService.getInstance();
        Object[] args = new Object[3];

        //URL for user preferences
        args[0] = host + "/rhn/account/UserPreferences.do";
        //custom email footer
        args[1] = OrgFactory.EMAIL_FOOTER.getValue();

        //custom account info
        args[2] = OrgFactory.EMAIL_ACCOUNT_INFO.getValue();

        //This is so ugly! For some reason we support these 'macros' for
        //account info only. But we made them look like XML tags as if spaces
        //didn't matter. However, spaces do matter. <sigh />
        args[2] = StringUtils.replace(args[2].toString(), "<login />", login);
        args[2] = StringUtils.replace(args[2].toString(), "<email-address />", email);

        return ls.getMessage("email.errata.notification.body.preferences", args);
    }
}