All Downloads are FREE. Search and download functionalities are using the official Maven repository.

be.bagofwords.application.BaseServer Maven / Gradle / Ivy

package be.bagofwords.application;


import be.bagofwords.ui.UI;
import be.bagofwords.util.SafeThread;
import be.bagofwords.util.Utils;
import be.bagofwords.util.WrappedSocketConnection;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;

public abstract class BaseServer extends SafeThread {

    public static final String ENCODING = "UTF-8";
    public static final long LONG_ERROR = Long.MAX_VALUE;
    public static final long LONG_OK = Long.MAX_VALUE - 1;
    public static final long LONG_END = Long.MAX_VALUE - 2;

    private ServerSocket serverSocket;
    private final List runningRequestHandlers;
    private final int scpPort;
    private int totalNumberOfConnections;

    public BaseServer(String name, int port) {
        super(name, false);
        this.runningRequestHandlers = new ArrayList<>();
        this.scpPort = port;
        this.totalNumberOfConnections = 0;
        try {
            this.serverSocket = new ServerSocket(scpPort);
        } catch (IOException exp) {
            throw new RuntimeException("Failed to initialize server " + getName() + " on port " + scpPort, exp);
        }
    }

    protected abstract SocketRequestHandler createSocketRequestHandler(Socket socket) throws IOException;

    @Override
    protected void runInt() throws Exception {
        UI.write("Started server " + getName() + " on port " + scpPort);
        while (!serverSocket.isClosed() && !isTerminateRequested()) {
            try {
                SocketRequestHandler handler = createSocketRequestHandler(serverSocket.accept());
                if (handler != null) {
                    synchronized (runningRequestHandlers) {
                        runningRequestHandlers.add(handler);
                    }
                    handler.start();
                }
                totalNumberOfConnections++;
            } catch (IOException e) {
                if (!(e instanceof SocketException || isTerminateRequested())) {
                    UI.writeError(e);
                }
            }
        }
    }

    @Override
    public void doTerminate() {
        IOUtils.closeQuietly(serverSocket);
        //once a request handler is finished, it removes itself from the list of requestHandlers, so we just wait until this list is empty
        while (!runningRequestHandlers.isEmpty()) {
            synchronized (runningRequestHandlers) {
                for (SocketRequestHandler requestHandler : runningRequestHandlers) {
                    if (!requestHandler.isTerminateRequested()) {
                        requestHandler.terminate(); //we can not call terminateAndWaitForFinish() here since to finish the request handler needs access to the runningRequestHandlers list
                    }
                }
            }
            Utils.threadSleep(10);
        }
        UI.write("Server " + getName() + " has been terminated.");
    }

    public int getTotalNumberOfConnections() {
        return totalNumberOfConnections;
    }

    public List getRunningRequestHandlers() {
        return runningRequestHandlers;
    }

    public abstract class SocketRequestHandler extends SafeThread {

        protected WrappedSocketConnection connection;

        public SocketRequestHandler(WrappedSocketConnection connection) throws IOException {
            super(BaseServer.this.getName() + "RequestHandler", false);
            this.connection = connection;
        }

        protected abstract void reportUnexpectedError(Exception ex);

        @Override
        protected void runInt() {
            try {
                handleRequests();
            } catch (Exception ex) {
                if (isUnexpectedError(ex)) {
                    reportUnexpectedError(ex);
                }
            }
            IOUtils.closeQuietly(connection);
            synchronized (runningRequestHandlers) {
                runningRequestHandlers.remove(this);
            }
        }

        protected abstract void handleRequests() throws Exception;

        @Override
        public void doTerminate() {
            IOUtils.closeQuietly(connection);
        }

        protected boolean isUnexpectedError(Exception ex) {
            if (ex.getMessage() != null && ex.getMessage().contains("Connection reset")) {
                return false;
            }
            for (StackTraceElement el : ex.getStackTrace()) {
                if (el.getMethodName().equals("readNextAction")) {
                    return false;
                }
            }
            return true;
        }


        public abstract long getTotalNumberOfRequests();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy