com.azprogrammer.qgf.controllers.HomeController.java Source code

Java tutorial

Introduction

Here is the source code for com.azprogrammer.qgf.controllers.HomeController.java

Source

/*
 * $Id$
 *
 * Copyright ( c ) 2010 Carefx Corporation. All Rights Reserved.
 *
 * This software is the confidential and proprietary information of Carefx
 * Corporation ("Confidential Information").  You shall not disclose such
 * Confidential Information and shall use it only in accordance with the terms
 * of the license agreement you entered into with Carefx Corporation or a Carefx
 * authorized reseller (the "License Agreement"). Carefx may make changes to the
 * Confidential Information from time to time. Such Confidential Information may
 * contain errors.
 *
 * EXCEPT AS EXPLICITLY SET FORTH IN THE LICENSE AGREEMENT, CAREFX DISCLAIMS ALL
 * WARRANTIES, COVENANTS, REPRESENTATIONS, INDEMNITIES, AND GUARANTEES WITH
 * RESPECT TO SOFTWARE AND DOCUMENTATION, WHETHER EXPRESS OR IMPLIED, WRITTEN OR
 * ORAL, STATUTORY OR OTHERWISE INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A
 * PARTICULAR PURPOSE. CAREFX DOES NOT WARRANT THAT END USER'S USE OF THE
 * SOFTWARE WILL BE UNINTERRUPTED, ERROR FREE OR SECURE.
 *
 * CAREFX SHALL NOT BE LIABLE TO END USER, OR ANY OTHER PERSON, CORPORATION OR
 * ENTITY FOR INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL
 * DAMAGES, OR DAMAGES FOR LOSS OF PROFITS, REVENUE, DATA OR USE, WHETHER IN AN
 * ACTION IN CONTRACT, TORT OR OTHERWISE, EVEN IF CAREFX HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES. CAREFX' TOTAL LIABILITY TO END USER SHALL NOT
 * EXCEED THE AMOUNTS PAID FOR THE CAREFX SOFTWARE BY END USER DURING THE PRIOR
 * TWELVE (12) MONTHS FROM THE DATE IN WHICH THE CLAIM AROSE.  BECAUSE SOME
 * STATES OR JURISDICTIONS DO NOT ALLOW LIMITATION OR EXCLUSION OF CONSEQUENTIAL
 * OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY NOT APPLY TO END USER.
 *
 * Copyright version 2.0
 */
package com.azprogrammer.qgf.controllers;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.Transaction;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import java.util.Properties;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
import net.sf.json.JsonConfig;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import com.azprogrammer.qgf.model.PMF;
import com.azprogrammer.qgf.model.WBChannel;
import com.azprogrammer.qgf.model.WBEmail;
import com.azprogrammer.qgf.model.WBGeometry;
import com.azprogrammer.qgf.model.WBMessage;
import com.azprogrammer.qgf.model.WhiteBoard;
import com.azprogrammer.qgf.text.InputValidator;
import com.azprogrammer.qgf.text.TextFormatter;
import com.azprogrammer.qgf.util.WebUtil;
import com.azprogrammer.qgf.views.ExternalRedirectView;
import com.azprogrammer.qgf.views.JSONView;
import com.google.appengine.api.channel.ChannelMessage;
import com.google.appengine.api.channel.ChannelService;
import com.google.appengine.api.channel.ChannelServiceFactory;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;

/**
 * @author lmontes
 *
 */

@Controller
public class HomeController {

    static final char[] validChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".toCharArray();
    protected InputValidator inputValidator;
    protected TextFormatter textFormatter;

    //how long ago does a user have to have pinged before not being in room anymore?
    protected long lastPingMillis = 1000 * 60 * 7;

    public HomeController() {

    }

    @RequestMapping(value = "/*")
    public String doHome(ModelMap model, HttpServletRequest req) {
        return "home";
    }

    @RequestMapping(value = "/whiteboard/{wbId}")
    public ModelAndView doWhiteboardREST(ModelMap model, HttpServletRequest req, @PathVariable String wbId) {
        return doWhiteboard(model, req, wbId);
    }

    @RequestMapping(value = "/boards")
    public String doBoards(ModelMap model, HttpServletRequest req, String wbId) {
        UserService userService = UserServiceFactory.getUserService();
        User user = userService.getCurrentUser(); // req.getUserPrincipal()?!?
        if (user == null) {
            String loginURL = userService.createLoginURL(req.getRequestURI());
            model.put("loginURL", loginURL);
            return "login";
        } else {
            if (isAdmin()) {

                long start = 0;
                try {
                    start = Long.parseLong(req.getParameter("start"));
                } catch (Exception numE) {
                }

                model.put("user", user);
                PersistenceManager pm = getPM();
                Query query = pm.newQuery(WhiteBoard.class);
                query.setOrdering("creationDate desc");
                query.setRange(start, start + 101);
                //Collection result = (Collection)query.execute(date);

                List<WhiteBoard> boards = (List<WhiteBoard>) query.execute();// pm.newQuery(query).execute();
                System.out.println("boards: " + boards.size());
                model.put("boards", boards);
                return "boards";
            } else {
                String logoutURL = userService.createLogoutURL(req.getRequestURI());
                model.put("logoutURL", logoutURL);
                return "logout";
            }
        }

    }

    @RequestMapping(value = "/whiteboard")
    public ModelAndView doWhiteboard(ModelMap model, HttpServletRequest req, String wbId) {

        ModelAndView mav = new ModelAndView();
        mav.addAllObjects(model);
        PersistenceManager pm = getPM();
        HttpSession session = req.getSession();
        WhiteBoard wb = null;
        List<WBMessage> messages = null;

        if ((wbId == null) || ("".equals(wbId))) {
            wbId = req.getParameter("wb");
        }

        if ((wbId != null) && (!"".equals(wbId.trim()))) {
            wbId = cleanupWbId(wbId);
            try {
                Key key = KeyFactory.stringToKey(wbId);
                wb = pm.getObjectById(WhiteBoard.class, key);
                //String query = "select from " + WBMessage.class.getName() + " where wbKey == KEY('" + wbId + "')";

                Query query = pm.newQuery(WBMessage.class, "this.wbKey == key");
                query.declareParameters("com.google.appengine.api.datastore.Key key");
                query.setOrdering("creationTime asc");
                //Collection result = (Collection)query.execute(date);

                messages = (List<WBMessage>) query.execute(key);// pm.newQuery(query).execute();

            } catch (Exception e) {
                model.put("errorMsg", e.getMessage());
            }
        } else {
            wb = new WhiteBoard();
            wb.setCreatedBySessionId(req.getSession().getId());
            wb.setCreationDate(new Date());
            wb.setReferer(req.getHeader("referer"));
            wb.setUserAgent(req.getHeader("user-agent"));
            pm.makePersistent(wb);

            ExternalRedirectView rv = new ExternalRedirectView(
                    "/whiteboard/" + KeyFactory.keyToString(wb.getKey()));
            mav.setView(rv);
            return mav;

        }

        ChannelService channelService = ChannelServiceFactory.getChannelService();

        if (wb == null) {
            mav.setViewName("badWbId");
            return mav;
        }

        if (messages == null) {
            messages = new ArrayList<WBMessage>();
        }

        //don't need key data in JSON
        JsonConfig jsconfig = new JsonConfig();
        String[] exlcudes = new String[] { "key", "wbKey", "userList", "shapeId" };
        jsconfig.setExcludes(exlcudes);
        HashMap<String, Object> messagesMap = new HashMap<String, Object>();
        messagesMap.put("messages", messages);
        model.put("messageMapJSON", JSONObject.fromObject(messagesMap, jsconfig).toString());

        String wbKeyStr = KeyFactory.keyToString(wb.getKey());

        Object userNameObj = req.getSession().getAttribute("userName");
        String userName = null;
        if (userNameObj != null) {
            userName = userNameObj.toString();
            WBChannel wbc = null;
            try {
                //String query = "select from " + WBChannel.class.getName() + " where sessionId == '" + session.getId () + "' && wbKey == '" + wbKeyStr + "'";
                //List<WBChannel> channels = (List<WBChannel>) pm.newQuery(query).execute();

                Query query = pm.newQuery(WBChannel.class, "this.wbKey == key && this.sessionId == sessId");
                query.declareParameters("com.google.appengine.api.datastore.Key key, String sessId");

                List<WBChannel> channels = (List<WBChannel>) query.execute(wb.getKey(), session.getId());// pm.newQuery(query).execute();

                if ((channels != null) && (channels.size() > 0)) {
                    wbc = channels.get(0);
                    Transaction tx = pm.currentTransaction();
                    tx.begin();
                    wbc.setTime(System.currentTimeMillis());
                    tx.commit();
                }
            } catch (Exception e) {

            }

            if (wbc == null) {
                wbc = new WBChannel();
                wbc.setSessionId(session.getId());
                wbc.setWbKey(wb.getKey());
                wbc.setUserName(userName);
                wbc.setTime(System.currentTimeMillis());
                wbc.setUserAgent(req.getHeader("user-agent"));
                pm.makePersistent(wbc);
            }

            pushNewUserList(wbId);

            model.put("userName", userName);
            String token = channelService.createChannel(session.getId());
            model.put("token", token);
        }

        model.put("wbId", wbKeyStr);
        if (WebUtil.isMobile(req)) {
            model.put("mobileTheme", WebUtil.getMobileTheme(req));
            mav.setViewName("mobileboard");
        } else {
            mav.setViewName("whiteboard");
        }
        return mav;
    }

