Package org.activeio.oneport

Source Code of org.activeio.oneport.OnePortAsynchChannelServer$OnePortAcceptListener

/**
*
* Copyright 2004 Hiram Chirino
*
* 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.activeio.oneport;

import java.io.IOException;
import java.net.URI;
import java.util.Iterator;

import org.activeio.AcceptListener;
import org.activeio.AsynchChannel;
import org.activeio.AsynchChannelListener;
import org.activeio.AsynchChannelServer;
import org.activeio.Channel;
import org.activeio.FilterAsynchChannel;
import org.activeio.FilterAsynchChannelServer;
import org.activeio.Packet;
import org.activeio.SynchChannel;
import org.activeio.adapter.AsynchToSynchChannelAdapter;
import org.activeio.adapter.SynchToAsynchChannelAdapter;
import org.activeio.filter.PushbackSynchChannel;
import org.activeio.packet.AppendedPacket;

import EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;

/**
* Allows multiple protocols share a single ChannelServer.  All protocols sharing the server
* must have a distinct magic number at the beging of the client's request.
*
* TODO: handle the case where a client opens a connection but sends no data down the stream.  We need
* to timeout that client.
*
* @version $Revision$
*/
final public class OnePortAsynchChannelServer extends FilterAsynchChannelServer {
   
    /**
     * The OnePortAsynchChannelServer listens for incoming connection
     * from a normal AsynchChannelServer.  This s the listner used
     * to receive the accepted channels.
     */
    final private class OnePortAcceptListener implements AcceptListener {
       
        public void onAccept(Channel channel) {
            try {
                AsynchChannel asynchChannel = SynchToAsynchChannelAdapter.adapt(channel);
                ProtocolInspectingAsynchChannel inspector = new ProtocolInspectingAsynchChannel(asynchChannel);
                inspector.start();               
            } catch (IOException e) {
                onAcceptError(e);
            }               
        }
       
        public void onAcceptError(IOException error) {
            dispose();
        }
    }

    /**
     * This channel filter sniffs the first few bytes of the byte stream
     * to see if a ProtocolRecognizer recognizes the protocol.  If it does not
     * it just closes the channel, otherwise the associated SubPortAsynchChannelServer
     * is notified that it accepted a channel.
     *
     */
    final private class ProtocolInspectingAsynchChannel extends FilterAsynchChannel {
        private Packet buffer;

        public ProtocolInspectingAsynchChannel(AsynchChannel next) throws IOException {
            super(next);
            setAsynchChannelListener(new AsynchChannelListener() {
                public void onPacket(Packet packet) {
                    if (buffer == null) {
                        buffer = packet;
                    } else {
                        buffer = AppendedPacket.join(buffer, packet);
                    }
                    findMagicNumber();
                }

                public void onPacketError(IOException error) {
                    dispose();
                }
            });
        }

        private void findMagicNumber() {
            for (Iterator iter = recognizerMap.keySet().iterator(); iter.hasNext();) {
                ProtocolRecognizer recognizer = (ProtocolRecognizer) iter.next();
                if (recognizer.recognizes(buffer.duplicate())) {

                    if( UnknownRecognizer.UNKNOWN_RECOGNIZER == recognizer ) {
                        // Dispose the channel.. don't know what to do with it.
                        dispose();
                    }
                   
                    SubPortAsynchChannelServer onePort = (SubPortAsynchChannelServer) recognizerMap.get(recognizer);
                    if( onePort == null ) {
                        // Dispose the channel.. don't know what to do with it.
                        dispose();
                    }

                    // Once the magic number is found:
                    // Stop the channel so that a decision can be taken on what to
                    // do with the
                    // channel. When the channel is restarted, the buffered up
                    // packets wiil get
                    // delivered.
                    try {
                        stop(NO_WAIT_TIMEOUT);
                        setAsynchChannelListener(null);
                    } catch (IOException e) {                       
                        getAsynchChannelListener().onPacketError(e);
                    }
                   
                    Channel channel = getNext();
                    channel = AsynchToSynchChannelAdapter.adapt(channel);
                    channel = new PushbackSynchChannel((SynchChannel) channel, buffer);
                    channel = SynchToAsynchChannelAdapter.adapt(channel);
                   
                    onePort.onAccept(channel);
                    break;
                }
            }
        }
    }   

    /**
     * Clients bind against the OnePortAsynchChannelServer and get
     * SubPortAsynchChannelServer which can be used to accept connections.
     */
    final private class SubPortAsynchChannelServer implements AsynchChannelServer {
       
        private final ProtocolRecognizer recognizer;
        private AcceptListener acceptListener;
        private boolean started;
       
        /**
         * @param recognizer
         */
        public SubPortAsynchChannelServer(ProtocolRecognizer recognizer) {
            this.recognizer = recognizer;
        }

        public void setAcceptListener(AcceptListener acceptListener) {
            this.acceptListener = acceptListener;
        }
       
        public URI getBindURI() {
            return next.getBindURI();
        }
       
        public URI getConnectURI() {
            return next.getConnectURI();
        }
       
        public void dispose() {
            started = false;
            recognizerMap.remove(recognizer);
        }
       
        public void start() throws IOException {
            started = true;
        }
        public void stop(long timeout) throws IOException {
            started = false;
        }
       
        void onAccept(Channel channel) {
            if( started && acceptListener!=null ) {
                acceptListener.onAccept(channel);
            } else {
                // Dispose the channel.. don't know what to do with it.
                channel.dispose();
            }
        }
       
        public Object narrow(Class target) {
            if( target.isAssignableFrom(getClass()) ) {
                return this;
            }
            return OnePortAsynchChannelServer.this.narrow(target);
        }   
       
    }
   
   
    private final ConcurrentHashMap recognizerMap = new ConcurrentHashMap();

    public OnePortAsynchChannelServer(AsynchChannelServer server) throws IOException {
        super(server);
        super.setAcceptListener(new OnePortAcceptListener());
    }
   
    public void setAcceptListener(AcceptListener acceptListener) {
        throw new IllegalAccessError("Not supported");
    }   
   
    public AsynchChannelServer bindAsynchChannel(ProtocolRecognizer recognizer) throws IOException {
       
        if( recognizerMap.contains(recognizer) )
            throw new IOException("That recognizer is allredy bound.");
       
        SubPortAsynchChannelServer server = new SubPortAsynchChannelServer(recognizer);
        Object old = recognizerMap.put(recognizer, server);
        return server;
    }
   
   
}
TOP

Related Classes of org.activeio.oneport.OnePortAsynchChannelServer$OnePortAcceptListener

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.