Index: src/edu/ucsb/nceas/metacat/DocumentImpl.java
===================================================================
--- src/edu/ucsb/nceas/metacat/DocumentImpl.java	(revision 1054)
+++ src/edu/ucsb/nceas/metacat/DocumentImpl.java	(revision 1055)
@@ -240,7 +240,7 @@
    * Register a document that resides on the filesystem with the database.
    * (ie, just an entry in xml_documents, nothing in xml_nodes).
    * Creates a reference to a filesystem document (used for non-xml data files).
-   *
+   * This class only be called in MetaCatServerlet.
    * @param conn the JDBC Connection to which all information is written
    * @param docname - the name of DTD, i.e. the name immediately following 
    *        the DOCTYPE keyword ( should be the root element name ) or
@@ -328,9 +328,106 @@
     }    
   }
   
+    /**
+   * Register a document that resides on the filesystem with the database.
+   * (ie, just an entry in xml_documents, nothing in xml_nodes).
+   * Creates a reference to a filesystem document (used for non-xml data files)
+   * This method will be called for register data file in xml_documents in 
+   * Replication.
+   * This method is revised from registerDocument.
+   *
+   * @param conn the JDBC Connection to which all information is written
+   * @param docname - the name of DTD, i.e. the name immediately following 
+   *        the DOCTYPE keyword ( should be the root element name ) or
+   *        the root element name if no DOCTYPE declaration provided
+   *        (Oracle's and IBM parsers are not aware if it is not the 
+   *        root element name)
+   * @param doctype - Public ID of the DTD, i.e. the name immediately 
+   *                  following the PUBLIC keyword in DOCTYPE declaration or
+   *                  the docname if no Public ID provided or
+   *                  null if no DOCTYPE declaration provided
+   * @param accnum the accession number to use for the INSERT OR UPDATE, which 
+   *               includes a revision number for this revision of the document 
+   *               (e.g., knb.1.1)
+   * @param user the user that owns the document
+   * @param serverCode the serverid from xml_replication on which this document
+   *        resides.
+   */
+  public static void registerDocumentInReplication(
+                     String docname, String doctype, String accnum, 
+                     String user, int serverCode)
+                     throws SQLException, AccessionNumberException, Exception
+  {
+    Connection dbconn = null;
+    MetaCatUtil util = new MetaCatUtil();
+    AccessionNumber ac;
+    try {
+      dbconn = util.openDBConnection();
+      String docIdWithoutRev=MetaCatUtil.getDocIdFromString(accnum);
+      int userSpecifyRev=MetaCatUtil.getVersionFromString(accnum);
+      int revInDataBase=getLatestRevisionNumber(dbconn, docIdWithoutRev);
+      //revIndataBase=-1, there is no record in xml_documents table
+      //the data file is a new one, inert it into table
+      //user specified rev should be great than 0
+      if (revInDataBase==-1 && userSpecifyRev>0 )
+      {
+        //ture means for replication
+        ac = new AccessionNumber(dbconn, accnum, "insert");
+      }
+      //rev is greater the last revsion number and revInDataBase isn't -1
+      // it is a updated data file
+      else if (userSpecifyRev>revInDataBase && revInDataBase>0)
+      {
+        
+        //archive the old entry 
+        archiveDocRevision(dbconn, docIdWithoutRev, user);
+        //delete the old entry in xml_documents
+        deleteXMLDocuments(dbconn, docIdWithoutRev);
+        ac = new AccessionNumber(dbconn, accnum, "update");
+      }
+      //other situation
+      else
+      {
+        
+        throw new Exception("Revision number couldn't be "
+                    +userSpecifyRev);
+      }
+      String docid = ac.getDocid();
+      String rev = ac.getRev();
+      SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss");
+      Date localtime = new Date();
+      String dateString = formatter.format(localtime);
+  
+      String sqlDateString = "to_date('" + dateString + 
+                                          "', 'YY-MM-DD HH24:MI:SS')";
+  
+      StringBuffer sql = new StringBuffer();
+      sql.append("insert into xml_documents (docid, docname, doctype, ");
+      sql.append("user_owner, user_updated, server_location, rev,date_created");
+      sql.append(", date_updated, public_access) values ('");
+      sql.append(docid).append("','");
+      sql.append(docname).append("','");
+      sql.append(doctype).append("','");
+      sql.append(user).append("','");
+      sql.append(user).append("','");
+      sql.append(serverCode).append("','");
+      sql.append(rev).append("',");
+      sql.append(sqlDateString).append(",");
+      sql.append(sqlDateString).append(",");
+      sql.append("'0')");
+      PreparedStatement pstmt = dbconn.prepareStatement(sql.toString());
+      pstmt.execute();
+      pstmt.close();
+      dbconn.close();
+    } finally {
+      util.returnConnection(dbconn);
+    }    
+  }
+  
  /**
    * This method will register a data file entry in xml_documents and save a
-   * data file input Stream into file system..
+   * data file input Stream into file system.. It is only used in force 
+   * replication
    *
    * @param  input, the input stream which contain the file content.
    * @param  , the input stream which contain the file content
@@ -360,7 +457,7 @@
     if (getDataFileLockGrant(accnum))
     {
       //register data file into xml_documents table
-      registerDocument(docname, doctype, accnum, user, serverCode);
+      registerDocumentInReplication(docname, doctype, accnum, user, serverCode);
       //write inputstream into file system.
       File dataDirectory = new File(filePath);
       File newFile = new File(dataDirectory, accnum); 
@@ -384,12 +481,12 @@
 	    outPut.close();
 	    fos.close();
       //force replication to other server
+      /*during replciation, don't need force replication again.
       MetaCatUtil util = new MetaCatUtil();
       if ((util.getOption("replicationdata")).equals("on"))
       {
         Connection dbConn = util.getConnection();
-        //this is local server, force replication to every server in its server
-        //list
+       
         if (serverCode==1)
         {
           
@@ -396,10 +493,10 @@
           ForceReplicationHandler frh = new ForceReplicationHandler(accnum,
                   "insert",false,ReplicationHandler.buildServerList(dbConn));
           util.returnConnection(dbConn);
-        }//if
+        }
         else
         {
-          //if it is super hub, replication to server list
+          
           if ((util.getOption("hub")).equals("super"))
           {
             ForceReplicationHandler frh = new ForceReplicationHandler(accnum, 
@@ -408,56 +505,17 @@
           }
           else
           {
-            //only replicate to home host of the document
+            
             String docId=util.getDocIdFromString(accnum);
             ForceReplicationHandler frh = new ForceReplicationHandler(accnum, 
                 true, ReplicationHandler.getHomeServer(docId));
           }
         }
-      }//if
+      }*/
     }//if
  }
   
