Package ca.uwaterloo.fydp.db

Source Code of ca.uwaterloo.fydp.db.serverDB

/**
* This package houses the optional extra database server for the XCDE server.  The database
* server will capture all events sent through the server into a database to supply the server
* admin screen with historical data and the data to client replay views.  Replay views will
* not function without this database being populated with change history data.
*/
package ca.uwaterloo.fydp.db;

import ca.uwaterloo.fydp.ossp.OSSPStimulus;
import ca.uwaterloo.fydp.ossp.impl.OSSPSimpleSynchronizer;
import ca.uwaterloo.fydp.ossp.std.*;
import ca.uwaterloo.fydp.xcde.*;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Iterator;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;

/**
* The root class of the XCDE database server. The main method is run to start
* the server, register the XCDE client listener. Terminate the execution of
* this program to shutdown the server.
*/
public class serverDB implements XCDERootDirClientCallbacks, XCDEDocClientCallbacks, Runnable
  {
  private XCDEDirClient client;
  private XCDEDirClient root;
  private OSSPSimpleSynchronizer sync;
  private Connection conn;
  private long timeInterval;
  private InetAddress XCDEaddr;
  private int XCDEport;
  private String MySQLname;
  private int MySQLport;
  private String dbUsername;
  private String dbPassword;
 
  private static final String DEFAULT_XCDE_SERVER = "localhost";
  private static final String DEFAULT_MYSQL_SERVER = "localhost";
  private static final int DEFAULT_XCDE_SERVER_PORT = 48879;
  private static final int DEFAULT_MYSQL_SERVER_PORT = 3306;
  private static final String DEFAULT_DB_USERNAME = "serverDB";
  private static final String DEFAULT_DB_PASSWORD = "db1user";
  private static final long DEFAULT_TIME_INTERVAL = 3600000;
  /**
   * Initializes the database logger to listen for XCDE change events.
   *
   * The mysql JDBC driver is loaded and the server and database are connected
   * to. The JDBC connection assumes that an XCDE database has already been
   * created with the appropriate tables setup. There must also be a user that
   * can connect to and modify the database; this should not be root due to
   * the security and stability considerations of having an automated program
   * run as the database superuser.
   *
   * @author Andrew Craik
   * @param serverAddr The address of the XCDE server to connect to
   * @param serverPort The port to connect to the XCDE server on
   * @param DBServer The hostname of the MySQL server to connect to
   * @param DBport The port to connect to the MySQL server on
   * @param DBuser The username to use to connect to the MySQL server
   * @param DBpasswd The password to use to connect to the MySQL server
   * @param timeInterval The time interval between changes that are sent to replay client backend
   */
  public serverDB(InetAddress serverAddr, int serverPort, String DBServer, int DBport, String DBuser, String DBpasswd, long timeInterval)
    {
    this.MySQLname = DBServer;
    this.MySQLport = DBport;
    this.dbPassword = DBpasswd;
    this.dbUsername = DBuser;
    this.timeInterval = timeInterval;
    this.XCDEaddr = serverAddr;
    this.XCDEport = serverPort;
    // we need a synchronization object so that all our changes are atomic.
    // we will use the same sync object for all changes to ensure stability
    // and atomicity
    sync = new OSSPSimpleSynchronizer();

    // we have to load the com.mysql.jdbc.Driver class so that when we go to
    // make an SQL
    // connection we are able to find the specific driver that we need
    try
      {
      Class.forName("com.mysql.jdbc.Driver");
      }
    catch (ClassNotFoundException e)
      {
      throw new RuntimeException("Could not locate the com.mysql.jdbc.Driver class!", e);
      }

    // now we have the MySQL JDBC dirver loaded we need to connect up using
    // either the user
    // supplied or default values for the different parameters
    try
      {
      conn = DriverManager.getConnection("jdbc:mysql://" + MySQLname
          + ":" + MySQLport + "/xcde", dbUsername, dbPassword);
      conn.setAutoCommit(true);
      }
    catch (SQLException e)
      {
      throw new RuntimeException("Unable to connect to jdbc:mysql://"
          + MySQLname + ":" + MySQLport + "/xcde as user "
          + dbUsername, e);
      }

    // The SQL database is ready for use so now we startup the XCDE server
    // we also register ourselves to handle changes to the root directory
    // structure and
    // download the contents of the same to initiate the recurisve open and
    // registration
    // for all directories and files on the server
    client = XCDE.connectToServer(XCDEaddr, XCDEport, sync);
    root = client;
    client.setCallbacks(this);
   
    // We call pace() to let OSSP block us 'till an appropriate time to send.
    client.pace();
    synchronized(sync)
      {
      client.beginDownloadState();
      }
   
    if (timeInterval >= 0)
      {
      Thread contentUpdate = new Thread(this, "updates doc contents periodically");
      contentUpdate.start();
      }
    }

  /**
   * Run this method to start the server and register the XCDEClient
   *
   * @param args Command line arguments to override default connection values.
   */
  public static void main(String[] args)
    {
    // set default servernames for address lookup
    String XCDEHost = DEFAULT_XCDE_SERVER;

    // set defaults
    int XCDEport = DEFAULT_XCDE_SERVER_PORT;
    int MySQLport = DEFAULT_MYSQL_SERVER_PORT;
    String dbUsername = DEFAULT_DB_USERNAME;
    String dbPassword = DEFAULT_DB_PASSWORD;
    String MySQLname = DEFAULT_MYSQL_SERVER;
    long timeInterval = DEFAULT_TIME_INTERVAL;

    // We are going to construct the listeners we need
    // first we process the command line to see if there are any options
    // there
    // to change the default configuration
    for (int i = 0; i < args.length; i += 2)
      {
      if (args[i].equals("--XCDEHost"))
        XCDEHost = args[i + 1];
      else if (args[i].equals("--XCDEPort"))
        XCDEport = Integer.getInteger(args[i + 1]).intValue();
      else if (args[i].equals("--MySQLHost"))
        MySQLname = args[i + 1];
      else if (args[i].equals("--MySQLHostPort"))
        MySQLport = Integer.getInteger(args[i + 1]).intValue();
      else if (args[i].equals("--dbUsername"))
        dbUsername = args[i + 1];
      else if (args[i].equals("--dbPassword"))
        dbPassword = args[i + 1];
      else if (args[i].equals("--timeInterval"))
        timeInterval = Long.parseLong(args[i + 1]);
      else if (args[i].equals("-h") || args[i].equals("--help"))
        {
        System.out.println("Starts the XCDE database logging server.  Usage:\n");
        System.out.println("\t--XCDEHost\t-\tSpecify the hostname running the XCDE server to listen to");
        System.out.println("\t--XCDEHostPort\t-\tSpecify the port on which the XCDE server is listening");
        System.out.println("\t--MySQLHost\t-\tSpecify the hostname running the MySQL server to log to");
        System.out.println("\t--MySQLPort\t-\tSpecify the port the MySQL server is listening to");
        System.out.println("\t--dbUsername\t-\tSpecify the username to be used to connect to the MySQL database");
        System.out.println("\t--dbPassword\t-\tSpecify the password to be used to connect to the MySQL database");
        System.out.println("\t--timeInterval\t-\tSpecify the time interval in msec between file content downloads, negative to disable");
        System.out.println("\t-h or --help\t-\tPrint this help");
        return;
        }
      else
        throw new IllegalArgumentException("Unrecognized argument "
            + args[i] + ".  Use --help to print command options!");
      }
    InetAddress XCDEaddr;
    try
      {
      XCDEaddr = InetAddress.getByName(XCDEHost);
      }
    catch (UnknownHostException e)
      {
      throw new IllegalArgumentException("Could not find host " + XCDEHost, e);
      }

    // we create our object and will ensure that we keep the reference to
    // ourselves by
    // using the synchronization object feature of XCDEClient, ugly but
    // functional
    new serverDB(XCDEaddr, XCDEport, MySQLname, MySQLport, dbUsername, dbPassword, timeInterval);
    }

  /**
   * This handler processes the initial list of files and directories in a
   * directory. We have to process the directory contents and set ourselves as
   * the callback for all directory contents. We also need to get the initial
   * state of diretories so we can register to listen for changes to files and
   * directories it contains.
   *
   * @param state
   *            List of files and directories contained in the current
   *            directory on the server
   */
  public void receiveState(XCDEDirClient client, List state)
    {
    for (Iterator i = state.iterator(); i.hasNext();)
      {
      OSSPDirectoryListingElement item = (OSSPDirectoryListingElement) i.next();
      // if we have a subdir open it, register for as the callback listner
      // and download
      // the directory contents
      if (item.className.equals(OSSPDirectory.class.getName()))
        {
        if (!runExistanceSQLQuery(buildDirectoryExistsStatement(client.getPath(), item.name)))
          runSQLInsertOrUpdate(buildDirectoryInsertStatement(client.getPath(), item.name));
        final XCDEDirClient dir = client.opendir(item.name);
        dir.setCallbacks(this);
       
        // We already hold the lock, so we must use asyncExec() in order to get
        // pacing.
        dir.asyncExec(new Runnable()
              {
              public void run()
                {
                if (dir.isConnected())
                  dir.beginDownloadState();
                }
              });
        }
      // if we have a file we just want to register to listen to changes
      // to the file
      else if (item.className.equals(XCDEDocument.class.getName()))
        {
        if (!runExistanceSQLQuery(buildFileExistsStatement(client.getPath(), item.name)))
          runSQLInsertOrUpdate(buildFileCreateStatement(client.getPath(), item.name));
        final XCDEDocClient file = client.openfile(item.name);
        file.setCallback(this);
       
        // We already hold the lock, so we must use asyncExec() in order to get
        // pacing.
        file.asyncExec(new Runnable()
            {
            public void run()
              {
              if (file.isConnected())
                file.beginDownloadState();
              }
            });
        }
      else
        {
        // Ignore things in the server that aren't recognized
        // by XCDE.
        continue;
        }
      }
    }

  /**
   * The initial state receiver for files. This isn't going to be used by the
   * database server normally since we are capturing the deltas and not the
   * full contents of the file.
   *
   * @param state
   *            The text of the change
   */
  public void receiveState(XCDEDocClient client, XCDEDocument document)
    {
    String filename = client.getPath().substring(client.getPath().lastIndexOf("/")+1);
    String path = client.getPath().substring(0,client.getPath().lastIndexOf("/")+1);
    runSQLInsertOrUpdate(buildFileContentStatement(path, filename, document.content));
    }

  public void notifyOfDisconnect(XCDEDirClient client)
    {
    // QUESTION do I need to do anything here, I don't think so
    }

  public void notifyOfDisconnect(XCDEDocClient client)
    {
    // QUESTION do I need to do anything here, I don't think so
    }

  // this will be the one that gets the file object passed in so we will rough
  // out
  // the code for what to do to log these changes and we can test later
  /**
   * Receives file changes from the server, processes them, and stores them
   * into the database
   *
   * @param ch the change
   */
  public void notifyOfChange(XCDEDocClient client, OSSPStimulus ch)
    {
    String insert = null;
    String filename = client.getPath().substring(client.getPath().lastIndexOf("/")+1);
    String path = client.getPath().substring(0,client.getPath().lastIndexOf("/")+1);

    if (ch instanceof XCDEDocChangeInsertion)
      {
      if(!runExistanceSQLQuery(buildUserExistanceStatement(((XCDEDocChangeInsertion)ch).user)))
        runSQLInsertOrUpdate(buildUserCreationStatement(((XCDEDocChangeInsertion)ch).user));
      insert = buildFileChangeStatement(path, filename, 'I', ((XCDEDocChangeInsertion)ch).pos,
                        ((XCDEDocChangeInsertion)ch).text, ((XCDEDocChangeInsertion)ch).user);
      }
    else if (ch instanceof XCDEDocChangeDeletion)
      {
      if(!runExistanceSQLQuery(buildUserExistanceStatement(((XCDEDocChangeDeletion)ch).user)))
        runSQLInsertOrUpdate(buildUserCreationStatement(((XCDEDocChangeDeletion)ch).user));
      insert = buildFileChangeStatement(path, filename, 'D', ((XCDEDocChangeDeletion)ch).pos,
                                    Integer.toString(((XCDEDocChangeDeletion)ch).num), ((XCDEDocChangeDeletion)ch).user);
      }
    else if (ch instanceof OSSPCompoundStimulus)
      {
      notifyOfChange(client, ((OSSPCompoundStimulus) ch).getFirst());
      notifyOfChange(client, ((OSSPCompoundStimulus) ch).getSecond());
      return;
      }
    else if (ch instanceof XCDEDocumentAnnotationStimulusAdd)
      {
      //TODO: store annotation additions
      }
    else if (ch instanceof XCDEDocumentAnnotationStimulusChange)
      {
      //TODO: store annotation changes
      }
    else if (ch instanceof XCDEDocumentAnnotationStimulusDelete)
      {
      //TODO: store annotation deletes
      }
    else
      throw new RuntimeException("Unknown XCDEDocChange received: " + ch.getClass().getName());

    if (insert != null)
      {
      System.out.println("========FileChange=========");
      System.out.println(insert);
      System.out.flush();
      runSQLInsertOrUpdate(insert);
      }
    }

  /**
   * Receives directory changes from the server, processes them, and stores
   * them into the database
   *
   * @param ch the change
   */
  public void notifyOfChange(XCDEDirClient client, OSSPStimulus ch)
    {
    String path = client.getPath();
    // we have to declare the holders for the different SQL components
    // so we can safely unwind in the finally block incase we have an
    // exception during exceution
    String sql = null;
   
    if (ch instanceof OSSPDirectoryStimulusNotifyCreate)
      {
      OSSPDirectoryStimulusNotifyCreate newDir = (OSSPDirectoryStimulusNotifyCreate) ch;
      if (newDir.getCreatedClassName().equals(OSSPDirectory.class.getName()))
        {
        //New thing is a directory.
        final XCDEDirClient newDirClient = client.opendir(newDir.getAffectedElementName());
        newDirClient.setCallbacks(this);
       
        // We already hold the lock, so we must use asyncExec() in order to get
        // pacing.
        newDirClient.asyncExec(new Runnable()
              {
              public void run()
                {
                if (newDirClient.isConnected())
                  newDirClient.beginDownloadState();
                }
              });
       
        sql = buildDirectoryInsertStatement(path, newDir.getAffectedElementName());
        }
      else if (newDir.getCreatedClassName().equals(XCDEDocument.class.getName()))
        {
        //New thing is a document.
        final XCDEDocClient newFileClient = client.openfile(newDir.getAffectedElementName());
        newFileClient.setCallback(this);
       
        // We already hold the lock, so we must use asyncExec() in order to get
        // pacing.
        newFileClient.asyncExec(new Runnable()
              {
              public void run()
                {
                if (newFileClient.isConnected())
                  newFileClient.beginDownloadState();
                }
              });
       
        sql = buildFileCreateStatement(path, newDir.getAffectedElementName());
        }
      else
        {
        // Ignore things in the server that aren't recognized by
        // XCDE.
        return;
        }
      }
    else if (ch instanceof OSSPDirectoryStimulusDelete)
      {
      OSSPDirectoryStimulusDelete delDir = (OSSPDirectoryStimulusDelete) ch;
      // we do not have to specifically unregister as the callback will be
      // destroyed
      // when the client is freed.
      if (client.getOpenChild(delDir.name) instanceof XCDEDirClient)
        {
        sql = buildDirectoryDeleteStatement(path, delDir.name);
        }
      else if (client.getOpenChild(delDir.name) instanceof XCDEDocClient)
        {
        sql = buildFileDeleteStatement(path, delDir.name);
        }
      else
        throw new RuntimeException("Unknown client type!");
      }
    else if (ch instanceof OSSPCompoundStimulus)
      {
      notifyOfChange(client, ((OSSPCompoundStimulus) ch).getFirst());
      notifyOfChange(client, ((OSSPCompoundStimulus) ch).getSecond());
      return;
      }
    else if (ch instanceof XCDERootDirectoryUserStimulusAdd)
      {
      runSQLInsertOrUpdate(buildUserCreationStatement(((XCDERootDirectoryUserStimulusAdd)ch).state.userName));
      sql = buildUserEventStatement('A',((XCDERootDirectoryUserStimulusAdd)ch).state.userName);
      }
    else if (ch instanceof XCDERootDirectoryUserStimulusRemove)
      {
      runSQLInsertOrUpdate(buildUserEventStatement('R',((XCDERootDirectoryUserStimulusRemove)ch).userName));
      sql = buildUserRemovalStatement(((XCDERootDirectoryUserStimulusRemove)ch).userName);
      }
    else if (ch instanceof XCDERootDirectoryUserStimulusChange)
      {
      XCDERootDirectoryUserStimulusChange change = (XCDERootDirectoryUserStimulusChange)ch;
      if (!change.currUserName.equals(change.newState.userName))
        {
        runSQLInsertOrUpdate(buildUserEventStatement('R',change.currUserName));
        runSQLInsertOrUpdate(buildUserRemovalStatement(change.currUserName));
        runSQLInsertOrUpdate(buildUserCreationStatement(change.newState.userName));
        sql = buildUserEventStatement('A', change.newState.userName);
        }
      else
        return;
      }
    else
      throw new RuntimeException("UnknownXCDEDirChange received!");

    System.out.println("=======Directory Change=======");
    System.out.println(sql);
    System.out.flush();
   
    runSQLInsertOrUpdate(sql);
    }

  //---------------------------------Private internal functions start here-------------------------------
 
  /**
   * Creates a SQL statement to add a File to the XCDE database
   * @param path The fully qualified path name of the directory containing the file
   * @param filename The name of the file created
   * @return A string that is the SQL statement
   */
  private String buildFileCreateStatement(String path, String filename)
    {
    //TODO hardcoded user, not sure if we can ever get a user for this in all cases
    return "INSERT INTO Files VALUES (NULL, '" + filename
           + "', (SELECT dirID FROM Directories WHERE FullName = '" + path + "'), NULL, NULL, 1, NULL)";
    }
 
  private String buildFileContentStatement(String path, String filename, String contents)
    {
    contents = replaceStr(contents);
    return "INSERT INTO FileContents VALUES (NULL, " +
            "(SELECT fileID FROM Files INNER JOIN Directories ON Files.DirLoc = Directories.dirID WHERE Files.FileName = '" + filename + "' AND Directories.FullName = '" + path + "'" +
            " AND Files.DropDate IS NULL AND Directories.DropDate IS NULL), NULL, '" + contents + "')";
    }

  /**
   * Create a SQL update statement to mark a File in the XCDE database as deleted
   * @param path The fully qualified path name of the directory containing the file
   * @param filename The name of the file to mark as deleted
   * @return A string that is the SQL statement
   */
  private String buildFileDeleteStatement(String path, String filename)
    {
    //TODO hardcoded user, not sure if we can ever get a user for this in all cases
    return "UPDATE Files,Directories SET Files.DropDate = NOW(), Files.DropUserID = 1 WHERE Files.FileName = '" + filename +
               "' AND Directories.dirID = Files.DirLoc AND Files.DropDate IS NULL AND Directories.FullName = '" + path
               + "' AND Directories.DropDate IS NULL";
    }

  /**
   * Create a SQL query statement that will return a row if the specified file exists in
   * the database
   * @param path The fully qualified path name of the directory that could contain the file
   * @param filename The name of the file being queried for
   * @return A string that is the SQL statement
   */
  private String buildFileExistsStatement(String path, String filename)
    {
    return "SELECT * FROM Files WHERE Files.FileName = '" + filename + "' AND Files.DropDate IS NULL AND Files.DirLoc = " +
           "(SELECT dirID FROM Directories WHERE FullName = '" + path + "' AND DropDate IS NULL)";
    }
 
  private String replaceStr(String data)
    {
    data = data.replace("\\", "\\\\");
    return data.replace("'", "\\'");
    }
 
  /**
   * Create a SQL query to add a FileChange event to the XCDE database
   * @param path The fully qualified path name of the directory containing the modified file
   * @param filename  The name of file modified
   * @param type The type of change made (one of I for insert or D for deletion)
   * @param pos The integer character position of the change
   * @param data The data associated with the change
   * @param user The name of the user who effected the change
   * @return A string that is the SQL statement
   */
  private String buildFileChangeStatement(String path, String filename, char type, int pos, String data, String user)
    {
    data = replaceStr(data);
    return "INSERT INTO FileChanges VALUES(NULL, " +
        "(SELECT fileID FROM Files INNER JOIN Directories ON " +
         "Directories.dirID = Files.DirLoc WHERE Files.FileName = '" +
         filename + "' AND Files.DropDate IS NULL AND Directories.FullName = '"+ path + "' AND Directories.DropDate IS NULL)" +
         ", '" + type + "', " + pos + ", '" + data + "', NULL, (SELECT usersID FROM Users WHERE ShortName = '" + user + "'))";
    }
 
  /**
   * Create a SQL insert statement to add a directory to the XCDE database
   * @param path The fully qualified path of the parent directory
   * @param newDir The name of the new directory
   * @return A string that is the SQL statement
   */
  private String buildDirectoryInsertStatement(String path, String newDir)
    {
    //TODO hardcoded user, not sure if we can ever get a user for this in all cases
    return "INSERT INTO Directories VALUES(NULL, '" + path + newDir + "/" + "', NULL, NULL, 1, NULL)";
    }
 
  /**
   * Create a SQL update statement to mark a directory as deleted in the XCDE database
   * @param path The fully qualified name of the parent directory
   * @param dirname The name of the directory to delete
   * @return A string that is the SQL statement
   */
  private String buildDirectoryDeleteStatement(String path, String dirname)
    {
    //TODO hardcoded user, not sure if we can ever get a user for this in all cases
    return "UPDATE Directories SET DropDate = NOW(), DropUserID = 1 WHERE FullName = '" + path + dirname + "/' AND DropDate IS NULL";
    }
 
  /**
   * Create a SQL query to determine if a directory exists in the current XCDE database
   * @param path The fully qualified name of the parent directory
   * @param dirname The name of the directory being queried for
   * @return A string that is the SQL query
   */
  private String buildDirectoryExistsStatement(String path, String dirname)
    {
    return "SELECT * FROM Directories WHERE FullName = '" + path + dirname + "/' AND DropDate IS NULL";
    }

  /**
   * Create a SQL query to determine if a user exists in the current XCDE database
   * @param username The short username
   * @return A string that is the SQL query
   */
  private String buildUserExistanceStatement(String username)
    {
    return "SELECT * FROM Users WHERE ShortName = '" + username + "' AND DropDate IS NULL";
    }
 
  /**
   * Create a SQL insert statement to add a user to the XCDE database
   * @param username The short username of the new user
   * @return A string that is the SQL insert statement
   */
  private String buildUserCreationStatement(String username)
    {
    return "INSERT INTO Users VALUES(NULL, '" + username + "', '" + username + "', '" + username + "', NULL, NULL)";
    }
 
  /**
   * Create a SQL update statement to mark a user as dropped from the XCDE database
   * @param username The short username of the user to drop
   * @return A string that is the SQL update statement
   */
  private String buildUserRemovalStatement(String username)
    {
    return "UPDATE Users SET Users.DropDate = Now() WHERE Users.shortname = '" + username + "' AND Users.DropDate IS NULL";
    }
 
  /**
   * Create a SQL statement to add a user even to the XCDE database
   * @param eventType Character for the event type
   * @param username The short username of the user associated with the event
   * @return The SQL string that is the insert statement
   */
  private String buildUserEventStatement(char eventType, String username)
    {
    return "INSERT INTO UserEvents VALUES(NULL, '" + eventType + "', NULL, (SELECT usersID FROM Users WHERE ShortName = '" + username + "' AND DropDate IS NULL), '')";
    }
 
  /**
   * Runs the SQL update or insert statement passed
   * @param sql The update or insert statement to be run
   */
  private void runSQLInsertOrUpdate(String sql)
    {
    Statement stmt = null;
    try
      {
      stmt = conn.createStatement();
      stmt.executeUpdate(sql);
      if (stmt.getUpdateCount() == 0)
        throw new RuntimeException("No rows affected by update " + sql);
      stmt.close();
      }
    catch (SQLException e)
      {
      throw new RuntimeException("SQLException thrown when trying to run " + sql, e);
      }
    finally
      {
      try
        {
        if (stmt != null)
          stmt.close();
        }
      catch (SQLException e)
        {
        // ignore failure since we are in finally and something else
        // has already
        // happened and we were just trying to do the right thing
        }
      }
    }
 
  /**
   * Runs the SQL query provided and returns true if 1 or more rows are returned, or false otherwise
   * @param query The SQL query to run
   * @return true if 1 or more rows are returned when the query is run, false otherwise
   */
  private boolean runExistanceSQLQuery(String query)
    {
    boolean toReturn = false;
    try
      {
      Statement check = conn.createStatement();
      ResultSet rs = check.executeQuery(query);
      rs.last();
      if (rs.getRow() > 0)
        toReturn = true;
      rs.close();
      check.close();
      }
    catch (SQLException e)
      {
      throw new RuntimeException("Error running query " + query, e);
      }
    return toReturn;
    }

  /**
   * The main method run by the file content capture thread, sleeps between complete
   * file content downloads.
   */
  public void run()
    {
    while (true)
      {
      try
        {
        Thread.sleep(timeInterval);
        }
      catch (InterruptedException e)
        {
        System.err.println(e);
        }
      System.out.println("########WAKEUP#########");
      synchronized (sync)
        {
        processDirectory(root);
        }
      }
    }
 
  /**
   * Used by the file content download thread to process directories recursively and
   * trigger download the document contents
   * @param dir The directory client whose children we want to process
   */
  private void processDirectory(XCDEDirClient dir)
    {
      Iterator i = dir.getOpenChildren();
      while (i.hasNext())
        {
        final Object child = i.next();
        if (child instanceof XCDEDirClient)
          {
          System.out.println("Found Dir " + ((XCDEDirClient)child).getPath());
          processDirectory((XCDEDirClient)child);
          }
        else if (child instanceof XCDEDocClient)
          {
          System.out.println("Found File " + ((XCDEDocClient)child).getPath());
          // We already hold the lock, so we must use asyncExec() in order to get
          // pacing.
          ((XCDEDocClient)child).asyncExec(new Runnable()
                {
                public void run()
                  {
                  if (((XCDEDocClient)child).isConnected())
                    ((XCDEDocClient)child).beginDownloadState();
                  }
                });
          }
        else
          throw new RuntimeException("Unexpected class type in directory processing " + child.getClass().getName());
        }
    }

  public void receiveUsers(XCDEDirClient client, List users)
    {
    for (Iterator i = users.iterator(); i.hasNext(); )
      {
      XCDERootDirectoryUserState state = (XCDERootDirectoryUserState)i.next();
      if(runExistanceSQLQuery(buildUserExistanceStatement(state.userName)))
        {
        continue;
        }
      else
        {
        runSQLInsertOrUpdate(buildUserCreationStatement(state.userName));
        runSQLInsertOrUpdate(buildUserEventStatement('A',state.userName));
        }
      }
   
    }
  }
TOP

Related Classes of ca.uwaterloo.fydp.db.serverDB

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.