    @RequestMapping(value = "/wbping")
    public ModelAndView doWhiteboardPing(ModelMap model, HttpServletRequest req) {
        model.clear();
        HttpSession session = req.getSession();
        try {
            PersistenceManager pm = getPM();
            WBChannel wbc = null;
            //String query = "select from " + WBChannel.class.getName() + " where sessionId == '" + session.getId () + "' && wbKey == '" + cleanupWbId (req.getParameter ("wbId")) + "'";
            //List<WBChannel> channels = (List<WBChannel>) pm.newQuery(query).execute();

            Query query = pm.newQuery(WBChannel.class, "this.wbKey == key && this.sessionId == sessId");
            query.declareParameters("com.google.appengine.api.datastore.Key key, String sessId");

            List<WBChannel> channels = (List<WBChannel>) query
                    .execute(KeyFactory.stringToKey(cleanupWbId(req.getParameter("wbId"))), session.getId());// pm.newQuery(query).execute();

            if ((channels != null) && (channels.size() > 0)) {
                wbc = channels.get(0);
                Transaction tx = pm.currentTransaction();
                tx.begin();
                wbc.setTime(System.currentTimeMillis());
                tx.commit();
                model.put("status", "ok");
            } else {
                model.put("error", "Invalid channel.");

            }
        } catch (Exception e) {
            model.put("error", e.getMessage());
        }

        return doJSON(model);
    }

    @RequestMapping(value = "/wbchannels/{wbId}")
    public ModelAndView doWhiteboardChannels(ModelMap model, HttpServletRequest req, @PathVariable String wbId) {
        model.clear();
        try {
            model.put("wbId", wbId);
            if (isAdmin()) {
                PersistenceManager pm = getPM();

                Query query = pm.newQuery(WBChannel.class, "this.wbKey == key");
                query.declareParameters("com.google.appengine.api.datastore.Key key");

                List<WBChannel> channels = (List<WBChannel>) query.execute(KeyFactory.stringToKey(wbId));

                if ((channels != null) && (channels.size() > 0)) {
                    model.put("channels", channels);
                    model.put("status", "ok");
                } else {
                    model.put("error", "no channels.");

                }
            } else {
                throw new Exception("Unauthorized");
            }
        } catch (Exception e) {
            model.put("error", e.getMessage());
        }

        return doJSON(model);
    }

