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

Java tutorial

Introduction

Here is the source code for com.edgenius.wiki.service.impl.NotificationServiceImpl.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.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.transaction.annotation.Transactional;

import com.edgenius.core.Global;
import com.edgenius.core.Installation;
import com.edgenius.core.SecurityValues.OPERATIONS;
import com.edgenius.core.SecurityValues.RESOURCE_TYPES;
import com.edgenius.core.Version;
import com.edgenius.core.model.Resource;
import com.edgenius.core.model.User;
import com.edgenius.core.service.MailService;
import com.edgenius.core.service.MessageService;
import com.edgenius.core.service.UserReadingService;
import com.edgenius.core.util.AuditLogger;
import com.edgenius.core.util.WebUtil;
import com.edgenius.wiki.ActivityType;
import com.edgenius.wiki.WikiConstants;
import com.edgenius.wiki.dao.NotificationDAO;
import com.edgenius.wiki.gwt.client.server.utils.SharedConstants;
import com.edgenius.wiki.model.ActivityLog;
import com.edgenius.wiki.model.Notification;
import com.edgenius.wiki.quartz.QuartzException;
import com.edgenius.wiki.quartz.VersionCheckJobInvoker;
import com.edgenius.wiki.security.service.SecurityCheckException;
import com.edgenius.wiki.security.service.SecurityService;
import com.edgenius.wiki.service.ActivityLogService;
import com.edgenius.wiki.service.NotificationService;
import com.edgenius.wiki.util.WikiUtil;

/**
 * @author Dapeng.Ni
 */

@Transactional
public class NotificationServiceImpl implements NotificationService {
    private static final Logger log = LoggerFactory.getLogger(NotificationServiceImpl.class);

    private NotificationDAO notificationDAO;
    private MailService mailService;
    private UserReadingService userReadingService;
    private SecurityService securityService;
    private MessageService messageService;
    private VersionCheckJobInvoker versionCheckJobInvoker;
    @Autowired
    private ActivityLogService activityLog;

    public void initScheduledJob() {
        if (!Global.VersionCheck)
            return;

        //when system start, do version check first.
        new Thread(new Runnable() {
            public void run() {
                //as if no connection, this method will block a while, so put it into thread to avoid server start up block.
                doVersionCheck();
            }
        }).start();

        //put version on Quartz job.
        try {
            versionCheckJobInvoker.invokeJob();
        } catch (QuartzException e) {
            log.error("Unable start schedule job for version check.", e);
        }
    }

    public void doVersionCheck() {
        HttpURLConnection conn = null;
        try {
            log.info("Version check starting");
            int currVer = (int) (NumberUtils.toFloat(Version.VERSION, 0f) * 1000);
            //hard code
            URL url = new URL("http://product.edgenius.com/versioncheck/" + SharedConstants.APP_NAME + "/"
                    + Installation.INSTANCE_ID + "/" + currVer);
            //         Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy url", 80));
            //         conn = (HttpURLConnection) url.openConnection(proxy);
            conn = (HttpURLConnection) url.openConnection();
            conn.setAllowUserInteraction(false);
            //         conn.addRequestProperty("Authorization", "Basic "+encrytString(username+":" + password));

            conn.setReadTimeout(20000);
            InputStream in = conn.getInputStream();
            StringBuffer sb = new StringBuffer();
            byte[] b = new byte[1024 * 10];
            int len;
            while ((len = in.read(b)) != -1) {
                sb.append(new String(b, 0, len));

            }
            String content = sb.toString();
            //         String content = "<version>3.01</version>";
            int start = content.indexOf("<version>");
            int end = content.indexOf("</version>");
            if (start != -1 && end != -1 && start < end) {
                String verStr = content.substring(start + 9, end);
                int version = (int) (NumberUtils.toFloat(verStr, 0f) * 1000);

                if (version > 0 && currVer > 0) {
                    if (version > currVer) {
                        //check if this new version is already send notification to user, if so, silence.

                        List<ActivityLog> activities = activityLog.getByTarget(
                                ActivityType.Type.SYSTEM_EVENT.getCode(),
                                ActivityType.SubType.VERSION_PING.getCode(), version, "VERSION_CHECK"); //hardcode
                        if (activities == null || activities.size() == 0) {
                            Map<String, Object> map = new HashMap<String, Object>();
                            map.put("newVer", verStr);
                            map.put("currVer", Version.VERSION);
                            mailService.sendPlainToSystemAdmins(WikiConstants.MAIL_TEMPL_VERSION_CHECK, map);
                            log.info("New version {} found and notified to system administrators.", version);

                            //log activity
                            ActivityLog activity = new ActivityLog();
                            activity.setType(ActivityType.Type.SYSTEM_EVENT.getCode());
                            activity.setSubType(ActivityType.SubType.VERSION_PING.getCode());
                            activity.setTgtResourceType(version);
                            activity.setTgtResourceName("VERSION_CHECK");//hardcode
                            activity.setExtroInfo(verStr);
                            activity.setCreatedDate(new Date());
                            activityLog.save(activity);
                        } else {
                            log.info(
                                    "New version {} found, but this version is already notified so no action takes",
                                    2000);
                        }
                    }
                } else {
                    log.info("Wrong version number returned:{}", content);
                }
            }
            log.info("Version check is done");

        } catch (Exception e) {
            log.warn("Version check not success. This probably because of your network connection");
        } finally {
            try {
                if (conn != null)
                    conn.disconnect();
            } catch (Exception e2) {
            }
        }
    }

