Version 3.1.0: ServerBridge
[nikiroo-utils.git] / src / be / nikiroo / utils / serial / server / ServerBridge.java
1 package be.nikiroo.utils.serial.server;
2
3 import java.io.IOException;
4 import java.net.Socket;
5
6 import be.nikiroo.utils.TraceHandler;
7 import be.nikiroo.utils.Version;
8 import be.nikiroo.utils.serial.Importer;
9
10 /**
11 * This class implements a simple server that can bridge two other
12 * {@link Server}s.
13 * <p>
14 * It can, of course, inspect the data that goes through it (by default, it
15 * prints traces of the data).
16 * <p>
17 * Note: this {@link ServerBridge} has to be discarded after use (cannot be
18 * started twice).
19 *
20 * @author niki
21 */
22 public class ServerBridge extends Server {
23 private final String forwardToHost;
24 private final int forwardToPort;
25 private final boolean forwardToSsl;
26
27 /**
28 * Create a new server that will start listening on the network when
29 * {@link ServerBridge#start()} is called.
30 *
31 * @param port
32 * the port to listen on, or 0 to assign any unallocated port
33 * found (which can later on be queried via
34 * {@link ServerBridge#getPort()}
35 * @param ssl
36 * use a SSL connection (or not)
37 *
38 * @throws IOException
39 * in case of I/O error
40 */
41 public ServerBridge(int port, boolean ssl, String forwardToHost,
42 int forwardToPort, boolean forwardToSsl) throws IOException {
43 super(port, ssl);
44 this.forwardToHost = forwardToHost;
45 this.forwardToPort = forwardToPort;
46 this.forwardToSsl = forwardToSsl;
47 }
48
49 /**
50 * Create a new server that will start listening on the network when
51 * {@link ServerBridge#start()} is called.
52 *
53 * @param name
54 * the server name (only used for debug info and traces)
55 * @param port
56 * the port to listen on
57 * @param ssl
58 * use a SSL connection (or not)
59 *
60 * @throws IOException
61 * in case of I/O error
62 */
63 public ServerBridge(String name, int port, boolean ssl,
64 String forwardToHost, int forwardToPort, boolean forwardToSsl)
65 throws IOException {
66 super(name, port, ssl);
67 this.forwardToHost = forwardToHost;
68 this.forwardToPort = forwardToPort;
69 this.forwardToSsl = forwardToSsl;
70 }
71
72 /**
73 * The traces handler for this {@link Server}.
74 * <p>
75 * <ul>
76 * <li>At level 1, it will only print basic IN/OUT messages with length.</li>
77 * <li>At level 2, it will also print the data as a String.</li>
78 * <li>At level 3, it will try to interpret it (SLOW) and print the object
79 * type if possible.</li>
80 * <li>At level 4, it will try to print the {@link Object#toString()} value.
81 * </li>
82 * </ul>
83 *
84 * @param tracer
85 * the new traces handler
86 */
87 @Override
88 public void setTraceHandler(TraceHandler tracer) {
89 super.setTraceHandler(tracer);
90 }
91
92 @Override
93 protected ConnectActionServer createConnectActionServer(Socket s) {
94 return new ConnectActionServerString(s) {
95 @Override
96 public void action(final Version clientVersion) throws Exception {
97 onClientContact(clientVersion);
98 final ConnectActionServerString bridge = this;
99
100 new ConnectActionClientString(forwardToHost, forwardToPort,
101 forwardToSsl, clientVersion) {
102 @Override
103 public void action(final Version serverVersion)
104 throws Exception {
105 onServerContact(serverVersion);
106
107 for (String fromClient = bridge.rec(); fromClient != null; fromClient = bridge
108 .rec()) {
109 onRec(clientVersion, fromClient);
110 String fromServer = send(fromClient);
111 onSend(serverVersion, fromServer);
112 bridge.send(fromServer);
113 }
114 }
115 }.connect();
116 }
117 };
118 }
119
120 /**
121 * This is the method that is called each time a client contact us.
122 *
123 * @param clientVersion
124 * the client version
125 * @param data
126 * the data sent by the client
127 */
128 protected void onClientContact(Version clientVersion) {
129 getTraceHandler().trace("CLIENT " + clientVersion);
130 }
131
132 /**
133 * This is the method that is called each time a client contact us.
134 *
135 * @param serverVersion
136 * the server version
137 * @param data
138 * the data sent by the client
139 */
140 protected void onServerContact(Version serverVersion) {
141 getTraceHandler().trace("SERVER " + serverVersion);
142 }
143
144 /**
145 * This is the method that is called each time a client contact us.
146 *
147 * @param clientVersion
148 * the client version
149 * @param data
150 * the data sent by the client
151 */
152 protected void onRec(Version clientVersion, String data) {
153 trace("<<< CLIENT (" + clientVersion + ")", data);
154 }
155
156 /**
157 * This is the method that is called each time the forwarded server contact
158 * us.
159 *
160 * @param serverVersion
161 * the client version
162 * @param data
163 * the data sent by the client
164 */
165 protected void onSend(Version serverVersion, String data) {
166 trace(">>> SERVER (" + serverVersion + ")", data);
167 }
168
169 /**
170 * Trace the data with the given prefix.
171 *
172 * @param prefix
173 * the prefix (client, server, version...)
174 * @param data
175 * the data to trace
176 */
177 private void trace(String prefix, String data) {
178 getTraceHandler().trace(prefix + ": " + data.length() + " characters",
179 1);
180
181 if (getTraceHandler().getTraceLevel() >= 2) {
182 try {
183 Object obj = new Importer().read(data).getValue();
184 if (obj == null) {
185 getTraceHandler().trace("NULL", 3);
186 getTraceHandler().trace("NULL", 4);
187 } else {
188 getTraceHandler().trace("(" + obj.getClass() + ")", 3);
189 getTraceHandler().trace("" + obj.toString(), 4);
190 }
191 } catch (Exception e) {
192 getTraceHandler().trace("(not an object)", 3);
193 getTraceHandler().trace(data, 4);
194 }
195
196 getTraceHandler().trace("", 4);
197 }
198 }
199
200 /**
201 * Start a bridge between 2 servers.
202 *
203 * @param args
204 * an array containing:
205 * <ul>
206 * <li>The bridge name</li>
207 * <li>The bridge port</li>
208 * <li>TRUE for a ssl bridge, FALSE for plain text</li>
209 * <li>The forward server host</li>
210 * <li>The forward server port</li>
211 * <li>TRUE for a ssl forward server, FALSE for plain text</li>
212 * <li>(optional) a trace level</li>
213 * </ul>
214 */
215 public static void main(String[] args) {
216 final TraceHandler tracer = new TraceHandler(true, false, 0);
217 try {
218 if (args.length < 6) {
219 tracer.error("Invalid syntax.\n"
220 + "Syntax: [name] [port] [ssl] [fhost] [fport] [fssl] ([trace level])\n"
221 + "\tname: the bridge name\n"
222 + "\tport: the bridge port\n"
223 + "\tssl: TRUE for an SSL bridge, FALSE for plain text\n"
224 + "\tfhost: the forward server host\n"
225 + "\tfport: the forward server port\n"
226 + "\tfssl: TRUE for an SSL forward server, FALSE for plain text\n"
227 + "\ttrace level: the optional trace level (default is 1)\n");
228 return;
229 }
230
231 int i = 0;
232 String name = args[i++];
233 int port = Integer.parseInt(args[i++]);
234 boolean ssl = Boolean.parseBoolean(args[i++]);
235 String fhost = args[i++];
236 int fport = Integer.parseInt(args[i++]);
237 boolean fssl = Boolean.parseBoolean(args[i++]);
238
239 int traceLevel = 1;
240 if (args.length > 6) {
241 traceLevel = Integer.parseInt(args[i++]);
242 }
243
244 ServerBridge bridge = new ServerBridge(name, port, ssl, fhost,
245 fport, fssl);
246 bridge.setTraceHandler(new TraceHandler(true, true, traceLevel));
247 bridge.run();
248 } catch (Exception e) {
249 tracer.error(e);
250 }
251 }
252 }