SmartSync - Network Enabled File Synchronizer

Tutorial

This tutorial is a quick introduction to SmartSync. It includes useful examples to learn the basic concepts of the architecture. To run the examples, you need a Java 2 runtime environment (see java.sun.com), a Servlet container like Tomcat and at least the evaluation version of SmartSync. The full source code of all examples and its compiled versions are also available in that package. So, don't hesitate to get a free copy of it!
At the end of this tutorial, you are able to deploy, run and configure SmartSync. Please refer to the API documentation and to the protocol definition for further reading.
Well, before you start, have a quick look at the overview document. It gives you an idea of SmartSyncs functionality.

Content

Package Structure
Document Roots
Operation Modes
Server Deployment
Client Integration
Progress Monitoring

Package Structure

li.netcat.smartsync This is the only package used by SmartSync. It has to be deployed on the client as well as on the server.

Document Roots

There are actually three document roots (directories) involved in the synchronization process. They are named as follows:

Operation Modes

Depending on the configuration, the client has three different modes of operation:

Make sure, that the application has sufficient rights to read and write files in these directories. Furthermore, the client and the server implementations try to create a checksum-file called chksum.crc in the document roots for performance reasons. Also not necessary, you may delete this file whenever you want, but you may not modify it. This can lead to an inconsistent state.

Server Deployment

The server part of SmartSync is the SmartSyncServer servlet that has to be deployed into a servlet container. Here is an example of a deployment descriptor (web.xml):

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE web-app
   PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
   "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
  <display-name>SmartSync</display-name> 
  <description>Servlet for directory snchronization.</description> 
  <servlet>
    <servlet-name>SmartSyncServer</servlet-name> 
    <description>This is the SmartSync servlet</description> 
    <servlet-class>li.netcat.smartsync.SmartSyncServer</servlet-class>
    <init-param>
      <param-name>reference-directory</param-name> 
      <param-value>c:\temp\server</param-value> 
    </init-param>
    <load-on-startup>5</load-on-startup> 
  </servlet>
  <servlet-mapping>
    <servlet-name>SmartSyncServer</servlet-name> 
    <url-pattern>/SmartSyncServer</url-pattern>
  </servlet-mapping>
</web-app>

Notice the initial parameter reference-directory, it has to be configured to point to the reference directory. Make also sure that the servlet container has access to the SmartSync package.

Client Integration

Supposed that the SmartSyncServer has been deployed on the local host on port 8080 and home directory smartsync, the following client code will synchronize the given directory:

public static void main(String[] args) {
  try {
    SmartSyncClient client = new SmartSyncClient();
    client.synchronize(
         new URL("http://localhost:8080/smartsync/SmartSyncServer"),
         new File("c:\\temp\\client"));
  }
  catch (IOException x) {
    x.printStackTrace();
  }
}

The synchronize method returns true or false if an update was available or not.

Progress Monitoring

Interactive clients give the user a view into the progress of the operation and the possibility to abort the operation. Since the look of a progress monitor must be individual to each application, no progress monitor is included in the SmartSync package.
Nevertheless, the following sections describes, how to build and integrate a custom progress monitor.

screenshot.gif (21890 Byte)

An implementation of the interface EventMonitor can be added to the SmartSyncClient with the following command:

client.addEventMonitor(new SmartSyncMonitor());

Here comes the code of the custom event monitor:

public class SmartSyncMonitor extends DialogPanel implements EventMonitor {
  private JFrame     _frame;
  private InfoPanel  _infoPanel;
  private TaskPanel  _taskPanel;
  private JButton    _cancelButton;
  private JButton    _exitButton;
  private boolean    _abort = false;
  
  public SmartSyncMonitor() {
    _infoPanel = new InfoPanel();
    _taskPanel = new TaskPanel();

    JPanel content = new JPanel(new BorderLayout(5, 5));
    content.add(_infoPanel, BorderLayout.NORTH);
    content.add(_taskPanel, BorderLayout.CENTER);
    setContent(content);
    addButton(_cancelButton = new JButton("Cancel"));
    _cancelButton.setEnabled(false);
    _cancelButton.addActionListener(new CancelListener());
    addButton(_exitButton = new JButton("Exit"));
    _exitButton.addActionListener(new ExitListener());
  }
  
  public JFrame open() {
    _frame = new JFrame("SmartSync Monitor");
    _frame.setContentPane(this);
    _frame.pack();
    Rectangle bounds = _frame.getGraphicsConfiguration().getBounds();
    _frame.setLocation(bounds.x + (bounds.width -  _frame.getWidth())/2, bounds.y + (bounds.height -  _frame.getHeight())/3);
    _frame.setVisible(true);
    _frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // due to bug 4030718 (http://developer.java.sun.com/developer/bugParade/bugs/4030718.html)
    _frame.toFront();
    return _frame;
  }
  