- /**
-   * unRegister a an XML file (data file) from the database (actually, 
-   * just make it a revision in the xml_revisions table and delete it
-   * from xml_documents table). 
-   *
-   * @param docid the ID of the document to be deleted from the database
-   */
-  public static void unRegisterDocument( Connection conn, String accnum,
-                                 String user, String[] groups )
-                throws Exception 
-  {
-    
 
-    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
-    AccessionNumber ac = new AccessionNumber(conn, accnum, "DELETE");
-    String docid = ac.getDocid();
-    String rev = ac.getRev();
-    
-
-    // check for 'write' permission for 'user' to delete this document
-    if ( !hasPermission(conn, user, groups, docid) ) {
-      throw new Exception("User " + user + 
-              " does not have permission to delete XML Document #" + accnum);
-    }
-
-    conn.setAutoCommit(false);
-    // Copy the record to the xml_revisions table
-    DocumentImpl.archiveDocRevision( conn, docid, user );
-
-    // Now delete it from the xml_documents table
-    
-    Statement stmt = conn.createStatement();
-    //stmt.execute("DELETE FROM xml_access WHERE docid = '" + docid + "'");
-    stmt.execute("DELETE FROM xml_documents WHERE docid = '" + docid + "'");
-    stmt.close();
-    conn.commit();
-    conn.setAutoCommit(true);
-   
-    
-  }
   
   public static boolean getDataFileLockGrant(String accnum) 
                                                   throws Exception
@@ -617,6 +675,91 @@
     return serverlocation;
   }
   
+  public String getHomeServer(String docId)
+  {
+    String homeServer=null;
+    Connection conn = null;
+    MetaCatUtil ut=new MetaCatUtil();
+    docId=ut.getDocIdFromString(docId);
+    ut.debugMessage("docId: "+docId, 50);
+    PreparedStatement pstmt=null;
+    //PreparedStatement getServerStatement=null;
+    int serverLocation;
+    try
+    {
+      conn=ut.getConnection();
+      //get a server location from xml_document table
+      pstmt = conn.prepareStatement("select server_location from "
+                                +"xml_documents where docid = ?");
+      pstmt.setString(1, docId);
+      pstmt.execute();
+      ResultSet serverName = pstmt.getResultSet();
+      //get a server location
+      if(serverName.next())
+      {
+        serverLocation=serverName.getInt(1);
+        ut.debugMessage("serverLocation: "+serverLocation, 50);
+        pstmt.close();
+      }
+      else
+      {
+        pstmt.close();
+        ut.returnConnection(conn);
+        return homeServer;
+      }
+      pstmt = conn.prepareStatement("select server " +
+                        "from xml_replication where serverid = ?");
+                        
+      
+      pstmt.setInt(1, serverLocation);
+      pstmt.execute();
+      ResultSet rs = pstmt.getResultSet();
+      boolean tableHasRows = rs.next();
+      if (tableHasRows)
+      {
+        
+          String server = rs.getString(1);
+          //get homeserver name
+          if(!server.equals("localhost"))
+          {
+            homeServer=server;
+          }
+          else
+          {
+            homeServer=ut.getLocalReplicationServerName();
+          }
+          ut.debugMessage("server: "+homeServer, 50);
+        
+      }
+      else
+      {
+        pstmt.close();
+        ut.returnConnection(conn);
+        return homeServer;
+      }
+      pstmt.close();
+    }
+    catch(Exception e)
+    {
+      System.out.println("error in DocumentIpml.getHomerserver(): " +
+                         e.getMessage());
+    }
+    finally
+    {
+      try
+      {
+        pstmt.close();
+        ut.returnConnection(conn);
+      }
+      catch (Exception ee)
+      {
+      }
+      
+    }
+   
+    return homeServer;
+  }
+ 
   public String getPublicaccess() {
     return publicaccess;
   }
