Package org.apache.geronimo.network.protocol

Source Code of org.apache.geronimo.network.protocol.SocketProtocol

/**
*
* Copyright 2004 The Apache Software Foundation
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/

package org.apache.geronimo.network.protocol;

import java.io.IOException;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.Collection;
import java.util.Iterator;

import EDU.oswego.cs.dl.util.concurrent.Mutex;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.geronimo.network.SelectionEventListner;
import org.apache.geronimo.network.SelectorManager;


/**
* @version $Revision: 1.10 $ $Date: 2004/04/25 02:03:37 $
*/
public class SocketProtocol implements AcceptableProtocol, SelectionEventListner {

    private Log log = LogFactory.getLog(SocketProtocol.class);
    private Protocol up;

    private SocketChannel acceptedSocketChannel;
    private SocketChannel socketChannel;
    private SocketAddress address;
    private SocketAddress socketInterface;

    private long timeout;
    private Mutex sendMutex;
    private SelectorManager selectorManager;
    private SelectionKey selectionKey;

    private long created;
    private long lastUsed;

    private static final int STARTED = 0;
    private static final int STOPPED = 1;
    private int state = STOPPED;

    ByteBuffer[] sendBuffer;
    ByteBuffer headerBuffer;
    ByteBuffer bodyBuffer;

    Object serviceReadMutex;
    Object serviceWriteMutex;

    static int nextConnectionId = 0;

    synchronized static int getNextConnectionId() {
        return nextConnectionId++;
    }

    public Protocol getUpProtocol() {
        return up;
    }

    public void setUpProtocol(Protocol up) {
        this.up = up;
    }

    public Protocol getDownProtocol() {
        throw new NoSuchMethodError("Socket protocol is at the bottom");
    }

    public void setDownProtocol(Protocol down) {
        throw new NoSuchMethodError("Socket protocol is at the bottom");
    }

    public void clearLinks() {
        up = null;
    }

    public SocketChannel getSocketChannel() {
        return socketChannel;
    }

    public void setSocketChannel(SocketChannel socketChannel) {
        this.socketChannel = socketChannel;
    }

    public SocketAddress getAddress() {
        return address;
    }

    public void setAddress(SocketAddress address) {
        if (state == STARTED) throw new IllegalStateException("Protocol already started");
        this.address = address;
    }

    public SocketAddress getInterface() {
        return socketInterface;
    }

    public void setInterface(SocketAddress socketInterface) {
        if (state == STARTED) throw new IllegalStateException("Protocol already started");
        this.socketInterface = socketInterface;
    }

    public long getTimeout() {
        return timeout;
    }

    public void setTimeout(long timeout) {
        if (state == STARTED) throw new IllegalStateException("Protocol already started");
        this.timeout = timeout;
    }

    public SelectorManager getSelectorManager() {
        return selectorManager;
    }

    public void setSelectorManager(SelectorManager selectorManager) {
        if (state == STARTED) throw new IllegalStateException("Protocol already started");
        this.selectorManager = selectorManager;
    }

    public boolean isDone() {
        return state == STOPPED;
    }

    public long getCreated() {
        return created;
    }

    public long getLastUsed() {
        return lastUsed;
    }

    public Protocol cloneProtocol() throws CloneNotSupportedException {
        SocketProtocol p = (SocketProtocol) super.clone();
        p.log = LogFactory.getLog(SocketProtocol.class.getName() + ":" + getNextConnectionId());
        return p;
    }

    public void setup() throws ProtocolException {
        log = LogFactory.getLog(SocketProtocol.class.getName() + ":" + getNextConnectionId());
        sendMutex = new Mutex();
        headerBuffer = ByteBuffer.allocate(4);
        serviceReadMutex = new Object();
        serviceWriteMutex = new Object();

        if (address == null && acceptedSocketChannel == null) throw new IllegalStateException("No address set");

        log.trace("Starting");
        if (acceptedSocketChannel == null) {
            try {
                socketChannel = SocketChannel.open();
                socketChannel.configureBlocking(true);
                if (socketInterface != null) socketChannel.socket().bind(socketInterface);
                socketChannel.socket().setReuseAddress(true);
                socketChannel.socket().setTcpNoDelay(true);
                socketChannel.connect(address);
            } catch (SocketException e) {
                state = STOPPED;
                throw new ProtocolException(e);
            } catch (IOException e) {
                state = STOPPED;
                throw new ProtocolException(e);
            }
        } else {
            socketChannel = acceptedSocketChannel;
        }

        try {
            socketChannel.configureBlocking(false);
            selectionKey = selectorManager.register(socketChannel, SelectionKey.OP_READ, this);
            log.trace("+OP_READ " + selectionKey);
        } catch (ClosedChannelException e) {
            state = STOPPED;
            throw new ProtocolException(e);
        } catch (IOException e) {
            state = STOPPED;
            throw new ProtocolException(e);
        }

        created = System.currentTimeMillis();
        lastUsed = System.currentTimeMillis();
        state = STARTED;
    }

    public void drain() throws ProtocolException {
        log.trace("Stopping");
        close();
        state = STOPPED;
    }

    public void teardown() throws ProtocolException {
    }

    public void sendUp(UpPacket packet) throws ProtocolException {
        throw new UnsupportedOperationException("Method not implemented");
    }

