public void registerDefaultProcessor(RemotingProcessor<?> processor) {
        if (this.defaultProcessor == null) {
            this.defaultProcessor = processor;
        } else {
            throw new IllegalStateException("The defaultProcessor has already been registered: "
                                            + this.defaultProcessor.getClass());
        }
    }

Register the default processor to process command with no specific processor registered.

@param processor

Register the default processor to process command with no specific processor registered .


public RemotingProcessor<?> getProcessor(CommandCode cmdCode) {
        RemotingProcessor<?> processor = this.cmd2processors.get(cmdCode);
        if (processor != null) {
            return processor;
        }
        return this.defaultProcessor;
    }

public RemotingProcessor < ? > getProcessor ( CommandCode cmdCode ) { RemotingProcessor < ? > processor = this . cmd2processors . get ( cmdCode ) ; if ( processor != null ) { return processor ; } return this . defaultProcessor ; }

Get the specific processor with command code of cmdCode if registered, otherwise the default processor is returned.

@param cmdCode
@return

Get the specific processor with command code of cmdCode if registered otherwise the default processor is returned .


private Url tryGet(String url) {
        SoftReference<Url> softRef = Url.parsedUrls.get(url);
        return (null == softRef) ? null : softRef.get();
    }

private Url tryGet ( String url ) { SoftReference < Url > softRef = Url . parsedUrls . get ( url ) ; return ( null == softRef ) ? null : softRef . get ( ) ; }


protected ProtocolCode decodeProtocolCode(ByteBuf in) {
        if (in.readableBytes() >= protocolCodeLength) {
            byte[] protocolCodeBytes = new byte[protocolCodeLength];
            in.readBytes(protocolCodeBytes);
            return ProtocolCode.fromBytes(protocolCodeBytes);
        }
        return null;
    }

protected ProtocolCode decodeProtocolCode ( ByteBuf in ) { if ( in . readableBytes ( ) >= protocolCodeLength ) { byte [ ] protocolCodeBytes = new byte [ protocolCodeLength ] ; in . readBytes ( protocolCodeBytes ) ; return ProtocolCode . fromBytes ( protocolCodeBytes ) ; } return null ; }

decode the protocol code

@param in input byte buf
@return an instance of ProtocolCode


@Override
    public Map<String, List<Connection>> getAll() {
        Map<String, List<Connection>> allConnections = new HashMap<String, List<Connection>>();
        Iterator<Map.Entry<String, RunStateRecordedFutureTask<ConnectionPool>>> iterator = this
            .getConnPools().entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, RunStateRecordedFutureTask<ConnectionPool>> entry = iterator.next();
            ConnectionPool pool = FutureTaskUtil.getFutureTaskResult(entry.getValue(), logger);
            if (null != pool) {
                allConnections.put(entry.getKey(), pool.getAll());
            }
        }
        return allConnections;
    }

@ Override public Map < String , List < Connection > > getAll ( ) { Map < String , List < Connection > > allConnections = new HashMap < String , List < Connection > > ( ) ; Iterator < Map . Entry < String , RunStateRecordedFutureTask < ConnectionPool > > > iterator = this . getConnPools ( ) . entrySet ( ) . iterator ( ) ; while ( iterator . hasNext ( ) ) { Map . Entry < String , RunStateRecordedFutureTask < ConnectionPool > > entry = iterator . next ( ) ; ConnectionPool pool = FutureTaskUtil . getFutureTaskResult ( entry . getValue ( ) , logger ) ; if ( null != pool ) { allConnections . put ( entry . getKey ( ) , pool . getAll ( ) ) ; } } return allConnections ; }

Get all connections of all poolKey.

@return a map with poolKey as key and a list of connections in ConnectionPool as value


@Override
    public void scan() {
        if (null != this.connTasks && !this.connTasks.isEmpty()) {
            Iterator<String> iter = this.connTasks.keySet().iterator();
            while (iter.hasNext()) {
                String poolKey = iter.next();
                ConnectionPool pool = this.getConnectionPool(this.connTasks.get(poolKey));
                if (null != pool) {
                    pool.scan();
                    if (pool.isEmpty()) {
                        if ((System.currentTimeMillis() - pool.getLastAccessTimestamp()) > DEFAULT_EXPIRE_TIME) {
                            iter.remove();
                            logger.warn("Remove expired pool task of poolKey {} which is empty.",
                                poolKey);
                        }
                    }
                }
            }
        }
    }

in case of cache pollution and connection leak, to do schedule scan

@see com.alipay.remoting.Scannable#scan()

in case of cache pollution and connection leak to do schedule scan


@Override
    public Connection getAndCreateIfAbsent(Url url) throws InterruptedException, RemotingException {
        // get and create a connection pool with initialized connections.
        ConnectionPool pool = this.getConnectionPoolAndCreateIfAbsent(url.getUniqueKey(),
            new ConnectionPoolCall(url));
        if (null != pool) {
            return pool.get();
        } else {
            logger.error("[NOTIFYME] bug detected! pool here must not be null!");
            return null;
        }
    }

If no task cached, create one and initialize the connections.

