    #!/usr/bin/env python
    """
    AppServer

    FUTURE

        * Implement the additional settings that are commented out below.
    """

    from Common import *
    from Object import Object
    from ConfigurableForServerSidePath import ConfigurableForServerSidePath
    from Application import Application
    from PlugIn import PlugIn
    import Profiler

    from threading import Thread, Event

    globalAppServer = None
        # Concrete app servers have to set this variable which then allows
        # any Python code to access the app server singleton like so:
        #     from WebKit.AppServer import globalAppServer

    DefaultConfig = {
        'PrintConfigAtStartUp': 1,
        'Verbose':              1,
        'PlugIns':              ['../PSP'],
        'CheckInterval':        100,

        # @@ 2000-04-27 ce: None of the following settings are implemented
    #   'ApplicationClassName': 'Application',
    }

    class AppServerError(Exception):
        pass

    class AppServer(ConfigurableForServerSidePath, Object):

        ## Init ##

        def __init__(self, path=None):
            self._startTime = time.time()

            global globalAppServer
            assert globalAppServer is None, 'more than one app server; or __init__() invoked more than once'
            globalAppServer = self

            ConfigurableForServerSidePath.__init__(self)
            Object.__init__(self)
            if path is None:
                path = os.path.dirname(__file__)  #os.getcwd()
            self._serverSidePath = os.path.abspath(path)
            self._webKitPath = os.path.abspath(os.path.dirname(__file__))
            self._webwarePath = os.path.dirname(self._webKitPath)

            self._verbose = self.setting('Verbose')
            self._plugIns = []
            self._reqCount = 0

            self.checkForInstall()
            self.config() # cache the config
            self.printStartUpMessage()
            sys.setcheckinterval(self.setting('CheckInterval'))
            self._app = self.createApplication()
            self.loadPlugIns()

            self.running = 1

            if self.isPersistent():
                self._closeEvent = Event()
                self._closeThread = Thread(target=self.closeThread)
    ##          self._closeThread.setDaemon(1)
                self._closeThread.start()

        def checkForInstall(self):
            """
            Exits with an error message if Webware was not installed.
            """
            if not os.path.exists(os.path.join(self._webwarePath, '_installed')):
                sys.stdout = sys.stderr
                print 'ERROR: You have not installed Webware.'
                print 'Please run install.py from inside the Webware directory.'
                print 'For example:'
                print '> cd ..'
                print '> python install.py'
                print
                sys.exit(0)

        def readyForRequests(self):
            """
            Should be invoked by subclasses when they are finally ready to
            accept requests. Records some stats and prints a message.
            """
            Profiler.readyTime = time.time()
            Profiler.readyDuration = Profiler.readyTime - Profiler.startTime
            print "Ready  (%.2f seconds after launch)\n" % Profiler.readyDuration
            sys.stdout.flush()
            sys.stderr.flush()

        def closeThread(self):
            self._closeEvent.wait()
            self.shutDown()

        def initiateShutdown(self):
            self._closeEvent.set()

        def recordPID(self):
            """
            Save the pid of the AppServer to a file name appserverpid.txt.
            """
            pidfile = open(os.path.join(self._serverSidePath, "appserverpid.txt"),"w")

            if os.name == 'posix':
                pidfile.write(str(os.getpid()))
            else:
                try:
                    import win32api
                except:
                    print "win32 extensions not present.  Webkit Will not be able to detatch from the controlling terminal."
                if sys.modules.has_key('win32api'):
                    pidfile.write(str(win32api.GetCurrentProcess()))

        def shutDown(self):
            """
            Subclasses may override and normally follow this sequence:
                1. set self._shuttingDown to 1
                2. class specific statements for shutting down
                3. Invoke super's shutDown() e.g., AppServer.shutDown(self)
            """
            print "Shutting down the AppServer"
            self._shuttingDown = 1
            self.running = 0
            self._app.shutDown()
            del self._plugIns
            del self._app
            if Profiler.profiler:
                print 'Writing profile stats to %s...' % Profiler.statsFilename
                Profiler.dumpStats()  # you might also considering having a page/servlet that lets you dump the stats on demand
                print
                print 'WARNING: Applications run much slower when profiled, so turn off profiling in Launch.py when you are finished.'
                print
                print 'AppServer ran for %0.2f seconds.' % (time.time()-Profiler.startTime)
            print "AppServer has been shutdown"

        ## Configuration ##

        def defaultConfig(self):
            return DefaultConfig

        def configFilename(self):
            return self.serverSidePath('Configs/AppServer.config')

        def configReplacementValues(self):
            return {      # Since these strings will be eval'ed we need to double escape any backslashes
                'WebwarePath' : string.replace(self._webwarePath, '\\', '\\\\'),
                'WebKitPath'  : string.replace(self._webKitPath, '\\', '\\\\'),
                'serverSidePath' : string.replace(self._serverSidePath, '\\', '\\\\'),
                }

        ## Network Server ##

        def createApplication(self):
            """ Creates and returns an application object. Invoked by __init__. """
            return Application(server=self)

        def printStartUpMessage(self):
            """ Invoked by __init__. """
            print 'WebKit AppServer', self.version()
            print 'part of Webware for Python'
            print 'Copyright 1999-2001 by Chuck Esterbrook. All Rights Reserved.'
            print 'WebKit and Webware are open source.'
            print 'Please visit:  http://webware.sourceforge.net'
            print
            print 'Process id is', os.getpid()
            print 'Date/time is', time.asctime(time.localtime(time.time()))
            print
            if self.setting('PrintConfigAtStartUp'):
                self.printConfig()

        ## Plug-ins ##

        def plugIns(self):
            """ Returns a list of the plug-ins loaded by the app server. Each plug-in is a python package. """
            return self._plugIns

        def plugIn(self, name, default=NoDefault):
            """ Returns the plug-in with the given name. """
            # @@ 2001-04-25 ce: linear search. yuck. Plus we should guarantee plug-in name uniqueness anyway
            for pi in self._plugIns:
                if pi.name()==name:
                    return pi
            if default is NoDefault:
                raise KeyError, name
            else:
                return default

        def loadPlugIn(self, path):
            """ Loads and returns the given plug-in. May return None if loading was unsuccessful (in which case this method prints a message saying so). Used by loadPlugIns(). """
            plugIn = None
            path = self.serverSidePath(path)
            try:
                plugIn = PlugIn(self, path)
                willNotLoadReason = plugIn.load()
                if willNotLoadReason:
                    print '    Plug-in %s cannot be loaded because:\n    %s' % (path, willNotLoadReason)
                    return None
                plugIn.install()
            except:
                import traceback
                traceback.print_exc(file=sys.stderr)
                self.error('Plug-in %s raised exception.' % path)
            return plugIn

        def loadPlugIns(self):
            """
            A plug-in allows you to extend the functionality of WebKit without necessarily having to modify it's source. Plug-ins are loaded by AppServer at startup time, just before listening for requests. See the docs for PlugIn.py for more info.
            """
            plugIns = self.setting('PlugIns')
            plugIns = map(lambda path, ssp=self.serverSidePath: ssp(path), plugIns)

            # Scan each directory named in the PlugInDirs list.
            # If those directories contain Python packages (that
            # don't have a "dontload" file) then add them to the
            # plugs in list.
            for plugInDir in self.setting('PlugInDirs'):
                plugInDir = self.serverSidePath(plugInDir)
                for filename in os.listdir(plugInDir):
                    filename = os.path.normpath(os.path.join(plugInDir, filename))
                    if os.path.isdir(filename) and \
                       os.path.exists(os.path.join(filename, '__init__.py')) and \
                       os.path.exists(os.path.join(filename, 'Properties.py')) and \
                       not os.path.exists(os.path.join(filename, 'dontload')) and \
                       os.path.basename(filename)!='WebKit' and \
                       filename not in plugIns:
                        plugIns.append(filename)

            print 'Plug-ins list:', string.join(plugIns, ', ')

            # Now that we have our plug-in list, load them...
            for plugInPath in plugIns:
                plugIn = self.loadPlugIn(plugInPath)
                if plugIn:
                    self._plugIns.append(plugIn)
            print

        ## Access ##

        def version(self):
            if not hasattr(self,'_webKitVersionString'):
                from MiscUtils.PropertiesObject import PropertiesObject
                props = PropertiesObject(os.path.join(self.webKitPath(), 'Properties.py'))
                self._webKitVersionString = props['versionString']
            return self._webKitVersionString

        def application(self):
            return self._app

        def startTime(self):
            """ Returns the time the app server was started (as seconds, like time()). """
            return self._startTime

        def numRequests(self):
            """ Return the number of requests received by this server since it was launched. """
            return self._reqCount

        def isPersistent(self):
            raise AbstractError, self.__class__

        def serverSidePath(self, path=None):
            """ Returns the absolute server-side path of the WebKit app server. If the optional path is passed in, then it is joined with the server side directory to form a path relative to the app server.
            """
            if path:
                return os.path.normpath(os.path.join(self._serverSidePath, path))
            else:
                return self._serverSidePath

        def webwarePath(self):
            return self._webwarePath

        def webKitPath(self):
            return self._webKitPath

        ## Warnings and Errors ##

        def warning(self, msg):
            # @@ 2000-04-25 ce: would this be useful?
            raise NotImplementedError

        def error(self, msg):
            """
            Flushes stdout and stderr, prints the message to stderr and exits with code 1.
            """
            sys.stdout.flush()
            sys.stderr.flush()
            sys.stderr.write('ERROR: %s\n' % msg)
            sys.stderr.flush()
            sys.exit(1)  # @@ 2000-05-29 ce: Doesn't work. Perhaps because of threads

    def main():
        try:
            server = AppServer()
            return
            print "Ready"
            print
            print 'WARNING: There is nothing to do here with the abstract AppServer. Use one of the adapters such as WebKit.cgi (with ThreadedAppServer) or OneShot.cgi'
            server.shutDown()
        except Exception, exc:  # Need to kill the Sweeper thread somehow
            print 'Caught exception:', exc
            print "Exiting AppServer"
            server.shutDown()
            del server
            sys.exit()

    def stop(*args, **kw):
        pidfile = os.path.join(os.path.dirname(__file__),"appserverpid.txt")
        pid = int(open(pidfile,"r").read())
        #now what for windows?
        if os.name == 'posix':
            import signal
            os.kill(pid,signal.SIGINT)
        else:
            try:
                import win32process
            except:
                print "Win32 extensions not present.  Webkit cannot terminate the running process."
            if sys.modules.has_key('win32process'):
                win32process.TerminateProcess(pid,0)

    if __name__=='__main__':
        main()