  //// interface EventMonitor
  
  public void onStart(URL remoteDirectory, File localDirectory) {
    _infoPanel.setTexts(remoteDirectory.toString(), localDirectory.toString());
    _taskPanel.setText("Checking for updates...");
    open();
  }
  
  public void onTaskAnnounce(Task task) {
    _taskPanel.addTask(task);
  }

  public void onTaskStart(Task task) {
    _cancelButton.setEnabled(true);
    _taskPanel.setCurrentTask(task);
  }
  
  public void onProgress(TransferProgress progress) {
    _taskPanel.setTransferProgress(progress);
  }
  
  public void onTaskCompletion(Task task) {
    _taskPanel.setTaskCompleted(task);
  }
  
  public void onSuccess(boolean updateDone) {
    _cancelButton.setEnabled(false);
    if (updateDone) {
      JOptionPane.showMessageDialog(this, "The directory structure has been updated successfully", "Information", JOptionPane.INFORMATION_MESSAGE);
    }
    else {
      _taskPanel.setText("No update available.");
    }
  }
  
  public void onIOException(IOException iox, Task task) {
    _cancelButton.setEnabled(false);
    if (task != null) {
      _taskPanel.setTaskFailed(task);
    }
    JOptionPane.showMessageDialog(this, iox.getMessage(), "Warning", JOptionPane.WARNING_MESSAGE);
  }
  
  public void onAbortCheck() throws UserAbortIOException {
    if (_abort) {
      throw new UserAbortIOException();
    }
  }
  
  //// inner classes
  
  
  private class CancelListener implements ActionListener {
    
    public void actionPerformed(ActionEvent event) {
      _abort = true;
      _cancelButton.setEnabled(false);
    }
  }
  
  private class ExitListener implements ActionListener {
    
    public void actionPerformed(ActionEvent event) {
      System.exit(0);
    }
  }
}

Beside the details of the layout, the main aspect is the implementation of the interface EventMonitor. An other object worth mentioning is the TransferProgress that includes all data needed to display the progress bar with some statistic information:

  ...
  private JLabel       _transferRate;
  private JLabel       _completedFiles;
  private JLabel       _completedTraffic;
  private JLabel       _remainTime;
  private JLabel       _remainFiles;
  private JLabel       _remainTraffic;
  private JProgressBar _progressBar;
  ...

  public void setTransferProgress(TransferProgress progress) {
    _transferRate.setText(formatTransferRate(progress.getTransferRate()));
    _completedFiles.setText(formatNrOfFiles(progress.getCompletedFiles()));
    _completedTraffic.setText(formatTraffic(progress.getCompletedTraffic()));
    _remainTime.setText(formatRemainingTime(progress.getRemainingTime()));
    _remainFiles.setText(formatNrOfFiles(progress.getRemainingFiles()));
    _remainTraffic.setText(formatTraffic(progress.getRemainingTraffic()));
    _progressBar.setValue((int)(progress.getProgress() * 100));
  }
  ...

Please refer to the complete sources in the example package for more details.

Links


Copyright © 2003 NetCat AG. All rights reserved.

keywords:java, net, servlet, synchronize, file, files, synchronize data, synchronize directory, synchronize files, synchronize files over HTTP, synchronize tree, file synchronizer, directory synchronizer, directory, directory structure, network, download, package, equalize, equalize, server, synchronise, file, files, synchronise data, synchronise directory, synchronise files, synchronise files over HTTP, synchronise tree, file synchroniser, file synchronisation, directory synchroniser, directory synchronisation, java, net, servlet, synchronize, file, files, synchronize data, synchronize directory, synchronize files, synchronize files over HTTP, synchronize tree, file synchronizer, directory synchronizer, directory, directory structure, network, download, package, equalize, equalize, server, synchronise, file, files, synchronise data, synchronise directory, synchronise files, synchronise files over HTTP, synchronise tree, file synchroniser, file synchronisation, directory synchroniser, directory synchronisation, java, net, servlet, synchronize, file, files, synchronize data, synchronize directory, synchronize files, synchronize files over HTTP, synchronize tree, file synchronizer, directory synchronizer, directory, directory structure, network, download, package, equalize, equalize, server, synchronise, file, files, synchronise data, synchronise directory, synchronise files, synchronise files over HTTP, synchronise tree, file synchroniser, file synchronisation, directory synchroniser, directory synchronisation