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

svn commit: r685516 - in /tuscany/java/sca/modules/binding-atom-abdera: pom.xml src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingListenerServlet.java src/test/java/org/apache/tuscany/sca/binding/atom/ContentNegotiationTest.java

Author: antelder
Date: Wed Aug 13 04:18:32 2008
New Revision: 685516

URL: http://svn.apache.org/viewvc?rev=685516&view=rev
Log:
TUSCANY-2504: apply patch from Dan Becker to give Atom binding support for negotiated content types

Added:
    tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ContentNegotiationTest.java
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/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=685516&r1=685515&r2=685516&view=diff
==============================================================================
--- tuscany/java/sca/modules/binding-atom-abdera/pom.xml (original)
+++ tuscany/java/sca/modules/binding-atom-abdera/pom.xml Wed Aug 13 04:18:32 2008
@@ -113,6 +113,18 @@
         </dependency>            
                 
         <dependency>
+            <groupId>org.apache.abdera</groupId>
+            <artifactId>abdera-extensions-main</artifactId>
+            <version>0.4.0-incubating</version> 
+        </dependency>            
+                
+        <dependency>
+            <groupId>org.apache.abdera</groupId>
+            <artifactId>abdera-extensions-json</artifactId>
+            <version>0.4.0-incubating</version> 
+        </dependency>            
+                
+        <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>servlet-api</artifactId>
             <version>2.4</version> 

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=685516&r1=685515&r2=685516&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 Wed Aug 13 04:18:32 2008
@@ -48,12 +48,14 @@
 import org.apache.abdera.model.Workspace;
 import org.apache.abdera.parser.ParseException;
 import org.apache.abdera.parser.Parser;
+import org.apache.abdera.writer.WriterFactory;
+
 import org.apache.commons.codec.binary.Base64;
 import org.apache.tuscany.sca.data.collection.Entry;
 import org.apache.tuscany.sca.databinding.Mediator;
 import org.apache.tuscany.sca.interfacedef.DataType;
-import org.apache.tuscany.sca.interfacedef.Operation;
 import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl;
+import org.apache.tuscany.sca.interfacedef.Operation;
 import org.apache.tuscany.sca.interfacedef.util.XMLType;
 import org.apache.tuscany.sca.invocation.InvocationChain;
 import org.apache.tuscany.sca.invocation.Invoker;
@@ -318,18 +320,35 @@
                 		}
                 	}
                 }
-                
-                // 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) {
-                    throw new ServletException(ioe);
-                }
+                // Content negotiation
+            	String acceptType = request.getHeader( "Accept" );
+            	String preferredType = getContentPreference( acceptType ); 
+            	if (( preferredType != null ) && ((preferredType.indexOf( "json") > -1) || (preferredType.indexOf( "JSON") > -1 ))) {
+            		// JSON response body
+                    response.setContentType("application/json;type=feed");
+                    
+                    try {
+                		Abdera abdera = new Abdera();
+                		WriterFactory wf = abdera.getWriterFactory();
+                		org.apache.abdera.writer.Writer json = wf.getWriter("json");
+                    	feed.writeTo(json, response.getWriter());
+                    } catch (Exception e) {
+                        throw new ServletException(e);
+                    }           		
+
+            	} else {
+            		// Write the Atom feed
+            		response.setContentType("application/atom+xml;type=feed");
+            		// 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) {
+            			throw new ServletException(ioe);
+            		}
+            	}
             } else {
                 response.sendError(HttpServletResponse.SC_NOT_FOUND);
             }
@@ -374,12 +393,30 @@
                       response.addHeader(LOCATION, link.getHref().toString());
                    }
                 }
-                response.setContentType("application/atom+xml;type=entry");
-                try {
-                        feedEntry.writeTo(getWriter(response));
-                } catch (IOException ioe) {
-                    throw new ServletException(ioe);
-                }
+
+                // Content negotiation
+                String acceptType = request.getHeader( "Accept" );
+            	String preferredType = getContentPreference( acceptType ); 
+            	if (( preferredType != null ) && ((preferredType.indexOf( "json") > -1) || (preferredType.indexOf( "JSON") > -1 ))) {
+            		// JSON response body
+                    response.setContentType("application/json;type=entry");
+                    try {
+                		Abdera abdera = new Abdera();
+                		WriterFactory wf = abdera.getWriterFactory();
+                		org.apache.abdera.writer.Writer json = wf.getWriter("json");
+                    	feedEntry.writeTo(json, response.getWriter());
+                    } catch (Exception e) {
+                        throw new ServletException(e);
+                    }           		
+            	} else {
+            		// XML response body 
+            		response.setContentType("application/atom+xml;type=entry");
+            		try {
+            			feedEntry.writeTo(getWriter(response));
+            		} catch (IOException ioe) {
+            			throw new ServletException(ioe);
+            		}
+            	}
             } else {
                 response.sendError(HttpServletResponse.SC_NOT_FOUND);
             }
@@ -710,4 +747,14 @@
         
         return feedId + "-" + feedUpdated.hashCode();
     }
+
+    public static String getContentPreference( String acceptType ) {
+    	if (( acceptType == null ) || ( acceptType.length() < 1 )) {
+            return "application/atom+xml";    		
+    	}
+    	StringTokenizer st = new StringTokenizer( acceptType, "," );
+    	if ( st.hasMoreTokens() )
+    		return st.nextToken();    		
+        return "application/atom+xml";
+    }
 }

Added: tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ContentNegotiationTest.java
URL: http://svn.apache.org/viewvc/tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ContentNegotiationTest.java?rev=685516&view=auto
==============================================================================
--- tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ContentNegotiationTest.java (added)
+++ tuscany/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ContentNegotiationTest.java Wed Aug 13 04:18:32 2008
@@ -0,0 +1,249 @@
+/*
+ * 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 java.io.Reader;
+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 content negotiation for Atom binding in Tuscany.
+ * Uses the SCA provided Provider composite to act as a server.
+ * Uses the Abdera provided Client to act as a client.
+ */
+public class ContentNegotiationTest {
+	public final static String providerURI = "http://localhost:8084/customer";
+	protected static SCADomain scaProviderDomain;
+	protected static CustomerClient testService;
+    protected static Abdera abdera;
+    protected static AbderaClient client;
+    protected static Parser abderaParser;    
+    protected static String lastId;
+
+	@BeforeClass
+	public static void init() throws Exception {
+		System.out.println(">>>ContentNegotiationTest.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(">>>ContentNegotiationTest.destroy");
+		scaProviderDomain.close();
+	}
+
+	@Test
+	public void testPrelim() throws Exception {
+		Assert.assertNotNull(scaProviderDomain);
+		Assert.assertNotNull( client );
+	}
+	
+    @Test
+	public void testPost() throws Exception {
+		System.out.println(">>>ContentNegotiationTest.testPost");
+		// 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.
+		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.assertEquals(201, res.getStatus());
+    	String returnedContentType = res.getContentType().toString().trim();
+    	Assert.assertEquals(contentType, returnedContentType );
+
+    	String eTag = res.getHeader( "ETag" );
+    	if ( eTag != null)
+    		lastId = eTag.substring( 1, eTag.length()-1);
+    	
+    	// AtomTestCaseUtils.printResponseHeaders( "Entry post response headers:", "   ", res );
+    	// System.out.println("Entry post response content:");
+    	// AtomTestCaseUtils.prettyPrint(abdera, res.getDocument());
+	}
+
+	@Test
+	public void testXMLEntryGet() throws Exception {
+		System.out.println(">>>ContentNegotiationTest.testXMLEntryGet");
+		RequestOptions opts = new RequestOptions();
+		opts.setHeader( "Accept", "application/atom+xml" );
+		
+		IRI colUri = new IRI(providerURI).resolve("customer");
+		ClientResponse res = client.get(colUri.toString() + "/" + lastId, opts);
+    	Assert.assertEquals(200, res.getStatus());
+    	String returnedContentType = res.getContentType().toString().trim();
+    	// Assert.assertEquals(contentType, returnedContentType );
+		res.release();	    
+	}
+
+	@Test
+	public void testJSONEntryGet() throws Exception {
+		System.out.println(">>>ContentNegotiationTest.testJSONEntryGet");
+		RequestOptions opts = new RequestOptions();
+		opts.setHeader( "Accept", "application/json" );
+		
+		IRI colUri = new IRI(providerURI).resolve("customer");
+		ClientResponse res = client.get(colUri.toString() + "/" + lastId, opts);
+		try {
+			Assert.assertEquals(200, res.getStatus());
+			// Abdera 0.4 throws exception on getContentType with application/json.    	
+			// System.out.println( "ContentNegotiationTest.testJSONEntryGet contentType=" + res.getContentType());
+			String contentType = res.getHeader( "Content-Type");
+			Assert.assertTrue( -1 < contentType.indexOf( "application/json" ));
+			// Following is a poor man's JSONObject test to avoid dependency on JSON libs.
+			// JSONObject jsonResp = new JSONObject(res.);
+			// Assert.assertEquals(12345, jsonResp.getInt("result"));
+			String responseBody = readResponse( res.getReader() );
+			Assert.assertTrue( responseBody.startsWith( "{") );
+			Assert.assertTrue( responseBody.endsWith( "}") );
+			Assert.assertTrue( -1 < responseBody.indexOf( "\"id\"" ));
+			Assert.assertTrue( -1 < responseBody.indexOf( "\"title\"" ));
+			Assert.assertTrue( -1 < responseBody.indexOf( "\"updated\"" ));
+			// AtomTestCaseUtils.printResponseHeaders( "JSON Entry response headers:", "   ", res );
+			// System.out.println( "ContentNegotiationTest.testJSONEntryGet JSON entry body=" + responseBody );
+		} finally {
+			res.release();	    			
+		}
+	}
+
+	@Test
+    public void testXMLFeedGet() throws Exception {		
+		System.out.println(">>>ContentNegotiationTest.testXMLFeedGet");
+		RequestOptions opts = new RequestOptions();
+		opts.setHeader( "Accept", "application/atom+xml" );
+		
+		// Atom feed request
+		ClientResponse res = client.get(providerURI, opts);
+		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 );
+			// RFC 4287 requires non-null id, title, updated elements
+			Assert.assertNotNull( feed.getId() );
+			Assert.assertNotNull( feed.getTitle() );
+			Assert.assertNotNull( feed.getUpdated() );
+			// AtomTestCaseUtils.printFeed( "Feed values", "   ", feed );
+		} finally {
+			res.release();
+		}
+	}		
+
+	@Test
+    public void testJSONFeedGet() throws Exception {		
+		System.out.println(">>>ContentNegotiationTest.testJSONFeedGet");
+		RequestOptions opts = new RequestOptions();
+		opts.setHeader( "Accept", "application/json" );
+		
+		// JSON feed request
+		ClientResponse res = client.get(providerURI, opts);
+		Assert.assertNotNull(res);
+		try {
+			// Assert feed provided since no predicates
+			Assert.assertEquals(200, res.getStatus());
+			// Abdera 0.4 throws exception on getContentType with application/json.    	
+			// System.out.println( "ContentNegotiationTest.testJSONEntryGet contentType=" + res.getContentType());
+			String contentType = res.getHeader( "Content-Type");
+			Assert.assertTrue( -1 < contentType.indexOf( "application/json" ));
+			// Following is a poor man's JSONObject test to avoid dependency on JSON libs.
+			// JSONObject jsonResp = new JSONObject(res.);
+			// Assert.assertEquals(12345, jsonResp.getInt("result"));
+			String responseBody = readResponse( res.getReader() );
+			Assert.assertTrue( responseBody.startsWith( "{") );
+			Assert.assertTrue( responseBody.endsWith( "}") );
+			Assert.assertTrue( -1 < responseBody.indexOf( "\"id\"" ));
+			Assert.assertTrue( -1 < responseBody.indexOf( "\"title\"" ));
+			Assert.assertTrue( -1 < responseBody.indexOf( "\"updated\"" ));
+			Assert.assertTrue( -1 < responseBody.indexOf( "\"entries\"" ));
+			// AtomTestCaseUtils.printResponseHeaders( "JSON Entry response headers:", "   ", res );
+			// System.out.println( "ContentNegotiationTest.testJSONEntryGet JSON entry body=" + responseBody );
+		} finally {
+			res.release();
+		}
+	}
+	
+	protected String readResponse( Reader responseReader ) {
+		if ( responseReader == null ) return ""; 
+		StringBuffer sb = new StringBuffer(1024);
+		try {
+			int charValue = 0;
+			while ((charValue = responseReader.read()) != -1) {
+				//result = result + (char) charValue;
+				sb.append((char)charValue);
+			}
+		} catch ( IOException e ) {
+		}
+		return sb.toString();
+	}
+}