Package org.apache.geronimo.remoting.transport.async.bio

Source Code of org.apache.geronimo.remoting.transport.async.bio.BlockingChannel

/**
*
* Copyright 2003-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.remoting.transport.async.bio;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Properties;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.geronimo.proxy.SimpleComponent;
import org.apache.geronimo.remoting.transport.ConnectionFailedException;
import org.apache.geronimo.remoting.transport.TransportException;
import org.apache.geronimo.remoting.transport.URISupport;
import org.apache.geronimo.remoting.transport.async.AsyncMsg;
import org.apache.geronimo.remoting.transport.async.Channel;
import org.apache.geronimo.remoting.transport.async.ChannelListner;
/**
* The Blocking implementation of the AsynchChannel interface. 
*
* This implemenation uses the standard Java 1.3 blocking socket IO.
*
* @version $Rev: 46019 $ $Date: 2004-09-14 04:56:06 -0500 (Tue, 14 Sep 2004) $
*/
public class BlockingChannel extends SimpleComponent implements Runnable, Channel {

    static final private Log log = LogFactory.getLog(BlockingChannel.class);

    private ChannelListner listner;
    private Thread worker;
    private SocketChannel socketChannel;
    private boolean closing = false;

    private Inflater inflator;
    private Deflater deflater;

    private URI remoteURI;
    private URI requestedURI;

    public void open(URI remoteURI, URI backConnectURI, ChannelListner listner) throws TransportException {

        if (log.isTraceEnabled())
            log.trace("Connecting to : " + remoteURI);

        this.listner = listner;
        this.remoteURI = remoteURI;
        int port = remoteURI.getPort();
        boolean enableTcpNoDelay = true;

        Properties params = URISupport.parseQueryParameters(remoteURI);
        enableTcpNoDelay = params.getProperty("tcp.nodelay", "true").equals("true");
        int compression = Integer.parseInt(params.getProperty("compression", "-1"));

        try {
            InetAddress addr = InetAddress.getByName(remoteURI.getHost());
            socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(true);
            socketChannel.connect(new InetSocketAddress(addr, port));
        } catch (Exception e) {
            throw new ConnectionFailedException("" + e);
        }
        try {
            socketChannel.socket().setTcpNoDelay(enableTcpNoDelay);

            DataOutputStream out = new DataOutputStream(socketChannel.socket().getOutputStream());
            out.writeUTF(remoteURI.toString());
            out.writeUTF(backConnectURI.toString());
            out.flush();
           
            if (compression != -1) {
                inflator = new Inflater(true);
                deflater = new Deflater(compression, true);
            }
           
        } catch (Exception e) {
            throw new TransportException("Connection handshake failed: " + e);
        }

        worker = new Thread(this, "Channel -> " + remoteURI);
        worker.setDaemon(true);
        worker.start();
    }

    public void init(URI localURI, SocketChannel socketChannel) throws IOException, URISyntaxException {
        this.socketChannel = socketChannel;

        DataOutputStream out = new DataOutputStream(socketChannel.socket().getOutputStream());
        out.flush();

        DataInputStream in = new DataInputStream(socketChannel.socket().getInputStream());
        // Use to get connection options.
        String destURI = in.readUTF();
        // Use in case we need to establish new connections back to
        // the source vm.  Could be null.
        String sourceURI = in.readUTF();
        this.remoteURI = new URI(sourceURI);
        this.requestedURI = new URI(destURI);
        if (log.isTraceEnabled()) {
            log.trace("Remote URI    : " + remoteURI);
            log.trace("Requested URI : " + requestedURI);
        }
       
        boolean enableTcpNoDelay = true;
        Properties params = URISupport.parseQueryParameters(requestedURI);
        enableTcpNoDelay = params.getProperty("tcp.nodelay", "true").equals("true");
        int compression = Integer.parseInt((String) params.getProperty("compression", "-1"));

        if (compression != -1) {
            inflator = new Inflater(true);
            deflater = new Deflater(compression, true);
        }

        /*
        */
        socketChannel.socket().setTcpNoDelay(enableTcpNoDelay);
        if (log.isTraceEnabled()) {
            log.trace("Compression level : " + compression);
            log.trace("tcp no delay : " + enableTcpNoDelay);
        }
    }

    public void open(ChannelListner listner) throws TransportException {
        this.listner = listner;
        worker = new Thread(this, "Channel <- " + remoteURI);
        worker.setDaemon(true);
        worker.start();
    }

    static int nextId = 0;
    /**
     * @return
     */
    synchronized private int getNextID() {
        return nextId++;
    }

    private Object sendMutex = new Object();
    public void send(AsyncMsg data) throws TransportException {
        try {
            ByteBuffer buffers[] = serialize(data);
            synchronized (sendMutex) {
                if (closing)
                    throw new TransportException("connection has been closed.");
                // should block.
                socketChannel.write(buffers);
            }
        } catch (IOException e) {
            throw new TransportException("" + e);
        }
    }

