001/**
002 *   GRANITE DATA SERVICES
003 *   Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 *   This file is part of the Granite Data Services Platform.
006 *
007 *   Granite Data Services is free software; you can redistribute it and/or
008 *   modify it under the terms of the GNU Lesser General Public
009 *   License as published by the Free Software Foundation; either
010 *   version 2.1 of the License, or (at your option) any later version.
011 *
012 *   Granite Data Services is distributed in the hope that it will be useful,
013 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
014 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015 *   General Public License for more details.
016 *
017 *   You should have received a copy of the GNU Lesser General Public
018 *   License along with this library; if not, write to the Free Software
019 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020 *   USA, or see <http://www.gnu.org/licenses/>.
021 */
022package org.granite.gravity.jetty8;
023
024import javax.servlet.ServletContext;
025import javax.servlet.http.HttpServletRequest;
026import javax.servlet.http.HttpSession;
027
028import org.eclipse.jetty.websocket.WebSocket;
029import org.eclipse.jetty.websocket.WebSocketHandler;
030import org.granite.context.GraniteContext;
031import org.granite.gravity.Gravity;
032import org.granite.gravity.GravityManager;
033import org.granite.logging.Logger;
034import org.granite.messaging.webapp.ServletGraniteContext;
035import org.granite.util.ContentType;
036
037import flex.messaging.messages.CommandMessage;
038import flex.messaging.messages.Message;
039
040public class JettyWebSocketHandler extends WebSocketHandler {
041        
042        private static final Logger log = Logger.getLogger(JettyWebSocketHandler.class);
043        
044        private final ServletContext servletContext;
045        
046        public JettyWebSocketHandler(ServletContext servletContext) {
047                this.servletContext = servletContext;
048        }
049        
050    public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
051        if (!protocol.startsWith("org.granite.gravity"))
052                return null;
053        
054                Gravity gravity = GravityManager.getGravity(servletContext);
055                JettyWebSocketChannelFactory channelFactory = new JettyWebSocketChannelFactory(gravity);
056                
057                try {
058                        String connectMessageId = request.getHeader("connectId") != null ? request.getHeader("connectId") : request.getParameter("connectId");
059                        String clientId = request.getHeader("GDSClientId") != null ? request.getHeader("GDSClientId") : request.getParameter("GDSClientId");
060                        String clientType = request.getHeader("GDSClientType") != null ? request.getHeader("GDSClientType") : request.getParameter("GDSClientType");
061                        String sessionId = null;
062                        HttpSession session = request.getSession("true".equals(servletContext.getInitParameter("org.granite.gravity.websocket.forceCreateSession")));
063                        if (session != null) {
064                        ServletGraniteContext.createThreadInstance(gravity.getGraniteConfig(), gravity.getServicesConfig(), 
065                                        this.servletContext, session, clientType);
066                        
067                                sessionId = session.getId();
068                        }
069                        else if (request.getCookies() != null) {
070                                for (int i = 0; i < request.getCookies().length; i++) {
071                                        if ("JSESSIONID".equals(request.getCookies()[i].getName())) {
072                                                sessionId = request.getCookies()[i].getValue();
073                                                break;
074                                        }
075                                }                               
076                        ServletGraniteContext.createThreadInstance(gravity.getGraniteConfig(), gravity.getServicesConfig(), 
077                                        this.servletContext, sessionId, clientType);
078                        }
079            else {
080                ServletGraniteContext.createThreadInstance(gravity.getGraniteConfig(), gravity.getServicesConfig(),
081                        this.servletContext, (String)null, clientType);
082            }
083                        
084                        log.info("WebSocket connection started %s clientId %s sessionId %s", protocol, clientId, sessionId);
085                        
086                        CommandMessage pingMessage = new CommandMessage();
087                        pingMessage.setMessageId(connectMessageId != null ? connectMessageId : "OPEN_CONNECTION");
088                        pingMessage.setOperation(CommandMessage.CLIENT_PING_OPERATION);
089                        if (clientId != null)
090                                pingMessage.setClientId(clientId);
091                        
092                        Message ackMessage = gravity.handleMessage(channelFactory, pingMessage);
093            if (sessionId != null)
094                ackMessage.setHeader("JSESSIONID", sessionId);
095                        
096                        JettyWebSocketChannel channel = gravity.getChannel(channelFactory, (String)ackMessage.getClientId());
097            channel.setSession(session);
098
099            String ctype = request.getContentType();
100            if (ctype == null && protocol.length() > "org.granite.gravity".length())
101                ctype = "application/x-" + protocol.substring("org.granite.gravity.".length());
102
103                        ContentType contentType = ContentType.forMimeType(ctype);
104                        if (contentType == null) {
105                                log.warn("No (or unsupported) content type in request: %s", request.getContentType());
106                                contentType = ContentType.AMF;
107                        }
108                        channel.setContentType(contentType);
109                        
110                        if (!ackMessage.getClientId().equals(clientId))
111                                channel.setConnectAckMessage(ackMessage);
112                        
113                        return channel;
114                }
115                finally {
116                        GraniteContext.release();
117                }
118    }
119}