com.edgenius.wiki.service.impl.NotifyMQConsumer.java Source code

Java tutorial

Introduction

Here is the source code for com.edgenius.wiki.service.impl.NotifyMQConsumer.java

Source

/* 
 * =============================================================
 * Copyright (C) 2007-2011 Edgenius (http://www.edgenius.com)
 * =============================================================
 * License Information: http://www.edgenius.com/licensing/edgenius/2.0/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2.0
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 * http://www.gnu.org/licenses/gpl.txt
 *  
 * ****************************************************************
 */
package com.edgenius.wiki.service.impl;

import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.edgenius.core.Global;
import com.edgenius.core.model.User;
import com.edgenius.core.service.MailService;
import com.edgenius.core.service.UserReadingService;
import com.edgenius.core.util.AuditLogger;
import com.edgenius.core.util.WebUtil;
import com.edgenius.wiki.Shell;
import com.edgenius.wiki.SpaceSetting;
import com.edgenius.wiki.WikiConstants;
import com.edgenius.wiki.blogsync.BlogSyncException;
import com.edgenius.wiki.blogsync.BlogSyncService;
import com.edgenius.wiki.dao.UserPageDAO;
import com.edgenius.wiki.gwt.client.model.BlogMeta;
import com.edgenius.wiki.model.Page;
import com.edgenius.wiki.model.PageComment;
import com.edgenius.wiki.model.Space;
import com.edgenius.wiki.model.UserPageMark;
import com.edgenius.wiki.security.service.SecurityService;
import com.edgenius.wiki.service.CommentException;
import com.edgenius.wiki.service.CommentService;
import com.edgenius.wiki.service.NotifyMQObject;
import com.edgenius.wiki.service.PageService;
import com.edgenius.wiki.util.WikiUtil;

/**
 * The reason why using this MQConsumer to send email rather than using MailMQProducer is, 
 * this one handles all email build logic (such as organize mail body, mail list address etc.)
 * This may save performance as this class is executing behind MQ consumer.
 * 
 * @author Dapeng.Ni
 */
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW, noRollbackFor = Exception.class)
public class NotifyMQConsumer {
    private static final Logger log = LoggerFactory.getLogger(NotifyMQConsumer.class);

    //directory user mailEngine rather using a MQ mail service
    private MailService mailEngine;
    private UserPageDAO userPageDAO;
    private UserReadingService userReadingService;
    private PageService pageService;
    private CommentService commentService;
    private BlogSyncService blogSyncService;
    private SecurityService securityService;

    //********************************************************************
    //               Function methods
    //********************************************************************
    public void handleMessage(Object msg) {
        NotifyMQObject mqObj;
        try {
            if (msg instanceof NotifyMQObject) {
                mqObj = (NotifyMQObject) msg;
                if (mqObj.getType() == NotifyMQObject.TYPE_SYSTEM_STATUS_CHECK) {
                    //send a http response to confirm JMS received
                    String url = WebUtil.getHostAppURL() + "status?uuid=" + mqObj.getSpaceUname();
                    try {
                        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
                        conn.setRequestMethod("GET");
                        conn.setReadTimeout(20000);
                        if (log.isDebugEnabled()) {
                            String uuid = IOUtils.toString(conn.getInputStream());
                            log.debug("Recieved system status JMS check UUID {}", uuid);
                        }
                        if (HttpURLConnection.HTTP_OK != conn.getResponseCode()) {
                            log.warn("Unable get response from system status JMS  confirm URL {}", url);
                        }
                    } catch (Exception e) {
                        log.error("Unable to send satus confirm URL " + url, e);
                    }
                    return;
                }
                securityService.proxyLogin(mqObj.getUsername());

                if (mqObj.getType() == NotifyMQObject.TYPE_PAGE_UPDATE) {
                    sendPageUpdateNodification(mqObj.getPageUid());
                } else if (mqObj.getType() == NotifyMQObject.TYPE_SPACE_REMOVE) {
                    sendSpaceRemovingNotification(mqObj.getSpace(), mqObj.getRemoveDelayHours());
                } else if (mqObj.getType() == NotifyMQObject.TYPE_COMMENT_NOTIFY) {
                    sendPageCommentsNotification(mqObj.getUsername(), mqObj.getPageUid(), mqObj.getCommentUid());
                } else if (mqObj.getType() == NotifyMQObject.TYPE_EXT_LINK_BLOG) {
                    syncExtBlog(mqObj.getSpaceUname(), mqObj.getBlogMeta(), mqObj.getSyncLimit());
                } else if (mqObj.getType() == NotifyMQObject.TYPE_EXT_POST) {
                    postBlog(mqObj.getBlogMeta(), mqObj.getId());
                } else if (mqObj.getType() == NotifyMQObject.TYPE_EXT_POST_COMMENT) {
                    postBlogComment(mqObj.getBlogMeta(), mqObj.getId());
                } else if (mqObj.getType() == NotifyMQObject.TYPE_EXT_REMOVE_POST) {
                    removeBlogPost(mqObj.getUsername(), mqObj.getBlogMeta(), mqObj.getId());
                } else if (mqObj.getType() == NotifyMQObject.TYPE_SPACE_MEUN_UPDATED) {
                    updateSpaceMenu(mqObj.getSpaceUname());
                }
            } else {
                AuditLogger.error("Unexpected object in Index Counsumer " + msg);
                return;
            }
        } finally {
            securityService.proxyLogout();
        }

    }

    /**
     * Shell request - to update space menu for this space
     * @param spaceUname
     */
    private void updateSpaceMenu(String spaceUname) {
        Shell.notifySpaceCreate(spaceUname);
    }

    /**
     * @param username
     * @param blogMeta
     * @param postID
     */
    private void removeBlogPost(String username, BlogMeta blogMeta, String postID) {
        try {
            blogSyncService.removePost(blogMeta, postID);
        } catch (BlogSyncException e) {
            log.error("Unable to post blog comment:" + blogMeta, e);
        }
    }

    /**
     * @param username
     * @param blogMeta
     * @param pageComment
     */
    private void postBlogComment(BlogMeta blogMeta, String commentID) {
        try {
            PageComment pageComment = commentService.getComment(NumberUtils.toInt(commentID));
            if (pageComment != null)
                blogSyncService.postComment(blogMeta, pageComment);
        } catch (BlogSyncException e) {
            log.error("Unable to post blog comment:" + blogMeta, e);
        }
    }

    /**
     * @param username
     * @param blogMeta
     * @param page
     */
    private void postBlog(BlogMeta blogMeta, String pageUid) {
        try {
            Page page = pageService.getPage(NumberUtils.toInt(pageUid));
            if (page != null)
                blogSyncService.post(blogMeta, page);
        } catch (BlogSyncException e) {
            log.error("Unable to post blog:" + blogMeta, e);
        }

    }

    /**
     * @param spaceUname
     * @param xmlrpc
     * @param username
     * @param password
     */
    private void syncExtBlog(String spaceUname, BlogMeta meta, int limit) {
        try {
            blogSyncService.downloadPosts(spaceUname, meta, limit);
            blogSyncService.downloadComments(spaceUname, meta);

            //only upload pages which anonymous is able to see.
            List<Page> pages = pageService.getPagesInSpace(spaceUname, null, 0,
                    userReadingService.getUserByName(null));
            for (Page page : pages) {
                blogSyncService.post(meta, page);
                List<PageComment> comments;
                try {
                    comments = commentService.getPageComments(spaceUname, page.getPageUuid());
                    for (PageComment pageComment : comments) {
                        blogSyncService.postComment(meta, pageComment);
                    }
                } catch (CommentException e) {
                    log.error("Unable to get page comment", e);
                }
            }

        } catch (BlogSyncException e) {
            log.error("Unable to download blog:" + meta, e);
        }
    }