    @RequestMapping(value = "/wbmessages/{wbId}")
    public ModelAndView doWhiteboardMessages(ModelMap model, HttpServletRequest req, @PathVariable String wbId) {
        model.clear();
        try {
            model.put("wbId", wbId);
            if (isAdmin()) {
                PersistenceManager pm = getPM();

                Query query = pm.newQuery(WBMessage.class, "this.wbKey == key");
                query.declareParameters("com.google.appengine.api.datastore.Key key");

                List<WBMessage> messages = (List<WBMessage>) query.execute(KeyFactory.stringToKey(wbId));

                if ((messages != null) && (messages.size() > 0)) {
                    model.put("messages", messages);
                    model.put("status", "ok");
                } else {
                    model.put("error", "no messages.");

                }
            } else {
                throw new Exception("Unauthorized");
            }
        } catch (Exception e) {
            model.put("error", e.getMessage());
        }

        return doJSON(model);
    }

    @RequestMapping(value = "/wbgetUsers")
    public ModelAndView doWhiteboardGetUsers(ModelMap model, HttpServletRequest req) {
        model.clear();
        try {
            List<WBChannel> channels = getLiveChannels(cleanupWbId(req.getParameter("wbId")));

            if ((channels != null) && (channels.size() > 0)) {
                Set<String> userNames = new HashSet<String>();
                for (WBChannel wbChannel : channels) {
                    userNames.add(wbChannel.getUserName());
                }

                model.put("userList", userNames);
                model.put("status", "ok");

            } else {
                model.put("error", "Invalid channel.");

            }
        } catch (Exception e) {
            model.put("error", e.getMessage());
        }

        return doJSON(model);
    }

    public ModelAndView doJSON(Map<String, Object> model) {
        ModelAndView mav = new ModelAndView(new JSONView());

        mav.addAllObjects(model);
        return mav;
    }

    protected List<WBChannel> getLiveChannels(String wbId) {
        List<WBChannel> channels = new ArrayList<WBChannel>();
        try {
            PersistenceManager pm = getPM();
            long time = System.currentTimeMillis() - lastPingMillis;

            //String query = "select from " + WBChannel.class.getName() + " where time > " + time + " && wbKey == '" + wbId + "'";
            //List <WBChannel> result = (List<WBChannel>) pm.newQuery(query).execute();

            Query query = pm.newQuery(WBChannel.class, "this.wbKey == key && this.time > lastPing");
            query.declareParameters("com.google.appengine.api.datastore.Key key, Long lastPing");

            List<WBChannel> result = (List<WBChannel>) query.execute(KeyFactory.stringToKey(wbId), time);// pm.newQuery(query).execute();

            for (WBChannel wbChannel : result) {
                channels.add(wbChannel);
            }

        } catch (Exception e) {

        }

        if (channels == null) {
            channels = new ArrayList<WBChannel>();
        }

        return channels;

    }

