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     */
022    package org.granite.gravity.jetty8;
023    
024    import javax.servlet.ServletContext;
025    import javax.servlet.http.HttpServletRequest;
026    import javax.servlet.http.HttpSession;
027    
028    import org.eclipse.jetty.websocket.WebSocket;
029    import org.eclipse.jetty.websocket.WebSocketHandler;
030    import org.granite.context.GraniteContext;
031    import org.granite.gravity.Gravity;
032    import org.granite.gravity.GravityManager;
033    import org.granite.logging.Logger;
034    import org.granite.messaging.webapp.ServletGraniteContext;
035    import org.granite.util.ContentType;
036    
037    import flex.messaging.messages.CommandMessage;
038    import flex.messaging.messages.Message;
039    
040    public 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    }