@see ConnectionManager#getAndCreateIfAbsent(Url)

If no task cached create one and initialize the connections .


@Override
    public void createConnectionAndHealIfNeed(Url url) throws InterruptedException,
                                                      RemotingException {
        // get and create a connection pool with initialized connections.
        ConnectionPool pool = this.getConnectionPoolAndCreateIfAbsent(url.getUniqueKey(),
            new ConnectionPoolCall(url));
        if (null != pool) {
            healIfNeed(pool, url);
        } else {
            logger.error("[NOTIFYME] bug detected! pool here must not be null!");
        }
    }

If no task cached, create one and initialize the connections.
If task cached, check whether the number of connections adequate, if not then heal it.

@param url
@return
@throws InterruptedException
@throws RemotingException

If no task cached create one and initialize the connections . If task cached check whether the number of connections adequate if not then heal it .


private void removeTask(String poolKey) {
        RunStateRecordedFutureTask<ConnectionPool> task = this.connTasks.remove(poolKey);
        if (null != task) {
            ConnectionPool pool = FutureTaskUtil.getFutureTaskResult(task, logger);
            if (null != pool) {
                pool.removeAllAndTryClose();
            }
        }
    }

private void removeTask ( String poolKey ) { RunStateRecordedFutureTask < ConnectionPool > task = this . connTasks . remove ( poolKey ) ; if ( null != task ) { ConnectionPool pool = FutureTaskUtil . getFutureTaskResult ( task , logger ) ; if ( null != pool ) { pool . removeAllAndTryClose ( ) ; } } }

remove task and remove all connections

@param poolKey


private void healIfNeed(ConnectionPool pool, Url url) throws RemotingException,
                                                         InterruptedException {
        String poolKey = url.getUniqueKey();
        // only when async creating connections done
        // and the actual size of connections less than expected, the healing task can be run.
        if (pool.isAsyncCreationDone() && pool.size() < url.getConnNum()) {
            FutureTask<Integer> task = this.healTasks.get(poolKey);
            if (null == task) {
                task = new FutureTask<Integer>(new HealConnectionCall(url, pool));
                task = this.healTasks.putIfAbsent(poolKey, task);
                if (null == task) {
                    task = this.healTasks.get(poolKey);
                    task.run();
                }
            }
            try {
                int numAfterHeal = task.get();
                if (logger.isDebugEnabled()) {
                    logger.debug("[NOTIFYME] - conn num after heal {}, expected {}, warmup {}",
                        numAfterHeal, url.getConnNum(), url.isConnWarmup());
                }
            } catch (InterruptedException e) {
                this.healTasks.remove(poolKey);
                throw e;
            } catch (ExecutionException e) {
                this.healTasks.remove(poolKey);
                Throwable cause = e.getCause();
                if (cause instanceof RemotingException) {
                    throw (RemotingException) cause;
                } else {
                    FutureTaskUtil.launderThrowable(cause);
                }
            }
            // heal task is one-off, remove from cache directly after run
            this.healTasks.remove(poolKey);
        }
    }

execute heal connection tasks if the actual number of connections in pool is less than expected

@param pool
@param url


private void doCreate(final Url url, final ConnectionPool pool, final String taskName,
                          final int syncCreateNumWhenNotWarmup) throws RemotingException {
        final int actualNum = pool.size();
        final int expectNum = url.getConnNum();
        if (actualNum < expectNum) {
            if (logger.isDebugEnabled()) {
                logger.debug("actual num {}, expect num {}, task name {}", actualNum, expectNum,
                    taskName);
            }
            if (url.isConnWarmup()) {
                for (int i = actualNum; i < expectNum; ++i) {
                    Connection connection = create(url);
                    pool.add(connection);
                }
            } else {
                if (syncCreateNumWhenNotWarmup < 0 || syncCreateNumWhenNotWarmup > url.getConnNum()) {
                    throw new IllegalArgumentException(
                        "sync create number when not warmup should be [0," + url.getConnNum() + "]");
                }
                // create connection in sync way
                if (syncCreateNumWhenNotWarmup > 0) {
                    for (int i = 0; i < syncCreateNumWhenNotWarmup; ++i) {
                        Connection connection = create(url);
                        pool.add(connection);
                    }
                    if (syncCreateNumWhenNotWarmup == url.getConnNum()) {
                        return;
                    }
                }
                // initialize executor in lazy way
                initializeExecutor();
                pool.markAsyncCreationStart();// mark the start of async
                try {
                    this.asyncCreateConnectionExecutor.execute(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                for (int i = pool.size(); i < url.getConnNum(); ++i) {
                                    Connection conn = null;
                                    try {
                                        conn = create(url);
                                    } catch (RemotingException e) {
                                        logger
                                            .error(
                                                "Exception occurred in async create connection thread for {}, taskName {}",
                                                url.getUniqueKey(), taskName, e);
                                    }
                                    pool.add(conn);
                                }
                            } finally {
                                pool.markAsyncCreationDone();// mark the end of async
                            }
                        }
                    });
                } catch (RejectedExecutionException e) {
                    pool.markAsyncCreationDone();// mark the end of async when reject
                    throw e;
                }
            } // end of NOT warm up
        } // end of if
    }