    public void sendDown(DownPacket packet) throws ProtocolException {
        if (state == STOPPED) throw new IllegalStateException("Protocol is not started");

        lastUsed = System.currentTimeMillis();

        try {
            log.trace("AQUIRING " + sendMutex);
            if (!sendMutex.attempt(timeout)) throw new ProtocolException("Send timeout.");
            log.trace("AQUIRED " + sendMutex);


            Collection patcketBuffers = packet.getBuffers();

            int n = patcketBuffers.size();
            sendBuffer = new ByteBuffer[n + 1];
            int size = 0;
            Iterator iter = patcketBuffers.iterator();
            for (int i = 1; iter.hasNext(); i++) {
                sendBuffer[i] = (ByteBuffer) iter.next();
                size += sendBuffer[i].remaining();
            }

            sendBuffer[0] = ByteBuffer.allocate(4);
            sendBuffer[0].putInt(size);
            sendBuffer[0].flip();

            log.trace("+OP_WRITE " + selectionKey);
            selectorManager.addInterestOps(selectionKey, SelectionKey.OP_WRITE);

        } catch (InterruptedException e) {
            log.debug("Communications error, closing connection: ", e);
            close();
            throw new ProtocolException(e);
        }
    }

    public void selectionEvent(SelectionKey selection) {
        try {
            if (selection.isReadable()) {
                synchronized (serviceReadMutex) {
                    serviceRead();
                }
            }
            if (selection.isWritable()) {
                synchronized (serviceWriteMutex) {
                    serviceWrite();
                }
            }
        } catch (CancelledKeyException e) {
            log.trace("Key Cancelled:", e);
            // who knows, by the time we get here,
            // the key could have been canceled.
        }
    }

    private void serviceWrite() {
        log.trace("serviceWrite() triggered.");
        try {
            if (sendBuffer == null) {
                log.trace("Write had allready been serviced.");
                return;
            }

            long count = socketChannel.write(sendBuffer);
            log.trace("Wrote " + count);

            for (int i = 0; i < sendBuffer.length; i++) {
                if (sendBuffer[i].hasRemaining()) {
                    // not all was delivered in this call setup selector
                    // so we setup to finish sending async.
                    log.trace("+OP_WRITE " + selectionKey);
                    selectorManager.addInterestOps(selectionKey, SelectionKey.OP_WRITE);

                    return;
                }
            }

            // release old buffers
            sendBuffer = null;

            log.trace("RELEASING " + sendMutex);
            sendMutex.release();
            log.trace("RELEASED " + sendMutex);

        } catch (IOException e) {
            log.debug("Communications error, closing connection: ", e);
            close();
        } finally {
            log.trace("serviceWrite() done.");
        }
    }

    public void serviceRead() {
        boolean tracing = log.isTraceEnabled();
        if (tracing) log.trace("serviceRead() triggered.");
        lastUsed = System.currentTimeMillis();
        try {
            while (true) {

                log.trace("HEADER reamining " + headerBuffer.remaining());

                // Are we reading the header??
                if (headerBuffer.hasRemaining()) {
                    if (tracing)
                        log.trace("Reading header");

                    long count = socketChannel.read(headerBuffer);
                    log.trace("HEADER Read " + count);

                    if (count == -1) {
                        close();
                        return;
                    }

                    if (headerBuffer.hasRemaining()) {
                        log.trace("HEADER reamining " + headerBuffer.remaining());
                        break; // not done reading the header.
                    }

                    headerBuffer.flip();

                    int size = headerBuffer.getInt();
                    log.trace("Gotta get " + size);

                    if (size == 0) {
                        headerBuffer.clear();
                        log.trace("+OP_READ " + selectionKey);
                        selectorManager.addInterestOps(selectionKey, SelectionKey.OP_READ);
                        return;
                    }

                    bodyBuffer = ByteBuffer.allocate(size);

                    bodyBuffer.clear();
                    bodyBuffer.limit(size);
                }

                log.trace("BODY... HEADER remaining: " + headerBuffer.remaining() + ", " + headerBuffer.hasRemaining());
                // Are we reading the body??
                if (bodyBuffer.hasRemaining()) {
                    if (tracing)
                        log.trace("Reading body");

                    long count = socketChannel.read(bodyBuffer);
                    log.trace("BODY Read " + count);
                    log.trace("BODY remaining " + bodyBuffer.remaining());

                    if (bodyBuffer.hasRemaining())
                        break; // not done reading the body.

                    bodyBuffer.flip();

                    UpPacket packet = new UpPacket();
                    packet.setBuffer(bodyBuffer);

                    // release old buffer
                    bodyBuffer = null;
                    headerBuffer.clear();

                    up.sendUp(packet);

                }
            }
            log.trace("+OP_READ " + selectionKey);
            selectorManager.addInterestOps(selectionKey, SelectionKey.OP_READ);
            if (tracing) log.trace("No more data available to be read.");

        } catch (CancelledKeyException e) {
            log.trace("Key Cancelled: ", e);
            // who knows, by the time we get here,
            // the key could have been canceled.
        } catch (ClosedChannelException e) {
            log.trace("Channel Closed: ", e);
            // who knows, by the time we get here,
            // the channel could have been closed.
        } catch (IOException e) {
            log.debug("Communications error, closing connection: ", e);
            close();
        } catch (ProtocolException e) {
            log.debug("Communications error, closing connection: ", e);
            close();
        } catch (Throwable e) {
            log.debug("Unhandled error, closing connection: ", e);
            close();
        } finally {
            if (tracing) log.trace("serviceRead() done.");
        }
    }

    public void close() {
        synchronized (this) {
            if (socketChannel != null) {
                log.trace("Closing");
                try {
                    selectionKey.cancel();
                    socketChannel.close();
                } catch (Throwable e) {
                    log.info("Closing error: ", e);
                }
                log.trace("Closed");
            }
            state = STOPPED;
        }
    }

    public void accept(SocketChannel socketChannel) {
        this.acceptedSocketChannel = socketChannel;
    }
}
TOP

Related Classes of org.apache.geronimo.network.protocol.SocketProtocol

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.