Package dtool.genie

Source Code of dtool.genie.AbstractSocketServer$ConnectionHandlerRunnable

/*******************************************************************************
* Copyright (c) 2014, 2014 Bruno Medeiros and other Contributors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     Bruno Medeiros - initial API and implementation
*******************************************************************************/
package dtool.genie;

import static melnorme.utilbox.core.Assert.AssertNamespace.assertFail;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;

import melnorme.utilbox.concurrency.SafeRunnable;
import dtool.genie.GenieServer.GenieConnectionHandler;
import dtool.util.StatusException;

/**
* Helper for Genie Server, manages a basic TCP socket server.
*/
public abstract class AbstractSocketServer {
 
  protected static final int MAX_CONNECTIONS = 256;
 
  protected final ServerSocket serverSocket;
  protected final int portNumber;
  protected final CountDownLatch terminationLatch = new CountDownLatch(1);
  protected final Semaphore connectionsSemaphore = new Semaphore(MAX_CONNECTIONS);
 
 
  public AbstractSocketServer(int portNumber) throws StatusException {
    this.serverSocket = createServerSocket(portNumber);
    this.portNumber = serverSocket.getLocalPort();
  }
 
  protected ServerSocket createServerSocket(int portNumber) throws StatusException {
    try {
      return new ServerSocket(portNumber);
    } catch (IOException ioe) {
      throw new StatusException("Error creating socket on port " + portNumber + ".", ioe);
    }
  }
 
  public int getServerPortNumber() {
    return portNumber;
  }
 
  public abstract void logMessage(String message);
  public abstract void logError(String message, Throwable throwable);
  public abstract void handleInternalError(Throwable throwable);
 
  public void runServer() {
    try {
      while(true) {
        Socket clientSocket = serverSocket.accept();
        logMessage("New connection from: " + clientSocket.getRemoteSocketAddress().toString());
        handleNewClientConnection(clientSocket);
      }
    } catch (SocketException se) {
      assertTrue(serverSocket.isClosed());
    } catch (IOException ioe) {
      logError("Unexpected exception during socket accept: " , ioe);
    } finally {
      closeServerSocket();
      logMessage("Server socket closed.");
      terminationLatch.countDown();
    }
  }
 
  protected void closeServerSocket() {
    try {
      logMessage("Closing server socket.");
      serverSocket.close();
    } catch (IOException e) {
      logError("Error trying to close socket: ", e);
    }
  }
 
  public int getActiveConnections() {
    return MAX_CONNECTIONS - connectionsSemaphore.availablePermits();
  }
 
  protected void handleNewClientConnection(Socket clientSocket) {
    connectionsSemaphore.acquireUninterruptibly();
    ConnectionHandlerRunnable genieConnectionHandler = createConnectionHandlerRunnable(clientSocket);
    createHandlerThread(genieConnectionHandler).start();
  }
 
  protected Thread createHandlerThread(ConnectionHandlerRunnable genieConnectionHandler) {
    return new Thread(genieConnectionHandler);
  }
 
  protected abstract GenieConnectionHandler createConnectionHandlerRunnable(Socket clientSocket);
 
  public abstract class ConnectionHandlerRunnable extends SafeRunnable {
   
    protected final Socket clientSocket;
   
    public ConnectionHandlerRunnable(Socket clientSocket) {
      this.clientSocket = clientSocket;
    }
   
    @Override
    protected void handleUncaughtException(Throwable e) {
      handleInternalError(e);
      assertFail();
    }
   
    @Override
    protected void safeRun() {
      handleConnection();
    }
   
    public void handleConnection() {
      try {
        handleConnectionStream();
      } catch (IOException e) {
        logError("IO error during connection handling: ", e);
      } finally {
        logMessage("Closing client connection : " + clientSocket.getRemoteSocketAddress().toString());
        try {
          clientSocket.close();
        } catch (IOException e) {
          logError("Error trying to close client socket: ", e);
        }
        connectionsSemaphore.release();
      }
    }
   
    protected abstract void handleConnectionStream() throws IOException;
   
  }
 
}
TOP

Related Classes of dtool.genie.AbstractSocketServer$ConnectionHandlerRunnable

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.