/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2011-2012 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.netmgt.provision.support; import java.net.SocketAddress; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import org.apache.mina.core.RuntimeIoException; import org.apache.mina.core.future.CloseFuture; import org.apache.mina.core.future.ConnectFuture; import org.apache.mina.core.future.IoFutureListener; import org.apache.mina.core.service.IoHandler; import org.apache.mina.core.service.IoProcessor; import org.apache.mina.core.service.SimpleIoProcessorPool; import org.apache.mina.core.session.IoSessionInitializer; import org.apache.mina.transport.socket.SocketConnector; import org.apache.mina.transport.socket.nio.NioProcessor; import org.apache.mina.transport.socket.nio.NioSession; import org.apache.mina.transport.socket.nio.NioSocketConnector; import org.opennms.core.utils.LogUtils; /** * <p>This {@link ConnectionFactory} type will create a new {@link NioSocketConnector} * for every call to {@link #connect(SocketAddress, SocketAddress, IoSessionInitializer)}. * This is a naive implementation that does not really take advantage of the asynchronous * operations in MINA since it is creating new threads for each socket operation.</p> * * @author Seth * @author ranger * @author Duncan Mackintosh */ public class ConnectionFactoryNewConnectorImpl extends ConnectionFactory { private static final Executor m_executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); private static final IoProcessor<NioSession> m_processor = new SimpleIoProcessorPool<NioSession>(NioProcessor.class, m_executor); /** * Create a new factory. Private because one should use {@link #getFactory(int)} */ protected ConnectionFactoryNewConnectorImpl(int timeoutInMillis) { super(timeoutInMillis); } private static final NioSocketConnector getSocketConnector(long timeout, IoHandler handler) { // Create a new NioSocketConnector NioSocketConnector connector = new NioSocketConnector(m_executor, m_processor); connector.setHandler(handler); connector.setConnectTimeoutMillis(timeout); return connector; } /** * <p>Connect to a remote socket. If org.opennms.netmgt.provision.maxConcurrentConnections * is set, this may block until a connection slot is available.</p> * * <p>You must dispose both the {@link ConnectionFactoryNewConnectorImpl} and {@link ConnectFuture} when done * by calling {@link #dispose(ConnectionFactoryNewConnectorImpl, ConnectFuture)}.</p> * * @param remoteAddress * Destination address * @param init * Initialiser for the IoSession * @return * ConnectFuture from a Mina connect call */ @Override public ConnectFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, IoSessionInitializer<? extends ConnectFuture> init, IoHandler handler) { SocketConnector connector = getSocketConnector(getTimeout(), handler); final ConnectFuture cf = connector.connect(remoteAddress, localAddress, init); cf.addListener(connectorDisposer(connector)); return cf; } private static IoFutureListener<ConnectFuture> connectorDisposer(final SocketConnector connector) { return new IoFutureListener<ConnectFuture>() { public void operationComplete(ConnectFuture future) { try { // Add a listener to the CloseFuture that will dispose of the connector once the // conversation is complete future.getSession().getCloseFuture().addListener(new IoFutureListener<CloseFuture>() { @Override public void operationComplete(CloseFuture future) { LogUtils.debugf(this, "Disposing of connector: %s", Thread.currentThread().getName()); connector.dispose(); } }); } catch (RuntimeIoException e) { LogUtils.debugf(this, e, "Exception of type %s caught, disposing of connector: %s", e.getClass().getName(), Thread.currentThread().getName()); // This will be thrown in the event of a ConnectException for example connector.dispose(); } } }; } /** * Delegates completely to {@link #connect(SocketAddress, SocketAddress, IoSessionInitializer, IoHandler)} * since we are recreating connectors during each invocation. * * @param remoteAddress * @param localAddress * @param init * @param handler */ @Override public ConnectFuture reConnect(SocketAddress remoteAddress, SocketAddress localAddress, IoSessionInitializer<? extends ConnectFuture> init, IoHandler handler) { return connect(remoteAddress, localAddress, init, handler); } @Override protected void dispose() { // Do nothing; we dispose of every NioSocketConnector as soon as a session is complete } }