You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tuscany.apache.org by lr...@apache.org on 2008/08/09 18:50:31 UTC

svn commit: r684294 - in /tuscany/java/sca/modules/binding-atom-abdera: ./ src/main/java/org/apache/tuscany/sca/binding/atom/provider/ src/test/java/org/apache/tuscany/sca/binding/atom/

Author: lresende
Date: Sat Aug  9 09:50:30 2008
New Revision: 684294

URL: http://svn.apache.org/viewvc?rev=684294&view=rev
Log:
TUSCANY-2477 - Applying Dan's patch that addes support for eTag and last-modified headers

Added:
    tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomTestCaseUtils.java   (with props)
    tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderEntryEntityTagsTest.java   (with props)
    tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderFeedEntityTagsTest.java   (with props)
Modified:
    tuscany/java/sca/modules/binding-atom-abdera/pom.xml
    tuscany/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingInvoker.java
    tuscany/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingListenerServlet.java

Modified: tuscany/java/sca/modules/binding-atom-abdera/pom.xml
URL: http://svn.apache.org/viewvc/tuscany/java/sca/modules/binding-atom-abdera/pom.xml?rev=684294&r1=684293&r2=684294&view=diff
==============================================================================
--- tuscany/java/sca/modules/binding-atom-abdera/pom.xml (original)
+++ tuscany/java/sca/modules/binding-atom-abdera/pom.xml Sat Aug  9 09:50:30 2008
@@ -81,7 +81,7 @@
         <dependency>
             <groupId>org.apache.abdera</groupId>
             <artifactId>abdera-core</artifactId>
-            <version>0.3.0-incubating</version> 
+            <version>0.4.0-incubating</version> 
             <exclusions>
                 <exclusion>
                     <groupId>org.apache.geronimo.specs</groupId>
@@ -93,7 +93,7 @@
         <dependency>
            <groupId>org.apache.abdera</groupId>
             <artifactId>abdera-parser</artifactId>
-            <version>0.3.0-incubating</version>
+            <version>0.4.0-incubating</version>
             <exclusions>
                 <exclusion>
                     <groupId>stax</groupId>
@@ -105,6 +105,12 @@
                 </exclusion>
             </exclusions>
         </dependency>           
+        
+        <dependency>
+            <groupId>org.apache.abdera</groupId>
+            <artifactId>abdera-client</artifactId>
+            <version>0.4.0-incubating</version> 
+        </dependency>            
                 
         <dependency>
             <groupId>javax.servlet</groupId>