    @RequestMapping(value = "/wbmail")
    public ModelAndView doWhiteboardMail(ModelMap model, HttpServletRequest req) {
        model.clear();

        try {
            WBEmail email = new WBEmail();
            HttpSession session = req.getSession();
            String userName = session.getAttribute("userName").toString();
            String toAddress = req.getParameter("email");

            if (!WebUtil.isValidEmail(toAddress)) {
                throw new Exception("invalid email");

            }

            //TODO validate message contents
            email.setFromUser(userName);
            email.setToAddress(toAddress);

            WhiteBoard wb = getWhiteBoard(req);
            if (wb == null) {
                throw new Exception("Invalid White Board");
            }

            email.setWbKey(wb.getKey());
            email.setCreationTime(System.currentTimeMillis());

            Properties props = new Properties();
            Session mailsession = Session.getDefaultInstance(props, null);

            String emailError = null;
            try {
                MimeMessage msg = new MimeMessage(mailsession);
                msg.setFrom(new InternetAddress("no_reply@drawitlive.com", "Draw it Live"));
                msg.addRecipient(Message.RecipientType.TO, new InternetAddress(toAddress));
                msg.setSubject("Please join the whiteboard session on " + req.getServerName());
                String msgBody = "To join " + userName
                        + " on a colloborative whiteboard follow this link: <a href=\"http://" + req.getServerName()
                        + "/whiteboard/" + req.getParameter("wbId") + "\"> http://" + req.getServerName()
                        + "/whiteboard/" + req.getParameter("wbId") + "</a>";
                msg.setText(msgBody, "UTF-8", "html");
                Transport.send(msg);

            } catch (AddressException e) {
                emailError = e.getMessage();
            } catch (MessagingException e) {
                emailError = e.getMessage();
            }

            if (emailError == null) {
                email.setStatus(WBEmail.STATUS_SENT);
            } else {
                email.setStatus(WBEmail.STATUS_ERROR);
            }

            getPM().makePersistent(email);

            if (email.getStatus() == WBEmail.STATUS_ERROR) {
                throw new Exception(emailError);
            }

            model.put("status", "ok");

        } catch (Exception e) {
            model.put("error", e.getMessage());
        }

        return doJSON(model);
    }

    @RequestMapping(value = "/wbpost")
    public ModelAndView doWhiteboardPost(ModelMap model, HttpServletRequest req) {
        model.clear();

        try {
            String jsonData = req.getParameter("data");
            JSONObject json = (JSONObject) JSONSerializer.toJSON(jsonData);
            WBMessage message = (WBMessage) JSONObject.toBean(json, WBMessage.class);
            HttpSession session = req.getSession();
            String userName = session.getAttribute("userName").toString();

            //TODO validate message contents
            message.setFromUser(userName);

            if (message.getChatMessage() != null) {
                message.setChatMessage(getInputValidator().cleanCommentText(message.getChatMessage()));
                message.setChatMessage(getTextFormatter().formatCommentText(message.getChatMessage()));
            }

            WhiteBoard wb = getWhiteBoard(req);
            if (wb == null) {
                throw new Exception("Invalid White Board");
            }

            message.setWbKey(wb.getKey());
            message.setFromUser(userName);
            message.setCreationTime(System.currentTimeMillis());

            //trim any text geom > 100 chars
            if (message.getGeometry() != null) {
                WBGeometry geom = message.getGeometry();
                if ((geom.getText() != null) && (geom.getText().length() > 100)) {
                    geom.setText(geom.getText().substring(0, 99));
                }
            }

            getPM().makePersistent(message);

            List<WBChannel> channels = getLiveChannels(KeyFactory.keyToString(wb.getKey()));
            ChannelService channelService = ChannelServiceFactory.getChannelService();
            String channelError = null;
            for (WBChannel wbChannel : channels) {

                // don't need to send drawing data back to originating user
                if ((message.getChatMessage() != null) || (!session.getId().equals(wbChannel.getSessionId()))) {
                    try {
                        channelService.sendMessage(new ChannelMessage(wbChannel.getSessionId(),
                                JSONObject.fromObject(message).toString()));

                    } catch (Exception e) {
                        channelError = e.getMessage();
                    }
                }
            }

            //if there was at least one channelError, we'll log it to the browser console
            if (channelError != null) {
                model.put("channelError",
                        "error delivering to at least one channel: " + channelError + "(user may have left)");
            }
            model.put("status", "ok");
            model.put("message", JSONObject.fromObject(message));

        } catch (Exception e) {
            model.put("error", e.getMessage());
        }

        return doJSON(model);
    }

    protected PersistenceManager getPM() {
        return PMF.get().getPersistenceManager();
    }

