Skip to content

Commit e9ba668

Browse files
committed
The ready state of a websocket is now represented as an enum. Also did some cleanup.
1 parent da1d539 commit e9ba668

File tree

4 files changed

+44
-80
lines changed

4 files changed

+44
-80
lines changed

src/main/java/org/java_websocket/WebSocket.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,21 @@
77

88
import org.java_websocket.drafts.Draft;
99
import org.java_websocket.exceptions.InvalidDataException;
10-
import org.java_websocket.exceptions.InvalidHandshakeException;
1110
import org.java_websocket.framing.Framedata;
12-
import org.java_websocket.handshake.ClientHandshakeBuilder;
1311

1412
public abstract class WebSocket {
1513
public enum Role {
1614
CLIENT, SERVER
1715
}
1816

17+
public enum READYSTATE {
18+
NOTYETCONNECTED, CONNECTING, OPEN, CLOSING, CLOSED;
19+
}
20+
1921
public static int RCVBUF = 16384;
2022

2123
public static/*final*/boolean DEBUG = false; // must be final in the future in order to take advantage of VM optimization
2224

23-
public static final int READY_STATE_CONNECTING = 0;
24-
public static final int READY_STATE_OPEN = 1;
25-
public static final int READY_STATE_CLOSING = 2;
26-
public static final int READY_STATE_CLOSED = 3;
2725
/**
2826
* The default port of WebSockets, as defined in the spec. If the nullary
2927
* constructor is used, DEFAULT_PORT will be the port the WebSocketServer
@@ -71,8 +69,6 @@ public enum Role {
7169

7270
public abstract boolean hasBufferedData();
7371

74-
public abstract void startHandshake( ClientHandshakeBuilder handshakedata ) throws InvalidHandshakeException;
75-
7672
/**
7773
* @returns null when connections is closed
7874
* @see Socket#getRemoteSocketAddress()
@@ -91,8 +87,13 @@ public enum Role {
9187

9288
public abstract boolean isClosing();
9389

90+
/**
91+
* Returns true when no further frames may be submitted<br>
92+
* This happens before the socket connection is closed.
93+
*/
9494
public abstract boolean isFlushAndClose();
9595

96+
/** Returns whether the close handshake has been completed and the socket is closed. */
9697
public abstract boolean isClosed();
9798

9899
public abstract Draft getDraft();
@@ -104,5 +105,5 @@ public enum Role {
104105
*
105106
* @return Returns '0 = CONNECTING', '1 = OPEN', '2 = CLOSING' or '3 = CLOSED'
106107
*/
107-
public abstract int getReadyState();
108+
public abstract READYSTATE getReadyState();
108109
}

src/main/java/org/java_websocket/WebSocketImpl.java

Lines changed: 26 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public class WebSocketImpl extends WebSocket {
5555

5656
public SelectionKey key;
5757

58-
/* only used to optain the socket addresses*/
58+
/* only used to obtain the socket addresses*/
5959
public final Socket socket;
6060
/** the possibly wrapped channel object whose selection is controlled by {@link #key} */
6161
public ByteChannel channel;
@@ -69,25 +69,14 @@ public class WebSocketImpl extends WebSocket {
6969
public final BlockingQueue<ByteBuffer> inQueue;
7070

7171
/**
72-
* Helper variable ment to store the thread which ( exclusively ) triggers this objects decode method.
72+
* Helper variable meant to store the thread which ( exclusively ) triggers this objects decode method.
7373
**/
7474
public volatile WebSocketWorker workerThread; // TODO reset worker?
7575

76-
/**
77-
* Determines whether to receive data as part of the
78-
* handshake, or as part of text/data frame transmitted over the websocket.
79-
*/
80-
private volatile boolean handshakeComplete = false;
81-
/**
82-
* Determines whether we sent already a request to Close the connection or not.
83-
*/
84-
private volatile boolean closeHandshakeSubmitted = false;
85-
8676
/** When true no further frames may be submitted to be sent */
8777
private volatile boolean flushandclosestate = false;
8878

89-
/** When true the socket has been closed */
90-
private volatile boolean isclosed = false;
79+
private READYSTATE readystate = READYSTATE.NOTYETCONNECTED;
9180

9281
/**
9382
* The listener to notify of WebSocket events.
@@ -135,25 +124,22 @@ public WebSocketImpl( WebSocketListener listener , Draft draft , Socket sock ) {
135124
inQueue = new LinkedBlockingQueue<ByteBuffer>();
136125
this.wsl = listener;
137126
this.role = Role.CLIENT;
138-
this.draft = draft.copyInstance();
127+
if( draft != null )
128+
this.draft = draft.copyInstance();
139129
this.socket = sock;
140130
}
141131

142132
/**
143-
* Should be called when a Selector has a key that is writable for this
144-
* WebSocketImpl's SocketChannel connection.
145133
*
146-
* @throws IOException
147-
* When socket related I/O errors occur.
148134
*/
149-
public void decode( ByteBuffer socketBuffer ) throws IOException {
135+
public void decode( ByteBuffer socketBuffer ) {
150136
if( !socketBuffer.hasRemaining() || flushandclosestate )
151137
return;
152138

153139
if( DEBUG )
154140
System.out.println( "process(" + socketBuffer.remaining() + "): {" + ( socketBuffer.remaining() > 1000 ? "too big to display" : new String( socketBuffer.array(), socketBuffer.position(), socketBuffer.remaining() ) ) + "}" );
155141

156-
if( handshakeComplete ) {
142+
if( readystate == READYSTATE.OPEN ) {
157143
decodeFrames( socketBuffer );
158144
} else {
159145
if( decodeHandshake( socketBuffer ) ) {
@@ -167,7 +153,7 @@ public void decode( ByteBuffer socketBuffer ) throws IOException {
167153
* Returns whether the handshake phase has is completed.
168154
* In case of a broken handshake this will be never the case.
169155
**/
170-
private boolean decodeHandshake( ByteBuffer socketBufferNew ) throws IOException {
156+
private boolean decodeHandshake( ByteBuffer socketBufferNew ) {
171157
ByteBuffer socketBuffer;
172158
if( tmpHandshakeBytes == null ) {
173159
socketBuffer = socketBufferNew;
@@ -324,7 +310,7 @@ private void decodeFrames( ByteBuffer socketBuffer ) {
324310
code = cf.getCloseCode();
325311
reason = cf.getMessage();
326312
}
327-
if( closeHandshakeSubmitted ) {
313+
if( readystate == READYSTATE.CLOSING ) {
328314
// complete the close handshake by disconnecting
329315
closeConnection( code, reason, true );
330316
} else {
@@ -372,12 +358,12 @@ private void decodeFrames( ByteBuffer socketBuffer ) {
372358
}
373359

374360
private void close( int code, String message, boolean remote ) {
375-
if( !closeHandshakeSubmitted ) {
376-
if( handshakeComplete ) {
361+
if( readystate != READYSTATE.CLOSING && readystate != READYSTATE.CLOSED ) {
362+
if( readystate == READYSTATE.OPEN ) {
377363
if( code == CloseFrame.ABNORMAL_CLOSE ) {
378364
assert ( remote == false );
365+
readystate = READYSTATE.CLOSING;
379366
flushAndClose( code, message, false );
380-
closeHandshakeSubmitted = true;
381367
return;
382368
}
383369
if( draft.getCloseHandshakeType() != CloseHandshakeType.NONE ) {
@@ -404,7 +390,7 @@ private void close( int code, String message, boolean remote ) {
404390
}
405391
if( code == CloseFrame.PROTOCOL_ERROR )// this endpoint found a PROTOCOL_ERROR
406392
flushAndClose( code, message, remote );
407-
closeHandshakeSubmitted = true;
393+
readystate = READYSTATE.CLOSING;
408394
tmpHandshakeBytes = null;
409395
return;
410396
}
@@ -425,7 +411,7 @@ public void close( int code, String message ) {
425411
**/
426412

427413
protected synchronized void closeConnection( int code, String message, boolean remote ) {
428-
if( isclosed ) {
414+
if( readystate == READYSTATE.CLOSED ) {
429415
return;
430416
}
431417

@@ -448,7 +434,7 @@ protected synchronized void closeConnection( int code, String message, boolean r
448434
tempContiniousFrame = null;
449435
handshakerequest = null;
450436

451-
isclosed = true;
437+
readystate = READYSTATE.CLOSED;
452438

453439
}
454440

@@ -583,10 +569,8 @@ private HandshakeState isFlashEdgeCase( ByteBuffer request ) throws IncompleteHa
583569
}
584570
}
585571

586-
@Override
587572
public void startHandshake( ClientHandshakeBuilder handshakedata ) throws InvalidHandshakeException {
588-
if( handshakeComplete )
589-
throw new IllegalStateException( "Handshake has already been sent." );
573+
assert ( readystate != READYSTATE.CONNECTING ) : "shall only be called once";
590574

591575
// Store the Handshake Request we are about to send
592576
this.handshakerequest = draft.postProcessHandshakeRequestAsClient( handshakedata );
@@ -643,10 +627,10 @@ private void deliverMessage( Framedata d ) throws InvalidDataException {
643627
}
644628
}
645629

646-
private void open( Handshakedata d ) throws IOException {
630+
private void open( Handshakedata d ) {
647631
if( DEBUG )
648632
System.out.println( "open using draft: " + draft.getClass().getSimpleName() );
649-
handshakeComplete = true;
633+
readystate = READYSTATE.OPEN;
650634
try {
651635
wsl.onWebsocketOpen( this, d );
652636
} catch ( RuntimeException e ) {
@@ -656,17 +640,19 @@ private void open( Handshakedata d ) throws IOException {
656640

657641
@Override
658642
public boolean isConnecting() {
659-
return ( !flushandclosestate && !closeHandshakeSubmitted && !handshakeComplete );
643+
assert ( flushandclosestate ? readystate == READYSTATE.CONNECTING : true );
644+
return readystate == READYSTATE.CONNECTING; // ifflushandclosestate
660645
}
661646

662647
@Override
663648
public boolean isOpen() {
664-
return ( !flushandclosestate && !isclosed && !closeHandshakeSubmitted && handshakeComplete );
649+
assert ( readystate == READYSTATE.OPEN ? !flushandclosestate : true );
650+
return readystate == READYSTATE.OPEN;
665651
}
666652

667653
@Override
668654
public boolean isClosing() {
669-
return ( !isclosed && closeHandshakeSubmitted );
655+
return readystate == READYSTATE.CLOSING;
670656
}
671657

672658
@Override
@@ -676,29 +662,12 @@ public boolean isFlushAndClose() {
676662

677663
@Override
678664
public boolean isClosed() {
679-
return isclosed;
665+
return readystate == READYSTATE.CLOSED;
680666
}
681667

682-
/**
683-
* Retrieve the WebSocketImpl 'readyState'.
684-
* This represents the state of the connection.
685-
* It returns a numerical value, as per W3C WebSockets specs.
686-
*
687-
* @return Returns '0 = CONNECTING', '1 = OPEN', '2 = CLOSING' or '3 = CLOSED'
688-
*/
689668
@Override
690-
public int getReadyState() {
691-
if( isConnecting() ) {
692-
return READY_STATE_CONNECTING;
693-
} else if( isOpen() ) {
694-
return READY_STATE_OPEN;
695-
} else if( isClosing() ) {
696-
return READY_STATE_CLOSING;
697-
} else if( isFlushAndClose() ) {
698-
return READY_STATE_CLOSED;
699-
}
700-
assert ( false );
701-
return -1; // < This can't happen, by design!
669+
public READYSTATE getReadyState() {
670+
return readystate;
702671
}
703672

704673
@Override

src/main/java/org/java_websocket/client/WebSocketClient.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import org.java_websocket.SocketChannelIOHelper;
2222
import org.java_websocket.WebSocket;
23+
import org.java_websocket.WebSocket.READYSTATE;
2324
import org.java_websocket.WebSocketAdapter;
2425
import org.java_websocket.WebSocketFactory;
2526
import org.java_websocket.WebSocketImpl;
@@ -330,15 +331,12 @@ private void sendHandshake() throws InvalidHandshakeException {
330331
}
331332

332333
/**
333-
* Retrieve the WebSocket 'readyState'.
334334
* This represents the state of the connection.
335-
* It returns a numerical value, as per W3C WebSockets specs.
336-
*
337-
* @return Returns '0 = CONNECTING', '1 = OPEN', '2 = CLOSING' or '3 = CLOSED'
335+
* You can use this method instead of
338336
*/
339-
public int getReadyState() {
337+
public READYSTATE getReadyState() {
340338
if( conn == null ) {
341-
return WebSocket.READY_STATE_CONNECTING;
339+
return READYSTATE.NOTYETCONNECTED;
342340
}
343341
return conn.getReadyState();
344342
}

src/main/java/org/java_websocket/server/WebSocketServer.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,17 @@ public WebSocketServer( InetSocketAddress address , int decodercount , List<Draf
138138
*
139139
* @param connectionscontainer
140140
* Allows to specify a collection that will be used to store the websockets in. <br>
141-
* If you plan to often iterate through the currently connected websockets you may want to use a collection that does not require synchronization like a {@link CopyOnWriteArraySet}. In that case make sure that you overload {@link #removeConnection(WebSocket)} and {@link #addConnection(WebSocket)}.<br>By default a {@link HashSet} will be used.
141+
* If you plan to often iterate through the currently connected websockets you may want to use a collection that does not require synchronization like a {@link CopyOnWriteArraySet}. In that case make sure that you overload {@link #removeConnection(WebSocket)} and {@link #addConnection(WebSocket)}.<br>
142+
* By default a {@link HashSet} will be used.
142143
*
143144
* @see #removeConnection(WebSocket) for more control over syncronized operation
144145
* @see <a href="https://github.com/TooTallNate/Java-WebSocket/wiki/Drafts" > more about drafts
145146
*/
146147
public WebSocketServer( InetSocketAddress address , int decodercount , List<Draft> drafts , Collection<WebSocket> connectionscontainer ) {
147-
if(address ==null || decodercount<1||connectionscontainer==null){
148+
if( address == null || decodercount < 1 || connectionscontainer == null ) {
148149
throw new IllegalArgumentException( "address and connectionscontainer must not be null and you need at least 1 decoder" );
149150
}
150-
151+
151152
if( drafts == null )
152153
this.drafts = Collections.emptyList();
153154
else
@@ -630,18 +631,13 @@ public void run() {
630631
assert ( buf != null );
631632
try {
632633
ws.decode( buf );
633-
// ws.flush();
634-
} catch ( IOException e ) {
635-
handleIOException( ws, e );
636634
} finally {
637635
pushBuffer( buf );
638636
}
639637
}
640638
} catch ( InterruptedException e ) {
641639
} catch ( RuntimeException e ) {
642640
handleFatal( ws, e );
643-
} catch ( Throwable e ) {
644-
e.printStackTrace();
645641
}
646642
}
647643
}

0 commit comments

Comments
 (0)