Table of Contents Previous Next
Logo
Slice for a Simple File System : 5.3 Slice Definitions for the File System
Copyright © 2003-2009 ZeroC, Inc.

5.3 Slice Definitions for the File System

Given the very simple requirements we just outlined, we can start designing interfaces for the system. Files and directories have something in common: they have a name and both files and directories can be contained in directories. This suggests a design that uses a base type that provides the common functionality, and derived types that provide the functionality specific to directories and files, as shown in Figure 5.1.
Figure 5.1. Inheritance Diagram of the File System.
The Slice definitions for this look as follows:
interface Node { 
    // ...
}; 

interface File extends Node { 
    // ...
}; 

interface Directory extends Node { 
    // ...
}; 
Next, we need to think about what operations should be provided by each interface. Seeing that directories and files have names, we can add an operation to obtain the name of a directory or file to the Node base interface:
interface Node { 
    idempotent string name();
}; 
The File interface provides operations to read and write a file. For simplicity, we limit ourselves to text files and we assume that read operations never fail and that only write operations can encounter error conditions. This leads to the following definitions:
exception GenericError {
    string reason;
};

sequence<string> Lines;

interface File extends Node { 
    idempotent Lines read();
    idempotent void write (Lines text) throws GenericError;
}; 
Note that read and write are marked idempotent because either operation can safely be invoked with the same parameter value twice in a row: the net result of doing so is the same has having (successfully) called the operation only once.
The write operation can raise an exception of type GenericError. The exception contains a single reason data member, of type string. If a write operation fails for some reason (such as running out of file system space), the operation throws a GenericError exception, with an explanation of the cause of the failure provided in the reason data member.
Directories provide an operation to list their contents. Because directories can contain both directories and files, we take advantage of the polymorphism provided by the Node base interface:
sequence<Node*> NodeSeq; 

interface Directory extends Node { 
    idempotent NodeSeq list(); 
}; 
The NodeSeq sequence contains elements of type Node*. Because Node is a base interface of both Directory and File, the NodeSeq sequence can contain proxies of either type. (Obviously, the receiver of a NodeSeq must down-cast each element to either File or Directory in order to get at the operations provided by the derived interfaces; only the name operation in the Node base interface can be invoked directly, without doing a down-cast first. Note that, because the elements of NodeSeq are of type Node* (not Node), we are using pass-by-reference semantics: the values returned by the list operation are proxies that each point to a remote node on the server.
These definitions are sufficient to build a simple (but functional) file system. Obviously, there are still some unanswered questions, such as how a client obtains the proxy for the root directory. We will address these questions in the relevant implementation chapter.
Table of Contents Previous Next
Logo