Server.java

1
package com.renomad.minum.web;
2
3
import com.renomad.minum.state.Constants;
4
import com.renomad.minum.logging.ILogger;
5
import com.renomad.minum.security.ITheBrig;
6
import com.renomad.minum.state.Context;
7
import com.renomad.minum.utils.ConcurrentSet;
8
import com.renomad.minum.utils.StacktraceUtils;
9
import com.renomad.minum.utils.ThrowingRunnable;
10
11
import java.io.IOException;
12
import java.net.ServerSocket;
13
import java.net.Socket;
14
import java.util.concurrent.ExecutorService;
15
import java.util.concurrent.Future;
16
17
/**
18
 * The purpose here is to make it marginally easier to
19
 * work with a ServerSocket.
20
 * <p>
21
 * First, instantiate this class using a running serverSocket
22
 * Then, by running the start method, we gain access to
23
 * the server's socket.  This way we can easily test / control
24
 * the server side but also tie it in with an ExecutorService
25
 * for controlling lots of server threads.
26
 */
27
final class Server implements IServer {
28
    private final ServerSocket serverSocket;
29
    private final SetOfSws setOfSWs;
30
    private final ExecutorService es;
31
    private final HttpServerType serverType;
32
    private final ILogger logger;
33
    private final String serverName;
34
    private final ITheBrig theBrig;
35
    private final Constants constants;
36
    private final WebFramework webFramework;
37
38
    /**
39
     * This is the future returned when we submitted the
40
     * thread for the central server loop to the ExecutorService
41
     */
42
    private Future<?> centralLoopFuture;
43
44
    Server(ServerSocket ss, Context context, String serverName, ITheBrig theBrig, WebFramework webFramework, ExecutorService es, HttpServerType serverType) {
45
        this.serverSocket = ss;
46
        this.logger = context.getLogger();
47
        this.constants = context.getConstants();
48
        this.webFramework = webFramework;
49
        this.serverName = serverName;
50
        this.theBrig = theBrig;
51
        setOfSWs = new SetOfSws(new ConcurrentSet<>(), logger, serverName);
52
        this.es = es;
53
        this.serverType = serverType;
54
    }
55
56
    @Override
57
    public void start() {
58
        ThrowingRunnable serverCode = buildMainServerLoop(es);
59
        Runnable t = ThrowingRunnable.throwingRunnableWrapper(serverCode, logger);
60
        this.centralLoopFuture = es.submit(t);
61
    }
62
63
    /**
64
     * This code is the innermost loop of the server, waiting for incoming
65
     * connections and then delegating their handling off to a handler.
66
     *
67
     * @param es         The ExecutorService helping us with the threads
68
     */
69
    private ThrowingRunnable buildMainServerLoop(ExecutorService es) {
70 1 1. buildMainServerLoop : replaced return value with null for com/renomad/minum/web/Server::buildMainServerLoop → KILLED
        return () -> {
71
            Thread.currentThread().setName("Main Server");
72
            try {
73
                // yes, this infinite loop can only exit by an exception.  But this is
74
                // the beating heart of a server, and to the best of my current knowledge,
75
                // when a server socket is force-closed it's going to throw an exception, and
76
                // that's just part of its life cycle
77
                //noinspection InfiniteLoopStatement
78
                while (true) {
79
                    logger.logTrace(() -> serverName + " waiting to accept connection");
80
                    Socket freshSocket = serverSocket.accept();
81
                    ISocketWrapper sw = new SocketWrapper(freshSocket, this, logger, constants.socketTimeoutMillis, constants.hostName);
82
                    logger.logTrace(() -> String.format("client connected from %s", sw.getRemoteAddrWithPort()));
83 1 1. lambda$buildMainServerLoop$2 : removed call to com/renomad/minum/web/SetOfSws::add → TIMED_OUT
                    setOfSWs.add(sw);
84
                    ThrowingRunnable innerServerCode = this.webFramework.makePrimaryHttpHandler(sw, theBrig);
85
                    Runnable task = ThrowingRunnable.throwingRunnableWrapper(innerServerCode, logger);
86
                    es.submit(task);
87
                }
88
            } catch (IOException ex) {
89 1 1. lambda$buildMainServerLoop$2 : removed call to com/renomad/minum/web/Server::handleServerException → TIMED_OUT
                handleServerException(ex, logger);
90
            }
91
        };
92
    }
93
94
    static void handleServerException(IOException ex, ILogger logger) {
95 2 1. handleServerException : negated conditional → KILLED
2. handleServerException : negated conditional → KILLED
        if (!(ex.getMessage().contains("Socket closed") || ex.getMessage().contains("Socket is closed"))) {
96
            logger.logAsyncError(() -> StacktraceUtils.stackTraceToString(ex));
97
        }
98
    }
99
100
    @Override
101
    public void close() throws IOException {
102
        // close all the running sockets
103 1 1. close : removed call to com/renomad/minum/web/SetOfSws::stopAllServers → TIMED_OUT
        setOfSWs.stopAllServers();
104
        logger.logTrace(() -> "close called on " + this);
105
        // close the primary server socket
106 1 1. close : removed call to java/net/ServerSocket::close → TIMED_OUT
        serverSocket.close();
107
    }
108
109
    @Override
110
    public String getHost() {
111 1 1. getHost : replaced return value with "" for com/renomad/minum/web/Server::getHost → TIMED_OUT
        return serverSocket.getInetAddress().getHostAddress();
112
    }
113
114
    @Override
115
    public int getPort() {
116 1 1. getPort : replaced int return with 0 for com/renomad/minum/web/Server::getPort → KILLED
        return serverSocket.getLocalPort();
117
    }
118
119
    @Override
120
    public void removeMyRecord(ISocketWrapper socketWrapper) {
121 1 1. removeMyRecord : removed call to com/renomad/minum/web/SetOfSws::remove → KILLED
        setOfSWs.remove(socketWrapper);
122
    }
123
124
    /**
125
     * Returns the name of this server, which is set
126
     * when the server is instantiated.
127
     */
128
    @Override
129
    public String toString() {
130 1 1. toString : replaced return value with "" for com/renomad/minum/web/Server::toString → TIMED_OUT
        return this.serverName;
131
    }
132
133
    @Override
134
    public Future<?> getCentralLoopFuture() {
135 1 1. getCentralLoopFuture : replaced return value with null for com/renomad/minum/web/Server::getCentralLoopFuture → KILLED
        return centralLoopFuture;
136
    }
137
138
    @Override
139
    public HttpServerType getServerType() {
140 1 1. getServerType : replaced return value with null for com/renomad/minum/web/Server::getServerType → KILLED
        return serverType;
141
    }
142
}

