Software Design Spring 2006 Today: 1) RemoteTurtleWorld 2) multiple inheritance RemoteTurtleWorld ----------------- Let's make TurtleWorld available as a remote object: from World import * from RemoteObject import * class RemoteTurtleWorld(TurtleWorld, RemoteObject): def __init__(self): TurtleWorld.__init__(self) RemoteObject.__init__(self) def quit(self): self.stopLoop() self.join() World.quit(self) def run_message(self, message): self.inter.run_code(message, '') def main(script, name): watcher = Watcher() world = RemoteTurtleWorld() ns = NameServer() world.connect(ns, name) world.threadLoop() world.mainloop() if __name__ == '__main__': main(*sys.argv) Some comments: 1) You can inherit from more than one class. The style I am using here is sometimes called a "mix-in", although that is a slight abuse of the term. 2) If you override a method, you can still call the original method by specifying the parent class. In this case __init__ invokes the __init__ method from both parent classes. Similarly, quit stops the request loop and then invokes World.quit. 3) All the methods in the World class are available for remote execution, but it would take some thinking to figure out which ones are likely to work. What would you do if you wanted more control of this interface? 4) run_message is added here as a remote method, to give clients the ability to execute arbitrary code on my laptop! 5) In order to run the GUI and the RemoteObject, we need to run two loops! One option: run each one for a fraction of a second. Problems: need both libraries to provide the right interface. non-responsiveness if one loop hangs Solution: run the loops in different threads thread schedule handles timesharing RemoteObject.threadLoop does what we want: def threadLoop(self): """run the request loop in a separate thread""" self.thread = threading.Thread(target=self.stoppableLoop) self.thread.start() def stoppableLoop(self): """run handleRequests until another thread clears self.running""" self.running = 1 try: while self.running: self.demon.handleRequests(0.1) finally: self.cleanup() def stopLoop(self): """if threadLoop is running, stop it""" self.running = 0 RemoteTurtleWorld client ------------------------ Your mission: write a client that 1) connects to the name server on ece 2) makes a proxy for the object named 'allen' 3) invokes run_message and passes some turtle code for execution. Your turtle code can assume that there is a variable 'world' that refers to the current world. Hint: you might want to write a client that reads a file and sends it as a remote message.