Modified: tuscany/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingInvoker.java
URL: http://svn.apache.org/viewvc/tuscany/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingInvoker.java?rev=684294&r1=684293&r2=684294&view=diff
==============================================================================
--- tuscany/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingInvoker.java (original)
+++ tuscany/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingInvoker.java Sat Aug  9 09:50:30 2008
@@ -86,7 +86,6 @@
 
         @Override
         public Message invoke(Message msg) {
-
             // Get an entry
             String id = (String)((Object[])msg.getBody())[0];
 
@@ -100,7 +99,8 @@
 
                 // Read the Atom entry
                 if (status == 200) {
-                    Document<org.apache.abdera.model.Entry> doc = abderaParser.parse(new InputStreamReader(getMethod.getResponseBodyAsStream()));
+                    Document<org.apache.abdera.model.Entry> doc = 
+                    	abderaParser.parse(new InputStreamReader(getMethod.getResponseBodyAsStream()));
                     parsing = true;
                     org.apache.abdera.model.Entry feedEntry = doc.getRoot();
                     
@@ -148,7 +148,6 @@
 
         @Override
         public Message invoke(Message msg) {
-
             // Post an entry
             Object[] args = (Object[])msg.getBody();
             org.apache.abdera.model.Entry feedEntry;
@@ -173,7 +172,8 @@
                 // Write the Atom entry
                 StringWriter writer = new StringWriter();
                 feedEntry.writeTo(writer);
-                postMethod.setRequestHeader("Content-type", "application/atom+xml; charset=utf-8");
+                // postMethod.setRequestHeader("Content-type", "application/atom+xml; charset=utf-8");
+                postMethod.setRequestHeader("Content-type", "application/atom+xml;type=entry");
                 postMethod.setRequestEntity(new StringRequestEntity(writer.toString()));
 
                 httpClient.executeMethod(postMethod);
@@ -228,7 +228,6 @@
 
         @Override
         public Message invoke(Message msg) {
-
             // Put an entry
             Object[] args = (Object[])msg.getBody();
             String id;
@@ -250,6 +249,7 @@
             // Send an HTTP PUT
             PutMethod putMethod = new PutMethod(uri + "/" + id);
             putMethod.setRequestHeader("Authorization", authorizationHeader);
+
             try {
 
                 // Write the Atom entry
@@ -260,7 +260,7 @@
 
                 httpClient.executeMethod(putMethod);
                 int status = putMethod.getStatusCode();
-                if (status == 200 || status == 201) {
+                if (status == 200 || status == 201 || status == 412) {
 
                     msg.setBody(null);
 
@@ -291,7 +291,6 @@
 
         @Override
         public Message invoke(Message msg) {
-
             // Delete an entry
             String id = (String)((Object[])msg.getBody())[0];
 
@@ -331,7 +330,6 @@
 
         @Override
         public Message invoke(Message msg) {
-
             // Get a feed
 
             // Send an HTTP GET
@@ -341,6 +339,7 @@
             try {
                 httpClient.executeMethod(getMethod);
                 int status = getMethod.getStatusCode();
+                // AtomBindingInvoker.printResponseHeader( getMethod );
 
                 // Read the Atom feed
                 if (status == 200) {
@@ -396,7 +395,6 @@
 
         @Override
         public Message invoke(Message msg) {
-
             // Get a feed from a query
             String queryString = (String)((Object[])msg.getBody())[0];
 

Modified: tuscany/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingListenerServlet.java
URL: http://svn.apache.org/viewvc/tuscany/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingListenerServlet.java?rev=684294&r1=684293&r2=684294&view=diff
==============================================================================
--- tuscany/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingListenerServlet.java (original)
+++ tuscany/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingListenerServlet.java Sat Aug  9 09:50:30 2008
@@ -26,6 +26,8 @@
 import java.io.UnsupportedEncodingException;
 import java.io.Writer;
 import java.net.URLDecoder;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 import java.util.StringTokenizer;
 import java.util.logging.Logger;
 
@@ -37,6 +39,7 @@
 
 import org.apache.abdera.Abdera;
 import org.apache.abdera.factory.Factory;
+import org.apache.abdera.i18n.iri.IRI;
 import org.apache.abdera.model.Collection;
 import org.apache.abdera.model.Document;
 import org.apache.abdera.model.Feed;
@@ -58,7 +61,6 @@
 import org.apache.tuscany.sca.invocation.MessageFactory;
 import org.apache.tuscany.sca.runtime.RuntimeWire;
 
-
 /**
  * A resource collection binding listener, implemented as a Servlet and
  * registered in a Servlet host provided by the SCA hosting runtime.
@@ -71,6 +73,11 @@
 
     private static final Factory abderaFactory = Abdera.getNewFactory();
     private static final Parser abderaParser = Abdera.getNewParser();
+    private static final String ETAG = "ETag";
+    private static final String LASTMODIFIED = "Last-Modified";    
+    private static final String LOCATION = "Location";    
+    private static final String CONTENTLOCATION = "Content-Location";    
+    private static final SimpleDateFormat dateFormat = new SimpleDateFormat( "EEE, dd MMM yyyy HH:mm:ss Z" ); // RFC 822 date time
     
     private RuntimeWire wire;
     private Invoker getFeedInvoker;
@@ -248,18 +255,76 @@
                     } else {
                         feed.setTitle("Feed");
                     }
+                    // All feeds must provide Id and updated elements.
+                    // However, some do not, so provide some program protection.
+                    feed.setId( "Feed" + feed.hashCode());
+                    Date lastModified = new Date( 0 );
                     
                     // Add entries to the feed
                     for (Entry<Object, Object> entry: collection) {
                         org.apache.abdera.model.Entry feedEntry = feedEntry(entry, itemClassType, itemXMLType, mediator, abderaFactory);
+                        // Use the most recent entry update as the feed update
+                        Date entryUpdated = feedEntry.getUpdated();
+                        if (( entryUpdated != null ) && (entryUpdated.compareTo( lastModified  ) > 0 ))
+                        	lastModified = entryUpdated;
                         feed.addEntry(feedEntry);
                     }
+                    // If no entries were newly updated,
+                    if ( lastModified.compareTo( new Date( 0 ) ) == 0 ) 
+                    	lastModified = new Date();
                 }
             }
             if (feed != null) {
+                String feedETag = "\"" + generateFeedETag( feed ) + "\"";
+                Date feedUpdated = feed.getUpdated();
+                // Test request for predicates.
+                String predicate = request.getHeader( "If-Match" );
+                if (( predicate != null ) && ( !predicate.equals(feedETag) )) {
+                	// No match, should short circuit
+                    response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
+                    return;
+                }
+                predicate = request.getHeader( "If-None-Match" );
+                if (( predicate != null ) && ( predicate.equals(feedETag) )) {
+                	// Match, should short circuit
+                    response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
+                    return;
+                }
+                if ( feedUpdated != null ) {
+                	predicate = request.getHeader( "If-Unmodified-Since" );                
+                	if ( predicate != null ) {
+                		try {
+                			Date predicateDate = dateFormat.parse( predicate ); 
+                			if ( predicateDate.compareTo( feedUpdated ) < 0 ) {
+                				// Match, should short circuit
+                				response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
+                				return;
+                			}             		
+                		} catch ( java.text.ParseException e ) {
+                			// Ignore and move on
+                		}
+                	}
+                	predicate = request.getHeader( "If-Modified-Since" );                
+                	if ( predicate != null ) {
+                		try {
+                			Date predicateDate = dateFormat.parse( predicate ); 
+                			if ( predicateDate.compareTo( feedUpdated ) > 0 ) {
+                				// Match, should short circuit
+                				response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
+                				return;
+                			}             		
+                		} catch ( java.text.ParseException e ) {
+                			// Ignore and move on
+                		}
+                	}
+                }
                 
                 // Write the Atom feed
                 response.setContentType("application/atom+xml; charset=utf-8");
+                // Provide Etag based on Id and time.               
+                response.addHeader(ETAG, feedETag );
+                if ( feedUpdated != null )
+                   response.addHeader(LASTMODIFIED, dateFormat.format( feedUpdated ));
                 try {
                          feed.getDocument().writeTo(response.getOutputStream());
                 } catch (IOException ioe) {
@@ -270,7 +335,6 @@
             }
             
         } else if (path.startsWith("/")) {
-
             // Return a specific entry in the collection
             org.apache.abdera.model.Entry feedEntry;
 
@@ -282,7 +346,6 @@
             if (responseMessage.isFault()) {
                 throw new ServletException((Throwable)responseMessage.getBody());
             }
-            
             if (supportsFeedEntries) {
                 // The service implementation returns a feed entry 
                 feedEntry = responseMessage.getBody();
@@ -292,10 +355,26 @@
                 Entry<Object, Object> entry = new Entry<Object, Object>(id, responseMessage.getBody()); 
                 feedEntry = feedEntry(entry, itemClassType, itemXMLType, mediator, abderaFactory);
             }
-
             // Write the Atom entry
             if (feedEntry != null) {
-                response.setContentType("application/atom+xml; charset=utf-8");
+                IRI feedId = feedEntry.getId();
+                if ( feedId != null )
+                   response.addHeader(ETAG, "\"" + feedId.toString() + "\"" );
+                Date entryUpdated = feedEntry.getUpdated();
+                if ( entryUpdated != null )
+                   response.addHeader(LASTMODIFIED, dateFormat.format( entryUpdated ));
+                // TODO Check If-Modified-Since If-Unmodified-Since predicates against LASTMODIFIED. 
+                // If true return 304 and null body.            
+                Link link = feedEntry.getSelfLink();
+                if (link != null) {
+                    response.addHeader(LOCATION, link.getHref().toString());
+                } else {
+                   link = feedEntry.getLink( "Edit" );
+                   if (link != null) {
+                      response.addHeader(LOCATION, link.getHref().toString());
+                   }
+                }
+                response.setContentType("application/atom+xml;type=entry");
                 try {
                         feedEntry.writeTo(getWriter(response));
                 } catch (IOException ioe) {
@@ -314,7 +393,6 @@
     @Override
     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
         IOException {
-
         // Authenticate the user
         String user = processAuthorizationHeader(request);
         if (user == null) {
@@ -390,14 +468,25 @@
             if (createdFeedEntry != null) {
 
                 // Set location of the created entry in the Location header
+                IRI feedId = createdFeedEntry.getId();
+                if ( feedId != null )
+                   response.addHeader(ETAG, "\"" + feedId.toString() + "\"" );
+                Date entryUpdated = createdFeedEntry.getUpdated();
+                if ( entryUpdated != null )
+                   response.addHeader(LASTMODIFIED, dateFormat.format( entryUpdated ));
                 Link link = createdFeedEntry.getSelfLink();
                 if (link != null) {
-                    response.addHeader("Location", link.getHref().toString());
+                    response.addHeader(LOCATION, link.getHref().toString());
+                } else {
+                   link = createdFeedEntry.getLink( "Edit" );
+                   if (link != null) {
+                      response.addHeader(LOCATION, link.getHref().toString());
+                   }
                 }
 
                 // Write the created Atom entry
                 response.setStatus(HttpServletResponse.SC_CREATED);
-                response.setContentType("application/atom+xml; charset=utf-8");
+                response.setContentType("application/atom+xml;type=entry");
                 try {
                         createdFeedEntry.writeTo(getWriter(response));
                 } catch (ParseException pe) {
@@ -420,7 +509,6 @@
 
     @Override
     protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
-
         // Authenticate the user
         String user = processAuthorizationHeader(request);
         if (user == null) {
@@ -449,7 +537,6 @@
 
                 // Let the component implementation create it
                 if (supportsFeedEntries) {
-                    
                     // The service implementation supports feed entries, pass the entry to it
                     Message requestMessage = messageFactory.createMessage();
                     requestMessage.setBody(new Object[] {id, feedEntry});
@@ -463,7 +550,6 @@
                         }
                     }
                 } else {
-                    
                     // The service implementation does not support feed entries, pass the data item to it
                     Message requestMessage = messageFactory.createMessage();
                     Entry<Object, Object> entry = entry(feedEntry, itemClassType, itemXMLType, mediator);
@@ -600,4 +686,28 @@
         response.setHeader("WWW-Authenticate", "BASIC realm=\"Tuscany\"");
         response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
     }
+    
+    /**
+     * Generate ETag based on feed Id and updated fields.
+     * @param feed
+     * @return ETag
+     */
+    public static String generateFeedETag( Feed feed ) {
+    	if ( feed == null ) {
+    		return null; 
+    	}
+        
+    	IRI feedIdIRI = feed.getId();
+        String feedId = "ID";
+        if ( feedIdIRI != null ) {
+        	feedId = feedIdIRI.toString();
+        }
+        
+        Date feedUpdated = feed.getUpdated();
+        if ( feedUpdated == null ) {
+        	return feedId;
+        }
+        
+        return feedId + "-" + feedUpdated.hashCode();
+    }
 }

Added: tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomTestCaseUtils.java
URL: http://svn.apache.org/viewvc/tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomTestCaseUtils.java?rev=684294&view=auto
==============================================================================
--- tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomTestCaseUtils.java (added)
+++ tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomTestCaseUtils.java Sat Aug  9 09:50:30 2008
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.tuscany.sca.binding.atom;
+
+import java.io.IOException;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Base;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.protocol.client.ClientResponse;
+import org.apache.abdera.protocol.client.RequestOptions;
+import org.apache.abdera.writer.Writer;
+import org.apache.abdera.writer.WriterFactory;
+
+/**
+ * Utilities to help print and test various aspects of entity tag support.
+ */
+public class AtomTestCaseUtils {
+
+    public static void prettyPrint(Abdera abdera, Base doc) throws IOException {
+        WriterFactory factory = abdera.getWriterFactory();
+        Writer writer = factory.getWriter("prettyxml");
+        writer.writeTo(doc, System.out);
+        System.out.println();
+ 	}
+
+    public static void printRequestHeaders( String title, String indent, RequestOptions request ) {
+     	System.out.println( title );
+     	if ( request == null ) {
+     		System.out.println( indent + " request is null");
+     		return;
+     	}
+     	String [] headerNames = request.getHeaderNames();
+     	for ( String headerName: headerNames) {
+     		String header = request.getHeader(headerName);
+    	       System.out.println( indent + " header name,value=" + headerName + "," + header );	
+     	}    	               	           
+     }
+    
+     public static void printResponseHeaders( String title, String indent, ClientResponse response ) {
+      	System.out.println( title );
+     	if ( response == null ) {
+     		System.out.println( indent + " response is null");
+     		return;
+     	}
+     	String [] headerNames = response.getHeaderNames();
+     	for ( String headerName: headerNames) {
+     	    String header = response.getHeader(headerName);
+     	    System.out.println( indent + " header name,value=" + headerName + "," + header );
+     	}
+     	               	           
+     }
+
+	public static Entry newEntry(String value) {
+		Abdera abdera = new Abdera();
+		Entry entry = abdera.newEntry();
+		entry.setTitle("customer " + value);
+
+		Content content = abdera.getFactory().newContent();
+		content.setContentType(Content.Type.TEXT);
+		content.setValue(value);
+		entry.setContentElement(content);
+
+		return entry;
+	}
+
+	public static Entry updateEntry(Entry entry, String value) {
+		Abdera abdera = new Abdera();
+		entry.setTitle("customer " + value);
+
+		Content content = abdera.getFactory().newContent();
+		content.setContentType(Content.Type.TEXT);
+		content.setValue(value);
+		entry.setContentElement(content);
+
+		return entry;
+	}		
+	
+}

Propchange: tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomTestCaseUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomTestCaseUtils.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderEntryEntityTagsTest.java
URL: http://svn.apache.org/viewvc/tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderEntryEntityTagsTest.java?rev=684294&view=auto
==============================================================================
--- tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderEntryEntityTagsTest.java (added)
+++ tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderEntryEntityTagsTest.java Sat Aug  9 09:50:30 2008
@@ -0,0 +1,436 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.tuscany.sca.binding.atom;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import junit.framework.Assert;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.apache.tuscany.sca.binding.atom.collection.Collection;
+import org.apache.tuscany.sca.host.embedded.SCADomain;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.i18n.iri.IRI;
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.model.Base;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.abdera.model.Document;
+import org.apache.abdera.model.Service;
+import org.apache.abdera.protocol.Response.ResponseType;
+import org.apache.abdera.protocol.client.AbderaClient;
+import org.apache.abdera.protocol.client.ClientResponse;
+import org.apache.abdera.protocol.client.RequestOptions;
+import org.apache.abdera.protocol.client.util.BaseRequestEntity;
+import org.apache.abdera.util.EntityTag;
+import org.apache.abdera.parser.Parser;
+
+/**
+ * Tests use of server provided entry entity tags for Atom binding in Tuscany.
+ * Tests conditional gets (e.g. get if-none-match) or conditional posts (post if-match)
+ * using entity tags or last modified header entries. 
+ * Uses the SCA provided Provider composite to act as a server.
+ * Uses the Abdera provided Client to act as a client.
+ */
+public class ProviderEntryEntityTagsTest {
+	public final static String providerURI = "http://localhost:8084/customer";
+	protected static SCADomain scaConsumerDomain;
+	protected static SCADomain scaProviderDomain;
+	protected static CustomerClient testService;
+    protected static Abdera abdera;
+    protected static AbderaClient client;
+    protected static Parser abderaParser;    
+    protected static String eTag;
+    protected static Date lastModified;
+    protected static final SimpleDateFormat dateFormat = new SimpleDateFormat( "EEE, dd MMM yyyy HH:mm:ss Z" ); // RFC 822 date time
+
+	@BeforeClass
+	public static void init() throws Exception {
+		System.out.println(">>>ProviderEntryEntityTagsTest.init");
+		scaProviderDomain = SCADomain.newInstance("org/apache/tuscany/sca/binding/atom/Provider.composite");
+		abdera = new Abdera();
+		client = new AbderaClient(abdera);
+		abderaParser = Abdera.getNewParser();
+	}
+
+	@AfterClass
+	public static void destroy() throws Exception {
+		System.out.println(">>>ProviderEntryEntityTagsTest.destroy");
+		scaProviderDomain.close();
+	}
+
+	@Test
+	public void testPrelim() throws Exception {
+		Assert.assertNotNull(scaProviderDomain);
+		Assert.assertNotNull( client );
+	}
+	
+    @Test
+	public void testEmptyCachePost() throws Exception {
+		// Pseudo-code
+		// 1) Example HTTP POST request (new entry put, new etag response)
+		// User client post request       
+		//        POST /myblog/entries HTTP/1.1
+		//        Slug: First Post
+		//        
+		//        <?xml version="1.0" ?>
+		//        <entry xmlns="http://www.w3.org/2005/Atom">
+		//          <title>Atom-Powered Robots Run Amok</title>
+		//          <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
+		//          <updated>2007-02-123T17:09:02Z</updated>
+		//          <author><name>Captain Lansing</name></author>
+		//          <content>It's something moving... solid metal</content>
+		//        </entry>
+
+		// Expected Atom server response (note unique ETag)
+		//       HTTP/1.1 201 Created
+		//       Date: Fri, 23 Feb 2007 21:17:11 GMT
+		//       Content-Length: nnn
+		//       Content-Type: application/atom+xml;type=entry
+		//       Location: http://example.org/edit/first-post.atom
+		//       Content-Location: http://example.org/edit/first-post.atom
+		//       ETag: "e180ee84f0671b1"
+		//       Last-Modified: Fri, 25 Jul 2008 14:36:44 -0500
+		// 
+		//        <?xml version="1.0" ?>
+		//        <entry xmlns="http://www.w3.org/2005/Atom">
+		//          <title>Atom-Powered Robots Run Amok</title>
+		//          <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
+		//          <updated>2007-02-123T17:09:02Z</updated>
+		//          <author><name>Captain Lansing</name></author>
+		//          <content>It's something moving... solid metal</content>
+		//        </entry>		
+		
+		// Testing of entry creation
+		Factory factory = abdera.getFactory();
+		String customerName = "Fred Farkle";
+		Entry entry = factory.newEntry();
+		entry.setTitle("customer " + customerName);
+		entry.setUpdated(new Date());
+		entry.addAuthor("Apache Tuscany");
+		// ID created by collection.
+        // entry.setId(id); // auto-provided
+        // entry.addLink("" + id, "edit"); // auto-provided
+        // entry.addLink("" + id, "alternate"); // auto-provided
+		Content content = abdera.getFactory().newContent();
+		content.setContentType(Content.Type.TEXT);
+		content.setValue(customerName);
+		entry.setContentElement(content);
+
+		RequestOptions opts = new RequestOptions();
+		final String contentType = "application/atom+xml; type=entry"; 
+		opts.setContentType(contentType);
+		// AtomTestCaseUtils.printRequestHeaders( "Post request headers", "   ", opts );
+		IRI colUri = new IRI(providerURI).resolve("customer");
+		// res = client.post(colUri.toString() + "?test=foo", entry, opts);
+		ClientResponse res = client.post(colUri.toString(), entry, opts);
+		
+	    // Assert response status code is 201-OK.
+		// Assert response header Content-Type: application/atom+xml; charset=UTF-8
+		// Assert response header Location: http://example.org/edit/first-post.atom
+		// Assert response header Content-Location: http://example.org/edit/first-post.atom
+		// Assert response header ETag: "e180ee84f0671b1"
+		// Assert response header Last-Modified: Fri, 25 Jul 2008 14:36:44 -0500	    
+	    // Assert collection size is 1.
+    	Assert.assertEquals(201, res.getStatus());
+    	Assert.assertEquals(contentType, res.getContentType().toString().trim());
+    	// Assert.assertNotNull( res.getLocation().toString() );
+    	// Assert.assertEquals( "", res.getContentLocation().toString() );
+    	// Save eTag for subsequent tests;
+    	eTag = res.getHeader( "ETag" );
+    	Assert.assertNotNull( eTag );     	
+    	lastModified = res.getLastModified();
+    	Assert.assertNotNull(lastModified);
+	}
+
+	@Test
+	public void testDirtyCachePut() throws Exception {
+		// 2) Conditional PUT request (post with etag. entry provided is stale)
+		// User client PUT request
+		//        PUT /edit/first-post.atom HTTP/1.1
+		// >      If-Match: "e180ee84f0671b1"
+		// 
+		//        <?xml version="1.0" ?>
+		//        <entry xmlns="http://www.w3.org/2005/Atom">
+		//         <title>Atom-Powered Robots Run Amok</title>
+		//         <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
+		//         <updated>2007-02-24T16:34:06Z</updated>
+		//         <author><name>Captain Lansing</name></author>
+		//         <content>Update: it's a hoax!</content>
+		//       </entry>
+		// Testing of entry creation
+		Factory factory = abdera.getFactory();
+		String customerName = "Molly Ringwald";
+		Entry entry = factory.newEntry();
+		entry.setTitle("customer " + customerName);
+		entry.setUpdated( new Date());
+		entry.addAuthor("Apache Tuscany");
+		String id = eTag.substring( 1, eTag.length()-1);
+        entry.setId(id); // auto-provided
+        // entry.addLink("" + id, "edit"); // auto-provided
+        // entry.addLink("" + id, "alternate"); // auto-provided
+		Content content = abdera.getFactory().newContent();
+		content.setContentType(Content.Type.TEXT);
+		content.setValue(customerName);
+		entry.setContentElement(content);
+
+		RequestOptions opts = new RequestOptions();
+		final String contentType = "application/atom+xml; type=entry"; 
+		opts.setContentType(contentType);
+		opts.setHeader( "If-None-Match", eTag);
+		
+		AtomTestCaseUtils.printRequestHeaders( "Put request headers", "   ", opts );
+		IRI colUri = new IRI(providerURI).resolve("customer");
+		// res = client.post(colUri.toString() + "?test=foo", entry, opts);
+	    id = eTag.substring( 1, eTag.length()-1);
+		// Warning. AbderaClient.put(String uri,Base base,RequestOptions options) caches on the client side.
+		// ClientResponse res = client.put(colUri.toString() + id, entry, opts);
+		ClientResponse res = client.put(colUri.toString() + "/" + id, new BaseRequestEntity( entry ), opts);
+		// Expected Atom server response (item was edited by another user)
+		// >      HTTP/1.1 412 Precondition Failed
+		//       Date: Sat, 24 Feb 2007 16:34:11 GMT
+
+	    // If-Match Assert response status code is 412. Precondition failed.
+	    // If-None-Match Assert response status code is 200. OK
+    	Assert.assertEquals(200, res.getStatus());
+    	// Put provides null body and no etags.
+    	res.release();
+	}
+	
+	@Test
+	public void testETagMissGet() throws Exception {
+		// 4) Conditional GET example (get with etag. etag not in cache)
+		// User client GET request
+		//       GET /edit/first-post.atom HTTP/1.1
+		// >      If-None-Match: "e180ee84f0671b1"
+
+		RequestOptions opts = new RequestOptions();
+		final String contentType = "application/atom+xml; type=entry"; 
+		opts.setContentType(contentType);
+		opts.setHeader( "If-None-Match", "123456");
+		opts.setHeader( "Pragma", "no-cache"); // turn off client caching
+		
+		IRI colUri = new IRI(providerURI).resolve("customer");
+		// res = client.post(colUri.toString() + "?test=foo", entry, opts);
+		String id = eTag.substring( 1, eTag.length()-1);
+		// Warning. AbderaClient.put(String uri,Base base,RequestOptions options) caches on the client side.
+		// ClientResponse res = client.put(colUri.toString() + id, entry, opts);
+		ClientResponse res = client.get(colUri.toString() + "/" + id, opts);
+		// Expected Atom server response (item was edited by another user)
+		// >      HTTP/1.1 412 Precondition Failed
+		//       Date: Sat, 24 Feb 2007 16:34:11 GMT
+
+		// Atom server response (item was up to date)
+		// >      HTTP/1.1 200 OK
+		//        Date: Sat, 24 Feb 2007 13:17:11 GMT
+		// >      ETag: "bb4f5e86e92ddb8549604a0df0763581"
+		// >      Last-Modified: Mon, 28 Jul 2008 10:25:37 -0500
+
+	    // Assert response status code is 200 OK.
+		// Assert header Content-Type: application/atom+xml;type=entry
+		// Assert header Location: http://example.org/edit/first-post.atom
+		// Assert header Content-Location: http://example.org/edit/first-post.atom
+		// Assert header ETag: "555555" (etag response != etag request)
+		// Assert header Last-Modified: Fri, 25 Jul 2008 14:36:44 -0500
+    	Assert.assertEquals(200, res.getStatus());
+    	Assert.assertEquals(contentType, res.getContentType().toString().trim());
+    	// Assert.assertNotNull( res.getLocation().toString() );
+    	// Assert.assertEquals( "", res.getContentLocation().toString() );
+    	Assert.assertNotNull( res.getHeader( "ETag" ) );     	
+    	lastModified = res.getLastModified();
+    	Assert.assertNotNull(lastModified);
+		res.release();
+	}
+
+	@Test
+	public void testETagHitGet() throws Exception {
+		// 3) Conditional GET example (get with etag. etag match)
+		// User client GET request
+		//       GET /edit/first-post.atom HTTP/1.1
+		// >      If-None-Match: "e180ee84f0671b1"
+
+		RequestOptions opts = new RequestOptions();
+		final String contentType = "application/atom+xml; type=entry"; 
+		opts.setContentType(contentType);
+		opts.setHeader( "If-None-Match", eTag);
+		opts.setHeader( "Pragma", "no-cache"); // turn off client caching		
+		
+		IRI colUri = new IRI(providerURI).resolve("customer");
+		// res = client.post(colUri.toString() + "?test=foo", entry, opts);
+		String id = eTag.substring( 1, eTag.length()-1);
+		// Warning. AbderaClient.put(String uri,Base base,RequestOptions options) caches on the client side.
+		// ClientResponse res = client.put(colUri.toString() + id, entry, opts);
+		ClientResponse res = client.get(colUri.toString() + "/" + id, opts);
+		// Atom server response (item was up to date)
+		// >      HTTP/1.1 304 Not Modified
+		//       Date: Sat, 24 Feb 2007 13:17:11 GMT
+
+	    // Assert response status code is 304 Not Modified.
+		// Assert header ETag: "e180ee84f0671b1"
+		// Assert header Last-Modified: Fri, 25 Jul 2008 14:36:44 -0500
+    	// Assert.assertEquals(304, res.getStatus());
+		res.release();	    
+	}
+
+
+	@Test
+	public void testUpToDateGet() throws Exception {
+		// 3) Conditional GET example (get with If-Mod. entry is up to date)
+		// User client GET request
+		//       GET /edit/first-post.atom HTTP/1.1
+		// >      If-Modified-Since: Sat, 29 Oct 2025 19:43:31 GMT
+		RequestOptions opts = new RequestOptions();
+		final String contentType = "application/atom+xml; type=entry"; 
+		opts.setContentType(contentType);
+		opts.setHeader( "If-Modified-Since", "Sat, 29 Oct 2025 19:43:31 GMT"); // "EEE, dd MMM yyyy HH:mm:ss Z // RFC 822 Date
+		opts.setHeader( "Pragma", "no-cache"); // turn off client caching
+		
+		IRI colUri = new IRI(providerURI).resolve("customer");
+		// res = client.post(colUri.toString() + "?test=foo", entry, opts);
+		String id = eTag.substring( 1, eTag.length()-1);
+		// Warning. AbderaClient.put(String uri,Base base,RequestOptions options) caches on the client side.
+		// ClientResponse res = client.put(colUri.toString() + id, entry, opts);
+		// Warning. AbderaClient.put(String uri,Base base,RequestOptions options) caches on the client side.
+		// ClientResponse res = client.get(colUri.toString() + "/" + id, opts);
+		ClientResponse res = client.execute( "GET", colUri.toString(), (BaseRequestEntity)null, opts);
+
+		// Atom server response (item was up to date)
+		// >      HTTP/1.1 304 Not Modified
+		//       Date: Sat, 24 Feb 2007 13:17:11 GMT
+
+	    // Assert response status code is 304 Not Modified.
+    	Assert.assertEquals(304, res.getStatus());
+		res.release();	    
+	}
+
+	@Test
+	public void testOutOfDateGet() throws Exception {
+		// 4) Conditional GET example (get with If-Mod. entry is not to date)
+		// User client GET request
+		//       GET /edit/first-post.atom HTTP/1.1
+		// >      If-Modified-Since: Sat, 29 Oct 1844 19:43:31 GMT
+		RequestOptions opts = new RequestOptions();
+		final String contentType = "application/atom+xml; type=entry"; 
+		opts.setContentType(contentType);
+		opts.setHeader( "If-Modified-Since", "Sat, 29 Oct 1844 19:43:31 GMT"); // "EEE, dd MMM yyyy HH:mm:ss Z // RFC 822 Date
+		opts.setHeader( "Pragma", "no-cache"); // turn off client caching
+		
+		IRI colUri = new IRI(providerURI).resolve("customer");
+		// res = client.post(colUri.toString() + "?test=foo", entry, opts);
+		String id = eTag.substring( 1, eTag.length()-1);
+		// Warning. AbderaClient.put(String uri,Base base,RequestOptions options) caches on the client side.
+		// ClientResponse res = client.put(colUri.toString() + id, entry, opts);
+		ClientResponse res = client.get(colUri.toString() + "/" + id, opts);
+
+		// Atom server response (item was up to date)
+		// >      HTTP/1.1 200 OK
+		//        Date: Sat, 24 Feb 2007 13:17:11 GMT
+		// >      ETag: "bb4f5e86e92ddb8549604a0df0763581"
+		// >      Last-Modified: Mon, 28 Jul 2008 10:25:37 -0500
+
+	    // Assert response status code is 200 OK.
+		// Assert header ETag: "e180ee84f0671b1"
+		// Assert header Last-Modified: Greater than If-Mod	    
+    	Assert.assertEquals(200, res.getStatus());
+    	Assert.assertEquals(contentType, res.getContentType().toString().trim());
+    	// Assert.assertNotNull( res.getLocation().toString() );
+    	// Assert.assertEquals( "", res.getContentLocation().toString() );
+    	Assert.assertNotNull( res.getHeader( "ETag" ) );     	
+    	lastModified = res.getLastModified();
+    	Assert.assertNotNull(lastModified);
+		res.release();
+	}
+	
+	@Test
+	public void testUpToDateUnModGet() throws Exception {
+		// 3) Conditional GET example (get with If-Unmod. entry is up to date)
+		// User client GET request
+		//       GET /edit/first-post.atom HTTP/1.1
+		// >      If-Unmodified-Since: Sat, 29 Oct 2025 19:43:31 GMT
+		RequestOptions opts = new RequestOptions();
+		final String contentType = "application/atom+xml; type=entry"; 
+		opts.setContentType(contentType);
+		opts.setHeader( "If-Unmodified-Since", "Sat, 29 Oct 2050 19:43:31 GMT" );
+		opts.setHeader( "Pragma", "no-cache"); // turn off client caching
+		
+		IRI colUri = new IRI(providerURI).resolve("customer");
+		// res = client.post(colUri.toString() + "?test=foo", entry, opts);
+		String id = eTag.substring( 1, eTag.length()-1);
+		// Warning. AbderaClient.put(String uri,Base base,RequestOptions options) caches on the client side.
+		// ClientResponse res = client.put(colUri.toString() + id, entry, opts);
+		ClientResponse res = client.get(colUri.toString() + "/" + id, opts);
+
+		// Atom server response (item was up to date)
+		// >      HTTP/1.1 304 Not Modified
+		//       Date: Sat, 24 Feb 2007 13:17:11 GMT
+
+	    // Assert response status code is 304 Not Modified.
+    	// Assert.assertEquals(304, res.getStatus());
+		// TODO Update when If-Unmodified-Since enabled.
+    	Assert.assertEquals(200, res.getStatus());
+		res.release();	        
+	}
+
+	@Test
+	public void testOutOfDateUnModGet() throws Exception {
+		// 4) Conditional GET example (get with If-Unmod. entry is not to date)
+		// User client GET request
+		//       GET /edit/first-post.atom HTTP/1.1
+		//        Host: example.org
+		// >      If-Unmodified-Since: Sat, 29 Oct 1844 19:43:31 GMT
+		RequestOptions opts = new RequestOptions();
+		final String contentType = "application/atom+xml; type=entry"; 
+		opts.setContentType(contentType);
+		opts.setHeader( "If-Unmodified-Since", "Sat, 29 Oct 1844 19:43:31 GMT" );
+		opts.setHeader( "Pragma", "no-cache"); // turn off client caching
+		
+		IRI colUri = new IRI(providerURI).resolve("customer");
+		// res = client.post(colUri.toString() + "?test=foo", entry, opts);
+		String id = eTag.substring( 1, eTag.length()-1);
+		// Warning. AbderaClient.put(String uri,Base base,RequestOptions options) caches on the client side.
+		// ClientResponse res = client.put(colUri.toString() + id, entry, opts);
+		ClientResponse res = client.get(colUri.toString() + "/" + id, opts);
+
+		// Atom server response (item was up to date)
+		// >      HTTP/1.1 200 OK
+		//        Date: Sat, 24 Feb 2007 13:17:11 GMT
+		// >      ETag: "bb4f5e86e92ddb8549604a0df0763581"
+		// >      Last-Modified: Mon, 28 Jul 2008 10:25:37 -0500
+
+	    // Assert response status code is 200 OK.
+		// Assert header Content-Type: application/atom+xml;type=entry
+		// Assert header Location: http://example.org/edit/first-post.atom
+		// Assert header Content-Location: http://example.org/edit/first-post.atom
+		// Assert header ETag: "e180ee84f0671b1"
+		// Assert header Last-Modified: Less than If-Unmod	    
+    	Assert.assertEquals(200, res.getStatus());
+    	Assert.assertEquals(contentType, res.getContentType().toString().trim());
+    	// Assert.assertNotNull( res.getLocation().toString() );
+    	// Assert.assertEquals( "", res.getContentLocation().toString() );
+    	Assert.assertNotNull( res.getHeader( "ETag" ) );     	
+    	lastModified = res.getLastModified();
+    	Assert.assertNotNull(lastModified);
+		res.release();
+	}
+}

Propchange: tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderEntryEntityTagsTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderEntryEntityTagsTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderFeedEntityTagsTest.java
URL: http://svn.apache.org/viewvc/tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderFeedEntityTagsTest.java?rev=684294&view=auto
==============================================================================
--- tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderFeedEntityTagsTest.java (added)
+++ tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderFeedEntityTagsTest.java Sat Aug  9 09:50:30 2008
@@ -0,0 +1,356 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.tuscany.sca.binding.atom;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import junit.framework.Assert;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.apache.tuscany.sca.host.embedded.SCADomain;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.i18n.iri.IRI;
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.model.Base;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.abdera.model.Document;
+import org.apache.abdera.model.Service;
+import org.apache.abdera.model.Collection;
+import org.apache.abdera.protocol.Response.ResponseType;
+import org.apache.abdera.protocol.client.AbderaClient;
+import org.apache.abdera.protocol.client.ClientResponse;
+import org.apache.abdera.protocol.client.RequestOptions;
+import org.apache.abdera.protocol.client.util.BaseRequestEntity;
+import org.apache.abdera.util.EntityTag;
+import org.apache.abdera.parser.Parser;
+
+/**
+ * Tests use of server provided feed entity tags for Atom binding in Tuscany.
+ * Tests conditional gets (e.g. get if-none-match) or conditional posts (post if-match)
+ * using entity tags and last modified entries in headers. 
+ * Uses the SCA provided Provider composite to act as a server.
+ * Uses the Abdera provided Client to act as a client.
+ */
+public class ProviderFeedEntityTagsTest {
+	public final static String providerURI = "http://localhost:8084/customer";
+	protected static SCADomain scaConsumerDomain;
+	protected static SCADomain scaProviderDomain;
+	protected static CustomerClient testService;
+    protected static Abdera abdera;
+    protected static AbderaClient client;
+    protected static Parser abderaParser;    
+    protected static String eTag;
+    protected static Date lastModified;
+    protected static final SimpleDateFormat dateFormat = new SimpleDateFormat( "EEE, dd MMM yyyy HH:mm:ss Z" ); // RFC 822 date time
+
+	@BeforeClass
+	public static void init() throws Exception {
+		System.out.println(">>>ProviderFeedEntityTagsTest.init");
+		scaProviderDomain = SCADomain.newInstance("org/apache/tuscany/sca/binding/atom/Provider.composite");
+		abdera = new Abdera();
+		client = new AbderaClient(abdera);
+		abderaParser = Abdera.getNewParser();
+	}
+
+	@AfterClass
+	public static void destroy() throws Exception {
+		System.out.println(">>>ProviderFeedEntityTagsTest.destroy");
+		scaProviderDomain.close();
+	}
+
+	@Test
+	public void testPrelim() throws Exception {
+		Assert.assertNotNull(scaProviderDomain);
+		Assert.assertNotNull( client );
+	}
+			
+	@Test
+    public void testFeedBasics() throws Exception {		
+		System.out.println(">>>ProviderFeedEntityTagsTest.testFeedBasics");
+		// Normal feed request
+		ClientResponse res = client.get(providerURI);
+		Assert.assertNotNull(res);
+		try {
+			// Asser feed provided since no predicates
+			Assert.assertEquals(200, res.getStatus());
+			Assert.assertEquals(ResponseType.SUCCESS, res.getType());
+	    	// AtomTestCaseUtils.printResponseHeaders( "Feed response headers:", "   ", res );
+	    	// System.out.println("Feed response content:");
+	    	// AtomTestCaseUtils.prettyPrint(abdera, res.getDocument());
+
+	    	// Perform other tests on feed.
+			Document<Feed> doc = res.getDocument();
+			Assert.assertNotNull( doc );
+			Feed feed = doc.getRoot();
+			Assert.assertNotNull( feed );
+			printFeed( "Feed values", "   ", feed );
+			// RFC 4287 requires non-null id, title, updated elements
+			Assert.assertNotNull( feed.getId() );
+			Assert.assertNotNull( feed.getTitle() );
+			Assert.assertNotNull( feed.getUpdated() );
+			
+			eTag = res.getHeader("ETag");
+			Assert.assertNotNull( eTag );
+			lastModified = res.getLastModified();
+			Assert.assertNotNull( lastModified );
+		} finally {
+			res.release();
+		}
+	}		
+
+	@Test
+    public void testUnmodifiedGetIfMatch() throws Exception {		
+		System.out.println(">>>ProviderFeedEntityTagsTest.testFeedUnmodifiedGetIfMatch");
+		// Feed request with predicates
+		RequestOptions opts = new RequestOptions();
+		final String contentType = "application/atom+xml"; 
+		opts.setContentType(contentType);
+		opts.setHeader( "If-Match", eTag);
+		
+		ClientResponse res = client.get(providerURI, opts);
+		Assert.assertNotNull(res);
+		try {
+	    	String thisETag = res.getHeader("ETag");
+			Assert.assertNotNull( thisETag );
+			Date thisLastModified = res.getLastModified();
+			Assert.assertNotNull( thisLastModified );
+                        
+			// Should return 200 - Feed provided since it matches etag.
+			Assert.assertEquals(200, res.getStatus());
+			Assert.assertEquals(ResponseType.SUCCESS, res.getType());
+	    	// AtomTestCaseUtils.printResponseHeaders( "Feed response headers:", "   ", res );
+	    	// System.out.println("Feed response content:");
+	    	// AtomTestCaseUtils.prettyPrint(abdera, res.getDocument());
+		} finally {
+			res.release();
+		}
+	}		
+
+	@Test
+    public void testUnmodifiedGetIfNoneMatch() throws Exception {		
+		System.out.println(">>>ProviderFeedEntityTagsTest.testFeedUnmodifiedGetIfNoneMatch");
+		// Feed request with predicates
+		RequestOptions opts = new RequestOptions();
+		final String contentType = "application/atom+xml"; 
+		opts.setContentType(contentType);
+		opts.setHeader( "If-None-Match", eTag);
+		
+		ClientResponse res = client.get(providerURI, opts);
+		Assert.assertNotNull(res);
+		try {
+			// Should return 304 - Feed not provided since it matches ETag.
+			Assert.assertEquals(304, res.getStatus());
+		} finally {
+			res.release();
+		}
+	}		
+
+	@Test
+    public void testUnmodifiedGetIfUnModified() throws Exception {		
+		System.out.println(">>>ProviderFeedEntityTagsTest.testFeedUnmodifiedGetIfUnModified");
+		// Feed request with predicates
+		RequestOptions opts = new RequestOptions();
+		final String contentType = "application/atom+xml"; 
+		opts.setContentType(contentType);
+		opts.setHeader( "If-Unmodified-Since", dateFormat.format( new Date() ));
+		
+		ClientResponse res = client.get(providerURI, opts);
+		Assert.assertNotNull(res);
+		try {
+			// Should return 304 - Feed not provided since feed is modified since.
+			Assert.assertEquals(304, res.getStatus());
+		} finally {
+			res.release();
+		}
+	}		
+
+	@Test
+    public void testUnmodifiedGetIfModified() throws Exception {		
+		System.out.println(">>>ProviderFeedEntityTagsTest.testFeedUnmodifiedGetIfModified");
+		// Feed request with predicates
+		RequestOptions opts = new RequestOptions();
+		final String contentType = "application/atom+xml"; 
+		opts.setContentType(contentType);
+		opts.setHeader( "If-Modified-Since", dateFormat.format( new Date( 0 ) ));
+		
+		ClientResponse res = client.get(providerURI, opts);
+		Assert.assertNotNull(res);
+		try {
+			// Should return 200 - Feed provided since feed is changed.
+			Assert.assertEquals(200, res.getStatus());
+			Assert.assertEquals(ResponseType.SUCCESS, res.getType());
+
+			String thisETag = res.getHeader("ETag");
+			Assert.assertNotNull( thisETag );
+			Date thisLastModified = res.getLastModified();
+			Assert.assertNotNull( thisLastModified );                        
+		} finally {
+			res.release();
+		}
+	}		
+
+	@Test
+    public void testModifiedGetIfNoneMatch() throws Exception {		
+		System.out.println(">>>ProviderFeedEntityTagsTest.testFeedModifiedGetIfNoneMatch");
+		// Post some new content to the feed.
+		Factory factory = abdera.getFactory();
+		String customerName = "Fred Farkle";
+		Entry entry = factory.newEntry();
+		entry.setTitle("customer " + customerName);
+		entry.setUpdated(new Date());
+		entry.addAuthor("Apache Tuscany");
+		Content content = abdera.getFactory().newContent();
+		content.setContentType(Content.Type.TEXT);
+		content.setValue(customerName);
+		entry.setContentElement(content);
+
+		RequestOptions opts = new RequestOptions();
+		String contentType = "application/atom+xml; type=entry"; 
+		opts.setContentType(contentType);
+		IRI colUri = new IRI(providerURI).resolve("customer");
+		ClientResponse res = client.post(colUri.toString(), entry, opts);
+			
+		// Feed request with predicates
+		opts = new RequestOptions();
+		contentType = "application/atom+xml"; 
+		opts.setContentType(contentType);
+		opts.setHeader( "If-None-Match", eTag);
+		
+		res = client.get(providerURI, opts);
+		Assert.assertNotNull(res);
+		try {
+	    	String thisETag = res.getHeader("ETag");
+			Assert.assertNotNull( thisETag );
+			Date thisLastModified = res.getLastModified();
+			Assert.assertNotNull( thisLastModified );
+                        
+			// Should return 200 - value since feed is changed
+			Assert.assertEquals(200, res.getStatus());
+			Assert.assertEquals(ResponseType.SUCCESS, res.getType());
+			
+	    	// AtomTestCaseUtils.printResponseHeaders( "Feed modified if-none-match response headers:", "   ", res );
+	    	// System.out.println("Feed response content:");
+	    	// AtomTestCaseUtils.prettyPrint(abdera, res.getDocument());
+		} finally {
+			res.release();
+		}
+	}		
+
+	@Test
+    public void testModifiedGetIfMatch() throws Exception {		
+		System.out.println(">>>ProviderFeedEntityTagsTest.testFeedModifiedGetIfMatch");
+		// Feed request with predicates
+		RequestOptions opts = new RequestOptions();
+		final String contentType = "application/atom+xml"; 
+		opts.setContentType(contentType);
+		opts.setHeader( "If-Match", eTag);
+		
+		ClientResponse res = client.get(providerURI, opts);
+		Assert.assertNotNull(res);
+		try {
+			// Should return 412 - Precondition failed since feed changed.
+			Assert.assertEquals(412, res.getStatus());
+	    	// AtomTestCaseUtils.printResponseHeaders( "Feed response headers:", "   ", res );
+	    	// System.out.println("Feed response content:");
+	    	// AtomTestCaseUtils.prettyPrint(abdera, res.getDocument());
+		} finally {
+			res.release();
+		}
+	}		
+
+	@Test
+    public void testModifiedGetIfUnModified() throws Exception {		
+		System.out.println(">>>ProviderFeedEntityTagsTest.testFeedUnmodifiedGetIfUnModified");
+		// Feed request with predicates
+		RequestOptions opts = new RequestOptions();
+		final String contentType = "application/atom+xml"; 
+		opts.setContentType(contentType);
+		opts.setHeader( "If-Unmodified-Since", dateFormat.format( new Date() ));
+		
+		ClientResponse res = client.get(providerURI, opts);
+		Assert.assertNotNull(res);
+		try {
+			// Should return 304 - Feed not provided since feed is modified since.			
+			Assert.assertEquals(304, res.getStatus());
+		} finally {
+			res.release();
+		}
+	}		
+
+	@Test
+    public void testModifiedGetIfModified() throws Exception {		
+		System.out.println(">>>ProviderFeedEntityTagsTest.testFeedUnmodifiedGetIfModified");
+		// Feed request with predicates
+		RequestOptions opts = new RequestOptions();
+		final String contentType = "application/atom+xml"; 
+		opts.setContentType(contentType);
+		opts.setHeader( "If-Modified-Since", dateFormat.format( lastModified ));
+		
+		ClientResponse res = client.get(providerURI, opts);
+		Assert.assertNotNull(res);
+		try {
+			// Should return 200 - Feed provided since feed is changed.
+			Assert.assertEquals(200, res.getStatus());
+			Assert.assertEquals(ResponseType.SUCCESS, res.getType());
+
+			String thisETag = res.getHeader("ETag");
+			Assert.assertNotNull( thisETag );
+			Date thisLastModified = res.getLastModified();
+			Assert.assertNotNull( thisLastModified );                        
+		} finally {
+			res.release();
+		}
+	}		
+
+
+	public static void printFeed( String title, String indent, Feed feed ) {
+		if ( feed == null ) {
+			System.out.println( title + " feed is null");
+			return;
+		}
+			
+		System.out.println( title );
+		System.out.println( indent + "id=" + feed.getId() );
+		System.out.println( indent + "title=" + feed.getTitle() );
+		System.out.println( indent + "updated=" + feed.getUpdated() );
+		System.out.println( indent + "author=" + feed.getAuthor() );
+		Collection collection = feed.getCollection();
+		if ( collection == null ) {
+			System.out.println( indent + "collection=null" );
+		} else {
+			System.out.println( indent + "collection=" + collection );
+		}
+		// System.out.println( indent + "collection size=" + feed.getCollection() );
+		// for (Collection collection : workspace.getCollections()) {
+		//    if (collection.getTitle().equals("customers")) {
+		//       String expected = uri + "customers";
+		//       String actual = collection.getResolvedHref().toString();
+		//       assertEquals(expected, actual);
+		//    }
+		// }
+
+	}
+
+}

Propchange: tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderFeedEntityTagsTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderFeedEntityTagsTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date