/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library 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 Lesser General Public License for more * details. */ package com.liferay.portal.fabric.netty.handlers; import com.liferay.portal.fabric.agent.FabricAgentRegistry; import com.liferay.portal.fabric.netty.agent.NettyFabricAgentConfig; import com.liferay.portal.fabric.netty.agent.NettyFabricAgentStub; import com.liferay.portal.fabric.netty.fileserver.handlers.FileResponseChannelHandler; import com.liferay.portal.fabric.netty.repository.NettyRepository; import com.liferay.portal.fabric.repository.Repository; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.util.CharPool; import com.liferay.portal.kernel.util.StringUtil; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.util.concurrent.EventExecutorGroup; import java.io.IOException; import java.net.SocketAddress; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; /** * @author Shuyang Zhou */ public class NettyFabricAgentRegistrationChannelHandler extends SimpleChannelInboundHandler<NettyFabricAgentConfig> { public NettyFabricAgentRegistrationChannelHandler( FabricAgentRegistry fabricAgentRegistry, Path repositoryParentPath, EventExecutorGroup eventExecutorGroup, long getFileTimeout, long rpcRelayTimeout, long startupTimeout) { if (fabricAgentRegistry == null) { throw new NullPointerException("Fabric agent registry is null"); } if (repositoryParentPath == null) { throw new NullPointerException("Repository parent path is null"); } if (eventExecutorGroup == null) { throw new NullPointerException("Event executor group is null"); } _fabricAgentRegistry = fabricAgentRegistry; _repositoryParentPath = repositoryParentPath; _eventExecutorGroup = eventExecutorGroup; _getFileTimeout = getFileTimeout; _rpcRelayTimeout = rpcRelayTimeout; _startupTimeout = startupTimeout; } @Override public void exceptionCaught( ChannelHandlerContext channelHandlerContext, Throwable throwable) { final Channel channel = channelHandlerContext.channel(); _log.error("Closing " + channel + " due to:", throwable); ChannelFuture channelFuture = channel.close(); channelFuture.addListener( new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture channelFuture) { if (_log.isInfoEnabled()) { _log.info(channel + " is closed"); } } }); } @Override protected void channelRead0( ChannelHandlerContext channelHandlerContext, NettyFabricAgentConfig nettyFabricAgentConfig) throws IOException { Channel channel = channelHandlerContext.channel(); SocketAddress socketAddress = channel.localAddress(); Path repositoryPath = Paths.get( _repositoryParentPath.toString(), StringUtil.replace( socketAddress.toString(), CharPool.COLON, CharPool.DASH)); Files.createDirectories(repositoryPath); Repository<Channel> repository = new NettyRepository( repositoryPath, _getFileTimeout); ChannelPipeline channelPipeline = channel.pipeline(); channelPipeline.addLast( new FileResponseChannelHandler( repository.getAsyncBroker(), _eventExecutorGroup)); NettyFabricAgentStub nettyFabricAgentStub = new NettyFabricAgentStub( channel, repository, nettyFabricAgentConfig.getRepositoryPath(), _rpcRelayTimeout, _startupTimeout); if (!_fabricAgentRegistry.registerFabricAgent( nettyFabricAgentStub, new OnRegistration( channel, nettyFabricAgentStub, repository))) { if (_log.isWarnEnabled()) { _log.warn("Rejected duplicated fabric agent on " + channel); } return; } if (_log.isInfoEnabled()) { _log.info("Registered fabric agent on " + channel); } } protected class OnRegistration implements Runnable { public OnRegistration( Channel channel, NettyFabricAgentStub nettyFabricAgentStub, Repository<Channel> repository) { _channel = channel; _nettyFabricAgentStub = nettyFabricAgentStub; _repository = repository; } @Override public void run() { NettyChannelAttributes.setNettyFabricAgentStub( _channel, _nettyFabricAgentStub); ChannelFuture channelFuture = _channel.closeFuture(); channelFuture.addListener( new PostDisconnectChannelFutureListener( _channel, _nettyFabricAgentStub, _repository)); } private final Channel _channel; private final NettyFabricAgentStub _nettyFabricAgentStub; private final Repository<Channel> _repository; } protected class PostDisconnectChannelFutureListener implements ChannelFutureListener { public PostDisconnectChannelFutureListener( Channel channel, NettyFabricAgentStub nettyFabricAgentStub, Repository<Channel> repository) { _channel = channel; _nettyFabricAgentStub = nettyFabricAgentStub; _repository = repository; } @Override public void operationComplete(ChannelFuture channelFuture) { if (_fabricAgentRegistry.unregisterFabricAgent( _nettyFabricAgentStub, null)) { if (_log.isInfoEnabled()) { _log.info("Unregistered fabric agent on " + _channel); } } else if (_log.isWarnEnabled()) { _log.warn("Unable to unregister fabric agent on " + _channel); } _repository.dispose(true); } private final Channel _channel; private final NettyFabricAgentStub _nettyFabricAgentStub; private final Repository<Channel> _repository; } private static final Log _log = LogFactoryUtil.getLog( NettyFabricAgentRegistrationChannelHandler.class); private final EventExecutorGroup _eventExecutorGroup; private final FabricAgentRegistry _fabricAgentRegistry; private final long _getFileTimeout; private final Path _repositoryParentPath; private final long _rpcRelayTimeout; private final long _startupTimeout; }