Mutations

70

1.1
Location : buildMainServerLoop
Killed by : com.renomad.minum.web.FullSystemTests.testFullSystem_EdgeCase_InstantlyClosed(com.renomad.minum.web.FullSystemTests)
replaced return value with null for com/renomad/minum/web/Server::buildMainServerLoop → KILLED

83

1.1
Location : lambda$buildMainServerLoop$2
Killed by : none
removed call to com/renomad/minum/web/SetOfSws::add → TIMED_OUT

89

1.1
Location : lambda$buildMainServerLoop$2
Killed by : none
removed call to com/renomad/minum/web/Server::handleServerException → TIMED_OUT

95

1.1
Location : handleServerException
Killed by : com.renomad.minum.web.FullSystemTests.testFullSystem_EdgeCase_InstantlyClosed(com.renomad.minum.web.FullSystemTests)
negated conditional → KILLED

2.2
Location : handleServerException
Killed by : com.renomad.minum.web.ServerTests
negated conditional → KILLED

103

1.1
Location : close
Killed by : none
removed call to com/renomad/minum/web/SetOfSws::stopAllServers → TIMED_OUT

106

1.1
Location : close
Killed by : none
removed call to java/net/ServerSocket::close → TIMED_OUT

111

1.1
Location : getHost
Killed by : none
replaced return value with "" for com/renomad/minum/web/Server::getHost → TIMED_OUT

116

1.1
Location : getPort
Killed by : com.renomad.minum.web.FullSystemTests.testFullSystem_EdgeCase_InstantlyClosed(com.renomad.minum.web.FullSystemTests)
replaced int return with 0 for com/renomad/minum/web/Server::getPort → KILLED

121

1.1
Location : removeMyRecord
Killed by : com.renomad.minum.FunctionalTests
removed call to com/renomad/minum/web/SetOfSws::remove → KILLED

130

1.1
Location : toString
Killed by : none
replaced return value with "" for com/renomad/minum/web/Server::toString → TIMED_OUT

135

1.1
Location : getCentralLoopFuture
Killed by : com.renomad.minum.web.FullSystemTests.testFullSystem_WithRedirect(com.renomad.minum.web.FullSystemTests)
replaced return value with null for com/renomad/minum/web/Server::getCentralLoopFuture → KILLED

140

1.1
Location : getServerType
Killed by : com.renomad.minum.FunctionalTests
replaced return value with null for com/renomad/minum/web/Server::getServerType → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0