    /**
     * @param space
     * @param removeDelayHours
     */
    private void sendPageCommentsNotification(String username, Integer pageUid, Integer commentUid) {

        Page page = pageService.getPage(pageUid);
        if (page == null) {
            log.error("Unable to get page by uid {}, send page comment notificaiton failed.", pageUid);
            return;
        }

        String comment = null;
        if (commentUid == null) {
            //send daily digest
            comment = ""; //TODO
        } else {
            PageComment pageComment = commentService.getComment(commentUid);
            if (pageComment != null)
                comment = pageComment.getBody();
        }

        if (comment == null) {
            log.error("Unable to get comment by uid {}, send page comment notificaiton failed.", commentUid);
            return;
        }

        int nType = page.getSpace().getSetting().getCommentNotifyType();
        String spaceUname = page.getSpace().getUnixName();
        Set<String> bccList = new HashSet<String>();
        if ((nType & SpaceSetting.COMMENT_NOTIFY_TO_AUTHOR) != 0) {
            if (page.getCreator() != null && page.getCreator().getContact() != null)
                bccList.add(page.getCreator().getContact().getEmail());
        }

        if ((nType & SpaceSetting.COMMENT_NOTIFY_TO_ALL_CONTRIBUTOR) != 0) {
            Set<User> contributor = pageService.getPageContributors(page.getPageUuid());
            for (User user : contributor) {
                if (user.getContact() != null)
                    bccList.add(user.getContact().getEmail());
            }
        }
        if ((nType & SpaceSetting.COMMENT_NOTIFY_TO_SPACE_OWNEER) != 0) {
            Set<String> adminList = userReadingService.getSpaceAdminMailList(spaceUname);
            if (adminList != null)
                bccList.addAll(adminList);
        }

        Map<String, Object> model = new HashMap<String, Object>();
        String link = WikiUtil.getPageRedirFullURL(spaceUname, page.getTitle(), page.getPageUuid());
        model.put(WikiConstants.ATTR_PAGE_LINK, link);
        model.put(WikiConstants.ATTR_PAGE_TITLE, page.getTitle());
        model.put(WikiConstants.ATTR_CONTENT, comment);
        if ((nType & SpaceSetting.COMMENT_NOTIFY_FEQ_EVERY_POST) != 0) {
            //send every post
            sendMail(WikiConstants.MAIL_TEMPL_COMMENT_PER_POST, bccList, model);

        } else {
            //send daily summary
            model.put(WikiConstants.ATTR_COUNT, commentService.getDailyCommentCount(pageUid));
            sendMail(WikiConstants.MAIL_TEMPL_COMMENT_DAILY_SUM, bccList, model);
        }

    }

    /**
     * @param spaceUname
     */
    private void sendSpaceRemovingNotification(Space space, int removeDelayHours) {

        String spaceUname = space.getUnixName();

        //all email receivers are in BCC list, rather than TO or CC
        Set<String> bccList = space.getAdminMailList();

        //if space removed, bccList are already filled before space permanently deleted.
        //if space is going remove, here will fill bccList.
        if (bccList == null) {
            bccList = userReadingService.getSpaceAdminMailList(spaceUname);
        }
        if (bccList.size() > 0) {
            Map<String, Object> model = new HashMap<String, Object>();
            model.put(WikiConstants.ATTR_ADMIN_URL, WikiUtil.getSystemAdminTokenLink());
            model.put(WikiConstants.ATTR_SPACE, space);
            SimpleDateFormat format = new SimpleDateFormat("MMM dd, yyyy hh:mma");
            model.put(WikiConstants.MODIFIED_DATE, format.format(space.getModifiedDate()));
            String link = WikiUtil.getPageRedirFullURL(spaceUname, null, null);
            model.put(WikiConstants.ATTR_PAGE_LINK, link);
            model.put(WikiConstants.ATTR_REMOVE_DELAY_HOURS, removeDelayHours);
            if (removeDelayHours > 0) {
                sendMail(WikiConstants.MAIL_TEMPL_SPACE_REMOVING, bccList, model);
            } else {
                sendMail(WikiConstants.MAIL_TEMPL_SPACE_REMOVED, bccList, model);
            }
        }
    }