    /**
     * @param data
     * @return
     */
    private ByteBuffer[] serialize(AsyncMsg data) throws IOException {
        ByteBuffer rc[] = new ByteBuffer[2];
        rc[0] = ByteBuffer.allocate(4);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        OutputStream t=baos;
        if (deflater!=null)
            t = new DeflaterOutputStream(t, deflater);
        DataOutputStream out = new DataOutputStream(t);

        data.writeExternal(out);
        out.close();
        rc[1] = ByteBuffer.wrap(baos.toByteArray());
        rc[0].putInt(rc[1].limit());
       
        rc[0].rewind();       
        rc[1].rewind();       
        return rc;
    }

    /**
     * @param buffer
     */
    public AsyncMsg deserialize(ByteBuffer[] message) throws IOException  {
        AsyncMsg asyncMsg = new AsyncMsg();

        InputStream t=new ByteArrayInputStream( message[1].array());
        if (inflator!=null)
            t = new InflaterInputStream(t, inflator);
        DataInputStream in = new DataInputStream( t );

        asyncMsg.readExternal(in);
        in.close();
        return asyncMsg;       
    }


    /* (non-Javadoc)
     * @see java.lang.Runnable#run()
     */
    public void run() {
       
        ByteBuffer message[] = new ByteBuffer[]{
                ByteBuffer.allocate(4),
                ByteBuffer.allocate(1024*10)
                };
       
        try {
            while (true) {
               
                log.trace("Waiting for message");
                message[0].clear();
                socketChannel.read(message[0]);
                while( message[0].position()!=4 ) {
                    socketChannel.read(message[0]);
                }
                message[0].flip();
                int size = message[0].getInt();
               
                // Signal from remote that the socket is being closed.
                if( size==-1 )
                    break;

                // Do we need a bigger buffer?
                // TODO: should we have a max size the buffer can grow to?                    
                if( size > message[1].capacity() )
                    message[1] = ByteBuffer.allocate(size);
                   
                // Load the body.                    
                message[1].clear();
                message[1].limit(size);
                socketChannel.read(message[1]);
                while( message[1].position()!=size ) {
                    socketChannel.read(message[1]);
                }
                message[1].flip();               
                listner.receiveEvent(deserialize(message));
            }
            log.trace("Stopping due to remote end closing.");
        } catch (IOException e) {
            log.trace("Stopping due to exception.", e);
        } finally {
            asyncClose();
        }
        log.trace("Stopped");
    }

    /**
     * Starts to terminate the connection.  Lets the remote end
     * know that we are closing.
     *
     * The server side calls this close.  Could be called in response to
     * 2 events:
     * - we initiated the close() (so we finish the close)
     * - An asynch error initiated the close(). (so we start the close process)
     * We keep state to know if we started the socket close(). 
     */
    synchronized private void asyncClose() {
        // socket is null when we finish close()
        if (socketChannel == null)
            return;
        try {
            socketChannel.socket().shutdownInput();
            // were we allready closing??   
            if (closing) {
                // both side should be shutdown now.  finish close.
                socketChannel.close();
            } else {
                closing = true;
                listner.closeEvent();
            }
        } catch (IOException e) {
            // If the 'nice' shutdown fails at any point,
            // then do the forced shutdown.
            forcedClose();
        }
    }

    /**
     * Starts to terminate the connection.  Lets the remote end
     * know that we are closing.
     *
     * The client side calls this close.  Could be called in response to
     * 2 events:
     * - the remote sever initiated the close(). (so we finish the close)
     * - we initiated the close() (so we wait for the remote side to finish the close)
     * We keep state to know if we started the socket close(). 
     *  
     */
    synchronized public void close() {
        // socket is null when we finish close()
        if (socketChannel == null)
            return;
        try {
            ByteBuffer buffer = ByteBuffer.allocate(4);
            buffer.asIntBuffer().put(-1);
            synchronized (sendMutex) {
                socketChannel.write(buffer);
                socketChannel.socket().shutdownOutput();
            }
            // were we allready closing??   
            if (closing) {
                // both side should be shutdown now.  finish close.
                socketChannel.close();
                socketChannel = null;
            } else {
                closing = true;
            }
        } catch (IOException e) {
            forcedClose();
        }
    }

    /**
     * forcibly terminates the connection without telling the remote end
     * that the connection is being closed.
     */
    private void forcedClose() {
        try {
            socketChannel.close();
        } catch (Throwable e) {
        }
        socketChannel = null;
    }

    /**
     * @return
     */
    public URI getRemoteURI() {
        return remoteURI;
    }
   
    /**
     * @return Returns the requestedURI.
     */
    public URI getRequestedURI() {
        return requestedURI;
    }

}
TOP

Related Classes of org.apache.geronimo.remoting.transport.async.bio.BlockingChannel

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.