Index: test/edu/ucsb/nceas/metacat/dataone/CrudServiceTest.java
===================================================================
--- test/edu/ucsb/nceas/metacat/dataone/CrudServiceTest.java	(revision 5358)
+++ test/edu/ucsb/nceas/metacat/dataone/CrudServiceTest.java	(revision 5359)
@@ -38,6 +38,11 @@
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
+import org.dataone.service.exceptions.InvalidRequest;
+import org.dataone.service.exceptions.InvalidToken;
+import org.dataone.service.exceptions.NotAuthorized;
+import org.dataone.service.exceptions.NotImplemented;
+import org.dataone.service.exceptions.ServiceFailure;
 import org.dataone.service.types.*;
 
 import edu.ucsb.nceas.metacat.properties.PropertyService;
@@ -85,12 +90,99 @@
 		suite.addTest(new CrudServiceTest("testCreateAndGet"));
 		suite.addTest(new CrudServiceTest("testGetSystemMetadata"));
 		suite.addTest(new CrudServiceTest("testUpdate"));
+		suite.addTest(new CrudServiceTest("testListObjects"));
 		//suite.addTest(new CrudServiceTest(""));
-		//suite.addTest(new CrudServiceTest(""));
 		return suite;
 	}
 	
 	/**
+	 * public ObjectList listObjects(AuthToken token, Date startTime, Date endTime, 
+     *     ObjectFormat objectFormat, boolean replicaStatus, int start, int count)
+     *       throws NotAuthorized, InvalidRequest, NotImplemented, ServiceFailure, InvalidToken
+	 */
+	public void testListObjects()
+	{
+	    printTestHeader("testListObjects");
+	    try
+	    {
+	        CrudService cs = CrudService.getInstance();
+	        AuthToken token = getToken();
+	        ObjectFormat of1 = ObjectFormat.convert("eml://ecoinformatics.org/eml-2.1.0");
+	        ObjectFormat of2 = ObjectFormat.convert("text/plain");
+	        //create docs at different times
+	        Date d1 = new Date();
+	        Identifier id1 = createDoc(token, getTestDoc(), of1);
+            SystemMetadata sm1 = getSystemMetadata(token, id1);
+            
+            Date d2 = new Date();
+            Identifier id2 = createDoc(token, getTestDoc(), of2);
+            SystemMetadata sm2 = getSystemMetadata(token, id2);
+            
+            Date d3 = new Date();
+            Identifier id3 = createDoc(token, getTestDoc(), of1);
+            SystemMetadata sm3 = getSystemMetadata(token, id3);
+              
+            Date d4 = new Date();
+            Identifier id4 = createDoc(token, getTestDoc(), of2);
+            SystemMetadata sm4 = getSystemMetadata(token, id4);
+            
+            Date d5 = new Date();
+            Identifier id5 = createDoc(token, getTestDoc(), of1);
+            SystemMetadata sm5 = getSystemMetadata(token, id5);  
+              
+            //now get the objects for specific time ranges and test that it returns
+            //the correct objects
+	        
+            //should return sm1 and sm2
+            ObjectList list1 = cs.listObjects(token, d1, d2, null);
+            assertTrue(list1.sizeObjectInfoList() == 2);
+            ObjectInfo oi1 = list1.getObjectInfo(0);
+            assertTrue(oi1.getIdentifier().getValue().equals(id1.getValue()));
+            ObjectInfo oi2 = list1.getObjectInfo(1);
+            assertTrue(oi2.getIdentifier().getValue().equals(id2.getValue()));
+            
+            //should only return sm1
+            ObjectList list2 = cs.listObjects(token, d1, d2, of1);
+            assertTrue(list2.sizeObjectInfoList() == 1);
+            ObjectInfo oi3 = list2.getObjectInfo(0);
+            assertTrue(oi3.getIdentifier().getValue().equals(id1.getValue()));
+            
+            //should return sm1-sm4
+            ObjectList list3 = cs.listObjects(token, d1, d4, null);
+            assertTrue(list3.sizeObjectInfoList() == 4);
+            ObjectInfo oi4 = list3.getObjectInfo(0);
+            assertTrue(oi4.getIdentifier().getValue().equals(id1.getValue()));
+            ObjectInfo oi5 = list3.getObjectInfo(1);
+            assertTrue(oi5.getIdentifier().getValue().equals(id2.getValue()));
+            ObjectInfo oi6 = list3.getObjectInfo(2);
+            assertTrue(oi6.getIdentifier().getValue().equals(id3.getValue()));
+            ObjectInfo oi7 = list3.getObjectInfo(3);
+            assertTrue(oi7.getIdentifier().getValue().equals(id4.getValue()));
+            
+            //should only return sm2 and sm4
+            ObjectList list4 = cs.listObjects(token, d1, d2, of2);
+            assertTrue(list4.sizeObjectInfoList() == 2);
+            ObjectInfo oi8 = list4.getObjectInfo(0);
+            assertTrue(oi8.getIdentifier().getValue().equals(id2.getValue()));
+            ObjectInfo oi9 = list4.getObjectInfo(1);
+            assertTrue(oi9.getIdentifier().getValue().equals(id4.getValue()));
+            
+            //should return all
+            ObjectList list5 = cs.listObjects(token, d1, d5, null);
+            assertTrue(list5.sizeObjectInfoList() == 5);
+            //should return 1, 3, 5
+            ObjectList list6 = cs.listObjects(token, d1, d2, of1);
+            assertTrue(list5.sizeObjectInfoList() == 3);
+            
+            
+	    }
+	    catch(Exception e)
+	    {
+	        fail("Error in listObjects: " + e.getMessage());
+	    }
+	}
+	
+	/**
 	 * public Identifier update(AuthToken token, Identifier guid, 
      *       InputStream object, Identifier obsoletedGuid, SystemMetadata sysmeta) 
      *         throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, 
@@ -299,6 +391,14 @@
 	 */
 	private Identifier createDoc(AuthToken token, String testDoc) throws Exception
 	{
+	    return createDoc(token, testDoc, ObjectFormat.convert("eml://ecoinformatics.org/eml-2.1.0"));
+	}
+	
+	/**
+	 * create a doc using CrudService.create() and return its id
+	 */
+	private Identifier createDoc(AuthToken token, String testDoc, ObjectFormat format) throws Exception
+	{
 	    Identifier id;
         CrudService cs = CrudService.getInstance();
         
@@ -308,7 +408,7 @@
         
         //create the system metadata then run the create method
         StringBufferInputStream sbis = new StringBufferInputStream(testDoc);
-        SystemMetadata sm = createSystemMetadata(id, testDoc);
+        SystemMetadata sm = createSystemMetadata(id, testDoc, format);
         //create the doc
         cs.create(token, id, sbis, sm);
         return id;
@@ -320,10 +420,20 @@
 	private SystemMetadata createSystemMetadata(Identifier id, String testDoc)
 	  throws Exception
 	{
+	    return createSystemMetadata(id, testDoc, 
+	            ObjectFormat.convert("eml://ecoinformatics.org/eml-2.1.0"));
+	}
+	
+	/**
+	 * create system metadata with a specified id, doc and format
+	 */
+	private SystemMetadata createSystemMetadata(Identifier id, String testDoc, ObjectFormat format)
+	  throws Exception
+	{
 	    SystemMetadata sm = new SystemMetadata();
         //set the id
         sm.setIdentifier(id);
-        sm.setObjectFormat(ObjectFormat.convert("eml://ecoinformatics.org/eml-2.1.0"));
+        sm.setObjectFormat(format);
         //create the checksum
         String checksumS = checksum(testDoc);
         ChecksumAlgorithm ca = ChecksumAlgorithm.convert("MD5");
Index: src/edu/ucsb/nceas/metacat/dataone/CrudService.java
===================================================================
--- src/edu/ucsb/nceas/metacat/dataone/CrudService.java	(revision 5358)
+++ src/edu/ucsb/nceas/metacat/dataone/CrudService.java	(revision 5359)
@@ -60,6 +60,8 @@
 import org.dataone.service.types.Identifier;
 import org.dataone.service.types.LogRecordSet;
 import org.dataone.service.types.SystemMetadata;
+import org.dataone.service.types.ObjectList;
+import org.dataone.service.types.ObjectFormat;
 import org.jibx.runtime.BindingDirectory;
 import org.jibx.runtime.IBindingFactory;
 import org.jibx.runtime.IMarshallingContext;
@@ -278,7 +280,71 @@
             throw new ServiceFailure("1030", "Error updating document in CrudService: " + e.getMessage());
         }
     }
