All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ow2.petals.microkernel.transport.platform.nio.server.NioServerAgent Maven / Gradle / Ivy

There is a newer version: 4.3.0
Show newest version
/**
 * Copyright (c) 2009-2012 Capgemini, 2009-2012 EBM WebSourcing, 2012-2016 Linagora
 * 
 * This program/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 program/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 program/library; If not, see http://www.gnu.org/licenses/
 * for the GNU Lesser General Public License version 2.1.
 */
package org.ow2.petals.microkernel.transport.platform.nio.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Logger;

import org.objectweb.fractal.fraclet.annotations.Component;
import org.objectweb.fractal.fraclet.annotations.Interface;
import org.objectweb.fractal.fraclet.annotations.Lifecycle;
import org.objectweb.fractal.fraclet.annotations.Requires;
import org.objectweb.fractal.fraclet.types.Step;
import org.ow2.petals.basisapi.exception.PetalsException;
import org.ow2.petals.microkernel.api.configuration.ConfigurationService;
import org.ow2.petals.microkernel.api.transport.FastRemoteTransportService;
import org.ow2.petals.microkernel.transport.Transporter;
import org.ow2.petals.microkernel.transport.platform.nio.monitoring.TcpTransporterMonitoring;
import org.ow2.petals.microkernel.transport.platform.nio.selector.InputSocketChannelContext;
import org.ow2.petals.microkernel.transport.platform.nio.selector.NioSelector;
import org.ow2.petals.microkernel.transport.platform.nio.selector.NioServer;
import org.ow2.petals.microkernel.transport.platform.nio.selector.PipedDeserializer;

import com.ebmwebsourcing.easycommons.log.LoggingUtil;

/**
 * The server agent of the NIO transporter.
 * 
 * @author Christophe DENEUX - Capgemini Sud
 */
@Component(provides = @Interface(name = "service", signature = NioServer.class) )
public class NioServerAgent implements NioServer {

    /**
     * The socket selector Fractal component to use to process network IO.
     */
    @Requires(name = NioSelector.NIO_SELECTOR_ITF)
    protected NioSelector selectorAgent;

    @Requires(name = NioReceiver.NIO_MSG_RECEIVER_ITF)
    protected NioReceiver messageReceiver;

    /**
     * Interface used to access configuration
     */
    @Requires(name = "configuration")
    protected ConfigurationService configurationService;

    /**
     * The TCP transporter monitoring service - Fractal component
     */
    @Requires(name = "transportermonitoring")
    private TcpTransporterMonitoring tcpTransporterMonitoring;

    private final LoggingUtil log = new LoggingUtil(Logger.getLogger(Constants.FRACTAL_COMPONENT_LOGGER_NAME));

    /**
     * The server socket on which connections are waited.
     */
    private InetSocketAddress serverSocket;

    /**
     * The server socket channel on which connections are waited.
     */
    private ServerSocketChannel serverSocketChannel;

    /**
     * Map containing the deserialization task associated to each socket channel.
     */
    private final Map deserializationTasks = new ConcurrentHashMap();

    /**
     * Acceptor thread pool. An acceptor is in charge to deserialize received data into its associated object and
     * transmit it to the {@link Transporter}.
     */
    private ThreadPoolExecutor threadPoolTaskExecutor = null;

