1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.classic.net;
15
16 import java.io.IOException;
17 import java.net.ServerSocket;
18 import java.net.Socket;
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 import ch.qos.logback.classic.LoggerContext;
26 import ch.qos.logback.classic.joran.JoranConfigurator;
27 import ch.qos.logback.core.joran.spi.JoranException;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 public class SimpleSocketServer extends Thread {
48
49 Logger logger = LoggerFactory.getLogger(SimpleSocketServer.class);
50
51 private final int port;
52 private final LoggerContext lc;
53 private boolean closed = false;
54 private ServerSocket serverSocket;
55 private List<SocketNode> socketNodeList = new ArrayList<SocketNode>();
56
57 public static void main(String argv[]) throws Exception {
58 int port = -1;
59 if (argv.length == 2) {
60 port = parsePortNumber(argv[0]);
61 } else {
62 usage("Wrong number of arguments.");
63 }
64
65 String configFile = argv[1];
66 LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
67 configureLC(lc, configFile);
68
69 SimpleSocketServer sss = new SimpleSocketServer(lc, port);
70 sss.start();
71 }
72
73 public SimpleSocketServer(LoggerContext lc, int port) {
74 this.lc = lc;
75 this.port = port;
76 }
77
78 public void run() {
79 try {
80 logger.info("Listening on port " + port);
81 serverSocket = new ServerSocket(port);
82 while (!closed) {
83 logger.info("Waiting to accept a new client.");
84 signalAlmostReadiness();
85 Socket socket = serverSocket.accept();
86 logger.info("Connected to client at " + socket.getInetAddress());
87 logger.info("Starting new socket node.");
88 SocketNode newSocketNode = new SocketNode(this, socket, lc);
89 synchronized (socketNodeList) {
90 socketNodeList.add(newSocketNode);
91 }
92 new Thread(newSocketNode).start();
93 }
94 } catch (Exception e) {
95 if(closed) {
96 logger.info("Exception in run method for a closed server. This is normal.");
97 } else {
98 logger.error("Unexpected failure in run method", e);
99 }
100 }
101 }
102
103
104
105
106
107 void signalAlmostReadiness() {
108 synchronized(this) {
109 this.notifyAll();
110 }
111 }
112 public boolean isClosed() {
113 return closed;
114 }
115
116 public void close() {
117 closed = true;
118 if (serverSocket != null) {
119 try {
120 serverSocket.close();
121 } catch (IOException e) {
122 logger.error("Failed to close serverSocket", e);
123 } finally {
124 serverSocket = null;
125 }
126 }
127
128 synchronized (socketNodeList) {
129 for(SocketNode sn: socketNodeList) {
130 sn.close();
131 }
132 socketNodeList.clear();
133 }
134 }
135
136 public void socketNodeClosing(SocketNode sn) {
137 logger.debug("Removing {}", sn);
138
139
140
141
142 synchronized (socketNodeList) {
143 socketNodeList.remove(sn);
144 }
145 }
146 static void usage(String msg) {
147 System.err.println(msg);
148 System.err.println("Usage: java " + SimpleSocketServer.class.getName()
149 + " port configFile");
150 System.exit(1);
151 }
152
153 static int parsePortNumber(String portStr) {
154 try {
155 return Integer.parseInt(portStr);
156 } catch (java.lang.NumberFormatException e) {
157 e.printStackTrace();
158 usage("Could not interpret port number [" + portStr + "].");
159
160 return -1;
161 }
162 }
163
164 static public void configureLC(LoggerContext lc, String configFile)
165 throws JoranException {
166 JoranConfigurator configurator = new JoranConfigurator();
167 lc.reset();
168 configurator.setContext(lc);
169 configurator.doConfigure(configFile);
170 }
171 }