    @RequestMapping(value = "/wbSetName")
    public ModelAndView doWBSetName(ModelMap model, HttpServletRequest req) {
        model.clear();

        HttpSession session = req.getSession();
        PersistenceManager pm = getPM();

        WhiteBoard wb = null;
        try {

            wb = getWhiteBoard(req);
            if (wb == null) {
                throw new Exception("Invalid Whiteboard ID");
            }
        } catch (Exception e) {
            model.put("error", e.getMessage());
        }

        try {
            if (wb != null) {
                String userName = cleanUpName(req);
                String wbId = KeyFactory.keyToString(wb.getKey());
                if ("".equals(userName)) {
                    model.put("error", "Invalid username");
                } else {
                    req.getSession().setAttribute("userName", userName);

                    WBChannel wbc = new WBChannel();
                    wbc.setSessionId(session.getId());
                    wbc.setWbKey(wb.getKey());
                    wbc.setUserName(userName);
                    wbc.setTime(System.currentTimeMillis());
                    wbc.setUserAgent(req.getHeader("user-agent"));
                    pm.makePersistent(wbc);
                    pushNewUserList(wbId);

                    ChannelService channelService = ChannelServiceFactory.getChannelService();
                    String token = channelService.createChannel(session.getId());
                    model.put("token", token);
                    model.put("userName", userName);
                    model.put("status", "ok");

                }
            }
        } catch (Exception e) {
            model.put("error", e.getMessage());
        }
        return doJSON(model);
    }

    protected void pushNewUserList(String wbId) {
        List<WBChannel> channels = getLiveChannels(wbId);
        HashSet<String> userNames = new HashSet<String>();
        for (WBChannel wbChannel : channels) {
            userNames.add(wbChannel.getUserName());
        }
        ChannelService channelService = ChannelServiceFactory.getChannelService();
        for (WBChannel wbChannel : channels) {
            try {
                WBMessage message = new WBMessage();
                message.setUserList(userNames);
                channelService.sendMessage(
                        new ChannelMessage(wbChannel.getSessionId(), JSONObject.fromObject(message).toString()));

            } catch (Exception e) {

            }
        }

    }

    protected WhiteBoard getWhiteBoard(HttpServletRequest req) throws Exception {
        PersistenceManager pm = getPM();
        return pm.getObjectById(WhiteBoard.class, KeyFactory.stringToKey(cleanupWbId(req.getParameter("wbId"))));

    }

    protected String cleanUpName(HttpServletRequest req) {
        String userName = req.getParameter("userName");
        if (userName == null) {
            userName = "";
        }

        userName = userName.trim();

        char[] userChars = userName.toCharArray();
        for (int i = 0; i < userChars.length; i++) {
            if (!validChar(userChars[i])) {
                userChars[i] = '_';
            }
        }

        return new String(userChars);
    }

    protected boolean validChar(char c) {
        for (int i = 0; i < validChars.length; i++) {
            if (c == validChars[i]) {
                return true;
            }
        }
        return false;
    }

    protected String cleanupWbId(String wbId) {
        if (wbId != null) {
            if (wbId.indexOf("'") > -1) {
                return null;
            }
            if (wbId.indexOf("\"") > -1) {
                return null;
            }
        }
        return wbId;
    }

    /**
     * @return the inputValidator
     */
    public InputValidator getInputValidator() {
        return inputValidator;
    }

    /**
     * @param inputValidator the inputValidator to set
     */
    @Autowired
    public void setInputValidator(InputValidator inputValidator) {
        this.inputValidator = inputValidator;
    }

    /**
     * @return the textFormatter
     */
    public TextFormatter getTextFormatter() {
        return textFormatter;
    }

    /**
     * @param textFormatter the textFormatter to set
     */
    @Autowired
    public void setTextFormatter(TextFormatter textFormatter) {
        this.textFormatter = textFormatter;
    }

    public boolean isAdmin() {

        UserService userService = UserServiceFactory.getUserService();
        User user = userService.getCurrentUser(); // req.getUserPrincipal()?!?
        if (user != null) {
            String nick = user.getNickname().toUpperCase();
            if (nick.startsWith("MONTESLU")) {
                return true;
            }
            return false;
        } else {
            return false;
        }
    }

}