Index: test/edu/ucsb/nceas/metacat/dataone/CrudServiceTest.java
===================================================================
--- test/edu/ucsb/nceas/metacat/dataone/CrudServiceTest.java	(revision 5349)
+++ test/edu/ucsb/nceas/metacat/dataone/CrudServiceTest.java	(revision 5350)
@@ -80,17 +80,69 @@
 	public static Test suite() 
 	{
 		TestSuite suite = new TestSuite();
-		suite.addTest(new CrudServiceTest("initialize"));
+		/*suite.addTest(new CrudServiceTest("initialize"));
 		suite.addTest(new CrudServiceTest("testSingletonAccessor"));
 		suite.addTest(new CrudServiceTest("testCreateAndGet"));
-		suite.addTest(new CrudServiceTest("testGetSystemMetadata"));
+		suite.addTest(new CrudServiceTest("testGetSystemMetadata"));*/
+		suite.addTest(new CrudServiceTest("testUpdate"));
 		//suite.addTest(new CrudServiceTest(""));
 		//suite.addTest(new CrudServiceTest(""));
-		//suite.addTest(new CrudServiceTest(""));
 		return suite;
 	}
 	
 	/**
+	 * public Identifier update(AuthToken token, Identifier guid, 
+     *       InputStream object, Identifier obsoletedGuid, SystemMetadata sysmeta) 
+     *         throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, 
+     *           UnsupportedType, InsufficientResources, NotFound, InvalidSystemMetadata, 
+     *           NotImplemented
+	 */
+	public void testUpdate()
+	{
+	    printTestHeader("testUpdate");
+	    try
+	    {
+	        CrudService cs = CrudService.getInstance();
+	        AuthToken token = getToken();
+            //create a doc
+            System.out.println("CST: creating document");
+            Identifier id = createDoc(token, getTestDoc());
+            System.out.println("CST: document created.  Id: " + id.getValue());
+            //get the doc and sysmetadata
+            System.out.println("CST: getting document with id " + id.getValue());
+            String gotDoc = getDoc(token, id);
+            System.out.println("CST: getting sysmeta for doc with id " + id.getValue());
+            SystemMetadata sm = getSystemMetadata(token, id);
+            //update the doc
+            System.out.println("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ doing the update now $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$");
+            gotDoc = gotDoc.replaceAll("XXX", "YYY");
+            System.out.println("CST: Changed test doc to " + gotDoc);
+            Identifier newid = new Identifier();
+            newid.setValue(generateDocumentId());
+            System.out.println("CST: Generated newid " + newid);
+            StringBufferInputStream sbis = new StringBufferInputStream(gotDoc);
+            SystemMetadata newsm = createSystemMetadata(newid, gotDoc);
+            System.out.println("CST: Created system metadata for new doc...updating.");
+            Identifier updatedid = cs.update(token, newid, sbis, id, newsm);
+            System.out.println("CST: Called update. Returned id " + id);
+            //get doc - check that it matches update
+            String newdoc = getDoc(token, newid);
+            assertTrue(gotDoc.equals(newdoc));
+            //get sysmeta - check that ids and other fields are updated
+            SystemMetadata newnewsm = getSystemMetadata(token, id);
+            List obsoletedByList = newnewsm.getObsoletedByList();
+            assertTrue(obsoletedByList.size() == 1);
+            String obsBy = ((Identifier)obsoletedByList.get(0)).getValue();
+            assertTrue(obsBy.equals(id.getValue()));
+        }
+        catch(Exception e)
+        {
+            e.printStackTrace();
+            fail("Error in testUpdate: " + e.getMessage());
+        }
+	}
+	
+	/**
 	 * public SystemMetadata getSystemMetadata(AuthToken token, Identifier guid)
      *       throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
      *       InvalidRequest, NotImplemented
@@ -229,7 +281,7 @@
 	 */
 	private String getTestDoc()
 	{
-	    return "<?xml version=\"1.0\"?><test></test>\n";
+	    return "<?xml version=\"1.0\"?><test><somecontent>This is some content XXX</somecontent></test>\n";
 	}
 	
 	/**
@@ -270,7 +322,20 @@
         
         //create the system metadata then run the create method
         StringBufferInputStream sbis = new StringBufferInputStream(testDoc);
-        SystemMetadata sm = new SystemMetadata();
+        SystemMetadata sm = createSystemMetadata(id, testDoc);
+        //create the doc
+        cs.create(token, id, sbis, sm);
+        System.out.println("document with id " + id.getValue() + " created.");
+        return id;
+	}
+	
+	/**
+	 * create a generic SystemMetadata object for testing
+	 */
+	private SystemMetadata createSystemMetadata(Identifier id, String testDoc)
+	  throws Exception
+	{
+	    SystemMetadata sm = new SystemMetadata();
         //set the id
         System.out.println("creating system metadata object for document with id " + id.getValue());
         sm.setIdentifier(id);
@@ -299,10 +364,7 @@
         nr.setValue("metacat");
         sm.setOriginMemberNode(nr);
         sm.setAuthoritativeMemberNode(nr);
-        //create the doc
-        cs.create(token, id, sbis, sm);
-        System.out.println("document with id " + id.getValue() + " created.");
-        return id;
+        return sm;
 	}
 	
 	/**
Index: src/edu/ucsb/nceas/metacat/DocumentImpl.java
===================================================================
--- src/edu/ucsb/nceas/metacat/DocumentImpl.java	(revision 5349)
+++ src/edu/ucsb/nceas/metacat/DocumentImpl.java	(revision 5350)
@@ -2566,6 +2566,7 @@
     	
         logMetacat.debug("DocumentImpl.write - conn usage count before writting: "
                 + conn.getUsageCount());
+        System.out.println("creating new accnum: " + accnum + " for action " + action);
         AccessionNumber ac = new AccessionNumber(accnum, action);
         String docid = ac.getDocid();
         String rev = ac.getRev();
Index: src/edu/ucsb/nceas/metacat/AccessionNumber.java
===================================================================
--- src/edu/ucsb/nceas/metacat/AccessionNumber.java	(revision 5349)
+++ src/edu/ucsb/nceas/metacat/AccessionNumber.java	(revision 5350)
@@ -155,7 +155,7 @@
       } else if ( action.equals("UPDATE") &&
                   reversionNumber <= getLastRevisionNumber(docid) ) {
         throw new AccessionNumberException
-                 ("Next revision number couldn't be less than or equal "
+                 ("Next revision number can't be less than or equal to "
                                               + getLastRevisionNumber(docid));
 
       // Revision number is not the recent one; throw an exception
Index: src/edu/ucsb/nceas/metacat/dataone/CrudService.java
===================================================================
--- src/edu/ucsb/nceas/metacat/dataone/CrudService.java	(revision 5349)
+++ src/edu/ucsb/nceas/metacat/dataone/CrudService.java	(revision 5350)
@@ -35,6 +35,7 @@
 import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.Timer;
+import java.util.List;
 
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
@@ -211,8 +212,7 @@
         if (isScienceMetadata) {
             // CASE METADATA:
             try {
-                String xml = IOUtils.toString(object);
-                this.insertDocument(xml, guid, sessionData);
+                this.insertDocument(object, guid, sessionData);
             } catch (IOException e) {
                 String msg = "Could not create string from XML stream: " +
                     " " + e.getMessage();
@@ -372,12 +372,49 @@
         }                
     }
 
+    /**
+     * update an existing object with a new object.  Change the system metadata
+     * to reflect the changes and update it as well.
+     */
     public Identifier update(AuthToken token, Identifier guid, 
             InputStream object, Identifier obsoletedGuid, SystemMetadata sysmeta) 
             throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, 
             UnsupportedType, InsufficientResources, NotFound, InvalidSystemMetadata, 
             NotImplemented {
-        throw new NotImplemented(1000, "This method not yet implemented.");
+        try
+        {
+            SessionData sessionData = getSessionData(token);
+            
+            //find the old systemmetadata (sm.old) document id (the one linked to obsoletedGuid)
+            SystemMetadata sm = getSystemMetadata(token, obsoletedGuid);
+            System.out.println("CS: got sm for obsoleteGuid: " + obsoletedGuid.getValue());
+            //change sm.old's obsoletedBy field 
+            List l = sm.getObsoletedByList();
+            l.add(guid);
+            sm.setObsoletedByList(l);
+            System.out.println("CS: set obsoletedBy to id: " + ((Identifier)l.get(0)).getValue());
+            //update sm.old
+            System.out.println("CS: updating system metadata...");
+            updateSystemMetadata(sm, sessionData);
+            System.out.println("CS: updated system metadata.");
+            //change the obsoletes field of the new systemMetadata (sm.new) to point to the id of the old one
+            System.out.println("CS: Adding obsoleteGuid to new sysmeta");
+            sysmeta.addObsolete(obsoletedGuid);
+            //insert sm.new
+            System.out.println("CS: inserting new sysmeta");
+            insertSystemMetadata(sysmeta, sessionData);
+            //call update with sm.new.object.id for object
+            //System.out.println("CS: updating old sm");
+            //updateSystemMetadata(sm, sessionData);
+            System.out.println("CS: updating doc");
+            updateDocument(object, obsoletedGuid, guid, sessionData);
+            System.out.println("CS: Done updating document.");
+            return guid;
+        }
+        catch(Exception e)
+        {
+            throw new ServiceFailure(1030, "Error updating document in CrudService: " + e.getMessage());
+        }
     }
 
     /*
@@ -531,6 +568,9 @@
         return newFile;
     }
 
+    /**
+     * insert a systemMetadata doc
+     */
     private void insertSystemMetadata(SystemMetadata sysmeta, SessionData sessionData) 
         throws ServiceFailure {
         logMetacat.debug("Starting to insert SystemMetadata...");
@@ -549,22 +589,124 @@
     }
     
     /**
+     * update a systemMetadata doc
+     */
+    private void updateSystemMetadata(SystemMetadata sm, SessionData sessionData)
+      throws ServiceFailure
+    {
+        try
+        {
+            System.out.println("Updating SystemMetadata with id " + sm.getIdentifier().getValue());
+            String smId = IdentifierManager.getInstance().getSystemMetadataId(sm.getIdentifier().getValue());
+            System.out.println("smId: " + smId);
+            sm.setDateSysMetadataModified(new Date());
+            String xml = new String(serializeSystemMetadata(sm).toByteArray());
+            Identifier id = new Identifier();
+            id.setValue(smId);
+            System.out.println("updating sysmeta doc with new id " + id.getValue());
+            String localId = updateDocument(xml, id, null, sessionData);
+            System.out.println("new updated localId: " + localId);
+            System.out.println("CS: updateDocument returned localId: " + localId);
+            IdentifierManager.getInstance().updateSystemMetadataMapping(sm.getIdentifier().getValue(), localId);
+        }
+        catch(Exception e)
+        {
+            throw new ServiceFailure(1030, "Error updating system metadata: " + e.getMessage());
+        }
+    }
+    
+    /**
+     * insert a document
+     * NOTE: this method shouldn't be used from the update or create() methods.  
+     * we shouldn't be putting the science metadata or data objects into memory.
+     */
+    private String insertDocument(String xml, Identifier guid, SessionData sessionData)
+        throws ServiceFailure
+    {
+        return insertOrUpdateDocument(xml, guid, sessionData, "insert");
+    }
+    
+    /**
+     * insert a document from a stream
+     */
+    private String insertDocument(InputStream is, Identifier guid, SessionData sessionData)
+      throws IOException, ServiceFailure
+    {
+        //HACK: change this eventually.  we should not be converting the stream to a string
+        String xml = IOUtils.toString(is);
+        return insertDocument(xml, guid, sessionData);
+    }
+    
+    /**
+     * update a document
+     * NOTE: this method shouldn't be used from the update or create() methods.  
+     * we shouldn't be putting the science metadata or data objects into memory.
+     */
+    private String updateDocument(String xml, Identifier obsoleteGuid, Identifier guid, SessionData sessionData)
+        throws ServiceFailure
+    {
+        return insertOrUpdateDocument(xml, obsoleteGuid, sessionData, "update");
+    }
+    
+    /**
+     * update a document from a stream
+     */
+    private String updateDocument(InputStream is, Identifier obsoleteGuid, Identifier guid, SessionData sessionData)
+      throws IOException, ServiceFailure
+    {
+        //HACK: change this eventually.  we should not be converting the stream to a string
+        String xml = IOUtils.toString(is);
+        String localId = updateDocument(xml, obsoleteGuid, guid, sessionData);
+        IdentifierManager im = IdentifierManager.getInstance();
+        if(guid != null)
+        {
+          im.createMapping(guid.getValue(), localId);
+        }
+        return localId;
+    }
+    
+    /**
      * insert a document, return the id of the document that was inserted
      */