    public Notification getMessage(Integer msgUid, User viewer) throws SecurityCheckException {
        //check if this user has permission to read this message
        Notification msg = notificationDAO.get(msgUid);
        //NO permission check?
        return msg;
    }

    public List<Notification> getUserMessages(User viewer, int start, int retCount) {
        if (viewer == null || viewer.isAnonymous())
            return null;

        List<Resource> adminResList = null;
        List<Resource> spaceResList = null;
        boolean isSysAdmin = securityService.isAllowResourceAdmin(SharedConstants.INSTANCE_NAME,
                RESOURCE_TYPES.INSTANCE, viewer);
        if (!isSysAdmin) {
            adminResList = securityService.getResourceOfUserHasOperation(viewer, OPERATIONS.ADMIN);
            spaceResList = securityService.getResourceOfUserHasOperation(viewer, OPERATIONS.WRITE);
        }
        List<Notification> msgs = new ArrayList<Notification>();
        Collection<? extends Notification> list = notificationDAO.getResourceMessages(viewer, isSysAdmin,
                spaceResList, adminResList, start, retCount);

        for (Notification notification : list) {
            if (isSysAdmin)
                notification.setRemovable(true);
            else {
                if (viewer != null && !viewer.isAnonymous() && viewer.equals(notification.getCreator())) {
                    notification.setRemovable(true);
                } else {
                    notification.setRemovable(false);
                }
            }
            msgs.add(notification);
        }

        return msgs;

    }

    public void sendTwitterMessage(String text, int sendEmail) {
        if (StringUtils.isBlank(text) || "@".equals(text) || "@@".equals(text))
            return;

        if (text.trim().startsWith("@")) {
            //parse message
            StringBuilder buf = new StringBuilder(text.trim());
            List<String> receivers = parseReceivers(buf);
            if (receivers.size() == 0) {
                //not valid receiver pass out, send to all user
                sendMessage(text, SharedConstants.MSG_TARGET_ALL_USERS, null, sendEmail);
            } else {
                String msg = buf.toString();

                if (!StringUtils.isBlank(msg)) {
                    for (String receiver : receivers) {
                        String piece = receiver.trim();
                        int target = -1;
                        if (piece.startsWith("@@")) {
                            target = SharedConstants.MSG_TARGET_SPACE_CONTRIBUTE_USERS;
                            piece = piece.substring(2);
                        } else if (piece.startsWith("@")) {
                            target = SharedConstants.MSG_TARGET_USER;
                            piece = piece.substring(1);
                        } else {
                            //unexpected
                            AuditLogger.error("Unexpected: Unable to parse message:" + text);
                        }
                        if (target != -1) {
                            if (piece.startsWith("'") && piece.endsWith("'")) {
                                piece = piece.substring(1, piece.length() - 1);
                            }
                            if (!StringUtils.isBlank(piece)) {
                                log.info("Message sending to {} in type {}", piece, target);
                                sendMessage(msg, target, piece, sendEmail);
                            }
                        }
                    }
                }
            }
        } else {
            sendMessage(text, SharedConstants.MSG_TARGET_ALL_USERS, null, sendEmail);
        }

    }

    public void removeMessage(Integer msgUid) {
        notificationDAO.remove(msgUid);

    }