    /**
     * 

* Counters about current connections established, with their state ACTIVE (index {@link #CONNECTION_STATE_ACTIVE}) * or ESTABLISHED (index {@link #CONNECTION_STATE_ESTABLISHED}), per remote container identified by its IP address. *

*

* The number of IDLE connections is the number of ESTABLISHED connections minus the number of ACTIVE connections. *

*/ private final ConcurrentMap currentConnections = new ConcurrentHashMap(); /** * Index into atomic long array of {@link #currentConnections} for ACTIVE connections */ private final static int CONNECTION_STATE_ACTIVE = 0; /** * Index into atomic long array of {@link #currentConnections} for an established connections (active or idle) */ private final static int CONNECTION_STATE_ESTABLISHED = 1; @Lifecycle(step = Step.START) public void start() throws Exception { this.log.start(); this.currentConnections.clear(); final int listenPort = this.configurationService.getContainerConfiguration().getTCPPort(); String host = this.configurationService.getContainerConfiguration().getTCPListen(); if (host == null || host.isEmpty()) { host = FastRemoteTransportService.DEFAULT_RECEIVER_LISTENING_ITF; this.log.config( "No value or empty value for the TCP listen interface, all network interfaces of the container host are used."); } this.serverSocket = new InetSocketAddress(host, listenPort); this.log.debug("Starting NIO transporter server on " + this.serverSocket + "..."); this.serverSocketChannel = ServerSocketChannel.open(); // Caution, as the queue of the thread pool is a LinkedBlockingQueue, // the parameters maxPoolSize has no sense. The keep alive time is used to decrease the core size when no // request incomes. final int nbAcceptors = this.configurationService.getContainerConfiguration().getTCPReceivers(); final long keepAliveTime = this.configurationService.getContainerConfiguration().getTCPReceiversKeepAlive(); this.threadPoolTaskExecutor = new ThreadPoolExecutor(nbAcceptors, nbAcceptors, keepAliveTime, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), new DeserializerThreadFactory(this.log)); this.threadPoolTaskExecutor.allowCoreThreadTimeOut(true); // TODO: Set socket options // this.serverSocketChannel.socket().setPerformancePreferences(0, 1, 2); try { this.serverSocketChannel.socket().bind(this.serverSocket, 100); } catch (final IOException e) { throw new PetalsException("The NIO tranporter can't listen on " + this.serverSocket, e); } this.serverSocketChannel.configureBlocking(false); this.log.info("The NIO transporter server is ready to process requests on " + this.serverSocket + "."); this.selectorAgent.register(SelectionKey.OP_ACCEPT, this.serverSocketChannel, this); this.log.end(); } @Lifecycle(step = Step.STOP) public void stop() { this.log.start(); this.log.debug("Stopping NIO Server agent."); try { this.serverSocketChannel.close(); } catch (final Exception e) { this.log.warning("Can't close the channel", e); } this.log.info("The NIO Server agent is stopped."); this.threadPoolTaskExecutor.shutdownNow(); this.log.end(); } public void onConnectionIsAccepted(final SocketChannel socketChannel, final Selector selector) throws IOException { final Socket socket = socketChannel.socket(); this.log.info("A connection is accepted: " + socket.toString()); final String containerIpAddress = socket.getInetAddress().getHostAddress(); this.tcpTransporterMonitoring.newIncomingConnection(containerIpAddress); final AtomicLong[] currentConnectionForContainer = this.currentConnections.putIfAbsent(containerIpAddress, new AtomicLong[] { new AtomicLong(0), new AtomicLong(1) }); if (currentConnectionForContainer != null) { currentConnectionForContainer[CONNECTION_STATE_ESTABLISHED].incrementAndGet(); } tcpTransporterMonitoring.pickIncomingConnectionNumbers(containerIpAddress); final PipedDeserializer deserializer = new PipedDeserializerImpl(socket, this.messageReceiver, this.tcpTransporterMonitoring, this.log.getLogger(), this.log); this.deserializationTasks.put(socketChannel, deserializer); socketChannel.register(selector, SelectionKey.OP_READ, new InputSocketChannelContext(socketChannel, deserializer, this)); } public void onRead(final PipedDeserializer deserializer) { try { this.threadPoolTaskExecutor.execute(deserializer); } catch (final RejectedExecutionException e) { this.log.error("A message deserialization task has been rejected (" + e.getMessage() + ")"); } } public void onClose(final SocketChannel socketChannel) { // We free the deserializer associated to the socket channel this.deserializationTasks.remove(socketChannel); final Socket socket = socketChannel.socket(); final String containerIpAddress = socket.getInetAddress().getHostAddress(); final AtomicLong[] currentConnectionForContainer = this.currentConnections.putIfAbsent(containerIpAddress, new AtomicLong[] { new AtomicLong(0), new AtomicLong(0) }); if (currentConnectionForContainer != null) { currentConnectionForContainer[CONNECTION_STATE_ESTABLISHED].decrementAndGet(); } tcpTransporterMonitoring.pickIncomingConnectionNumbers(containerIpAddress); this.log.info("A connection is released: " + socket.toString()); } @Override public void onConnectionActive(final SocketChannel socketChannel) { final String containerIpAddress = socketChannel.socket().getInetAddress().getHostAddress(); final AtomicLong[] currentConnectionForContainer = this.currentConnections.putIfAbsent(containerIpAddress, new AtomicLong[] { new AtomicLong(1), new AtomicLong(0) }); if (currentConnectionForContainer != null) { currentConnectionForContainer[CONNECTION_STATE_ACTIVE].incrementAndGet(); } this.tcpTransporterMonitoring.pickIncomingConnectionNumbers(containerIpAddress); this.tcpTransporterMonitoring.incPendingIncomingMessagesProbe(containerIpAddress); } @Override public void onConnectionIdle(final SocketChannel socketChannel) { final String containerIpAddress = socketChannel.socket().getInetAddress().getHostAddress(); final AtomicLong[] currentConnectionForContainer = this.currentConnections.putIfAbsent(containerIpAddress, new AtomicLong[] { new AtomicLong(0), new AtomicLong(1) }); if (currentConnectionForContainer != null) { currentConnectionForContainer[CONNECTION_STATE_ACTIVE].decrementAndGet(); } this.tcpTransporterMonitoring.pickIncomingConnectionNumbers(containerIpAddress); // Here the data was read from the media, but now not converted into a message exchange, so the receipt is // always in progress. See PipedDeserializeImpl.run(). } @Override public long getNumActiveConnections(final String containerIpAddress) { return this.currentConnections.get(containerIpAddress)[CONNECTION_STATE_ACTIVE].longValue(); } @Override public long getNumIdleConnections(final String containerIpAddress) { final AtomicLong[] values = this.currentConnections.get(containerIpAddress); return values[CONNECTION_STATE_ESTABLISHED].longValue() - values[CONNECTION_STATE_ACTIVE].longValue(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy