How to transfer files more easily

With SIMON 1.2.0, it's now easier than before to transfer files from server to client and vice versa.

In the following example I will show you how to transfer a file from client to server.

Shared Code

First, we need the server's interface:

package de.root1.simon.samples.filetransfer.shared;

import de.root1.simon.filetransmit.FileReceiver;

public interface FileTransferServer {

    public static String BIND_NAME = "FileTransferServer";
    public FileReceiver getFileReceiver();

}

As you can see. The server will provide a method to get an instance of FileReceiver. This is the pre-implemented interface to receive files.

Server Code

package de.root1.simon.samples.filetransfer.server;

import de.root1.simon.filetransmit.DefaultFileReceiver;
import de.root1.simon.Registry;
import de.root1.simon.Simon;
import de.root1.simon.annotation.SimonRemote;
import de.root1.simon.exceptions.NameBindingException;
import de.root1.simon.filetransmit.FileReceiverProgressListener;
import de.root1.simon.samples.filetransfer.shared.FileTransferServer;
import java.io.File;
import java.io.IOException;
import java.net.UnknownHostException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@SimonRemote(value = {FileTransferServer.class})
public class FileTransferServerImpl implements FileTransferServer {

    private final static Logger logger = LoggerFactory.getLogger(FileTransferServerImpl.class);

    DefaultFileReceiver ft;

    public FileTransferServerImpl() {

        ft = new DefaultFileReceiver();
        ft.setDownloadFolder(new File("/home/achristian/Downloads"));

        // optional step, can be skipped if you don't want to track the progress
        ft.addProgressListener(new FileReceiverProgressListener() {

            @Override
            public void started(File f, long length) {
                logger.info("Started receive file: {} size: {}", f, length);
            }

            @Override
            public void inProgress(File f, long bytesReceived, long length) {
                logger.info("In progress receive file: {} received: {}/{}", new Object[]{f, bytesReceived, length});
            }

            @Override
            public void completed(File f) {
                logger.info("Completed receive file: {}", f);
            }

            @Override
            public void aborted(File f, Exception ex) {
                logger.info("Aborted receive file {}: {}", f, ex);
            }
        });
    }

    @Override
    public DefaultFileReceiver getFileReceiver() {
        return ft;
    }

    public static void main(String[] args) throws UnknownHostException, IOException, NameBindingException {
        Registry registry = Simon.createRegistry();
        registry.start();
        registry.bind(FileTransferServer.BIND_NAME, new FileTransferServerImpl());
        System.out.println("Server running");

//        registry.stop();
    } 
}

In this small scenario, the server only provides the FileReceiver via the default implementation DefaultFileReceiver. All you need top do is to provide a folder where the received files are stored. If you wanto to track the download progress, you can specify a progress listener like in this example. But remember to clean up any listener that is no longer used. In this example we just skipped this step to keep it simple.

So, all you need to implement is, if you whish, the progress listener. All the rest comes pre-implemented.

Client Code

Now to the client part. Here's the same as with the server: Quite easy and very less to implement. The biggest part is again the listener, which is of course optional.

package de.root1.simon.samples.filetransfer.client;

import de.root1.simon.filetransmit.DefaultFileSender;
import de.root1.simon.filetransmit.FileReceiver;
import de.root1.simon.Lookup;
import de.root1.simon.Simon;
import de.root1.simon.exceptions.EstablishConnectionFailed;
import de.root1.simon.exceptions.LookupFailedException;
import de.root1.simon.filetransmit.FileSenderProgressListener;
import de.root1.simon.samples.filetransfer.shared.FileTransferServer;
import java.io.File;
import java.net.UnknownHostException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FileTransferClient {

    private final static Logger logger = LoggerFactory.getLogger(FileTransferClient.class);

    public static void main(String[] args) throws UnknownHostException, LookupFailedException, EstablishConnectionFailed {
        Lookup nameLookup = Simon.createNameLookup("localhost");
        FileTransferServer server = (FileTransferServer) nameLookup.lookup(FileTransferServer.BIND_NAME);
        System.out.println("Connected");
        FileReceiver fileReceiver = server.getFileReceiver();

        // connect file sender with file receiver
        DefaultFileSender fs = new DefaultFileSender(fileReceiver);

        // optional step, can be skipped if you don't want to track the progress
        fs.addProgressListener(new FileSenderProgressListener() {

            @Override
            public void started(int id, File f, long length) {
                logger.info("Started file transfer: {}@{} size: {}", new Object[]{id, f.getName(), length});
            }

            @Override
            public void inProgress(int id, File f, long bytesSent, long length) {
                logger.info("In Progress {}@{} {}/{}", new Object[]{id, f.getName(), bytesSent, length});
            }

            @Override
            public void completed(int id, File f) {
                logger.info("Completed file transfer: {}@{}", new Object[]{id, f.getName()});
            }

            @Override
            public void aborted(int id, File f, Exception ex) {
                logger.info("Aborted file transfer: {}@{}: {}", new Object[]{id, f.getName(), ex});
            }

        });

        System.out.println("Prepared sender. Sending ...");
        fs.sendFile(new File("/home/achristian/Arbeitsfläche/xyz.dat"), true);
        System.out.println("done");

        // dont't forget to close, otherwise the send-thread will continue idle'ing around
        fs.close();

    }

}

All you need to do on client side:

  • connect to server
  • get file receiver instance from server
  • Create file sender instance and connect it to file receiver
  • Send files with just one further line of code
  • Close file sender when you're done

Please have a look at the javadoc for DefaultFileSender and DefaultFileReceiver to get more information and fine tune settings.

Of course this does not only work from client to server. To transfer files from server to client, just let the client provide the server a callback which provides a get-methode for a client-side instance of DefaultFileReceiver. That's all.

If you want to be more flexible on how files are sent, please read about the RawChannel HowTo.