org.dcache.util.ChannelCdcSessionHandlerWrapper.java Source code

Java tutorial

Introduction

Here is the source code for org.dcache.util.ChannelCdcSessionHandlerWrapper.java

Source

/* dCache - http://www.dcache.org/
 *
 * Copyright (C) 2018 Deutsches Elektronen-Synchrotron
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.dcache.util;

import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelOutboundHandler;
import io.netty.channel.ChannelPromise;
import io.netty.util.AttributeKey;

import java.net.SocketAddress;

import dmg.cells.nucleus.CDC;

/**
 * This class wraps some ChannelDuplexHandler and ensures that, if the Netty
 * Channel has a specific key then the value of this key is used as the CDC
 * session.  This class is really a hack to work-around that CDC is a
 * thread-local value that is not propagated when Netty schedules tasks outside
 * of the event loop.  Such scheduled tasks current happen in the pool, as the
 * response to a CloseRequest is delayed until after the mover has closed.
 * There seems to be no easy way to propagate the CDC within Netty scheduled
 * tasks.
 */
@Sharable
public class ChannelCdcSessionHandlerWrapper implements ChannelOutboundHandler, ChannelInboundHandler {
    public static final AttributeKey<String> SESSION = AttributeKey.newInstance("org.dcache.cells.cdc.session");

    private final ChannelDuplexHandler _inner;

    public ChannelCdcSessionHandlerWrapper(ChannelDuplexHandler inner) {
        _inner = inner;
    }

    /**
     * Bind a particular session value to this channel.
     */
    public static void bindSessionToChannel(Channel channel, String session) {
        channel.attr(SESSION).set(session);
    }

    /*
     * Decorate ChannelOutboundHandler methods.
     */

    @Override
    public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)
            throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.bind(ctx, localAddress, promise);
        }
    }

    @Override
    public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
            ChannelPromise promise) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.connect(ctx, remoteAddress, localAddress, promise);
        }
    }

    @Override
    public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.disconnect(ctx, promise);
        }
    }

    @Override
    public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.close(ctx, promise);
        }
    }

    @Override
    public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.deregister(ctx, promise);
        }
    }

    @Override
    public void read(ChannelHandlerContext ctx) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.read(ctx);
        }
    }

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.write(ctx, msg, promise);
        }
    }

    @Override
    public void flush(ChannelHandlerContext ctx) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.flush(ctx);
        }
    }

    /*
     * Decorate ChannelInboundHandler methods.
     */

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.channelRegistered(ctx);
        }
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.channelUnregistered(ctx);
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.channelActive(ctx);
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.channelInactive(ctx);
        }
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.channelRead(ctx, msg);
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.channelReadComplete(ctx);
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.channelWritabilityChanged(ctx);
        }
    }

    @Override
    @SuppressWarnings("deprecation")
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.exceptionCaught(ctx, cause);
        }
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.handlerAdded(ctx);
        }
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        try (AutoCloseable oldCdc = withCdcSession(ctx)) {
            _inner.handlerRemoved(ctx);
        }
    }

    private AutoCloseable withCdcSession(ChannelHandlerContext ctx) {
        if (CDC.getSession() == null) {
            String session = ctx.channel().attr(SESSION).get();
            if (session != null) {
                CDC captured = new CDC();
                CDC.setSession(session);
                return captured;
            }
        }
        return () -> {
        };
    }
}