+    
+    /**
+     *  Retrieve the list of objects present on the MN that match the calling 
+     *  parameters. This method is required to support the process of Member 
+     *  Node synchronization. At a minimum, this method should be able to 
+     *  return a list of objects that match:
+     *  startTime <= SystemMetadata.dateSysMetadataModified
+     *  but is expected to also support date range (by also specifying endTime), 
+     *  and should also support slicing of the matching set of records by 
+     *  indicating the starting index of the response (where 0 is the index 
+     *  of the first item) and the count of elements to be returned.
+     *  
+     * @see http://mule1.dataone.org/ArchitectureDocs/mn_api_replication.html#MN_replication.listObjects
+     * @param token
+     * @param startTime
+     * @param endTime
+     * @param objectFormat
+     * @param replicaStatus
+     * @param start
+     * @param count
+     * @return ObjectList
+     * @throws NotAuthorized
+     * @throws InvalidRequest
+     * @throws NotImplemented
+     * @throws ServiceFailure
+     * @throws InvalidToken
+     */
+    public ObjectList listObjects(AuthToken token, Date startTime, Date endTime, 
+        ObjectFormat objectFormat, boolean replicaStatus, int start, int count)
+      throws NotAuthorized, InvalidRequest, NotImplemented, ServiceFailure, InvalidToken
+    {
+      ObjectList ol = new ObjectList();
+      //do an squery on metacat to return systemMetadata docs where 
+      //sm.dateSysMetadataModified >= startTime
+      //sm.dateSysMetadataModified <= endTime
+      //further slice the returned dataset if replicaStatus is false.
+      //if start != 0, return only the documents with index >= start
+      //if the number of results is > count, return the first count docs
+      return ol;
+    }
+    
+    /**
+     * Call listObjects with the default values for replicaStatus (true), start (0),
+     * and count (1000).
+     * @param token
+     * @param startTime
+     * @param endTime
+     * @param objectFormat
+     * @return
+     * @throws NotAuthorized
+     * @throws InvalidRequest
+     * @throws NotImplemented
+     * @throws ServiceFailure
+     * @throws InvalidToken
+     */
+    public ObjectList listObjects(AuthToken token, Date startTime, Date endTime, 
+        ObjectFormat objectFormat)
+      throws NotAuthorized, InvalidRequest, NotImplemented, ServiceFailure, InvalidToken
+    {
+       return listObjects(token, startTime, endTime, objectFormat, true, 0, 1000);
+    }
 
+    /**
+     * Delete a document.  NOT IMPLEMENTED
+     */
     public Identifier delete(AuthToken token, Identifier guid)
             throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
             NotImplemented {
@@ -285,6 +351,9 @@
         throw new NotImplemented("1000", "This method not yet implemented.");
     }
 
+    /**
+     * describe a document.  NOT IMPLEMENTED
+     */
     public DescribeResponse describe(AuthToken token, Identifier guid)
             throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
             NotImplemented {
@@ -291,6 +360,9 @@
         throw new NotImplemented("1000", "This method not yet implemented.");
     }
     
+    /**
+     * get a document with a specified guid.
+     */
     public InputStream get(AuthToken token, Identifier guid)
             throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
             NotImplemented {
@@ -341,6 +413,9 @@
         }
     }
 
+    /**
+     * get the checksum for a document.  NOT IMPLEMENTED
+     */
     public Checksum getChecksum(AuthToken token, Identifier guid)
             throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
             InvalidRequest, NotImplemented {
@@ -347,6 +422,9 @@
         throw new NotImplemented("1000", "This method not yet implemented.");
     }
 
+    /**
+     * get the checksum for a document.  NOT IMPLEMENTED
+     */
     public Checksum getChecksum(AuthToken token, Identifier guid, 
             String checksumAlgorithm) throws InvalidToken, ServiceFailure, 
             NotAuthorized, NotFound, InvalidRequest, NotImplemented {
@@ -353,6 +431,9 @@
         throw new NotImplemented("1000", "This method not yet implemented.");
     }
 
+    /**
+     * get log records.  NOT IMPLEMENTED
+     */
     public LogRecordSet getLogRecords(AuthToken token, Date fromDate, Date toDate)
             throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest, 
             NotImplemented {
@@ -359,6 +440,9 @@
         throw new NotImplemented("1000", "This method not yet implemented.");
     }
 
+    /**
+     * get the system metadata for a document with a specified guid.
+     */
     public SystemMetadata getSystemMetadata(AuthToken token, Identifier guid)
             throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
             InvalidRequest, NotImplemented {
@@ -463,6 +547,13 @@
         return scimeta;
     }
 
+    /**
+     * insert a data doc
+     * @param object
+     * @param guid
+     * @param sessionData
+     * @throws ServiceFailure
+     */
     private void insertDataObject(InputStream object, Identifier guid, 
             SessionData sessionData) throws ServiceFailure {
         
@@ -538,6 +629,14 @@
         }
     }
 
+    /**
+     * write a file to a stream
+     * @param dir
+     * @param fileName
+     * @param data
+     * @return
+     * @throws ServiceFailure
+     */
     private File writeStreamToFile(File dir, String fileName, InputStream data) 
         throws ServiceFailure {
         
@@ -723,6 +822,12 @@
         return localId;
     }
     
+    /**
+     * serialize a system metadata doc
+     * @param sysmeta
+     * @return
+     * @throws ServiceFailure
+     */
     public static ByteArrayOutputStream serializeSystemMetadata(SystemMetadata sysmeta) 
         throws ServiceFailure {
         IBindingFactory bfact;
@@ -739,6 +844,12 @@
         return sysmetaOut;
     }
     
+    /**
+     * deserialize a system metadata doc
+     * @param xml
+     * @return
+     * @throws ServiceFailure
+     */
     public static SystemMetadata deserializeSystemMetadata(InputStream xml) 
         throws ServiceFailure {
         try {