do create connections

@param url
@param pool
@param taskName
@param syncCreateNumWhenNotWarmup you can specify this param to ensure at least desired number of connections available in sync way
@throws RemotingException


public void closeConnection(String addr) {
        Url url = this.addressParser.parse(addr);
        this.connectionManager.remove(url.getUniqueKey());
    }

public void closeConnection ( String addr ) { Url url = this . addressParser . parse ( addr ) ; this . connectionManager . remove ( url . getUniqueKey ( ) ) ; }

Close all connections of a address

@param addr


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();
            }
        }
    }

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 ( ) ; } } }


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);
            }
        }
    }


public Object setAttributeIfAbsent(String key, Object value) {
        return attributes.putIfAbsent(key, value);
    }

public Object setAttributeIfAbsent ( String key , Object value ) { return attributes . putIfAbsent ( key , value ) ; }

set attribute if key absent.

@param key
@param value
@return


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);
            }
        }

    }

Help register single-interest user processor.

@param processor  the processor need to be registered
@param userProcessors   the map of user processors

Help register single - interest user processor .


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);
            }
        }

    }

Help register multi-interest user processor.

@param processor  the processor with multi-interest need to be registered
@param userProcessors    the map of user processors

Help register multi - interest user processor .


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));
            }
        }
    }

dispatch request command to user processor
@param ctx remoting context
@param cmd rpc request command


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;
    }

deserialize request command

@return true if deserialize success; false if exception catched


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());
    }

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 ( ) ) ; }

pre process remoting context, initial some useful infos and pass to biz

@param ctx remoting context
@param cmd rpc request command
@param currentTimestamp current timestamp

pre process remoting context initial some useful infos and pass to biz


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());
    }

print some log when request timeout and discarded in io thread.

print some log when request timeout and discarded in io thread .


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());
        }
    }

print some debug log when receive request


@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);
        }
    }

@ 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 ) ; } }

Process the remoting command with its own executor or with the defaultExecutor if its own if null.

@param ctx
@param msg
@param defaultExecutor
@throws Exception

Process the remoting command with its own executor or with the defaultExecutor if its own if null .


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);
        }
    }

Invocation with callback.

@param conn
@param request
@param invokeCallback
@param timeoutMillis
@throws InterruptedException


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);
            }
        }
    }

Oneway invocation.

@param conn
@param request
@throws InterruptedException


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;
    }

from bit set to byte
@param bs
@return byte represent the bit set


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;
    }

from byte to bit set
@param value
@return bit set represent the byte


public void addReconnectTask(Url url) {
        ReconnectTask task = new ReconnectTask();
        task.url = url;
        tasks.add(task);
    }

public void addReconnectTask ( Url url ) { ReconnectTask task = new ReconnectTask ( ) ; task . url = url ; tasks . add ( task ) ; }


public void stop() {
        if (!this.started) {
            return;
        }
        this.started = false;
        healConnectionThreads.interrupt();
        this.tasks.clear();
        this.canceled.clear();
    }

public void stop ( ) { if ( ! this . started ) { return ; } this . started = false ; healConnectionThreads . interrupt ( ) ; this . tasks . clear ( ) ; this . canceled . clear ( ) ; }


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;
    }

Convert application request object to remoting request command.

@param request
@param conn
@param timeoutMillis
@return
@throws CodecException

Convert application request object to remoting request command .


@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;
    }

@ 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 ; }

Filter connections to monitor

@param connections


@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);
        }
    }

Monitor connections and close connections with status is off

@param connPools


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()));
                    }
                }
            }
        }
    }

close the connection of the fresh select connections

@param lastSelectConnect
@param serviceOffConnections
@throws InterruptedException


public static boolean getBool(String key, String defaultValue) {
        return Boolean.parseBoolean(System.getProperty(key, defaultValue));
    }

public static boolean getBool ( String key , String defaultValue ) { return Boolean . parseBoolean ( System . getProperty ( key , defaultValue ) ) ; }

~~~ public helper methods to retrieve system property


private void infoLog(String format, String addr) {
        if (logger.isInfoEnabled()) {
            if (StringUtils.isNotEmpty(addr)) {
                logger.info(format, addr);
            } else {
                logger.info(format, "UNKNOWN-ADDR");
            }
        }
    }

private void infoLog ( String format , String addr ) { if ( logger . isInfoEnabled ( ) ) { if ( StringUtils . isNotEmpty ( addr ) ) { logger . info ( format , addr ) ; } else { logger . info ( format , "UNKNOWN-ADDR" ) ; } } }

print info log
@param format
@param addr


public boolean isRequestTimeout() {
        if (this.timeout > 0 && (this.rpcCommandType != RpcCommandType.REQUEST_ONEWAY)
            && (System.currentTimeMillis() - this.arriveTimestamp) > this.timeout) {
            return true;
        }
        return false;
    }

public boolean isRequestTimeout ( ) { if ( this . timeout > 0 && ( this . rpcCommandType != RpcCommandType . REQUEST_ONEWAY ) && ( System . currentTimeMillis ( ) - this . arriveTimestamp ) > this . timeout ) { return true ; } return false ; }