-    private String insertDocument(String xml, Identifier guid, SessionData sessionData) 
+    private String insertOrUpdateDocument(String xml, Identifier guid, SessionData sessionData, String insertOrUpdate) 
         throws ServiceFailure {
         logMetacat.debug("Starting to insert xml document...");
         IdentifierManager im = IdentifierManager.getInstance();
 
         // generate guid/localId pair for sysmeta
-        String localId = im.generateLocalId(guid.getValue(), 1);
+        String localId = null;
+        if(insertOrUpdate.equals("insert"))
+        {
+            localId = im.generateLocalId(guid.getValue(), 1);
+        }
+        else
+        {
+            //localid should already exist in the identifier table, so just find it
+            try
+            {
+                localId = im.getLocalId(guid.getValue());
+                //increment the revision
+                String docid = localId.substring(0, localId.lastIndexOf("."));
+                String revS = localId.substring(localId.lastIndexOf(".") + 1, localId.length());
+                int rev = new Integer(revS).intValue();
+                rev++;
+                docid = docid + "." + rev;
+                localId = docid;
+            }
+            catch(McdbDocNotFoundException e)
+            {
+                throw new ServiceFailure(1030, "CrudService.insertOrUpdateDocument(): " +
+                    "guid " + guid.getValue() + " should have been in the identifier table, but it wasn't: " + e.getMessage());
+            }
+        }
         logMetacat.debug("Metadata guid|localId: " + guid.getValue() + "|" +
                 localId);
 
         String[] action = new String[1];
-        action[0] = "insert";
+        action[0] = insertOrUpdate;
         params.put("action", action);
         String[] docid = new String[1];
+        System.out.println(insertOrUpdate + "ing with localId " + localId);
         docid[0] = localId;
         params.put("docid", docid);
         String[] doctext = new String[1];
Index: src/edu/ucsb/nceas/metacat/IdentifierManager.java
===================================================================
--- src/edu/ucsb/nceas/metacat/IdentifierManager.java	(revision 5349)
+++ src/edu/ucsb/nceas/metacat/IdentifierManager.java	(revision 5350)
@@ -224,7 +224,53 @@
         createGenericMapping(guid, localId, TYPE_SYSTEM_METADATA);
     }
     
