Input:
Synchronous invocation using a parsed { @link Url }

 Notice :

  DO NOT modify the request object concurrently when this method is called .

 When do invocation use the parsed { @link Url } to find a available connection if none then create one .

 You can use { @link Url#setConnectTimeout } to specify connection timeout time unit is milliseconds .
 You can use { @link Url#setConnNum } to specify connection number for each ip and port .
 You can use { @link Url#setConnWarmup } to specify whether need warmup all connections for the first time you call this method .

 You should use { @link #closeConnection ( Url url ) } to close it if you want .
 [CODESPLIT] public Object invokeSync ( final Url url , final Object request , final int timeoutMillis ) throws RemotingException , InterruptedException { return this . invokeSync ( url , request , null , timeoutMillis ) ; }


Input: Synchronous invocation with a { @link InvokeContext } common api notice please see { @link #invokeSync ( Url Object int ) } [CODESPLIT] public Object invokeSync ( final Url url , final Object request , final InvokeContext invokeContext , final int timeoutMillis ) throws RemotingException , InterruptedException { return this . rpcRemoting . invokeSync ( url , request , invokeContext , timeoutMillis ) ; }


Input:
Synchronous invocation using a { @link Connection }

 Notice :
  DO NOT modify the request object concurrently when this method is called .  [CODESPLIT] public Object invokeSync ( final Connection conn , final Object request , final int timeoutMillis ) throws RemotingException , InterruptedException { return this . rpcRemoting . invokeSync ( conn , request , null , timeoutMillis ) ; }


Input: Synchronous invocation with a { @link InvokeContext } common api notice please see { @link #invokeSync ( Connection Object int ) } [CODESPLIT] public Object invokeSync ( final Connection conn , final Object request , final InvokeContext invokeContext , final int timeoutMillis ) throws RemotingException , InterruptedException { return this . rpcRemoting . invokeSync ( conn , request , invokeContext , timeoutMillis ) ; }


Input:
Future invocation using a { @link Connection }
 You can get result use the returned { @link RpcResponseFuture } .
 Notice :
  DO NOT modify the request object concurrently when this method is called .  [CODESPLIT] public RpcResponseFuture invokeWithFuture ( final Connection conn , final Object request , int timeoutMillis ) throws RemotingException { return this . rpcRemoting . invokeWithFuture ( conn , request , null , timeoutMillis ) ; }


Input: Callback invocation with a { @link InvokeContext } common api notice please see { @link #invokeWithCallback ( Url Object InvokeCallback int ) } [CODESPLIT] public void invokeWithCallback ( final Url url , final Object request , final InvokeContext invokeContext , final InvokeCallback invokeCallback , final int timeoutMillis ) throws RemotingException , InterruptedException { this . rpcRemoting . invokeWithCallback ( url , request , invokeContext , invokeCallback , timeoutMillis ) ; }


Input:
Callback invocation using a { @link Connection }
 You can specify an implementation of { @link InvokeCallback } to get the result .
 Notice :
  DO NOT modify the request object concurrently when this method is called .  [CODESPLIT] public void invokeWithCallback ( final Connection conn , final Object request , final InvokeCallback invokeCallback , final int timeoutMillis ) throws RemotingException { this . rpcRemoting . invokeWithCallback ( conn , request , null , invokeCallback , timeoutMillis ) ; }


Input: Callback invocation with a { @link InvokeContext } common api notice please see { @link #invokeWithCallback ( Connection Object InvokeCallback int ) } [CODESPLIT] public void invokeWithCallback ( final Connection conn , final Object request , final InvokeContext invokeContext , final InvokeCallback invokeCallback , final int timeoutMillis ) throws RemotingException { this . rpcRemoting . invokeWithCallback ( conn , request , invokeContext , invokeCallback , timeoutMillis ) ; }


Input:
Create a stand alone connection using ip and port .

 Notice :

 Each time you call this method will create a new connection .
 Bolt will not control this connection .
 You should use { @link #closeStandaloneConnection } to close it . [CODESPLIT] public Connection createStandaloneConnection ( String ip , int port , int connectTimeout ) throws RemotingException { return this . connectionManager . create ( ip , port , connectTimeout ) ; }


Input:
Create a stand alone connection using address address format example - 127 . 0 . 0 . 1 : 12200

 Notice :

 Each time you can this method will create a new connection .
 Bolt will not control this connection .
 You should use { @link #closeStandaloneConnection } to close it .
 [CODESPLIT] public Connection createStandaloneConnection ( String addr , int connectTimeout ) throws RemotingException { return this . connectionManager . create ( addr , connectTimeout ) ; }


Input:
Get a connection using address address format example - 127 . 0 . 0 . 1 : 12200?key1 = value1&key2 = value2

 Notice :

 Get a connection if none then create .

 You can use { [CODESPLIT] public Connection getConnection ( String addr , int connectTimeout ) throws RemotingException , InterruptedException { Url url = this . addressParser . parse ( addr ) ; return this . getConnection ( url , connectTimeout ) ; }


Input: Get a connection using a { @link Url } . <br > <p > Notice : <ol > <li > Get a connection if none then create . <li > Bolt will control this connection in { @link com . alipay . remoting . ConnectionPool } <li > You should use { @link #closeConnection ( Url url ) } to close it . < / ol > [CODESPLIT] public Connection getConnection ( Url url , int connectTimeout ) throws RemotingException , InterruptedException { url . setConnectTimeout ( connectTimeout ) ; return this . connectionManager . getAndCreateIfAbsent ( url ) ; }


Input: check connection the address format example - 127 . 0 . 0 . 1 : 12200?key1 = value1&key2 = value2 [CODESPLIT] public boolean checkConnection ( String addr ) { Url url = this . addressParser . parse ( addr ) ; Connection conn = this . connectionManager . get ( url . getUniqueKey ( ) ) ; try { this . connectionManager . check ( conn ) ; } catch ( Exception e ) { return false ; } return true ; }


Input: Close all connections of a address [CODESPLIT] public void closeConnection ( String addr ) { Url url = this . addressParser . parse ( addr ) ; this . connectionManager . remove ( url . getUniqueKey ( ) ) ; }


Input: Enable heart beat for a certain connection . If this address not connected then do nothing . <p > Notice : this method takes no effect on a stand alone connection . [CODESPLIT] public void enableConnHeartbeat ( String addr ) { Url url = this . addressParser . parse ( addr ) ; this . enableConnHeartbeat ( url ) ; }


Input: Enable heart beat for a certain connection . If this { @link Url } not connected then do nothing . <p > Notice : this method takes no effect on a stand alone connection . [CODESPLIT] public void enableConnHeartbeat ( Url url ) { if ( null != url ) { this . connectionManager . enableHeartbeat ( this . connectionManager . get ( url . getUniqueKey ( ) ) ) ; } }


Input: Disable heart beat for a certain connection . If this addr not connected then do nothing . <p > Notice : this method takes no effect on a stand alone connection . [CODESPLIT] public void disableConnHeartbeat ( String addr ) { Url url = this . addressParser . parse ( addr ) ; this . disableConnHeartbeat ( url ) ; }


Input: Disable heart beat for a certain connection . If this { @link Url } not connected then do nothing . <p > Notice : this method takes no effect on a stand alone connection . [CODESPLIT] public void disableConnHeartbeat ( Url url ) { if ( null != url ) { this . connectionManager . disableHeartbeat ( this . connectionManager . get ( url . getUniqueKey ( ) ) ) ; } }


Input: Initialization . [CODESPLIT] private void init ( ) { this . channel . attr ( HEARTBEAT_COUNT ) . set ( new Integer ( 0 ) ) ; this . channel . attr ( PROTOCOL ) . set ( this . protocolCode ) ; this . channel . attr ( VERSION ) . set ( this . version ) ; this . channel . attr ( HEARTBEAT_SWITCH ) . set ( true ) ; }


Input: Do something when closing . [CODESPLIT] public void onClose ( ) { Iterator < Entry < Integer , InvokeFuture > > iter = invokeFutureMap . entrySet ( ) . iterator ( ) ; while ( iter . hasNext ( ) ) { Entry < Integer , InvokeFuture > entry = iter . next ( ) ; iter . remove ( ) ; InvokeFuture future = entry . getValue ( ) ; if ( future != null ) { future . putResponse ( future . createConnectionClosedResponse ( this . getRemoteAddress ( ) ) ) ; future . cancelTimeout ( ) ; future . tryAsyncExecuteInvokeCallbackAbnormally ( ) ; } } }


Input: Close the connection . [CODESPLIT] public void close ( ) { if ( closed . compareAndSet ( false , true ) ) { try { if ( this . getChannel ( ) != null ) { this . getChannel ( ) . close ( ) . addListener ( new ChannelFutureListener ( ) { @ Override public void operationComplete ( ChannelFuture future ) throws Exception { if ( logger . isInfoEnabled ( ) ) { logger . info ( "Close the connection to remote address={}, result={}, cause={}" , RemotingUtil . parseRemoteAddress ( Connection . this . getChannel ( ) ) , future . isSuccess ( ) , future . cause ( ) ) ; } } } ) ; } } catch ( Exception e ) { logger . warn ( "Exception caught when closing connection {}" , RemotingUtil . parseRemoteAddress ( Connection . this . getChannel ( ) ) , e ) ; } } }


Input: set attribute if key absent . [CODESPLIT] public Object setAttributeIfAbsent ( String key , Object value ) { return attributes . putIfAbsent ( key , value ) ; }


Input: This method has been modified to check the size of decoded msgs which is represented by the local variable { @code RecyclableArrayList out } . If has decoded more than one msg then construct an array list to submit all decoded msgs to the pipeline . [CODESPLIT] @ Override public void channelRead ( ChannelHandlerContext ctx , Object msg ) throws Exception { if ( msg instanceof ByteBuf ) { RecyclableArrayList out = RecyclableArrayList . newInstance ( ) ; try { ByteBuf data = ( ByteBuf ) msg ; first = cumulation == null ; if ( first ) { cumulation = data ; } else { cumulation = cumulator . cumulate ( ctx . alloc ( ) , cumulation , data ) ; } callDecode ( ctx , cumulation , out ) ; } catch ( DecoderException e ) { throw e ; } catch ( Throwable t ) { throw new DecoderException ( t ) ; } finally { if ( cumulation != null && ! cumulation . isReadable ( ) ) { numReads = 0 ; cumulation . release ( ) ; cumulation = null ; } else if ( ++ numReads >= discardAfterReads ) { // We did enough reads already try to discard some bytes so we not risk to see a OOME. // See https://github.com/netty/netty/issues/4275 numReads = 0 ; discardSomeReadBytes ( ) ; } int size = out . size ( ) ; if ( size == 0 ) { decodeWasNull = true ; } else if ( size == 1 ) { ctx . fireChannelRead ( out . get ( 0 ) ) ; } else { ArrayList < Object > ret = new ArrayList < Object > ( size ) ; for ( int i = 0 ; i < size ; i ++ ) { ret . add ( out . get ( i ) ) ; } ctx . fireChannelRead ( ret ) ; } out . recycle ( ) ; } } else { ctx . fireChannelRead ( msg ) ; } }


Input: Called once data should be decoded from the given { @link ByteBuf } . This method will call { @link #decode ( ChannelHandlerContext ByteBuf List ) } as long as decoding should take place . [CODESPLIT] protected void callDecode ( ChannelHandlerContext ctx , ByteBuf in , List < Object > out ) { try { while ( in . isReadable ( ) ) { int outSize = out . size ( ) ; int oldInputLength = in . readableBytes ( ) ; decode ( ctx , in , out ) ; // Check if this handler was removed before continuing the loop. // If it was removed, it is not safe to continue to operate on the buffer. // // See https://github.com/netty/netty/issues/1664 if ( ctx . isRemoved ( ) ) { break ; } if ( outSize == out . size ( ) ) { if ( oldInputLength == in . readableBytes ( ) ) { break ; } else { continue ; } } if ( oldInputLength == in . readableBytes ( ) ) { throw new DecoderException ( StringUtil . simpleClassName ( getClass ( ) ) + ".decode() did not read anything but decoded a message." ) ; } if ( isSingleDecode ( ) ) { break ; } } } catch ( DecoderException e ) { throw e ; } catch ( Throwable cause ) { throw new DecoderException ( cause ) ; } }


Input: Help register single - interest user processor . [CODESPLIT] public static void registerUserProcessor ( UserProcessor < ? > processor , ConcurrentHashMap < String , UserProcessor < ? > > userProcessors ) { if ( null == processor ) { throw new RuntimeException ( "User processor should not be null!" ) ; } if ( processor instanceof MultiInterestUserProcessor ) { registerUserProcessor ( ( MultiInterestUserProcessor ) processor , userProcessors ) ; } else { if ( StringUtils . isBlank ( processor . interest ( ) ) ) { throw new RuntimeException ( "Processor interest should not be blank!" ) ; } UserProcessor < ? > preProcessor = userProcessors . putIfAbsent ( processor . interest ( ) , processor ) ; if ( preProcessor != null ) { String errMsg = "Processor with interest key [" + processor . interest ( ) + "] has already been registered to rpc server, can not register again!" ; throw new RuntimeException ( errMsg ) ; } } }


Input: Help register multi - interest user processor . [CODESPLIT] private static void registerUserProcessor ( MultiInterestUserProcessor < ? > processor , ConcurrentHashMap < String , UserProcessor < ? > > userProcessors ) { if ( null == processor . multiInterest ( ) || processor . multiInterest ( ) . isEmpty ( ) ) { throw new RuntimeException ( "Processor interest should not be blank!" ) ; } for ( String interest : processor . multiInterest ( ) ) { UserProcessor < ? > preProcessor = userProcessors . putIfAbsent ( interest , processor ) ; if ( preProcessor != null ) { String errMsg = "Processor with interest key [" + interest + "] has already been registered to rpc server, can not register again!" ; throw new RuntimeException ( errMsg ) ; } } }


Input: Send response using remoting context if necessary . <br > If request type is oneway no need to send any response nor exception . [CODESPLIT] public void sendResponseIfNecessary ( final RemotingContext ctx , byte type , final RemotingCommand response ) { final int id = response . getId ( ) ; if ( type != RpcCommandType . REQUEST_ONEWAY ) { RemotingCommand serializedResponse = response ; try { response . serialize ( ) ; } catch ( SerializationException e ) { String errMsg = "SerializationException occurred when sendResponseIfNecessary in RpcRequestProcessor, id=" + id ; logger . error ( errMsg , e ) ; serializedResponse = this . getCommandFactory ( ) . createExceptionResponse ( id , ResponseStatus . SERVER_SERIAL_EXCEPTION , e ) ; try { serializedResponse . serialize ( ) ; // serialize again for exception response } catch ( SerializationException e1 ) { // should not happen logger . error ( "serialize SerializationException response failed!" ) ; } } catch ( Throwable t ) { String errMsg = "Serialize RpcResponseCommand failed when sendResponseIfNecessary in RpcRequestProcessor, id=" + id ; logger . error ( errMsg , t ) ; serializedResponse = this . getCommandFactory ( ) . createExceptionResponse ( id , t , errMsg ) ; } ctx . writeAndFlush ( serializedResponse ) . addListener ( new ChannelFutureListener ( ) { @ Override public void operationComplete ( ChannelFuture future ) throws Exception { if ( logger . isDebugEnabled ( ) ) { logger . debug ( "Rpc response sent! requestId=" + id + ". The address is " + RemotingUtil . parseRemoteAddress ( ctx . getChannelContext ( ) . channel ( ) ) ) ; } if ( ! future . isSuccess ( ) ) { logger . error ( "Rpc response send failed! id=" + id + ". The address is " + RemotingUtil . parseRemoteAddress ( ctx . getChannelContext ( ) . channel ( ) ) , future . cause ( ) ) ; } } } ) ; } else { if ( logger . isDebugEnabled ( ) ) { logger . debug ( "Oneway rpc request received, do not send response, id=" + id + ", the address is " + RemotingUtil . parseRemoteAddress ( ctx . getChannelContext ( ) . channel ( ) ) ) ; } } }


Input: dispatch request command to user processor [CODESPLIT] private void dispatchToUserProcessor ( RemotingContext ctx , RpcRequestCommand cmd ) { final int id = cmd . getId ( ) ; final byte type = cmd . getType ( ) ; // processor here must not be null, for it have been checked before UserProcessor processor = ctx . getUserProcessor ( cmd . getRequestClass ( ) ) ; if ( processor instanceof AsyncUserProcessor ) { try { processor . handleRequest ( processor . preHandleRequest ( ctx , cmd . getRequestObject ( ) ) , new RpcAsyncContext ( ctx , cmd , this ) , cmd . getRequestObject ( ) ) ; } catch ( RejectedExecutionException e ) { logger . warn ( "RejectedExecutionException occurred when do ASYNC process in RpcRequestProcessor" ) ; sendResponseIfNecessary ( ctx , type , this . getCommandFactory ( ) . createExceptionResponse ( id , ResponseStatus . SERVER_THREADPOOL_BUSY ) ) ; } catch ( Throwable t ) { String errMsg = "AYSNC process rpc request failed in RpcRequestProcessor, id=" + id ; logger . error ( errMsg , t ) ; sendResponseIfNecessary ( ctx , type , this . getCommandFactory ( ) . createExceptionResponse ( id , t , errMsg ) ) ; } } else { try { Object responseObject = processor . handleRequest ( processor . preHandleRequest ( ctx , cmd . getRequestObject ( ) ) , cmd . getRequestObject ( ) ) ; sendResponseIfNecessary ( ctx , type , this . getCommandFactory ( ) . createResponse ( responseObject , cmd ) ) ; } catch ( RejectedExecutionException e ) { logger . warn ( "RejectedExecutionException occurred when do SYNC process in RpcRequestProcessor" ) ; sendResponseIfNecessary ( ctx , type , this . getCommandFactory ( ) . createExceptionResponse ( id , ResponseStatus . SERVER_THREADPOOL_BUSY ) ) ; } catch ( Throwable t ) { String errMsg = "SYNC process rpc request failed in RpcRequestProcessor, id=" + id ; logger . error ( errMsg , t ) ; sendResponseIfNecessary ( ctx , type , this . getCommandFactory ( ) . createExceptionResponse ( id , t , errMsg ) ) ; } } }


Input: deserialize request command [CODESPLIT] private boolean deserializeRequestCommand ( RemotingContext ctx , RpcRequestCommand cmd , int level ) { boolean result ; try { cmd . deserialize ( level ) ; result = true ; } catch ( DeserializationException e ) { logger . error ( "DeserializationException occurred when process in RpcRequestProcessor, id={}, deserializeLevel={}" , cmd . getId ( ) , RpcDeserializeLevel . valueOf ( level ) , e ) ; sendResponseIfNecessary ( ctx , cmd . getType ( ) , this . getCommandFactory ( ) . createExceptionResponse ( cmd . getId ( ) , ResponseStatus . SERVER_DESERIAL_EXCEPTION , e ) ) ; result = false ; } catch ( Throwable t ) { String errMsg = "Deserialize RpcRequestCommand failed in RpcRequestProcessor, id=" + cmd . getId ( ) + ", deserializeLevel=" + level ; logger . error ( errMsg , t ) ; sendResponseIfNecessary ( ctx , cmd . getType ( ) , this . getCommandFactory ( ) . createExceptionResponse ( cmd . getId ( ) , t , errMsg ) ) ; result = false ; } return result ; }


Input: pre process remoting context initial some useful infos and pass to biz [CODESPLIT] private void preProcessRemotingContext ( RemotingContext ctx , RpcRequestCommand cmd , long currentTimestamp ) { ctx . setArriveTimestamp ( cmd . getArriveTime ( ) ) ; ctx . setTimeout ( cmd . getTimeout ( ) ) ; ctx . setRpcCommandType ( cmd . getType ( ) ) ; ctx . getInvokeContext ( ) . putIfAbsent ( InvokeContext . BOLT_PROCESS_WAIT_TIME , currentTimestamp - cmd . getArriveTime ( ) ) ; }


Input: print some log when request timeout and discarded in io thread . [CODESPLIT] private void timeoutLog ( final RpcRequestCommand cmd , long currentTimestamp , RemotingContext ctx ) { if ( logger . isDebugEnabled ( ) ) { logger . debug ( "request id [{}] currenTimestamp [{}] - arriveTime [{}] = server cost [{}] >= timeout value [{}]." , cmd . getId ( ) , currentTimestamp , cmd . getArriveTime ( ) , ( currentTimestamp - cmd . getArriveTime ( ) ) , cmd . getTimeout ( ) ) ; } String remoteAddr = "UNKNOWN" ; if ( null != ctx ) { ChannelHandlerContext channelCtx = ctx . getChannelContext ( ) ; Channel channel = channelCtx . channel ( ) ; if ( null != channel ) { remoteAddr = RemotingUtil . parseRemoteAddress ( channel ) ; } } logger . warn ( "Rpc request id[{}], from remoteAddr[{}] stop process, total wait time in queue is [{}], client timeout setting is [{}]." , cmd . getId ( ) , remoteAddr , ( currentTimestamp - cmd . getArriveTime ( ) ) , cmd . getTimeout ( ) ) ; }


Input: print some debug log when receive request [CODESPLIT] private void debugLog ( RemotingContext ctx , RpcRequestCommand cmd , long currentTimestamp ) { if ( logger . isDebugEnabled ( ) ) { logger . debug ( "Rpc request received! requestId={}, from {}" , cmd . getId ( ) , RemotingUtil . parseRemoteAddress ( ctx . getChannelContext ( ) . channel ( ) ) ) ; logger . debug ( "request id {} currenTimestamp {} - arriveTime {} = server cost {} < timeout {}." , cmd . getId ( ) , currentTimestamp , cmd . getArriveTime ( ) , ( currentTimestamp - cmd . getArriveTime ( ) ) , cmd . getTimeout ( ) ) ; } }


Input: Process the remoting command with its own executor or with the defaultExecutor if its own if null . [CODESPLIT] @ Override public void process ( RemotingContext ctx , T msg , ExecutorService defaultExecutor ) throws Exception { ProcessTask task = new ProcessTask ( ctx , msg ) ; if ( this . getExecutor ( ) != null ) { this . getExecutor ( ) . execute ( task ) ; } else { defaultExecutor . execute ( task ) ; } }


Input: Synchronous invocation [CODESPLIT] protected RemotingCommand invokeSync ( final Connection conn , final RemotingCommand request , final int timeoutMillis ) throws RemotingException , InterruptedException { final InvokeFuture future = createInvokeFuture ( request , request . getInvokeContext ( ) ) ; conn . addInvokeFuture ( future ) ; final int requestId = request . getId ( ) ; try { conn . getChannel ( ) . writeAndFlush ( request ) . addListener ( new ChannelFutureListener ( ) { @ Override public void operationComplete ( ChannelFuture f ) throws Exception { if ( ! f . isSuccess ( ) ) { conn . removeInvokeFuture ( requestId ) ; future . putResponse ( commandFactory . createSendFailedResponse ( conn . getRemoteAddress ( ) , f . cause ( ) ) ) ; logger . error ( "Invoke send failed, id={}" , requestId , f . cause ( ) ) ; } } } ) ; } catch ( Exception e ) { conn . removeInvokeFuture ( requestId ) ; future . putResponse ( commandFactory . createSendFailedResponse ( conn . getRemoteAddress ( ) , e ) ) ; logger . error ( "Exception caught when sending invocation, id={}" , requestId , e ) ; } RemotingCommand response = future . waitResponse ( timeoutMillis ) ; if ( response == null ) { conn . removeInvokeFuture ( requestId ) ; response = this . commandFactory . createTimeoutResponse ( conn . getRemoteAddress ( ) ) ; logger . warn ( "Wait response, request id={} timeout!" , requestId ) ; } return response ; }


Input: Invocation with callback . [CODESPLIT] protected void invokeWithCallback ( final Connection conn , final RemotingCommand request , final InvokeCallback invokeCallback , final int timeoutMillis ) { final InvokeFuture future = createInvokeFuture ( conn , request , request . getInvokeContext ( ) , invokeCallback ) ; conn . addInvokeFuture ( future ) ; final int requestId = request . getId ( ) ; try { Timeout timeout = TimerHolder . getTimer ( ) . newTimeout ( new TimerTask ( ) { @ Override public void run ( Timeout timeout ) throws Exception { InvokeFuture future = conn . removeInvokeFuture ( requestId ) ; if ( future != null ) { future . putResponse ( commandFactory . createTimeoutResponse ( conn . getRemoteAddress ( ) ) ) ; future . tryAsyncExecuteInvokeCallbackAbnormally ( ) ; } } } , timeoutMillis , TimeUnit . MILLISECONDS ) ; future . addTimeout ( timeout ) ; conn . getChannel ( ) . writeAndFlush ( request ) . addListener ( new ChannelFutureListener ( ) { @ Override public void operationComplete ( ChannelFuture cf ) throws Exception { if ( ! cf . isSuccess ( ) ) { InvokeFuture f = conn . removeInvokeFuture ( requestId ) ; if ( f != null ) { f . cancelTimeout ( ) ; f . putResponse ( commandFactory . createSendFailedResponse ( conn . getRemoteAddress ( ) , cf . cause ( ) ) ) ; f . tryAsyncExecuteInvokeCallbackAbnormally ( ) ; } logger . error ( "Invoke send failed. The address is {}" , RemotingUtil . parseRemoteAddress ( conn . getChannel ( ) ) , cf . cause ( ) ) ; } } } ) ; } catch ( Exception e ) { InvokeFuture f = conn . removeInvokeFuture ( requestId ) ; if ( f != null ) { f . cancelTimeout ( ) ; f . putResponse ( commandFactory . createSendFailedResponse ( conn . getRemoteAddress ( ) , e ) ) ; f . tryAsyncExecuteInvokeCallbackAbnormally ( ) ; } logger . error ( "Exception caught when sending invocation. The address is {}" , RemotingUtil . parseRemoteAddress ( conn . getChannel ( ) ) , e ) ; } }


Input: Oneway invocation . [CODESPLIT] protected void oneway ( final Connection conn , final RemotingCommand request ) { try { conn . getChannel ( ) . writeAndFlush ( request ) . addListener ( new ChannelFutureListener ( ) { @ Override public void operationComplete ( ChannelFuture f ) throws Exception { if ( ! f . isSuccess ( ) ) { logger . error ( "Invoke send failed. The address is {}" , RemotingUtil . parseRemoteAddress ( conn . getChannel ( ) ) , f . cause ( ) ) ; } } } ) ; } catch ( Exception e ) { if ( null == conn ) { logger . error ( "Conn is null" ) ; } else { logger . error ( "Exception caught when sending invocation. The address is {}" , RemotingUtil . parseRemoteAddress ( conn . getChannel ( ) ) , e ) ; } } }


Input: create an instance of { @link ProtocolSwitch } according to byte value [CODESPLIT] public static ProtocolSwitch create ( int value ) { ProtocolSwitch status = new ProtocolSwitch ( ) ; status . setBs ( toBitSet ( value ) ) ; return status ; }


Input: create an instance of { @link ProtocolSwitch } according to switch index [CODESPLIT] public static ProtocolSwitch create ( int [ ] index ) { ProtocolSwitch status = new ProtocolSwitch ( ) ; for ( int i = 0 ; i < index . length ; ++ i ) { status . turnOn ( index [ i ] ) ; } return status ; }


Input: from bit set to byte [CODESPLIT] public static byte toByte ( BitSet bs ) { int value = 0 ; for ( int i = 0 ; i < bs . length ( ) ; ++ i ) { if ( bs . get ( i ) ) { value += 1 << i ; } } if ( bs . length ( ) > 7 ) { throw new IllegalArgumentException ( "The byte value " + value + " generated according to bit set " + bs + " is out of range, should be limited between [" + Byte . MIN_VALUE + "] to [" + Byte . MAX_VALUE + "]" ) ; } return ( byte ) value ; }


Input: from byte to bit set [CODESPLIT] public static BitSet toBitSet ( int value ) { if ( value > Byte . MAX_VALUE || value < Byte . MIN_VALUE ) { throw new IllegalArgumentException ( "The value " + value + " is out of byte range, should be limited between [" + Byte . MIN_VALUE + "] to [" + Byte . MAX_VALUE + "]" ) ; } BitSet bs = new BitSet ( ) ; int index = 0 ; while ( value != 0 ) { if ( value % 2 != 0 ) { bs . set ( index ) ; } ++ index ; value = ( byte ) ( value >> 1 ) ; } return bs ; }


Input: Get connection and set init invokeContext if invokeContext not { @code null } [CODESPLIT] protected Connection getConnectionAndInitInvokeContext ( Url url , InvokeContext invokeContext ) throws RemotingException , InterruptedException { long start = System . currentTimeMillis ( ) ; Connection conn ; try { conn = this . connectionManager . getAndCreateIfAbsent ( url ) ; } finally { if ( null != invokeContext ) { invokeContext . putIfAbsent ( InvokeContext . CLIENT_CONN_CREATETIME , ( System . currentTimeMillis ( ) - start ) ) ; } } return conn ; }


Input: add reconnect task [CODESPLIT] public void addReconnectTask ( Url url ) { ReconnectTask task = new ReconnectTask ( ) ; task . url = url ; tasks . add ( task ) ; }


Input: stop reconnect thread [CODESPLIT] public void stop ( ) { if ( ! this . started ) { return ; } this . started = false ; healConnectionThreads . interrupt ( ) ; this . tasks . clear ( ) ; this . canceled . clear ( ) ; }


Input: Oneway rpc invocation . <br > Notice! DO NOT modify the request object concurrently when this method is called . [CODESPLIT] public void oneway ( final String addr , final Object request , final InvokeContext invokeContext ) throws RemotingException , InterruptedException { Url url = this . addressParser . parse ( addr ) ; this . oneway ( url , request , invokeContext ) ; }


Input: Oneway rpc invocation . <br > Notice! DO NOT modify the request object concurrently when this method is called . [CODESPLIT] public void oneway ( final Connection conn , final Object request , final InvokeContext invokeContext ) throws RemotingException { RequestCommand requestCommand = ( RequestCommand ) toRemotingCommand ( request , conn , invokeContext , - 1 ) ; requestCommand . setType ( RpcCommandType . REQUEST_ONEWAY ) ; preProcessInvokeContext ( invokeContext , requestCommand , conn ) ; super . oneway ( conn , requestCommand ) ; }


Input: Synchronous rpc invocation . <br > Notice! DO NOT modify the request object concurrently when this method is called . [CODESPLIT] public Object invokeSync ( final String addr , final Object request , final InvokeContext invokeContext , final int timeoutMillis ) throws RemotingException , InterruptedException { Url url = this . addressParser . parse ( addr ) ; return this . invokeSync ( url , request , invokeContext , timeoutMillis ) ; }


Input: Synchronous rpc invocation . <br > Notice! DO NOT modify the request object concurrently when this method is called . [CODESPLIT] public Object invokeSync ( final Connection conn , final Object request , final InvokeContext invokeContext , final int timeoutMillis ) throws RemotingException , InterruptedException { RemotingCommand requestCommand = toRemotingCommand ( request , conn , invokeContext , timeoutMillis ) ; preProcessInvokeContext ( invokeContext , requestCommand , conn ) ; ResponseCommand responseCommand = ( ResponseCommand ) super . invokeSync ( conn , requestCommand , timeoutMillis ) ; responseCommand . setInvokeContext ( invokeContext ) ; Object responseObject = RpcResponseResolver . resolveResponseObject ( responseCommand , RemotingUtil . parseRemoteAddress ( conn . getChannel ( ) ) ) ; return responseObject ; }


Input: Rpc invocation with future returned . <br > Notice! DO NOT modify the request object concurrently when this method is called . [CODESPLIT] public RpcResponseFuture invokeWithFuture ( final Connection conn , final Object request , final InvokeContext invokeContext , final int timeoutMillis ) throws RemotingException { RemotingCommand requestCommand = toRemotingCommand ( request , conn , invokeContext , timeoutMillis ) ; preProcessInvokeContext ( invokeContext , requestCommand , conn ) ; InvokeFuture future = super . invokeWithFuture ( conn , requestCommand , timeoutMillis ) ; return new RpcResponseFuture ( RemotingUtil . parseRemoteAddress ( conn . getChannel ( ) ) , future ) ; }


Input: Rpc invocation with callback . <br > Notice! DO NOT modify the request object concurrently when this method is called . [CODESPLIT] public void invokeWithCallback ( String addr , Object request , final InvokeContext invokeContext , InvokeCallback invokeCallback , int timeoutMillis ) throws RemotingException , InterruptedException { Url url = this . addressParser . parse ( addr ) ; this . invokeWithCallback ( url , request , invokeContext , invokeCallback , timeoutMillis ) ; }


Input: Rpc invocation with callback . <br > Notice! DO NOT modify the request object concurrently when this method is called . [CODESPLIT] public void invokeWithCallback ( final Connection conn , final Object request , final InvokeContext invokeContext , final InvokeCallback invokeCallback , final int timeoutMillis ) throws RemotingException { RemotingCommand requestCommand = toRemotingCommand ( request , conn , invokeContext , timeoutMillis ) ; preProcessInvokeContext ( invokeContext , requestCommand , conn ) ; super . invokeWithCallback ( conn , requestCommand , invokeCallback , timeoutMillis ) ; }


Input: Convert application request object to remoting request command . [CODESPLIT] protected RemotingCommand toRemotingCommand ( Object request , Connection conn , InvokeContext invokeContext , int timeoutMillis ) throws SerializationException { RpcRequestCommand command = this . getCommandFactory ( ) . createRequestCommand ( request ) ; if ( null != invokeContext ) { // set client custom serializer for request command if not null Object clientCustomSerializer = invokeContext . get ( InvokeContext . BOLT_CUSTOM_SERIALIZER ) ; if ( null != clientCustomSerializer ) { try { command . setSerializer ( ( Byte ) clientCustomSerializer ) ; } catch ( ClassCastException e ) { throw new IllegalArgumentException ( "Illegal custom serializer [" + clientCustomSerializer + "], the type of value should be [byte], but now is [" + clientCustomSerializer . getClass ( ) . getName ( ) + "]." ) ; } } // enable crc by default, user can disable by set invoke context `false` for key `InvokeContext.BOLT_CRC_SWITCH` Boolean crcSwitch = invokeContext . get ( InvokeContext . BOLT_CRC_SWITCH , ProtocolSwitch . CRC_SWITCH_DEFAULT_VALUE ) ; if ( null != crcSwitch && crcSwitch ) { command . setProtocolSwitch ( ProtocolSwitch . create ( new int [ ] { ProtocolSwitch . CRC_SWITCH_INDEX } ) ) ; } } else { // enable crc by default, if there is no invoke context. command . setProtocolSwitch ( ProtocolSwitch . create ( new int [ ] { ProtocolSwitch . CRC_SWITCH_INDEX } ) ) ; } command . setTimeout ( timeoutMillis ) ; command . setRequestClass ( request . getClass ( ) . getName ( ) ) ; command . setInvokeContext ( invokeContext ) ; command . serialize ( ) ; logDebugInfo ( command ) ; return command ; }


Input: Filter connections to monitor [CODESPLIT] @ Override public Map < String , List < Connection > > filter ( List < Connection > connections ) { List < Connection > serviceOnConnections = new ArrayList < Connection > ( ) ; List < Connection > serviceOffConnections = new ArrayList < Connection > ( ) ; Map < String , List < Connection > > filteredConnections = new ConcurrentHashMap < String , List < Connection > > ( ) ; for ( Connection connection : connections ) { String serviceStatus = ( String ) connection . getAttribute ( Configs . CONN_SERVICE_STATUS ) ; if ( serviceStatus != null ) { if ( connection . isInvokeFutureMapFinish ( ) && ! freshSelectConnections . containsValue ( connection ) ) { serviceOffConnections . add ( connection ) ; } } else { serviceOnConnections . add ( connection ) ; } } filteredConnections . put ( Configs . CONN_SERVICE_STATUS_ON , serviceOnConnections ) ; filteredConnections . put ( Configs . CONN_SERVICE_STATUS_OFF , serviceOffConnections ) ; return filteredConnections ; }


Input: Monitor connections and close connections with status is off [CODESPLIT] @ Override public void monitor ( Map < String , RunStateRecordedFutureTask < ConnectionPool > > connPools ) { try { if ( null != connPools && ! connPools . isEmpty ( ) ) { Iterator < Map . Entry < String , RunStateRecordedFutureTask < ConnectionPool > > > iter = connPools . entrySet ( ) . iterator ( ) ; while ( iter . hasNext ( ) ) { Map . Entry < String , RunStateRecordedFutureTask < ConnectionPool > > entry = iter . next ( ) ; String poolKey = entry . getKey ( ) ; ConnectionPool pool = FutureTaskUtil . getFutureTaskResult ( entry . getValue ( ) , logger ) ; List < Connection > connections = pool . getAll ( ) ; Map < String , List < Connection > > filteredConnectons = this . filter ( connections ) ; List < Connection > serviceOnConnections = filteredConnectons . get ( Configs . CONN_SERVICE_STATUS_ON ) ; List < Connection > serviceOffConnections = filteredConnectons . get ( Configs . CONN_SERVICE_STATUS_OFF ) ; if ( serviceOnConnections . size ( ) > CONNECTION_THRESHOLD ) { Connection freshSelectConnect = serviceOnConnections . get ( random . nextInt ( serviceOnConnections . size ( ) ) ) ; freshSelectConnect . setAttribute ( Configs . CONN_SERVICE_STATUS , Configs . CONN_SERVICE_STATUS_OFF ) ; Connection lastSelectConnect = freshSelectConnections . remove ( poolKey ) ; freshSelectConnections . put ( poolKey , freshSelectConnect ) ; closeFreshSelectConnections ( lastSelectConnect , serviceOffConnections ) ; } else { if ( freshSelectConnections . containsKey ( poolKey ) ) { Connection lastSelectConnect = freshSelectConnections . remove ( poolKey ) ; closeFreshSelectConnections ( lastSelectConnect , serviceOffConnections ) ; } if ( logger . isInfoEnabled ( ) ) { logger . info ( "the size of serviceOnConnections [{}] reached CONNECTION_THRESHOLD [{}]." , serviceOnConnections . size ( ) , CONNECTION_THRESHOLD ) ; } } for ( Connection offConn : serviceOffConnections ) { if ( offConn . isFine ( ) ) { offConn . close ( ) ; } } } } } catch ( Exception e ) { logger . error ( "ScheduledDisconnectStrategy monitor error" , e ) ; } }


Input: close the connection of the fresh select connections [CODESPLIT] private void closeFreshSelectConnections ( Connection lastSelectConnect , List < Connection > serviceOffConnections ) throws InterruptedException { if ( null != lastSelectConnect ) { if ( lastSelectConnect . isInvokeFutureMapFinish ( ) ) { serviceOffConnections . add ( lastSelectConnect ) ; } else { Thread . sleep ( RETRY_DETECT_PERIOD ) ; if ( lastSelectConnect . isInvokeFutureMapFinish ( ) ) { serviceOffConnections . add ( lastSelectConnect ) ; } else { if ( logger . isInfoEnabled ( ) ) { logger . info ( "Address={} won't close at this schedule turn" , RemotingUtil . parseRemoteAddress ( lastSelectConnect . getChannel ( ) ) ) ; } } } } }


Input: / * Handle the request ( s ) . [CODESPLIT] private void handle ( final RemotingContext ctx , final Object msg ) { try { if ( msg instanceof List ) { final Runnable handleTask = new Runnable ( ) { @ Override public void run ( ) { if ( logger . isDebugEnabled ( ) ) { logger . debug ( "Batch message! size={}" , ( ( List < ? > ) msg ) . size ( ) ) ; } for ( final Object m : ( List < ? > ) msg ) { RpcCommandHandler . this . process ( ctx , m ) ; } } } ; if ( RpcConfigManager . dispatch_msg_list_in_default_executor ( ) ) { // If msg is list ,then the batch submission to biz threadpool can save io thread. // See com.alipay.remoting.decoder.ProtocolDecoder processorManager . getDefaultExecutor ( ) . execute ( handleTask ) ; } else { handleTask . run ( ) ; } } else { process ( ctx , msg ) ; } } catch ( final Throwable t ) { processException ( ctx , msg , t ) ; } }


Input: / * Return error command if necessary . [CODESPLIT] private void processExceptionForSingleCommand ( RemotingContext ctx , Object msg , Throwable t ) { final int id = ( ( RpcCommand ) msg ) . getId ( ) ; final String emsg = "Exception caught when processing " + ( ( msg instanceof RequestCommand ) ? "request, id=" : "response, id=" ) ; logger . warn ( emsg + id , t ) ; if ( msg instanceof RequestCommand ) { final RequestCommand cmd = ( RequestCommand ) msg ; if ( cmd . getType ( ) != RpcCommandType . REQUEST_ONEWAY ) { if ( t instanceof RejectedExecutionException ) { final ResponseCommand response = this . commandFactory . createExceptionResponse ( id , ResponseStatus . SERVER_THREADPOOL_BUSY ) ; // RejectedExecutionException here assures no response has been sent back // Other exceptions should be processed where exception was caught, because here we don't known whether ack had been sent back. ctx . getChannelContext ( ) . writeAndFlush ( response ) . addListener ( new ChannelFutureListener ( ) { @ Override public void operationComplete ( ChannelFuture future ) throws Exception { if ( future . isSuccess ( ) ) { if ( logger . isInfoEnabled ( ) ) { logger . info ( "Write back exception response done, requestId={}, status={}" , id , response . getResponseStatus ( ) ) ; } } else { logger . error ( "Write back exception response failed, requestId={}" , id , future . cause ( ) ) ; } } } ) ; } } } }


Input: ~~~ public helper methods to retrieve system property [CODESPLIT] public static boolean getBool ( String key , String defaultValue ) { return Boolean . parseBoolean ( System . getProperty ( key , defaultValue ) ) ; }


Input: Deserialize according to mask . <ol > <li > If mask < = { @link RpcDeserializeLevel#DESERIALIZE_CLAZZ } only deserialize clazz - only one part . < / li > <li > If mask < = { @link RpcDeserializeLevel#DESERIALIZE_HEADER } deserialize clazz and header - two parts . < / li > <li > If mask < = { @link RpcDeserializeLevel#DESERIALIZE_ALL } deserialize clazz header and content - all three parts . < / li > < / ol > [CODESPLIT] public void deserialize ( long mask ) throws DeserializationException { if ( mask <= RpcDeserializeLevel . DESERIALIZE_CLAZZ ) { this . deserializeClazz ( ) ; } else if ( mask <= RpcDeserializeLevel . DESERIALIZE_HEADER ) { this . deserializeClazz ( ) ; this . deserializeHeader ( this . getInvokeContext ( ) ) ; } else if ( mask <= RpcDeserializeLevel . DESERIALIZE_ALL ) { this . deserialize ( ) ; } }


Input: Getter method for property <tt > customSerializer< / tt > . [CODESPLIT] public CustomSerializer getCustomSerializer ( ) { if ( this . customSerializer != null ) { return customSerializer ; } if ( this . requestClass != null ) { this . customSerializer = CustomSerializerManager . getCustomSerializer ( this . requestClass ) ; } if ( this . customSerializer == null ) { this . customSerializer = CustomSerializerManager . getCustomSerializer ( this . getCmdCode ( ) ) ; } return this . customSerializer ; }


Input: Setter method for property <tt > listener< / tt > . [CODESPLIT] public void setConnectionEventListener ( ConnectionEventListener listener ) { if ( listener != null ) { this . eventListener = listener ; if ( this . eventExecutor == null ) { this . eventExecutor = new ConnectionEventExecutor ( ) ; } } }


Input: print info log [CODESPLIT] private void infoLog ( String format , String addr ) { if ( logger . isInfoEnabled ( ) ) { if ( StringUtils . isNotEmpty ( addr ) ) { logger . info ( format , addr ) ; } else { logger . info ( format , "UNKNOWN-ADDR" ) ; } } }


Input: whether this request already timeout [CODESPLIT] public boolean isRequestTimeout ( ) { if ( this . timeout > 0 && ( this . rpcCommandType != RpcCommandType . REQUEST_ONEWAY ) && ( System . currentTimeMillis ( ) - this . arriveTimestamp ) > this . timeout ) { return true ; } return false ; }


Input: Get user processor for class name . [CODESPLIT] public UserProcessor < ? > getUserProcessor ( String className ) { return StringUtils . isBlank ( className ) ? null : this . userProcessors . get ( className ) ; }


Input: get one connection randomly [CODESPLIT] private Connection randomGet ( List < Connection > conns ) { if ( null == conns || conns . isEmpty ( ) ) { return null ; } int size = conns . size ( ) ; int tries = 0 ; Connection result = null ; while ( ( result == null || ! result . isFine ( ) ) && tries ++ < MAX_TIMES ) { result = conns . get ( this . random . nextInt ( size ) ) ; } if ( result != null && ! result . isFine ( ) ) { result = null ; } return result ; }


Input: Getter method for property <tt > customSerializer< / tt > . [CODESPLIT] public CustomSerializer getCustomSerializer ( ) { if ( this . customSerializer != null ) { return customSerializer ; } if ( this . responseClass != null ) { this . customSerializer = CustomSerializerManager . getCustomSerializer ( this . responseClass ) ; } if ( this . customSerializer == null ) { this . customSerializer = CustomSerializerManager . getCustomSerializer ( this . getCmdCode ( ) ) ; } return this . customSerializer ; }


Input: get [CODESPLIT] @ SuppressWarnings ( "unchecked" ) public < T > T get ( String key ) { return ( T ) this . context . get ( key ) ; }


Input: get and use default if not found [CODESPLIT] @ SuppressWarnings ( "unchecked" ) public < T > T get ( String key , T defaultIfNotFound ) { return this . context . get ( key ) != null ? ( T ) this . context . get ( key ) : defaultIfNotFound ; }


Input: Get property value according to property key [CODESPLIT] public String getProperty ( String key ) { if ( properties == null ) { return null ; } return properties . getProperty ( key ) ; }


Input: Compute CRC32 code for byte [] . [CODESPLIT] public static final int crc32 ( byte [ ] array , int offset , int length ) { CRC32 crc32 = CRC_32_THREAD_LOCAL . get ( ) ; crc32 . update ( array , offset , length ) ; int ret = ( int ) crc32 . getValue ( ) ; crc32 . reset ( ) ; return ret ; }


Input: Analyze the response command and generate the response object . [CODESPLIT] public static Object resolveResponseObject ( ResponseCommand responseCommand , String addr ) throws RemotingException { preProcess ( responseCommand , addr ) ; if ( responseCommand . getResponseStatus ( ) == ResponseStatus . SUCCESS ) { return toResponseObject ( responseCommand ) ; } else { String msg = String . format ( "Rpc invocation exception: %s, the address is %s, id=%s" , responseCommand . getResponseStatus ( ) , addr , responseCommand . getId ( ) ) ; logger . warn ( msg ) ; if ( responseCommand . getCause ( ) != null ) { throw new InvokeException ( msg , responseCommand . getCause ( ) ) ; } else { throw new InvokeException ( msg + ", please check the server log for more." ) ; } } }


Input: Convert remoting response command to application response object . [CODESPLIT] private static Object toResponseObject ( ResponseCommand responseCommand ) throws CodecException { RpcResponseCommand response = ( RpcResponseCommand ) responseCommand ; response . deserialize ( ) ; return response . getResponseObject ( ) ; }


Input: Convert remoting response command to throwable if it is a throwable otherwise return null . [CODESPLIT] private static Throwable toThrowable ( ResponseCommand responseCommand ) throws CodecException { RpcResponseCommand resp = ( RpcResponseCommand ) responseCommand ; resp . deserialize ( ) ; Object ex = resp . getResponseObject ( ) ; if ( ex != null && ex instanceof Throwable ) { return ( Throwable ) ex ; } return null ; }


Input: Detail your error msg with the error msg returned from response command [CODESPLIT] private static String detailErrMsg ( String clientErrMsg , ResponseCommand responseCommand ) { RpcResponseCommand resp = ( RpcResponseCommand ) responseCommand ; if ( StringUtils . isNotBlank ( resp . getErrorMsg ( ) ) ) { return String . format ( "%s, ServerErrorMsg:%s" , clientErrMsg , resp . getErrorMsg ( ) ) ; } else { return String . format ( "%s, ServerErrorMsg:null" , clientErrMsg ) ; } }


Input: create server exception using error msg and fill the stack trace using the stack trace of throwable . [CODESPLIT] private RpcServerException createServerException ( Throwable t , String errMsg ) { String formattedErrMsg = String . format ( "[Server]OriginErrorMsg: %s: %s. AdditionalErrorMsg: %s" , t . getClass ( ) . getName ( ) , t . getMessage ( ) , errMsg ) ; RpcServerException e = new RpcServerException ( formattedErrMsg ) ; e . setStackTrace ( t . getStackTrace ( ) ) ; return e ; }


Input: print trace log [CODESPLIT] public static void printConnectionTraceLog ( Logger logger , String traceId , InvokeContext invokeContext ) { String sourceIp = invokeContext . get ( InvokeContext . CLIENT_LOCAL_IP ) ; Integer sourcePort = invokeContext . get ( InvokeContext . CLIENT_LOCAL_PORT ) ; String targetIp = invokeContext . get ( InvokeContext . CLIENT_REMOTE_IP ) ; Integer targetPort = invokeContext . get ( InvokeContext . CLIENT_REMOTE_PORT ) ; StringBuilder logMsg = new StringBuilder ( ) ; logMsg . append ( traceId ) . append ( "," ) ; logMsg . append ( sourceIp ) . append ( "," ) ; logMsg . append ( sourcePort ) . append ( "," ) ; logMsg . append ( targetIp ) . append ( "," ) ; logMsg . append ( targetPort ) ; if ( logger . isInfoEnabled ( ) ) { logger . info ( logMsg . toString ( ) ) ; } }


Input: Create the right event loop according to current platform and system property fallback to NIO when epoll not enabled . [CODESPLIT] public static EventLoopGroup newEventLoopGroup ( int nThreads , ThreadFactory threadFactory ) { return epollEnabled ? new EpollEventLoopGroup ( nThreads , threadFactory ) : new NioEventLoopGroup ( nThreads , threadFactory ) ; }


Input: Use { [CODESPLIT] public static void enableTriggeredMode ( ServerBootstrap serverBootstrap ) { if ( epollEnabled ) { if ( ConfigManager . netty_epoll_lt_enabled ( ) ) { serverBootstrap . childOption ( EpollChannelOption . EPOLL_MODE , EpollMode . LEVEL_TRIGGERED ) ; } else { serverBootstrap . childOption ( EpollChannelOption . EPOLL_MODE , EpollMode . EDGE_TRIGGERED ) ; } } }


Input: Start! [CODESPLIT] public void start ( ) { scheduledService . scheduleWithFixedDelay ( new Runnable ( ) { @ Override public void run ( ) { for ( Scannable scanned : scanList ) { try { scanned . scan ( ) ; } catch ( Throwable t ) { logger . error ( "Exception caught when scannings." , t ) ; } } } } , 10000 , 10000 , TimeUnit . MILLISECONDS ) ; }


Input: Parse the remote address of the channel . [CODESPLIT] public static String parseRemoteAddress ( final Channel channel ) { if ( null == channel ) { return StringUtils . EMPTY ; } final SocketAddress remote = channel . remoteAddress ( ) ; return doParse ( remote != null ? remote . toString ( ) . trim ( ) : StringUtils . EMPTY ) ; }


Input: Parse the local address of the channel . [CODESPLIT] public static String parseLocalAddress ( final Channel channel ) { if ( null == channel ) { return StringUtils . EMPTY ; } final SocketAddress local = channel . localAddress ( ) ; return doParse ( local != null ? local . toString ( ) . trim ( ) : StringUtils . EMPTY ) ; }


Input: Parse the remote host ip of the channel . [CODESPLIT] public static String parseRemoteIP ( final Channel channel ) { if ( null == channel ) { return StringUtils . EMPTY ; } final InetSocketAddress remote = ( InetSocketAddress ) channel . remoteAddress ( ) ; if ( remote != null ) { return remote . getAddress ( ) . getHostAddress ( ) ; } return StringUtils . EMPTY ; }


Input: Parse the remote hostname of the channel . [CODESPLIT] public static String parseRemoteHostName ( final Channel channel ) { if ( null == channel ) { return StringUtils . EMPTY ; } final InetSocketAddress remote = ( InetSocketAddress ) channel . remoteAddress ( ) ; if ( remote != null ) { return remote . getAddress ( ) . getHostName ( ) ; } return StringUtils . EMPTY ; }


Input: Parse the local host ip of the channel . [CODESPLIT] public static String parseLocalIP ( final Channel channel ) { if ( null == channel ) { return StringUtils . EMPTY ; } final InetSocketAddress local = ( InetSocketAddress ) channel . localAddress ( ) ; if ( local != null ) { return local . getAddress ( ) . getHostAddress ( ) ; } return StringUtils . EMPTY ; }


Input: Parse the remote host port of the channel . [CODESPLIT] public static int parseRemotePort ( final Channel channel ) { if ( null == channel ) { return - 1 ; } final InetSocketAddress remote = ( InetSocketAddress ) channel . remoteAddress ( ) ; if ( remote != null ) { return remote . getPort ( ) ; } return - 1 ; }


Input: Parse the local host port of the channel . [CODESPLIT] public static int parseLocalPort ( final Channel channel ) { if ( null == channel ) { return - 1 ; } final InetSocketAddress local = ( InetSocketAddress ) channel . localAddress ( ) ; if ( local != null ) { return local . getPort ( ) ; } return - 1 ; }


Input: Parse the socket address omit the leading / if present . [CODESPLIT] public static String parseSocketAddressToString ( SocketAddress socketAddress ) { if ( socketAddress != null ) { return doParse ( socketAddress . toString ( ) . trim ( ) ) ; } return StringUtils . EMPTY ; }


Input: Parse the host ip of socket address . [CODESPLIT] public static String parseSocketAddressToHostIp ( SocketAddress socketAddress ) { final InetSocketAddress addrs = ( InetSocketAddress ) socketAddress ; if ( addrs != null ) { InetAddress addr = addrs . getAddress ( ) ; if ( null != addr ) { return addr . getHostAddress ( ) ; } } return StringUtils . EMPTY ; }


Input: <ol > <li > if an address starts with a / skip it . <li > if an address contains a / substring it . < / ol > [CODESPLIT] private static String doParse ( String addr ) { if ( StringUtils . isBlank ( addr ) ) { return StringUtils . EMPTY ; } if ( addr . charAt ( 0 ) == ' ' ) { return addr . substring ( 1 ) ; } else { int len = addr . length ( ) ; for ( int i = 1 ; i < len ; ++ i ) { if ( addr . charAt ( i ) == ' ' ) { return addr . substring ( i + 1 ) ; } } return addr ; } }


Input: add a connection [CODESPLIT] public void add ( Connection connection ) { markAccess ( ) ; if ( null == connection ) { return ; } boolean res = this . conns . addIfAbsent ( connection ) ; if ( res ) { connection . increaseRef ( ) ; } }


Input: removeAndTryClose a connection [CODESPLIT] public void removeAndTryClose ( Connection connection ) { if ( null == connection ) { return ; } boolean res = this . conns . remove ( connection ) ; if ( res ) { connection . decreaseRef ( ) ; } if ( connection . noRef ( ) ) { connection . close ( ) ; } }


Input: get a connection [CODESPLIT] public Connection get ( ) { markAccess ( ) ; if ( null != this . conns ) { List < Connection > snapshot = new ArrayList < Connection > ( this . conns ) ; if ( snapshot . size ( ) > 0 ) { return this . strategy . select ( snapshot ) ; } else { return null ; } } else { return null ; } }


Input: Register custom serializer for class name . [CODESPLIT] public static void registerCustomSerializer ( String className , CustomSerializer serializer ) { CustomSerializer prevSerializer = classCustomSerializer . putIfAbsent ( className , serializer ) ; if ( prevSerializer != null ) { throw new RuntimeException ( "CustomSerializer has been registered for class: " + className + ", the custom serializer is: " + prevSerializer . getClass ( ) . getName ( ) ) ; } }


Input: Get the custom serializer for class name . [CODESPLIT] public static CustomSerializer getCustomSerializer ( String className ) { if ( ! classCustomSerializer . isEmpty ( ) ) { return classCustomSerializer . get ( className ) ; } return null ; }


Input: Register custom serializer for command code . [CODESPLIT] public static void registerCustomSerializer ( CommandCode code , CustomSerializer serializer ) { CustomSerializer prevSerializer = commandCustomSerializer . putIfAbsent ( code , serializer ) ; if ( prevSerializer != null ) { throw new RuntimeException ( "CustomSerializer has been registered for command code: " + code + ", the custom serializer is: " + prevSerializer . getClass ( ) . getName ( ) ) ; } }


Input: Get the custom serializer for command code . [CODESPLIT] public static CustomSerializer getCustomSerializer ( CommandCode code ) { if ( ! commandCustomSerializer . isEmpty ( ) ) { return commandCustomSerializer . get ( code ) ; } return null ; }


Input: Start schedule task [CODESPLIT] public void start ( ) { /** initial delay to execute schedule task, unit: ms */ long initialDelay = ConfigManager . conn_monitor_initial_delay ( ) ; /** period of schedule task, unit: ms*/ long period = ConfigManager . conn_monitor_period ( ) ; this . executor = new ScheduledThreadPoolExecutor ( 1 , new NamedThreadFactory ( "ConnectionMonitorThread" , true ) , new ThreadPoolExecutor . AbortPolicy ( ) ) ; MonitorTask monitorTask = new MonitorTask ( ) ; this . executor . scheduleAtFixedRate ( monitorTask , initialDelay , period , TimeUnit . MILLISECONDS ) ; }


Input: Notice : only { @link GlobalSwitch#SERVER_MANAGE_CONNECTION_SWITCH } switch on will close all connections . [CODESPLIT] @ Override protected boolean doStop ( ) { if ( null != this . channelFuture ) { this . channelFuture . channel ( ) . close ( ) ; } if ( this . switches ( ) . isOn ( GlobalSwitch . SERVER_SYNC_STOP ) ) { this . bossGroup . shutdownGracefully ( ) . awaitUninterruptibly ( ) ; } else { this . bossGroup . shutdownGracefully ( ) ; } if ( this . switches ( ) . isOn ( GlobalSwitch . SERVER_MANAGE_CONNECTION_SWITCH ) && null != this . connectionManager ) { this . connectionManager . removeAll ( ) ; logger . warn ( "Close all connections from server side!" ) ; } logger . warn ( "Rpc Server stopped!" ) ; return true ; }


Input: One way invocation with a { @link InvokeContext } common api notice please see { @link #oneway ( String Object ) } [CODESPLIT] public void oneway ( final String addr , final Object request , final InvokeContext invokeContext ) throws RemotingException , InterruptedException { check ( ) ; this . rpcRemoting . oneway ( addr , request , invokeContext ) ; }


Input:
One way invocation using a parsed { @link Url }

 Notice :

  DO NOT modify the request object concurrently when this method is called .

 When do invocation use the parsed { @link Url } to find a available client connection if none then throw exception

 [CODESPLIT] public void oneway ( final Url url , final Object request ) throws RemotingException , InterruptedException { check ( ) ; this . rpcRemoting . oneway ( url , request , null ) ; }


Input: One way invocation with a { @link InvokeContext } common api notice please see { @link #oneway ( Url Object ) } [CODESPLIT] public void oneway ( final Url url , final Object request , final InvokeContext invokeContext ) throws RemotingException , InterruptedException { check ( ) ; this . rpcRemoting . oneway ( url , request , invokeContext ) ; }


Input:
Future invocation using a string address address format example - 127 . 0 . 0 . 1 : 12200?key1 = value1&key2 = value2
 You can get result use the returned { @link RpcResponseFuture } .
 Notice :

  DO NOT modify the request object concurrently when this method is called .

 When do invocation use the string address to find a available client connection if none then throw exception

 Unlike rpc client address arguments takes no effect here for rpc server will not create connection .

 [CODESPLIT] public RpcResponseFuture invokeWithFuture ( final String addr , final Object request , final int timeoutMillis ) throws RemotingException , InterruptedException { check ( ) ; return this . rpcRemoting . invokeWithFuture ( addr , request , null , timeoutMillis ) ; }


Input: Future invocation with a { @link InvokeContext } common api notice please see { @link #invokeWithFuture ( String Object int ) } [CODESPLIT] public RpcResponseFuture invokeWithFuture ( final String addr , final Object request , final InvokeContext invokeContext , final int timeoutMillis ) throws RemotingException , InterruptedException { check ( ) ; return this . rpcRemoting . invokeWithFuture ( addr , request , invokeContext , timeoutMillis ) ; }


Input:
Future invocation using a parsed { @link Url }
 You can get result use the returned { @link RpcResponseFuture } .
 Notice :

  DO NOT modify the request object concurrently when this method is called .

 When do invocation use the parsed { @link Url } to find a available client connection if none then throw exception

 [CODESPLIT] public RpcResponseFuture invokeWithFuture ( final Url url , final Object request , final int timeoutMillis ) throws RemotingException , InterruptedException { check ( ) ; return this . rpcRemoting . invokeWithFuture ( url , request , null , timeoutMillis ) ; }


Input: Future invocation with a { @link InvokeContext } common api notice please see { @link #invokeWithFuture ( Url Object int ) } [CODESPLIT] public RpcResponseFuture invokeWithFuture ( final Url url , final Object request , final InvokeContext invokeContext , final int timeoutMillis ) throws RemotingException , InterruptedException { check ( ) ; return this . rpcRemoting . invokeWithFuture ( url , request , invokeContext , timeoutMillis ) ; }


Input: Future invocation with a { @link InvokeContext } common api notice please see { @link #invokeWithFuture ( Connection Object int ) } [CODESPLIT] public RpcResponseFuture invokeWithFuture ( final Connection conn , final Object request , final InvokeContext invokeContext , final int timeoutMillis ) throws RemotingException { return this . rpcRemoting . invokeWithFuture ( conn , request , invokeContext , timeoutMillis ) ; }


Input:
Callback invocation using a string address address format example - 127 . 0 . 0 . 1 : 12200?key1 = value1&key2 = value2
 You can specify an implementation of { @link InvokeCallback } to get the result .
 Notice :

  DO NOT modify the request object concurrently when this method is called .

 When do invocation use the string address to find a available client connection if none then throw exception

 Unlike rpc client address arguments takes no effect here for rpc server will not create connection .

 [CODESPLIT] public void invokeWithCallback ( final String addr , final Object request , final InvokeCallback invokeCallback , final int timeoutMillis ) throws RemotingException , InterruptedException { check ( ) ; this . rpcRemoting . invokeWithCallback ( addr , request , null , invokeCallback , timeoutMillis ) ; }


Input: check whether a client address connected [CODESPLIT] public boolean isConnected ( String remoteAddr ) { Url url = this . rpcRemoting . addressParser . parse ( remoteAddr ) ; return this . isConnected ( url ) ; }


Input: check whether a { @link Url } connected [CODESPLIT] public boolean isConnected ( Url url ) { Connection conn = this . rpcRemoting . connectionManager . get ( url . getUniqueKey ( ) ) ; if ( null != conn ) { return conn . isFine ( ) ; } return false ; }


Input: init netty write buffer water mark [CODESPLIT] private void initWriteBufferWaterMark ( ) { int lowWaterMark = this . netty_buffer_low_watermark ( ) ; int highWaterMark = this . netty_buffer_high_watermark ( ) ; if ( lowWaterMark > highWaterMark ) { throw new IllegalArgumentException ( String . format ( "[server side] bolt netty high water mark {%s} should not be smaller than low water mark {%s} bytes)" , highWaterMark , lowWaterMark ) ) ; } else { logger . warn ( "[server side] bolt netty low water mark is {} bytes, high water mark is {} bytes" , lowWaterMark , highWaterMark ) ; } this . bootstrap . childOption ( ChannelOption . WRITE_BUFFER_WATER_MARK , new WriteBufferWaterMark ( lowWaterMark , highWaterMark ) ) ; }


Input: Check if the provided BytebBuffer contains a valid utf8 encoded string . <p > Using the algorithm Flexible and Economical UTF - 8 Decoder by Björn Höhrmann ( http : // bjoern . hoehrmann . de / utf - 8 / decoder / dfa / ) [CODESPLIT] public static boolean isValidUTF8 ( ByteBuffer data , int off ) { int len = data . remaining ( ) ; if ( len < off ) { return false ; } int state = 0 ; for ( int i = off ; i < len ; ++ i ) { state = utf8d [ 256 + ( state << 4 ) + utf8d [ ( 0xff & data . get ( i ) ) ] ] ; if ( state == 1 ) { return false ; } } return true ; }


Input: Get a frame with a specific opcode [CODESPLIT] public static FramedataImpl1 get ( Opcode opcode ) { if ( opcode == null ) { throw new IllegalArgumentException ( "Supplied opcode cannot be null" ) ; } switch ( opcode ) { case PING : return new PingFrame ( ) ; case PONG : return new PongFrame ( ) ; case TEXT : return new TextFrame ( ) ; case BINARY : return new BinaryFrame ( ) ; case CLOSING : return new CloseFrame ( ) ; case CONTINUOUS : return new ContinuousFrame ( ) ; default : throw new IllegalArgumentException ( "Supplied opcode is invalid" ) ; } }


Input: Returns whether the whole outQueue has been flushed [CODESPLIT] public static boolean batch ( WebSocketImpl ws , ByteChannel sockchannel ) throws IOException { if ( ws == null ) { return false ; } ByteBuffer buffer = ws . outQueue . peek ( ) ; WrappedByteChannel c = null ; if ( buffer == null ) { if ( sockchannel instanceof WrappedByteChannel ) { c = ( WrappedByteChannel ) sockchannel ; if ( c . isNeedWrite ( ) ) { c . writeMore ( ) ; } } } else { do { // FIXME writing as much as possible is unfair!! /*int written = */ sockchannel . write ( buffer ) ; if ( buffer . remaining ( ) > 0 ) { return false ; } else { ws . outQueue . poll ( ) ; // Buffer finished. Remove it. buffer = ws . outQueue . peek ( ) ; } } while ( buffer != null ) ; } if ( ws . outQueue . isEmpty ( ) && ws . isFlushAndClose ( ) && ws . getDraft ( ) != null && ws . getDraft ( ) . getRole ( ) != null && ws . getDraft ( ) . getRole ( ) == Role . SERVER ) { // ws . closeConnection ( ) ; } return c == null || ! ( ( WrappedByteChannel ) sockchannel ) . isNeedWrite ( ) ; }


Input: Set the close code for this close frame [CODESPLIT] public void setCode ( int code ) { this . code = code ; // CloseFrame.TLS_ERROR is not allowed to be transfered over the wire if ( code == CloseFrame . TLS_ERROR ) { this . code = CloseFrame . NOCODE ; this . reason = "" ; } updatePayload ( ) ; }


Input: Validate the payload to valid utf8 [CODESPLIT] private void validateUtf8 ( ByteBuffer payload , int mark ) throws InvalidDataException { try { payload . position ( payload . position ( ) + 2 ) ; reason = Charsetfunctions . stringUtf8 ( payload ) ; } catch ( IllegalArgumentException e ) { throw new InvalidDataException ( CloseFrame . NO_UTF8 ) ; } finally { payload . position ( mark ) ; } }


Input: Update the payload to represent the close code and the reason [CODESPLIT] private void updatePayload ( ) { byte [ ] by = Charsetfunctions . utf8Bytes ( reason ) ; ByteBuffer buf = ByteBuffer . allocate ( 4 ) ; buf . putInt ( code ) ; buf . position ( 2 ) ; ByteBuffer pay = ByteBuffer . allocate ( 2 + by . length ) ; pay . put ( buf ) ; pay . put ( by ) ; pay . rewind ( ) ; super . setPayload ( pay ) ; }


Input: Check if the requested protocol is part of this draft [CODESPLIT] private HandshakeState containsRequestedProtocol ( String requestedProtocol ) { for ( IProtocol knownProtocol : knownProtocols ) { if ( knownProtocol . acceptProvidedProtocol ( requestedProtocol ) ) { protocol = knownProtocol ; log . trace ( "acceptHandshake - Matching protocol found: {}" , protocol ) ; return HandshakeState . MATCHED ; } } return HandshakeState . NOT_MATCHED ; }


Input: Translate the buffer depending when it has an extended payload length ( 126 or 127 ) [CODESPLIT] private TranslatedPayloadMetaData translateSingleFramePayloadLength ( ByteBuffer buffer , Opcode optcode , int oldPayloadlength , int maxpacketsize , int oldRealpacketsize ) throws InvalidFrameException , IncompleteException , LimitExceededException { int payloadlength = oldPayloadlength , realpacketsize = oldRealpacketsize ; if ( optcode == Opcode . PING || optcode == Opcode . PONG || optcode == Opcode . CLOSING ) { log . trace ( "Invalid frame: more than 125 octets" ) ; throw new InvalidFrameException ( "more than 125 octets" ) ; } if ( payloadlength == 126 ) { realpacketsize += 2 ; // additional length bytes translateSingleFrameCheckPacketSize ( maxpacketsize , realpacketsize ) ; byte [ ] sizebytes = new byte [ 3 ] ; sizebytes [ 1 ] = buffer . get ( /*1 + 1*/ ) ; sizebytes [ 2 ] = buffer . get ( /*1 + 2*/ ) ; payloadlength = new BigInteger ( sizebytes ) . intValue ( ) ; } else { realpacketsize += 8 ; // additional length bytes translateSingleFrameCheckPacketSize ( maxpacketsize , realpacketsize ) ; byte [ ] bytes = new byte [ 8 ] ; for ( int i = 0 ; i < 8 ; i ++ ) { bytes [ i ] = buffer . get ( /*1 + i*/ ) ; } long length = new BigInteger ( bytes ) . longValue ( ) ; translateSingleFrameCheckLengthLimit ( length ) ; payloadlength = ( int ) length ; } return new TranslatedPayloadMetaData ( payloadlength , realpacketsize ) ; }


Input: Check if the frame size exceeds the allowed limit [CODESPLIT] private void translateSingleFrameCheckLengthLimit ( long length ) throws LimitExceededException { if ( length > Integer . MAX_VALUE ) { log . trace ( "Limit exedeed: Payloadsize is to big..." ) ; throw new LimitExceededException ( "Payloadsize is to big..." ) ; } if ( length > maxFrameSize ) { log . trace ( "Payload limit reached. Allowed: {} Current: {}" , maxFrameSize , length ) ; throw new LimitExceededException ( "Payload limit reached." , maxFrameSize ) ; } if ( length < 0 ) { log . trace ( "Limit underflow: Payloadsize is to little..." ) ; throw new LimitExceededException ( "Payloadsize is to little..." ) ; } }


Input: Check if the max packet size is smaller than the real packet size [CODESPLIT] private void translateSingleFrameCheckPacketSize ( int maxpacketsize , int realpacketsize ) throws IncompleteException { if ( maxpacketsize < realpacketsize ) { log . trace ( "Incomplete frame: maxpacketsize < realpacketsize" ) ; throw new IncompleteException ( realpacketsize ) ; } }


Input: Generate a final key from a input string [CODESPLIT] private String generateFinalKey ( String in ) { String seckey = in . trim ( ) ; String acc = seckey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" ; MessageDigest sh1 ; try { sh1 = MessageDigest . getInstance ( "SHA1" ) ; } catch ( NoSuchAlgorithmException e ) { throw new IllegalStateException ( e ) ; } return Base64 . encodeBytes ( sh1 . digest ( acc . getBytes ( ) ) ) ; }


Input: Process the frame if it is a continuous frame or the fin bit is not set [CODESPLIT] private void processFrameContinuousAndNonFin ( WebSocketImpl webSocketImpl , Framedata frame , Opcode curop ) throws InvalidDataException { if ( curop != Opcode . CONTINUOUS ) { processFrameIsNotFin ( frame ) ; } else if ( frame . isFin ( ) ) { processFrameIsFin ( webSocketImpl , frame ) ; } else if ( currentContinuousFrame == null ) { log . error ( "Protocol error: Continuous frame sequence was not started." ) ; throw new InvalidDataException ( CloseFrame . PROTOCOL_ERROR , "Continuous frame sequence was not started." ) ; } //Check if the whole payload is valid utf8, when the opcode indicates a text if ( curop == Opcode . TEXT && ! Charsetfunctions . isValidUTF8 ( frame . getPayloadData ( ) ) ) { log . error ( "Protocol error: Payload is not UTF8" ) ; throw new InvalidDataException ( CloseFrame . NO_UTF8 ) ; } //Checking if the current continuous frame contains a correct payload with the other frames combined if ( curop == Opcode . CONTINUOUS && currentContinuousFrame != null ) { addToBufferList ( frame . getPayloadData ( ) ) ; } }


Input: Process the frame if it is a binary frame [CODESPLIT] private void processFrameBinary ( WebSocketImpl webSocketImpl , Framedata frame ) { try { webSocketImpl . getWebSocketListener ( ) . onWebsocketMessage ( webSocketImpl , frame . getPayloadData ( ) ) ; } catch ( RuntimeException e ) { logRuntimeException ( webSocketImpl , e ) ; } }


Input: Log the runtime exception to the specific WebSocketImpl [CODESPLIT] private void logRuntimeException ( WebSocketImpl webSocketImpl , RuntimeException e ) { log . error ( "Runtime exception during onWebsocketMessage" , e ) ; webSocketImpl . getWebSocketListener ( ) . onWebsocketError ( webSocketImpl , e ) ; }


Input: Process the frame if it is a text frame [CODESPLIT] private void processFrameText ( WebSocketImpl webSocketImpl , Framedata frame ) throws InvalidDataException { try { webSocketImpl . getWebSocketListener ( ) . onWebsocketMessage ( webSocketImpl , Charsetfunctions . stringUtf8 ( frame . getPayloadData ( ) ) ) ; } catch ( RuntimeException e ) { logRuntimeException ( webSocketImpl , e ) ; } }


Input: Process the frame if it is the last frame [CODESPLIT] private void processFrameIsFin ( WebSocketImpl webSocketImpl , Framedata frame ) throws InvalidDataException { if ( currentContinuousFrame == null ) { log . trace ( "Protocol error: Previous continuous frame sequence not completed." ) ; throw new InvalidDataException ( CloseFrame . PROTOCOL_ERROR , "Continuous frame sequence was not started." ) ; } addToBufferList ( frame . getPayloadData ( ) ) ; checkBufferLimit ( ) ; if ( currentContinuousFrame . getOpcode ( ) == Opcode . TEXT ) { ( ( FramedataImpl1 ) currentContinuousFrame ) . setPayload ( getPayloadFromByteBufferList ( ) ) ; ( ( FramedataImpl1 ) currentContinuousFrame ) . isValid ( ) ; try { webSocketImpl . getWebSocketListener ( ) . onWebsocketMessage ( webSocketImpl , Charsetfunctions . stringUtf8 ( currentContinuousFrame . getPayloadData ( ) ) ) ; } catch ( RuntimeException e ) { logRuntimeException ( webSocketImpl , e ) ; } } else if ( currentContinuousFrame . getOpcode ( ) == Opcode . BINARY ) { ( ( FramedataImpl1 ) currentContinuousFrame ) . setPayload ( getPayloadFromByteBufferList ( ) ) ; ( ( FramedataImpl1 ) currentContinuousFrame ) . isValid ( ) ; try { webSocketImpl . getWebSocketListener ( ) . onWebsocketMessage ( webSocketImpl , currentContinuousFrame . getPayloadData ( ) ) ; } catch ( RuntimeException e ) { logRuntimeException ( webSocketImpl , e ) ; } } currentContinuousFrame = null ; clearBufferList ( ) ; }


Input: Process the frame if it is not the last frame [CODESPLIT] private void processFrameIsNotFin ( Framedata frame ) throws InvalidDataException { if ( currentContinuousFrame != null ) { log . trace ( "Protocol error: Previous continuous frame sequence not completed." ) ; throw new InvalidDataException ( CloseFrame . PROTOCOL_ERROR , "Previous continuous frame sequence not completed." ) ; } currentContinuousFrame = frame ; addToBufferList ( frame . getPayloadData ( ) ) ; checkBufferLimit ( ) ; }


Input: Process the frame if it is a closing frame [CODESPLIT] private void processFrameClosing ( WebSocketImpl webSocketImpl , Framedata frame ) { int code = CloseFrame . NOCODE ; String reason = "" ; if ( frame instanceof CloseFrame ) { CloseFrame cf = ( CloseFrame ) frame ; code = cf . getCloseCode ( ) ; reason = cf . getMessage ( ) ; } if ( webSocketImpl . getReadyState ( ) == ReadyState . CLOSING ) { // complete the close handshake by disconnecting webSocketImpl . closeConnection ( code , reason , true ) ; } else { // echo close handshake if ( getCloseHandshakeType ( ) == CloseHandshakeType . TWOWAY ) webSocketImpl . close ( code , reason , true ) ; else webSocketImpl . flushAndClose ( code , reason , false ) ; } }


Input: Check the current size of the buffer and throw an exception if the size is bigger than the max allowed frame size [CODESPLIT] private void checkBufferLimit ( ) throws LimitExceededException { long totalSize = getByteBufferListSize ( ) ; if ( totalSize > maxFrameSize ) { clearBufferList ( ) ; log . trace ( "Payload limit reached. Allowed: {} Current: {}" , maxFrameSize , totalSize ) ; throw new LimitExceededException ( maxFrameSize ) ; } }


Input: Method to generate a full bytebuffer out of all the fragmented frame payload [CODESPLIT] private ByteBuffer getPayloadFromByteBufferList ( ) throws LimitExceededException { long totalSize = 0 ; ByteBuffer resultingByteBuffer ; synchronized ( byteBufferList ) { for ( ByteBuffer buffer : byteBufferList ) { totalSize += buffer . limit ( ) ; } checkBufferLimit ( ) ; resultingByteBuffer = ByteBuffer . allocate ( ( int ) totalSize ) ; for ( ByteBuffer buffer : byteBufferList ) { resultingByteBuffer . put ( buffer ) ; } } resultingByteBuffer . flip ( ) ; return resultingByteBuffer ; }


Input: Get the current size of the resulting bytebuffer in the bytebuffer list [CODESPLIT] private long getByteBufferListSize ( ) { long totalSize = 0 ; synchronized ( byteBufferList ) { for ( ByteBuffer buffer : byteBufferList ) { totalSize += buffer . limit ( ) ; } } return totalSize ; }


Input: Implements the handshake protocol between two peers required for the establishment of the SSL / TLS connection . During the handshake encryption configuration information - such as the list of available cipher suites - will be exchanged and if the handshake is successful will lead to an established SSL / TLS session . <p > <p / > A typical handshake will usually contain the following steps : <p > <ul > <li > 1 . wrap : ClientHello< / li > <li > 2 . unwrap : ServerHello / Cert / ServerHelloDone< / li > <li > 3 . wrap : ClientKeyExchange< / li > <li > 4 . wrap : ChangeCipherSpec< / li > <li > 5 . wrap : Finished< / li > <li > 6 . unwrap : ChangeCipherSpec< / li > <li > 7 . unwrap : Finished< / li > < / ul > <p / > Handshake is also used during the end of the session in order to properly close the connection between the two peers . A proper connection close will typically include the one peer sending a CLOSE message to another and then wait for the other s CLOSE message to close the transport link . The other peer from his perspective would read a CLOSE message from his peer and then enter the handshake procedure to send his own CLOSE message as well . [CODESPLIT] private boolean doHandshake ( ) throws IOException { SSLEngineResult result ; HandshakeStatus handshakeStatus ; // NioSslPeer's fields myAppData and peerAppData are supposed to be large enough to hold all message data the peer // will send and expects to receive from the other peer respectively. Since the messages to be exchanged will usually be less // than 16KB long the capacity of these fields should also be smaller. Here we initialize these two local buffers // to be used for the handshake, while keeping client's buffers at the same size. int appBufferSize = engine . getSession ( ) . getApplicationBufferSize ( ) ; myAppData = ByteBuffer . allocate ( appBufferSize ) ; peerAppData = ByteBuffer . allocate ( appBufferSize ) ; myNetData . clear ( ) ; peerNetData . clear ( ) ; handshakeStatus = engine . getHandshakeStatus ( ) ; boolean handshakeComplete = false ; while ( ! handshakeComplete ) { switch ( handshakeStatus ) { case FINISHED : handshakeComplete = ! this . peerNetData . hasRemaining ( ) ; if ( handshakeComplete ) return true ; socketChannel . write ( this . peerNetData ) ; break ; case NEED_UNWRAP : if ( socketChannel . read ( peerNetData ) < 0 ) { if ( engine . isInboundDone ( ) && engine . isOutboundDone ( ) ) { return false ; } try { engine . closeInbound ( ) ; } catch ( SSLException e ) { //Ignore, cant do anything against this exception } engine . closeOutbound ( ) ; // After closeOutbound the engine will be set to WRAP state, in order to try to send a close message to the client. handshakeStatus = engine . getHandshakeStatus ( ) ; break ; } peerNetData . flip ( ) ; try { result = engine . unwrap ( peerNetData , peerAppData ) ; peerNetData . compact ( ) ; handshakeStatus = result . getHandshakeStatus ( ) ; } catch ( SSLException sslException ) { engine . closeOutbound ( ) ; handshakeStatus = engine . getHandshakeStatus ( ) ; break ; } switch ( result . getStatus ( ) ) { case OK : break ; case BUFFER_OVERFLOW : // Will occur when peerAppData's capacity is smaller than the data derived from peerNetData's unwrap. peerAppData = enlargeApplicationBuffer ( peerAppData ) ; break ; case BUFFER_UNDERFLOW : // Will occur either when no data was read from the peer or when the peerNetData buffer was too small to hold all peer's data. peerNetData = handleBufferUnderflow ( peerNetData ) ; break ; case CLOSED : if ( engine . isOutboundDone ( ) ) { return false ; } else { engine . closeOutbound ( ) ; handshakeStatus = engine . getHandshakeStatus ( ) ; break ; } default : throw new IllegalStateException ( "Invalid SSL status: " + result . getStatus ( ) ) ; } break ; case NEED_WRAP : myNetData . clear ( ) ; try { result = engine . wrap ( myAppData , myNetData ) ; handshakeStatus = result . getHandshakeStatus ( ) ; } catch ( SSLException sslException ) { engine . closeOutbound ( ) ; handshakeStatus = engine . getHandshakeStatus ( ) ; break ; } switch ( result . getStatus ( ) ) { case OK : myNetData . flip ( ) ; while ( myNetData . hasRemaining ( ) ) { socketChannel . write ( myNetData ) ; } break ; case BUFFER_OVERFLOW : // Will occur if there is not enough space in myNetData buffer to write all the data that would be generated by the method wrap. // Since myNetData is set to session's packet size we should not get to this point because SSLEngine is supposed // to produce messages smaller or equal to that, but a general handling would be the following: myNetData = enlargePacketBuffer ( myNetData ) ; break ; case BUFFER_UNDERFLOW : throw new SSLException ( "Buffer underflow occured after a wrap. I don't think we should ever get here." ) ; case CLOSED : try { myNetData . flip ( ) ; while ( myNetData . hasRemaining ( ) ) { socketChannel . write ( myNetData ) ; } // At this point the handshake status will probably be NEED_UNWRAP so we make sure that peerNetData is clear to read. peerNetData . clear ( ) ; } catch ( Exception e ) { handshakeStatus = engine . getHandshakeStatus ( ) ; } break ; default : throw new IllegalStateException ( "Invalid SSL status: " + result . getStatus ( ) ) ; } break ; case NEED_TASK : Runnable task ; while ( ( task = engine . getDelegatedTask ( ) ) != null ) { executor . execute ( task ) ; } handshakeStatus = engine . getHandshakeStatus ( ) ; break ; case NOT_HANDSHAKING : break ; default : throw new IllegalStateException ( "Invalid SSL status: " + handshakeStatus ) ; } } return true ; }


Input: Compares <code > sessionProposedCapacity<code > with buffer s capacity . If buffer s capacity is smaller returns a buffer with the proposed capacity . If it s equal or larger returns a buffer with capacity twice the size of the initial one . [CODESPLIT] private ByteBuffer enlargeBuffer ( ByteBuffer buffer , int sessionProposedCapacity ) { if ( sessionProposedCapacity > buffer . capacity ( ) ) { buffer = ByteBuffer . allocate ( sessionProposedCapacity ) ; } else { buffer = ByteBuffer . allocate ( buffer . capacity ( ) * 2 ) ; } return buffer ; }


Input: Handles { @link SSLEngineResult . Status#BUFFER_UNDERFLOW } . Will check if the buffer is already filled and if there is no space problem will return the same buffer so the client tries to read again . If the buffer is already filled will try to enlarge the buffer either to session s proposed size or to a larger capacity . A buffer underflow can happen only after an unwrap so the buffer will always be a peerNetData buffer . [CODESPLIT] private ByteBuffer handleBufferUnderflow ( ByteBuffer buffer ) { if ( engine . getSession ( ) . getPacketBufferSize ( ) < buffer . limit ( ) ) { return buffer ; } else { ByteBuffer replaceBuffer = enlargePacketBuffer ( buffer ) ; buffer . flip ( ) ; replaceBuffer . put ( buffer ) ; return replaceBuffer ; } }


Input: Checking the handshake for the role as server [CODESPLIT] private static HandshakeBuilder translateHandshakeHttpServer ( String [ ] firstLineTokens , String line ) throws InvalidHandshakeException { // translating/parsing the request from the CLIENT if ( ! "GET" . equalsIgnoreCase ( firstLineTokens [ 0 ] ) ) { throw new InvalidHandshakeException ( String . format ( "Invalid request method received: %s Status line: %s" , firstLineTokens [ 0 ] , line ) ) ; } if ( ! "HTTP/1.1" . equalsIgnoreCase ( firstLineTokens [ 2 ] ) ) { throw new InvalidHandshakeException ( String . format ( "Invalid status line received: %s Status line: %s" , firstLineTokens [ 2 ] , line ) ) ; } ClientHandshakeBuilder clienthandshake = new HandshakeImpl1Client ( ) ; clienthandshake . setResourceDescriptor ( firstLineTokens [ 1 ] ) ; return clienthandshake ; }


Input: Checking the handshake for the role as client [CODESPLIT] private static HandshakeBuilder translateHandshakeHttpClient ( String [ ] firstLineTokens , String line ) throws InvalidHandshakeException { // translating/parsing the response from the SERVER if ( ! "101" . equals ( firstLineTokens [ 1 ] ) ) { throw new InvalidHandshakeException ( String . format ( "Invalid status code received: %s Status line: %s" , firstLineTokens [ 1 ] , line ) ) ; } if ( ! "HTTP/1.1" . equalsIgnoreCase ( firstLineTokens [ 0 ] ) ) { throw new InvalidHandshakeException ( String . format ( "Invalid status line received: %s Status line: %s" , firstLineTokens [ 0 ] , line ) ) ; } HandshakeBuilder handshake = new HandshakeImpl1Server ( ) ; ServerHandshakeBuilder serverhandshake = ( ServerHandshakeBuilder ) handshake ; serverhandshake . setHttpStatus ( Short . parseShort ( firstLineTokens [ 1 ] ) ) ; serverhandshake . setHttpStatusMessage ( firstLineTokens [ 2 ] ) ; return handshake ; }


Input: Method to decode the provided ByteBuffer [CODESPLIT] public void decode ( ByteBuffer socketBuffer ) { assert ( socketBuffer . hasRemaining ( ) ) ; log . trace ( "process({}): ({})" , socketBuffer . remaining ( ) , ( socketBuffer . remaining ( ) > 1000 ? "too big to display" : new String ( socketBuffer . array ( ) , socketBuffer . position ( ) , socketBuffer . remaining ( ) ) ) ) ; if ( readyState != ReadyState . NOT_YET_CONNECTED ) { if ( readyState == ReadyState . OPEN ) { decodeFrames ( socketBuffer ) ; } } else { if ( decodeHandshake ( socketBuffer ) && ( ! isClosing ( ) && ! isClosed ( ) ) ) { assert ( tmpHandshakeBytes . hasRemaining ( ) != socketBuffer . hasRemaining ( ) || ! socketBuffer . hasRemaining ( ) ) ; // the buffers will never have remaining bytes at the same time if ( socketBuffer . hasRemaining ( ) ) { decodeFrames ( socketBuffer ) ; } else if ( tmpHandshakeBytes . hasRemaining ( ) ) { decodeFrames ( tmpHandshakeBytes ) ; } } } }


Input: Returns whether the handshake phase has is completed . In case of a broken handshake this will be never the case . [CODESPLIT] private boolean decodeHandshake ( ByteBuffer socketBufferNew ) { ByteBuffer socketBuffer ; if ( tmpHandshakeBytes . capacity ( ) == 0 ) { socketBuffer = socketBufferNew ; } else { if ( tmpHandshakeBytes . remaining ( ) < socketBufferNew . remaining ( ) ) { ByteBuffer buf = ByteBuffer . allocate ( tmpHandshakeBytes . capacity ( ) + socketBufferNew . remaining ( ) ) ; tmpHandshakeBytes . flip ( ) ; buf . put ( tmpHandshakeBytes ) ; tmpHandshakeBytes = buf ; } tmpHandshakeBytes . put ( socketBufferNew ) ; tmpHandshakeBytes . flip ( ) ; socketBuffer = tmpHandshakeBytes ; } socketBuffer . mark ( ) ; try { HandshakeState handshakestate ; try { if ( role == Role . SERVER ) { if ( draft == null ) { for ( Draft d : knownDrafts ) { d = d . copyInstance ( ) ; try { d . setParseMode ( role ) ; socketBuffer . reset ( ) ; Handshakedata tmphandshake = d . translateHandshake ( socketBuffer ) ; if ( ! ( tmphandshake instanceof ClientHandshake ) ) { log . trace ( "Closing due to wrong handshake" ) ; closeConnectionDueToWrongHandshake ( new InvalidDataException ( CloseFrame . PROTOCOL_ERROR , "wrong http function" ) ) ; return false ; } ClientHandshake handshake = ( ClientHandshake ) tmphandshake ; handshakestate = d . acceptHandshakeAsServer ( handshake ) ; if ( handshakestate == HandshakeState . MATCHED ) { resourceDescriptor = handshake . getResourceDescriptor ( ) ; ServerHandshakeBuilder response ; try { response = wsl . onWebsocketHandshakeReceivedAsServer ( this , d , handshake ) ; } catch ( InvalidDataException e ) { log . trace ( "Closing due to wrong handshake. Possible handshake rejection" , e ) ; closeConnectionDueToWrongHandshake ( e ) ; return false ; } catch ( RuntimeException e ) { log . error ( "Closing due to internal server error" , e ) ; wsl . onWebsocketError ( this , e ) ; closeConnectionDueToInternalServerError ( e ) ; return false ; } write ( d . createHandshake ( d . postProcessHandshakeResponseAsServer ( handshake , response ) ) ) ; draft = d ; open ( handshake ) ; return true ; } } catch ( InvalidHandshakeException e ) { // go on with an other draft } } if ( draft == null ) { log . trace ( "Closing due to protocol error: no draft matches" ) ; closeConnectionDueToWrongHandshake ( new InvalidDataException ( CloseFrame . PROTOCOL_ERROR , "no draft matches" ) ) ; } return false ; } else { // special case for multiple step handshakes Handshakedata tmphandshake = draft . translateHandshake ( socketBuffer ) ; if ( ! ( tmphandshake instanceof ClientHandshake ) ) { log . trace ( "Closing due to protocol error: wrong http function" ) ; flushAndClose ( CloseFrame . PROTOCOL_ERROR , "wrong http function" , false ) ; return false ; } ClientHandshake handshake = ( ClientHandshake ) tmphandshake ; handshakestate = draft . acceptHandshakeAsServer ( handshake ) ; if ( handshakestate == HandshakeState . MATCHED ) { open ( handshake ) ; return true ; } else { log . trace ( "Closing due to protocol error: the handshake did finally not match" ) ; close ( CloseFrame . PROTOCOL_ERROR , "the handshake did finally not match" ) ; } return false ; } } else if ( role == Role . CLIENT ) { draft . setParseMode ( role ) ; Handshakedata tmphandshake = draft . translateHandshake ( socketBuffer ) ; if ( ! ( tmphandshake instanceof ServerHandshake ) ) { log . trace ( "Closing due to protocol error: wrong http function" ) ; flushAndClose ( CloseFrame . PROTOCOL_ERROR , "wrong http function" , false ) ; return false ; } ServerHandshake handshake = ( ServerHandshake ) tmphandshake ; handshakestate = draft . acceptHandshakeAsClient ( handshakerequest , handshake ) ; if ( handshakestate == HandshakeState . MATCHED ) { try { wsl . onWebsocketHandshakeReceivedAsClient ( this , handshakerequest , handshake ) ; } catch ( InvalidDataException e ) { log . trace ( "Closing due to invalid data exception. Possible handshake rejection" , e ) ; flushAndClose ( e . getCloseCode ( ) , e . getMessage ( ) , false ) ; return false ; } catch ( RuntimeException e ) { log . error ( "Closing since client was never connected" , e ) ; wsl . onWebsocketError ( this , e ) ; flushAndClose ( CloseFrame . NEVER_CONNECTED , e . getMessage ( ) , false ) ; return false ; } open ( handshake ) ; return true ; } else { log . trace ( "Closing due to protocol error: draft {} refuses handshake" , draft ) ; close ( CloseFrame . PROTOCOL_ERROR , "draft " + draft + " refuses handshake" ) ; } } } catch ( InvalidHandshakeException e ) { log . trace ( "Closing due to invalid handshake" , e ) ; close ( e ) ; } } catch ( IncompleteHandshakeException e ) { if ( tmpHandshakeBytes . capacity ( ) == 0 ) { socketBuffer . reset ( ) ; int newsize = e . getPreferredSize ( ) ; if ( newsize == 0 ) { newsize = socketBuffer . capacity ( ) + 16 ; } else { assert ( e . getPreferredSize ( ) >= socketBuffer . remaining ( ) ) ; } tmpHandshakeBytes = ByteBuffer . allocate ( newsize ) ; tmpHandshakeBytes . put ( socketBufferNew ) ; // tmpHandshakeBytes.flip(); } else { tmpHandshakeBytes . position ( tmpHandshakeBytes . limit ( ) ) ; tmpHandshakeBytes . limit ( tmpHandshakeBytes . capacity ( ) ) ; } } return false ; }


Input: Close the connection if the received handshake was not correct [CODESPLIT] private void closeConnectionDueToWrongHandshake ( InvalidDataException exception ) { write ( generateHttpResponseDueToError ( 404 ) ) ; flushAndClose ( exception . getCloseCode ( ) , exception . getMessage ( ) , false ) ; }


Input: Close the connection if there was a server error by a RuntimeException [CODESPLIT] private void closeConnectionDueToInternalServerError ( RuntimeException exception ) { write ( generateHttpResponseDueToError ( 500 ) ) ; flushAndClose ( CloseFrame . NEVER_CONNECTED , exception . getMessage ( ) , false ) ; }


Input:
Generate a simple response for the corresponding endpoint to indicate some error [CODESPLIT] private ByteBuffer generateHttpResponseDueToError ( int errorCode ) { String errorCodeDescription ; switch ( errorCode ) { case 404 : errorCodeDescription = "404 WebSocket Upgrade Failure" ; break ; case 500 : default : errorCodeDescription = "500 Internal Server Error" ; } return ByteBuffer . wrap ( Charsetfunctions . asciiBytes ( "HTTP/1.1 " + errorCodeDescription + "\r\nContent-Type: text/html\nServer: TooTallNate Java-WebSocket\r\nContent-Length: " + ( 48 + errorCodeDescription . length ( ) ) + "\r\n\r\n
" + errorCodeDescription + "
" ) ) ; }


Input: This will close the connection immediately without a proper close handshake . The code and the message therefore won t be transfered over the wire also they will be forwarded to onClose / onWebsocketClose . [CODESPLIT] public synchronized void closeConnection ( int code , String message , boolean remote ) { if ( readyState == ReadyState . CLOSED ) { return ; } //Methods like eot() call this method without calling onClose(). Due to that reason we have to adjust the ReadyState manually if ( readyState == ReadyState . OPEN ) { if ( code == CloseFrame . ABNORMAL_CLOSE ) { readyState = ReadyState . CLOSING ; } } if ( key != null ) { // key.attach( null ); //see issue #114 key . cancel ( ) ; } if ( channel != null ) { try { channel . close ( ) ; } catch ( IOException e ) { if ( e . getMessage ( ) . equals ( "Broken pipe" ) ) { log . trace ( "Caught IOException: Broken pipe during closeConnection()" , e ) ; } else { log . error ( "Exception during channel.close()" , e ) ; wsl . onWebsocketError ( this , e ) ; } } } try { this . wsl . onWebsocketClose ( this , code , message , remote ) ; } catch ( RuntimeException e ) { wsl . onWebsocketError ( this , e ) ; } if ( draft != null ) draft . reset ( ) ; handshakerequest = null ; readyState = ReadyState . CLOSED ; }


Input: Send Text data to the other end . [CODESPLIT] @ Override public void send ( String text ) { if ( text == null ) throw new IllegalArgumentException ( "Cannot send 'null' data to a WebSocketImpl." ) ; send ( draft . createFrames ( text , role == Role . CLIENT ) ) ; }


Input: Send Binary data ( plain bytes ) to the other end . [CODESPLIT] @ Override public void send ( ByteBuffer bytes ) { if ( bytes == null ) throw new IllegalArgumentException ( "Cannot send 'null' data to a WebSocketImpl." ) ; send ( draft . createFrames ( bytes , role == Role . CLIENT ) ) ; }


Input: Write a list of bytebuffer ( frames in binary form ) into the outgoing queue [CODESPLIT] private void write ( List < ByteBuffer > bufs ) { synchronized ( synchronizeWriteObject ) { for ( ByteBuffer b : bufs ) { write ( b ) ; } } }


Input: Reset everything relevant to allow a reconnect [CODESPLIT] private void reset ( ) { Thread current = Thread . currentThread ( ) ; if ( current == writeThread || current == connectReadThread ) { throw new IllegalStateException ( "You cannot initialize a reconnect out of the websocket thread. Use reconnect in another thread to insure a successful cleanup." ) ; } try { closeBlocking ( ) ; if ( writeThread != null ) { this . writeThread . interrupt ( ) ; this . writeThread = null ; } if ( connectReadThread != null ) { this . connectReadThread . interrupt ( ) ; this . connectReadThread = null ; } this . draft . reset ( ) ; if ( this . socket != null ) { this . socket . close ( ) ; this . socket = null ; } } catch ( Exception e ) { onError ( e ) ; engine . closeConnection ( CloseFrame . ABNORMAL_CLOSE , e . getMessage ( ) ) ; return ; } connectLatch = new CountDownLatch ( 1 ) ; closeLatch = new CountDownLatch ( 1 ) ; this . engine = new WebSocketImpl ( this , this . draft ) ; }


Input: Initiates the websocket connection . This method does not block . [CODESPLIT] public void connect ( ) { if ( connectReadThread != null ) throw new IllegalStateException ( "WebSocketClient objects are not reuseable" ) ; connectReadThread = new Thread ( this ) ; connectReadThread . setName ( "WebSocketConnectReadThread-" + connectReadThread . getId ( ) ) ; connectReadThread . start ( ) ; }


Input: Same as <code > connect< / code > but blocks with a timeout until the websocket connected or failed to do so . <br > [CODESPLIT] public boolean connectBlocking ( long timeout , TimeUnit timeUnit ) throws InterruptedException { connect ( ) ; return connectLatch . await ( timeout , timeUnit ) && engine . isOpen ( ) ; }


Input: Extract the specified port [CODESPLIT] private int getPort ( ) { int port = uri . getPort ( ) ; if ( port == - 1 ) { String scheme = uri . getScheme ( ) ; if ( "wss" . equals ( scheme ) ) { return WebSocketImpl . DEFAULT_WSS_PORT ; } else if ( "ws" . equals ( scheme ) ) { return WebSocketImpl . DEFAULT_PORT ; } else { throw new IllegalArgumentException ( "unknown scheme: " + scheme ) ; } } return port ; }


Input: Create and send the handshake to the other endpoint [CODESPLIT] private void sendHandshake ( ) throws InvalidHandshakeException { String path ; String part1 = uri . getRawPath ( ) ; String part2 = uri . getRawQuery ( ) ; if ( part1 == null || part1 . length ( ) == 0 ) path = "/" ; else path = part1 ; if ( part2 != null ) path += ' ' + part2 ; int port = getPort ( ) ; String host = uri . getHost ( ) + ( ( port != WebSocketImpl . DEFAULT_PORT && port != WebSocketImpl . DEFAULT_WSS_PORT ) ? ":" + port : "" ) ; HandshakeImpl1Client handshake = new HandshakeImpl1Client ( ) ; handshake . setResourceDescriptor ( path ) ; handshake . put ( "Host" , host ) ; if ( headers != null ) { for ( Map . Entry < String , String > kv : headers . entrySet ( ) ) { handshake . put ( kv . getKey ( ) , kv . getValue ( ) ) ; } } engine . startHandshake ( handshake ) ; }


Input: Calls subclass implementation of <var > onOpen< / var > . [CODESPLIT] @ Override public final void onWebsocketOpen ( WebSocket conn , Handshakedata handshake ) { startConnectionLostTimer ( ) ; onOpen ( ( ServerHandshake ) handshake ) ; connectLatch . countDown ( ) ; }


Input: Calls subclass implementation of <var > onClose< / var > . [CODESPLIT] @ Override public final void onWebsocketClose ( WebSocket conn , int code , String reason , boolean remote ) { stopConnectionLostTimer ( ) ; if ( writeThread != null ) writeThread . interrupt ( ) ; onClose ( code , reason , remote ) ; connectLatch . countDown ( ) ; closeLatch . countDown ( ) ; }


Input: Setter for the interval checking for lost connections A value lower or equal 0 results in the check to be deactivated [CODESPLIT] public void setConnectionLostTimeout ( int connectionLostTimeout ) { synchronized ( syncConnectionLost ) { this . connectionLostTimeout = TimeUnit . SECONDS . toNanos ( connectionLostTimeout ) ; if ( this . connectionLostTimeout <= 0 ) { log . trace ( "Connection lost timer stopped" ) ; cancelConnectionLostTimer ( ) ; return ; } if ( this . websocketRunning ) { log . trace ( "Connection lost timer restarted" ) ; //Reset all the pings try { ArrayList < WebSocket > connections = new ArrayList < WebSocket > ( getConnections ( ) ) ; WebSocketImpl webSocketImpl ; for ( WebSocket conn : connections ) { if ( conn instanceof WebSocketImpl ) { webSocketImpl = ( WebSocketImpl ) conn ; webSocketImpl . updateLastPong ( ) ; } } } catch ( Exception e ) { log . error ( "Exception during connection lost restart" , e ) ; } restartConnectionLostTimer ( ) ; } } }


Input: Stop the connection lost timer [CODESPLIT] protected void stopConnectionLostTimer ( ) { synchronized ( syncConnectionLost ) { if ( connectionLostCheckerService != null || connectionLostCheckerFuture != null ) { this . websocketRunning = false ; log . trace ( "Connection lost timer stopped" ) ; cancelConnectionLostTimer ( ) ; } } }


Input: Start the connection lost timer [CODESPLIT] protected void startConnectionLostTimer ( ) { synchronized ( syncConnectionLost ) { if ( this . connectionLostTimeout <= 0 ) { log . trace ( "Connection lost timer deactivated" ) ; return ; } log . trace ( "Connection lost timer started" ) ; this . websocketRunning = true ; restartConnectionLostTimer ( ) ; } }