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