Source code for /engineering/autohit-2003/src/autohit/server/service/HttpCommandService.javaOriginal file HttpCommandService.java
   1 /**
   2  * AUTOHIT 2003
   3  * Copyright Erich P Gatejen (c) 1989,1997,2003,2004
   4  * 
   5  * This program is free software; you can redistribute it and/or modify 
   6  * it under the terms of the GNU General Public License as published by 
   7  * the Free Software Foundation; either version 2 of the License, or (at
   8  * your option) any later version.
   9  * This program is distributed in the hope that it will be useful, but
  10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  11  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12  * more details.
  13  * 
  14  * You should have received a copy of the GNU General Public License along
  15  * with this program; if not, write to the Free Software Foundation, Inc.,
  16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17  *
  18  * Additional license information can be found in the documentation.
  19  * @author Erich P Gatejen
  20  */
  21 package autohit.server.service;
  22 
  23 import java.net.ServerSocket;
  24 import java.net.Socket;
  25 import java.net.SocketTimeoutException;
  26 import java.util.HashSet;
  27 import java.util.Iterator;
  28 
  29 import autohit.common.AutohitErrorCodes;
  30 import autohit.common.AutohitProperties;
  31 import autohit.common.Utils;
  32 import autohit.common.channels.Channel;
  33 import autohit.common.channels.Controller;
  34 import autohit.common.channels.Injector;
  35 import autohit.common.channels.SimpleInjector;
  36 import autohit.server.invoker.SimTextCommand;
  37 
  38 /**
  39  * This is a socket relay service. It's a dumb relay for sockets. Don't ask why
  40  * I did this. It will accept connections on port
  41  * AutohitProperties.value_SOCKETRELAY_SERVER_PORT. It'll relay them to the
  42  * current property settings for
  43  * AutohitProperties.SERVICE_SOCKETRELAY_DESTINATION_ADDR and
  44  * AutohitProperties.SERVICE_SOCKETRELAY_DESTINATION_PORT for address and port,
  45  * respectively. If either is not set, a default will be used, though there is
  46  * little utility in the default.
  47  * <p>
  48  * <p>
  49  * The relay will stay active until either side drops the connection. There is
  50  * absolutely no filtering or logging.
  51  * 
  52  * @author Erich P. Gatejen
  53  * @version 1.0 <i>Version History</i><code>EPG - Initial - 12SEP03</code>
  54  */
  55 public class HttpCommandService extends Service {
  56 
  57 	final private static int ACCEPT_TIMEOUT = 2000;
  58 	final private static int CLEANUP_THRESHOLD = 200;
  59 	
  60 	public final static String INJECTOR_NAME = AutohitProperties.COMMAND_SERVER_INJECTOR + ".HttpCommandService";
  61 
  62 	/**
  63 	 *  accept port */
  64 	ServerSocket listen;
  65 
  66 	/**
  67 	 *  active ports */
  68 	HashSet active;
  69 	
  70 	/**
  71 	 *  Channel stuff 
  72 	 *  */
  73 	private Channel commandChannel;
  74 	private Injector commandInjector;
  75 	private SimTextCommand commander;
  76 
  77 
  78 	/**
  79 	 *  Default constructor */
  80 	public HttpCommandService() {
  81 		super();
  82 	}
  83 
  84 	/**
  85 	 * Complete construction. This will be called when the VM is initialized. */
  86 	public void construct() throws ServiceException {
  87 
  88 		try {
  89 			
  90 			// How are we confiugred
  91 			int port = AutohitProperties.default_HTTPCOMMAND_SERVER_PORT;
  92 			String portString =
  93 				(String) Utils.testGetProperty(
  94 					AutohitProperties.SERVICE_HTTPCOMMAND_SERVER_PORT,
  95 					sc.getPropertiesSet());
  96 			if (portString != null) {
  97 				port = Integer.parseInt(portString);
  98 			} 
  99 			// Set up communication
 100 			listen = new ServerSocket(port);
 101 			active = new HashSet();
 102 			
 103 			// command interface
 104 			commandInjector = new SimpleInjector();
 105 			commandChannel = Controller.tune(AutohitProperties.COMMAND_SERVER_STATION);
 106 			commandChannel.register(INJECTOR_NAME, commandInjector);
 107 			
 108 			commander = new SimTextCommand();
 109 			commander.init(sc);
 110 	
 111 		} catch (NumberFormatException nee) {
 112 			throw new ServiceException(
 113 				"Failed constructing HttpCommandService.  Bad value for property " +
 114 				AutohitProperties.SERVICE_HTTPCOMMAND_SERVER_PORT + ". message=" + nee.getMessage(),
 115 				ServiceException.CODE_SERVICE_STARTUP_FAULT);
 116 				
 117 		} catch (Exception ee) {
 118 			throw new ServiceException(
 119 				"Failed constructing HttpCommandService.  message=" + ee.getMessage(),
 120 				ServiceException.CODE_SERVICE_STARTUP_FAULT);
 121 		}
 122 
 123 	}
 124 
 125 	/**
 126 	 * Fast loop. We spend most of our time waiting for connections. Cycle back
 127 	 * to VM only after an accept or a timeout.
 128 	 * 
 129 	 * @see autohit.vm.VMException
 130 	 */
 131 	public void execute() throws ServiceException {
 132 
 133 		Socket accepted;
 134 
 135 		// Try to accept
 136 		try {
 137 
 138 			// Do we need to clean the active set?
 139 			if (active.size() > CLEANUP_THRESHOLD) {
 140 				this.cleanActive();
 141 			}
 142 
 143 			// ACCEPT
 144 			listen.setSoTimeout(ACCEPT_TIMEOUT);
 145 			accepted = listen.accept();
 146 			myLog.debug("HttpCommandService:Accepted a connection.", AutohitErrorCodes.CODE_DEBUGGING_SERVICES);
 147 
 148 			// Build helper
 149 			HttpCommandHelper srh = new HttpCommandHelper();
 150 			srh.init(accepted, myLog, commandInjector, commander, this);
 151 			myLog.debug(
 152 				"HttpCommandService:Relay helper initialized.",
 153 				AutohitErrorCodes.CODE_DEBUGGING_SERVICES);
 154 
 155 			// dispatch
 156 			srh.start();
 157 			active.add(srh);
 158 			myLog.debug("HttpCommandService:Relay helper dispatched.", AutohitErrorCodes.CODE_DEBUGGING_SERVICES);
 159 
 160 		} catch (SocketTimeoutException ste) {
 161 			// This is ok. See if we are dead.
 162 			if (this.getState() < HttpCommandService.STATE_ACTIVE_THRESHOLD) 
 163 				throw new ServiceException(
 164 						"HttpCommandService ordered to stop.",
 165 						ServiceException.CODE_SERVICE_INTENTIONAL_HALT);
 166 
 167 		} catch (Exception ee) {
 168 			throw new ServiceException(
 169 				"Fault in HttpCommandService.  message=" + ee.getMessage(),
 170 				ServiceException.CODE_SERVICE_GENERAL_FAULT);
 171 		}
 172 	}
 173 
 174 	/**
 175 	 * Helper */
 176 	private void cleanActive() throws Exception {
 177 
 178 		Iterator i = active.iterator();
 179 
 180 		while (i.hasNext()) {
 181 			HttpCommandHelper srh = (HttpCommandHelper) i.next();
 182 			if (!srh.isAlive())
 183 				active.remove(srh);
 184 		}
 185 	}
 186 
 187 	/**
 188 	 * Complete destroy. This will be called when the VM is finalizing. */
 189 	public void destruct() throws ServiceException {
 190 
 191 		Iterator i = active.iterator();
 192 
 193 		while (i.hasNext()) {
 194 			HttpCommandHelper srh = (HttpCommandHelper) i.next();
 195 			active.remove(srh);
 196 			if (srh.isAlive()) {
 197 				try {
 198 					srh.interrupt();
 199 				} catch (Exception eee) { // dont care
 200 				}
 201 			}
 202 		} // end while
 203 
 204 	} // end destruct
 205 
 206 }