Package org.restlet.engine.connector

Source Code of org.restlet.engine.connector.ConnectionController

/**
* Copyright 2005-2011 Noelios Technologies.
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL 1.0 (the
* "Licenses"). You can select the license that you prefer but you may not use
* this file except in compliance with one of these Licenses.
*
* You can obtain a copy of the LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0.html
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1.php
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1.php
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://www.noelios.com/products/restlet-engine
*
* Restlet is a registered trademark of Noelios Technologies.
*/

package org.restlet.engine.connector;

import java.io.IOException;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Level;

import org.restlet.Context;
import org.restlet.engine.io.IoState;
import org.restlet.util.SelectionListener;
import org.restlet.util.SelectionRegistration;

/**
* Controls the IO work of parent connector helper and manages its connections.
*
* @author Jerome Louvel
*/
public class ConnectionController extends Controller implements Runnable {

    /** The NIO selector. */
    private volatile Selector selector;

    /** The list of new selection registrations. */
    private final Queue<SelectionRegistration> newRegistrations;

    /** The list of updated selection registrations. */
    private final Queue<SelectionRegistration> updatedRegistrations;

    /**
     * Constructor.
     *
     * @param helper
     *            The parent connector helper.
     */
    public ConnectionController(ConnectionHelper<?> helper) {
        super(helper);
        this.newRegistrations = new ConcurrentLinkedQueue<SelectionRegistration>();
        this.updatedRegistrations = new ConcurrentLinkedQueue<SelectionRegistration>();
    }

    /**
     * Control each connection for messages to read or write.
     *
     * @throws IOException
     */
    protected void controlConnections() throws IOException {
        // Close connections or register interest in NIO operations
        for (Connection<?> conn : getHelper().getConnections()) {
            if (conn.getState() == ConnectionState.CLOSED) {
                // Detach the connection and collect it
                getHelper().getConnections().remove(conn);
                getHelper().checkin(conn);
            } else if ((conn.getState() == ConnectionState.CLOSING)
                    && conn.isEmpty()) {
                conn.close(false);
            } else if (conn.hasTimedOut()) {
                conn.onTimeOut();
            } else if (conn.updateState()) {
                getUpdatedRegistrations().add(conn.getRegistration());
            } else if (conn.getInboundWay().getIoState() == IoState.READY) {
                conn.getInboundWay().onSelected();
            } else if (conn.getOutboundWay().getIoState() == IoState.READY) {
                conn.getOutboundWay().onSelected();
            }
        }
    }

    /**
     * Creates a new NIO selector.
     *
     * @return A new NIO selector.
     */
    protected Selector createSelector() {
        Selector result = null;

        try {
            result = Selector.open();
        } catch (IOException ioe) {
            Context.getCurrentLogger().log(Level.WARNING,
                    "Unable to open the controller's NIO selector", ioe);
        }

        return result;
    }

    @Override
    protected void doInit() {
        this.selector = createSelector();
        // Done in the controller for thread safety reason regarding the byte
        // buffers part of the pooled connections
        getHelper().createConnectionPool();
    }

    @Override
    protected void doRelease() {
        try {
            getSelector().close();
        } catch (IOException e) {
            getHelper().getLogger().log(Level.WARNING,
                    "Unable to close the NIO selector", e);
        }
    }

    @Override
    protected void doRun(long sleepTime) throws IOException {
        super.doRun(sleepTime);
        registerKeys();
        updateKeys();
        selectKeys(sleepTime);
        controlConnections();
    }

    /**
     * Returns the queue of new selection registrations.
     *
     * @return The queue of new selection registrations.
     */
    protected Queue<SelectionRegistration> getNewRegistrations() {
        return this.newRegistrations;
    }

    /**
     * Returns the NIO selector.
     *
     * @return The NIO selector.
     */
    protected Selector getSelector() {
        return selector;
    }

    /**
     * Returns the queue of updated selection registrations.
     *
     * @return The queue of updated selection registrations.
     */
    protected Queue<SelectionRegistration> getUpdatedRegistrations() {
        return this.updatedRegistrations;
    }

    /**
     * Called back when a ready key has been selected.
     *
     * @param selectedKey
     *            The selected key selected.
     */
    protected void onSelected(SelectionKey selectedKey)
            throws ClosedByInterruptException {
        // Notify the selected way
        try {
            if (selectedKey.attachment() != null) {
                ((SelectionRegistration) selectedKey.attachment())
                        .onSelected(selectedKey.readyOps());
            }
        } catch (CancelledKeyException cke) {
            getHelper().getLogger().log(Level.FINER,
                    "Problem during NIO selection", cke);
            getNewRegistrations().add(
                    ((SelectionRegistration) selectedKey.attachment()));
        }
    }

    /**
     * Registers a selection listener with the underlying selector for the given
     * operations and returns the registration created.
     *
     * @param selectableChannel
     *            The NIO selectable channel.
     * @param interestOperations
     *            The initial operations of interest.
     * @param listener
     *            The listener to notify.
     * @return The created registration.
     */
    public SelectionRegistration register(SelectableChannel selectableChannel,
            int interestOperations, SelectionListener listener)
            throws IOException {
        SelectionRegistration result = new SelectionRegistration(
                selectableChannel, interestOperations, listener);
        getNewRegistrations().add(result);
        return result;
    }

    /**
     * Registers all the new selection registration requests.
     */
    protected void registerKeys() {
        SelectionRegistration newRegistration = getNewRegistrations().poll();

        while (newRegistration != null) {
            if (getHelper().getLogger().isLoggable(Level.FINEST)) {
                getHelper().getLogger().log(
                        Level.FINEST,
                        "Registering new NIO interest with selector: "
                                + newRegistration);
            }

            newRegistration.register(getSelector());
            newRegistration = getNewRegistrations().poll();
        }
    }

    /**
     * Selects the keys ready for IO operations.
     *
     * @param sleepTime
     *            The max sleep time.
     * @throws IOException
     * @throws ClosedByInterruptException
     */
    protected void selectKeys(long sleepTime) throws IOException,
            ClosedByInterruptException {
        // Select the connections ready for NIO operations
        int selectCount = getSelector().select(sleepTime);

        if (selectCount > 0) {
            if (getHelper().getLogger().isLoggable(Level.FINEST)) {
                getHelper().getLogger().log(Level.FINEST,
                        "NIO selected " + selectCount + " key(s) !");
            }

            for (Iterator<SelectionKey> keys = getSelector().selectedKeys()
                    .iterator(); keys.hasNext();) {
                // Retrieve the next selected key
                onSelected(keys.next());
                keys.remove();
            }
        }
    }

    @Override
    public void shutdown() throws IOException {
        super.shutdown();
        getSelector().close();
    }

    /**
     * Updates all the selection registrations for new interest or cancellation.
     *
     * @throws IOException
     */
    protected void updateKeys() throws IOException {
        SelectionRegistration updatedRegistration = getUpdatedRegistrations()
                .poll();

        while (updatedRegistration != null) {
            if (getHelper().getLogger().isLoggable(Level.FINEST)) {
                getHelper().getLogger().log(
                        Level.FINEST,
                        "Updating NIO interest with selector: "
                                + updatedRegistration);
            }

            updatedRegistration.update();
            updatedRegistration = getUpdatedRegistrations().poll();
        }
    }

}
TOP

Related Classes of org.restlet.engine.connector.ConnectionController

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.