@@ -1270,7 +1413,7 @@
     String docid = ac.getDocid();
     String rev = ac.getRev();
     MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
-                             serverCode + " override: " + override);
+                             serverCode + " override: " + override, 10);
                         
     if((serverCode != 1 && action.equals("UPDATE")) && !override)
     { //if this document being written is not a resident of this server then
@@ -1396,6 +1539,140 @@
   }
 
   /**
+   * Write an XML file to the database during replication
+   *
+   * @param conn the JDBC connection to the database
+   * @param xml the xml stream to be loaded into the database
+   * @param pub flag for public "read" access on xml document
+   * @param dtd the dtd to be uploaded on server's file system
+   * @param action the action to be performed (INSERT or UPDATE)
+   * @param accnum the docid + rev# to use on INSERT or UPDATE
+   * @param user the user that owns the document
+   * @param groups the groups to which user belongs
+   * @param homeServer the name of server which the document origanlly create
+   * @param validate, if the xml document is valid or not
+   */
+
+  public static String writeReplication( Connection conn,Reader xml,String pub,
+                Reader dtd, String action, String accnum, String user,
+                            String[] groups,String homeServer, boolean validate)
+                throws Exception
+  {
+    // NEW - WHEN CLIENT ALWAYS PROVIDE ACCESSION NUMBER INCLUDING REV IN IT
+    MetaCatUtil util = new MetaCatUtil();
+    AccessionNumber ac = new AccessionNumber(conn, accnum, action);
+    String docid = ac.getDocid();
+    String rev = ac.getRev();
+    int serverCode=-2;
+    //get server code for the home server
+    serverCode=getServerCode(homeServer);
+    //if the server is not in the xml replication table, insert it.
+    if (serverCode==-1)
+    {
+      insertServerIntoReplicationTable(homeServer);
+      //get server code again
+      serverCode=getServerCode(homeServer);
+    }
+      
+    MetaCatUtil.debugMessage("action: " + action + " servercode: " + 
+                             serverCode, 10);
+                        
+    if((serverCode != 1 && action.equals("UPDATE")) )
+    { //if this document being written is not a resident of this server then
+      //we need to try to get a lock from it's resident server.  If the
+      //resident server will not give a lock then we send the user a message
+      //saying that he/she needs to download a new copy of the file and
+      //merge the differences manually.
+      int istreamInt; 
+      char istreamChar;
+      DocumentIdentifier id = new DocumentIdentifier(accnum);
+      String updaterev = id.getRev();
+      String server = MetacatReplication.getServer(serverCode);
+      MetacatReplication.replLog("attempting to lock " + accnum);
+      URL u = new URL("https://" + server + "?server="
+           +util.getLocalReplicationServerName()+"&action=getlock&updaterev=" 
+           +updaterev + "&docid=" + docid);
+      //System.out.println("sending message: " + u.toString());
+      String serverResStr = MetacatReplication.getURLContent(u);
+      String openingtag =serverResStr.substring(0, serverResStr.indexOf(">")+1);
+      if(openingtag.equals("<lockgranted>"))
+      {//the lock was granted go ahead with the insert
+        try 
+        {
+          //System.out.println("In lockgranted");
+          MetacatReplication.replLog("lock granted for " + accnum + " from " +
+                                      server);
+          XMLReader parser = initializeParser(conn, action, docid, updaterev,
+                                  validate, user, groups, pub, serverCode, dtd);
+          conn.setAutoCommit(false);
+          parser.parse(new InputSource(xml)); 
+          conn.commit();
+          conn.setAutoCommit(true);
+        } 
+        catch (Exception e) 
+        {
+          conn.rollback();
+          conn.setAutoCommit(true);
+          throw e;
+        }
+        return (accnum);
+      }
+
+      else if(openingtag.equals("<filelocked>"))
+      {//the file is currently locked by another user
+       //notify our user to wait a few minutes, check out a new copy and try
+       //again.
+        //System.out.println("file locked");
+        MetacatReplication.replLog("lock denied for " + accnum + " on " +
+                                   server + " reason: file already locked");
+        throw new Exception("The file specified is already locked by another " +
+                            "user.  Please wait 30 seconds, checkout the " +
+                            "newer document, merge your changes and try " +
+                            "again.");
+      }
+      else if(openingtag.equals("<outdatedfile>"))
+      {//our file is outdated.  notify our user to check out a new copy of the
+       //file and merge his version with the new version.
+        //System.out.println("outdated file");
+        MetacatReplication.replLog("lock denied for " + accnum + " on " +
+                                    server + " reason: local file outdated");
+        throw new Exception("The file you are trying to update is an outdated" +
+                            " version.  Please checkout the newest document, " +
+                            "merge your changes and try again.");
+      }
+    }
+    
+    if ( action.equals("UPDATE") ) {
+      // check for 'write' permission for 'user' to update this document
+
+      if ( !hasPermission(conn, user, groups, docid) ) {
+        throw new Exception("User " + user + 
+              " does not have permission to update XML Document #" + accnum);
+      }          
+    }
+
+    try 
+    { 
+      
+      XMLReader parser = initializeParser(conn, action, docid, rev, validate,
+                                          user, groups, pub, serverCode, dtd);
+      conn.setAutoCommit(false);
+      parser.parse(new InputSource(xml));
+      conn.commit();
+      conn.setAutoCommit(true);
+    } 
+    catch (Exception e) 
+    {
+      conn.rollback();
+      conn.setAutoCommit(true);
+      throw e;
+    }
+
+    return(accnum);
+  }
+
+  
+  /**
    * Delete an XML file from the database (actually, just make it a revision
    * in the xml_revisions table)
    *
@@ -1637,7 +1914,112 @@
       
     return serverLocation;
   }
+  
   /**
+   * Given a server name, return its servercode in xml_replication table.
+   * If no server is found, -1 will return
+   * @param serverName, 
+   */
+  private static int getServerCode(String serverName) 
+  {
+    PreparedStatement pStmt=null;
+    int serverLocation=-2;
+    Connection dbConn = null;
+    MetaCatUtil util = new MetaCatUtil();
+    
+    
+    //we should consider about local host too
+    if (serverName.equals(util.getLocalReplicationServerName()))
+    { 
+      serverLocation=1;
+      return serverLocation;
+    }
+    
+   
+    try
+    {
+      //check xml_replication table
+      dbConn=util.getConnection();
+      pStmt = dbConn.prepareStatement
+      ("SELECT serverid FROM xml_replication WHERE server='" + serverName +"'");
+      pStmt.execute();
+
+      ResultSet rs = pStmt.getResultSet();
+      boolean hasRow = rs.next();
+      //if there is entry in xml_replication, get the serverid
+      if (hasRow)
+      {
+        serverLocation = rs.getInt(1);
+        pStmt.close();
+      }
+      else
+      {
+        // if htere is no entry in xml_replication, -1 will return
+        serverLocation=-1;
+        pStmt.close();
+      }
+    }
+    catch (Exception e)
+    {
+      util.debugMessage("Error in DocumentImpl.getServerCode(): "
+                                    +e.getMessage(), 30);
+    }
+    finally
+    {
+      try
+      {
+        util.returnConnection(dbConn);
+      }
+      catch (Exception ee)
+      {}
+    }
+                 
+      
+    return serverLocation;
+  }
+  
+  /**
+   * Insert a server into xml_replcation table
+   * @param server, the name of server 
+   */
+  private static void  insertServerIntoReplicationTable(String server)
+  {
+    PreparedStatement pStmt=null;
+    Connection dbConn = null;
+    int replicate = 1;
+    MetaCatUtil util = new MetaCatUtil();
+    try
+    {
+       dbConn=util.getConnection();
+       pStmt = dbConn.prepareStatement("INSERT INTO xml_replication " +
+                                      "(server, last_checked, replicate) " +
+                                      "VALUES ('" + server + "', to_date(" +
+                                      "'01/01/00', 'MM/DD/YY'), '" +
+                                      replicate + "')");
+        pStmt.execute();
+        pStmt.close();
+        dbConn.commit();
+    }
+    catch (Exception e)
+    {
+      util.debugMessage("Error in DocumentImpl.getServerCode(): "
+                                    +e.getMessage(), 30);
+    }
+    finally
+    {
+      try
+      {
+        pStmt.close();
+        util.returnConnection(dbConn);
+      }
+      catch (Exception ee)
+      {}
+    }
+
+  }
+  
+  
+  /**
    * the main routine used to test the DBWriter utility.
    * <p>
    * Usage: java DocumentImpl <-f filename -a action -d docid>
