summaryrefslogtreecommitdiffstats
path: root/java/sca/contrib/modules/binding-feed
diff options
context:
space:
mode:
authorlresende <lresende@13f79535-47bb-0310-9956-ffa450edef68>2008-11-19 00:07:37 +0000
committerlresende <lresende@13f79535-47bb-0310-9956-ffa450edef68>2008-11-19 00:07:37 +0000
commitad1c9458ea08eb593be252b706a88568f17c494c (patch)
treea40c652e6409242cc858afbdf24e52e429892115 /java/sca/contrib/modules/binding-feed
parent85ec6444c1ff2cb29da5889344d365779d3dc778 (diff)
Moving current trunk modules to contrib, before starting the Equinox branch merge
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@718812 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/sca/contrib/modules/binding-feed')
-rw-r--r--java/sca/contrib/modules/binding-feed/LICENSE205
-rw-r--r--java/sca/contrib/modules/binding-feed/NOTICE6
-rw-r--r--java/sca/contrib/modules/binding-feed/pom.xml165
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/AtomBinding.java30
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/AtomBindingFactory.java35
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/RSSBinding.java30
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/RSSBindingFactory.java35
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/collection/Collection.java72
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/collection/MediaCollection.java55
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/collection/NotFoundException.java45
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/impl/AtomBindingFactoryImpl.java36
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/impl/AtomBindingImpl.java96
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/impl/RSSBindingFactoryImpl.java36
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/impl/RSSBindingImpl.java101
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomBindingInvoker.java345
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomBindingProviderFactory.java74
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomFeedEntryUtil.java117
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomReferenceBindingProvider.java116
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomServiceBindingProvider.java87
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/FeedBindingListenerServlet.java788
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/RSSBindingInvoker.java91
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/RSSBindingProviderFactory.java74
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/RSSReferenceBindingProvider.java65
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/RSSServiceBindingProvider.java85
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/resources/META-INF/services/org.apache.tuscany.sca.binding.feed.AtomBindingFactory19
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/resources/META-INF/services/org.apache.tuscany.sca.binding.feed.RSSBindingFactory19
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor20
-rw-r--r--java/sca/contrib/modules/binding-feed/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory20
-rw-r--r--java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/Consumer.java35
-rw-r--r--java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/CustomerClient.java25
-rw-r--r--java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/CustomerClientImpl.java97
-rw-r--r--java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/CustomerCollectionImpl.java136
-rw-r--r--java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/Provider.java41
-rw-r--r--java/sca/contrib/modules/binding-feed/src/test/resources/org/apache/tuscany/sca/binding/feed/Consumer.composite32
-rw-r--r--java/sca/contrib/modules/binding-feed/src/test/resources/org/apache/tuscany/sca/binding/feed/Provider.composite33
35 files changed, 3266 insertions, 0 deletions
diff --git a/java/sca/contrib/modules/binding-feed/LICENSE b/java/sca/contrib/modules/binding-feed/LICENSE
new file mode 100644
index 0000000000..6e529a25c4
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/LICENSE
@@ -0,0 +1,205 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
+
+
+
diff --git a/java/sca/contrib/modules/binding-feed/NOTICE b/java/sca/contrib/modules/binding-feed/NOTICE
new file mode 100644
index 0000000000..1325efd8bf
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/NOTICE
@@ -0,0 +1,6 @@
+${pom.name}
+Copyright (c) 2005 - 2008 The Apache Software Foundation
+
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
+
diff --git a/java/sca/contrib/modules/binding-feed/pom.xml b/java/sca/contrib/modules/binding-feed/pom.xml
new file mode 100644
index 0000000000..c0c895a894
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/pom.xml
@@ -0,0 +1,165 @@
+<?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.
+-->
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-modules</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>tuscany-binding-feed</artifactId>
+ <name>Apache Tuscany SCA Atom+RSS Feed Binding Extension</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-assembly</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-interface-java</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-data-api</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-core-spi</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-databinding</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-host-http</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-httpclient</groupId>
+ <artifactId>commons-httpclient</artifactId>
+ <version>3.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>rome</groupId>
+ <artifactId>rome</artifactId>
+ <version>0.9</version>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.4</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-host-jetty</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-implementation-java-runtime</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-host-embedded</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.5</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ <version>1.3</version>
+ <exclusions>
+ <exclusion>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>1.1.1</version>
+ <exclusions>
+ <exclusion>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>avalon-framework</groupId>
+ <artifactId>avalon-framework</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ </dependencies>
+
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+
+ <configuration>
+ <instructions>
+ <Bundle-Version>${tuscany.version}</Bundle-Version>
+ <Bundle-SymbolicName>org.apache.tuscany.sca.binding.feed</Bundle-SymbolicName>
+ <Bundle-Description>${pom.name}</Bundle-Description>
+ <Export-Package>org.apache.tuscany.sca.binding.feed*</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/AtomBinding.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/AtomBinding.java
new file mode 100644
index 0000000000..00aa813af2
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/AtomBinding.java
@@ -0,0 +1,30 @@
+/*
+ * 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.feed;
+
+import org.apache.tuscany.sca.assembly.Binding;
+
+/**
+ * Atom binding model.
+ *
+ * @version $Rev$ $Date$
+ */
+public interface AtomBinding extends Binding {
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/AtomBindingFactory.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/AtomBindingFactory.java
new file mode 100644
index 0000000000..050ba9b73c
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/AtomBindingFactory.java
@@ -0,0 +1,35 @@
+/*
+ * 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.feed;
+
+/**
+ * Factory for the Atom binding
+ *
+ * @version $Rev$ $Date$
+ */
+public interface AtomBindingFactory {
+
+ /**
+ * Creates a new Atom binding.
+ * @return the new Atom binding
+ */
+ AtomBinding createAtomBinding();
+
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/RSSBinding.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/RSSBinding.java
new file mode 100644
index 0000000000..81b9fd95ad
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/RSSBinding.java
@@ -0,0 +1,30 @@
+/*
+ * 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.feed;
+
+import org.apache.tuscany.sca.assembly.Binding;
+
+/**
+ * RSS Feed binding model.
+ *
+ * @version $Rev$ $Date$
+ */
+public interface RSSBinding extends Binding {
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/RSSBindingFactory.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/RSSBindingFactory.java
new file mode 100644
index 0000000000..c95c8ac012
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/RSSBindingFactory.java
@@ -0,0 +1,35 @@
+/*
+ * 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.feed;
+
+/**
+ * Factory for the RSS binding
+ *
+ * @version $Rev$ $Date$
+ */
+public interface RSSBindingFactory {
+
+ /**
+ * Creates a new RSS binding.
+ * @return the new RSS binding
+ */
+ RSSBinding createRSSBinding();
+
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/collection/Collection.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/collection/Collection.java
new file mode 100644
index 0000000000..30068afa0a
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/collection/Collection.java
@@ -0,0 +1,72 @@
+/*
+ * 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.feed.collection;
+
+import org.osoa.sca.annotations.Remotable;
+
+import com.sun.syndication.feed.atom.Entry;
+
+/**
+ * Provides access to a collection of resources using Atom.
+ *
+ * @version $Rev$ $Date$
+ */
+@Remotable
+public interface Collection {
+
+ /**
+ * Get an RSS or Atom feed for a collection of resources.
+ *
+ * @return the RSS or Atom feed
+ */
+ com.sun.syndication.feed.atom.Feed getFeed();
+
+ /**
+ * Creates a new entry.
+ *
+ * @param entry
+ * @return
+ */
+ Entry post(Entry entry);
+
+ /**
+ * Retrieves an entry.
+ *
+ * @param id
+ * @return
+ */
+ Entry get(String id) throws NotFoundException;
+
+ /**
+ * Update an entry.
+ *
+ * @param id
+ * @param entry
+ * @return
+ */
+ void put(String id, Entry entry) throws NotFoundException;
+
+ /**
+ * Delete an entry.
+ *
+ * @param id
+ */
+ void delete(String id) throws NotFoundException;
+
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/collection/MediaCollection.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/collection/MediaCollection.java
new file mode 100644
index 0000000000..39a4213a65
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/collection/MediaCollection.java
@@ -0,0 +1,55 @@
+/*
+ * 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.feed.collection;
+
+import java.io.InputStream;
+
+import org.osoa.sca.annotations.Remotable;
+
+import com.sun.syndication.feed.atom.Entry;
+
+/**
+ * Provides access to a collection of resources using Atom.
+ *
+ * @version $Rev$ $Date$
+ */
+@Remotable
+public interface MediaCollection extends Collection {
+
+ /**
+ * Creates a new media entry
+ *
+ * @param title
+ * @param slug
+ * @param contentType
+ * @param media
+ */
+ Entry postMedia(String title, String slug, String contentType, InputStream media);
+
+ /**
+ * Update a media entry.
+ *
+ * @param id
+ * @param contentType
+ * @param media
+ * @return
+ */
+ void putMedia(String id, String contentType, InputStream media) throws NotFoundException;
+
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/collection/NotFoundException.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/collection/NotFoundException.java
new file mode 100644
index 0000000000..503f30e685
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/collection/NotFoundException.java
@@ -0,0 +1,45 @@
+/*
+ * 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.feed.collection;
+
+/**
+ * Indicates that a resource could not be found.
+ *
+ * @version $Rev$ $Date$
+ */
+public class NotFoundException extends Exception {
+ private static final long serialVersionUID = -5046027674128627383L;
+
+ public NotFoundException() {
+ }
+
+ public NotFoundException(String message) {
+ super(message);
+ }
+
+ public NotFoundException(Throwable cause) {
+ super(cause);
+ }
+
+ public NotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/impl/AtomBindingFactoryImpl.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/impl/AtomBindingFactoryImpl.java
new file mode 100644
index 0000000000..a9a1167544
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/impl/AtomBindingFactoryImpl.java
@@ -0,0 +1,36 @@
+/*
+ * 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.feed.impl;
+
+import org.apache.tuscany.sca.binding.feed.AtomBinding;
+import org.apache.tuscany.sca.binding.feed.AtomBindingFactory;
+
+/**
+ * Factory for the Atom binding model.
+ *
+ * @version $Rev$ $Date$
+ */
+public class AtomBindingFactoryImpl implements AtomBindingFactory {
+
+ public AtomBinding createAtomBinding() {
+ return new AtomBindingImpl();
+ }
+
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/impl/AtomBindingImpl.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/impl/AtomBindingImpl.java
new file mode 100644
index 0000000000..76551bc412
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/impl/AtomBindingImpl.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.feed.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tuscany.sca.binding.feed.AtomBinding;
+import org.apache.tuscany.sca.policy.Intent;
+import org.apache.tuscany.sca.policy.IntentAttachPointType;
+import org.apache.tuscany.sca.policy.PolicySet;
+import org.apache.tuscany.sca.policy.PolicySetAttachPoint;
+
+/**
+ * Implementation of the Atom Feed binding model.
+ *
+ * @version $Rev$ $Date$
+ */
+class AtomBindingImpl implements AtomBinding, PolicySetAttachPoint {
+
+ private String name;
+ private String uri;
+ private List<Intent> requiredIntents = new ArrayList<Intent>();
+ private List<PolicySet> policySets = new ArrayList<PolicySet>();
+ private IntentAttachPointType intentAttachPointType;
+ private List<PolicySet> applicablePolicySets = new ArrayList<PolicySet>();
+
+ public List<PolicySet> getApplicablePolicySets() {
+ return applicablePolicySets;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getURI() {
+ return uri;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setURI(String uri) {
+ this.uri = uri;
+ }
+
+
+ public boolean isUnresolved() {
+ // The binding is always resolved
+ return false;
+ }
+
+ public void setUnresolved(boolean unresolved) {
+ // The binding is always resolved
+ }
+
+ public List<PolicySet> getPolicySets() {
+ return policySets;
+ }
+
+ public List<Intent> getRequiredIntents() {
+ return requiredIntents;
+ }
+
+ public IntentAttachPointType getType() {
+ return intentAttachPointType;
+ }
+
+ public void setType(IntentAttachPointType intentAttachPointType) {
+ this.intentAttachPointType = intentAttachPointType;
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/impl/RSSBindingFactoryImpl.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/impl/RSSBindingFactoryImpl.java
new file mode 100644
index 0000000000..4d8fb943f0
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/impl/RSSBindingFactoryImpl.java
@@ -0,0 +1,36 @@
+/*
+ * 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.feed.impl;
+
+import org.apache.tuscany.sca.binding.feed.RSSBinding;
+import org.apache.tuscany.sca.binding.feed.RSSBindingFactory;
+
+/**
+ * Factory for the RSS binding model.
+ *
+ * @version $Rev$ $Date$
+ */
+public class RSSBindingFactoryImpl implements RSSBindingFactory {
+
+ public RSSBinding createRSSBinding() {
+ return new RSSBindingImpl();
+ }
+
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/impl/RSSBindingImpl.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/impl/RSSBindingImpl.java
new file mode 100644
index 0000000000..9df2ec60da
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/impl/RSSBindingImpl.java
@@ -0,0 +1,101 @@
+/*
+ * 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.feed.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tuscany.sca.binding.feed.RSSBinding;
+import org.apache.tuscany.sca.policy.Intent;
+import org.apache.tuscany.sca.policy.IntentAttachPointType;
+import org.apache.tuscany.sca.policy.PolicySet;
+import org.apache.tuscany.sca.policy.PolicySetAttachPoint;
+
+/**
+ * Implementation of the RSS Feed binding model.
+ *
+ * @version $Rev$ $Date$
+ */
+class RSSBindingImpl implements RSSBinding, PolicySetAttachPoint {
+
+ private String name;
+ private String uri;
+ private List<Intent> requiredIntents = new ArrayList<Intent>();
+ private List<PolicySet> policySets = new ArrayList<PolicySet>();
+ private IntentAttachPointType intentAttachPointType;
+ private List<PolicySet> applicablePolicySets = new ArrayList<PolicySet>();
+
+ public List<PolicySet> getApplicablePolicySets() {
+ return applicablePolicySets;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getURI() {
+ return uri;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setURI(String uri) {
+ this.uri = uri;
+ }
+
+ public boolean isUnresolved() {
+ return false;
+ }
+
+ public void setUnresolved(boolean unresolved) {
+ // The binding is always resolved
+ }
+
+ public List<PolicySet> getPolicySets() {
+ return policySets;
+ }
+
+ public List<Intent> getRequiredIntents() {
+ return requiredIntents;
+ }
+
+ public IntentAttachPointType getType() {
+ return intentAttachPointType;
+ }
+
+ public void setType(IntentAttachPointType intentAttachPointType) {
+ this.intentAttachPointType = intentAttachPointType;
+ }
+
+ public void setPolicySets(List<PolicySet> policySets) {
+ this.policySets = policySets;
+ }
+
+ public void setRequiredIntents(List<Intent> intents) {
+ this.requiredIntents = intents;
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomBindingInvoker.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomBindingInvoker.java
new file mode 100644
index 0000000000..45b35d9206
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomBindingInvoker.java
@@ -0,0 +1,345 @@
+/*
+ * 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.feed.provider;
+
+import java.io.InputStreamReader;
+import java.io.StringWriter;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.methods.DeleteMethod;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.PutMethod;
+import org.apache.commons.httpclient.methods.StringRequestEntity;
+import org.apache.tuscany.sca.binding.feed.collection.NotFoundException;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.invocation.Invoker;
+import org.apache.tuscany.sca.invocation.Message;
+import org.apache.tuscany.sca.invocation.DataExchangeSemantics;
+import org.osoa.sca.ServiceRuntimeException;
+
+import com.sun.syndication.feed.atom.Entry;
+import com.sun.syndication.feed.atom.Feed;
+import com.sun.syndication.io.WireFeedInput;
+import com.sun.syndication.io.XmlReader;
+
+/**
+ * Invoker for the Atom binding.
+ *
+ * @version $Rev$ $Date$
+ */
+class AtomBindingInvoker implements Invoker, DataExchangeSemantics {
+
+ Operation operation;
+ String uri;
+ HttpClient httpClient;
+ String authorizationHeader;
+
+ //FIXME Support conversion to/from data api entries
+
+ AtomBindingInvoker(Operation operation, String uri, HttpClient httpClient, String authorizationHeader) {
+ this.operation = operation;
+ this.uri = uri;
+ this.httpClient = httpClient;
+ this.authorizationHeader = authorizationHeader;
+ }
+
+ public Message invoke(Message msg) {
+ // Shouldn't get here, as the only supported methods are
+ // defined in the ResourceCollection interface, and implemented
+ // by specific invoker subclasses
+ throw new UnsupportedOperationException(operation.getName());
+ }
+
+ public boolean allowsPassByReference() {
+ return true;
+ }
+
+ /**
+ * Get operation invoker
+ */
+ public static class GetInvoker extends AtomBindingInvoker {
+
+ public GetInvoker(Operation operation, String uri, HttpClient httpClient, String authorizationHeader) {
+ super(operation, uri, httpClient, authorizationHeader);
+ }
+
+ @Override
+ public Message invoke(Message msg) {
+
+ // Get an entry
+ String id = (String)((Object[])msg.getBody())[0];
+
+ // Send an HTTP GET
+ GetMethod getMethod = new GetMethod(uri + "/" + id);
+ getMethod.setRequestHeader("Authorization", authorizationHeader);
+ try {
+ httpClient.executeMethod(getMethod);
+ int status = getMethod.getStatusCode();
+
+ // Read the Atom entry
+ if (status == 200) {
+ Entry feedEntry =
+ AtomFeedEntryUtil.readFeedEntry("atom_1.0", new InputStreamReader(getMethod.getResponseBodyAsStream()));
+ msg.setBody(feedEntry);
+
+ } else if (status == 404) {
+ msg.setFaultBody(new NotFoundException());
+ } else {
+ msg.setFaultBody(new ServiceRuntimeException("HTTP status code: " + status));
+ }
+
+ } catch (Exception e) {
+ msg.setFaultBody(new ServiceRuntimeException(e));
+ } finally {
+ getMethod.releaseConnection();
+ }
+
+ return msg;
+ }
+ }
+
+ /**
+ * Post operation invoker
+ */
+ public static class PostInvoker extends AtomBindingInvoker {
+
+ public PostInvoker(Operation operation, String uri, HttpClient httpClient, String authorizationHeader) {
+ super(operation, uri, httpClient, authorizationHeader);
+ }
+
+ @Override
+ public Message invoke(Message msg) {
+
+ // Post an entry
+ Entry feedEntry = (Entry)((Object[])msg.getBody())[0];
+
+ // Send an HTTP POST
+ PostMethod postMethod = new PostMethod(uri);
+ postMethod.setRequestHeader("Authorization", authorizationHeader);
+ try {
+
+ // Write the Atom entry
+ StringWriter writer = new StringWriter();
+ AtomFeedEntryUtil.writeFeedEntry(feedEntry, "atom_1.0", writer);
+ postMethod.setRequestHeader("Content-type", "application/atom+xml; charset=utf-8");
+ postMethod.setRequestEntity(new StringRequestEntity(writer.toString()));
+
+ httpClient.executeMethod(postMethod);
+ int status = postMethod.getStatusCode();
+
+ // Read the Atom entry
+ if (status == 200 || status == 201) {
+ Entry createdEntry =
+ AtomFeedEntryUtil
+ .readFeedEntry("atom_1.0", new InputStreamReader(postMethod.getResponseBodyAsStream()));
+ msg.setBody(createdEntry);
+
+ } else if (status == 404) {
+ msg.setFaultBody(new NotFoundException());
+ } else {
+ msg.setFaultBody(new ServiceRuntimeException("HTTP status code: " + status));
+ }
+
+ } catch (Exception e) {
+ msg.setFaultBody(new ServiceRuntimeException(e));
+ } finally {
+ postMethod.releaseConnection();
+ }
+
+ return msg;
+ }
+ }
+
+ /**
+ * Put operation invoker
+ */
+ public static class PutInvoker extends AtomBindingInvoker {
+
+ public PutInvoker(Operation operation, String uri, HttpClient httpClient, String authorizationHeader) {
+ super(operation, uri, httpClient, authorizationHeader);
+ }
+
+ @Override
+ public Message invoke(Message msg) {
+
+ // Put an entry
+ Object[] args = (Object[])msg.getBody();
+ String id = (String)args[0];
+ Entry feedEntry = (Entry)args[1];
+
+ // Send an HTTP PUT
+ PutMethod putMethod = new PutMethod(uri + "/" + id);
+ putMethod.setRequestHeader("Authorization", authorizationHeader);
+ try {
+
+ // Write the Atom entry
+ StringWriter writer = new StringWriter();
+ AtomFeedEntryUtil.writeFeedEntry(feedEntry, "atom_1.0", writer);
+ putMethod.setRequestHeader("Content-type", "application/atom+xml; charset=utf-8");
+ putMethod.setRequestEntity(new StringRequestEntity(writer.toString()));
+
+ httpClient.executeMethod(putMethod);
+ int status = putMethod.getStatusCode();
+
+ // Read the Atom entry
+ if (status == 200 || status == 201) {
+ try {
+ Entry updatedEntry =
+ AtomFeedEntryUtil.readFeedEntry("atom_1.0", new InputStreamReader(putMethod
+ .getResponseBodyAsStream()));
+ msg.setBody(updatedEntry);
+ } catch (Exception e) {
+ // Returning the updated entry is optional
+ }
+
+ } else if (status == 404) {
+ msg.setFaultBody(new NotFoundException());
+ } else {
+ msg.setFaultBody(new ServiceRuntimeException("HTTP status code: " + status));
+ }
+
+ } catch (Exception e) {
+ msg.setFaultBody(new ServiceRuntimeException(e));
+ } finally {
+ putMethod.releaseConnection();
+ }
+
+ return msg;
+ }
+ }
+
+ /**
+ * Delete operation invoker
+ */
+ public static class DeleteInvoker extends AtomBindingInvoker {
+
+ public DeleteInvoker(Operation operation, String uri, HttpClient httpClient, String authorizationHeader) {
+ super(operation, uri, httpClient, authorizationHeader);
+ }
+
+ @Override
+ public Message invoke(Message msg) {
+
+ // Delete an entry
+ String id = (String)((Object[])msg.getBody())[0];
+
+ // Send an HTTP DELETE
+ DeleteMethod deleteMethod = new DeleteMethod(uri + "/" + id);
+ deleteMethod.setRequestHeader("Authorization", authorizationHeader);
+ try {
+ httpClient.executeMethod(deleteMethod);
+ int status = deleteMethod.getStatusCode();
+
+ // Read the Atom entry
+ if (status == 200) {
+ msg.setBody(null);
+
+ } else if (status == 404) {
+ msg.setFaultBody(new NotFoundException());
+ } else {
+ msg.setFaultBody(new ServiceRuntimeException("HTTP status code: " + status));
+ }
+
+ } catch (Exception e) {
+ msg.setFaultBody(new ServiceRuntimeException(e));
+ } finally {
+ deleteMethod.releaseConnection();
+ }
+
+ return msg;
+ }
+ }
+
+ /**
+ * GetAll operation invoker
+ */
+ public static class GetAllInvoker extends AtomBindingInvoker {
+
+ public GetAllInvoker(Operation operation, String uri, HttpClient httpClient, String authorizationHeader) {
+ super(operation, uri, httpClient, authorizationHeader);
+ }
+
+ @Override
+ public Message invoke(Message msg) {
+
+ // Get a feed
+
+ // Send an HTTP GET
+ GetMethod getMethod = new GetMethod(uri);
+ getMethod.setRequestHeader("Authorization", authorizationHeader);
+ try {
+ httpClient.executeMethod(getMethod);
+ int status = getMethod.getStatusCode();
+
+ // Read the Atom feed
+ if (status == 200) {
+ WireFeedInput input = new WireFeedInput();
+ Feed feed = (Feed)input.build(new XmlReader(getMethod.getResponseBodyAsStream()));
+ msg.setBody(feed);
+
+ } else if (status == 404) {
+ msg.setFaultBody(new NotFoundException());
+ } else {
+ msg.setFaultBody(new ServiceRuntimeException("HTTP status code: " + status));
+ }
+
+ } catch (Exception e) {
+ msg.setFaultBody(new ServiceRuntimeException(e));
+ } finally {
+ getMethod.releaseConnection();
+ }
+
+ return msg;
+ }
+ }
+
+ /**
+ * PostMedia operation invoker
+ */
+ public static class PostMediaInvoker extends AtomBindingInvoker {
+
+ public PostMediaInvoker(Operation operation, String uri, HttpClient httpClient, String authorizationHeader) {
+ super(operation, uri, httpClient, authorizationHeader);
+ }
+
+ @Override
+ public Message invoke(Message msg) {
+ // TODO implement
+ return super.invoke(msg);
+ }
+ }
+
+ /**
+ * PutMedia operation invoker
+ */
+ public static class PutMediaInvoker extends AtomBindingInvoker {
+
+ public PutMediaInvoker(Operation operation, String uri, HttpClient httpClient, String authorizationHeader) {
+ super(operation, uri, httpClient, authorizationHeader);
+ }
+
+ @Override
+ public Message invoke(Message msg) {
+ // TODO implement
+ return super.invoke(msg);
+ }
+ }
+
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomBindingProviderFactory.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomBindingProviderFactory.java
new file mode 100644
index 0000000000..9a858f899f
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomBindingProviderFactory.java
@@ -0,0 +1,74 @@
+/*
+ * 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.feed.provider;
+
+import org.apache.tuscany.sca.binding.feed.AtomBinding;
+import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.databinding.DataBindingExtensionPoint;
+import org.apache.tuscany.sca.databinding.Mediator;
+import org.apache.tuscany.sca.databinding.TransformerExtensionPoint;
+import org.apache.tuscany.sca.databinding.impl.MediatorImpl;
+import org.apache.tuscany.sca.host.http.ServletHost;
+import org.apache.tuscany.sca.host.http.ServletHostExtensionPoint;
+import org.apache.tuscany.sca.invocation.MessageFactory;
+import org.apache.tuscany.sca.provider.BindingProviderFactory;
+import org.apache.tuscany.sca.provider.ReferenceBindingProvider;
+import org.apache.tuscany.sca.provider.ServiceBindingProvider;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.apache.tuscany.sca.runtime.RuntimeComponentReference;
+import org.apache.tuscany.sca.runtime.RuntimeComponentService;
+
+/**
+ * Implementation of the Atom binding model.
+ *
+ * @version $Rev$ $Date$
+ */
+public class AtomBindingProviderFactory implements BindingProviderFactory<AtomBinding> {
+
+ private MessageFactory messageFactory;
+ private Mediator mediator;
+ private ServletHost servletHost;
+
+ public AtomBindingProviderFactory(ExtensionPointRegistry extensionPoints) {
+ ServletHostExtensionPoint servletHosts = extensionPoints.getExtensionPoint(ServletHostExtensionPoint.class);
+ this.servletHost = servletHosts.getServletHosts().get(0);
+ ModelFactoryExtensionPoint modelFactories = extensionPoints.getExtensionPoint(ModelFactoryExtensionPoint.class);
+ this.messageFactory = modelFactories.getFactory(MessageFactory.class);
+ this.mediator = new MediatorImpl(extensionPoints.getExtensionPoint(DataBindingExtensionPoint.class),
+ extensionPoints.getExtensionPoint(TransformerExtensionPoint.class));
+ }
+
+ public ReferenceBindingProvider createReferenceBindingProvider(RuntimeComponent component,
+ RuntimeComponentReference reference,
+ AtomBinding binding) {
+ return new AtomReferenceBindingProvider(component, reference, binding);
+ }
+
+ public ServiceBindingProvider createServiceBindingProvider(RuntimeComponent component,
+ RuntimeComponentService service,
+ AtomBinding binding) {
+ return new AtomServiceBindingProvider(component, service, binding, servletHost, messageFactory, mediator);
+ }
+
+ public Class<AtomBinding> getModelType() {
+ return AtomBinding.class;
+ }
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomFeedEntryUtil.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomFeedEntryUtil.java
new file mode 100644
index 0000000000..7adbfca6e8
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomFeedEntryUtil.java
@@ -0,0 +1,117 @@
+/*
+ * 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.feed.provider;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.input.SAXBuilder;
+import org.jdom.output.Format;
+import org.jdom.output.XMLOutputter;
+
+import com.sun.syndication.feed.atom.Content;
+import com.sun.syndication.feed.atom.Entry;
+import com.sun.syndication.feed.atom.Feed;
+import com.sun.syndication.io.FeedException;
+import com.sun.syndication.io.WireFeedInput;
+import com.sun.syndication.io.WireFeedOutput;
+
+/**
+ * Utility methods to read/write Atom entries.
+ *
+ * @version $Rev$ $Date$
+ */
+class AtomFeedEntryUtil {
+
+ /**
+ * Read an Atom entry
+ *
+ * @param request
+ * @return
+ * @throws IOException
+ * @throws JDOMException
+ * @throws FeedException
+ * @throws IllegalArgumentException
+ */
+ static Entry readFeedEntry(String feedType, Reader reader) throws JDOMException, IOException, IllegalArgumentException,
+ FeedException {
+ SAXBuilder builder = new SAXBuilder();
+ Document document = builder.build(reader);
+ Element root = document.getRootElement();
+ root.detach();
+ Feed feed = new Feed();
+ feed.setFeedType(feedType);
+ WireFeedOutput wireFeedOutput = new WireFeedOutput();
+ document = wireFeedOutput.outputJDom(feed);
+ document.getRootElement().addContent(root);
+ WireFeedInput input = new WireFeedInput();
+ feed = (Feed)input.build(document);
+ Entry feedEntry = (Entry)feed.getEntries().get(0);
+ if (feedEntry.getContents().size() != 0) {
+ Content content = (Content)feedEntry.getContents().get(0);
+ if ("text/xml".equals(content.getType())) {
+ Element element = root.getChild("content", root.getNamespace());
+ if (!element.getChildren().isEmpty()) {
+ element = (Element)element.getChildren().get(0);
+ XMLOutputter outputter = new XMLOutputter();
+ StringWriter sw = new StringWriter();
+ outputter.output(element, sw);
+ content.setValue(sw.toString());
+ }
+ }
+ }
+ return feedEntry;
+ }
+
+ /**
+ * Write an Atom entry.
+ *
+ * @param entry
+ * @param response
+ * @throws FeedException
+ * @throws IllegalArgumentException
+ * @throws IOException
+ * @throws ServletException
+ */
+ static void writeFeedEntry(Entry feedEntry, String feedType, Writer writer) throws IllegalArgumentException, FeedException,
+ IOException {
+ Feed feed = new Feed();
+ feed.setFeedType(feedType);
+ List<Entry> feedEntries = new ArrayList<Entry>();
+ feedEntries.add(feedEntry);
+ feed.setEntries(feedEntries);
+
+ WireFeedOutput wireFeedOutput = new WireFeedOutput();
+ Document document = wireFeedOutput.outputJDom(feed);
+ Element root = document.getRootElement();
+ Element element = (Element)root.getChildren().get(0);
+ XMLOutputter outputter = new XMLOutputter();
+ outputter.setFormat(Format.getPrettyFormat());
+ outputter.output(element, writer);
+ }
+
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomReferenceBindingProvider.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomReferenceBindingProvider.java
new file mode 100644
index 0000000000..d9bda1fb9a
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomReferenceBindingProvider.java
@@ -0,0 +1,116 @@
+/*
+ * 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.feed.provider;
+
+import java.net.URI;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.commons.httpclient.auth.AuthScope;
+import org.apache.tuscany.sca.binding.feed.AtomBinding;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.invocation.Invoker;
+import org.apache.tuscany.sca.provider.ReferenceBindingProvider;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.apache.tuscany.sca.runtime.RuntimeComponentReference;
+
+/**
+ * Implementation of the Atom binding provider.
+ *
+ * @version $Rev$ $Date$
+ */
+class AtomReferenceBindingProvider implements ReferenceBindingProvider {
+
+ private RuntimeComponentReference reference;
+ private AtomBinding binding;
+ private String authorizationHeader;
+ private HttpClient httpClient;
+
+ /**
+ * Constructs a new AtomReferenceBindingProvider
+ * @param component
+ * @param reference
+ * @param binding
+ */
+ AtomReferenceBindingProvider(RuntimeComponent component,
+ RuntimeComponentReference reference,
+ AtomBinding binding) {
+ this.reference = reference;
+ this.binding = binding;
+
+ // Prepare authorization header
+ String authorization = "admin" + ":" + "admin";
+ authorizationHeader = "Basic " + new String(Base64.encodeBase64(authorization.getBytes()));
+
+ // Create an HTTP client
+ httpClient = new HttpClient(new MultiThreadedHttpConnectionManager());
+ httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(60000);
+ }
+
+ public Invoker createInvoker(Operation operation) {
+ String operationName = operation.getName();
+ if (operationName.equals("get")) {
+ return new AtomBindingInvoker.GetInvoker(operation, binding.getURI(), httpClient, authorizationHeader);
+ } else if (operationName.equals("post")) {
+ return new AtomBindingInvoker.PostInvoker(operation, binding.getURI(), httpClient, authorizationHeader);
+ } else if (operationName.equals("put")) {
+ return new AtomBindingInvoker.PutInvoker(operation, binding.getURI(), httpClient, authorizationHeader);
+ } else if (operationName.equals("delete")) {
+ return new AtomBindingInvoker.DeleteInvoker(operation, binding.getURI(), httpClient,
+ authorizationHeader);
+ } else if (operationName.equals("getFeed") || operationName.equals("getAll")) {
+ return new AtomBindingInvoker.GetAllInvoker(operation, binding.getURI(), httpClient,
+ authorizationHeader);
+ } else if (operationName.equals("postMedia")) {
+ return new AtomBindingInvoker.PostMediaInvoker(operation, binding.getURI(), httpClient,
+ authorizationHeader);
+ } else if (operationName.equals("putMedia")) {
+ return new AtomBindingInvoker.PutMediaInvoker(operation, binding.getURI(), httpClient,
+ authorizationHeader);
+ }
+
+ return new AtomBindingInvoker(operation, binding.getURI(), httpClient, authorizationHeader);
+ }
+
+ public InterfaceContract getBindingInterfaceContract() {
+ return reference.getInterfaceContract();
+ }
+
+ public void start() {
+
+ // Configure the HTTP client credentials
+ Credentials credentials = new UsernamePasswordCredentials("admin", "admin");
+ httpClient.getParams().setAuthenticationPreemptive(true);
+ URI uri = URI.create(binding.getURI());
+ httpClient.getState().setCredentials(new AuthScope(uri.getHost(), uri.getPort()), credentials);
+ }
+
+ public void stop() {
+ }
+
+ public boolean supportsOneWayInvocation() {
+ return false;
+ }
+
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomServiceBindingProvider.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomServiceBindingProvider.java
new file mode 100644
index 0000000000..23c36f51e3
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/AtomServiceBindingProvider.java
@@ -0,0 +1,87 @@
+/*
+ * 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.feed.provider;
+
+import org.apache.tuscany.sca.binding.feed.AtomBinding;
+import org.apache.tuscany.sca.databinding.Mediator;
+import org.apache.tuscany.sca.host.http.ServletHost;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+import org.apache.tuscany.sca.invocation.MessageFactory;
+import org.apache.tuscany.sca.provider.ServiceBindingProvider;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.apache.tuscany.sca.runtime.RuntimeComponentService;
+import org.apache.tuscany.sca.runtime.RuntimeWire;
+
+/**
+ * Implementation of the Atom binding provider.
+ *
+ * @version $Rev$ $Date$
+ */
+class AtomServiceBindingProvider implements ServiceBindingProvider {
+
+ private RuntimeComponentService service;
+ private AtomBinding binding;
+ private ServletHost servletHost;
+ private MessageFactory messageFactory;
+ private String servletMapping;
+ private Mediator mediator;
+
+ AtomServiceBindingProvider(RuntimeComponent component,
+ RuntimeComponentService service,
+ AtomBinding binding,
+ ServletHost servletHost,
+ MessageFactory messageFactory,
+ Mediator mediator) {
+ this.service = service;
+ this.binding = binding;
+ this.servletHost = servletHost;
+ this.messageFactory = messageFactory;
+ this.mediator = mediator;
+ }
+
+ public InterfaceContract getBindingInterfaceContract() {
+ return service.getInterfaceContract();
+ }
+
+ public boolean supportsOneWayInvocation() {
+ return false;
+ }
+
+ public void start() {
+ RuntimeComponentService componentService = (RuntimeComponentService)service;
+ RuntimeWire wire = componentService.getRuntimeWire(binding);
+
+ FeedBindingListenerServlet servlet =
+ new FeedBindingListenerServlet(wire, messageFactory, mediator, "atom_1.0");
+
+ servletMapping = binding.getURI();
+ if (!servletMapping.endsWith("/")) {
+ servletMapping += "/";
+ }
+ if (!servletMapping.endsWith("*")) {
+ servletMapping += "*";
+ }
+ servletHost.addServletMapping(servletMapping, servlet);
+ }
+
+ public void stop() {
+ servletHost.removeServletMapping(servletMapping);
+ }
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/FeedBindingListenerServlet.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/FeedBindingListenerServlet.java
new file mode 100644
index 0000000000..89366456f5
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/FeedBindingListenerServlet.java
@@ -0,0 +1,788 @@
+/*
+ * 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.feed.provider;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.logging.Logger;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.namespace.QName;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.tuscany.sca.data.collection.Item;
+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.util.XMLType;
+import org.apache.tuscany.sca.invocation.InvocationChain;
+import org.apache.tuscany.sca.invocation.Invoker;
+import org.apache.tuscany.sca.invocation.Message;
+import org.apache.tuscany.sca.invocation.MessageFactory;
+import org.apache.tuscany.sca.runtime.RuntimeWire;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.Namespace;
+import org.jdom.output.Format;
+import org.jdom.output.XMLOutputter;
+
+import com.sun.syndication.feed.atom.Content;
+import com.sun.syndication.feed.atom.Entry;
+import com.sun.syndication.feed.atom.Feed;
+import com.sun.syndication.feed.atom.Link;
+import com.sun.syndication.feed.synd.SyndFeed;
+import com.sun.syndication.feed.synd.SyndFeedImpl;
+import com.sun.syndication.io.FeedException;
+import com.sun.syndication.io.SyndFeedOutput;
+import com.sun.syndication.io.WireFeedOutput;
+
+/**
+ * A resource collection binding listener, implemented as a Servlet and
+ * registered in a Servlet host provided by the SCA hosting runtime.
+ *
+ * @version $Rev$ $Date$
+ */
+class FeedBindingListenerServlet extends HttpServlet {
+ private static final Logger logger = Logger.getLogger(FeedBindingListenerServlet.class.getName());
+ private static final long serialVersionUID = 1L;
+
+ private static final Namespace APP_NS = Namespace.getNamespace("app", "http://purl.org/atom/app#");
+ private static final Namespace ATOM_NS = Namespace.getNamespace("atom", "http://www.w3.org/2005/Atom");
+
+ private RuntimeWire wire;
+ private Invoker getFeedInvoker;
+ private Invoker getAllInvoker;
+ private Invoker queryInvoker;
+ private Invoker getInvoker;
+ private Invoker postInvoker;
+ private Invoker postMediaInvoker;
+ private Invoker putInvoker;
+ private Invoker putMediaInvoker;
+ private Invoker deleteInvoker;
+ private MessageFactory messageFactory;
+ private String feedType;
+ private Mediator mediator;
+ private DataType<?> itemClassType;
+ private DataType<?> itemXMLType;
+ private boolean supportsFeedEntries;
+
+ /**
+ * Constructs a new binding listener.
+ *
+ * @param wire
+ * @param messageFactory
+ * @param feedType
+ */
+ FeedBindingListenerServlet(RuntimeWire wire, MessageFactory messageFactory, Mediator mediator, String feedType) {
+ this.wire = wire;
+ this.messageFactory = messageFactory;
+ this.mediator = mediator;
+ this.feedType = feedType;
+
+ // Get the invokers for the supported operations
+ Operation getOperation = null;
+ for (InvocationChain invocationChain : this.wire.getInvocationChains()) {
+ invocationChain.setAllowsPassByReference(true);
+ Operation operation = invocationChain.getTargetOperation();
+ String operationName = operation.getName();
+ if (operationName.equals("getFeed")) {
+ getFeedInvoker = invocationChain.getHeadInvoker();
+ } else if (operationName.equals("getAll")) {
+ getAllInvoker = invocationChain.getHeadInvoker();
+ } else if (operationName.equals("query")) {
+ queryInvoker = invocationChain.getHeadInvoker();
+ } else if (operationName.equals("get")) {
+ getInvoker = invocationChain.getHeadInvoker();
+ getOperation = operation;
+ } else if (operationName.equals("put")) {
+ putInvoker = invocationChain.getHeadInvoker();
+ } else if (operationName.equals("putMedia")) {
+ putMediaInvoker = invocationChain.getHeadInvoker();
+ } else if (operationName.equals("post")) {
+ postInvoker = invocationChain.getHeadInvoker();
+ } else if (operationName.equals("postMedia")) {
+ postMediaInvoker = invocationChain.getHeadInvoker();
+ } else if (operationName.equals("delete")) {
+ deleteInvoker = invocationChain.getHeadInvoker();
+ }
+ }
+
+ // Determine the collection item type
+ itemXMLType = new DataTypeImpl<Class<?>>(String.class.getName(), String.class, String.class);
+ Class<?> itemClass = getOperation.getOutputType().getPhysical();
+ if (itemClass == Entry.class) {
+ supportsFeedEntries = true;
+ }
+ DataType<XMLType> outputType = getOperation.getOutputType();
+ QName qname = outputType.getLogical().getElementName();
+ qname = new QName(qname.getNamespaceURI(), itemClass.getSimpleName());
+ itemClassType = new DataTypeImpl<XMLType>("java:complexType", itemClass, new XMLType(qname, null));
+
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+ // No authentication required for a get request
+
+ // Get the request path
+ String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8");
+
+ // The feedType parameter is used to override what type of feed is going
+ // to be produced
+ String requestFeedType = request.getParameter("feedType");
+ if (requestFeedType == null)
+ requestFeedType = feedType;
+
+ logger.info(">>> FeedEndPointServlet (" + requestFeedType + ") " + request.getRequestURI());
+
+ // Handle an Atom request
+ if (requestFeedType.startsWith("atom_")) {
+
+ if (path != null && path.equals("/atomsvc")) {
+
+ // Return the Atom service document
+ response.setContentType("application/atomsvc+xml; charset=utf-8");
+ Document document = new Document();
+ Element service = new Element("service", APP_NS);
+ document.setRootElement(service);
+
+ Element workspace = new Element("workspace", APP_NS);
+ Element title = new Element("title", ATOM_NS);
+ title.setText("resource");
+ workspace.addContent(title);
+ service.addContent(workspace);
+
+ Element collection = new Element("collection", APP_NS);
+ String href = request.getRequestURL().toString();
+ href = href.substring(0, href.length() - "/atomsvc".length());
+ collection.setAttribute("href", href);
+ Element collectionTitle = new Element("title", ATOM_NS);
+ collectionTitle.setText("entries");
+ collection.addContent(collectionTitle);
+ workspace.addContent(collection);
+
+ XMLOutputter outputter = new XMLOutputter();
+ Format format = Format.getPrettyFormat();
+ format.setEncoding("UTF-8");
+ outputter.setFormat(format);
+ outputter.output(document, getWriter(response));
+
+ } else if (path == null || path.length() == 0 || path.equals("/")) {
+
+ // Return a feed containing the entries in the collection
+ Feed feed = null;
+ if (supportsFeedEntries) {
+
+ // The service implementation supports feed entries, invoke its getFeed operation
+ Message requestMessage = messageFactory.createMessage();
+ Message responseMessage = getFeedInvoker.invoke(requestMessage);
+ if (responseMessage.isFault()) {
+ throw new ServletException((Throwable)responseMessage.getBody());
+ }
+ feed = (Feed)responseMessage.getBody();
+
+ } else {
+
+ // The service implementation does not support feed entries,
+ // invoke its getAll operation to get the data item collection, then create
+ // feed entries from the items
+ Message requestMessage = messageFactory.createMessage();
+ Message responseMessage;
+ if (request.getQueryString() != null) {
+ requestMessage.setBody(new Object[] {request.getQueryString()});
+ responseMessage = queryInvoker.invoke(requestMessage);
+ } else {
+ responseMessage = getAllInvoker.invoke(requestMessage);
+ }
+ if (responseMessage.isFault()) {
+ throw new ServletException((Throwable)responseMessage.getBody());
+ }
+ org.apache.tuscany.sca.data.collection.Entry<Object, Object>[] collection =
+ (org.apache.tuscany.sca.data.collection.Entry<Object, Object>[])responseMessage.getBody();
+ if (collection != null) {
+ // Create the feed
+ feed = new Feed();
+ feed.setTitle("Feed");
+ for (org.apache.tuscany.sca.data.collection.Entry<Object, Object> entry: collection) {
+ Entry feedEntry = createFeedEntry(entry);
+ feed.getEntries().add(feedEntry);
+ }
+ }
+ }
+ if (feed != null) {
+
+ // Write the Atom feed
+ response.setContentType("application/atom+xml; charset=utf-8");
+ feed.setFeedType(requestFeedType);
+ WireFeedOutput feedOutput = new WireFeedOutput();
+ try {
+ feedOutput.output(feed, getWriter(response));
+ } catch (FeedException e) {
+ throw new ServletException(e);
+ }
+ } else {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+
+ } else if (path.startsWith("/")) {
+
+ // Return a specific entry in the collection
+ Entry feedEntry;
+
+ // Invoke the get operation on the service implementation
+ Message requestMessage = messageFactory.createMessage();
+ String id = path.substring(1);
+ requestMessage.setBody(new Object[] {id});
+ Message responseMessage = getInvoker.invoke(requestMessage);
+ if (responseMessage.isFault()) {
+ throw new ServletException((Throwable)responseMessage.getBody());
+ }
+ if (supportsFeedEntries) {
+
+ // The service implementation returns a feed entry
+ feedEntry = responseMessage.getBody();
+
+ } else {
+
+ // The service implementation only returns a data item, create an entry
+ // from it
+ feedEntry = createFeedEntry(new org.apache.tuscany.sca.data.collection.Entry<Object, Object>(id, responseMessage.getBody()));
+ }
+
+ // Write the Atom entry
+ if (feedEntry != null) {
+ response.setContentType("application/atom+xml; charset=utf-8");
+ try {
+ AtomFeedEntryUtil.writeFeedEntry(feedEntry, feedType, getWriter(response));
+ } catch (FeedException e) {
+ throw new ServletException(e);
+ }
+ } else {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+
+ } else {
+
+ // Path doesn't match any known pattern
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+ } else {
+
+ // Handle an RSS request
+ if (path == null || path.length() == 0 || path.equals("/")) {
+
+ // Return an RSS feed containing the entries in the collection
+ Feed feed = null;
+ if (supportsFeedEntries) {
+
+ // The service implementation supports feed entries, invoke its getFeed operation
+ Message requestMessage = messageFactory.createMessage();
+ Message responseMessage = getFeedInvoker.invoke(requestMessage);
+ if (responseMessage.isFault()) {
+ throw new ServletException((Throwable)responseMessage.getBody());
+ }
+ feed = (Feed)responseMessage.getBody();
+
+ } else {
+
+ // The service implementation does not support feed entries, invoke its
+ // getAll operation to get the data item collection. then create feed entries
+ // from the data items
+ Message requestMessage = messageFactory.createMessage();
+ Message responseMessage;
+ if (request.getQueryString() != null) {
+ requestMessage.setBody(new Object[] {request.getQueryString()});
+ responseMessage = queryInvoker.invoke(requestMessage);
+ } else {
+ responseMessage = getAllInvoker.invoke(requestMessage);
+ }
+ if (responseMessage.isFault()) {
+ throw new ServletException((Throwable)responseMessage.getBody());
+ }
+ org.apache.tuscany.sca.data.collection.Entry<Object, Object>[] collection =
+ (org.apache.tuscany.sca.data.collection.Entry<Object, Object>[])responseMessage.getBody();
+ if (collection != null) {
+ // Create the feed
+ feed = new Feed();
+ feed.setTitle("Feed");
+ for (org.apache.tuscany.sca.data.collection.Entry<Object, Object> entry: collection) {
+ Entry feedEntry = createFeedEntry(entry);
+ feed.getEntries().add(feedEntry);
+ }
+ }
+ }
+
+ // Convert to an RSS feed
+ if (feed != null) {
+ response.setContentType("application/rss+xml; charset=utf-8");
+ feed.setFeedType("atom_1.0");
+ SyndFeed syndFeed = new SyndFeedImpl(feed);
+ syndFeed.setFeedType(requestFeedType);
+ syndFeed.setLink(path);
+ SyndFeedOutput syndOutput = new SyndFeedOutput();
+ try {
+ syndOutput.output(syndFeed, getWriter(response));
+ } catch (FeedException e) {
+ throw new ServletException(e);
+ }
+ } else {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+ } else {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+ }
+ }
+
+ /**
+ * Create an Atom entry from a data collection entry.
+ * @param entry
+ * @return
+ */
+ private Entry createFeedEntry(org.apache.tuscany.sca.data.collection.Entry<Object, Object> entry) {
+ Object key = entry.getKey();
+ Object data = entry.getData();
+ if (data instanceof Item) {
+ Item item = (Item)data;
+
+ Entry feedEntry = new Entry();
+ feedEntry.setId(key.toString());
+ feedEntry.setTitle(item.getTitle());
+
+ String value = item.getContents();
+ if (value != null) {
+ Content content = new Content();
+ content.setType("text/xml");
+ content.setValue(value);
+ List<Content> contents = new ArrayList<Content>();
+ contents.add(content);
+ feedEntry.setContents(contents);
+ }
+
+ String href = item.getLink();
+ if (href == null) {
+ href = key.toString();
+ }
+ Link link = new Link();
+ link.setRel("edit");
+ link.setHref(href);
+ feedEntry.getOtherLinks().add(link);
+ link = new Link();
+ link.setRel("alternate");
+ link.setHref(href);
+ feedEntry.getAlternateLinks().add(link);
+
+ Date date = item.getDate();
+ if (date == null) {
+ date = new Date();
+ }
+ feedEntry.setCreated(date);
+ return feedEntry;
+
+ } else if (data != null) {
+ Entry feedEntry = new Entry();
+ feedEntry.setId(key.toString());
+ feedEntry.setTitle("item");
+
+ // Convert the item to XML
+ String value = mediator.mediate(data, itemClassType, itemXMLType, null).toString();
+
+ Content content = new Content();
+ content.setType("text/xml");
+ content.setValue(value);
+ List<Content> contents = new ArrayList<Content>();
+ contents.add(content);
+ feedEntry.setContents(contents);
+
+ Link link = new Link();
+ link.setRel("edit");
+ link.setHref(key.toString());
+ feedEntry.getOtherLinks().add(link);
+ link = new Link();
+ link.setRel("alternate");
+ link.setHref(key.toString());
+ feedEntry.getAlternateLinks().add(link);
+
+ feedEntry.setCreated(new Date());
+ return feedEntry;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Create a data collection entry from an Atom entry.
+ * @param feedEntry
+ * @return
+ */
+ private org.apache.tuscany.sca.data.collection.Entry<Object, Object> createEntry(Entry feedEntry) {
+ if (feedEntry != null) {
+ if (itemClassType.getPhysical() == Item.class) {
+ String key = feedEntry.getId();
+
+ Item item = new Item();
+ item.setTitle(feedEntry.getTitle());
+
+ List<?> contents = feedEntry.getContents();
+ if (!contents.isEmpty()) {
+ Content content = (Content)contents.get(0);
+ String value = content.getValue();
+ item.setContents(value);
+ }
+
+ for (Object l : feedEntry.getOtherLinks()) {
+ Link link = (Link)l;
+ if (link.getRel() == null || "edit".equals(link.getRel())) {
+ String href = link.getHref();
+ if (href.startsWith("null/")) {
+ href = href.substring(5);
+ }
+ item.setLink(href);
+ break;
+ }
+ }
+
+ item.setDate(feedEntry.getCreated());
+
+ return new org.apache.tuscany.sca.data.collection.Entry<Object, Object>(key, item);
+
+ } else {
+ String key = feedEntry.getId();
+
+ // Create the item from XML
+ List<?> contents = feedEntry.getContents();
+ if (contents.isEmpty()) {
+ return null;
+ }
+ Content content = (Content)contents.get(0);
+ String value = content.getValue();
+ Object data = mediator.mediate(value, itemXMLType, itemClassType, null);
+
+ return new org.apache.tuscany.sca.data.collection.Entry<Object, Object>(key, data);
+ }
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
+ IOException {
+
+ // Authenticate the user
+ String user = processAuthorizationHeader(request);
+ if (user == null) {
+ unauthorized(response);
+ return;
+ }
+
+ // Get the request path
+ String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8");
+
+ if (path == null || path.length() == 0 || path.equals("/")) {
+ Entry createdFeedEntry = null;
+
+ // Create a new Atom entry
+ String contentType = request.getContentType();
+ if (contentType != null && contentType.startsWith("application/atom+xml")) {
+
+ // Read the entry from the request
+ Entry feedEntry;
+ try {
+ feedEntry = AtomFeedEntryUtil.readFeedEntry(feedType, request.getReader());
+ } catch (JDOMException e) {
+ throw new ServletException(e);
+ } catch (FeedException e) {
+ throw new ServletException(e);
+ }
+
+ // 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[] {feedEntry});
+ Message responseMessage = postInvoker.invoke(requestMessage);
+ if (responseMessage.isFault()) {
+ throw new ServletException((Throwable)responseMessage.getBody());
+ }
+ createdFeedEntry = responseMessage.getBody();
+ } else {
+
+ // The service implementation does not support feed entries, pass the data item to it
+ Message requestMessage = messageFactory.createMessage();
+ org.apache.tuscany.sca.data.collection.Entry<Object, Object> entry = createEntry(feedEntry);
+ requestMessage.setBody(new Object[] {entry.getKey(), entry.getData()});
+ Message responseMessage = postInvoker.invoke(requestMessage);
+ if (responseMessage.isFault()) {
+ throw new ServletException((Throwable)responseMessage.getBody());
+ }
+ entry.setKey(responseMessage.getBody());
+ createdFeedEntry = createFeedEntry(entry);
+ }
+
+ } else if (contentType != null) {
+
+ // Create a new media entry
+
+ // Get incoming headers
+ String title = request.getHeader("Title");
+ String slug = request.getHeader("Slug");
+
+ // Let the component implementation create the media entry
+ Message requestMessage = messageFactory.createMessage();
+ requestMessage.setBody(new Object[] {title, slug, contentType, request.getInputStream()});
+ Message responseMessage = postMediaInvoker.invoke(requestMessage);
+ if (responseMessage.isFault()) {
+ throw new ServletException((Throwable)responseMessage.getBody());
+ }
+ createdFeedEntry = responseMessage.getBody();
+ } else {
+ response.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
+ }
+
+ // A new entry was created successfully
+ if (createdFeedEntry != null) {
+
+ // Set location of the created entry in the Location header
+ for (Object l : createdFeedEntry.getOtherLinks()) {
+ Link link = (Link)l;
+ if (link.getRel() == null || "edit".equals(link.getRel())) {
+ response.addHeader("Location", link.getHref());
+ break;
+ }
+ }
+
+ // Write the created Atom entry
+ response.setStatus(HttpServletResponse.SC_CREATED);
+ response.setContentType("application/atom+xml; charset=utf-8");
+ try {
+ AtomFeedEntryUtil.writeFeedEntry(createdFeedEntry, feedType, getWriter(response));
+ } catch (FeedException e) {
+ throw new ServletException(e);
+ }
+
+ } else {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+
+ } else {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+ }
+
+ private Writer getWriter(HttpServletResponse response) throws UnsupportedEncodingException, IOException {
+ Writer writer = new OutputStreamWriter(response.getOutputStream(), "UTF-8");
+ return writer;
+ }
+
+ @Override
+ protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+ // Authenticate the user
+ String user = processAuthorizationHeader(request);
+ if (user == null) {
+ unauthorized(response);
+ return;
+ }
+
+ // Get the request path
+ String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8");
+
+ if (path != null && path.startsWith("/")) {
+ String id = path.substring(1);
+
+ // Update an Atom entry
+ String contentType = request.getContentType();
+ if (contentType != null && contentType.startsWith("application/atom+xml")) {
+
+ // Read the entry from the request
+ Entry feedEntry;
+ try {
+ feedEntry = AtomFeedEntryUtil.readFeedEntry(feedType, request.getReader());
+ } catch (JDOMException e) {
+ throw new ServletException(e);
+ } catch (FeedException e) {
+ throw new ServletException(e);
+ }
+
+ // 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});
+ Message responseMessage = putInvoker.invoke(requestMessage);
+ if (responseMessage.isFault()) {
+ Object body = responseMessage.getBody();
+ if (body.getClass().getName().endsWith(".NotFoundException")) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ } else {
+ throw new ServletException((Throwable)responseMessage.getBody());
+ }
+ }
+ } else {
+
+ // The service implementation does not support feed entries, pass the data item to it
+ Message requestMessage = messageFactory.createMessage();
+ org.apache.tuscany.sca.data.collection.Entry<Object, Object> entry = createEntry(feedEntry);
+ requestMessage.setBody(new Object[] {entry.getKey(), entry.getData()});
+ Message responseMessage = putInvoker.invoke(requestMessage);
+ if (responseMessage.isFault()) {
+ Object body = responseMessage.getBody();
+ if (body.getClass().getName().endsWith(".NotFoundException")) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ } else {
+ throw new ServletException((Throwable)responseMessage.getBody());
+ }
+ }
+ }
+
+ } else if (contentType != null) {
+
+ // Updated a media entry
+
+ // Let the component implementation create the media entry
+ Message requestMessage = messageFactory.createMessage();
+ requestMessage.setBody(new Object[] {id, contentType, request.getInputStream()});
+ Message responseMessage = putMediaInvoker.invoke(requestMessage);
+ Object body = responseMessage.getBody();
+ if (responseMessage.isFault()) {
+ if (body.getClass().getName().endsWith(".NotFoundException")) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ } else {
+ throw new ServletException((Throwable)responseMessage.getBody());
+ }
+ }
+ } else {
+ response.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
+ }
+ } else {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+ }
+
+ @Override
+ protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException,
+ IOException {
+
+ // Authenticate the user
+ String user = processAuthorizationHeader(request);
+ if (user == null) {
+ unauthorized(response);
+ return;
+ }
+
+ // Get the request path
+ String path = URLDecoder.decode(request.getRequestURI().substring(request.getServletPath().length()), "UTF-8");
+
+ String id;
+ if (path != null && path.startsWith("/")) {
+ id = path.substring(1);
+ } else {
+ id = "";
+ }
+
+ // Delete a specific entry from the collection
+ Message requestMessage = messageFactory.createMessage();
+ requestMessage.setBody(new Object[] {id});
+ Message responseMessage = deleteInvoker.invoke(requestMessage);
+ if (responseMessage.isFault()) {
+ Object body = responseMessage.getBody();
+ if (body.getClass().getName().endsWith(".NotFoundException")) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ } else {
+ throw new ServletException((Throwable)responseMessage.getBody());
+ }
+ }
+ }
+
+ /**
+ * Process the authorization header
+ *
+ * @param request
+ * @return
+ * @throws ServletException
+ */
+ private String processAuthorizationHeader(HttpServletRequest request) throws ServletException {
+ try {
+ String authorization = request.getHeader("Authorization");
+ if (authorization != null) {
+ StringTokenizer tokens = new StringTokenizer(authorization);
+ if (tokens.hasMoreTokens()) {
+ String basic = tokens.nextToken();
+ if (basic.equalsIgnoreCase("Basic")) {
+ String credentials = tokens.nextToken();
+ String userAndPassword = new String(Base64.decodeBase64(credentials.getBytes()));
+ int colon = userAndPassword.indexOf(":");
+ if (colon != -1) {
+ String user = userAndPassword.substring(0, colon);
+ String password = userAndPassword.substring(colon + 1);
+
+ // Authenticate the User.
+ if (authenticate(user, password)) {
+ return user;
+ }
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new ServletException(e);
+ }
+ return null;
+ }
+
+ /**
+ * Authenticate a user.
+ *
+ * @param user
+ * @param password
+ * @return
+ */
+ private boolean authenticate(String user, String password) {
+
+ // TODO Handle this using SCA security policies
+ //FIXME Why are we using endsWith instead of equals here??
+ return ("admin".endsWith(user) && "admin".equals(password));
+ }
+
+ /**
+ * Reject an unauthorized request.
+ *
+ * @param response
+ */
+ private void unauthorized(HttpServletResponse response) throws IOException {
+ response.setHeader("WWW-Authenticate", "BASIC realm=\"Tuscany\"");
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/RSSBindingInvoker.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/RSSBindingInvoker.java
new file mode 100644
index 0000000000..c5bd3ec009
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/RSSBindingInvoker.java
@@ -0,0 +1,91 @@
+/*
+ * 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.feed.provider;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.logging.Logger;
+
+import org.apache.tuscany.sca.invocation.Invoker;
+import org.apache.tuscany.sca.invocation.Message;
+import org.apache.tuscany.sca.invocation.DataExchangeSemantics;
+
+import com.sun.syndication.feed.atom.Feed;
+import com.sun.syndication.feed.synd.SyndFeed;
+import com.sun.syndication.io.FeedException;
+import com.sun.syndication.io.SyndFeedInput;
+import com.sun.syndication.io.WireFeedInput;
+import com.sun.syndication.io.XmlReader;
+
+/**
+ * Invoker for the RSS binding.
+ *
+ * @version $Rev$ $Date$
+ */
+class RSSBindingInvoker implements Invoker, DataExchangeSemantics {
+ private static final Logger logger = Logger.getLogger(RSSBindingInvoker.class.getName());
+
+ private String feedType;
+ private String uri;
+
+ RSSBindingInvoker(String uri, String feedType) {
+ this.uri = uri;
+ this.feedType = feedType;
+ }
+
+ public Message invoke(Message msg) {
+ try {
+ logger.info(">>> RSSBindingInvoker (" + feedType + ") " + uri);
+
+ // Read the configured feed URI into a Feed object
+ Feed feed;
+ if (feedType.startsWith("atom_")) {
+
+ // Read an Atom feed
+ WireFeedInput input = new WireFeedInput();
+ feed = (Feed)input.build(new XmlReader(new URL(uri)));
+ } else {
+
+ // Read an RSS feed and convert it to an Atom feed
+ SyndFeedInput input = new SyndFeedInput();
+ SyndFeed syndFeed = input.build(new XmlReader(new URL(uri)));
+ feed = (Feed)syndFeed.createWireFeed("atom_1.0");
+ }
+
+ //FIXME Support conversion to data-api entries
+
+ msg.setBody(feed);
+
+ } catch (MalformedURLException e) {
+ msg.setFaultBody(e);
+ } catch (IllegalArgumentException e) {
+ msg.setFaultBody(e);
+ } catch (FeedException e) {
+ msg.setFaultBody(e);
+ } catch (IOException e) {
+ msg.setFaultBody(e);
+ }
+ return msg;
+ }
+
+ public boolean allowsPassByReference() {
+ return true;
+ }
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/RSSBindingProviderFactory.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/RSSBindingProviderFactory.java
new file mode 100644
index 0000000000..f4c336e12b
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/RSSBindingProviderFactory.java
@@ -0,0 +1,74 @@
+/*
+ * 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.feed.provider;
+
+import org.apache.tuscany.sca.binding.feed.RSSBinding;
+import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.databinding.DataBindingExtensionPoint;
+import org.apache.tuscany.sca.databinding.Mediator;
+import org.apache.tuscany.sca.databinding.TransformerExtensionPoint;
+import org.apache.tuscany.sca.databinding.impl.MediatorImpl;
+import org.apache.tuscany.sca.host.http.ServletHost;
+import org.apache.tuscany.sca.host.http.ServletHostExtensionPoint;
+import org.apache.tuscany.sca.invocation.MessageFactory;
+import org.apache.tuscany.sca.provider.BindingProviderFactory;
+import org.apache.tuscany.sca.provider.ReferenceBindingProvider;
+import org.apache.tuscany.sca.provider.ServiceBindingProvider;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.apache.tuscany.sca.runtime.RuntimeComponentReference;
+import org.apache.tuscany.sca.runtime.RuntimeComponentService;
+
+/**
+ * Implementation of the RSS binding provider factory.
+ *
+ * @version $Rev$ $Date$
+ */
+public class RSSBindingProviderFactory implements BindingProviderFactory<RSSBinding> {
+
+ private MessageFactory messageFactory;
+ private Mediator mediator;
+ private ServletHost servletHost;
+
+ public RSSBindingProviderFactory(ExtensionPointRegistry extensionPoints) {
+ ServletHostExtensionPoint servletHosts = extensionPoints.getExtensionPoint(ServletHostExtensionPoint.class);
+ this.servletHost = servletHosts.getServletHosts().get(0);
+ ModelFactoryExtensionPoint modelFactories = extensionPoints.getExtensionPoint(ModelFactoryExtensionPoint.class);
+ this.messageFactory = modelFactories.getFactory(MessageFactory.class);
+ this.mediator = new MediatorImpl(extensionPoints.getExtensionPoint(DataBindingExtensionPoint.class),
+ extensionPoints.getExtensionPoint(TransformerExtensionPoint.class));
+ }
+
+ public ReferenceBindingProvider createReferenceBindingProvider(RuntimeComponent component,
+ RuntimeComponentReference reference,
+ RSSBinding binding) {
+ return new RSSReferenceBindingProvider(component, reference, binding);
+ }
+
+ public ServiceBindingProvider createServiceBindingProvider(RuntimeComponent component,
+ RuntimeComponentService service,
+ RSSBinding binding) {
+ return new RSSServiceBindingProvider(component, service, binding, servletHost, messageFactory, mediator);
+ }
+
+ public Class<RSSBinding> getModelType() {
+ return RSSBinding.class;
+ }
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/RSSReferenceBindingProvider.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/RSSReferenceBindingProvider.java
new file mode 100644
index 0000000000..278ed9cb7e
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/RSSReferenceBindingProvider.java
@@ -0,0 +1,65 @@
+/*
+ * 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.feed.provider;
+
+import org.apache.tuscany.sca.binding.feed.RSSBinding;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.invocation.Invoker;
+import org.apache.tuscany.sca.provider.ReferenceBindingProvider;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.apache.tuscany.sca.runtime.RuntimeComponentReference;
+
+/**
+ * Implementation of the RSS binding provider.
+ *
+ * @version $Rev$ $Date$
+ */
+class RSSReferenceBindingProvider implements ReferenceBindingProvider {
+
+ private RuntimeComponentReference reference;
+ private RSSBinding binding;
+
+ RSSReferenceBindingProvider(RuntimeComponent component,
+ RuntimeComponentReference reference,
+ RSSBinding binding) {
+ this.reference = reference;
+ this.binding = binding;
+ }
+
+ public Invoker createInvoker(Operation operation) {
+ return new RSSBindingInvoker(binding.getURI(), "rss_2.0");
+ }
+
+ public boolean supportsOneWayInvocation() {
+ return false;
+ }
+
+ public InterfaceContract getBindingInterfaceContract() {
+ return reference.getInterfaceContract();
+ }
+
+ public void start() {
+ }
+
+ public void stop() {
+ }
+
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/RSSServiceBindingProvider.java b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/RSSServiceBindingProvider.java
new file mode 100644
index 0000000000..779b28cef6
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/java/org/apache/tuscany/sca/binding/feed/provider/RSSServiceBindingProvider.java
@@ -0,0 +1,85 @@
+/*
+ * 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.feed.provider;
+
+import org.apache.tuscany.sca.binding.feed.RSSBinding;
+import org.apache.tuscany.sca.databinding.Mediator;
+import org.apache.tuscany.sca.host.http.ServletHost;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+import org.apache.tuscany.sca.invocation.MessageFactory;
+import org.apache.tuscany.sca.provider.ServiceBindingProvider;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.apache.tuscany.sca.runtime.RuntimeComponentService;
+import org.apache.tuscany.sca.runtime.RuntimeWire;
+
+/**
+ * Implementation of the RSS binding provider.
+ *
+ * @version $Rev$ $Date$
+ */
+class RSSServiceBindingProvider implements ServiceBindingProvider {
+
+ private RuntimeComponentService service;
+ private RSSBinding binding;
+ private ServletHost servletHost;
+ private MessageFactory messageFactory;
+ private String servletMapping;
+ private Mediator mediator;
+
+ RSSServiceBindingProvider(RuntimeComponent component,
+ RuntimeComponentService service,
+ RSSBinding binding,
+ ServletHost servletHost,
+ MessageFactory messageFactory,
+ Mediator mediator) {
+ this.service = service;
+ this.binding = binding;
+ this.servletHost = servletHost;
+ this.messageFactory = messageFactory;
+ this.mediator = mediator;
+ }
+
+ public InterfaceContract getBindingInterfaceContract() {
+ return service.getInterfaceContract();
+ }
+
+ public boolean supportsOneWayInvocation() {
+ return false;
+ }
+
+ public void start() {
+ RuntimeComponentService componentService = (RuntimeComponentService)service;
+ RuntimeWire wire = componentService.getRuntimeWire(binding);
+
+ FeedBindingListenerServlet servlet =
+ new FeedBindingListenerServlet(wire, messageFactory, mediator, "rss_2.0");
+
+ servletMapping = binding.getURI();
+ servletHost.addServletMapping(servletMapping, servlet);
+
+ // Save the actual binding URI in the binding
+ binding.setURI(servletHost.getURLMapping(binding.getURI()).toString());
+ }
+
+ public void stop() {
+ servletHost.removeServletMapping(servletMapping);
+ }
+
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/main/resources/META-INF/services/org.apache.tuscany.sca.binding.feed.AtomBindingFactory b/java/sca/contrib/modules/binding-feed/src/main/resources/META-INF/services/org.apache.tuscany.sca.binding.feed.AtomBindingFactory
new file mode 100644
index 0000000000..49478e3db0
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/resources/META-INF/services/org.apache.tuscany.sca.binding.feed.AtomBindingFactory
@@ -0,0 +1,19 @@
+# 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.
+
+# Implementation class for the model factory
+org.apache.tuscany.sca.binding.feed.impl.AtomBindingFactoryImpl \ No newline at end of file
diff --git a/java/sca/contrib/modules/binding-feed/src/main/resources/META-INF/services/org.apache.tuscany.sca.binding.feed.RSSBindingFactory b/java/sca/contrib/modules/binding-feed/src/main/resources/META-INF/services/org.apache.tuscany.sca.binding.feed.RSSBindingFactory
new file mode 100644
index 0000000000..f69b024da9
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/resources/META-INF/services/org.apache.tuscany.sca.binding.feed.RSSBindingFactory
@@ -0,0 +1,19 @@
+# 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.
+
+# Implementation class for the model factory
+org.apache.tuscany.sca.binding.feed.impl.RSSBindingFactoryImpl \ No newline at end of file
diff --git a/java/sca/contrib/modules/binding-feed/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor b/java/sca/contrib/modules/binding-feed/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor
new file mode 100644
index 0000000000..3f073b28b9
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor
@@ -0,0 +1,20 @@
+# 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.
+
+# Implementation class for the artifact processor extension
+org.apache.tuscany.sca.assembly.xml.DefaultBeanModelProcessor;qname=http://tuscany.apache.org/xmlns/sca/1.0#binding.atom,model=org.apache.tuscany.sca.binding.feed.AtomBinding,factory=org.apache.tuscany.sca.binding.feed.AtomBindingFactory
+org.apache.tuscany.sca.assembly.xml.DefaultBeanModelProcessor;qname=http://tuscany.apache.org/xmlns/sca/1.0#binding.rss,model=org.apache.tuscany.sca.binding.feed.RSSBinding,factory=org.apache.tuscany.sca.binding.feed.RSSBindingFactory
diff --git a/java/sca/contrib/modules/binding-feed/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory b/java/sca/contrib/modules/binding-feed/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory
new file mode 100644
index 0000000000..f81a0d33ae
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory
@@ -0,0 +1,20 @@
+# 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.
+
+# Implementation class for the binding extension
+org.apache.tuscany.sca.binding.feed.provider.AtomBindingProviderFactory;model=org.apache.tuscany.sca.binding.feed.AtomBinding
+org.apache.tuscany.sca.binding.feed.provider.RSSBindingProviderFactory;model=org.apache.tuscany.sca.binding.feed.RSSBinding
diff --git a/java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/Consumer.java b/java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/Consumer.java
new file mode 100644
index 0000000000..4a33637121
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/Consumer.java
@@ -0,0 +1,35 @@
+/*
+ * 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.feed;
+
+import org.apache.tuscany.sca.host.embedded.SCADomain;
+
+public class Consumer {
+
+ public static void main(String[] args) throws Exception {
+
+ SCADomain scaDomain = SCADomain.newInstance("org/apache/tuscany/sca/binding/feed/Consumer.composite");
+
+ CustomerClient testService = scaDomain.getService(CustomerClient.class, "CustomerClient");
+ testService.testCustomerCollection();
+
+ scaDomain.close();
+ }
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/CustomerClient.java b/java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/CustomerClient.java
new file mode 100644
index 0000000000..b7416011ba
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/CustomerClient.java
@@ -0,0 +1,25 @@
+/*
+ * 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.feed;
+
+public interface CustomerClient {
+
+ void testCustomerCollection() throws Exception;
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/CustomerClientImpl.java b/java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/CustomerClientImpl.java
new file mode 100644
index 0000000000..884e954036
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/CustomerClientImpl.java
@@ -0,0 +1,97 @@
+/*
+ * 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.feed;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tuscany.sca.binding.feed.collection.Collection;
+import org.osoa.sca.annotations.Reference;
+
+import com.sun.syndication.feed.atom.Content;
+import com.sun.syndication.feed.atom.Entry;
+import com.sun.syndication.feed.atom.Feed;
+
+public class CustomerClientImpl implements CustomerClient {
+
+ @Reference
+ public Collection resourceCollection;
+
+ public void testCustomerCollection() throws Exception {
+
+ Entry newEntry = newEntry("Sponge Bob");
+ System.out.println(">>> post entry=" + newEntry.getTitle());
+ newEntry = resourceCollection.post(newEntry);
+ System.out.println("<<< post id=" + newEntry.getId() + " entry=" + newEntry.getTitle());
+
+ newEntry = newEntry("Jane Bond");
+ System.out.println(">>> post entry=" + newEntry.getTitle());
+ newEntry = resourceCollection.post(newEntry);
+ System.out.println("<<< post id=" + newEntry.getId() + " entry=" + newEntry.getTitle());
+
+ System.out.println(">>> get id=" + newEntry.getId());
+ Entry entry = resourceCollection.get(newEntry.getId());
+ System.out.println("<<< get id=" + entry.getId() + " entry=" + entry.getTitle());
+
+ System.out.println(">>> put id=" + newEntry.getId() + " entry=" + entry.getTitle());
+ resourceCollection.put(entry.getId(), updateEntry(entry, "James Bond"));
+ System.out.println("<<< put id=" + entry.getId() + " entry=" + entry.getTitle());
+
+ System.out.println(">>> delete id=" + entry.getId());
+ resourceCollection.delete(entry.getId());
+ System.out.println("<<< delete id=" + entry.getId());
+
+ System.out.println(">>> get collection");
+ Feed feed = resourceCollection.getFeed();
+ System.out.println("<<< get collection");
+ for (Object o : feed.getEntries()) {
+ Entry e = (Entry)o;
+ System.out.println("id = " + e.getId() + " entry = " + e.getTitle());
+ }
+ }
+
+ private Entry newEntry(String value) {
+
+ Entry entry = new Entry();
+ entry.setTitle("customer " + value);
+
+ Content content = new Content();
+ content.setValue(value);
+ content.setType(Content.TEXT);
+ List<Object> list = new ArrayList<Object>();
+ list.add(content);
+ entry.setContents(list);
+
+ return entry;
+ }
+
+ private Entry updateEntry(Entry entry, String value) {
+
+ entry.setTitle("customer " + value);
+ Content content = new Content();
+ content.setValue(value);
+ content.setType(Content.TEXT);
+ List<Object> list = new ArrayList<Object>();
+ list.add(content);
+ entry.setContents(list);
+
+ return entry;
+ }
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/CustomerCollectionImpl.java b/java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/CustomerCollectionImpl.java
new file mode 100644
index 0000000000..ca4a5a1946
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/CustomerCollectionImpl.java
@@ -0,0 +1,136 @@
+/*
+ * 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.feed;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.tuscany.sca.binding.feed.collection.Collection;
+import org.osoa.sca.annotations.Scope;
+
+import com.sun.syndication.feed.atom.Content;
+import com.sun.syndication.feed.atom.Entry;
+import com.sun.syndication.feed.atom.Feed;
+import com.sun.syndication.feed.atom.Link;
+
+@Scope("COMPOSITE")
+public class CustomerCollectionImpl implements Collection {
+
+ private Map<String, Entry> entries = new HashMap<String, Entry>();
+
+ public CustomerCollectionImpl() {
+
+ for (int i = 0; i < 4; i++) {
+ String id = "urn:uuid:customer-" + UUID.randomUUID().toString();
+
+ Entry entry = new Entry();
+ entry.setTitle("customer " + "Jane Doe_" + String.valueOf(i));
+ entry.setId(id);
+
+ Content content = new Content();
+ content.setValue("Jane Doe_" + String.valueOf(i));
+ content.setType(Content.TEXT);
+ entry.setContents(Collections.singletonList(content));
+
+ List<Link> links = new ArrayList<Link>();
+ Link link = new Link();
+ link.setRel("edit");
+ link.setHref("" + id);
+ links.add(link);
+ entry.setOtherLinks(links);
+
+ links = new ArrayList<Link>();
+ link = new Link();
+ link.setRel("alternate");
+ link.setHref("" + id);
+ links.add(link);
+ entry.setAlternateLinks(links);
+
+ entry.setCreated(new Date());
+
+ entries.put(id, entry);
+ System.out.println(">>> id=" + id);
+ }
+ }
+
+ public Entry post(Entry entry) {
+ System.out.println(">>> ResourceCollectionImpl.post entry=" + entry.getTitle());
+
+ String id = "urn:uuid:customer-" + UUID.randomUUID().toString();
+ entry.setId(id);
+
+ List<Link> links = new ArrayList<Link>();
+ Link link = new Link();
+ link.setRel("edit");
+ link.setHref("" + id);
+ links.add(link);
+ entry.setOtherLinks(links);
+
+ links = new ArrayList<Link>();
+ link = new Link();
+ link.setRel("alternate");
+ link.setHref("" + id);
+ links.add(link);
+ entry.setAlternateLinks(links);
+
+ entry.setCreated(new Date());
+
+ entries.put(id, entry);
+ System.out.println(">>> ResourceCollectionImpl.post return id=" + id);
+
+ return entry;
+ }
+
+ public Entry get(String id) {
+ System.out.println(">>> ResourceCollectionImpl.get id=" + id);
+ return entries.get(id);
+ }
+
+ public void put(String id, Entry entry) {
+ System.out.println(">>> ResourceCollectionImpl.put id=" + id + " entry=" + entry.getTitle());
+
+ entry.setUpdated(new Date());
+ entries.put(id, entry);
+ }
+
+ public void delete(String id) {
+ System.out.println(">>> ResourceCollectionImpl.delete id=" + id);
+ entries.remove(id);
+ }
+
+ @SuppressWarnings("unchecked")
+ public Feed getFeed() {
+ System.out.println(">>> ResourceCollectionImpl.get collection");
+
+ Feed feed = new Feed();
+ feed.setTitle("customers");
+ Content subtitle = new Content();
+ subtitle.setValue("This is a sample feed");
+ feed.setSubtitle(subtitle);
+ feed.getEntries().addAll(entries.values());
+ return feed;
+ }
+
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/Provider.java b/java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/Provider.java
new file mode 100644
index 0000000000..a9ddc1a2c8
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/test/java/org/apache/tuscany/sca/binding/feed/Provider.java
@@ -0,0 +1,41 @@
+/*
+ * 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.feed;
+
+import java.io.IOException;
+
+import org.apache.tuscany.sca.host.embedded.SCADomain;
+
+public class Provider {
+
+ public static void main(String[] args) {
+
+ SCADomain scaDomain = SCADomain.newInstance("org/apache/tuscany/sca/binding/feed/Provider.composite");
+ System.out.println("Provider.composite ready...");
+
+ try {
+ System.in.read();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ scaDomain.close();
+ }
+}
diff --git a/java/sca/contrib/modules/binding-feed/src/test/resources/org/apache/tuscany/sca/binding/feed/Consumer.composite b/java/sca/contrib/modules/binding-feed/src/test/resources/org/apache/tuscany/sca/binding/feed/Consumer.composite
new file mode 100644
index 0000000000..1987c042e6
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/test/resources/org/apache/tuscany/sca/binding/feed/Consumer.composite
@@ -0,0 +1,32 @@
+<?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://customer"
+ name="Consumer">
+
+ <component name="CustomerClient">
+ <implementation.java class="org.apache.tuscany.sca.binding.feed.CustomerClientImpl"/>
+ <reference name="resourceCollection">
+ <tuscany:binding.atom uri="http://localhost:8084/customer"/>
+ </reference>
+ </component>
+
+</composite>
diff --git a/java/sca/contrib/modules/binding-feed/src/test/resources/org/apache/tuscany/sca/binding/feed/Provider.composite b/java/sca/contrib/modules/binding-feed/src/test/resources/org/apache/tuscany/sca/binding/feed/Provider.composite
new file mode 100644
index 0000000000..9268fbe211
--- /dev/null
+++ b/java/sca/contrib/modules/binding-feed/src/test/resources/org/apache/tuscany/sca/binding/feed/Provider.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://customer"
+ name="Provider">
+
+ <service name="customer" promote="CustomerCollection">
+ <tuscany:binding.atom uri = "http://localhost:8084/customer"/>
+ </service>
+
+ <component name="CustomerCollection">
+ <implementation.java class="org.apache.tuscany.sca.binding.feed.CustomerCollectionImpl"/>
+ </component>
+
+</composite>