All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.atomix.catalyst.transport.netty.NettyHandler Maven / Gradle / Ivy

There is a newer version: 1.2.1
Show newest version
/*
 * Copyright 2015 the original author or authors.
 *
 * 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 io.atomix.catalyst.transport.netty;

import io.atomix.catalyst.concurrent.SingleThreadContext;
import io.atomix.catalyst.concurrent.ThreadContext;
import io.atomix.catalyst.transport.Connection;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;

/**
 * Netty handler.
 *
 * @author Jordan Halterman
 */
class NettyHandler extends ChannelInboundHandlerAdapter {
  private final Map connections;
  private final Consumer listener;
  private final ThreadContext context;
  private final NettyOptions options;

  protected NettyHandler(Map connections, Consumer listener, ThreadContext context, NettyOptions options) {
    this.connections = connections;
    this.listener = listener;
    this.context = context;
    this.options = options;
  }

  /**
   * Adds a connection for the given channel.
   *
   * @param channel The channel for which to add the connection.
   * @param connection The connection to add.
   */
  protected void setConnection(Channel channel, NettyConnection connection) {
    connections.put(channel, connection);
  }

  /**
   * Returns the connection for the given channel.
   *
   * @param channel The channel for which to return the connection.
   * @return The connection.
   */
  protected NettyConnection getConnection(Channel channel) {
    return connections.get(channel);
  }

  /**
   * Removes the connection for the given channel.
   *
   * @param channel The channel for which to remove the connection.
   * @return The connection.
   */
  protected NettyConnection removeConnection(Channel channel) {
    return connections.remove(channel);
  }

  /**
   * Returns the current execution context or creates one.
   */
  private ThreadContext getOrCreateContext(Channel channel) {
    ThreadContext context = ThreadContext.currentContext();
    if (context != null) {
      return context;
    }
    return new SingleThreadContext(Thread.currentThread(), channel.eventLoop(), this.context.serializer().clone());
  }

  @Override
  public void channelActive(ChannelHandlerContext context) throws Exception {
    Channel channel = context.channel();
    NettyConnection connection = new NettyConnection(channel, getOrCreateContext(channel), options);
    setConnection(channel, connection);
    // synchronously notify listeners in order to ensure message handlers
    // are registered before messages are handled.
    CompletableFuture.runAsync(() -> listener.accept(connection), this.context.executor()).join();
  }

  @Override
  public void channelRead(final ChannelHandlerContext context, Object message) {
    ByteBuf buffer = (ByteBuf) message;
    int type = buffer.readByte();
    switch (type) {
      case NettyConnection.REQUEST:
        handleRequest(buffer, context);
        break;
      case NettyConnection.RESPONSE:
        handleResponse(buffer, context);
        break;
    }
  }

  /**
   * Handles a request.
   */
  private void handleRequest(ByteBuf request, ChannelHandlerContext context) {
    NettyConnection connection = getConnection(context.channel());
    if (connection != null) {
      connection.handleRequest(request);
    }
  }

  /**
   * Handles a response.
   */
  private void handleResponse(ByteBuf response, ChannelHandlerContext context) {
    NettyConnection connection = getConnection(context.channel());
    if (connection != null) {
      connection.handleResponse(response);
    }
  }

  @Override
  public void exceptionCaught(ChannelHandlerContext context, final Throwable t) throws Exception {
    Channel channel = context.channel();
    NettyConnection connection = getConnection(channel);
    if (connection != null) {
      try {
        if (channel.isOpen()) {
          channel.close();
        }
      } catch (Throwable ignore) {
      }
      connection.handleException(t);
    } else {
      channel.close();
    }
  }

  @Override
  public void channelInactive(ChannelHandlerContext context) throws Exception {
    Channel channel = context.channel();
    NettyConnection connection = removeConnection(channel);
    if (connection != null) {
      connection.handleClosed();
    }
  }

  @Override
  public void userEventTriggered(ChannelHandlerContext context, Object event) throws Exception {
    if (event instanceof IdleStateEvent && ((IdleStateEvent) event).state() == IdleState.ALL_IDLE) {
      context.close();
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy