PageRenderTime 27ms CodeModel.GetById 12ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/razweb/src/com/razie/pub/http/LightServer.scala

http://razpub.googlecode.com/
Scala | 170 lines | 106 code | 23 blank | 41 comment | 15 complexity | ea47987d09df764db2d682bfade4e8bd MD5 | raw file
  1/**
  2 * Razvan's public code. Copyright 2008 based on Apache license (share alike) see LICENSE.txt for
  3 * details.
  4 */
  5package com.razie.pub.http;
  6
  7import java.io.DataInputStream;
  8import java.io.IOException;
  9import java.io.PrintStream;
 10import java.net.ServerSocket;
 11import java.net.Socket;
 12import java.util.ArrayList;
 13import java.util.List;
 14import java.util.Properties;
 15
 16import razie.base.AttrAccess;
 17import razie.base.AttrAccessImpl;
 18import razie.base.life.Being
 19
 20import razie.base.ActionItem;
 21import com.razie.pub.base.ExecutionContext;
 22import com.razie.pub.base.data.HtmlRenderUtils;
 23import com.razie.pub.base.log.Log;
 24import com.razie.pub.comms.MyServerSocket;
 25
 26/**
 27 * Simple/light socket server: spawns receiver threads to process connections. You can use it not
 28 * just for http...just derive and overwrite the makeReceiver() to use a fancier receiver
 29 * 
 30 * <p>
 31 * As is, you can hook it up with the {@link com.razie.pub.http.LightCmdGET} and implement simple
 32 * services or lightsoa bindings...that's usually enough. ROADMAP for usage: define your lightsoa
 33 * classes, and register them with the server and start the server...that's it.
 34 * 
 35 * <p>
 36 * See self-documented samples in {@link com.razie.pub.http.test.TestLightServer} which does
 37 * everything you can with the server.
 38 * 
 39 * <p>
 40 * derived from kieser.net sample
 41 * 
 42     * construct a server - will open the socket and you'll have to invoke run/process on a thread
 43     * to start accepting connections
 44     * 
 45 * @param port - the port to listen to
 46 * @param maxConnections - set this to something nonzero to limit the number of connections accepted in parallel 
 47 * 
 48 * @author razvanc99
 49 */
 50class LightServer (val port:Int, val maxConnections:Int, val mainContext:ExecutionContext, var contents:ContentServer) 
 51extends Being with Runnable {
 52    // TODO find an icon for this
 53    override def whoAreYou = new ActionItem("SocketServer");//TODO constant
 54    override def whatAreYouDoing = new ActionItem("Listening...");//TODO constant
 55
 56    var currConnections = 0;
 57    def lessConns() { currConnections-=1 } // TODO java compat
 58    def enterCtx() { if (mainContext != null) mainContext.enter } // TODO java compat
 59    
 60    var listener : ServerSocket = listen
 61
 62    def listen : ServerSocket = {
 63        // not sure why i try 3 times, but...seems sturdier than not ;)
 64    var listener : ServerSocket = null
 65       var i = 0
 66        while (i < 3) {
 67            try {
 68                listener = new ServerSocket(port);
 69                i = 3 // connected, stop trying
 70            } catch {
 71               case be:java.net.BindException =>
 72                Log.alarmThisAndThrow("HTTP_ERR_BIND CANNOT bind socket - another program is using it: port=" + port+" ", be);
 73               case ioe : IOException =>
 74                Log.alarmThisAndThrow("HTTP_ERR IOException on socket listen: ", ioe);
 75
 76      // TODO why do i sleep here? forgot to comment...
 77                    Thread.sleep(500);
 78            }
 79        }
 80    listener
 81    }
 82
 83    // Listen for incoming connections and handle them
 84    def run() {
 85
 86            if (mainContext != null)
 87                mainContext.enter();
 88            
 89        while ((currConnections < maxConnections) || (maxConnections == 0)) {
 90            try {
 91               synchronized  {
 92               currConnections = currConnections+1
 93               }
 94               
 95                // i guess i have to die now...
 96                if (listener.isClosed()) {
 97                    return;
 98                }
 99                val server = listener.accept();
100                val conn_c = makeReceiver(new MyServerSocket(server));
101                Log.logThis("HTTP_CLIENT_IP: " + server.getInetAddress().getHostAddress());
102                runReceiver(conn_c);
103            } catch {
104               case ioe:IOException => {
105                // sockets are closed onShutdown() - don't want irrelevant exceptions in log
106                if (ioe.getMessage().equals("Socket closed"))
107                    Log.logThis("socket closed...stopped listening: " + ioe.getMessage());
108                else
109                    Log.logThis("IOException on socket listen: " + ioe, ioe);
110               }
111            }
112        }
113    }
114
115    /** main factory method - overload this to create your own receivers */
116    def makeReceiver(socket:MyServerSocket) : SocketReceiver = {
117      val in = socket.getInputStream();
118  
119      // need to detect if the client is in line mode (i.e. http) or not
120      Thread.sleep(100)
121      println ("AVAIL "+in.available) 
122
123      if (in.available > 3)
124         this mkWebServer socket
125      else
126         this mkTelnetServer socket
127    }
128
129    def mkWebServer (socket:MyServerSocket) : SocketReceiver = 
130       new LightReceiver  (this, socket, contents)
131    def mkTelnetServer (socket:MyServerSocket) : SocketReceiver = 
132       new TelnetReceiver  (socket, contents)
133       
134    /** if you have a special thread handling, overload this and use your own threads */
135    def runReceiver (conn_c:SocketReceiver) {
136       if (conn_c.isInstanceOf[Runnable]) {
137        val t = new Thread(conn_c.asInstanceOf[Runnable]);
138        t.setName("AgentReceiver" + t.getName());
139        t.start();
140       } else conn_c.run()
141    }
142
143    def shutdown() {
144        try {
145            // it may be null if it didn't initialize properly (socket busy) - no reason to fail shutdown...
146            if (this.listener != null)
147                this.listener.close();
148        } catch {
149           case ioe:IOException => {
150            Log.logThis("IOException on socket close: " + ioe);
151            ioe.printStackTrace();
152           }
153        }
154    }
155
156    val logger = razie.Log;
157
158    def registerHandler(c:SocketCmdHandler ) { contents.asInstanceOf[LightContentServer] registerHandler c }
159
160    def removeHandler(c:SocketCmdHandler ) { contents.asInstanceOf[LightContentServer] removeHandler c }
161
162    /**
163     * @return the listeners
164     */
165    def getHandlers () : java.util.List[SocketCmdHandler] =  contents.asInstanceOf[LightContentServer].getHandlers
166}
167
168trait SocketReceiver {
169   def run() : Unit
170}