whether this request already timeout

@return


public UserProcessor<?> getUserProcessor(String className) {
        return StringUtils.isBlank(className) ? null : this.userProcessors.get(className);
    }

public UserProcessor < ? > getUserProcessor ( String className ) { return StringUtils . isBlank ( className ) ? null : this . userProcessors . get ( className ) ; }

Get user processor for class name.

@param className
@return


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;
    }

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 ; }

get one connection randomly

@param conns
@return


@SuppressWarnings("unchecked")
    public <T> T get(String key, T defaultIfNotFound) {
        return this.context.get(key) != null ? (T) this.context.get(key) : defaultIfNotFound;
    }

@ SuppressWarnings ( "unchecked" ) public < T > T get ( String key , T defaultIfNotFound ) { return this . context . get ( key ) != null ? ( T ) this . context . get ( key ) : defaultIfNotFound ; }

get and use default if not found

@param key
@param defaultIfNotFound
@param <T>
@return


public String getProperty(String key) {
        if (properties == null) {
            return null;
        }
        return properties.getProperty(key);
    }

public String getProperty ( String key ) { if ( properties == null ) { return null ; } return properties . getProperty ( key ) ; }

Get property value according to property key

@param key
@return property value


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.");
            }
        }

    }

Analyze the response command and generate the response object.

@param responseCommand response command
@param addr response address
@return response object

Analyze the response command and generate the response object .


private static Object toResponseObject(ResponseCommand responseCommand) throws CodecException {
        RpcResponseCommand response = (RpcResponseCommand) responseCommand;
        response.deserialize();
        return response.getResponseObject();
    }

private static Object toResponseObject ( ResponseCommand responseCommand ) throws CodecException { RpcResponseCommand response = ( RpcResponseCommand ) responseCommand ; response . deserialize ( ) ; return response . getResponseObject ( ) ; }

Convert remoting response command to application response object.

Convert remoting response command to application response object .


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;
    }

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 ; }

Convert remoting response command to throwable if it is a throwable, otherwise return null.

Convert remoting response command to throwable if it is a throwable otherwise return null .


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);
        }
    }

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
)
;
}
}

Detail your error msg with the error msg returned from response command


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;
    }

create server exception using error msg and fill the stack trace using the stack trace of throwable.

@param t the origin throwable to fill the stack trace of rpc server exception
@param errMsg additional error msg, null is allowed
@return an instance of RpcServerException

create server exception using error msg and fill the stack trace using the stack trace of throwable .


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());
        }
    }

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 ( ) ) ; } }

print trace log
@param traceId
@param invokeContext


public static EventLoopGroup newEventLoopGroup(int nThreads, ThreadFactory threadFactory) {
        return epollEnabled ? new EpollEventLoopGroup(nThreads, threadFactory)
            : new NioEventLoopGroup(nThreads, threadFactory);
    }

public static EventLoopGroup newEventLoopGroup ( int nThreads , ThreadFactory threadFactory ) { return epollEnabled ? new EpollEventLoopGroup ( nThreads , threadFactory ) : new NioEventLoopGroup ( nThreads , threadFactory ) ; }

Create the right event loop according to current platform and system property, fallback to NIO when epoll not enabled.

@param nThreads
@param threadFactory
@return an EventLoopGroup suitable for the current platform

Create the right event loop according to current platform and system property fallback to NIO when epoll not enabled .


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);
    }

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 ) ; }

Parse the remote address of the channel.

@param channel
@return

Parse the remote address of the channel .


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);
    }

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 ) ; }

Parse the local address of the channel.

@param channel
@return

Parse the local address of the channel .


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;
    }

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 ; }

Parse the remote host ip of the channel.

@param channel
@return

Parse the remote host ip of the channel .


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;
    }

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 ; }

Parse the remote hostname of the channel.

Note: take care to use this method, for a reverse name lookup takes uncertain time in {@link InetAddress#getHostName}.

@param channel
@return

Parse the remote hostname of the channel .


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;
    }

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 ; }

Parse the local host ip of the channel.

@param channel
@return

Parse the local host ip of the channel .


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;
    }

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 ; }

Parse the remote host port of the channel.

@param channel
@return int

Parse the remote host port of the channel .


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;
    }

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 ; }

Parse the local host port of the channel.

@param channel
@return int

Parse the local host port of the channel .


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;
    }

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 ; }

Parse the host ip of socket address.

e.g. /127.0.0.1:1234 -> 127.0.0.1

@param socketAddress
@return String


public void add(Connection connection) {
        markAccess();
        if (null == connection) {
            return;
        }
        boolean res = this.conns.addIfAbsent(connection);
        if (res) {
            connection.increaseRef();
        }
    }

public void add ( Connection connection ) { markAccess ( ) ; if ( null == connection ) { return ; } boolean res = this . conns . addIfAbsent ( connection ) ; if ( res ) { connection . increaseRef ( ) ; } }


