The server is remarkably free of code that relates to distribution: most of the server code is simply application logic that would be present just the same as a non-distributed version. Again, this is one of the major advantages of Ice: distribution concerns are kept away from application code so that you can concentrate on developing application logic instead of networking infrastructure.
On this page:
Implementing a File System Server in Python
We have now seen enough of the server-side Python mapping to implement a server for our file system. (You may find it useful to review these Slice definitions before studying the source code.)
Our server is implemented in a single source file,
server.py, containing our server's main program as well as the definitions of our
File servant subclasses.
Server Main Program in Python
Our server main program creates and destroys an Ice communicator and call the
run helper function.
run uses this communicator instantiate our file system objects:
Much of this code is boiler plate: we create a communicator, then an object adapter, and, towards the end, activate the object adapter and call
The interesting part of the code follows the adapter creation: here, the server instantiates a few nodes for our file system to create the structure shown below:
A small file system.
As we will see shortly, the servants for our directories and files are of type
FileI, respectively. The constructor for either type of servant accepts two parameters, the name of the directory or file to be created and a reference to the servant for the parent directory. (For the root directory, which has no parent, we pass
None.) Thus, the statement
creates the root directory, with the name
"/" and no parent directory.
Here is the code that establishes the structure in the above illustration:
We first create the root directory and a file
README within the root directory. (Note that we pass a reference to the root directory as the parent when we create the new node of type
The next step is to fill the file with text:
Recall that Slice sequences map to Python lists. The Slice type
Lines is simply a list of strings; we add a line of text to our
README file by initializing the
text list to contain one element.
Finally, we call the Slice
write operation on our
FileI servant by simply writing:
This statement is interesting: the server code invokes an operation on one of its own servants. Because the call happens via a reference to the servant (of type
FileI) and not via a proxy (of type
FilePrx), the Ice run time does not know that this call is even taking place — such a direct call into a servant is not mediated by the Ice run time in any way and is dispatched as an ordinary Python method call.
In similar fashion, the remainder of the code creates a subdirectory called
Coleridge and, within that directory, a file called
Kubla_Khan to complete the structure in the above illustration.
FileI Servant Class in Python
FileI servant class has the following basic structure:
The class has a number of data members:
This class member stores a reference to the single object adapter we use in our server.
This instance member stores the name of the file incarnated by the servant.
This instance member stores the reference to the servant for the file's parent directory.
This instance member holds the contents of the file.
_lines data members are initialized by the constructor:
After initializing the instance members, the code verifies that the reference to the parent is not
None because every file must have a parent directory. The constructor then generates an identity for the file by calling
Ice.generateUUID and adds itself to the servant map by calling
ObjectAdapter.add. Finally, the constructor creates a proxy for this file and calls the
addChild method on its parent directory.
addChild is a helper function that a child directory or file calls to add itself to the list of descendant nodes of its parent directory. We will see the implementation of this function in
The remaining methods of the
FileI class implement the Slice operations we defined in the
File Slice interfaces:
name method is inherited from the generated
Node class. It simply returns the value of the
_name instance member.
write methods are inherited from the generated
File class and simply return and set the
_lines instance member.
DirectoryI Servant Class in Python
DirectoryI class has the following basic structure:
DirectoryI Data Members in Python
As for the
FileI class, we have data members to store the object adapter, the name, and the parent directory. (For the root directory, the
_parent member holds
None.) In addition, we have a
_contents data member that stores the list of child directories. These data members are initialized by the constructor:
DirectoryI Constructor in Python
The constructor creates an identity for the new directory by calling
Ice.generateUUID. (For the root directory, we use the fixed identity
"RootDir".) The servant adds itself to the servant map by calling
ObjectAdapter.add and then creates a proxy to itself and passes it to the
addChild helper function.
DirectoryI Methods in Python
addChild simply adds the passed reference to the
The remainder of the operations,
list, are trivial: