// Copyright 2012 Georg-August-Universität Göttingen, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package de.ugoe.cs.autoquest.httpmonitor.proxy; import javax.servlet.Servlet; import de.ugoe.cs.autoquest.httpmonitor.HttpMonitorComponent; import de.ugoe.cs.autoquest.httpmonitor.HttpMonitorException; import de.ugoe.cs.autoquest.httpmonitor.HttpMonitorExchangeHandler; import de.ugoe.cs.autoquest.httpmonitor.HttpMonitorLogManager; import de.ugoe.cs.autoquest.httpmonitor.HttpMonitorServer; import de.ugoe.cs.autoquest.httpmonitor.Runner; import de.ugoe.cs.autoquest.httpmonitor.ShutdownHook; import de.ugoe.cs.util.console.Console; /** *

* The HTTP monitory proxy monitor starts a web server ({@link HttpMonitorServer}) that receives * proxies HTTP messages and response. Each exchange of a request and a response is forwarded to * an exchange handler. The exchange handler is either a local log manager * ({@link HttpMonitorLogManager}) or a connection to an external and central HTTP monitor via * an {@link HttpMonitorRemoteExchangeHandler}. The class ensures that on shutdown e.g. caused * by CTRL-C the server and all other requied components are stopped correctly. *

* * @author Patrick Harms */ public class HttpMonitoringProxy implements HttpMonitorComponent { /** */ private static final long serialVersionUID = 1L; /** * the port on which the webserver shall listen. */ private int port; /** * the web server receiving the HTTP requests to be proxied */ private HttpMonitorServer server; /** * the manager for all currently recorded exchanges */ private ExchangeListenerManager exchangeListenerManager; /** * the exchange handler to handle are request/response combinations, i.e., exchanges */ private HttpMonitorExchangeHandler exchangeHandler; /** * the directory into which the log files shall be written */ private String logFileBaseDir; /** * the thread needed to handle CTRL-C events */ private Thread shutdownHook; /** * the name of the proxied server */ private String proxiedServer; /** * the port of the proxied server */ private int proxiedPort; /** * the name of the server where the HTTP monitor runs if the exchanges are not logged locally */ private String httpMonitorServer; /** * the port of the server where the HTTP monitor runs if the exchanges are not logged locally */ private int httpMonitorPort; /** *

* initializes the proxy with the command line arguments. Those are the log directory * as first argument, the port to listen to as second argument, the proxied server and port * as third argument, and either the server and port of the HTTP monitor or the term local as * fourth argument. If the term local is provided as fourth argument, logging of exchanges * takes place locally. *

* * @param commandLineArguments the command line arguments when starting the monitor using * the {@link Runner} */ public HttpMonitoringProxy(String[] commandLineArguments) { if (commandLineArguments.length != 4) { Console.printerrln("invalid number of command line parameters. Three are required:"); Console.printerrln(" 1. the port on which to listen"); Console.printerrln(" 2. the server and port to be proxied (format \"host:port\")"); Console.printerrln (" 3. variant a: the value \"local\" for logging recorded exchanges locally"); Console.printerrln (" variant b: the server and port of the HTTP monitor to send the recorded\n" + " exchanges to (format \"host:port\")"); throw new IllegalArgumentException(); } this.logFileBaseDir = commandLineArguments[0]; try { this.port = Integer.parseInt(commandLineArguments[1]); } catch (NumberFormatException e) { Console.printerrln("invalid port specification " + commandLineArguments[1]); } Console.println("listening on port " + this.port); proxiedServer = commandLineArguments[2]; int index = proxiedServer.indexOf(':'); if (index > -1) { try { proxiedPort = Integer.parseInt(proxiedServer.substring(index + 1)); } catch (NumberFormatException e) { Console.printerrln ("invalid port specification " + proxiedServer.substring(index + 1)); } proxiedServer = proxiedServer.substring(0, index); } else { proxiedPort = 80; } Console.println("proxing " + proxiedServer + ":" + proxiedPort); httpMonitorServer = commandLineArguments[3]; index = httpMonitorServer.indexOf(':'); if (index > -1) { try { httpMonitorPort = Integer.parseInt(httpMonitorServer.substring(index + 1)); } catch (NumberFormatException e) { Console.printerrln ("invalid port specification " + httpMonitorServer.substring(index + 1)); } httpMonitorServer = httpMonitorServer.substring(0, index); } else if ("local".equals(httpMonitorServer)) { httpMonitorServer = null; } else { httpMonitorPort = 80; } if (httpMonitorServer != null) { Console.println("sending log data to " + httpMonitorServer + ":" + httpMonitorPort); exchangeHandler = new HttpMonitorRemoteExchangeHandler(httpMonitorServer, httpMonitorPort); } else { Console.println("storing logs locally into directory " + logFileBaseDir); exchangeHandler = new HttpMonitorLogManager(logFileBaseDir); } } /* (non-Javadoc) * @see de.ugoe.cs.autoquest.htmlmonitor.HttpMonitorComponent#init() */ @Override public synchronized void init() throws HttpMonitorException { if (server != null) { throw new IllegalStateException("already initialized."); } exchangeHandler.init(); exchangeListenerManager = new ExchangeListenerManager(exchangeHandler); exchangeListenerManager.init(); Servlet servlet = new HttpMonitoringProxyServlet(proxiedServer, proxiedPort, exchangeListenerManager); server = new HttpMonitorServer(port, servlet); server.init(); shutdownHook = new Thread (new ShutdownHook(server, exchangeListenerManager, exchangeHandler)); } /* (non-Javadoc) * @see de.ugoe.cs.autoquest.htmlmonitor.HttpMonitorComponent#start() */ @Override public synchronized void start() { if ((exchangeHandler == null) || (exchangeListenerManager == null) || (server == null)) { throw new IllegalStateException("not initialized."); } try { Runtime.getRuntime().addShutdownHook(shutdownHook); exchangeHandler.start(); exchangeListenerManager.start(); server.start(); } catch (HttpMonitorException e) { Console.printerrln("could not start HTTP monitoring proxy: " + e); Console.logException(e); } } /* (non-Javadoc) * @see de.ugoe.cs.autoquest.htmlmonitor.HttpMonitorComponent#stop() */ @Override public synchronized void stop() { if ((exchangeHandler == null) || (exchangeListenerManager == null) || (server == null)) { throw new IllegalStateException("not initialized."); } Runtime.getRuntime().removeShutdownHook(shutdownHook); server.stop(); exchangeListenerManager.stop(); exchangeHandler.stop(); server = null; exchangeListenerManager = null; exchangeHandler = null; } }