public void removeAndTryClose(Connection connection) {
        if (null == connection) {
            return;
        }
        boolean res = this.conns.remove(connection);
        if (res) {
            connection.decreaseRef();
        }
        if (connection.noRef()) {
            connection.close();
        }
    }

public void removeAndTryClose ( Connection connection ) { if ( null == connection ) { return ; } boolean res = this . conns . remove ( connection ) ; if ( res ) { connection . decreaseRef ( ) ; } if ( connection . noRef ( ) ) { connection . close ( ) ; } }

removeAndTryClose a connection

@param connection


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;
        }
    }

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 ; } }


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());
        }
    }

Register custom serializer for class name.

@param className
@param serializer
@return

Register custom serializer for class name .


public static CustomSerializer getCustomSerializer(String className) {
        if (!classCustomSerializer.isEmpty()) {
            return classCustomSerializer.get(className);
        }
        return null;
    }

public static CustomSerializer getCustomSerializer ( String className ) { if ( ! classCustomSerializer . isEmpty ( ) ) { return classCustomSerializer . get ( className ) ; } return null ; }

Get the custom serializer for class name.

@param className
@return

Get the custom serializer for class name .


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());
        }
    }

Register custom serializer for command code.

@param code
@param serializer
@return

Register custom serializer for command code .


public static CustomSerializer getCustomSerializer(CommandCode code) {
        if (!commandCustomSerializer.isEmpty()) {
            return commandCustomSerializer.get(code);
        }
        return null;
    }

public static CustomSerializer getCustomSerializer ( CommandCode code ) { if ( ! commandCustomSerializer . isEmpty ( ) ) { return commandCustomSerializer . get ( code ) ; } return null ; }

Get the custom serializer for command code.

@param code
@return

Get the custom serializer for command code .


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);
    }


public boolean isConnected(String remoteAddr) {
        Url url = this.rpcRemoting.addressParser.parse(remoteAddr);
        return this.isConnected(url);
    }

public boolean isConnected ( String remoteAddr ) { Url url = this . rpcRemoting . addressParser . parse ( remoteAddr ) ; return this . isConnected ( url ) ; }

check whether a client address connected

@param remoteAddr
@return


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));
    }


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");
        }
    }

public
static
FramedataImpl1
get
(
Opcode
opcode
)
{
if
(
opcode
==
)
{
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"
)
;
}
}

Get a frame with a specific opcode

@param opcode the opcode representing the frame
@return the frame with a specific opcode


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();
	}

Returns whether the whole outQueue has been flushed
@param ws The WebSocketImpl associated with the channels
@param sockchannel The channel to write to
@throws IOException May be thrown by {@link WrappedByteChannel#writeMore()}
@return returns Whether there is more data to write


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();
    }

Set the close code for this close frame
@param code the close code


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 );
        }
    }

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 ) ; } }

Validate the payload to valid utf8
@param mark the current mark
@param payload the current payload
@throws InvalidDataException the current payload is not a valid utf8


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);
    }

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 ) ; }

Update the payload to represent the close code and the reason


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;
	}

Check if the requested protocol is part of this draft
@param requestedProtocol the requested protocol
@return MATCHED if it is matched, otherwise NOT_MATCHED


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...");
		}
	}

Check if the frame size exceeds the allowed limit
@param length the current payload length
@throws LimitExceededException if the payload length is to big


private void translateSingleFrameCheckPacketSize(int maxpacketsize, int realpacketsize) throws IncompleteException {
		if( maxpacketsize < realpacketsize ) {
			log.trace( "Incomplete frame: maxpacketsize < realpacketsize" );
			throw new IncompleteException( realpacketsize );
		}
	}

Check if the max packet size is smaller than the real packet size
@param maxpacketsize the max packet size
@param realpacketsize the real packet size
@throws IncompleteException if the maxpacketsize is smaller than the realpackagesize


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() ) );
	}

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 ( ) ) ) ; }

Generate a final key from a input string
@param in the input string
@return a final key


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());
        }
    }

Process the frame if it is a continuous frame or the fin bit is not set
@param webSocketImpl the websocket implementation to use
@param frame the current frame
@param curop the current Opcode
@throws InvalidDataException if there is a protocol error


private void processFrameBinary(WebSocketImpl webSocketImpl, Framedata frame) {
		try {
			webSocketImpl.getWebSocketListener().onWebsocketMessage( webSocketImpl, frame.getPayloadData() );
		} catch ( RuntimeException e ) {
			logRuntimeException(webSocketImpl, e);
		}
	}

private void processFrameBinary ( WebSocketImpl webSocketImpl , Framedata frame ) { try { webSocketImpl . getWebSocketListener ( ) . onWebsocketMessage ( webSocketImpl , frame . getPayloadData ( ) ) ; } catch ( RuntimeException e ) { logRuntimeException ( webSocketImpl , e ) ; } }

Process the frame if it is a binary frame
@param webSocketImpl the websocket impl
@param frame the frame


private void logRuntimeException(WebSocketImpl webSocketImpl, RuntimeException e) {
		log.error( "Runtime exception during onWebsocketMessage", e );
		webSocketImpl.getWebSocketListener().onWebsocketError( webSocketImpl, e );
	}