+    public void updateSystemMetadataMapping(String guid, String localId)
+    {
+        int serialNumber = -1;
+        DBConnection dbConn = null;
+        try {
+            // Parse the localId into scope and rev parts
+            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
+            String docid = acc.getDocid();
+            int rev = 1;
+            if(acc.getRev() != null)
+            {
+              rev = (new Integer(acc.getRev()).intValue());
+            }
+
+            // Get a database connection from the pool
+            dbConn = 
+                DBConnectionPool.getDBConnection("Identifier.createMapping");
+            serialNumber = dbConn.getCheckOutSerialNumber();
+
+            // Execute the insert statement
+            String query = "update systemmetadata set (docid, rev) = (?, ?) where guid='" + guid + "'";
+            System.out.println("query: " + query + " for params: (guid:" + guid + ", docid=" + docid + ", rev=" + rev + ")");
+            PreparedStatement stmt = dbConn.prepareStatement(query);
+            stmt.setString(1, docid);
+            stmt.setInt(2, rev);
+            int rows = stmt.executeUpdate();
+
+            stmt.close();
+        } catch (SQLException e) {
+            e.printStackTrace();
+            logMetacat.error("SQL error while updating a mapping to the system metadata identifier: " 
+                    + e.getMessage());
+        } catch (NumberFormatException e) {
+            e.printStackTrace();
+            logMetacat.error("NumberFormat error while updating a mapping to the system metadata identifier: " 
+                    + e.getMessage());
+        } catch (AccessionNumberException e) {
+            e.printStackTrace();
+            logMetacat.error("AccessionNumber error while updating a mapping to the system metadata identifier: " 
+                    + e.getMessage());
+        } finally {
+            // Return database connection to the pool
+            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
+        }
+    }
     
+    
     /**
      * return the localId of a system metadata document based on its guid
      */
