Index: src/xmltables-oracle.sql
===================================================================
--- src/xmltables-oracle.sql	(revision 6106)
+++ src/xmltables-oracle.sql	(revision 6107)
@@ -414,6 +414,8 @@
    submitter VARCHAR2(256), -- the user who originally submitted the doc
    object_format VARCHAR2(256), --the format of the object
    size VARCHAR2(256), --the size of the object
+   replication_allowed boolean,	 -- replication allowed
+   number_replicas NUMBER(8), 	-- the number of replicas allowed
    CONSTRAINT systemMetadata_pk 
 		PRIMARY KEY (guid)
 )
@@ -429,6 +431,23 @@
 		FOREIGN KEY (guid) REFERENCES systemMetadata
 );
 
+CREATE TABLE systemMetadataReplicationPolicy (
+	guid VARCHAR2(2000),	-- the globally unique string identifier of the object that the system metadata describes
+	member_node VARCHAR(250),	 -- replication member node
+	policy VARCHAR2(2000),	 -- the policy (preferred, blocked, etc...TBD)
+	CONSTRAINT systemMetadataReplicationPolicy_fk 
+		FOREIGN KEY (guid) REFERENCES systemMetadata
+);
+
+CREATE TABLE systemMetadataReplicationStatus (
+	guid VARCHAR2(2000),	-- the globally unique string identifier of the object that the system metadata describes
+	member_node VARCHAR(250),	 -- replication member node
+	status VARCHAR(250),	 -- replication status
+	date_verified DATE, 	-- the date replication was verified   
+	CONSTRAINT systemMetadataReplicationStatus_fk 
+		FOREIGN KEY (guid) REFERENCES systemMetadata
+);
+
 /*
  * Table used to store all document identifiers in metacat.  Each identifier
  * has a globally unique, unconstrained string, which we will refer to as a
Index: src/xmltables-postgres.sql
===================================================================
--- src/xmltables-postgres.sql	(revision 6106)
+++ src/xmltables-postgres.sql	(revision 6107)
@@ -289,23 +289,27 @@
  * data first or the systemMetadata first.
  */
 CREATE TABLE systemMetadata (
-   guid   text,          -- the globally unique string identifier of the object that the system metadata describes
-   date_uploaded TIMESTAMP, -- the date/time the document was first submitted
-   rights_holder VARCHAR(250), --the user who has rights to the document, usually the first persons to upload it
-   checksum VARCHAR(512), --the checksum of the doc using the given algorithm (see below)
-   checksum_algorithm VARCHAR(250), --the algorithm used to calculate the checksum
-   origin_member_node VARCHAR(250), --the member node where the document was first uploaded
-   authoritive_member_node VARCHAR(250), --the member node that currently controls the document
-   date_modified TIMESTAMP, -- the last date/time that the file was changed
-   submitter VARCHAR(256), -- the user who originally submitted the doc
-   object_format VARCHAR(256), --the format of the object
-   size VARCHAR(256), --the size of the object
-   CONSTRAINT systemMetadata_pk PRIMARY KEY (guid)
+	guid   text,          -- the globally unique string identifier of the object that the system metadata describes
+	date_uploaded TIMESTAMP, -- the date/time the document was first submitted
+	rights_holder VARCHAR(250), --the user who has rights to the document, usually the first persons to upload it
+	checksum VARCHAR(512), --the checksum of the doc using the given algorithm (see below)
+	checksum_algorithm VARCHAR(250), --the algorithm used to calculate the checksum
+	origin_member_node VARCHAR(250), --the member node where the document was first uploaded
+	authoritive_member_node VARCHAR(250), --the member node that currently controls the document
+	date_modified TIMESTAMP, -- the last date/time that the file was changed
+	submitter VARCHAR(256), -- the user who originally submitted the doc
+	object_format VARCHAR(256), --the format of the object
+	size VARCHAR(256), --the size of the object
+	replication_allowed boolean,	 -- replication allowed
+	number_replicas INT8, 	-- the number of replicas allowed
+	CONSTRAINT systemMetadata_pk PRIMARY KEY (guid)
 );
 /*
  * For devs to remove docid, rev
  * ALTER TABLE systemMetadata DROP COLUMN docid;
  * ALTER TABLE systemMetadata DROP COLUMN rev;
+ * ALTER TABLE systemMetadata ADD COLUMN replication_allowed boolean;
+ * ALTER TABLE systemMetadata ADD COLUMN number_replicas INT8;
  */
 
 /*
@@ -315,11 +319,27 @@
    guid   		text,          -- the globally unique string identifier of the object that the system metadata describes
    relationship	VARCHAR(250),	 -- the provenance relationship defined between objects
    target_guid	text,          -- the globally unique string identifier of the other object
-   
    CONSTRAINT systemMetadataProvenance_fk 
 		FOREIGN KEY (guid) REFERENCES systemMetadata
 );
 
+CREATE TABLE systemMetadataReplicationPolicy (
+	guid text,	-- the globally unique string identifier of the object that the system metadata describes
+	member_node VARCHAR(250),	 -- replication member node
+	policy text,	 -- the policy (preferred, blocked, etc...TBD)
+	CONSTRAINT systemMetadataReplicationPolicy_fk 
+		FOREIGN KEY (guid) REFERENCES systemMetadata
+);
+
+CREATE TABLE systemMetadataReplicationStatus (
+	guid text,	-- the globally unique string identifier of the object that the system metadata describes
+	member_node VARCHAR(250),	 -- replication member node
+	status VARCHAR(250),	 -- replication status
+	date_verified TIMESTAMP, 	-- the date replication was verified   
+	CONSTRAINT systemMetadataReplicationStatus_fk 
+		FOREIGN KEY (guid) REFERENCES systemMetadata
+);
+
 /*
  * accesssubtree -- table to store access subtree info
  */
Index: src/edu/ucsb/nceas/metacat/IdentifierManager.java
===================================================================
--- src/edu/ucsb/nceas/metacat/IdentifierManager.java	(revision 6106)
+++ src/edu/ucsb/nceas/metacat/IdentifierManager.java	(revision 6107)
@@ -24,23 +24,29 @@
 
 package edu.ucsb.nceas.metacat;
 
-import java.util.*;
-
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Vector;
 
 import org.apache.log4j.Logger;
 import org.dataone.service.types.Checksum;
 import org.dataone.service.types.ChecksumAlgorithm;
+import org.dataone.service.types.Identifier;
 import org.dataone.service.types.NodeReference;
 import org.dataone.service.types.ObjectFormat;
 import org.dataone.service.types.ObjectInfo;
 import org.dataone.service.types.ObjectList;
+import org.dataone.service.types.Replica;
+import org.dataone.service.types.ReplicationPolicy;
+import org.dataone.service.types.ReplicationStatus;
 import org.dataone.service.types.Subject;
 import org.dataone.service.types.SystemMetadata;
-import org.dataone.service.types.Identifier;
 
 import edu.ucsb.nceas.metacat.database.DBConnection;
 import edu.ucsb.nceas.metacat.database.DBConnectionPool;
@@ -294,6 +300,15 @@
         sysMeta.setDescribedByList(getSystemMetadataProvenance(sysMeta.getIdentifier().getValue(), "describedBy"));
         sysMeta.setDerivedFromList(getSystemMetadataProvenance(sysMeta.getIdentifier().getValue(), "derivedFrom"));
         
+        // look up replication policy
+        ReplicationPolicy replicationPolicy = new ReplicationPolicy();
+        replicationPolicy.setBlockedMemberNodeList(getReplicationPolicy(guid, "blocked"));
+        replicationPolicy.setPreferredMemberNodeList(getReplicationPolicy(guid, "preferred"));
+		sysMeta.setReplicationPolicy(replicationPolicy);
+		
+		// look up replication status
+		sysMeta.setReplicaList(getReplicationStatus(guid));
+        
         return sysMeta;
     }
     
@@ -303,43 +318,122 @@
     	List<Identifier> identifiers = new ArrayList<Identifier>();
     	String sql = "select guid, relationship, target_guid " +
     		"from systemMetadataProvenance where guid = ? and relationship = ?";
-    DBConnection dbConn = null;
-    int serialNumber = -1;
-    try 
-    {
-        // Get a database connection from the pool
-        dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getSystemMetadataProvenance");
-        serialNumber = dbConn.getCheckOutSerialNumber();
-
-        // Execute the statement
-        PreparedStatement stmt = dbConn.prepareStatement(sql);
-        stmt.setString(1, guid);
-        stmt.setString(2, relationship);
-        ResultSet rs = stmt.executeQuery();
-        while (rs.next()) 
-        {
-            String targetGuid = rs.getString(3);
-            Identifier id = new Identifier();
-            id.setValue(targetGuid);
-            identifiers.add(id);
-        
-        } 
-        stmt.close();
-        
-    } 
-    catch (SQLException e) 
-    {
-        logMetacat.error("Error while getting system metadata provenance for guid " + guid, e);
-    } 
-    finally 
-    {
-        // Return database connection to the pool
-        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
-    }
+	    DBConnection dbConn = null;
+	    int serialNumber = -1;
+	    try {
+	        // Get a database connection from the pool
+	        dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getSystemMetadataProvenance");
+	        serialNumber = dbConn.getCheckOutSerialNumber();
+	
+	        // Execute the statement
+	        PreparedStatement stmt = dbConn.prepareStatement(sql);
+	        stmt.setString(1, guid);
+	        stmt.setString(2, relationship);
+	        ResultSet rs = stmt.executeQuery();
+	        while (rs.next()) 
+	        {
+	            String targetGuid = rs.getString(3);
+	            Identifier id = new Identifier();
+	            id.setValue(targetGuid);
+	            identifiers.add(id);
+	        
+	        } 
+	        stmt.close();
+	        
+	    } 
+	    catch (SQLException e) {
+	        logMetacat.error("Error while getting system metadata provenance for guid " + guid, e);
+	    } 
+	    finally {
+	        // Return database connection to the pool
+	        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
+	    }
+	    
+	    return identifiers;
+	}
     
-    return identifiers;
-}
+    private List<NodeReference> getReplicationPolicy(String guid, String policy)
+		throws McdbDocNotFoundException {
+		
+		List<NodeReference> nodes = new ArrayList<NodeReference>();
+		String sql = "select guid, policy, member_node " +
+			"from systemMetadataReplicationPolicy where guid = ? and policy = ?";
+	    DBConnection dbConn = null;
+	    int serialNumber = -1;
+	    try {
+	        // Get a database connection from the pool
+	        dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getReplicationPolicy");
+	        serialNumber = dbConn.getCheckOutSerialNumber();
+	
+	        // Execute the statement
+	        PreparedStatement stmt = dbConn.prepareStatement(sql);
+	        stmt.setString(1, guid);
+	        stmt.setString(2, policy);
+	        ResultSet rs = stmt.executeQuery();
+	        while (rs.next()) 
+	        {
+	            String memberNode = rs.getString(3);
+	            NodeReference node = new NodeReference();
+	            node.setValue(memberNode);
+	            nodes.add(node);
+	        
+	        } 
+	        stmt.close();
+	        
+	    } catch (SQLException e) {
+	        logMetacat.error("Error while getting system metadata replication policy for guid " + guid, e);
+	    } 
+	    finally {
+	        // Return database connection to the pool
+	        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
+	    }
+	    
+	    return nodes;
+	}
     
+    private List<Replica> getReplicationStatus(String guid) throws McdbDocNotFoundException {
+		
+		List<Replica> replicas = new ArrayList<Replica>();
+		String sql = "select guid, member_node, status, date_verified " +
+			"from systemMetadataReplicationStatus where guid = ?";
+	    DBConnection dbConn = null;
+	    int serialNumber = -1;
+	    try {
+	        // Get a database connection from the pool
+	        dbConn = DBConnectionPool.getDBConnection("IdentifierManager.getReplicas");
+	        serialNumber = dbConn.getCheckOutSerialNumber();
+	
+	        // Execute the statement
+	        PreparedStatement stmt = dbConn.prepareStatement(sql);
+	        stmt.setString(1, guid);
+	        ResultSet rs = stmt.executeQuery();
+	        while (rs.next()) 
+	        {
+	            String memberNode = rs.getString(2);
+	            String status = rs.getString(3);
+	            java.sql.Date verified = rs.getDate(4);
+	            
+	            Replica replica = new Replica();	            
+	            NodeReference node = new NodeReference();
+	            node.setValue(memberNode);
+	            replica.setReplicaMemberNode(node);
+	            replica.setReplicationStatus(ReplicationStatus.convert(status));
+	            replica.setReplicaVerified(new Date(verified.getTime()));
+	            replicas.add(replica);
+	        } 
+	        stmt.close();
+	        
+	    } catch (SQLException e) {
+	        logMetacat.error("Error while getting system metadata replication policy for guid " + guid, e);
+	    } 
+	    finally {
+	        // Return database connection to the pool
+	        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
+	    }
+	    
+	    return replicas;
+	}
+    
     /**
      * return information on the document with localId.  These are the fields
      * from the xml_documents table.  They can be used to contstruct metadata 
@@ -780,7 +874,8 @@
     private void updateSystemMetadataFields(long dateUploaded, String rightsHolder,
             String checksum, String checksumAlgorithm, String originMemberNode,
             String authoritativeMemberNode, long modifiedDate, String submitter, 
-            String guid, String objectFormat, long size)
+            String guid, String objectFormat, long size, boolean replicationAllowed,
+            int numberReplicas)
     {
         DBConnection dbConn = null;
         int serialNumber = -1;
@@ -795,8 +890,8 @@
             String query = "update " + TYPE_SYSTEM_METADATA + 
                 " set (date_uploaded, rights_holder, checksum, checksum_algorithm, " +
                 "origin_member_node, authoritive_member_node, date_modified, " +
-                "submitter, object_format, size) " +
-                "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) where guid = ?";
+                "submitter, object_format, size, replication_allowed, number_replicas) " +
+                "= (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) where guid = ?";
             PreparedStatement stmt = dbConn.prepareStatement(query);
             
             //data values
@@ -810,8 +905,10 @@
             stmt.setString(8, submitter);
             stmt.setString(9, objectFormat);
             stmt.setString(10, new Long(size).toString());
+            stmt.setBoolean(11, replicationAllowed);
+            stmt.setInt(12, numberReplicas);
             //where clause
-            stmt.setString(11, guid);
+            stmt.setString(13, guid);
             logMetacat.debug("stmt: " + stmt.toString());
             //execute
             int rows = stmt.executeUpdate();
@@ -839,7 +936,7 @@
         try {
             // Get a database connection from the pool
             dbConn = 
-                DBConnectionPool.getDBConnection("IdentifierManager.createMapping");
+                DBConnectionPool.getDBConnection("IdentifierManager.insertSystemMetadataProvenance");
             serialNumber = dbConn.getCheckOutSerialNumber();
 
             // remove existing values first
@@ -876,13 +973,116 @@
         }
     }
     
+    private void insertReplicationPolicy(String guid, String policy, List<String> memberNodes)
+    {
+        DBConnection dbConn = null;
+        int serialNumber = -1;
+        
+        try {
+            // Get a database connection from the pool
+            dbConn = 
+                DBConnectionPool.getDBConnection("IdentifierManager.insertReplicationPolicy");
+            serialNumber = dbConn.getCheckOutSerialNumber();
+
+            // remove existing values first
+            String delete = "delete from systemMetadataReplicationPolicy " + 
+            "where guid = ? and policy = ?";
+	        PreparedStatement stmt = dbConn.prepareStatement(delete);
+	        //data values
+	        stmt.setString(1, guid);
+	        stmt.setString(2, policy);
+	        //execute
+	        int deletedCount = stmt.executeUpdate();
+	        stmt.close();
+            
+            for (String memberNode: memberNodes) {
+	            // Execute the insert statement
+	            String insert = "insert into systemMetadataReplicationPolicy " + 
+	                "(guid, policy, member_node) " +
+	                "values (?, ?, ?)";
+	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
+	            
+	            //data values
+	            insertStatement.setString(1, guid);
+	            insertStatement.setString(2, policy);
+	            insertStatement.setString(3, memberNode);
+	            //execute
+	            int rows = insertStatement.executeUpdate();
+	            insertStatement.close();
+            }
+        } catch (SQLException e) {
+            logMetacat.error("SQL error while adding systemMetadataReplicationPolicy for: " + guid, e); 
+        } finally {
+            // Return database connection to the pool
+            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
+        }
+    }
+    
+    private void insertReplicationStatus(String guid, List<Replica> replicas) {
+        DBConnection dbConn = null;
+        int serialNumber = -1;
+        
+        try {
+            // Get a database connection from the pool
+            dbConn = DBConnectionPool.getDBConnection("IdentifierManager.insertReplicas");
+            serialNumber = dbConn.getCheckOutSerialNumber();
+
+            // remove existing values first
+            String delete = "delete from systemMetadataReplicationStatus " + 
+            "where guid = ?";
+	        PreparedStatement stmt = dbConn.prepareStatement(delete);
+	        //data values
+	        stmt.setString(1, guid);
+	        //execute
+	        int deletedCount = stmt.executeUpdate();
+	        stmt.close();
+            
+            for (Replica replica: replicas) {
+	            // Execute the insert statement
+	            String insert = "insert into systemMetadataReplicationStatus " + 
+	                "(guid, member_node, status, date_verified) " +
+	                "values (?, ?, ?, ?)";
+	            PreparedStatement insertStatement = dbConn.prepareStatement(insert);
+	            
+	            //data values
+	            String memberNode = replica.getReplicaMemberNode().getValue();
+	            String status = replica.getReplicationStatus().toString();
+	            java.sql.Date sqlDate = new java.sql.Date(replica.getReplicaVerified().getTime());
+	            insertStatement.setString(1, guid);
+	            insertStatement.setString(2, memberNode);
+	            insertStatement.setString(3, status);
+	            insertStatement.setDate(4, sqlDate);
+
+	            //execute
+	            int rows = insertStatement.executeUpdate();
+	            insertStatement.close();
+            }
+        } catch (SQLException e) {
+            logMetacat.error("SQL error while adding systemMetadataReplicationStatus for: " + guid, e); 
+        } finally {
+            // Return database connection to the pool
+            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
+        }
+    }
+    
     /**
      * Insert the system metadata fields into the db
      * @param sm
      */
-    public void updateSystemMetadata(SystemMetadata sm)
-    {
-        updateSystemMetadataFields(
+    public void updateSystemMetadata(SystemMetadata sm) {
+    	
+        Boolean replicationAllowed = false;
+		Integer numberReplicas = -1;
+    	ReplicationPolicy replicationPolicy = sm.getReplicationPolicy();
+    	if (replicationPolicy != null) {
+    		replicationAllowed = replicationPolicy.getReplicationAllowed();
+    		numberReplicas = replicationPolicy.getNumberReplicas();
+    		replicationAllowed = replicationAllowed == null ? false: replicationAllowed;
+    		numberReplicas = numberReplicas == null ? -1: numberReplicas;
+    	}
+
+    	// the main systemMetadata fields
+		updateSystemMetadataFields(
                 sm.getDateUploaded().getTime(),
                 sm.getRightsHolder().getValue(), 
                 sm.getChecksum().getValue(), 
@@ -893,7 +1093,9 @@
                 sm.getSubmitter().getValue(), 
                 sm.getIdentifier().getValue(),
                 sm.getObjectFormat().toString(),
-                sm.getSize());
+                sm.getSize(),
+                replicationAllowed, 
+                numberReplicas);
         
         // add provenance information
         String guid = sm.getIdentifier().getValue();
@@ -934,7 +1136,30 @@
         	targetGuids.add(id.getValue());
         }
         this.insertSystemMetadataProvenance(guid, relationship, targetGuids);
+                
+        // save replication policies
+        if (replicationPolicy != null) {
+		    List<String> nodes = null;
+		    String policy = null;
+		    
+		    nodes = new ArrayList<String>();
+		    policy = "blocked";
+		    for (NodeReference node: replicationPolicy.getBlockedMemberNodeList()) {
+		    	nodes.add(node.getValue());
+		    }
+		    this.insertReplicationPolicy(guid, policy, nodes);
+		    
+		    nodes = new ArrayList<String>();
+		    policy = "preferred";
+		    for (NodeReference node: replicationPolicy.getPreferredMemberNodeList()) {
+		    	nodes.add(node.getValue());
+		    }
+	        this.insertReplicationPolicy(guid, policy, nodes);
+        }
         
+        // save replica information
+        this.insertReplicationStatus(guid, sm.getReplicaList());
+        
     }
     
     /**
