HTTPServletHandler.java |
/* * $Id: HTTPServletHandler.java,v 1.75 2012/03/15 21:07:39 agoubard Exp $ * * See the COPYRIGHT file for redistribution and use restrictions. */ package org.xins.common.servlet.container; import java.io.File; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Properties; import javax.servlet.ServletException; import org.apache.log4j.LogManager; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.helpers.NullEnumeration; import org.xins.common.Library; import org.xins.common.Log; /** * HTTP server used to invoke the XINS servlet. * * @version $Revision: 1.75 $ $Date: 2012/03/15 21:07:39 $ * @author <a href="mailto:anthony.goubard@japplis.com">Anthony Goubard</a> * @author <a href="mailto:ernst@ernstdehaan.com">Ernst de Haan</a> */ public class HTTPServletHandler { /** * The default port number is 8080. */ public static final int DEFAULT_PORT_NUMBER = 8080; /** * The web server. */ private ServerSocket _serverSocket; /** * The thread that waits for connections from the client. */ private SocketAcceptor _acceptor; /** * Flag indicating if the server should wait for other connections or stop. */ private boolean _running; /** * Mapping between the path and the servlet. */ private Map<String, LocalServletHandler> _servlets = new HashMap<String, LocalServletHandler>(); /** * Creates a new HTTPSevletHandler with no Servlet. Use the addServlet * methods to add the WAR files or the Servlets. * * @param port * The port of the servlet server. * * @param daemon * <code>true</code> if the thread listening to connection should be a * daemon thread, <code>false</code> otherwise. * * @throws IOException * if the servlet container cannot be started. */ public HTTPServletHandler(int port, boolean daemon) throws IOException { // Configure log4j if not already done. Enumeration appenders = LogManager.getLoggerRepository().getRootLogger().getAllAppenders(); if (appenders instanceof NullEnumeration) { configureLoggerFallback(); } // Start the HTTP server. startServer(port, daemon); } /** * Creates a new <code>HTTPServletHandler</code>. This servlet handler * starts a web server on port 8080 and wait for calls from the * <code>XINSServiceCaller</code>. * * <p>Note that all the libraries used by this WAR file should already be * in the classpath. * * @param warFile * the war file of the application to deploy, cannot be * <code>null</code>. * * @throws ServletException * if the servlet cannot be initialized. * * @throws IOException * if the servlet container cannot be started. */ public HTTPServletHandler(File warFile) throws ServletException, IOException { this(DEFAULT_PORT_NUMBER, true); addWAR(warFile, "/"); } /** * Creates a new <code>HTTPSevletHandler</code>. This servlet handler * starts a web server on the specified port and waits for calls from the XINSServiceCaller. * Note that all the libraries used by this WAR file should already be in * the classpath. * * @param warFile * the war file of the application to deploy, cannot be * <code>null</code>. * * @param port * The port of the servlet server. * * @param daemon * <code>true</code> if the thread listening to connection should be a * daemon thread, <code>false</code> otherwise. * * @throws ServletException * if the servlet cannot be initialized. * * @throws IOException * if the servlet container cannot be started. */ public HTTPServletHandler(File warFile, int port, boolean daemon) throws ServletException, IOException { this(port, daemon); addWAR(warFile, "/"); } /** * Creates a new HTTPSevletHandler. This Servlet handler starts a web server * and wait for calls from the XINSServiceCaller. * * @param servletClassName * The name of the servlet's class to load, cannot be <code>null</code>. * * @throws ServletException * if the servlet cannot be initialized. * * @throws IOException * if the servlet container cannot be started. */ public HTTPServletHandler(String servletClassName) throws ServletException, IOException { this(DEFAULT_PORT_NUMBER, true); addServlet(servletClassName, "/"); } /** * Creates a new HTTPSevletHandler. This Servlet handler starts a web server * and wait for calls from the XINSServiceCaller. * * @param servletClassName * The name of the servlet's class to load, cannot be <code>null</code>. * * @param port * The port of the servlet server. * * @param daemon * <code>true</code> if the thread listening to connection should be a * daemon thread, <code>false</code> otherwise. * * @throws ServletException * if the servlet cannot be initialized. * * @throws IOException * if the servlet container cannot be started. */ public HTTPServletHandler(String servletClassName, int port, boolean daemon) throws ServletException, IOException { this(port, daemon); addServlet(servletClassName, "/"); } /** * Initializes the logging subsystem with fallback default settings. */ private static void configureLoggerFallback() { Properties settings = new Properties(); settings.setProperty("log4j.rootLogger", "ALL, console"); settings.setProperty("log4j.appender.console", "org.apache.log4j.ConsoleAppender"); settings.setProperty("log4j.appender.console.layout", "org.apache.log4j.PatternLayout"); settings.setProperty("log4j.appender.console.layout.ConversionPattern", "%6c{1} %-6p %x %m%n"); settings.setProperty("log4j.logger.org.xins.", "INFO"); PropertyConfigurator.configure(settings); } /** * Adds a WAR file to the server. * The servlet with the virtual path "/" will be the default one. * Note that all the libraries used by this WAR file should already be in * the classpath. * * @param warFile * The war file of the application to deploy, cannot be <code>null</code>. * * @param virtualPath * The virtual path of the HTTP server that links to this WAR file, cannot be <code>null</code>. * * @throws ServletException * if the servlet cannot be initialized. */ public void addWAR(File warFile, String virtualPath) throws ServletException { LocalServletHandler servlet = new LocalServletHandler(warFile); if (! virtualPath.endsWith("/")) { virtualPath += '/'; } _servlets.put(virtualPath, servlet); } /** * Adds a new servlet. * The servlet with the virtual path "/" will be the default one. * * @param servletClassName * The name of the servlet's class to load, cannot be <code>null</code>. * * @param virtualPath * The virtual path of the HTTP server that links to this WAR file, cannot be <code>null</code>. * * @throws ServletException * if the servlet cannot be initialized. */ public void addServlet(String servletClassName, String virtualPath) throws ServletException{ LocalServletHandler servlet = new LocalServletHandler(servletClassName); if (! virtualPath.endsWith("/")) { virtualPath += '/'; } _servlets.put(virtualPath, servlet); } /** * Remove a servlet from the server. * * @param virtualPath * The virtual path of the servlet to remove, cannot be <code>null</code>. */ public void removeServlet(String virtualPath) { if (! virtualPath.endsWith("/")) { virtualPath += '/'; } LocalServletHandler servlet = (LocalServletHandler) _servlets.get(virtualPath); servlet.close(); _servlets.remove(virtualPath); } /** * Starts the web server. * * @param port * the port of the servlet server. * * @param daemon * <code>true</code> if the thread listening to connection should be a * daemon thread, <code>false</code> otherwise. * * @throws IOException * if the web server cannot be started. */ public void startServer(int port, boolean daemon) throws IOException { // Create the server socket _serverSocket = new ServerSocket(port, 5); _running = true; _acceptor = new SocketAcceptor(daemon); _acceptor.start(); } /** * Returns the port the server is accepting connections on. * * @return * the server socket, e.g. <code>8080</code>. * * @throws IllegalStateException * if the port cannot be determined, for example because the server is * not started. * * @since XINS 1.5.0 */ public int getPort() throws IllegalStateException { int port; try { port = _serverSocket.getLocalPort(); } catch (NullPointerException exception) { port = -1; } if (port < 0) { throw new IllegalStateException("Unable to determine port."); } return port; } /** * Disposes the servlet and stops the web server. */ public void close() { _running = false; for (LocalServletHandler servlet : _servlets.values()) { servlet.close(); } try { _serverSocket.close(); } catch (IOException ioe) { Log.log_1502(ioe); } } /** * Thread waiting for connection from the client. */ private class SocketAcceptor extends Thread { /** * Create the thread. * * @param daemon * <code>true</code> if the server should be a daemon thread,$ * <code>false</code> otherwise. */ public SocketAcceptor(boolean daemon) { setDaemon(daemon); setName("XINS " + Library.getVersion() + " Servlet container."); } /** * Executes the thread. */ public void run() { Log.log_1500(_serverSocket.getLocalPort()); try { while (_running) { // Wait for a connection Socket clientSocket = _serverSocket.accept(); HTTPQueryHandler queryHandler = new HTTPQueryHandler(clientSocket, _servlets); queryHandler.start(); } } catch (SocketException ie) { // fall through } catch (IOException ioe) { Log.log_1501(ioe); } } } }