Java tutorial
/* * Copyright (c) 2015 The Jupiter Project * * Licensed under the Apache License, version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jupiter.transport.netty.handler.connector; import io.netty.channel.*; import io.netty.util.ReferenceCountUtil; import org.jupiter.common.util.Signal; import org.jupiter.common.util.internal.logging.InternalLogger; import org.jupiter.common.util.internal.logging.InternalLoggerFactory; import org.jupiter.transport.netty.channel.NettyChannel; import org.jupiter.transport.payload.JResponseBytes; import org.jupiter.transport.processor.ConsumerProcessor; import java.io.IOException; import static org.jupiter.common.util.StackTraceUtil.stackTrace; /** * jupiter * org.jupiter.transport.netty.handler.connector * * @author jiachun.fjc */ @ChannelHandler.Sharable public class ConnectorHandler extends ChannelInboundHandlerAdapter { private static final InternalLogger logger = InternalLoggerFactory.getInstance(ConnectorHandler.class); private ConsumerProcessor processor; @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Channel ch = ctx.channel(); if (msg instanceof JResponseBytes) { try { processor.handleResponse(NettyChannel.attachChannel(ch), (JResponseBytes) msg); } catch (Throwable t) { logger.error("An exception was caught: {}, on {} #channelRead().", stackTrace(t), ch); } } else { if (logger.isWarnEnabled()) { logger.warn("Unexpected message type received: {}, channel: {}.", msg.getClass(), ch); } ReferenceCountUtil.release(msg); } } @Override public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { Channel ch = ctx.channel(); ChannelConfig config = ch.config(); // ?: ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK // ?: ChannelOption.WRITE_BUFFER_LOW_WATER_MARK if (!ch.isWritable()) { // ?channel(OutboundBuffer)?WRITE_BUFFER_HIGH_WATER_MARK if (logger.isWarnEnabled()) { logger.warn( "{} is not writable, high water mask: {}, the number of flushed entries that are not written yet: {}.", ch, config.getWriteBufferHighWaterMark(), ch.unsafe().outboundBuffer().size()); } config.setAutoRead(false); } else { // ??OutboundBuffer?WRITE_BUFFER_LOW_WATER_MARK if (logger.isWarnEnabled()) { logger.warn( "{} is writable(rehabilitate), low water mask: {}, the number of flushed entries that are not written yet: {}.", ch, config.getWriteBufferLowWaterMark(), ch.unsafe().outboundBuffer().size()); } config.setAutoRead(true); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { Channel ch = ctx.channel(); if (cause instanceof Signal) { logger.error("An I/O signal was caught: {}, force to close channel: {}.", ((Signal) cause).name(), ch); ch.close(); } else if (cause instanceof IOException) { logger.error("An I/O exception was caught: {}, force to close channel: {}.", stackTrace(cause), ch); ch.close(); } else { logger.error("An unexpected exception was caught: {}, channel: {}.", stackTrace(cause), ch); } } public ConsumerProcessor processor() { return processor; } public void processor(ConsumerProcessor processor) { this.processor = processor; } }