How can I detect network disconnection in Apache Camel?

前端 未结 2 1895
心在旅途
心在旅途 2021-01-28 20:34

I need to log when a client is disconnected from Apache Camel connection. How can I detect a netty-tcp disconnection?

    from(\"{{uri.client.address}}\")


        
相关标签:
2条回答
  • 2021-01-28 21:04

    Use an ErrorHandler, e.g. the LoggingErrorHandler:

    RouteBuilder builder = new RouteBuilder() {
        public void configure() {
            // use logging error handler
            errorHandler(loggingErrorHandler("com.mycompany.foo"));
    
            // here is our regular route
            from("{{uri.client.address}}").to("mock:out");
        }
    }; 
    
    0 讨论(0)
  • 2021-01-28 21:24

    Its a bit more complicated to log individual client disconnects but I will try to share what I had to do.

    You need to extend SimpleChannelInboundHandler with your own class and add the methods needed. For an example class see here:

    https://github.com/apache/camel/blob/master/components/camel-netty4/src/main/java/org/apache/camel/component/netty4/handlers/ServerChannelHandler.java

    The main method there to look at which I have changed to include client disconnect is this one:

     @Override
      public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //command to send when there is a disconnect from client side
        String command = "clientDisconnect";
        if (LOG.isTraceEnabled()) {
          LOG.trace("Channel closed: {}", ctx.channel());
        }
        LOG.info("Channel has disconnected: affects ", uniqueClientId);
        //create Exchange and let the consumer process it
        final Exchange exchange = consumer.getEndpoint().createExchange(ctx, command);
        //create inOnly as there is no client waiting for a response
        exchange.setPattern(ExchangePattern.InOnly);
        // set the exchange charset property for converting
        if (consumer.getConfiguration().getCharsetName() != null) {
          exchange.setProperty(Exchange.CHARSET_NAME, IOHelper.normalizeCharset(consumer.getConfiguration().getCharsetName()));
        }
        // we want to handle the UoW
        consumer.createUoW(exchange);
        //set the uniqueClientId
        beforeProcess(exchange, ctx, command);
        processAsynchronously(exchange, ctx, command);
        // to keep track of open sockets
        consumer.getNettyServerBootstrapFactory().removeChannel(ctx.channel());
        super.channelInactive(ctx);
    }
    

    Note the part where I log if the channel has connected.

    You can also log the ip address of different client if you want to do different things for different clients in your main route. This should help you.

    Edit: Once you have extended that class, call the extended class TCPServerHandler. Then you need to create a TCPServerHandlerFactory to refer to previous class and set your encoder/decoder. This class can look like this:

    public class TCPServerInitializerFactory extends ServerInitializerFactory  {
      private NettyConsumer consumer;
    
      public TCPServerInitializerFactory(NettyConsumer consumer) {
        this.consumer = consumer;
      }
      @Override
      protected void initChannel(Channel channel) throws Exception {
        ChannelPipeline pipeline = channel.pipeline();
        pipeline.addLast("string-encoder", new StringEncoder(CharsetUtil.UTF_8));
        pipeline.addLast("string-decoder", new StringDecoder(CharsetUtil.UTF_8));
        **pipeline.addLast("handler", new TCPServerHandler(consumer));**
      }
    
      @Override
      public ServerInitializerFactory createPipelineFactory(NettyConsumer nettyConsumer) {
        return new TCPServerInitializerFactory(nettyConsumer);
      }
    }
    

    The line marked with ** is where you are creating the TCPServerHandler class.

    Then back in camel in your route class you need to add the factory to your registry like this:

    TCPServerInitializerFactory serverFactory = new TCPServerInitializerFactory(null);
        final CamelContext camelContext = getContext();
        final org.apache.camel.impl.SimpleRegistry registry = new org.apache.camel.impl.SimpleRegistry();
        final org.apache.camel.impl.CompositeRegistry compositeRegistry = new org.apache.camel.impl.CompositeRegistry();
        compositeRegistry.addRegistry(camelContext.getRegistry());
        compositeRegistry.addRegistry(registry);
        ((org.apache.camel.impl.DefaultCamelContext) camelContext).setRegistry(compositeRegistry);
    registry.put("spf", serverFactory);
    

    Then refer to it as such:

    from("netty4:tcp://0.0.0.0:3000?serverInitializerFactory=#spf&sync=true")...
    

    Now you may wondering, all of this to register a log for a disconnect. This is because to be able to distinguish when a client disconnects and actually get the ip of the client you need to the Netty code. You can save some value in the exchange and then later in your route do something.

    0 讨论(0)
提交回复
热议问题