summaryrefslogtreecommitdiffstats
path: root/java/sca/modules
diff options
context:
space:
mode:
Diffstat (limited to 'java/sca/modules')
-rw-r--r--java/sca/modules/binding-atom-abdera/pom.xml10
-rw-r--r--java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingInvoker.java16
-rw-r--r--java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingListenerServlet.java132
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomTestCaseUtils.java96
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderEntryEntityTagsTest.java436
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderFeedEntityTagsTest.java356
6 files changed, 1024 insertions, 22 deletions
diff --git a/java/sca/modules/binding-atom-abdera/pom.xml b/java/sca/modules/binding-atom-abdera/pom.xml
index 72caa56169..ec8ecaeee7 100644
--- a/java/sca/modules/binding-atom-abdera/pom.xml
+++ b/java/sca/modules/binding-atom-abdera/pom.xml
@@ -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>
diff --git a/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingInvoker.java b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingInvoker.java
index 9b55bfd0ac..dafcf57311 100644
--- a/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingInvoker.java
+++ b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingInvoker.java
@@ -86,7 +86,6 @@ class AtomBindingInvoker implements Invoker {
@Override
public Message invoke(Message msg) {
-
// Get an entry
String id = (String)((Object[])msg.getBody())[0];
@@ -100,7 +99,8 @@ class AtomBindingInvoker implements Invoker {
// 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 @@ class AtomBindingInvoker implements Invoker {
@Override
public Message invoke(Message msg) {
-
// Post an entry
Object[] args = (Object[])msg.getBody();
org.apache.abdera.model.Entry feedEntry;
@@ -173,7 +172,8 @@ class AtomBindingInvoker implements Invoker {
// 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 @@ class AtomBindingInvoker implements Invoker {
@Override
public Message invoke(Message msg) {
-
// Put an entry
Object[] args = (Object[])msg.getBody();
String id;
@@ -250,6 +249,7 @@ class AtomBindingInvoker implements Invoker {
// Send an HTTP PUT
PutMethod putMethod = new PutMethod(uri + "/" + id);
putMethod.setRequestHeader("Authorization", authorizationHeader);
+
try {
// Write the Atom entry
@@ -260,7 +260,7 @@ class AtomBindingInvoker implements Invoker {
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 @@ class AtomBindingInvoker implements Invoker {
@Override
public Message invoke(Message msg) {
-
// Delete an entry
String id = (String)((Object[])msg.getBody())[0];
@@ -331,7 +330,6 @@ class AtomBindingInvoker implements Invoker {
@Override
public Message invoke(Message msg) {
-
// Get a feed
// Send an HTTP GET
@@ -341,6 +339,7 @@ class AtomBindingInvoker implements Invoker {
try {
httpClient.executeMethod(getMethod);
int status = getMethod.getStatusCode();
+ // AtomBindingInvoker.printResponseHeader( getMethod );
// Read the Atom feed
if (status == 200) {
@@ -396,7 +395,6 @@ class AtomBindingInvoker implements Invoker {
@Override
public Message invoke(Message msg) {
-
// Get a feed from a query
String queryString = (String)((Object[])msg.getBody())[0];
diff --git a/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingListenerServlet.java b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingListenerServlet.java
index 8244a2495f..e171de8595 100644
--- a/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingListenerServlet.java
+++ b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingListenerServlet.java
@@ -26,6 +26,8 @@ import java.io.OutputStreamWriter;
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 javax.xml.namespace.QName;
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.Message;
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 @@ class AtomBindingListenerServlet extends HttpServlet {
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 @@ class AtomBindingListenerServlet extends HttpServlet {
} 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 @@ class AtomBindingListenerServlet extends HttpServlet {
}
} else if (path.startsWith("/")) {
-
// Return a specific entry in the collection
org.apache.abdera.model.Entry feedEntry;
@@ -282,7 +346,6 @@ class AtomBindingListenerServlet extends HttpServlet {
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 @@ class AtomBindingListenerServlet extends HttpServlet {
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 @@ class AtomBindingListenerServlet extends HttpServlet {
@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 @@ class AtomBindingListenerServlet extends HttpServlet {
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 @@ class AtomBindingListenerServlet extends HttpServlet {
@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 @@ class AtomBindingListenerServlet extends HttpServlet {
// 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 @@ class AtomBindingListenerServlet extends HttpServlet {
}
}
} 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 @@ class AtomBindingListenerServlet extends HttpServlet {
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();
+ }
}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomTestCaseUtils.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomTestCaseUtils.java
new file mode 100644
index 0000000000..6beed6881f
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomTestCaseUtils.java
@@ -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;
+ }
+
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderEntryEntityTagsTest.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderEntryEntityTagsTest.java
new file mode 100644
index 0000000000..fbdf9a05f7
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderEntryEntityTagsTest.java
@@ -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();
+ }
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderFeedEntityTagsTest.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderFeedEntityTagsTest.java
new file mode 100644
index 0000000000..faa7d414f5
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderFeedEntityTagsTest.java
@@ -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);
+ // }
+ // }
+
+ }
+
+}