Java tutorial
/* KIARA - Middleware for efficient and QoS/Security-aware invocation of services and exchange of messages * * Copyright (C) 2014 German Research Center for Artificial Intelligence (DFKI) * * 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 3 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. */ package org.fiware.kiara.netty; import org.fiware.kiara.transport.impl.TransportImpl; import org.fiware.kiara.transport.TransportFactory; import org.fiware.kiara.transport.impl.TransportMessageListener; import org.fiware.kiara.transport.impl.TransportMessage; import org.fiware.kiara.transport.impl.TransportConnectionListener; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import java.io.IOException; import java.net.SocketAddress; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author Dmitri Rubinstein {@literal <dmitri.rubinstein@dfki.de>} * @param <I> * @param <T> */ public abstract class BaseHandler<I, T extends TransportFactory> extends SimpleChannelInboundHandler<I> implements TransportImpl { private static final Logger logger = LoggerFactory.getLogger(BaseHandler.class); private final T transportFactory; protected volatile Channel channel = null; private TransportConnectionListener connectionListener; private final List<TransportMessageListener> listeners = new ArrayList<>(); public static enum Mode { CLIENT, SERVER } protected final Mode mode; public static enum State { UNINITIALIZED, WAIT_CONNECT, CONNECTED, WAIT_CLOSE, CLOSED } protected State state; protected BaseHandler(Mode mode, State state, T transportFactory, TransportConnectionListener connectionListener) { this.mode = mode; this.state = state; this.connectionListener = connectionListener; this.transportFactory = transportFactory; } @Override public T getTransportFactory() { return transportFactory; } @Override public void addMessageListener(TransportMessageListener listener) { if (listener == null) { throw new NullPointerException("listener"); } synchronized (listeners) { listeners.add(listener); } } @Override public boolean removeMessageListener(TransportMessageListener listener) { if (listener == null) { return false; } synchronized (listeners) { return listeners.remove(listener); } } public TransportConnectionListener getConnectionListener() { return connectionListener; } public void setConnectionListener(TransportConnectionListener connectionListener) { this.connectionListener = connectionListener; } protected final void notifyListeners(final TransportMessage message) { TransportMessageListener currentListeners[] = null; synchronized (listeners) { if (!listeners.isEmpty()) { currentListeners = listeners.toArray(new TransportMessageListener[listeners.size()]); } } if (currentListeners != null) { for (TransportMessageListener listener : currentListeners) { if (listener.onMessage(message)) break; } } } @Override public SocketAddress getLocalAddress() { if (channel == null) { throw new IllegalStateException(); } return channel.localAddress(); } @Override public SocketAddress getRemoteAddress() { if (channel == null) { throw new IllegalStateException(); } return channel.remoteAddress(); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { channel = ctx.channel(); switch (state) { case UNINITIALIZED: case WAIT_CONNECT: state = State.CONNECTED; if (connectionListener != null) { connectionListener.onConnectionOpened(this); } break; case WAIT_CLOSE: closeChannel(); break; default: throw new IllegalStateException(); } } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { if (logger.isDebugEnabled()) { logger.debug("Class: " + getClass().getName() + ", channel closed {}", ctx); } state = State.CLOSED; channel = null; if (connectionListener != null) { connectionListener.onConnectionClosed(this); } } @Override public void channelReadComplete(ChannelHandlerContext ctx) { ctx.flush(); } protected final void closeChannel() { if (channel != null) { channel.closeFuture().addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { future.removeListener(this); state = State.CLOSED; channel = null; } }); } } @Override public void close() throws IOException { if (state == State.WAIT_CLOSE || state == State.CLOSED) { return; } state = State.WAIT_CLOSE; closeChannel(); } @Override public boolean isOpen() { return state == State.CONNECTED && channel != null; } }