    /**
     * @param page
     */
    private void sendPageUpdateNodification(Integer pageUid) {
        List<UserPageMark> watched = userPageDAO.getWatchedByPageUid(pageUid);
        if (watched != null && watched.size() != 0) {
            Page page = pageService.getPage(pageUid);
            if (page != null) {
                log.info("Prepare sending email for page : " + page.getTitle());

                List<String> bccList = new ArrayList<String>();
                for (UserPageMark userPageMark : watched) {
                    String email = null;
                    try {
                        email = userPageMark.getUser().getContact().getEmail();
                    } catch (Exception e) {
                        log.warn("Can not find user contact email for " + userPageMark.getUser());
                    }
                    if (email != null)
                        bccList.add(email);
                }
                if (bccList.size() > 0) {
                    Map<String, Object> model = new HashMap<String, Object>();
                    model.put(WikiConstants.ATTR_PAGE, page);
                    String modifier;
                    if (page.getModifier() != null) {
                        modifier = page.getModifier().getFullname();
                    } else {
                        //Anonymous
                        User anony = WikiUtil.getAnonymous(userReadingService);
                        modifier = anony.getFullname();
                    }
                    model.put(WikiConstants.MODIFIER_FULLNAME, modifier);
                    SimpleDateFormat format = new SimpleDateFormat("MMM dd, yyyy hh:mma");
                    model.put(WikiConstants.MODIFIED_DATE, format.format(page.getModifiedDate()));
                    String link = WikiUtil.getPageRedirFullURL(page.getSpace().getUnixName(), page.getTitle(),
                            page.getPageUuid());
                    model.put(WikiConstants.ATTR_PAGE_LINK, link);

                    sendMail(WikiConstants.MAIL_TEMPL_PAGE_CHANGE_NOTIFICATION, bccList, model);
                }
            } else {
                log.warn("Page {} doesn't exist, No watched email send out.", pageUid);
            }
        } else {
            log.info("No user watches for this page. No email send out.");
        }
    }

    /**
     * @param msg
     * @param bccList
     * @param model
     */
    private void sendMail(String templName, Collection<String> bccList, Map<String, Object> model) {

        SimpleMailMessage msg = new SimpleMailMessage();
        //So far don't user setBcc(bccList) to all user since if one of them mail address is bad, it may cause 
        //al emails can not be send.
        for (String bcc : bccList) {
            //because message "TO" user can not be blank, so here just add default mail address but add 
            //the really recipient on BCC in order to hide user private email info.
            msg.setTo(bcc);
            msg.setFrom(Global.DefaultNotifyMail);
            try {
                //whatever error happen, go on to next user
                mailEngine.sendPlainMail(msg, templName, model);
            } catch (Throwable e) {
                log.error("Send Page Notify mail failed to " + bcc + ". ", e);
            }
        }
        log.info("Email sent to " + bccList.size() + " users.");
    }

    //********************************************************************
    //               set / get
    //********************************************************************
    public void setUserPageDAO(UserPageDAO userPageDAO) {
        this.userPageDAO = userPageDAO;
    }

    public void setMailEngine(MailService mailEngine) {
        this.mailEngine = mailEngine;
    }

    public void setUserReadingService(UserReadingService userReadingService) {
        this.userReadingService = userReadingService;
    }

    public void setPageService(PageService pageService) {
        this.pageService = pageService;
    }

    public void setCommentService(CommentService commentService) {
        this.commentService = commentService;
    }

    public void setBlogSyncService(BlogSyncService blogSyncService) {
        this.blogSyncService = blogSyncService;
    }

    public void setSecurityService(SecurityService securityService) {
        this.securityService = securityService;
    }

}