You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@roller.apache.org by sn...@apache.org on 2005/09/21 18:38:16 UTC

svn commit: r290739 - in /incubator/roller/branches/roller_2.0: sandbox/atomprotocol/src/org/roller/presentation/atomapi/ sandbox/atomprotocol/tests/ sandbox/atomprotocol/tests/org/ sandbox/atomprotocol/tests/org/roller/ sandbox/atomprotocol/tests/org/...

Author: snoopdave
Date: Wed Sep 21 09:38:07 2005
New Revision: 290739

URL: http://svn.apache.org/viewcvs?rev=290739&view=rev
Log:
Starting new Atom Protocol impl

Added:
    incubator/roller/branches/roller_2.0/sandbox/atomprotocol/tests/
    incubator/roller/branches/roller_2.0/sandbox/atomprotocol/tests/org/
    incubator/roller/branches/roller_2.0/sandbox/atomprotocol/tests/org/roller/
    incubator/roller/branches/roller_2.0/sandbox/atomprotocol/tests/org/roller/presentation/
    incubator/roller/branches/roller_2.0/sandbox/atomprotocol/tests/org/roller/presentation/atomapi04/
    incubator/roller/branches/roller_2.0/sandbox/atomprotocol/tests/org/roller/presentation/atomapi04/AtomCollectionTest.java
    incubator/roller/branches/roller_2.0/sandbox/atomprotocol/tests/org/roller/presentation/atomapi04/AtomServletTest.java
    incubator/roller/branches/roller_2.0/tests/org/roller/presentation/atomapi04/
      - copied from r289678, incubator/roller/branches/roller_2.0/tests/org/roller/presentation/atomapi/
Removed:
    incubator/roller/branches/roller_2.0/tests/org/roller/presentation/atomapi/
    incubator/roller/branches/roller_2.0/tests/org/roller/presentation/atomapi04/AtomCollectionTest.java
    incubator/roller/branches/roller_2.0/tests/org/roller/presentation/atomapi04/AtomServletTest.java
Modified:
    incubator/roller/branches/roller_2.0/sandbox/atomprotocol/src/org/roller/presentation/atomapi/AtomCollection.java

Modified: incubator/roller/branches/roller_2.0/sandbox/atomprotocol/src/org/roller/presentation/atomapi/AtomCollection.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_2.0/sandbox/atomprotocol/src/org/roller/presentation/atomapi/AtomCollection.java?rev=290739&r1=290738&r2=290739&view=diff
==============================================================================
--- incubator/roller/branches/roller_2.0/sandbox/atomprotocol/src/org/roller/presentation/atomapi/AtomCollection.java (original)
+++ incubator/roller/branches/roller_2.0/sandbox/atomprotocol/src/org/roller/presentation/atomapi/AtomCollection.java Wed Sep 21 09:38:07 2005
@@ -34,31 +34,24 @@
 /*
  * Based on: draft-ietf-atompub-protocol-04.txt 
  * 
- * appCollection = element
- *    app:collection { 
- *       attribute next { text } ?, 
- *       appMember* 
- *    }
+ * appCollection =
+ *    element app:collection {
+ *       ( appMemberType* 
+ *         appSearchTemplate
+ *         & anyElement* )
+ * }
  * 
  * Here is an example Atom collection:
  * 
  * <?xml version="1.0" encoding='utf-8'?> 
- * <collection xmlns="http://purl.org/atom/app#"> 
- * <member href="http://example.org/1"
- *    hrefreadonly="http://example.com/1/bar" 
- *    title="Sample 1"
- *    updated="2003-12-13T18:30:02Z" /> 
- * <member href="http://example.org/2"
- *    hrefreadonly="http://example.com/2/bar" 
- *    title="Sample 2"
- *    updated="2003-12-13T18:30:02Z" /> 
- * <member href="http://example.org/3"
- *    hrefreadonly="http://example.com/3/bar" 
- *    title="Sample 3"
- *    updated="2003-12-13T18:30:02Z" /> 
- * <member href="http://example.org/4"
- *    title="Sample 4" 
- *    updated="2003-12-13T18:30:02Z" /> 
+ * <collection xmlns="http://purl.org/atom/app">
+ *    <member-type>text</member-type>
+ *    <member-type>html</member-type>
+ *    <member-type>xhtml</member-type>
+ *    <member-type>src</member-type>
+ *    <member-type>generic</member-type>
+ *    <search-template>http://example.org/{index}</search-template>
+ *    <search-template>http://example.org/d/{daterange}</search-template>
  * </collection>
  */
 public class AtomCollection
