d359e08b217f623ddde1749090aeefc2391deffd
1 package be
.nikiroo
.utils
.serial
.server
;
3 import java
.io
.IOException
;
4 import java
.io
.InputStream
;
5 import java
.io
.OutputStream
;
6 import java
.net
.Socket
;
8 import javax
.net
.ssl
.SSLException
;
10 import be
.nikiroo
.utils
.CryptUtils
;
11 import be
.nikiroo
.utils
.IOUtils
;
12 import be
.nikiroo
.utils
.StringUtils
;
13 import be
.nikiroo
.utils
.serial
.Exporter
;
14 import be
.nikiroo
.utils
.serial
.Importer
;
15 import be
.nikiroo
.utils
.streams
.BufferedOutputStream
;
16 import be
.nikiroo
.utils
.streams
.NextableInputStream
;
17 import be
.nikiroo
.utils
.streams
.NextableInputStreamStep
;
18 import be
.nikiroo
.utils
.streams
.ReplaceInputStream
;
19 import be
.nikiroo
.utils
.streams
.ReplaceOutputStream
;
22 * Base class used for the client/server basic handling.
24 * It represents a single action: a client is expected to only execute one
25 * action, while a server is expected to execute one action for each client
30 abstract class ConnectAction
{
32 private boolean server
;
34 private CryptUtils crypt
;
36 private Object lock
= new Object();
37 private NextableInputStream in
;
38 private BufferedOutputStream out
;
39 private boolean contentToSend
;
42 * Method that will be called when an action is performed on either the
43 * client or server this {@link ConnectAction} represent.
46 * in case of I/O error
48 abstract protected void action() throws Exception
;
51 * Handler called when an unexpected error occurs in the code.
54 * the exception that occurred, SSLException usually denotes a
57 abstract protected void onError(Exception e
);
60 * Create a new {@link ConnectAction}.
63 * the socket to bind to
65 * TRUE for a server action, FALSE for a client action (will
68 * an optional key to encrypt all the communications (if NULL,
69 * everything will be sent in clear text)
71 protected ConnectAction(Socket s
, boolean server
, String key
) {
75 crypt
= new CryptUtils(key
);
80 * The total amount of bytes received.
82 * @return the amount of bytes received
84 public long getBytesReceived() {
85 return in
.getBytesRead();
89 * The total amount of bytes sent.
91 * @return the amount of bytes sent
93 public long getBytesWritten() {
94 return out
.getBytesWritten();
98 * Actually start the process (this is synchronous).
100 public void connect() {
102 // TODO: assure that \b is never used, make sure \n usage is OK
103 in
= new NextableInputStream(s
.getInputStream(),
104 new NextableInputStreamStep('\b'));
107 out
= new BufferedOutputStream(s
.getOutputStream());
117 } catch (Exception e
) {
122 } catch (Exception e
) {
129 * Serialise and send the given object to the counter part (and, only for
130 * client, return the deserialised answer -- the server will always receive
136 * @return the answer (which can be NULL if no answer, or NULL for an answer
137 * which is NULL) if this action is a client, always NULL if it is a
140 * @throws IOException
141 * in case of I/O error
142 * @throws NoSuchFieldException
143 * if the serialised data contains information about a field
144 * which does actually not exist in the class we know of
145 * @throws NoSuchMethodException
146 * if a class described in the serialised data cannot be created
147 * because it is not compatible with this code
148 * @throws ClassNotFoundException
149 * if a class described in the serialised data cannot be found
151 protected Object
sendObject(Object data
) throws IOException
,
152 NoSuchFieldException
, NoSuchMethodException
, ClassNotFoundException
{
153 return send(out
, data
, false);
157 * Reserved for the server: flush the data to the client and retrieve its
160 * Also used internally for the client (only do something if there is
163 * Will only flush the data if there is contentToSend.
165 * @return the deserialised answer (which can actually be NULL)
167 * @throws IOException
168 * in case of I/O error
169 * @throws NoSuchFieldException
170 * if the serialised data contains information about a field
171 * which does actually not exist in the class we know of
172 * @throws NoSuchMethodException
173 * if a class described in the serialised data cannot be created
174 * because it is not compatible with this code
175 * @throws ClassNotFoundException
176 * if a class described in the serialised data cannot be found
177 * @throws java.lang.NullPointerException
178 * if the counter part has no data to send
180 protected Object
recObject() throws IOException
, NoSuchFieldException
,
181 NoSuchMethodException
, ClassNotFoundException
,
182 java
.lang
.NullPointerException
{
187 * Send the given string to the counter part (and, only for client, return
188 * the answer -- the server will always receive NULL).
191 * the data to send (we will add a line feed)
193 * @return the answer if this action is a client (without the added line
194 * feed), NULL if it is a server
196 * @throws IOException
197 * in case of I/O error
198 * @throws SSLException
199 * in case of crypt error
201 protected String
sendString(String line
) throws IOException
{
203 return (String
) send(out
, line
, true);
204 } catch (NoSuchFieldException e
) {
207 } catch (NoSuchMethodException e
) {
210 } catch (ClassNotFoundException e
) {
219 * Reserved for the server (externally): flush the data to the client and
220 * retrieve its answer.
222 * Also used internally for the client (only do something if there is
225 * Will only flush the data if there is contentToSend.
227 * @return the answer (which can be NULL if no more content)
229 * @throws IOException
230 * in case of I/O error
231 * @throws SSLException
232 * in case of crypt error
234 protected String
recString() throws IOException
{
236 return (String
) rec(true);
237 } catch (NoSuchFieldException e
) {
240 } catch (NoSuchMethodException e
) {
243 } catch (ClassNotFoundException e
) {
246 } catch (NullPointerException e
) {
255 * Serialise and send the given object to the counter part (and, only for
256 * client, return the deserialised answer -- the server will always receive
260 * the stream to write to
264 * TRUE to write it as a String, FALSE to write it as an Object
266 * @return the answer (which can be NULL if no answer, or NULL for an answer
267 * which is NULL) if this action is a client, always NULL if it is a
270 * @throws IOException
271 * in case of I/O error
272 * @throws SSLException
273 * in case of crypt error
274 * @throws IOException
275 * in case of I/O error
276 * @throws NoSuchFieldException
277 * if the serialised data contains information about a field
278 * which does actually not exist in the class we know of
279 * @throws NoSuchMethodException
280 * if a class described in the serialised data cannot be created
281 * because it is not compatible with this code
282 * @throws ClassNotFoundException
283 * if a class described in the serialised data cannot be found
285 private Object
send(BufferedOutputStream out
, Object data
, boolean asString
)
286 throws IOException
, NoSuchFieldException
, NoSuchMethodException
,
287 ClassNotFoundException
, java
.lang
.NullPointerException
{
289 synchronized (lock
) {
292 sub
= crypt
.encrypt64(out
.open());
297 // TODO: could be possible to check for non-crypt and only
299 sub
= new ReplaceOutputStream(sub
, //
300 new String
[] { "\\", "\b" }, //
301 new String
[] { "\\\\", "\\b" });
305 sub
.write(StringUtils
.getBytes(data
.toString()));
307 new Exporter(sub
).append(data
);
320 contentToSend
= true;
322 return rec(asString
);
323 } catch (NullPointerException e
) {
324 // We accept no data here for Objects
332 * Reserved for the server: flush the data to the client and retrieve its
335 * Also used internally for the client (only do something if there is
338 * Will only flush the data if there is contentToSend.
340 * Note that the behaviour is slightly different for String and Object
341 * reading regarding exceptions:
343 * <li>NULL means that the counter part has no more data to send</li>
344 * <li>All the exceptions except {@link IOException} are there for Object
349 * TRUE for String reading, FALSE for Object reading (which can
352 * @return the deserialised answer (which can actually be NULL)
354 * @throws IOException
355 * in case of I/O error
356 * @throws NoSuchFieldException
357 * if the serialised data contains information about a field
358 * which does actually not exist in the class we know of
359 * @throws NoSuchMethodException
360 * if a class described in the serialised data cannot be created
361 * because it is not compatible with this code
362 * @throws ClassNotFoundException
363 * if a class described in the serialised data cannot be found
364 * @throws java.lang.NullPointerException
365 * for Objects only: if the counter part has no data to send
367 @SuppressWarnings("resource")
368 private Object
rec(boolean asString
) throws IOException
,
369 NoSuchFieldException
, NoSuchMethodException
,
370 ClassNotFoundException
, java
.lang
.NullPointerException
{
372 synchronized (lock
) {
373 if (server
|| contentToSend
) {
376 contentToSend
= false;
379 if (in
.next() && !in
.eof()) {
380 // TODO: could be possible to check for non-crypt and only
382 InputStream read
= new ReplaceInputStream(in
.open(), //
383 new String
[] { "\\\\", "\\b" }, //
384 new String
[] { "\\", "\b" });
388 read
= crypt
.decrypt64(read
);
392 return IOUtils
.readSmallStream(read
);
395 return new Importer().read(read
).getValue();
402 throw new NullPointerException();