/* * JBoss, Home of Professional Open Source. * Copyright 2006, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This 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 software 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 software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.protocol.mgmt; import java.io.Closeable; import java.io.IOException; import java.util.Map; import javax.net.ssl.SSLContext; import javax.security.auth.callback.CallbackHandler; import org.jboss.as.protocol.ProtocolConnectionConfiguration; import org.jboss.as.protocol.ProtocolConnectionManager; import org.jboss.as.protocol.logging.ProtocolLogger; import org.jboss.remoting3.Channel; import org.jboss.remoting3.CloseHandler; import org.jboss.remoting3.Connection; import org.xnio.OptionMap; /** * Strategy management clients can use for controlling the lifecycle of the channel. * * @author <a href="kabir.khan@jboss.com">Kabir Khan</a> * @author Emanuel Muckenhuber */ public abstract class ManagementClientChannelStrategy implements Closeable { /** The remoting channel service type. */ private static final String DEFAULT_CHANNEL_SERVICE_TYPE = "management"; /** * Get the channel. * * @return the channel * @throws IOException */ public abstract Channel getChannel() throws IOException; /** * Create a new client channel strategy. * * @param channel the existing channel * @return the management client channel strategy */ public static ManagementClientChannelStrategy create(final Channel channel) { return new Existing(channel); } /** * Create a new establishing management client channel-strategy * * @param baseConfig the base connection configuration * @param handler the {@code ManagementMessageHandler} * @param cbHandler a callback handler * @param saslOptions the sasl options * @param sslContext the ssl context * @param closeHandler a close handler * @return the management client channel strategy */ public static ManagementClientChannelStrategy create(final ProtocolConnectionConfiguration baseConfig, final ManagementMessageHandler handler, final CallbackHandler cbHandler, final Map<String, String> saslOptions, final SSLContext sslContext, final CloseHandler<Channel> closeHandler) { return create(createConfiguration(baseConfig, saslOptions, cbHandler, sslContext), ManagementChannelReceiver.createDelegating(handler), closeHandler); } /** * Create a new establishing management client channel-strategy * * @param configuration the connection configuration * @param receiver the channel receiver * @param closeHandler the close handler * @return the management client channel strategy */ public static ManagementClientChannelStrategy create(final ProtocolConnectionConfiguration configuration, final Channel.Receiver receiver, final CloseHandler<Channel> closeHandler) { return new Establishing(configuration, receiver, closeHandler); } /** * The existing channel strategy. */ private static class Existing extends ManagementClientChannelStrategy { // The underlying channel private final Channel channel; private volatile boolean closed = false; private Existing(final Channel channel) { this.channel = channel; } @Override public Channel getChannel() throws IOException { if(closed) { throw ProtocolLogger.ROOT_LOGGER.channelClosed(); } return channel; } @Override public void close() { this.closed = true; // closing the channel is not our responsibility } } private static ProtocolConnectionConfiguration createConfiguration(final ProtocolConnectionConfiguration configuration, final Map<String, String> saslOptions, final CallbackHandler callbackHandler, final SSLContext sslContext) { final ProtocolConnectionConfiguration config = ProtocolConnectionConfiguration.copy(configuration); config.setCallbackHandler(callbackHandler); config.setSslContext(sslContext); config.setSaslOptions(saslOptions); return config; } /** * When getting the underlying channel this strategy is trying to automatically (re-)connect * when either the connection or channel was closed. */ private static class Establishing extends FutureManagementChannel { private final String serviceType = DEFAULT_CHANNEL_SERVICE_TYPE; private final OptionMap channelOptions; private final Channel.Receiver receiver; private final ProtocolConnectionManager connectionManager; private final CloseHandler<Channel> closeHandler; private Establishing(final ProtocolConnectionConfiguration configuration, final Channel.Receiver receiver, final CloseHandler<Channel> closeHandler) { this.receiver = receiver; this.channelOptions = configuration.getOptionMap(); this.connectionManager = ProtocolConnectionManager.create(configuration, this); this.closeHandler = closeHandler; } @Override public Channel getChannel() throws IOException { Channel channel = super.getChannel(); if(channel != null) { return channel; } // Try to connect and wait for the channel connectionManager.connect(); // In case connect did not succeed the next getChannel() call needs to try to reconnect channel = super.getChannel(); if(channel == null) { throw ProtocolLogger.ROOT_LOGGER.channelClosed(); } return channel; } @Override public void connectionOpened(final Connection connection) throws IOException { final Channel channel = openChannel(connection, serviceType, channelOptions); if(setChannel(channel)) { channel.receiveMessage(receiver); } else { channel.closeAsync(); } } @Override public void close() throws IOException { try { super.close(); } finally { connectionManager.shutdown(); } } @Override protected Channel openChannel(final Connection connection, final String serviceType, final OptionMap options) throws IOException { final Channel channel = super.openChannel(connection, serviceType, options); channel.addCloseHandler(closeHandler); return channel; } } }