@@ -66,100 +59,27 @@
     public static final Namespace ns = 
         Namespace.getNamespace("http://purl.org/atom/app#");
     
-    private static SimpleDateFormat df =
-        new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ssZ" );
-    private String next    = null;
-    private List   members = new ArrayList();
+    private List memberTypes = new ArrayList(); // array of strings
+    private String dateRangeTemplate = null;
+    private String indexTemplate = null;
 
     public AtomCollection()
     {
     }
-
-    /** URI of collection containing member elements updated earlier in time */
-    public String getNext()
-    {
-        return next;
-    }
-
-    public void setNext(String next)
-    {
-        this.next = next;
-    }
-
-    public List getMembers()
-    {
-        return members;
-    }
-
-    public void setMembers(List members)
+    
+    public List getMemberTypes()
     {
-        this.members = members;
+        return memberTypes;
     }
 
-    public void addMember(Member member)
+    public void setMemberTypes(List memberTypes)
     {
-        members.add(member);
+        this.memberTypes = memberTypes;
     }
 
-    /** Models an Atom collection member */
-    /*
-     * appMember = element app:member { attribute title { text }, attribute href {
-     * text }, attribute hrefreadonly { text } ?, attribute updated { text } }
-     */
-    public static class Member
+    public void addMemberType(String memberType)
     {
-        private String title;
-        private String href;
-        private String hrefreadonly;
-        private Date   updated;
-
-        public Member()
-        {
-        }
-
-        /** Human readable title */
-        public String getTitle()
-        {
-            return title;
-        }
-
-        public void setTitle(String title)
-        {
-            this.title = title;
-        }
-
-        /** The URI used to edit the member source */
-        public String getHref()
-        {
-            return href;
-        }
-
-        public void setHref(String href)
-        {
-            this.href = href;
-        }
-
-        /** The URI for readonly access to member source */
-        public String getHrefreadonly()
-        {
-            return hrefreadonly;
-        }
-
-        public void setHrefreadonly(String hrefreadonly)
-        {
-            this.hrefreadonly = hrefreadonly;
-        }
-
-        /** Same as updated value of collection member */
-        public Date getUpdated()
-        {
-            return updated;
-        }
-
-        public void setUpdated(Date updated)
-        {
-            this.updated = updated;
-        }
+        memberTypes.add(memberType);
     }
 
     /** Deserialize an Atom Collection XML document into an object */
@@ -168,17 +88,17 @@
     {
         AtomCollection collection = new AtomCollection();
         Element root = document.getRootElement();
-        if (root.getAttribute("next") != null)
-        {
-            collection.setNext(root.getAttribute("next").getValue());
-        }
-        List mems = root.getChildren("member", ns);
-        Iterator iter = mems.iterator();
-        while (iter.hasNext())
-        {
-            Element e = (Element) iter.next();
-            collection.addMember(AtomCollection.elementToMember(e));
-        }
+//        if (root.getAttribute("next") != null)
+//        {
+//            collection.setNext(root.getAttribute("next").getValue());
+//        }
+//        List mems = root.getChildren("member", ns);
+//        Iterator iter = mems.iterator();
+//        while (iter.hasNext())
+//        {
+//            Element e = (Element) iter.next();
+//            collection.addMember(AtomCollection.elementToMember(e));
+//        }
         return collection;
     }
 
@@ -186,78 +106,19 @@
     public static Document collectionToDocument(AtomCollection collection)
     {
         Document doc = new Document();
-        Element root = new Element("collection", ns);
-        doc.setRootElement(root);
-        if (collection.getNext() != null)
-        {
-            root.setAttribute("next", collection.getNext());
-        }
-        Iterator iter = collection.getMembers().iterator();
-        while (iter.hasNext())
-        {
-            Member member = (Member) iter.next();
-            root.addContent(AtomCollection.memberToElement(member));
-        }
+//        Element root = new Element("collection", ns);
+//        doc.setRootElement(root);
+//        if (collection.getNext() != null)
+//        {
+//            root.setAttribute("next", collection.getNext());
+//        }
+//        Iterator iter = collection.getMembers().iterator();
+//        while (iter.hasNext())
+//        {
+//            Member member = (Member) iter.next();
+//            root.addContent(AtomCollection.memberToElement(member));
+//        }
         return doc;
     }
 
