001 /* 002 * Copyright 2010 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package com.hs.mail.container.server; 017 018 import java.io.IOException; 019 import java.net.InetAddress; 020 import java.net.ServerSocket; 021 import java.net.Socket; 022 023 import org.apache.commons.io.IOUtils; 024 import org.apache.commons.lang.StringUtils; 025 import org.apache.log4j.Logger; 026 import org.springframework.core.task.TaskExecutor; 027 028 import com.hs.mail.container.server.socket.ServerSocketFactory; 029 import com.hs.mail.container.server.socket.SocketConnection; 030 031 /** 032 * 033 * @author Won Chul Doh 034 * @since May 3, 2010 035 * 036 */ 037 public class DefaultServer implements Server { 038 039 static Logger logger = Logger.getLogger(DefaultServer.class); 040 041 /** 042 * The port on which this server will be made available. 043 */ 044 protected int port = -1; 045 046 /** 047 * The host name of bindTo address. 048 */ 049 protected String bind = null; 050 051 /** 052 * Network interface to which the service will bind. If not set, the server 053 * binds to all available interfaces. 054 */ 055 protected InetAddress bindTo = null; 056 057 /** 058 * The connection backlog. 059 */ 060 protected int backlog = -1; 061 062 /** 063 * The connection idle timeout. Used primarily to prevent server problems 064 * from hanging a connection. 065 */ 066 protected int connectionTimeout = 0; 067 068 /** 069 * Indicates whether or not TCP_NODELAY is enabled. 070 */ 071 protected boolean tcpNoDelay = true; 072 073 /** 074 * Factory creating server sockets. 075 */ 076 protected ServerSocketFactory serverSocketFactory = null; 077 078 /** 079 * The connection handler used by this service. 080 */ 081 protected ConnectionHandler connectionHandler = null; 082 083 private TaskExecutor taskExecutor = null; 084 085 private MainSocketThread mainThread = null; 086 087 public int getPort() { 088 return port; 089 } 090 091 public void setPort(int port) { 092 this.port = port; 093 } 094 095 public String getBind() { 096 return bind; 097 } 098 099 public void setBind(String bind) { 100 this.bind = bind; 101 } 102 103 public InetAddress getBindTo() { 104 return bindTo; 105 } 106 107 public void setBindTo(InetAddress bindTo) { 108 this.bindTo = bindTo; 109 } 110 111 public int getBacklog() { 112 return backlog; 113 } 114 115 public void setBacklog(int backlog) { 116 this.backlog = backlog; 117 } 118 119 public int getConnectionTimeout() { 120 return connectionTimeout; 121 } 122 123 public void setConnectionTimeout(int connectionTimeout) { 124 this.connectionTimeout = connectionTimeout; 125 } 126 127 public boolean isTcpNoDelay() { 128 return tcpNoDelay; 129 } 130 131 public void setTcpNoDelay(boolean tcpNoDelay) { 132 this.tcpNoDelay = tcpNoDelay; 133 } 134 135 public ServerSocketFactory getServerSocketFactory() { 136 return serverSocketFactory; 137 } 138 139 public void setServerSocketFactory(ServerSocketFactory factory) { 140 this.serverSocketFactory = factory; 141 } 142 143 public ConnectionHandler getConnectionHandler() { 144 return connectionHandler; 145 } 146 147 public void setConnectionHandler(ConnectionHandler connectionHandler) { 148 this.connectionHandler = connectionHandler; 149 } 150 151 public TaskExecutor getTaskExecutor() { 152 return taskExecutor; 153 } 154 155 public void setTaskExecutor(TaskExecutor taskExecutor) { 156 this.taskExecutor = taskExecutor; 157 } 158 159 /** 160 * This method returns the type of service provided by this server. 161 * This should be invariant over the life of the class. 162 * 163 * Subclasses may override this implementation. This implementation 164 * parses the complete class name and returns the undecorated class 165 * name. 166 * 167 * @return description of this server 168 */ 169 public String getServiceType() { 170 String name = getClass().getName(); 171 int i = name.lastIndexOf("."); 172 if (i > 0 && i < name.length() - 2) { 173 name = name.substring(i + 1); 174 } 175 return name; 176 } 177 178 public void configure() throws Exception { 179 if (!StringUtils.isEmpty(bind) && !"*".equals(bind)) { 180 bindTo = InetAddress.getByName(bind); 181 } 182 } 183 184 public void start() { 185 mainThread = new MainSocketThread(); 186 mainThread.start(); 187 188 StringBuilder logBuffer = new StringBuilder(64) 189 .append(getServiceType()) 190 .append(" started on port ") 191 .append(port); 192 Logger.getLogger("console").info(logBuffer.toString()); 193 } 194 195 public void stop() { 196 mainThread.setCanContinue(false); 197 } 198 199 class MainSocketThread extends Thread { 200 201 protected boolean canContinue = true; 202 protected ServerSocket serverSocket = null; 203 204 public MainSocketThread() { 205 } 206 207 public synchronized void setCanContinue(boolean canContinue) { 208 this.canContinue = canContinue; 209 } 210 211 public void run() { 212 open(); 213 214 if (null == this.serverSocket) { 215 return; 216 } 217 218 while (this.canContinue) { 219 Socket soc = null; 220 221 try { 222 soc = this.serverSocket.accept(); 223 soc.setTcpNoDelay(tcpNoDelay); 224 soc.setSoTimeout(connectionTimeout); 225 226 SocketConnection sc = new SocketConnection(connectionHandler, soc); 227 228 try { 229 taskExecutor.execute(sc); 230 } catch (Exception e) { 231 if (logger.isDebugEnabled()) { 232 logger.error("Cannot add work into thread pool: " + e.getMessage(), e); 233 } else { 234 logger.error("Cannot add work into thread pool: " + e.getMessage()); 235 } 236 237 if (soc != null) { 238 try { 239 soc.close(); 240 } catch (Exception ce) { 241 } 242 } 243 } 244 } catch (IOException e) { 245 if (soc != null) { 246 try { 247 IOUtils.closeQuietly(soc.getInputStream ()); 248 IOUtils.closeQuietly(soc.getOutputStream()); 249 soc.close(); 250 } catch (IOException ae) { 251 } 252 soc = null; 253 } 254 255 if (logger.isDebugEnabled()) { 256 logger.warn("IOException occurred: " + e.getMessage(), e); 257 } else { 258 logger.warn("IOException occurred: " + e.getMessage()); 259 } 260 261 try { 262 synchronized (this) { 263 if (this.canContinue) { 264 if (logger.isInfoEnabled()) { 265 logger.info("Will reopen server socket."); 266 } 267 this.serverSocket.close(); 268 open(); 269 } 270 } 271 } catch (Exception oe) { 272 if (logger.isDebugEnabled()) { 273 logger.error("Cannot reopen server socket: " + oe.getMessage(), oe); 274 } else { 275 logger.error("Cannot reopen server socket: " + oe.getMessage()); 276 } 277 break; 278 } 279 } 280 } 281 } 282 283 protected void open() { 284 if (null != bindTo) { 285 try { 286 this.serverSocket = serverSocketFactory.createServerSocket(port, backlog, bindTo); 287 } catch (IOException e) { 288 try { 289 if (backlog > 0) { 290 this.serverSocket = serverSocketFactory.createServerSocket(port, backlog); 291 } else { 292 this.serverSocket = serverSocketFactory.createServerSocket(port); 293 } 294 } catch (IOException ae) { 295 if (logger.isDebugEnabled()) { 296 logger.error("Cannot open server socket (" + port + "," + backlog + "):" + e.getMessage(), e); 297 } else { 298 logger.error("Cannot open server socket (" + port + "," + backlog + "):" + e.getMessage()); 299 } 300 } 301 } 302 } else { 303 try { 304 if (backlog > 0) { 305 this.serverSocket = serverSocketFactory.createServerSocket(port, backlog); 306 } else { 307 this.serverSocket = serverSocketFactory.createServerSocket(port); 308 } 309 } catch (IOException e) { 310 if (logger.isDebugEnabled()) { 311 logger.error("Cannot open server socket (" + port + "," + backlog + "):" + e.getMessage(), e); 312 } else { 313 logger.error("Cannot open server socket (" + port + "," + backlog + "):" + e.getMessage()); 314 } 315 } 316 } 317 } 318 } 319 320 }