diff options
author | beckerdo <beckerdo@13f79535-47bb-0310-9956-ffa450edef68> | 2008-10-29 19:45:05 +0000 |
---|---|---|
committer | beckerdo <beckerdo@13f79535-47bb-0310-9956-ffa450edef68> | 2008-10-29 19:45:05 +0000 |
commit | d418a3d6f69f0f3058b7122688cc436bd21c647e (patch) | |
tree | 6dd2a1782210a355d9c21929d728069a82d56e6c /java/sca/modules/binding-atom-abdera/src/test | |
parent | 772f7df672ca613f14cb2475fb69e09dbe239fc7 (diff) |
Tuscany-2567 Support for streaming postMedia and putMedia in Atom binding
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@708990 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/sca/modules/binding-atom-abdera/src/test')
3 files changed, 530 insertions, 0 deletions
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/MediaCollectionImpl.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/MediaCollectionImpl.java new file mode 100644 index 0000000000..5d5953aaaa --- /dev/null +++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/MediaCollectionImpl.java @@ -0,0 +1,210 @@ +/* + * 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.InputStream; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.apache.abdera.Abdera; +import org.apache.abdera.factory.Factory; +import org.apache.abdera.i18n.iri.IRI; +import org.apache.abdera.model.Content; +import org.apache.abdera.model.Entry; +import org.apache.abdera.model.Feed; +import org.apache.tuscany.sca.binding.atom.collection.Collection; +import org.apache.tuscany.sca.binding.atom.collection.MediaCollection; +import org.apache.tuscany.sca.binding.atom.collection.NotFoundException; +import org.osoa.sca.annotations.Scope; + +@Scope("COMPOSITE") +public class MediaCollectionImpl implements MediaCollection { + private final Abdera abdera = new Abdera(); + private Map<String, Entry> entries = new HashMap<String, Entry>(); + private Map<String, String> mediaFiles = new HashMap<String, String>(); + public Date lastModified = new Date(); + + public Entry post(Entry entry) { + System.out.println(">>> MediaCollectionImpl.post entry=" + entry.getTitle()); + + if(!("Exception_Test".equalsIgnoreCase(entry.getTitle()))) + { + String id = "urn:uuid:customer-" + UUID.randomUUID().toString(); + entry.setId(id); + + entry.addLink("" + id, "edit"); + entry.addLink("" + id, "alternate"); + Date now = new Date(); + entry.setUpdated(now); + lastModified = now; + entries.put(id, entry); + + System.out.println(">>> MediaCollectionImpl.post return id=" + id); + + return entry; + + } + else + { + throw new IllegalArgumentException("Exception in Post method"); + } + } + + public Entry get(String id) { + System.out.println(">>> MediaCollectionImpl.get id=" + id); + return entries.get(id); + } + + public void put(String id, Entry entry) throws NotFoundException { + System.out.println(">>> MediaCollectionImpl.put id=" + id + " entry=" + entry.getTitle()); + if(entries.containsKey(id)){ + Date now = new Date(); + entry.setUpdated(now); + lastModified = now; + entries.put(id, entry); + } + else { + throw new NotFoundException(); + } + } + + public void delete(String id) throws NotFoundException { + System.out.println(">>> MediaCollectionImpl.delete id=" + id); + if(entries.containsKey(id)){ + entries.remove(id); + lastModified = new Date(); + } + else { + throw new NotFoundException(); + } + } + + public Feed getFeed() { + System.out.println(">>> MediaCollectionImpl.getFeed"); + + Feed feed = this.abdera.getFactory().newFeed(); + feed.setId("customers" + this.hashCode() ); // provide unique id for feed instance. + feed.setTitle("customers"); + feed.setSubtitle("This is a sample feed"); + feed.setUpdated(lastModified); + feed.addLink(""); + feed.addLink("", "self"); + + for (Entry entry : entries.values()) { + feed.addEntry(entry); + } + + return feed; + } + + public Feed query(String queryString) { + System.out.println(">>> MediaCollectionImpl.query collection " + queryString); + return getFeed(); + } + + // This method used for testing. + protected void testPut(String value) { + String id = "urn:uuid:customer-" + UUID.randomUUID().toString(); + + Entry entry = abdera.getFactory().newEntry(); + entry.setId(id); + entry.setTitle("customer " + value); + + Content content = this.abdera.getFactory().newContent(); + content.setContentType(Content.Type.TEXT); + content.setValue(value); + + entry.setContentElement(content); + + entry.addLink("" + id, "edit"); + entry.addLink("" + id, "alternate"); + + entry.setUpdated(new Date()); + + entries.put(id, entry); + System.out.println(">>> id=" + id); + } + + // MediaCollection role + public Entry postMedia(String title, String slug, String contentType, InputStream media) { + System.out.println(">>> MediaCollectionImpl.postMedia title=" + title + ", slug=" + slug + ", contentType=" + contentType ); + + Factory factory = abdera.getFactory(); + Entry entry = factory.newEntry(); + // Must provide entry to media as per Atom Pub spec (http://tools.ietf.org/html/rfc5023#section-9.6) + // <?xml version="1.0"?> + // <entry xmlns="http://www.w3.org/2005/Atom"> + // <title>The Beach</title> (REQUIRED) + // <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id> (REQUIRED) + // <updated>2005-10-07T17:17:08Z</updated> + // <summary type="text" /> (REQUIRED, OPTIONAL to populate + // <content type="image/png" src="http://media.example.org/the_beach.png"/> + // <link rel="edit-media" href="http://media.example.org/edit/the_beach.png" /> + // <link rel="edit" href="http://example.org/media/edit/the_beach.atom" /> + // </entry> + + // Normalize title + entry.setTitle( title ); + String normalTitle = title.replace( " ", "_" ); + String hostURL = "http://media.example.org/"; + int lastDelimiterPos = contentType != null ? contentType.lastIndexOf( "/" ) : -1; + String extension = ""; + if ( lastDelimiterPos != -1 ) { + extension = contentType.substring( lastDelimiterPos + 1 ); + } else { + extension = contentType; + } + long mediaLength = -1; + try { + mediaLength = media.skip( Long.MAX_VALUE ); + } catch ( IOException e ){} + + // A true implementation would store the media to a repository, e.g. file system. + // This implementation record's the id and the location. + String id = "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a-" + mediaFiles.size(); + String reposLocation = hostURL + "edit/" + normalTitle; + mediaFiles.put( id, reposLocation ); + + // Build entry for media link. + entry.setUpdated( new Date() ); + entry.setId( id ); + // Convention. Return header properties as key values. + entry.setSummary( "Content-Type=" + contentType + ",Content-Length=" + mediaLength ); + entry.setContent( new IRI( hostURL + normalTitle + "." + extension ), contentType ); + entry.addLink( reposLocation + ".atom", "edit" ); + entry.addLink( reposLocation + "." + extension, "edit-media" ); + return entry; + } + + public void putMedia(String id, String contentType, InputStream media) throws NotFoundException { + System.out.println(">>> MediaCollectionImpl.putMedia id=" + id + ", contentType=" + contentType ); + + // Must responsd with success or not found as per Atom Pub spec (http://tools.ietf.org/html/rfc5023#section-9.6) + // Body is null. + if ( !id.endsWith( "0" ) ) + throw new NotFoundException( "Media at id=" + id + " not found." ); + + // A true implementation would update the media in the media repository. + } + +} diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/MediaCollectionTestCase.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/MediaCollectionTestCase.java new file mode 100644 index 0000000000..0aabf225a4 --- /dev/null +++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/MediaCollectionTestCase.java @@ -0,0 +1,287 @@ +/* + * 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.File; +import java.io.FileInputStream; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +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.model.Entry; +import org.apache.abdera.model.Feed; +import org.apache.abdera.model.Document; +import org.apache.abdera.model.Link; +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; + +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.PutMethod; +import org.apache.commons.httpclient.methods.InputStreamRequestEntity; + +/** + * 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 MediaCollectionTestCase { + public final static String providerURI = "http://localhost:8084/receipt"; + 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 String mediaId; + 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(">>>MediaCollectionTestCase.init"); + scaProviderDomain = SCADomain.newInstance("org/apache/tuscany/sca/binding/atom/ReceiptProvider.composite"); + abdera = new Abdera(); + client = new AbderaClient(abdera); + abderaParser = Abdera.getNewParser(); + } + + @AfterClass + public static void destroy() throws Exception { + System.out.println(">>>MediaCollectionTestCase.destroy"); + scaProviderDomain.close(); + } + + @Test + public void testPrelim() throws Exception { + Assert.assertNotNull(scaProviderDomain); + Assert.assertNotNull( client ); + } + + @Test + public void testMediaEntryPost() throws Exception { + // Pseudo Code (see APP (http://tools.ietf.org/html/rfc5023#section-9.6) + // Post request + // POST /edit/ HTTP/1.1 + // Host: media.example.org + // Content-Type: image/png + // Slug: The Beach + // Content-Length: nnn + // ...binary data... + + // Testing of entry creation + String receiptName = "Auto Repair Bill"; + String fileName = "ReceiptToms.gif"; + File input = new File( fileName ); + boolean exists = input.exists(); + Assert.assertTrue( exists ); + + // Prepare HTTP post + // PostMethod post = new PostMethod( colUri.toString() ); + PostMethod post = new PostMethod( providerURI ); + post.addRequestHeader( "Content-Type", "image/gif" ); + post.addRequestHeader( "Title", "Title " + receiptName + "" ); + post.addRequestHeader( "Slug", "Slug " + receiptName + "" ); + post.setRequestEntity( + new InputStreamRequestEntity( new FileInputStream( input ), "image/gif" ) ); + + // Get HTTP client + HttpClient httpclient = new HttpClient(); + try { + // Execute request + int result = httpclient.executeMethod(post); + // Pseudo Code (see APP (http://tools.ietf.org/html/rfc5023#section-9.6) + // Post response + // Tuscany responds with proper media links. Note that the media is + // stored in a different location than the media information which is + // stored in the Atom feed. + // HTTP/1.1 201 Created + // Display status code + // System.out.println("Response status code: " + result + ", status text=" + post.getStatusText() ); + Assert.assertEquals(201, result ); + // Display response + // System.out.println("Response body: "); + // System.out.println(post.getResponseBodyAsString()); // Warning: BodyAsString recommends BodyAsStream + + // Location: http://example.org/media/edit/the_beach.atom (REQUIRED) + // System.out.println( "Response Location=" + post.getResponseHeader( "Location" ).getValue() + "." ); + Header header = post.getResponseHeader( "Location" ); + Assert.assertNotNull( header ); + Assert.assertNotNull( header.getValue() ); + // ContentLocation: http://example.org/media/edit/the_beach.jpg (REQUIRED) + // System.out.println( "Response Content-Location=" + post.getResponseHeader( "Content-Location" ).getValue() ); + header = post.getResponseHeader( "Content-Location" ); + Assert.assertNotNull( header ); + Assert.assertNotNull( header.getValue() ); + // Content-Type: application/atom+xml;type=entry;charset="utf-8" + // System.out.println( "Response Content-Type=" + post.getResponseHeader( "Content-Type" ).getValue()); + header = post.getResponseHeader( "Content-Type" ); + Assert.assertNotNull( header ); + Assert.assertNotNull( header.getValue() ); + // Content-Length: nnn (OPTIONAL) + // System.out.println( "Response Content-Length=" + post.getResponseHeader( "Content-Length" ).getValue() ); + header = post.getResponseHeader( "Content-Length" ); + Assert.assertNotNull( header ); + Assert.assertNotNull( header.getValue() ); + // <?xml version="1.0"?> + // <entry xmlns="http://www.w3.org/2005/Atom"> + // <title>The Beach</title> (REQUIRED) + // <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id> (REQUIRED) + // <updated>2005-10-07T17:17:08Z</updated> + // <author><name>Daffy</name></author> + // <summary type="text" /> (REQUIRED, OPTIONAL to populate + // <content type="image/png" src="http://media.example.org/the_beach.png"/> + // <link rel="edit-media" href="http://media.example.org/edit/the_beach.png" /> + // <link rel="edit" href="http://example.org/media/edit/the_beach.atom" /> + // </entry> + Document<Entry> document = abderaParser.parse( post.getResponseBodyAsStream() ); + Entry entry = document.getRoot(); + String title = entry.getTitle(); + // System.out.println( "mediaPost entry.title=" + title ); + Assert.assertNotNull( title ); + IRI id = entry.getId(); + // System.out.println( "mediaPost entry.id=" + id ); + Assert.assertNotNull( id ); + mediaId = id.toString(); + Assert.assertNotNull( mediaId ); // Save for put/update request + Date updated = entry.getUpdated(); + // System.out.println( "mediaPost entry.updated=" + updated); + Assert.assertNotNull( updated ); + String summary = entry.getSummary(); + // System.out.println( "mediaPost entry.summary=" + summary); + Assert.assertNotNull( summary ); + IRI contentSrc = entry.getContentSrc(); + // System.out.println( "mediaPost entry.content.src=" + contentSrc + ", type=" + entry.getContentType()); + Assert.assertNotNull( contentSrc ); + Link editLink = entry.getEditLink(); + // System.out.println( "mediaPost entry.editLink" + " rel=" + editLink.getRel() + ", href=" + editLink.getHref() ); + Assert.assertNotNull( editLink ); + Assert.assertNotNull( editLink.getRel() ); + Assert.assertNotNull( editLink.getHref() ); + Link editMediaLink = entry.getEditMediaLink(); + // System.out.println( "mediaPost entry.editMediaLink" + " rel=" + editMediaLink.getRel() + ", href=" + editMediaLink.getHref() ); + Assert.assertNotNull( editMediaLink ); + Assert.assertNotNull( editMediaLink.getRel() ); + Assert.assertNotNull( editMediaLink.getHref() ); + + } finally { + // Release current connection to the connection pool once you are done + post.releaseConnection(); + } + } + + @Test + public void testMediaEntryPutFound() throws Exception { + // Pseudo Code (see APP (http://tools.ietf.org/html/rfc5023#section-9.6) + // Testing of entry update + String receiptName = "Value Autoglass Bill"; + String fileName = "ReceiptValue.jpg"; + File input = new File( fileName ); + boolean exists = input.exists(); + Assert.assertTrue( exists ); + + // Prepare HTTP put request + // PUT /edit/the_beach.png HTTP/1.1 + // Host: media.example.org + // Content-Type: image/png + // Content-Length: nnn + // ...binary data... + PutMethod put = new PutMethod( providerURI + "/" + mediaId ); + put.addRequestHeader( "Content-Type", "image/jpg" ); + put.addRequestHeader( "Title", "Title " + receiptName + "" ); + put.addRequestHeader( "Slug", "Slug " + receiptName + "" ); + put.setRequestEntity( + new InputStreamRequestEntity( new FileInputStream( input ), "image/jpg" ) ); + + // Get HTTP client + HttpClient httpclient = new HttpClient(); + try { + // Execute request + int result = httpclient.executeMethod(put); + // Pseudo Code (see APP (http://tools.ietf.org/html/rfc5023#section-9.6) + // Display status code + // System.out.println("Response status code: " + result + ", status text=" + put.getStatusText() ); + Assert.assertEquals(200, result ); + // Display response. Should be empty for put. + // System.out.println("Response body: "); + // System.out.println(put.getResponseBodyAsString()); // Warning: BodyAsString recommends BodyAsStream + } finally { + // Release current connection to the connection pool once you are done + put.releaseConnection(); + } + } + + @Test + public void testMediaEntryPutNotFound() throws Exception { + // Pseudo Code (see APP (http://tools.ietf.org/html/rfc5023#section-9.6) + // Testing of entry update + String receiptName = "Value Autoglass Bill"; + String fileName = "ReceiptValue.jpg"; + File input = new File( fileName ); + boolean exists = input.exists(); + Assert.assertTrue( exists ); + + // Prepare HTTP put request + // PUT /edit/the_beach.png HTTP/1.1 + // Host: media.example.org + // Content-Type: image/png + // Content-Length: nnn + // ...binary data... + PutMethod put = new PutMethod( providerURI + "/" + mediaId + "-bogus" ); // Does not exist. + put.addRequestHeader( "Content-Type", "image/jpg" ); + put.addRequestHeader( "Title", "Title " + receiptName + "" ); + put.addRequestHeader( "Slug", "Slug " + receiptName + "" ); + put.setRequestEntity( + new InputStreamRequestEntity( new FileInputStream( input ), "image/jpg" ) ); + + // Get HTTP client + HttpClient httpclient = new HttpClient(); + try { + // Execute request + int result = httpclient.executeMethod(put); + // Pseudo Code (see APP (http://tools.ietf.org/html/rfc5023#section-9.6) + // Display status code + // System.out.println("Response status code: " + result + ", status text=" + put.getStatusText() ); + Assert.assertEquals(404, result ); + // Display response. Should be empty for put. + // System.out.println("Response body: "); + // System.out.println(put.getResponseBodyAsString()); // Warning: BodyAsString recommends BodyAsStream + } finally { + // Release current connection to the connection pool once you are done + put.releaseConnection(); + } + } +} diff --git a/java/sca/modules/binding-atom-abdera/src/test/resources/org/apache/tuscany/sca/binding/atom/ReceiptProvider.composite b/java/sca/modules/binding-atom-abdera/src/test/resources/org/apache/tuscany/sca/binding/atom/ReceiptProvider.composite new file mode 100644 index 0000000000..71aa932a12 --- /dev/null +++ b/java/sca/modules/binding-atom-abdera/src/test/resources/org/apache/tuscany/sca/binding/atom/ReceiptProvider.composite @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<!-- + * 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. +--> +<composite xmlns="http://www.osoa.org/xmlns/sca/1.0" + xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.0"
+ targetNamespace = "http://receipt" + name="ReceiptProvider">
+
+ <service name="receipt" promote="MediaCollection">
+ <tuscany:binding.atom uri = "http://localhost:8084/receipt"/>
+ </service>
+
+ <component name="MediaCollection">
+ <implementation.java class="org.apache.tuscany.sca.binding.atom.MediaCollectionImpl"/>
+ </component>
+
+</composite>
|