Log the runtime exception to the specific WebSocketImpl
@param webSocketImpl the implementation of the websocket
@param e the runtime exception


private void processFrameText(WebSocketImpl webSocketImpl, Framedata frame) throws InvalidDataException {
		try {
			webSocketImpl.getWebSocketListener().onWebsocketMessage( webSocketImpl, Charsetfunctions.stringUtf8( frame.getPayloadData() ) );
		} catch ( RuntimeException e ) {
			logRuntimeException(webSocketImpl, e);
		}
	}

private void processFrameText ( WebSocketImpl webSocketImpl , Framedata frame ) throws InvalidDataException { try { webSocketImpl . getWebSocketListener ( ) . onWebsocketMessage ( webSocketImpl , Charsetfunctions . stringUtf8 ( frame . getPayloadData ( ) ) ) ; } catch ( RuntimeException e ) { logRuntimeException ( webSocketImpl , e ) ; } }

Process the frame if it is a text frame
@param webSocketImpl the websocket impl
@param frame the frame


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();
	}

Process the frame if it is the last frame
@param webSocketImpl the websocket impl
@param frame the frame
@throws InvalidDataException if there is a protocol error


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();
	}

Process the frame if it is not the last frame
@param frame the frame
@throws InvalidDataException if there is a protocol error


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 );
		}
	}

Process the frame if it is a closing frame
@param webSocketImpl the websocket impl
@param frame the frame


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);
		}
	}

Check the current size of the buffer and throw an exception if the size is bigger than the max allowed frame size
@throws LimitExceededException if the current size is bigger than the allowed size


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;
	}

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 ; }

Method to generate a full bytebuffer out of all the fragmented frame payload
@return a bytebuffer containing all the data
@throws LimitExceededException will be thrown when the totalSize is bigger then Integer.MAX_VALUE due to not being able to allocate more


private long getByteBufferListSize() {
		long totalSize = 0;
		synchronized (byteBufferList) {
			for (ByteBuffer buffer : byteBufferList) {
				totalSize += buffer.limit();
			}
		}
		return totalSize;
	}

private long getByteBufferListSize ( ) { long totalSize = 0 ; synchronized ( byteBufferList ) { for ( ByteBuffer buffer : byteBufferList ) { totalSize += buffer . limit ( ) ; } } return totalSize ; }

Get the current size of the resulting bytebuffer in the bytebuffer list
@return the size as long (to not get an integer overflow)


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;
	}

Checking the handshake for the role as server
@return a handshake
@param firstLineTokens the token of the first line split as as an string array
@param line the whole line


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;
	}

Checking the handshake for the role as client
@return a handshake
@param firstLineTokens the token of the first line split as as an string array
@param line the whole line


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 );
				}
			}
		}
	}

Method to decode the provided ByteBuffer

@param socketBuffer the ByteBuffer to decode


private void closeConnectionDueToWrongHandshake( InvalidDataException exception ) {
		write( generateHttpResponseDueToError( 404 ) );
		flushAndClose( exception.getCloseCode(), exception.getMessage(), false );
	}

private void closeConnectionDueToWrongHandshake ( InvalidDataException exception ) { write ( generateHttpResponseDueToError ( 404 ) ) ; flushAndClose ( exception . getCloseCode ( ) , exception . getMessage ( ) , false ) ; }

Close the connection if the received handshake was not correct

@param exception the InvalidDataException causing this problem


private void closeConnectionDueToInternalServerError( RuntimeException exception ) {
		write( generateHttpResponseDueToError( 500 ) );
		flushAndClose( CloseFrame.NEVER_CONNECTED, exception.getMessage(), false );
	}

private void closeConnectionDueToInternalServerError ( RuntimeException exception ) { write ( generateHttpResponseDueToError ( 500 ) ) ; flushAndClose ( CloseFrame . NEVER_CONNECTED , exception . getMessage ( ) , false ) ; }

Close the connection if there was a server error by a RuntimeException

@param exception the RuntimeException causing this problem


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 + "
" ) );
	}

Generate a simple response for the corresponding endpoint to indicate some error

@param errorCode the http error code
@return the complete response as ByteBuffer


@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 ) );
	}

Send Text data to the other end.

@throws WebsocketNotConnectedException websocket is not yet connected


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 );
	}

Reset everything relevant to allow a reconnect
@since 1.3.8


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();
	}

Initiates the websocket connection. This method does not block.

Initiates the websocket connection . This method does not block .


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;
	}

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
;
}

Extract the specified port
@return the specified port or the default port for the specific scheme


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 );
	}

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 ) ; }

Create and send the handshake to the other endpoint
@throws InvalidHandshakeException  a invalid handshake was created


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();
            }
        }
    }

Setter for the interval checking for lost connections
A value lower or equal 0 results in the check to be deactivated

@param connectionLostTimeout the interval in seconds
@since 1.3.4


protected void stopConnectionLostTimer() {
        synchronized (syncConnectionLost) {
            if (connectionLostCheckerService != null || connectionLostCheckerFuture != null) {
                this.websocketRunning = false;
                log.trace("Connection lost timer stopped");
                cancelConnectionLostTimer();
            }
        }
    }