-    /** Deserialize an Atom collection member XML element into an object */
-    public static Member elementToMember(Element element) throws Exception
-    {
-        Member member = new Member();
-        member.setTitle(element.getAttribute("title").getValue());
-        member.setHref(element.getAttribute("href").getValue());
-        if (element.getAttribute("href") != null)
-        {
-            member.setHref(element.getAttribute("href").getValue());
-        }
-        member.setUpdated(df.parse(element.getAttribute("updated").getValue()));
-        return member;
-    }
-
-    /** Serialize a collection member into an XML element */
-    public static Element memberToElement(Member member)
-    {
-        Element element = new Element("member", ns);
-        element.setAttribute("title", member.getTitle()); // TODO: escape/strip HTML?
-        element.setAttribute("href", member.getHref());
-        if (member.getHrefreadonly() != null)
-        {
-            element.setAttribute("hrefreadonly", member.getHrefreadonly());
-        }
-        element.setAttribute("updated", df.format(member.getUpdated()));
-        return element;
-    }
-
-    /** Start and end date range */
-    public static class Range { Date start=null; Date end=null; }
-    
-    /** Parse HTTP Range header into a start and end date range */
-    public static Range parseRange(String rangeString) throws ParseException 
-    {
-        // Range: updated=<isodate>/<isodate>   
-        // Range: updated=<isodate>/ 
-        // Range: updated=/<isodate>  
-
-        Range range = new Range();
-        String[] split = rangeString.split("=");
-        if (split[1].startsWith("/")) 
-        {
-            // we have only end date
-            range.end = df.parse(split[1].split("/")[1]);
-        }
-        else if (split[1].endsWith("/"))
-        {
-            // we have only start date
-            range.start = df.parse(split[1].split("/")[0]);
-        }
-        else
-        {
-            // both dates present
-            String[] dates = split[1].split("/");
-            range.start = df.parse(dates[0]);
-            range.end = df.parse(dates[1]);
-        }
-        return range;
-    }
 }