    public void sendMessage(String text, int targetType, String targetName, int withEmail) {

        Notification message = new Notification();
        WikiUtil.setTouchedInfo(userReadingService, message);
        message.setMessage(text);
        message.setTargetType(targetType);
        message.setTargetName(targetName);
        notificationDAO.saveOrUpdate(message);

        if (withEmail == SEND_MAIL_ALAWYS || withEmail == SEND_MAIL_ONLY_HAS_RECEIVERS) {
            // Send to all user
            if (targetType == SharedConstants.MSG_TARGET_USER && !StringUtils.isBlank(targetName)) {
                User user = userReadingService.getUserByName(targetName);
                if (user != null && !user.isAnonymous())
                    sendMailToUser(message, user.getContact().getEmail());
            } else if (targetType == SharedConstants.MSG_TARGET_SPACE_ADMIN_ONLY
                    && !StringUtils.isBlank(targetName)) {
                //space resource: send email to all admin of this space
                Set<String> users = userReadingService.getSpaceAdminMailList(targetName);
                for (String user : users) {
                    sendMailToUser(message, user);
                }
            } else if (targetType == SharedConstants.MSG_TARGET_SPACE_CONTRIBUTE_USERS
                    && !StringUtils.isBlank(targetName)) {
                Set<String> users = userReadingService.getSpaceContributorMailList(targetName);
                for (String user : users) {
                    sendMailToUser(message, user);
                }
            } else if (targetType == SharedConstants.MSG_TARGET_INSTANCE_ADMIN_ONLY) {
                Set<String> users = userReadingService.getSystemAdminMailList();
                for (String user : users) {
                    sendMailToUser(message, user);
                }
            } else {
                //TODO --- not implemented yet
                //SharedConstants.MSG_TARGET_ALL_USERS //send to all user?
                //SharedConstants.MSG_TARGET_FOLLOWERS
            }
            log.info("Email sent to {} for message.", message.getTargetName());
        }
    }

    //********************************************************************
    //               private method
    //********************************************************************
    public List<String> parseReceivers(StringBuilder buf) {
        int len = buf.length();
        List<String> receivers = new ArrayList<String>();
        StringBuilder rece = new StringBuilder();
        int isReceiver = 0;
        int idx;
        for (idx = 0; idx < len; idx++) {
            char ch = buf.charAt(idx);

            if (ch == '@' && isReceiver != 2) {
                rece.append(ch);
                isReceiver = 1; //expect text or '
                continue;
            }

            if (isReceiver == 0) {
                if (ch != ' ') {
                    break;
                } else {
                    continue;
                }
            }

            if (ch == '\'' && isReceiver > 0) {
                rece.append(ch);
                if (isReceiver == 1 && idx > 0 && buf.charAt(idx - 1) == '@') {
                    isReceiver = 2; //expect end '
                } else if (isReceiver == 2) {
                    receivers.add(rece.toString());
                    rece = new StringBuilder();
                    isReceiver = 0;
                }
                continue;
            }

            if (ch == ' ' && isReceiver == 1) {
                receivers.add(rece.toString());
                rece = new StringBuilder();
                isReceiver = 0;
                continue;
            }
            if (isReceiver > 0) {
                rece.append(ch);
            }
        }
        if (rece.length() != 0) {
            //this already means something wrong - no message in text body, only receivers.  
            //however, just put receiver in list and let outside method to process this case 
            receivers.add(rece.toString());
        }
        buf.delete(0, idx);

        return receivers;
    }

    /**
     * @param message
     */
    private void sendMailToUser(Notification message, String receiveAddr) {
        try {
            User sender = message.getCreator();

            SimpleMailMessage msg = new SimpleMailMessage();
            msg.setFrom(Global.DefaultNotifyMail);
            Map<String, Object> map = new HashMap<String, Object>();
            map.put(WikiConstants.ATTR_USER, sender);
            map.put(WikiConstants.ATTR_PAGE_TITLE, messageService.getMessage("new.message.notify.mail.subject"));
            map.put("message", message.getMessage());
            map.put(WikiConstants.ATTR_PAGE_LINK, WebUtil.getHostAppURL());
            msg.setTo(receiveAddr);
            mailService.sendPlainMail(msg, WikiConstants.MAIL_TEMPL_MESSAGE, map);
        } catch (Exception e) {
            log.error("Failed send notification email:" + receiveAddr, e);
        }
    }

    //********************************************************************
    //               set /get
    //********************************************************************
    public void setNotificationDAO(NotificationDAO notificationDAO) {
        this.notificationDAO = notificationDAO;
    }

    public void setMailService(MailService mailService) {
        this.mailService = mailService;
    }

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

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

    public void setMessageService(MessageService messageService) {
        this.messageService = messageService;
    }

    public void setVersionCheckJobInvoker(VersionCheckJobInvoker versionCheckJobInvoker) {
        this.versionCheckJobInvoker = versionCheckJobInvoker;
    }

}