diff options
Diffstat (limited to 'java/sca/modules')
3 files changed, 327 insertions, 19 deletions
diff --git a/java/sca/modules/binding-atom-abdera/pom.xml b/java/sca/modules/binding-atom-abdera/pom.xml index ec8ecaeee7..cfd2e60849 100644 --- a/java/sca/modules/binding-atom-abdera/pom.xml +++ b/java/sca/modules/binding-atom-abdera/pom.xml @@ -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> 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 e171de8595..766907ef11 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 @@ -48,12 +48,14 @@ import org.apache.abdera.model.Service; 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 @@ class AtomBindingListenerServlet extends HttpServlet { } } } - - // 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 @@ class AtomBindingListenerServlet extends HttpServlet { 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 @@ class AtomBindingListenerServlet extends HttpServlet { 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"; + } } diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ContentNegotiationTest.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ContentNegotiationTest.java new file mode 100644 index 0000000000..08f8e3db2a --- /dev/null +++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ContentNegotiationTest.java @@ -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();
+ }
+}
|