/* * Copyright 2013 Cloud4SOA, www.cloud4soa.eu * * 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. */ /* * Copyright 2009-2012 the original author or authors. * * 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 org.cloudfoundry.caldecott.client; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.cloudfoundry.caldecott.TunnelException; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.concurrent.ExecutorConfigurationSupport; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; /** * A class responsible for starting and stopping the TunnelAcceptor based on the configuration options. * * @author Thomas Risberg */ public class TunnelServer { protected final Log logger = LogFactory.getLog(getClass()); // configuration options private final InetSocketAddress local; private final TunnelFactory tunnelFactory; private final TaskExecutor taskExecutor; // variables to keep state for server private final ServerSocket serverSocket; private TunnelAcceptor acceptor; public TunnelServer(InetSocketAddress local, TunnelFactory tunnelFactory) { this(local, tunnelFactory, getDefaultThreadExecutor()); } public TunnelServer(InetSocketAddress local, TunnelFactory tunnelFactory, TaskExecutor taskExecutor) { this.local = local; this.tunnelFactory = tunnelFactory; this.taskExecutor = taskExecutor; try { this.serverSocket = new ServerSocket(); serverSocket.setReuseAddress(true); serverSocket.bind(local); } catch (IOException e) { throw new TunnelException("Error configuring server socket", e); } } public void start() { logger.info("Starting server on " + local); initializeTaskExecutor(taskExecutor); synchronized (this) { if (acceptor == null) { this.acceptor = new TunnelAcceptor(serverSocket, tunnelFactory, taskExecutor); acceptor.start(); } else { throw new TunnelException("Server already running."); } } } public void stop() { logger.info("Stopping server on " + local); synchronized (this) { shutdownTaskExecutor(taskExecutor); if (acceptor != null) { acceptor.stop(); if (acceptor.isActive()) { logger.info("Server is actively servicing connections, waiting for client to close"); while (acceptor.isActive()) { try { Thread.sleep(1000); } catch (InterruptedException ignore) {} } } try { serverSocket.close(); } catch (IOException e) { logger.warn("Error while closing server socket" + e.getMessage()); } logger.info("Server on " + local + " is now stopped"); } else { throw new TunnelException("Server is not running."); } } } protected static void initializeTaskExecutor(TaskExecutor taskExecutor) { if (taskExecutor instanceof ExecutorConfigurationSupport) { ((ExecutorConfigurationSupport)taskExecutor).initialize(); } } protected static void shutdownTaskExecutor(TaskExecutor taskExecutor) { if (taskExecutor instanceof ExecutorConfigurationSupport) { ((ExecutorConfigurationSupport)taskExecutor).shutdown(); } } protected static TaskExecutor getDefaultThreadExecutor() { ThreadPoolTaskExecutor te = new ThreadPoolTaskExecutor(); te.setCorePoolSize(5); te.setMaxPoolSize(10); te.setQueueCapacity(100); return te; } }