protected
void
stopConnectionLostTimer
(
)
{
synchronized
(
syncConnectionLost
)
{
if
(
connectionLostCheckerService
!=
||
connectionLostCheckerFuture
!=
)
{
this
.
websocketRunning
=
false
;
log
.
trace
(
"Connection lost timer stopped"
)
;
cancelConnectionLostTimer
(
)
;
}
}
}

Stop the connection lost timer
@since 1.3.4


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();
        }
    }

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
(
)
;
}
}

Start the connection lost timer
@since 1.3.4


private void restartConnectionLostTimer() {
		cancelConnectionLostTimer();
		connectionLostCheckerService = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("connectionLostChecker"));
		Runnable connectionLostChecker = new Runnable() {

			/**
			 * Keep the connections in a separate list to not cause deadlocks
			 */
			private ArrayList<WebSocket> connections = new ArrayList<WebSocket>(  );
			@Override
			public void run() {
				connections.clear();
				try {
					connections.addAll( getConnections() );
					long minimumPongTime = (long) (System.nanoTime() - ( connectionLostTimeout * 1.5 ));
					for( WebSocket conn : connections ) {
						executeConnectionLostDetection(conn, minimumPongTime);
					}
				} catch ( Exception e ) {
					//Ignore this exception
				}
				connections.clear();
			}
		};

		connectionLostCheckerFuture = connectionLostCheckerService.scheduleAtFixedRate(connectionLostChecker, connectionLostTimeout, connectionLostTimeout, TimeUnit.NANOSECONDS);
	}

This methods allows the reset of the connection lost timer in case of a changed parameter
@since 1.3.4


private void executeConnectionLostDetection(WebSocket webSocket, long minimumPongTime) {
		if (!(webSocket instanceof WebSocketImpl)) {
			return;
		}
		WebSocketImpl webSocketImpl = (WebSocketImpl) webSocket;
		if( webSocketImpl.getLastPong() < minimumPongTime ) {
			log.trace("Closing connection due to no pong received: {}", webSocketImpl);
			webSocketImpl.closeConnection( CloseFrame.ABNORMAL_CLOSE, "The connection was closed because the other endpoint did not respond with a pong in time. For more information check: https://github.com/TooTallNate/Java-WebSocket/wiki/Lost-connection-detection" );
		} else {
			if( webSocketImpl.isOpen() ) {
				webSocketImpl.sendPing();
			} else {
				log.trace("Trying to ping a non open connection: {}", webSocketImpl);
			}
		}
	}

Send a ping to the endpoint or close the connection since the other endpoint did not respond with a ping
@param webSocket the websocket instance
@param minimumPongTime the lowest/oldest allowable last pong time (in nanoTime) before we consider the connection to be lost


private void cancelConnectionLostTimer() {
       if( connectionLostCheckerService != null ) {
            connectionLostCheckerService.shutdownNow();
            connectionLostCheckerService = null;
        }
        if( connectionLostCheckerFuture != null ) {
        	connectionLostCheckerFuture.cancel(false);
            connectionLostCheckerFuture = null;
        }
    }

private void cancelConnectionLostTimer ( ) { if ( connectionLostCheckerService != null ) { connectionLostCheckerService . shutdownNow ( ) ; connectionLostCheckerService = null ; } if ( connectionLostCheckerFuture != null ) { connectionLostCheckerFuture . cancel ( false ) ; connectionLostCheckerFuture = null ; } }

Cancel any running timer for the connection lost detection
@since 1.3.4


@Override
	public ServerHandshakeBuilder onWebsocketHandshakeReceivedAsServer( WebSocket conn, Draft draft, ClientHandshake request ) throws InvalidDataException {
		return new HandshakeImpl1Server();
	}

@ Override public ServerHandshakeBuilder onWebsocketHandshakeReceivedAsServer ( WebSocket conn , Draft draft , ClientHandshake request ) throws InvalidDataException { return new HandshakeImpl1Server ( ) ; }

This default implementation does not do anything. Go ahead and overwrite it.

@see org.java_websocket.WebSocketListener#onWebsocketHandshakeReceivedAsServer(WebSocket, Draft, ClientHandshake)

This default implementation does not do anything . Go ahead and overwrite it .


@Override
	public void onWebsocketPing( WebSocket conn, Framedata f ) {
		conn.sendFrame( new PongFrame( (PingFrame)f ) );
	}

@ Override public void onWebsocketPing ( WebSocket conn , Framedata f ) { conn . sendFrame ( new PongFrame ( ( PingFrame ) f ) ) ; }

This default implementation will send a pong in response to the received ping.
The pong frame will have the same payload as the ping frame.

@see org.java_websocket.WebSocketListener#onWebsocketPing(WebSocket, Framedata)

This default implementation will send a pong in response to the received ping . The pong frame will have the same payload as the ping frame .


