cef10adf1c80736a4603c8d99c1fe4c82710d480
1 package be
.nikiroo
.utils
.serial
.server
;
3 import java
.io
.BufferedReader
;
4 import java
.io
.IOException
;
5 import java
.io
.InputStreamReader
;
6 import java
.io
.OutputStreamWriter
;
7 import java
.net
.Socket
;
9 import javax
.net
.ssl
.SSLException
;
11 import be
.nikiroo
.utils
.Version
;
12 import be
.nikiroo
.utils
.serial
.Exporter
;
13 import be
.nikiroo
.utils
.serial
.Importer
;
16 * Base class used for the client/server basic handling.
18 * It represents a single action: a client is expected to only execute one
19 * action, while a server is expected to execute one action for each client
24 abstract class ConnectAction
{
26 private boolean server
;
27 private Version version
;
28 private Version clientVersion
;
30 private Object lock
= new Object();
31 private BufferedReader in
;
32 private OutputStreamWriter out
;
33 private boolean contentToSend
;
35 private long bytesReceived
;
36 private long bytesSent
;
39 * Method that will be called when an action is performed on either the
40 * client or server this {@link ConnectAction} represent.
43 * the counter part version
46 * in case of I/O error
48 abstract protected void action(Version version
) throws Exception
;
51 * Method called when we negotiate the version with the client.
53 * Thus, it is only called on the server.
55 * Will return the actual server version by default.
57 * @param clientVersion
60 * @return the version to send to the client
62 abstract protected Version
negotiateVersion(Version clientVersion
);
65 * Handler called when an unexpected error occurs in the code.
68 * the exception that occurred
70 abstract protected void onError(Exception e
);
73 * Create a new {@link ConnectAction}.
76 * the socket to bind to
78 * TRUE for a server action, FALSE for a client action (will
81 * the version of this client-or-server
83 protected ConnectAction(Socket s
, boolean server
, Version version
) {
87 if (version
== null) {
88 this.version
= new Version();
90 this.version
= version
;
93 clientVersion
= new Version();
97 * The version of this client-or-server.
101 public Version
getVersion() {
106 * The total amount of bytes received.
108 * @return the amount of bytes received
110 public long getBytesReceived() {
111 return bytesReceived
;
115 * The total amount of bytes sent.
117 * @return the amount of bytes sent
119 public long getBytesSent() {
124 * Actually start the process (this is synchronous).
126 public void connect() {
128 in
= new BufferedReader(new InputStreamReader(s
.getInputStream(),
131 out
= new OutputStreamWriter(s
.getOutputStream(), "UTF-8");
134 String line
= in
.readLine();
135 if (line
!= null && line
.startsWith("VERSION ")) {
136 // "VERSION client-version" (VERSION 1.0.0)
137 Version clientVersion
= new Version(
138 line
.substring("VERSION ".length()));
139 this.clientVersion
= clientVersion
;
140 Version v
= negotiateVersion(clientVersion
);
145 sendString("VERSION " + v
.toString());
148 action(clientVersion
);
150 String v
= sendString("VERSION " + version
.toString());
151 if (v
!= null && v
.startsWith("VERSION ")) {
152 v
= v
.substring("VERSION ".length());
155 action(new Version(v
));
165 } catch (Exception e
) {
166 if (e
instanceof SSLException
) {
168 for (String cipher
: Server
.getAnonCiphers()) {
169 if (!ciphers
.isEmpty()) {
175 e
= new SSLException("SSL error (available SSL ciphers: "
183 } catch (Exception e
) {
190 * Serialise and send the given object to the counter part (and, only for
191 * client, return the deserialised answer -- the server will always receive
197 * @return the answer (which can be NULL) if this action is a client, always
198 * NULL if it is a server
200 * @throws IOException
201 * in case of I/O error
202 * @throws NoSuchFieldException
203 * if the serialised data contains information about a field
204 * which does actually not exist in the class we know of
205 * @throws NoSuchMethodException
206 * if a class described in the serialised data cannot be created
207 * because it is not compatible with this code
208 * @throws ClassNotFoundException
209 * if a class described in the serialised data cannot be found
211 protected Object
sendObject(Object data
) throws IOException
,
212 NoSuchFieldException
, NoSuchMethodException
, ClassNotFoundException
{
213 synchronized (lock
) {
214 String rep
= sendString(new Exporter().append(data
).toString(true,
217 return new Importer().read(rep
).getValue();
225 * Reserved for the server: flush the data to the client and retrieve its
228 * Also used internally for the client (only do something if there is
231 * Will only flush the data if there is contentToSend.
233 * @return the deserialised answer (which can actually be NULL)
235 * @throws IOException
236 * in case of I/O error
237 * @throws NoSuchFieldException
238 * if the serialised data contains information about a field
239 * which does actually not exist in the class we know of
240 * @throws NoSuchMethodException
241 * if a class described in the serialised data cannot be created
242 * because it is not compatible with this code
243 * @throws ClassNotFoundException
244 * if a class described in the serialised data cannot be found
245 * @throws java.lang.NullPointerException
246 * if the counter part has no data to send
248 protected Object
recObject() throws IOException
, NoSuchFieldException
,
249 NoSuchMethodException
, ClassNotFoundException
,
250 java
.lang
.NullPointerException
{
251 String str
= recString();
253 throw new NullPointerException("No more data available");
256 return new Importer().read(str
).getValue();
260 * Send the given string to the counter part (and, only for client, return
261 * the answer -- the server will always receive NULL).
264 * the data to send (we will add a line feed)
266 * @return the answer if this action is a client (without the added line
267 * feed), NULL if it is a server
269 * @throws IOException
270 * in case of I/O error
272 protected String
sendString(String line
) throws IOException
{
273 synchronized (lock
) {
276 bytesSent
+= line
.length() + 1;
283 contentToSend
= true;
289 * Reserved for the server (externally): flush the data to the client and
290 * retrieve its answer.
292 * Also used internally for the client (only do something if there is
295 * Will only flush the data if there is contentToSend.
297 * @return the answer (which can be NULL)
299 * @throws IOException
300 * in case of I/O error
302 protected String
recString() throws IOException
{
303 synchronized (lock
) {
304 if (server
|| contentToSend
) {
307 contentToSend
= false;
310 String line
= in
.readLine();
312 bytesReceived
+= line
.length();