Added: incubator/roller/branches/roller_2.0/sandbox/atomprotocol/tests/org/roller/presentation/atomapi04/AtomCollectionTest.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_2.0/sandbox/atomprotocol/tests/org/roller/presentation/atomapi04/AtomCollectionTest.java?rev=290739&view=auto
==============================================================================
--- incubator/roller/branches/roller_2.0/sandbox/atomprotocol/tests/org/roller/presentation/atomapi04/AtomCollectionTest.java (added)
+++ incubator/roller/branches/roller_2.0/sandbox/atomprotocol/tests/org/roller/presentation/atomapi04/AtomCollectionTest.java Wed Sep 21 09:38:07 2005
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2005 David M Johnson (For RSS and Atom In Action)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.roller.presentation.atomapi04;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.jdom.Document;
+import org.roller.presentation.atomapi.AtomCollection;
+import org.roller.presentation.atomapi.AtomService;
+
+/**
+ * @author Dave Johnson
+ */
+public class AtomCollectionTest extends TestCase {
+    
+    private static SimpleDateFormat df =
+        new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ssZ" );
+   
+    /** Creates a new instance of AtomCollectionTest */
+    public AtomCollectionTest() {
+    }
+
+    public void testRangeParsing() throws Exception {
+        Date end = new Date(); // now 
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(end);
+        cal.add(Calendar.DATE, -1);
+        Date start = cal.getTime(); // one day ago
+        String startString = df.format(start);
+        String endString = df.format(end);
+        
+        String r1 = "Range: updated="+startString+"/"+endString;
+        AtomCollection.Range range = AtomCollection.parseRange(r1);
+        assertNotNull(range.start);
+        assertNotNull(range.end);
+        
+        String r2 = "Range: updated="+startString+"/";
+        range = AtomCollection.parseRange(r2);
+        assertNotNull(range.start);
+        assertNull(range.end);
+        
+        String r3 = "Range: updated="+"/"+endString;
+        range = AtomCollection.parseRange(r3);
+        assertNull(range.start);
+        assertNotNull(range.end);
+    }
+    
+    public void testCollectionBean() throws Exception {
+        
+        // create a collection with a member
+        Date date1 = new Date();
+        AtomCollection collection = new AtomCollection();
+        AtomCollection.Member member1 = new AtomCollection.Member();
+        member1.setTitle("title1");
+        member1.setHref("http://example.com/item1");
+        member1.setUpdated(date1);
+        collection.addMember(member1);
+        
+        // add another member
+        Date date2 = new Date();
+        AtomCollection.Member member2 = new AtomCollection.Member();
+        member2.setTitle("title2");
+        member2.setHref("http://example.com/item2");
+        member2.setUpdated(date2);
+        collection.addMember(member2);
+        
+        // serialize to XML
+        Document doc = AtomCollection.collectionToDocument(collection);
+        assertEquals("collection", doc.getRootElement().getName());
+        assertEquals(2, doc.getRootElement().getContent().size());
+        
+        // deserialize from XML and assert we've got the same stuff
+        AtomCollection col2 = AtomCollection.documentToCollection(doc);
+        assertEquals(2, col2.getMembers().size());
+        
+        AtomCollection.Member m1 = (AtomCollection.Member)col2.getMembers().get(0);
+        assertEquals("title1", m1.getTitle());
+        assertEquals("http://example.com/item1", m1.getHref());
+        assertCloseEnough(date1, m1.getUpdated());
+        
+        AtomCollection.Member m2 = (AtomCollection.Member)col2.getMembers().get(1);
+        assertEquals("title2", m2.getTitle());
+        assertEquals("http://example.com/item2", m2.getHref());
+        assertCloseEnough(date2, m2.getUpdated());
+    }
+    
+    public void testServiceBean() {
+        
+        AtomService.Collection collection = new AtomService.Collection();
+        collection.setTitle("All blog entries");
+        collection.setContents("entries");
+        collection.setHref("http://example.com/collection1");
+        
+        AtomService.Workspace workspace = new AtomService.Workspace();
+        workspace.setTitle("My blog");
+        workspace.addCollection(collection);
+        
+        AtomService service = new AtomService();
+        service.addWorkspace(workspace);
+
+        // serialize to XML
+        Document doc = AtomService.serviceToDocument(service);
+        assertEquals("service", doc.getRootElement().getName());
+        assertEquals(1, doc.getRootElement().getContent().size());
+  
+        // deserialize from XML and assert we've got the same stuff
+        AtomService service2 = AtomService.documentToService(doc);
+        
+        AtomService.Workspace workspace2 = 
+            (AtomService.Workspace)service2.getWorkspaces().get(0);
+        assertEquals("My blog", workspace2.getTitle());
+        
+        AtomService.Collection collection2 = 
+            (AtomService.Collection)workspace2.getCollections().get(0);
+        assertEquals("All blog entries", collection2.getTitle());
+        assertEquals("entries", collection.getContents());
+        assertEquals("http://example.com/collection1", collection2.getHref());
+    }
+
+    /** Compare times ignoring milliseconds */
+    public void assertCloseEnough(Date d1, Date d2) {
+        long t1 = d1.getTime() - d1.getTime() % 1000;
+        long t2 = d2.getTime() - d2.getTime() % 1000;
+        assertEquals(t1, t2);
+    }
+    
+    public static Test suite() {
+		TestSuite suite = new TestSuite();
+		suite.addTest(new TestSuite(AtomCollectionTest.class));
+		return suite;
+	}
+}

