Custom files: Introduction

In the first section of this tutorial, we created a very simple Styx system which exposed a single file, an InMemoryFile that simply represented a section of RAM. Similarly, the FileOnDisk class is used to create a Styx file that represents a literal file on the local filesystem. The key to creating powerful distributed systems using Styx is to design and construct new types of virtual files that exhibit the correct behaviour.

In this section of the tutorial, you will learn how to create customized virtual files. In essence, this simply involves creating a subclass of the StyxFile class and overriding key methods such as read() and write().

Custom file 1: WhoAmI

For our first example, let's create a file that, when read, will return the IP address and port number of the client that is making the connection. This file will therefore return data that is different for each client that is connected. This will be a read-only file. We'll call this class "WhoAmIFile". (See the full source code of the WhoAmIFile class, including full comments, here.)

As always, we need to subclass the StyxFile class:

    public class WhoAmIFile extends StyxFile
    
Note that the StyxFile class is not abstract: it provides methods to give (not very useful) default behaviour. Now we need to create a constructor:
    public WhoAmIFile() throws StyxException
    {
        super("whoami");
        this.setPermissions(0444);
    }
    
The call to the superclass constructor sets the name of the file. Note that the superclass constructor throws a StyxException if the file name is illegal. We know that this is not the case here, but we will simply re-throw the exception anyway. Then we set the permissions of the file: we will not allow writing to this file, so we give it read permissions only (0444, i.e. r--r--r--).

Now we must override the read() method so that the IP address and port are returned to the client. This is very easily done:

    public void read(StyxFileClient client, long offset, int count, int tag)
        throws StyxException
    {
        String clientAddr = client.getSession().getRemoteAddress().toString();
        this.processAndReplyRead(clientAddr, client, offset, count, tag);
    }
    
In the first line of this method we get the client's IP address and port as a String. Then we call processAndReplyRead() to return the data to the client.

Replying to the client

In the above example, we used the processAndReplyRead() helper method to process the read request and return the data to the client. This is a very useful method that is used when the entire contents of a file can be represented as a String, byte array or ByteBuffer. If the file cannot be represented in this way we have to work a little harder, as we shall see in the example below. In this case, we have to work out exactly what data we need to give to the client (based on the client's read request and the contents of the whole file) and call one of the replyRead() methods.

A read/write file

The above example implemented a read-only file...