socketServers.py
上传用户:quxuerui
上传日期:2018-01-08
资源大小:41811k
文件大小:24k
源码类别:

网格计算

开发平台:

Java

  1. #Licensed to the Apache Software Foundation (ASF) under one
  2. #or more contributor license agreements.  See the NOTICE file
  3. #distributed with this work for additional information
  4. #regarding copyright ownership.  The ASF licenses this file
  5. #to you under the Apache License, Version 2.0 (the
  6. #"License"); you may not use this file except in compliance
  7. #with the License.  You may obtain a copy of the License at
  8. #     http://www.apache.org/licenses/LICENSE-2.0
  9. #Unless required by applicable law or agreed to in writing, software
  10. #distributed under the License is distributed on an "AS IS" BASIS,
  11. #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. #See the License for the specific language governing permissions and
  13. #limitations under the License.
  14. # Various socket server and helper classes.
  15. #
  16. #
  17. import os, sys, socket, threading, pprint, re, xmlrpclib, time
  18.   
  19. from select import select
  20. from SocketServer import ThreadingMixIn, ForkingMixIn
  21. from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
  22. from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer
  23. from SimpleHTTPServer import SimpleHTTPRequestHandler
  24. from random import Random
  25. from urlparse import urlparse
  26. Fault = xmlrpclib.Fault
  27. from hodlib.Common.util import local_fqdn
  28. from hodlib.Common.logger import hodDummyLogger
  29. class hodHTTPHandler(BaseHTTPRequestHandler):
  30.   port = -1
  31.   def __init__(self, request, client_address, server, registerService):
  32.     self.registerService = registerService
  33.     BaseHTTPRequestHandler.__init__(self, request, client_address, server)
  34.   
  35.   def log_message(self, *args):
  36.     """Forget logging for now."""
  37.     
  38.     pass
  39.       
  40.   def do_GET(self):
  41.     self.fullUrl = "http://%s:%s%s" % (self.server.server_address[0],
  42.                                        self.server.server_address[1], 
  43.                                        self.path)
  44.     
  45.     parsedUrl = urlparse(self.fullUrl)
  46.     self.writeHeaders()
  47.     self.writeData(parsedUrl)
  48.   
  49.   def w(self, string):
  50.     self.wfile.write("%sn" % string)
  51.   
  52.   def writeHeaders(self):
  53.    self.send_response(200, 'OK')
  54.    self.send_header('Content-type', 'text/html')
  55.    self.end_headers()   
  56.      
  57.   def sendWrongPage(self, userJob):
  58.     self.w('<font class="alert">')
  59.     if userJob == False:
  60.       self.w('invalid URL specified')   
  61.     elif re.match("^d+$", userJob):
  62.       self.w('invalid URL specified, job <b>%s</b> does not exist' % userJob)
  63.     elif re.match("^w+$", userJob):
  64.       self.w('invalid URL specified, user <b>%s</b> does not exist' % userJob) 
  65.     self.w('</font>')
  66.     
  67.   def getServiceHosts(self, serviceInfo):
  68.     hostInfo = { 'long' : {}, 'short' : {} }
  69.     for user in serviceInfo:
  70.       for job in serviceInfo[user]:
  71.         for host in serviceInfo[user][job]:
  72.           for serviceItem in serviceInfo[user][job][host]:
  73.             serviceName = serviceItem.keys()
  74.             serviceName = serviceName[0]
  75.             if isinstance(serviceItem[serviceName], str):
  76.               hostInfo['short'][self.getJobKey(user, job, host)] = True
  77.             hostInfo['long'][self.getJobKey(user, job, host)] = True
  78.     
  79.     return hostInfo
  80.   def getJobInfo(self, job, serviceInfo):
  81.     jobInfo = {}
  82.     
  83.     for user in serviceInfo.keys():
  84.       for someJob in serviceInfo[user].keys():
  85.         if job == someJob:
  86.           jobInfo[user] = { job : serviceInfo[user][job] }
  87.     
  88.     return jobInfo
  89.   
  90.   def getJobKey(self, user, job, host):
  91.     return "%s-%s-%s" % (user, job, host)
  92.   
  93.   def writeData(self, parsedUrl):
  94.     options = parsedUrl[4]
  95.     serviceInfo = self.server.service.getServiceInfo()
  96.     users = serviceInfo.keys()
  97.     users.sort()
  98.     self.w("<html>")
  99.     self.w("<body>")
  100.     self.w("<head>")
  101.     self.writeCSS()
  102.     self.w("</head>")
  103.     self.w('<font class="header2">HOD Service Registry Information</font>')
  104.     if serviceInfo == {}:
  105.       self.w('<br><br><font class="header">&nbsp;&nbsp;No HOD clusters configured.</font>')
  106.     else:
  107.       if parsedUrl[2] == '/':
  108.         self.w('&nbsp;&nbsp;&nbsp;<table class="main">')
  109.         count = 0
  110.         for user in users:
  111.           self.writeUserData(user, options, serviceInfo, count)
  112.           count = count + 1
  113.       elif parsedUrl[2][1:] in serviceInfo:
  114.         self.w('&nbsp;&nbsp;&nbsp;<table class="main">')
  115.         self.writeUserData(parsedUrl[2][1:], options, serviceInfo, 0)
  116.       elif re.match("^d+$", parsedUrl[2][1:]):
  117.         jobInfo = self.getJobInfo(parsedUrl[2][1:], serviceInfo)
  118.         if jobInfo.keys():
  119.           self.w('&nbsp;&nbsp;&nbsp;<table class="main">')
  120.           for user in jobInfo.keys():
  121.             self.writeUserData(user, options, jobInfo, 0)   
  122.         else:
  123.           self.sendWrongPage(parsedUrl[2][1:]) 
  124.           self.w('&nbsp;&nbsp;&nbsp;<table class="main">')
  125.           count = 0
  126.           for user in users:
  127.             self.writeUserData(user, options, serviceInfo, count)
  128.             count = count + 1
  129.       elif re.match("^w+$", parsedUrl[2][1:]):
  130.         self.sendWrongPage(parsedUrl[2][1:]) 
  131.         self.w('&nbsp;&nbsp;&nbsp;<table class="main">')
  132.         count = 0
  133.         for user in users:
  134.           self.writeUserData(user, options, serviceInfo, count)
  135.           count = count + 1        
  136.       else:
  137.         self.sendWrongPage(False) 
  138.         self.w('&nbsp;&nbsp;&nbsp;<table class="main">')
  139.         count = 0
  140.         for user in users:
  141.           self.writeUserData(user, options, serviceInfo, count)
  142.           count = count + 1
  143.     self.w('</table>')
  144.     self.w("</pre>")
  145.     self.w("</body>")
  146.     self.w("</html>")
  147.   def writeCSS(self):
  148.     self.w('<style type="text/css">')
  149.     
  150.     self.w('table.main { border: 0px; padding: 1; background-color: #E1ECE0; width: 70%; margin: 10; }')
  151.     self.w('table.sub1 { background-color: #F1F1F1; padding: 0; }')
  152.     self.w('table.sub2 { background-color: #FFFFFF; padding: 0; }')
  153.     self.w('table.sub3 { border: 1px solid #EEEEEE; background-color: #FFFFFF; padding: 0; }')
  154.     self.w('td.header { border-bottom: 1px solid #CCCCCC; padding: 2;}')
  155.     self.w('td.service1 { border: 0px; background-color: #FFFFFF; padding: 2; width: 10%}')
  156.     self.w('td.service2 { border: 0px; background-color: #FFFFFF; padding: 2; width: 90%}')
  157.     self.w('td { vertical-align: top; padding: 0; }')
  158.     self.w('td.noborder { border-style: none; border-collapse: collapse; }')
  159.     self.w('tr.colored { background-color: #F1F1F1; }')
  160.     self.w('font { font-family: Helvetica, Arial, sans-serif; font-size: 10pt; color: #666666; }')
  161.     self.w('font.header { font-family: Helvetica, Arial, sans-serif;  font-size: 10pt; color: #333333; font-style: bold }')
  162.     self.w('font.header2 { font-family: Helvetica, Arial, sans-serif; font-size: 16pt; color: #333333; }')
  163.     self.w('font.sml { font-family: Helvetica, Arial, sans-serif; font-size: 8pt; color: #666666; }')
  164.     self.w('font.alert { font-family: Helvetica, Arial, sans-serif; font-size: 9pt; color: #FF7A22; }')
  165.     self.w('a { font-family: Helvetica, Arial, sans-serif; text-decoration:none; font-size: 10pt; color: #111111; }')
  166.     self.w('a:visited { font-family: Helvetica, Arial, sans-serif; color:#2D4628; text-decoration:none; font-size: 10pt; }')
  167.     self.w('a:hover { font-family: Helvetica, Arial, sans-serif; color:#00A033; text-decoration:none; font-size: 10pt; }')
  168.     self.w('a.small { font-family:  Helvetica, Arial, sans-serif; text-decoration:none; font-size: 8pt }')
  169.     self.w('a.small:hover { color:#822499; text-decoration:none; font-size: 8pt }')
  170.     self.w("</style>")
  171.   def writeUserData(self, user, options, serviceInfo, count):
  172.     hostInfo = self.getServiceHosts(serviceInfo)
  173.     hostKey = 'short'
  174.     if options == 'display=long':
  175.       hostKey = 'long'
  176.     if count == 0:
  177.       self.w('<tr>')
  178.       self.w('<td class="header" colspan="2">')
  179.       self.w('<font class="header">Active Users</font>')
  180.       self.w('</td>')
  181.       self.w('</tr>')
  182.     self.w('<tr>')
  183.     self.w('<td><font>%s</font></td>' % user)
  184.     self.w('<td>')
  185.     jobIDs = serviceInfo[user].keys()
  186.     jobIDs.sort()
  187.     for jobID in jobIDs: 
  188.       self.w('<table class="sub1" width="100%">')
  189.       if count == 0:
  190.         self.w('<tr>')
  191.         self.w('<td class="header" colspan="2">')
  192.         self.w('<font class="header">PBS Job Identifiers</font>')
  193.         self.w('</td>')
  194.         self.w('</tr>')        
  195.       self.w('<tr>')
  196.       self.w('<td><font>%s</font></td>' % jobID)
  197.       self.w('<td>')
  198.       hosts = serviceInfo[user][jobID].keys()
  199.       hosts.sort()
  200.       for host in hosts:
  201.         if hostInfo[hostKey].has_key(self.getJobKey(user, jobID, host)):
  202.           self.w('<table class="sub2" width="100%">')
  203.           if count == 0:
  204.             self.w('<tr>')
  205.             self.w('<td class="header" colspan="2">')
  206.             self.w('<font class="header">Hosts Running Services</font>')
  207.             self.w('</td>')
  208.             self.w('</tr>')  
  209.           self.w('<tr>')
  210.           self.w('<td><font>%s</font></td>' % host)
  211.           self.w('<td>')
  212.           self.w('<table class="sub3" width="100%">')
  213.           self.w('<tr>')
  214.           self.w('<td colspan="2">')
  215.           self.w('<font class="header">Service Information</font>')
  216.           self.w('</td>')
  217.           self.w('</tr>')  
  218.           for serviceItem in serviceInfo[user][jobID][host]:
  219.             serviceName = serviceItem.keys()
  220.             serviceName = serviceName[0]
  221.             if isinstance(serviceItem[serviceName], dict) and 
  222.               options == 'display=long':
  223.               self.w('<tr class="colored">')
  224.               self.w('<td><font>%s</font></td>' % serviceName)
  225.               self.w('<td>')
  226.               self.w('<table width="100%">')
  227.               for key in serviceItem[serviceName]:
  228.                 self.w('<tr>')
  229.                 self.w('<td class="service1"><font>%s</font></td>' % key)
  230.                 self.w('<td class="service2"><font>%s</font></td>' % serviceItem[serviceName][key])
  231.                 self.w('</tr>')
  232.               self.w('</table>')
  233.               self.w('</td>')
  234.               self.w('</tr>')
  235.             elif isinstance(serviceItem[serviceName], str):
  236.               self.w('<tr class="colored">')
  237.               self.w('<td><font class="service1">%s</font></td>' % serviceName)
  238.               self.w('<td>')
  239.               (host, port) = serviceItem[serviceName].split(':')
  240.               hostnameInfo = socket.gethostbyname_ex(host)
  241.               if serviceName.startswith('mapred'):
  242.                 self.w('<a href="http://%s:%s">Hadoop Job Tracker</a>' % (hostnameInfo[0], port))
  243.               elif serviceName.startswith('hdfs'):
  244.                 self.w('<a href="http://%s:%s">HDFS Name Node</a>&nbsp' % (hostnameInfo[0], port))
  245.               else:
  246.                 self.w('<font class="service2">%s</font>' % serviceItem[serviceName])
  247.               self.w('</td>')
  248.               self.w('</tr>')
  249.           self.w('</table>')    
  250.           self.w('</td>')
  251.           self.w('</tr>')
  252.           self.w('</table>')
  253.           count = count + 1
  254.       self.w('</td>')  
  255.       self.w('</tr>')
  256.       self.w('</table>')
  257.       count = count + 1
  258.     self.w('</td>')
  259.     self.w('</tr>')
  260. #    self.w("<pre>")
  261. #    self.w(pprint.pformat(serviceInfo))
  262. #    self.w("</pre>")
  263.     
  264. class baseSocketServer:
  265.     def __init__(self, host, ports):
  266.         self.host = host
  267.         self.ports = ports
  268.         self.__stopForever = threading.Event()
  269.         self.__stopForever.clear()
  270.         self.__run = threading.Event()
  271.         self.__run.set()    
  272.         self.server_address = ()
  273.         self.mThread = None
  274.         
  275.     def server_bind(self):
  276.         """server_bind() method binds to a random range of ports."""
  277.         self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  278.         if len(self.ports) > 1:
  279.             randomPort = Random(os.getpid())
  280.             portSequence = range(self.ports[0], self.ports[1])
  281.             maxTryCount = abs(self.ports[0] - self.ports[1])
  282.             tryCount = 0
  283.             while True:
  284.                 somePort = randomPort.choice(portSequence)
  285.                 self.server_address = (self.host, somePort)
  286.                 try:
  287.                     self.socket.bind(self.server_address)
  288.                 except socket.gaierror, errData:
  289.                     raise socket.gaierror, errData
  290.                 except:
  291.                     tryCount = tryCount + 1
  292.                     if tryCount > maxTryCount:
  293.                         bindError = "bind failure for port range %s:%d" % (
  294.                             self.ports)
  295.                         raise socket.error, bindError
  296.                 else:
  297.                     break
  298.         else:
  299.             self.server_address = (self.host, int(self.ports[0]))
  300.             self.socket.bind(self.server_address)
  301.         
  302.         if self.host == '':
  303.             self.server_address = (local_fqdn(), self.server_address[1])
  304.     def _serve_forever(self):
  305.         """Replacement for serve_forever loop.
  306.         
  307.            All baseSocketServers run within a master thread; that thread
  308.            imitates serve_forever, but checks an event (self.__stopForever) 
  309.            before processing new connections.
  310.         """
  311.         
  312.         while not self.__stopForever.isSet():
  313.             (rlist, wlist, xlist) = select([self.socket], [], [], 
  314.                                            1)
  315.             
  316.             if (len(rlist) > 0 and self.socket == rlist[0]):
  317.                 self.handle_request()
  318.         
  319.             while not self.__run.isSet():
  320.                 if self.__stopForever.isSet():
  321.                     break
  322.                 time.sleep(1)
  323.         
  324.         self.server_close()
  325.         
  326.         return True
  327.     def serve_forever(self):
  328.         """Handle requests until stopForever event flag indicates stop."""
  329.         self.mThread = threading.Thread(name="baseSocketServer", 
  330.                                         target=self._serve_forever)
  331.         self.mThread.start()
  332.         return self.mThread
  333.     def pause(self):
  334.         """Temporarily stop servicing requests."""
  335.         self.__run.clear()
  336.     def cont(self):
  337.         """Resume servicing requests."""
  338.         self.__run.set()
  339.     def stop(self):
  340.         """Set the stopForever flag to tell serve_forever() to exit."""
  341.     
  342.         self.__stopForever.set()
  343.         if self.mThread: self.mThread.join()
  344.         return True
  345.     def is_alive(self):
  346.         if self.mThread != None:
  347.             return self.mThread.isAlive()
  348.         else:
  349.             return False
  350. class threadedHTTPServer(baseSocketServer, ThreadingMixIn, HTTPServer):
  351.     def __init__(self, host, ports):
  352.         baseSocketServer.__init__(self, host, ports)
  353.         HTTPServer.__init__(self, self.server_address, SimpleHTTPRequestHandler)
  354. class forkingHTTPServer(baseSocketServer, ForkingMixIn, HTTPServer):
  355.     def __init__(self, host, ports):
  356.         baseSocketServer.__init__(self, host, ports)
  357.         HTTPServer.__init__(self, self.server_address, SimpleHTTPRequestHandler)
  358. class hodHTTPServer(baseSocketServer, ThreadingMixIn, HTTPServer):
  359.     service = None 
  360.     def __init__(self, host, ports, serviceobj = None):
  361.         self.service = serviceobj
  362.         baseSocketServer.__init__(self, host, ports)
  363.         HTTPServer.__init__(self, self.server_address, hodHTTPHandler)
  364.     def finish_request(self, request, client_address):
  365.         self.RequestHandlerClass(request, client_address, self, self.service)
  366.         
  367. class hodXMLRPCServer(baseSocketServer, ThreadingMixIn, SimpleXMLRPCServer):
  368.     def __init__(self, host, ports, 
  369.                  requestHandler=SimpleXMLRPCRequestHandler, 
  370.                  logRequests=False, allow_none=False, encoding=None):
  371.         baseSocketServer.__init__(self, host, ports)
  372.         SimpleXMLRPCServer.__init__(self, self.server_address, requestHandler, 
  373.                                     logRequests)
  374.         
  375.         self.register_function(self.stop, 'stop')
  376. try:
  377.     from twisted.web import server, xmlrpc
  378.     from twisted.internet import reactor, defer
  379.     from twisted.internet.threads import deferToThread
  380.     from twisted.python import log
  381.                 
  382.     class twistedXMLRPC(xmlrpc.XMLRPC):
  383.         def __init__(self, logger):
  384.             xmlrpc.XMLRPC.__init__(self)
  385.             
  386.             self.__XRMethods = {}
  387.             self.__numRequests = 0
  388.             self.__logger = logger
  389.             self.__pause = False
  390.     
  391.         def render(self, request):
  392.             request.content.seek(0, 0)
  393.             args, functionPath = xmlrpclib.loads(request.content.read())
  394.             try:
  395.                 function = self._getFunction(functionPath)
  396.             except Fault, f:
  397.                 self._cbRender(f, request)
  398.             else:
  399.                 request.setHeader("content-type", "text/xml")
  400.                 defer.maybeDeferred(function, *args).addErrback(
  401.                     self._ebRender).addCallback(self._cbRender, request)
  402.             
  403.             return server.NOT_DONE_YET
  404.     
  405.         def _cbRender(self, result, request):
  406.             if isinstance(result, xmlrpc.Handler):
  407.                 result = result.result
  408.             if not isinstance(result, Fault):
  409.                 result = (result,)
  410.             try:
  411.                 s = xmlrpclib.dumps(result, methodresponse=1)
  412.             except:
  413.                 f = Fault(self.FAILURE, "can't serialize output")
  414.                 s = xmlrpclib.dumps(f, methodresponse=1)
  415.             request.setHeader("content-length", str(len(s)))
  416.             request.write(s)
  417.             request.finish()
  418.      
  419.         def _ebRender(self, failure):
  420.             if isinstance(failure.value, Fault):
  421.                 return failure.value
  422.             log.err(failure)
  423.             return Fault(self.FAILURE, "error")
  424.         
  425.         def _getFunction(self, methodName):
  426.             while self.__pause:
  427.                 time.sleep(1)
  428.             
  429.             self.__numRequests = self.__numRequests + 1
  430.             function = None
  431.             try:
  432.                 def defer_function(*args):
  433.                     return deferToThread(self.__XRMethods[methodName], 
  434.                                          *args)
  435.                 function = defer_function
  436.                 self.__logger.info(
  437.                     "[%s] processing defered XML-RPC call to: %s ..." % 
  438.                     (self.__numRequests, methodName))            
  439.             except KeyError:
  440.                 self.__logger.warn(
  441.                     "[%s] fault %s on XML-RPC call to %s, method not found." % (
  442.                     self.__numRequests, self.NOT_FOUND, methodName))
  443.                 raise xmlrpc.NoSuchFunction(self.NOT_FOUND, 
  444.                                             "method %s not found" % methodName)
  445.             
  446.             return function
  447.         
  448.         def register_function(self, functionRef, methodName):
  449.             self.__XRMethods[methodName] = functionRef
  450.             
  451.         def list_methods(self):
  452.             return self.__XRMethods.keys()
  453.         
  454.         def num_requests(self):
  455.             return self.__numRequests
  456.         
  457.         def pause(self):
  458.             self.__pause = True
  459.         
  460.         def cont(self):
  461.             self.__pause = False
  462.             
  463.     class twistedXMLRPCServer:
  464.         def __init__(self, host, ports, logger=None, threadPoolSize=100):
  465.             self.__host = host
  466.             self.__ports = ports
  467.             
  468.             if logger == None:
  469.                 logger = hodDummyLogger()
  470.             
  471.             self.__logger = logger
  472.                 
  473.             self.server_address = ['', '']
  474.             reactor.suggestThreadPoolSize(threadPoolSize)    
  475.     
  476.             self.__stopForever = threading.Event()
  477.             self.__stopForever.clear()
  478.             self.__mThread = None
  479.                 
  480.             self.__xmlrpc = twistedXMLRPC(self.__logger)
  481.                 
  482.         def _serve_forever(self):
  483.             if len(self.__ports) > 1:
  484.                 randomPort = Random(os.getpid())
  485.                 portSequence = range(self.__ports[0], self.__ports[1])
  486.     
  487.                 maxTryCount = abs(self.__ports[0] - self.__ports[1])
  488.                 tryCount = 0
  489.                 while True:
  490.                     somePort = randomPort.choice(portSequence)
  491.                     self.server_address = (self.__host, int(somePort))
  492.                     if self.__host == '':
  493.                         self.server_address = (local_fqdn(), self.server_address[1])
  494.                     try:
  495.                         reactor.listenTCP(int(somePort), server.Site(
  496.                             self.__xmlrpc), interface=self.__host)
  497.                         reactor.run(installSignalHandlers=0)
  498.                     except:
  499.                         self.__logger.debug("Failed to bind to: %s:%s." % (
  500.                             self.__host, somePort))
  501.                         tryCount = tryCount + 1
  502.                         if tryCount > maxTryCount:
  503.                             self.__logger.warn("Failed to bind to: %s:%s" % (
  504.                                 self.__host, self.__ports))
  505.                             sys.exit(1)
  506.                     else:
  507.                         break
  508.             else:
  509.                 try:
  510.                     self.server_address = (self.__host, int(self.__ports[0]))
  511.                     if self.__host == '':
  512.                         self.server_address = (local_fqdn(), self.server_address[1])
  513.                     reactor.listenTCP(int(self.__ports[0]), server.Site(self.__xmlrpc), 
  514.                                       interface=self.__host)
  515.                     reactor.run(installSignalHandlers=0)
  516.                 except:
  517.                     self.__logger.warn("Failed to bind to: %s:%s."% (
  518.                             self.__host, self.__ports[0]))
  519.                     sys.exit(1)
  520.             
  521.         def serve_forever(self):
  522.             """Handle requests until stopForever event flag indicates stop."""
  523.     
  524.             self.__mThread = threading.Thread(name="XRServer",
  525.                                               target=self._serve_forever)
  526.             self.__mThread.start()
  527.             
  528.             if not self.__mThread.isAlive():
  529.                 raise Exception("Twisted XMLRPC server thread dead.")
  530.                     
  531.         def register_function(self, functionRef, methodName):
  532.             self.__xmlrpc.register_function(functionRef, methodName)
  533.         
  534.         def register_introspection_functions(self):
  535.             pass
  536.         
  537.         def register_instance(self, instance):
  538.             for method in dir(instance):
  539.                 if not method.startswith('_'):
  540.                     self.register_function(getattr(instance, method), method)
  541.         
  542.         def pause(self):
  543.             self.__xmlrpc.pause()
  544.         
  545.         def cont(self):
  546.             self.__xmlrpc.cont()
  547.         
  548.         def stop(self):
  549.             def stop_thread():
  550.                 time.sleep(2)
  551.                 reactor.stop()
  552.                 
  553.             self.__stopForever.set()
  554.             
  555.             stopThread = threading.Thread(name='XRStop', target=stop_thread)
  556.             stopThread.start()
  557.                 
  558.             return True
  559.             
  560.         def is_alive(self):
  561.             status = False
  562.             if reactor.running == 1:
  563.                 status = True
  564.             
  565.             return status
  566.         
  567.         def status(self):
  568.             """Return status information on running XMLRPC Server."""
  569.             stat = { 'XR server address'     : self.server_address,
  570.                      'XR methods'            : self.system_listMethods(),
  571.                      'XR server alive'       : self.is_alive(),
  572.                      'XR requests processed' : self.__xmlrpc.num_requests(),
  573.                      'XR server stop flag'   : self.__stopForever.isSet()}
  574.             return(stat)
  575.         
  576.         def system_listMethods(self):
  577.             return self.__xmlrpc.list_methods()
  578.         
  579.         def get_server_address(self):
  580.             waitCount = 0
  581.             while self.server_address == '':
  582.                 if waitCount == 9:
  583.                     break 
  584.                 time.sleep(1)
  585.                 waitCount = waitCount + 1
  586.                 
  587.             return self.server_address
  588. except ImportError:
  589.     pass