Added: incubator/roller/branches/roller_2.0/sandbox/atomprotocol/tests/org/roller/presentation/atomapi04/AtomServletTest.java
URL: http://svn.apache.org/viewcvs/incubator/roller/branches/roller_2.0/sandbox/atomprotocol/tests/org/roller/presentation/atomapi04/AtomServletTest.java?rev=290739&view=auto
==============================================================================
--- incubator/roller/branches/roller_2.0/sandbox/atomprotocol/tests/org/roller/presentation/atomapi04/AtomServletTest.java (added)
+++ incubator/roller/branches/roller_2.0/sandbox/atomprotocol/tests/org/roller/presentation/atomapi04/AtomServletTest.java Wed Sep 21 09:38:07 2005
@@ -0,0 +1,448 @@
+package org.roller.presentation.atomapi04;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.jdom.Document;
+import org.jdom.input.SAXBuilder;
+import org.roller.RollerTestBase;
+import org.roller.model.WeblogManager;
+import org.roller.pojos.UserData;
+import org.roller.pojos.WeblogEntryData;
+import org.roller.pojos.WebsiteData;
+import org.roller.presentation.MockRollerContext;
+import org.roller.presentation.atomapi.AtomCollection;
+import org.roller.presentation.atomapi.AtomService;
+import org.roller.presentation.atomapi.AtomServlet;
+import org.roller.presentation.atomapi.WSSEUtilities;
+import org.roller.util.Utilities;
+
+import com.mockrunner.mock.web.ActionMockObjectFactory;
+import com.mockrunner.mock.web.MockHttpServletRequest;
+import com.mockrunner.mock.web.MockHttpServletResponse;
+import com.mockrunner.mock.web.MockServletContext;
+import com.mockrunner.mock.web.WebMockObjectFactory;
+import com.mockrunner.servlet.ServletTestModule;
+import com.mockrunner.struts.ActionTestModule;
+import com.sun.syndication.feed.atom.Content;
+import com.sun.syndication.feed.atom.Entry;
+
+/**
+ * Test new Rome based Atom API implementation.
+ * @author David M Johnson
+ */
+public class AtomServletTest extends RollerTestBase
+{    
+    private ActionMockObjectFactory mockFactory;
+    protected MockRollerContext rollerContext;
+    protected ActionTestModule strutsModule;
+    private ServletTestModule servletModule;
+    private static SimpleDateFormat df =
+        new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ssZ" );
+
+    protected WebMockObjectFactory getMockFactory()
+    {
+        if (mockFactory == null) 
+        {
+            mockFactory = new ActionMockObjectFactory();
+        }
+        return mockFactory;
+    }
+    
+    //------------------------------------------------------------------------------
+    /** 
+     * Test get of introspection URI
+     */
+    public void testGetIntrospection() throws Exception
+    {
+        UserData user = (UserData)mUsersCreated.get(0);        
+                
+        MockHttpServletRequest mockRequest = getMockFactory().getMockRequest();
+        mockRequest.addHeader("X-WSSE", 
+                generateWSSEHeader(user.getUserName(), user.getPassword()));
+        mockRequest.setContextPath("/atom");
+        mockRequest.setPathInfo("/" + user.getUserName());
+        getServletModule().doGet();
+
+        String output = getServletModule().getOutput();
+        SAXBuilder builder = new SAXBuilder();
+        Document doc = builder.build(new StringReader(output));
+        
+        AtomService service = AtomService.documentToService(doc);
+        assertEquals(1, service.getWorkspaces().size());
+    }
+
+    //------------------------------------------------------------------------------
+    /** 
+     * Test get of entries collection URI
+     */
+    public void testGetEntriesCollection() throws Exception
+    {
+        UserData user = (UserData)mUsersCreated.get(0);        
+                
+        // get entries collection
+        MockHttpServletRequest mockRequest = getMockFactory().getMockRequest();
+        mockRequest.addHeader("X-WSSE", 
+                generateWSSEHeader(user.getUserName(), user.getPassword()));
+        mockRequest.setContextPath("/atom");
+        mockRequest.setPathInfo("/" + user.getUserName() + "/entries");
+        getServletModule().doGet();
+        
+        // assert that we got 20 entries
+        String output = getServletModule().getOutput();
+        SAXBuilder builder = new SAXBuilder();
+        Document doc = builder.build(new StringReader(output));
+        AtomCollection col = AtomCollection.documentToCollection(doc);
+        assertEquals(20, col.getMembers().size());
+        
+        // use collection next URI to get next batch of entries
+        resetMocks();
+        String[] next = Utilities.stringToStringArray(col.getNext(), "/");
+        
+        mockRequest = getMockFactory().getMockRequest();
+        mockRequest.addHeader("X-WSSE", 
+            generateWSSEHeader(user.getUserName(), user.getPassword()));
+        mockRequest.setContextPath("/atom");
+        mockRequest.setPathInfo(
+            "/" + user.getUserName() + "/entries/" + next[next.length-1]);
+        getServletModule().doGet();
+
+        // assert that we got another 20 entries
+        output = getServletModule().getOutput();
+        doc = builder.build(new StringReader(output));
+        col = AtomCollection.documentToCollection(doc);
+        assertEquals(10, col.getMembers().size());   
+    }
+
+    //------------------------------------------------------------------------------
+    /** 
+     * Test get of entries collection URI with a range
+     */
+    public void testGetEntriesCollectionRange() throws Exception
+    {
+        UserData user = (UserData)mUsersCreated.get(0);     
+        
+        Date end = new Date(); // now 
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(end);
+        cal.add(Calendar.DATE, -30);
+        Date start = cal.getTime(); // one day ago
+        String startString = df.format(start);
+        String endString = df.format(end);
+        
+        // get entries collection
+        MockHttpServletRequest mockRequest = getMockFactory().getMockRequest();
+        mockRequest.addHeader("X-WSSE", 
+            generateWSSEHeader(user.getUserName(), user.getPassword()));
+        mockRequest.addHeader("Range",
+            "updated=" + startString + "/" + endString);
+        mockRequest.setContextPath("/atom");
+        mockRequest.setPathInfo("/" + user.getUserName() + "/entries");
+        getServletModule().doGet();
+        
+        // assert that we got 20 entries
+        String output = getServletModule().getOutput();
+        SAXBuilder builder = new SAXBuilder();
+        Document doc = builder.build(new StringReader(output));
+        AtomCollection col = AtomCollection.documentToCollection(doc);
+        assertEquals(20, col.getMembers().size());
+        
+        // use collection next URI to get next batch of entries
+        resetMocks();
+        String[] next = Utilities.stringToStringArray(col.getNext(), "/");
+        
+        mockRequest = getMockFactory().getMockRequest();
+        mockRequest.addHeader("X-WSSE", 
+            generateWSSEHeader(user.getUserName(), user.getPassword()));
+        mockRequest.setContextPath("/atom");
+        mockRequest.setPathInfo("/" + user.getUserName() + "/entries");
+        mockRequest.setQueryString("Range=updated="+startString+"/"+endString);
+        getServletModule().doGet();
+
+        // assert that we got another 20 entries
+        output = getServletModule().getOutput();
+        doc = builder.build(new StringReader(output));
+        col = AtomCollection.documentToCollection(doc);
+        assertEquals(20, col.getMembers().size());   
+    }
+
+    //------------------------------------------------------------------------------
+    /** 
+     * Test that GET on the EditURI returns an entry.
+     */
+    public void testGetEntry() throws Exception
+    {
+        UserData user = (UserData)mUsersCreated.get(0);
+        WebsiteData website = (WebsiteData)
+            getRoller().getUserManager().getWebsites(user, null).get(0);
+        WeblogEntryData entry = (WeblogEntryData) 
+            getRoller().getWeblogManager().getWeblogEntries(
+                website, null, null, null, null, new Integer(1)).get(0);
+
+        Entry fetchedEntry = getEntry(user, entry.getId());
+        assertEquals(entry.getId(), fetchedEntry.getId());
+    }
+    
+    //------------------------------------------------------------------------------
+    /** 
+     * Test that POST to the PostURI returns an entry.
+     */
+    public void testPostEntry() throws Exception
+    {
+        UserData user = (UserData)mUsersCreated.get(0);        
+        
+        // Create an entry in a feed, so Rome can handle it
+        Content content = new Content();
+        content.setMode(Content.ESCAPED);
+        content.setValue("test entry text");
+        List contents = new ArrayList();
+        contents.add(content);
+
+        Entry entry = new Entry();
+        entry.setTitle("test entry title");
+        entry.setContents(contents);
+        
+        StringWriter entryWriter = new StringWriter();
+        AtomServlet.serializeEntry(entry, entryWriter);
+        
+        MockHttpServletRequest mockRequest = getMockFactory().getMockRequest();
+        mockRequest.setContextPath("/atom");
+        mockRequest.setPathInfo(user.getUserName() + "/entries/");
+        mockRequest.addHeader("X-WSSE", 
+                generateWSSEHeader(user.getUserName(), user.getPassword()));
+        mockRequest.setBodyContent(entryWriter.toString());
+        getServletModule().doPost();
+
+        String output = getServletModule().getOutput();
+        Entry returnedEntry = AtomServlet.parseEntry(new StringReader(output));        
+        assertEquals(returnedEntry.getTitle(), entry.getTitle());
+        
+        MockHttpServletResponse mockResponse = getMockFactory().getMockResponse();
+        assertEquals(HttpServletResponse.SC_CREATED, mockResponse.getStatusCode());
+        assertTrue(mockResponse.containsHeader("Location"));
+       
+        getRoller().release();
+        resetMocks();
+
+        Entry fetchedEntry = getEntry(user, returnedEntry.getId());
+        assertEquals(returnedEntry.getId(), fetchedEntry.getId());
+    }
+    
+    //------------------------------------------------------------------------------
+    /** 
+     * Test that PUT on the EditURI updates an entry.
+     */
+    public void testPutEntry() throws Exception
+    {
+        UserData user = (UserData)mUsersCreated.get(0);
+        WebsiteData website = (WebsiteData)
+            getRoller().getUserManager().getWebsites(user, null).get(0);        
+        
+        WeblogEntryData entry = (WeblogEntryData) 
+            getRoller().getWeblogManager().getWeblogEntries(
+                website, null, null, null, null, new Integer(1)).get(0);
+        
+        // Fetch that entry using Atom
+        Entry fetchedEntry = getEntry(user, entry.getId());
+        assertEquals(entry.getId(), fetchedEntry.getId());
+        
+        // Make a change to the fetched entry
+        fetchedEntry.setTitle("TEST TITLE");
+        
+        // Use Atom PUT to update the entry
+        StringWriter entryWriter = new StringWriter();
+        AtomServlet.serializeEntry(fetchedEntry, entryWriter);
+        MockHttpServletRequest mockRequest2 = getMockFactory().getMockRequest();
+        mockRequest2.setContextPath("/atom");
+        mockRequest2.setPathInfo(user.getUserName() + "/entry/" + entry.getId());
+        mockRequest2.addHeader("X-WSSE", 
+           generateWSSEHeader(user.getUserName(), user.getPassword()));
+        mockRequest2.setBodyContent(entryWriter.toString());
+        getServletModule().doPut();      
+        
+        getRoller().release();
+        resetMocks();
+
+        // Get the entry again to make sure the update was made
+        Entry fetchedEntry2 = getEntry(user, entry.getId());
+        assertEquals(fetchedEntry.getTitle(), fetchedEntry2.getTitle());
+    }
+    
+    //------------------------------------------------------------------------------
+    /** 
+     * Test that DELETE on EditURI deletes entry. 
+     */
+    public void testDeleteEntry() throws Exception
+    {
+        UserData user = (UserData)mUsersCreated.get(0);
+        WebsiteData website = (WebsiteData)
+            getRoller().getUserManager().getWebsites(user, null).get(0);        
+
+        WeblogEntryData entry = (WeblogEntryData) 
+            getRoller().getWeblogManager().getWeblogEntries(
+                website, null, null, null, null, new Integer(1)).get(0);
+
+        Entry fetchedEntry = getEntry(user, entry.getId());
+        assertEquals(entry.getId(), fetchedEntry.getId());
+
+        // Use Atom DELETE to delete the entry
+        MockHttpServletRequest mockRequest2 = getMockFactory().getMockRequest();
+        mockRequest2.setContextPath("/atom");
+        mockRequest2.setPathInfo(user.getUserName() + "/entry/" + entry.getId());
+        mockRequest2.addHeader("X-WSSE", 
+                generateWSSEHeader(user.getUserName(), user.getPassword()));
+        getServletModule().doDelete();      
+        getRoller().release();
+        resetMocks();
+        try 
+        {
+            getEntry(user, entry.getId()).getId();
+            fail(); // no exception was thrown!
+        }
+        catch (Exception expected) {}
+    }
+
+     //------------------------------------------------------------------------------
+    private Entry getEntry(UserData user, String id) throws Exception
+    {
+        MockHttpServletRequest mockRequest = getMockFactory().getMockRequest();
+        mockRequest.setContextPath("/atom");
+        mockRequest.setPathInfo(user.getUserName() + "/entry/" + id);
+        mockRequest.addHeader("X-WSSE", 
+                generateWSSEHeader(user.getUserName(), user.getPassword()));
+        getServletModule().doGet();
+
+        String output = getServletModule().getOutput();
+        return AtomServlet.parseEntry(new StringReader(output));        
+    }
+    
+    //------------------------------------------------------------------------------
+    public void testPostResource() throws Exception 
+    {    
+        UserData user = (UserData)mUsersCreated.get(0);      
+        
+        // read test file into byte array
+        String fileName = "rssbadge.gif";
+        File testFile = new File(fileName);
+        FileInputStream fis = new FileInputStream(testFile);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Utilities.copyInputToOutput(fis, baos);
+        
+        // post file as resource
+        MockHttpServletRequest mockRequest = getMockFactory().getMockRequest();
+        mockRequest.setContextPath("/atom");
+        mockRequest.setPathInfo(user.getUserName() + "/resources/");
+        mockRequest.addHeader("Name", fileName); 
+        mockRequest.addHeader("X-WSSE", 
+                generateWSSEHeader(user.getUserName(), user.getPassword()));        
+        mockRequest.setBodyContent(baos.toByteArray());
+        getServletModule().doPost();
+        
+        MockHttpServletResponse mockResponse = getMockFactory().getMockResponse();
+        assertEquals(HttpServletResponse.SC_CREATED, mockResponse.getStatusCode());
+        assertTrue(mockResponse.containsHeader("Location"));
+        
+        getRoller().release();
+        resetMocks();
+    }
+
+    //------------------------------------------------------------------------------
+    public void setUp() throws Exception
+    {
+        super.setUp();       
+        super.setUpTestWeblogs();        
+        resetMocks();
+        MockServletContext ctx = getMockFactory().getMockServletContext();
+        ctx.setRealPath("/", "");
+        rollerContext = new MockRollerContext();
+        rollerContext.init(ctx);
+    }
+
+    //------------------------------------------------------------------------------
+    /** 
+     * Really really reset mocks.
+     */
+    private void resetMocks() 
+    {
+        mockFactory = null;
+        getMockFactory().refresh();
+        getMockFactory().getMockRequest().clearParameters();
+        getMockFactory().getMockRequest().clearAttributes();
+        setServletModule(new ServletTestModule(getMockFactory()));        
+        getServletModule().setServlet(
+            getServletModule().createServlet(AtomServlet.class));
+        getServletModule().clearOutput();
+    }
+    
+    //------------------------------------------------------------------------------
+    /**
+     * @param servletModule The servletModule to set.
+     */
+    protected void setServletModule(ServletTestModule servletModule)
+    {
+        this.servletModule = servletModule;
+    }
+
+    //------------------------------------------------------------------------------
+    /**
+     * @return Returns the servletModule.
+     */
+    protected ServletTestModule getServletModule()
+    {
+        return servletModule;
+    }   
+
+    //------------------------------------------------------------------------------
+    public void tearDown() throws Exception
+    {
+        super.tearDown();
+        super.tearDownTestWeblogs();
+    }   
+    
+    //------------------------------------------------------------------------
+    public static Test suite()
+    {
+        return new TestSuite(AtomServletTest.class);
+    }
+
+    //------------------------------------------------------------------------------
+    public static String generateWSSEHeader(String username, String password)
+        throws Exception
+    {  
+        byte[] nonceBytes = Long.toString(new Date().getTime()).getBytes();
+        String nonce = new String(WSSEUtilities.base64Encode(nonceBytes));
+        
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+        String created = sdf.format(new Date());
+        
+        String digest = WSSEUtilities.generateDigest(
+                nonceBytes, created.getBytes("UTF-8"), password.getBytes("UTF-8"));
+        
+        StringBuffer header = new StringBuffer("UsernameToken Username=\"");
+        header.append(username);
+        header.append("\", ");
+        header.append("PasswordDigest=\"");
+        header.append(digest);
+        header.append("\", ");
+        header.append("Nonce=\"");
+        header.append(nonce);
+        header.append("\", ");
+        header.append("Created=\"");
+        header.append(created);
+        header.append("\"");
+        return header.toString();
+    }
+}