public void stop( int timeout ) throws InterruptedException {
		if( !isclosed.compareAndSet( false, true ) ) { // this also makes sure that no further connections will be added to this.connections
			return;
		}

		List<WebSocket> socketsToClose;

		// copy the connections in a list (prevent callback deadlocks)
		synchronized ( connections ) {
			socketsToClose = new ArrayList<WebSocket>( connections );
		}

		for( WebSocket ws : socketsToClose ) {
			ws.close( CloseFrame.GOING_AWAY );
		}

		wsf.close();

		synchronized ( this ) {
			if( selectorthread != null  && selector != null) {
				selector.wakeup();
				selectorthread.join( timeout );
			}
		}
	}

Closes all connected clients sockets, then closes the underlying
ServerSocketChannel, effectively killing the server socket selectorthread,
freeing the port the server was bound to and stops all internal workerthreads.

If this method is called before the server is started it will never start.

@param timeout
Specifies how many milliseconds the overall close handshaking may take altogether before the connections are closed without proper close handshaking.<br>

@throws InterruptedException Interrupt

Closes all connected clients sockets then closes the underlying ServerSocketChannel effectively killing the server socket selectorthread freeing the port the server was bound to and stops all internal workerthreads .


public int getPort() {
		int port = getAddress().getPort();
		if( port == 0 && server != null ) {
			port = server.socket().getLocalPort();
		}
		return port;
	}

public int getPort ( ) { int port = getAddress ( ) . getPort ( ) ; if ( port == 0 && server != null ) { port = server . socket ( ) . getLocalPort ( ) ; } return port ; }

Gets the port number that this server listens on.

@return The port number.

Gets the port number that this server listens on .


private void doAdditionalRead() throws InterruptedException, IOException {
		WebSocketImpl conn;
		while ( !iqueue.isEmpty() ) {
			conn = iqueue.remove( 0 );
			WrappedByteChannel c = ( (WrappedByteChannel) conn.getChannel() );
			ByteBuffer buf = takeBuffer();
			try {
				if( SocketChannelIOHelper.readMore( buf, conn, c ) )
					iqueue.add( conn );
				if( buf.hasRemaining() ) {
					conn.inQueue.put( buf );
					queue( conn );
				} else {
					pushBuffer( buf );
				}
			} catch ( IOException e ) {
				pushBuffer( buf );
				throw e;
			}
		}
	}

private void doAdditionalRead ( ) throws InterruptedException , IOException { WebSocketImpl conn ; while ( ! iqueue . isEmpty ( ) ) { conn = iqueue . remove ( 0 ) ; WrappedByteChannel c = ( ( WrappedByteChannel ) conn . getChannel ( ) ) ; ByteBuffer buf = takeBuffer ( ) ; try { if ( SocketChannelIOHelper . readMore ( buf , conn , c ) ) iqueue . add ( conn ) ; if ( buf . hasRemaining ( ) ) { conn . inQueue . put ( buf ) ; queue ( conn ) ; } else { pushBuffer ( buf ) ; } } catch ( IOException e ) { pushBuffer ( buf ) ; throw e ; } } }

Do an additional read
@throws InterruptedException thrown by taking a buffer
@throws IOException if an error happened during read


private void doAccept(SelectionKey key, Iterator<SelectionKey> i) throws IOException, InterruptedException {
		if( !onConnect( key ) ) {
			key.cancel();
			return;
		}

		SocketChannel channel = server.accept();
		if(channel==null){
			return;
		}
		channel.configureBlocking( false );
		Socket socket = channel.socket();
		socket.setTcpNoDelay( isTcpNoDelay() );
		socket.setKeepAlive( true );
		WebSocketImpl w = wsf.createWebSocket( this, drafts );
		w.setSelectionKey(channel.register( selector, SelectionKey.OP_READ, w ));
		try {
			w.setChannel( wsf.wrapChannel( channel, w.getSelectionKey() ));
			i.remove();
			allocateBuffers( w );
		} catch (IOException ex) {
			if( w.getSelectionKey() != null )
				w.getSelectionKey().cancel();

			handleIOException( w.getSelectionKey(), null, ex );
		}
	}

private void doAccept ( SelectionKey key , Iterator < SelectionKey > i ) throws IOException , InterruptedException { if ( ! onConnect ( key ) ) { key . cancel ( ) ; return ; } SocketChannel channel = server . accept ( ) ; if ( channel == null ) { return ; } channel . configureBlocking ( false ) ; Socket socket = channel . socket ( ) ; socket . setTcpNoDelay ( isTcpNoDelay ( ) ) ; socket . setKeepAlive ( true ) ; WebSocketImpl w = wsf . createWebSocket ( this , drafts ) ; w . setSelectionKey ( channel . register ( selector , SelectionKey . OP_READ , w ) ) ; try { w . setChannel ( wsf . wrapChannel ( channel , w . getSelectionKey ( ) ) ) ; i . remove ( ) ; allocateBuffers ( w ) ; } catch ( IOException ex ) { if ( w . getSelectionKey ( ) != null ) w . getSelectionKey ( ) . cancel ( ) ; handleIOException ( w . getSelectionKey ( ) , null , ex ) ; } }

Execute a accept operation
@param key the selectionkey to read off
@param i the iterator for the selection keys
@throws InterruptedException  thrown by taking a buffer
@throws IOException if an error happened during accept