Fix Cache (URL to File could fail if no parent)
[nikiroo-utils.git] / src / be / nikiroo / utils / serial / server / ServerBridge.java
CommitLineData
8537d55a
NR
1package be.nikiroo.utils.serial.server;
2
3import java.io.IOException;
452f38c8 4import java.lang.reflect.Array;
8537d55a
NR
5import java.net.Socket;
6
452f38c8 7import be.nikiroo.utils.StringUtils;
8537d55a
NR
8import be.nikiroo.utils.TraceHandler;
9import be.nikiroo.utils.Version;
10import be.nikiroo.utils.serial.Importer;
11
12/**
13 * This class implements a simple server that can bridge two other
14 * {@link Server}s.
15 * <p>
16 * It can, of course, inspect the data that goes through it (by default, it
17 * prints traces of the data).
18 * <p>
19 * Note: this {@link ServerBridge} has to be discarded after use (cannot be
20 * started twice).
21 *
22 * @author niki
23 */
24public class ServerBridge extends Server {
25 private final String forwardToHost;
26 private final int forwardToPort;
27 private final boolean forwardToSsl;
28
29 /**
30 * Create a new server that will start listening on the network when
31 * {@link ServerBridge#start()} is called.
32 *
33 * @param port
34 * the port to listen on, or 0 to assign any unallocated port
35 * found (which can later on be queried via
36 * {@link ServerBridge#getPort()}
37 * @param ssl
452f38c8
NR
38 * use an SSL connection (or not)
39 * @param forwardToHost
40 * the host server to forward the calls to
41 * @param forwardToPort
42 * the host port to forward the calls to
43 * @param forwardToSsl
44 * use an SSL connection for the forward server or not
8537d55a
NR
45 *
46 * @throws IOException
47 * in case of I/O error
48 */
49 public ServerBridge(int port, boolean ssl, String forwardToHost,
50 int forwardToPort, boolean forwardToSsl) throws IOException {
51 super(port, ssl);
52 this.forwardToHost = forwardToHost;
53 this.forwardToPort = forwardToPort;
54 this.forwardToSsl = forwardToSsl;
55 }
56
57 /**
58 * Create a new server that will start listening on the network when
59 * {@link ServerBridge#start()} is called.
60 *
61 * @param name
62 * the server name (only used for debug info and traces)
63 * @param port
64 * the port to listen on
65 * @param ssl
452f38c8
NR
66 * use an SSL connection (or not)
67 * @param forwardToHost
68 * the host server to forward the calls to
69 * @param forwardToPort
70 * the host port to forward the calls to
71 * @param forwardToSsl
72 * use an SSL connection for the forward server or not
8537d55a
NR
73 *
74 * @throws IOException
75 * in case of I/O error
76 */
77 public ServerBridge(String name, int port, boolean ssl,
78 String forwardToHost, int forwardToPort, boolean forwardToSsl)
79 throws IOException {
80 super(name, port, ssl);
81 this.forwardToHost = forwardToHost;
82 this.forwardToPort = forwardToPort;
83 this.forwardToSsl = forwardToSsl;
84 }
85
86 /**
87 * The traces handler for this {@link Server}.
88 * <p>
452f38c8 89 * The trace levels are handled as follow:
8537d55a 90 * <ul>
452f38c8
NR
91 * <li>1: it will only print basic IN/OUT messages with length</li>
92 * <li>2: it will try to interpret it as an object (SLOW) and print the
93 * object class if possible</li>
94 * <li>3: it will try to print the {@link Object#toString()} value, or the
95 * data if it is not an object</li>
96 * <li>4: it will also print the unzipped serialised value if it is an
97 * object</li>
8537d55a
NR
98 * </ul>
99 *
100 * @param tracer
101 * the new traces handler
102 */
103 @Override
104 public void setTraceHandler(TraceHandler tracer) {
105 super.setTraceHandler(tracer);
106 }
107
108 @Override
109 protected ConnectActionServer createConnectActionServer(Socket s) {
110 return new ConnectActionServerString(s) {
111 @Override
112 public void action(final Version clientVersion) throws Exception {
113 onClientContact(clientVersion);
114 final ConnectActionServerString bridge = this;
115
116 new ConnectActionClientString(forwardToHost, forwardToPort,
117 forwardToSsl, clientVersion) {
118 @Override
119 public void action(final Version serverVersion)
120 throws Exception {
121 onServerContact(serverVersion);
122
123 for (String fromClient = bridge.rec(); fromClient != null; fromClient = bridge
124 .rec()) {
125 onRec(clientVersion, fromClient);
126 String fromServer = send(fromClient);
127 onSend(serverVersion, fromServer);
128 bridge.send(fromServer);
129 }
d827da2a
NR
130
131 getTraceHandler().trace("=== DONE", 1);
132 getTraceHandler().trace("", 1);
8537d55a 133 }
0ff71477
NR
134
135 @Override
136 protected void onError(Exception e) {
d827da2a 137 ServerBridge.this.onError(e);
0ff71477 138 }
8537d55a
NR
139 }.connect();
140 }
141 };
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
8537d55a
NR
149 */
150 protected void onClientContact(Version clientVersion) {
d827da2a 151 getTraceHandler().trace(">>> CLIENT " + clientVersion);
8537d55a
NR
152 }
153
154 /**
155 * This is the method that is called each time a client contact us.
156 *
157 * @param serverVersion
158 * the server version
8537d55a
NR
159 */
160 protected void onServerContact(Version serverVersion) {
d827da2a 161 getTraceHandler().trace("<<< SERVER " + serverVersion);
217a3310 162 getTraceHandler().trace("");
8537d55a
NR
163 }
164
165 /**
166 * This is the method that is called each time a client contact us.
167 *
168 * @param clientVersion
169 * the client version
170 * @param data
171 * the data sent by the client
172 */
173 protected void onRec(Version clientVersion, String data) {
d827da2a 174 trace(">>> CLIENT (" + clientVersion + ")", data);
8537d55a
NR
175 }
176
177 /**
178 * This is the method that is called each time the forwarded server contact
179 * us.
180 *
181 * @param serverVersion
182 * the client version
183 * @param data
184 * the data sent by the client
185 */
186 protected void onSend(Version serverVersion, String data) {
d827da2a 187 trace("<<< SERVER (" + serverVersion + ")", data);
8537d55a
NR
188 }
189
190 /**
191 * Trace the data with the given prefix.
192 *
193 * @param prefix
194 * the prefix (client, server, version...)
195 * @param data
196 * the data to trace
197 */
198 private void trace(String prefix, String data) {
452f38c8
NR
199 int size = data.length();
200 String ssize = size + " byte";
201 if (size > 1) {
202 ssize = size + " bytes";
203 if (size >= 1000) {
204 size = size / 1000;
205 ssize = size + " kb";
206 if (size > 1000) {
207 size = size / 1000;
208 ssize = size + " MB";
209 }
210 }
211 }
212
213 getTraceHandler().trace(prefix + ": " + ssize, 1);
8537d55a
NR
214
215 if (getTraceHandler().getTraceLevel() >= 2) {
216 try {
452f38c8
NR
217 if (data.startsWith("ZIP:")) {
218 data = StringUtils.unzip64(data.substring(4));
219 }
220
8537d55a
NR
221 Object obj = new Importer().read(data).getValue();
222 if (obj == null) {
452f38c8 223 getTraceHandler().trace("NULL", 2);
8537d55a
NR
224 getTraceHandler().trace("NULL", 3);
225 getTraceHandler().trace("NULL", 4);
226 } else {
452f38c8
NR
227 if (obj.getClass().isArray()) {
228 getTraceHandler().trace(
229 "(" + obj.getClass() + ") with "
230 + Array.getLength(obj) + "element(s)",
231 3);
232 } else {
233 getTraceHandler().trace("(" + obj.getClass() + ")", 2);
234 }
235 getTraceHandler().trace("" + obj.toString(), 3);
236 getTraceHandler().trace(data, 4);
8537d55a 237 }
452f38c8
NR
238 } catch (NoSuchMethodException e) {
239 getTraceHandler().trace("(not an object)", 2);
240 getTraceHandler().trace(data, 3);
241 getTraceHandler().trace("", 4);
242 } catch (NoSuchFieldException e) {
243 getTraceHandler().trace(
217a3310 244 "(incompatible: " + e.getMessage() + ")", 2);
452f38c8
NR
245 getTraceHandler().trace(data, 3);
246 getTraceHandler().trace("", 4);
247 } catch (ClassNotFoundException e) {
248 getTraceHandler().trace(
249 "(unknown object: " + e.getMessage() + ")", 2);
250 getTraceHandler().trace(data, 3);
251 getTraceHandler().trace("", 4);
8537d55a 252 } catch (Exception e) {
217a3310
NR
253 getTraceHandler().trace(
254 "(decode error: " + e.getMessage() + ")", 2);
452f38c8
NR
255 getTraceHandler().trace(data, 3);
256 getTraceHandler().trace("", 4);
8537d55a
NR
257 }
258
452f38c8 259 getTraceHandler().trace("", 2);
8537d55a
NR
260 }
261 }
262
263 /**
264 * Start a bridge between 2 servers.
265 *
266 * @param args
267 * an array containing:
268 * <ul>
269 * <li>The bridge name</li>
270 * <li>The bridge port</li>
452f38c8 271 * <li>TRUE for an SSL bridge, FALSE for plain text</li>
8537d55a
NR
272 * <li>The forward server host</li>
273 * <li>The forward server port</li>
452f38c8 274 * <li>TRUE for an SSL forward server, FALSE for plain text</li>
8537d55a 275 * <li>(optional) a trace level</li>
217a3310 276 * <li>(optional) a truncate size for data</li>
8537d55a
NR
277 * </ul>
278 */
279 public static void main(String[] args) {
280 final TraceHandler tracer = new TraceHandler(true, false, 0);
281 try {
282 if (args.length < 6) {
283 tracer.error("Invalid syntax.\n"
217a3310 284 + "Syntax: [name] [port] [ssl] [fhost] [fport] [fssl] ([trace level]) ([max])\n"
8537d55a
NR
285 + "\tname: the bridge name\n"
286 + "\tport: the bridge port\n"
287 + "\tssl: TRUE for an SSL bridge, FALSE for plain text\n"
288 + "\tfhost: the forward server host\n"
289 + "\tfport: the forward server port\n"
290 + "\tfssl: TRUE for an SSL forward server, FALSE for plain text\n"
217a3310
NR
291 + "\ttrace level: the optional trace level (default is 1)\n"
292 + "\tmax: the maximum size after which to truncate data\n");
8537d55a
NR
293 return;
294 }
295
296 int i = 0;
297 String name = args[i++];
298 int port = Integer.parseInt(args[i++]);
299 boolean ssl = Boolean.parseBoolean(args[i++]);
300 String fhost = args[i++];
301 int fport = Integer.parseInt(args[i++]);
302 boolean fssl = Boolean.parseBoolean(args[i++]);
303
304 int traceLevel = 1;
305 if (args.length > 6) {
306 traceLevel = Integer.parseInt(args[i++]);
307 }
217a3310
NR
308 int maxPrintSize = 1;
309 if (args.length > 7) {
310 maxPrintSize = Integer.parseInt(args[i++]);
311 }
8537d55a
NR
312
313 ServerBridge bridge = new ServerBridge(name, port, ssl, fhost,
314 fport, fssl);
217a3310
NR
315 bridge.setTraceHandler(new TraceHandler(true, true, traceLevel,
316 maxPrintSize));
8537d55a
NR
317 bridge.run();
318 } catch (Exception e) {
319 tracer.error(e);
320 }
321 }
322}