// --------------------------------------------------------------------------- // jWebSocket - Jetty Engine // Copyright (c) 2010 Alexander Schulze, Innotrade GmbH // --------------------------------------------------------------------------- // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation; either version 3 of the License, or (at your // option) any later version. // 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 Lesser General Public License for // more details. // You should have received a copy of the GNU Lesser General Public License along // with this program; if not, see <http://www.gnu.org/licenses/lgpl.html>. // --------------------------------------------------------------------------- package org.jwebsocket.jetty; import java.util.Date; import org.apache.log4j.Logger; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ssl.SslSelectChannelConnector; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.jwebsocket.api.EngineConfiguration; import org.jwebsocket.api.WebSocketConnector; import org.jwebsocket.engines.BaseEngine; import org.jwebsocket.kit.CloseReason; import org.jwebsocket.kit.WebSocketException; import org.jwebsocket.logging.Logging; /** * * @author aschulze */ public class JettyEngine extends BaseEngine { private static Logger mLog = Logging.getLogger(JettyEngine.class); private boolean mIsRunning = false; private Server mJettyServer = null; public JettyEngine(EngineConfiguration aConfiguration) { super(aConfiguration); int lPort = aConfiguration.getPort(); int lSSLPort = aConfiguration.getSSLPort(); String lContext = aConfiguration.getContext(); if (lContext == null) { lContext = "/"; } String lServlet = aConfiguration.getContext(); if (lServlet == null) { lServlet = "/*"; } try { // create Jetty server if (mLog.isDebugEnabled()) { mLog.debug("Instantiating Jetty server at " + "port " + lPort + ", ssl-port " + lSSLPort + ", context: '" + lContext + "', servlet: '" + lServlet + "'..."); } mJettyServer = new Server(lPort); SslSelectChannelConnector lSSLConnector = new SslSelectChannelConnector(); String lWebSocketHome = System.getenv("JWEBSOCKET_HOME"); String lKeyStore = lWebSocketHome + "/conf/jWebSocket.ks"; if (mLog.isDebugEnabled()) { mLog.debug("Loading SSL cert from keystore '" + lKeyStore + "'..."); } lSSLConnector.setPort(lSSLPort); lSSLConnector.setKeystore(lKeyStore); lSSLConnector.setPassword("jWebSocket"); lSSLConnector.setKeyPassword("jWebSocket"); mJettyServer.addConnector(lSSLConnector); if (mLog.isDebugEnabled()) { mLog.debug("Instantiating SelectChannelConnector..."); } if (mLog.isDebugEnabled()) { mLog.debug("Adding connector to server..."); } if (mLog.isDebugEnabled()) { mLog.debug("Setting the context w/o sessions..."); } ServletContextHandler lServletContext = new ServletContextHandler(ServletContextHandler.NO_SESSIONS); lServletContext.setContextPath(lContext); mJettyServer.setHandler(lServletContext); lServletContext.addServlet(new ServletHolder(new JettyServlet()), lServlet); mJettyServer.setStopAtShutdown(true); if (mLog.isDebugEnabled()) { mLog.debug("Starting embedded Jetty server..."); } mJettyServer.start(); // if (mLog.isDebugEnabled()) { // mLog.debug("Joining embedded Jetty server..."); // } // mJettyServer.join(); } catch (Exception lEx) { mLog.error(lEx.getClass().getSimpleName() + "Instantiating Embedded Jetty Server: " + lEx.getMessage()); } if (mLog.isDebugEnabled()) { mLog.debug("Jetty Server sucessfully instantiated at port " + lPort + ", SSL port " + lSSLPort + "..."); } } @Override public void startEngine() throws WebSocketException { if (mLog.isDebugEnabled()) { mLog.debug("Starting Jetty engine '" + getId() + "..."); } super.startEngine(); if (mLog.isInfoEnabled()) { mLog.info("Jetty engine '" + getId() + "' started."); } } @Override public void stopEngine(CloseReason aCloseReason) throws WebSocketException { if (mLog.isDebugEnabled()) { mLog.debug("Stopping Jetty engine '" + getId() + "..."); } // resetting "isRunning" causes engine listener to terminate mIsRunning = false; // inherited method stops all connectors long lStarted = new Date().getTime(); int lNumConns = getConnectors().size(); super.stopEngine(aCloseReason); try { mJettyServer.stop(); } catch (Exception lEx) { mLog.error(lEx.getClass().getSimpleName() + "Stopping Embedded Jetty Server: " + lEx.getMessage()); } /* // now wait until all connectors have been closed properly // or timeout exceeds... try { while (getConnectors().size() > 0 && new Date().getTime() - lStarted < 10000) { Thread.sleep(250); } } catch (Exception lEx) { mLog.error(lEx.getClass().getSimpleName() + ": " + lEx.getMessage()); } if (mLog.isDebugEnabled()) { long lDuration = new Date().getTime() - lStarted; int lRemConns = getConnectors().size(); if (lRemConns > 0) { mLog.warn(lRemConns + " of " + lNumConns + " Jetty connectors '" + getId() + "' did not stop after " + lDuration + "ms."); } else { mLog.debug(lNumConns + " Jetty connectors '" + getId() + "' stopped after " + lDuration + "ms."); } } */ } @Override public void connectorStarted(WebSocketConnector aConnector) { if (mLog.isDebugEnabled()) { mLog.debug("Detected new connector at port " + aConnector.getRemotePort() + "."); } super.connectorStarted(aConnector); } @Override public void connectorStopped(WebSocketConnector aConnector, CloseReason aCloseReason) { if (mLog.isDebugEnabled()) { mLog.debug("Detected stopped connector at port " + aConnector.getRemotePort() + "."); } super.connectorStopped(aConnector, aCloseReason); } @Override /* * Returns {@code true} if the TCP engine is running or {@code false} * otherwise. The alive status represents the state of the TCP engine * listener thread. */ public boolean isAlive() { return mIsRunning; } }