Package org.xlightweb

Source Code of org.xlightweb.SimpleDualPortServer$Registry

/*
*  Copyright (c) xlightweb.org, 2008 - 2009. All rights reserved.
*
*  This 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 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 library; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
* Please refer to the LGPL license at: http://www.gnu.org/copyleft/lesser.txt
* The latest copy of this software may be found on http://www.xlightweb.org/
*/
package org.xlightweb;


import java.io.Closeable;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.Map.Entry;


import org.xlightweb.server.HttpServer;
import org.xsocket.connection.IConnectHandler;
import org.xsocket.connection.IDataHandler;
import org.xsocket.connection.IDisconnectHandler;
import org.xsocket.connection.INonBlockingConnection;
import org.xsocket.connection.Server;



/**
*
* @author grro@xlightweb.org
*/
public final class SimpleDualPortServer implements Runnable, Closeable {

    private final Server httpServer;
    private final Server tcpServer;

   
    public static void main(String[] args) throws IOException {
        SimpleDualPortServer server = new SimpleDualPortServer(Integer.parseInt(args[0]), Integer.parseInt(args[0]));
        server.run();
    }

   
    public SimpleDualPortServer(int httpListenport, int tcpListenport) throws IOException {
        Registry registry = new Registry();
       
        httpServer = new HttpServer(httpListenport, new HttpRequestHandler(registry));
        tcpServer = new Server(tcpListenport, new TcpConnectHandler(registry));
    }


    public void run() {
        try {
            httpServer.start();
            tcpServer.run();
        } catch (IOException ioe) {
            throw new RuntimeException(ioe);
        }
    }
   
    public void close() throws IOException {
        httpServer.close();
        tcpServer.close();
    }
   
   
   
    public int getHttpServerListenPort() {
        return httpServer.getLocalPort();
    }
   
    public int getTcpServerListenPort() {
        return tcpServer.getLocalPort();
    }
   
   
    private static final class HttpRequestHandler implements IHttpRequestHandler {
       
        private final Registry registry;

       
        public HttpRequestHandler(Registry registry) {
            this.registry = registry;
        }
       
        public void onRequest(IHttpExchange exchange) throws IOException, BadMessageException {
           
            IHttpRequest request = exchange.getRequest();
            String path = request.getRequestURI();
           
            int channelId;
            int idx = path.indexOf("/");
            int idx2 = path.indexOf("/", idx + 1);
            if (idx2 == -1) {
                channelId = Integer.parseInt(path.substring(idx + 1, path.length()));
            } else {
                channelId = Integer.parseInt(path.substring(idx + 1, idx2));
            }

            NonBlockingBodyDataSource ds = request.getNonBlockingBody();
            ds.addCompleteListener(new BodyCompleteListener(ds, registry, channelId, exchange));
           
        }
    }
   
    private static final class BodyCompleteListener implements IBodyCompleteListener {
       
        private final NonBlockingBodyDataSource ds;
        private final Registry registry;
        private final int channelId;
        private final IHttpExchange exchange;
       
        public BodyCompleteListener(NonBlockingBodyDataSource ds, Registry registry, int channelId, IHttpExchange exchange) {
            this.ds = ds;
            this.registry = registry;
            this.channelId = channelId;
            this.exchange = exchange;
        }
       
        public void onComplete() throws IOException {
            try {
                int available = ds.available();
                ByteBuffer[] data = ds.readByteBufferByLength(available);
               
                INonBlockingConnection con = registry.retrieveTcpConnection(channelId, 1000);
               
                IDataHandler dh = new IDataHandler() {
                  public boolean onData(INonBlockingConnection connection) throws IOException {
                        connection.resetToReadMark();
                        connection.markReadPosition();
                        int length = connection.readInt();
                        ByteBuffer[] data = connection.readByteBufferByLength(length);
                        connection.removeReadMark();
                       
                        registry.addTcpConnection(channelId, connection);
                        exchange.send(new HttpResponse(200, "text/plain", data));
                        return false;
                   
                };
                con.setHandler(dh);
               
                con.write(available);
                con.write(data);
               
            } catch (SocketTimeoutException ste) {
                exchange.sendError(404);
            }
           
        }
    }
   
   
   
   
    private static final class TcpConnectHandler implements IConnectHandler, IDisconnectHandler {
       
        private final Registry registry;
       
        public TcpConnectHandler(Registry registry) {
            this.registry = registry;
        }
       

        public boolean onConnect(INonBlockingConnection connection) throws IOException {
           
            IDataHandler cannelIdReader = new IDataHandler() {
               
                public boolean onData(INonBlockingConnection connection) throws IOException {
                    Integer channelId = connection.readInt();
                   
                    registry.addTcpConnection(channelId, connection);

                    connection.setHandler(null);
                    return true;
                }
            };
           
            connection.setHandler(cannelIdReader);
            return true;
        }
       
        public boolean onDisconnect(INonBlockingConnection connection) throws IOException {
            registry.removeTcpConnection(connection);
            return true;
        }
    }
   
   
   
    private static final class Registry {
       
        private final Random random = new Random();
       
        private final HashMap<Integer, List<INonBlockingConnection>> openConnections = new HashMap<Integer, List<INonBlockingConnection>>();
       
       
        synchronized void addTcpConnection(int channelId, INonBlockingConnection nbc) {
            nbc.setAttachment(channelId);
           
            List<INonBlockingConnection> cons = openConnections.get(channelId);
            if (cons == null)  {
                cons = new ArrayList<INonBlockingConnection>();
                openConnections.put(channelId, cons);
            }
           
            cons.add(nbc);
           
            notifyAll();
        }
       
       
        synchronized void removeTcpConnection(INonBlockingConnection nbc) {
            Integer channelId = (Integer) nbc.getAttachment();
            List<INonBlockingConnection> cons = openConnections.get(channelId);
            cons.remove(nbc);
            if (cons.isEmpty()) {
                openConnections.remove(channelId);
            }
        }

       
        synchronized INonBlockingConnection retrieveTcpConnection(Integer channelId, long timeoutMillis) throws SocketTimeoutException {
           
            long start = System.currentTimeMillis();
           
            do {
                List<INonBlockingConnection> cons = openConnections.get(channelId);
                if (cons == null) {
                    try {
                        wait(timeoutMillis);
                    } catch (InterruptedException ignore) { }
                } else {
                    if (cons.isEmpty()) {
                        openConnections.remove(channelId);
                    } else {
                        INonBlockingConnection con = cons.remove(getRandomId(cons.size() - 1));
                        if (cons.isEmpty()) {
                            openConnections.remove(channelId);
                        }
                        return con;
                    }
                }
               
            } while (System.currentTimeMillis() < (start + timeoutMillis));
           
            throw new SocketTimeoutException("colud not get a connection of channel " + channelId);
        }

        private int getRandomId(int max) {
            if (max == 0) {
                return 0;
            }
           
            int i = 0;
            do {
                i = random.nextInt();
            } while (i < 0);
           
            i = i % max;
            return i;
        }
       
        @Override
        public synchronized String toString() {
            StringBuilder sb = new StringBuilder();
            for (Entry<Integer, List<INonBlockingConnection>> entry : openConnections.entrySet()) {
                sb.append(entry.getKey() + ": ");
                for (INonBlockingConnection con : entry.getValue()) {
                    sb.append(con.getId() + " ");
                }
                sb.append("\r\n");
            }
           
            return sb.toString();
        }
    }
   
}
TOP

Related Classes of org.xlightweb.SimpleDualPortServer$Registry

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.