1 package be
.nikiroo
.utils
.serial
.server
;
3 import java
.io
.IOException
;
4 import java
.lang
.reflect
.Array
;
5 import java
.net
.Socket
;
7 import be
.nikiroo
.utils
.StringUtils
;
8 import be
.nikiroo
.utils
.TraceHandler
;
9 import be
.nikiroo
.utils
.Version
;
10 import be
.nikiroo
.utils
.serial
.Importer
;
13 * This class implements a simple server that can bridge two other
16 * It can, of course, inspect the data that goes through it (by default, it
17 * prints traces of the data).
19 * Note: this {@link ServerBridge} has to be discarded after use (cannot be
24 public class ServerBridge
extends Server
{
25 private final String forwardToHost
;
26 private final int forwardToPort
;
27 private final boolean forwardToSsl
;
30 * Create a new server that will start listening on the network when
31 * {@link ServerBridge#start()} is called.
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()}
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
44 * use an SSL connection for the forward server or not
47 * in case of I/O error
49 public ServerBridge(int port
, boolean ssl
, String forwardToHost
,
50 int forwardToPort
, boolean forwardToSsl
) throws IOException
{
52 this.forwardToHost
= forwardToHost
;
53 this.forwardToPort
= forwardToPort
;
54 this.forwardToSsl
= forwardToSsl
;
58 * Create a new server that will start listening on the network when
59 * {@link ServerBridge#start()} is called.
62 * the server name (only used for debug info and traces)
64 * the port to listen on
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
72 * use an SSL connection for the forward server or not
75 * in case of I/O error
77 public ServerBridge(String name
, int port
, boolean ssl
,
78 String forwardToHost
, int forwardToPort
, boolean forwardToSsl
)
80 super(name
, port
, ssl
);
81 this.forwardToHost
= forwardToHost
;
82 this.forwardToPort
= forwardToPort
;
83 this.forwardToSsl
= forwardToSsl
;
87 * The traces handler for this {@link Server}.
89 * The trace levels are handled as follow:
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
101 * the new traces handler
104 public void setTraceHandler(TraceHandler tracer
) {
105 super.setTraceHandler(tracer
);
109 protected ConnectActionServer
createConnectActionServer(Socket s
) {
110 return new ConnectActionServerString(s
) {
112 public void action(final Version clientVersion
) throws Exception
{
113 onClientContact(clientVersion
);
114 final ConnectActionServerString bridge
= this;
116 new ConnectActionClientString(forwardToHost
, forwardToPort
,
117 forwardToSsl
, clientVersion
) {
119 public void action(final Version serverVersion
)
121 onServerContact(serverVersion
);
123 for (String fromClient
= bridge
.rec(); fromClient
!= null; fromClient
= bridge
125 onRec(clientVersion
, fromClient
);
126 String fromServer
= send(fromClient
);
127 onSend(serverVersion
, fromServer
);
128 bridge
.send(fromServer
);
131 getTraceHandler().trace("=== DONE", 1);
132 getTraceHandler().trace("", 1);
136 protected void onError(Exception e
) {
137 ServerBridge
.this.onError(e
);
145 * This is the method that is called each time a client contact us.
147 * @param clientVersion
150 protected void onClientContact(Version clientVersion
) {
151 getTraceHandler().trace(">>> CLIENT " + clientVersion
);
155 * This is the method that is called each time a client contact us.
157 * @param serverVersion
160 protected void onServerContact(Version serverVersion
) {
161 getTraceHandler().trace("<<< SERVER " + serverVersion
);
162 getTraceHandler().trace("");
166 * This is the method that is called each time a client contact us.
168 * @param clientVersion
171 * the data sent by the client
173 protected void onRec(Version clientVersion
, String data
) {
174 trace(">>> CLIENT (" + clientVersion
+ ")", data
);
178 * This is the method that is called each time the forwarded server contact
181 * @param serverVersion
184 * the data sent by the client
186 protected void onSend(Version serverVersion
, String data
) {
187 trace("<<< SERVER (" + serverVersion
+ ")", data
);
191 * Trace the data with the given prefix.
194 * the prefix (client, server, version...)
198 private void trace(String prefix
, String data
) {
199 int size
= data
.length();
200 String ssize
= size
+ " byte";
202 ssize
= size
+ " bytes";
205 ssize
= size
+ " kb";
208 ssize
= size
+ " MB";
213 getTraceHandler().trace(prefix
+ ": " + ssize
, 1);
215 if (getTraceHandler().getTraceLevel() >= 2) {
217 if (data
.startsWith("ZIP:")) {
218 data
= StringUtils
.unzip64(data
.substring(4));
221 Object obj
= new Importer().read(data
).getValue();
223 getTraceHandler().trace("NULL", 2);
224 getTraceHandler().trace("NULL", 3);
225 getTraceHandler().trace("NULL", 4);
227 if (obj
.getClass().isArray()) {
228 getTraceHandler().trace(
229 "(" + obj
.getClass() + ") with "
230 + Array
.getLength(obj
) + "element(s)",
233 getTraceHandler().trace("(" + obj
.getClass() + ")", 2);
235 getTraceHandler().trace("" + obj
.toString(), 3);
236 getTraceHandler().trace(data
, 4);
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(
244 "(incompatible: " + e
.getMessage() + ")", 2);
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);
252 } catch (Exception e
) {
253 getTraceHandler().trace(
254 "(decode error: " + e
.getMessage() + ")", 2);
255 getTraceHandler().trace(data
, 3);
256 getTraceHandler().trace("", 4);
259 getTraceHandler().trace("", 2);
264 * Start a bridge between 2 servers.
267 * an array containing:
269 * <li>The bridge name</li>
270 * <li>The bridge port</li>
271 * <li>TRUE for an SSL bridge, FALSE for plain text</li>
272 * <li>The forward server host</li>
273 * <li>The forward server port</li>
274 * <li>TRUE for an SSL forward server, FALSE for plain text</li>
275 * <li>(optional) a trace level</li>
276 * <li>(optional) a truncate size for data</li>
279 public static void main(String
[] args
) {
280 final TraceHandler tracer
= new TraceHandler(true, false, 0);
282 if (args
.length
< 6) {
283 tracer
.error("Invalid syntax.\n"
284 + "Syntax: [name] [port] [ssl] [fhost] [fport] [fssl] ([trace level]) ([max])\n"
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"
291 + "\ttrace level: the optional trace level (default is 1)\n"
292 + "\tmax: the maximum size after which to truncate data\n");
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
++]);
305 if (args
.length
> 6) {
306 traceLevel
= Integer
.parseInt(args
[i
++]);
308 int maxPrintSize
= 1;
309 if (args
.length
> 7) {
310 maxPrintSize
= Integer
.parseInt(args
[i
++]);
313 ServerBridge bridge
= new ServerBridge(name
, port
, ssl
, fhost
,
315 bridge
.setTraceHandler(new TraceHandler(true, true, traceLevel
,
318 } catch (Exception e
) {