summaryrefslogtreecommitdiffstats
path: root/java/sca/modules/binding-atom
diff options
context:
space:
mode:
authorlresende <lresende@13f79535-47bb-0310-9956-ffa450edef68>2008-11-19 00:10:54 +0000
committerlresende <lresende@13f79535-47bb-0310-9956-ffa450edef68>2008-11-19 00:10:54 +0000
commit60744a36aae604ac3c4499ed54f1082ab8f5947d (patch)
treee31d312659c912cdf29ef7a677406795fe5b3726 /java/sca/modules/binding-atom
parentad1c9458ea08eb593be252b706a88568f17c494c (diff)
Copying modules from Equinox branch, to start merging the delta changes from 1.x/original trunk
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@718815 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to '')
-rw-r--r--java/sca/modules/binding-atom-abdera/LICENSE205
-rw-r--r--java/sca/modules/binding-atom-abdera/META-INF/MANIFEST.MF55
-rw-r--r--java/sca/modules/binding-atom-abdera/NOTICE6
-rw-r--r--java/sca/modules/binding-atom-abdera/pom.xml207
-rw-r--r--java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/collection/Collection.java81
-rw-r--r--java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/collection/MediaCollection.java55
-rw-r--r--java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/collection/NotFoundException.java45
-rw-r--r--java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingInvoker.java485
-rw-r--r--java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingListenerServlet.java836
-rw-r--r--java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingProviderFactory.java74
-rw-r--r--java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingUtil.java164
-rw-r--r--java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomReferenceBindingProvider.java183
-rw-r--r--java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomServiceBindingProvider.java87
-rw-r--r--java/sca/modules/binding-atom-abdera/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory19
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomDeleteTestCase.java109
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomGetTestCase.java107
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomPostTestCase.java96
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomPutTestCase.java114
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomTestCaseUtils.java96
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/Consumer.java42
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ConsumerProviderAtomTestCase.java165
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ContentNegotiationTest.java265
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/CustomerClient.java29
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/CustomerClientImpl.java99
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/CustomerCollectionImpl.java149
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/Provider.java48
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderEntryEntityTagsTest.java477
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderFeedEntityTagsTest.java365
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderServiceDocumentTest.java189
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/resources/org/apache/tuscany/sca/binding/atom/Consumer.composite32
-rw-r--r--java/sca/modules/binding-atom-abdera/src/test/resources/org/apache/tuscany/sca/binding/atom/Provider.composite33
-rw-r--r--java/sca/modules/binding-atom/LICENSE205
-rw-r--r--java/sca/modules/binding-atom/META-INF/MANIFEST.MF23
-rw-r--r--java/sca/modules/binding-atom/NOTICE6
-rw-r--r--java/sca/modules/binding-atom/pom.xml62
-rw-r--r--java/sca/modules/binding-atom/src/main/java/org/apache/tuscany/sca/binding/atom/AtomBinding.java43
-rw-r--r--java/sca/modules/binding-atom/src/main/java/org/apache/tuscany/sca/binding/atom/AtomBindingFactory.java35
-rw-r--r--java/sca/modules/binding-atom/src/main/java/org/apache/tuscany/sca/binding/atom/impl/AtomBindingFactoryImpl.java36
-rw-r--r--java/sca/modules/binding-atom/src/main/java/org/apache/tuscany/sca/binding/atom/impl/AtomBindingImpl.java115
-rw-r--r--java/sca/modules/binding-atom/src/main/resources/META-INF/services/org.apache.tuscany.sca.binding.atom.AtomBindingFactory19
-rw-r--r--java/sca/modules/binding-atom/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor19
-rw-r--r--java/sca/modules/binding-atom/src/test/java/org/apache/tuscany/sca/binding/atom/AtomBindingProcessorTestCase.java91
42 files changed, 5571 insertions, 0 deletions
diff --git a/java/sca/modules/binding-atom-abdera/LICENSE b/java/sca/modules/binding-atom-abdera/LICENSE
new file mode 100644
index 0000000000..6e529a25c4
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/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/modules/binding-atom-abdera/META-INF/MANIFEST.MF b/java/sca/modules/binding-atom-abdera/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..8e52c6f2a8
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/META-INF/MANIFEST.MF
@@ -0,0 +1,55 @@
+Manifest-Version: 1.0
+Export-Package: org.apache.tuscany.sca.binding.atom.collection;uses:="
+ org.osoa.sca.annotations,org.apache.abdera.model";version="1.4"
+Private-Package: org.apache.tuscany.sca.binding.atom.provider;version=
+ "1.4"
+Tool: Bnd-0.0.255
+Bundle-Name: Apache Tuscany SCA Atom Feed Binding Extension
+Created-By: 1.6.0_07 (Sun Microsystems Inc.)
+Bundle-Vendor: The Apache Software Foundation
+Bundle-Version: 1.4
+Bnd-LastModified: 1225397264250
+Bundle-ManifestVersion: 2
+Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
+Bundle-Description: Apache Tuscany SCA Atom Feed Binding Extension
+Import-Package: javax.activation;version="1.1";resolution:=optional,
+ javax.servlet,
+ javax.servlet.http,
+ javax.xml.namespace,
+
+ org.apache.abdera,
+ org.apache.abdera.factory,
+ org.apache.abdera.i18n.iri,
+ org.apache.abdera.model,
+ org.apache.abdera.parser,
+ org.apache.abdera.protocol;resolution:=optional,
+ org.apache.abdera.protocol.client;resolution:=optional,
+ org.apache.abdera.protocol.client.util;resolution:=optional,
+ org.apache.abdera.writer,
+ org.apache.commons.codec.binary,
+ org.apache.commons.httpclient,
+ org.apache.commons.httpclient.auth,
+ org.apache.commons.httpclient.methods,
+ org.apache.commons.httpclient.params,
+ org.apache.tuscany.sca.assembly;version="1.4",
+ org.apache.tuscany.sca.binding.atom;version="1.4",
+ org.apache.tuscany.sca.binding.atom.collection;version="1.4",
+ org.apache.tuscany.sca.binding.http;version="1.4",
+ org.apache.tuscany.sca.core;version="1.4",
+ org.apache.tuscany.sca.data.collection;version="1.4",
+ org.apache.tuscany.sca.databinding;version="1.4",
+ org.apache.tuscany.sca.databinding.impl;version="1.4",
+ org.apache.tuscany.sca.host.http;version="1.4",
+ org.apache.tuscany.sca.interfacedef;version="1.4",
+ org.apache.tuscany.sca.interfacedef.impl;version="1.4",
+ org.apache.tuscany.sca.interfacedef.util;version="1.4",
+ org.apache.tuscany.sca.invocation;version="1.4",
+ org.apache.tuscany.sca.policy;version="1.4.0",
+ org.apache.tuscany.sca.provider;version="1.4",
+ org.apache.tuscany.sca.runtime;version="1.4",
+
+ org.osoa.sca;version="1.4",
+ org.osoa.sca.annotations;version="1.4"
+Bundle-SymbolicName: org.apache.tuscany.sca.binding.atom.abdera
+Bundle-DocURL: http://www.apache.org/
+
diff --git a/java/sca/modules/binding-atom-abdera/NOTICE b/java/sca/modules/binding-atom-abdera/NOTICE
new file mode 100644
index 0000000000..1325efd8bf
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/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/modules/binding-atom-abdera/pom.xml b/java/sca/modules/binding-atom-abdera/pom.xml
new file mode 100644
index 0000000000..be24ff561e
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/pom.xml
@@ -0,0 +1,207 @@
+<?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>1.4-EQUINOX-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>tuscany-binding-atom-abdera</artifactId>
+ <name>Apache Tuscany SCA Atom Feed Binding Extension</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-binding-atom</artifactId>
+ <version>1.4-EQUINOX-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-assembly</artifactId>
+ <version>1.4-EQUINOX-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-interface-java</artifactId>
+ <version>1.4-EQUINOX-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-data-api</artifactId>
+ <version>1.4-EQUINOX-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-core-spi</artifactId>
+ <version>1.4-EQUINOX-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-databinding</artifactId>
+ <version>1.4-EQUINOX-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-host-http</artifactId>
+ <version>1.4-EQUINOX-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-binding-http</artifactId>
+ <version>1.4-EQUINOX-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-httpclient</groupId>
+ <artifactId>commons-httpclient</artifactId>
+ <version>3.0.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.abdera</groupId>
+ <artifactId>abdera-core</artifactId>
+ <version>0.4.0-incubating</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-activation_1.0.2_spec</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.abdera</groupId>
+ <artifactId>abdera-parser</artifactId>
+ <version>0.4.0-incubating</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-stax-api_1.0_spec</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>xom</groupId>
+ <artifactId>xom</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.ws.commons.axiom</groupId>
+ <artifactId>axiom-impl</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.ws.commons.axiom</groupId>
+ <artifactId>axiom-impl</artifactId>
+ <version>1.2.7</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.abdera</groupId>
+ <artifactId>abdera-client</artifactId>
+ <version>0.4.0-incubating</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.abdera</groupId>
+ <artifactId>abdera-extensions-main</artifactId>
+ <version>0.4.0-incubating</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.abdera</groupId>
+ <artifactId>abdera-extensions-json</artifactId>
+ <version>0.4.0-incubating</version>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-host-jetty</artifactId>
+ <version>1.4-EQUINOX-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-implementation-java-runtime</artifactId>
+ <version>1.4-EQUINOX-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-node-impl</artifactId>
+ <version>1.4-EQUINOX-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>
+
+</project>
diff --git a/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/collection/Collection.java b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/collection/Collection.java
new file mode 100644
index 0000000000..7356cd0d2a
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/collection/Collection.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.binding.atom.collection;
+
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.osoa.sca.annotations.Remotable;
+
+/**
+ * Provides access to a collection of resources using Atom.
+ *
+ * @version $Rev$ $Date$
+ */
+@Remotable
+public interface Collection {
+
+ /**
+ * Get an Atom feed for a collection of resources.
+ *
+ * @return the Atom feed
+ */
+ Feed getFeed();
+
+ /**
+ * Get an Atom feed for a collection of resources resulting
+ * from a query.
+ *
+ * @param queryString a query string
+ * @return the Atom feed
+ */
+ Feed query(String queryString);
+
+ /**
+ * 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/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/collection/MediaCollection.java b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/collection/MediaCollection.java
new file mode 100644
index 0000000000..cc351442e7
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/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.atom.collection;
+
+import java.io.InputStream;
+
+import org.osoa.sca.annotations.Remotable;
+
+import org.apache.abdera.model.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/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/collection/NotFoundException.java b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/collection/NotFoundException.java
new file mode 100644
index 0000000000..b457840922
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/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.atom.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/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingInvoker.java b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingInvoker.java
new file mode 100644
index 0000000000..dafcf57311
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingInvoker.java
@@ -0,0 +1,485 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.binding.atom.provider;
+
+import static org.apache.tuscany.sca.binding.atom.provider.AtomBindingUtil.entry;
+import static org.apache.tuscany.sca.binding.atom.provider.AtomBindingUtil.feedEntry;
+
+import java.io.InputStreamReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.model.Document;
+import org.apache.abdera.model.Feed;
+import org.apache.abdera.parser.Parser;
+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.atom.collection.NotFoundException;
+import org.apache.tuscany.sca.data.collection.Entry;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.invocation.Invoker;
+import org.apache.tuscany.sca.invocation.Message;
+import org.osoa.sca.ServiceRuntimeException;
+
+/**
+ * Invoker for the Atom binding.
+ *
+ * @version $Rev$ $Date$
+ */
+class AtomBindingInvoker implements Invoker {
+
+ private static final Factory abderaFactory = Abdera.getNewFactory();
+ private static final Parser abderaParser = Abdera.getNewParser();
+
+ Operation operation;
+ String uri;
+ HttpClient httpClient;
+ String authorizationHeader;
+ AtomReferenceBindingProvider provider;
+
+ AtomBindingInvoker(Operation operation, String uri, HttpClient httpClient, String authorizationHeader, AtomReferenceBindingProvider bindingProvider) {
+ this.operation = operation;
+ this.uri = uri;
+ this.httpClient = httpClient;
+ this.authorizationHeader = authorizationHeader;
+ this.provider = bindingProvider;
+ }
+
+ 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());
+ }
+
+ /**
+ * Get operation invoker
+ */
+ public static class GetInvoker extends AtomBindingInvoker {
+
+ public GetInvoker(Operation operation, String uri, HttpClient httpClient, String authorizationHeader, AtomReferenceBindingProvider bindingProvider) {
+ super(operation, uri, httpClient, authorizationHeader, bindingProvider);
+ }
+
+ @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);
+ boolean parsing = false;
+ try {
+ httpClient.executeMethod(getMethod);
+ int status = getMethod.getStatusCode();
+
+ // Read the Atom entry
+ if (status == 200) {
+ Document<org.apache.abdera.model.Entry> doc =
+ abderaParser.parse(new InputStreamReader(getMethod.getResponseBodyAsStream()));
+ parsing = true;
+ org.apache.abdera.model.Entry feedEntry = doc.getRoot();
+
+ if (provider.supportsFeedEntries()) {
+
+ // Return the Atom entry
+ msg.setBody(feedEntry);
+
+ } else {
+
+ // Convert the feed entry to a data entry and return the data item
+ Entry<Object, Object> entry = entry(feedEntry, provider.getItemClassType(),
+ provider.getItemXMLType(), provider.getMediator());
+ msg.setBody(entry.getData());
+ }
+
+ } 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 {
+ if (!parsing) {
+ // Release the connection unless the Abdera parser is
+ // parsing the response, in this case it will release it
+ getMethod.releaseConnection();
+ }
+ }
+
+ return msg;
+ }
+ }
+
+ /**
+ * Post operation invoker
+ */
+ public static class PostInvoker extends AtomBindingInvoker {
+
+ public PostInvoker(Operation operation, String uri, HttpClient httpClient, String authorizationHeader, AtomReferenceBindingProvider bindingProvider) {
+ super(operation, uri, httpClient, authorizationHeader, bindingProvider);
+ }
+
+ @Override
+ public Message invoke(Message msg) {
+ // Post an entry
+ Object[] args = (Object[])msg.getBody();
+ org.apache.abdera.model.Entry feedEntry;
+ if (provider.supportsFeedEntries()) {
+
+ // Expect an Atom entry
+ feedEntry = (org.apache.abdera.model.Entry)args[0];
+ } else {
+
+ // Expect a key and data item
+ Entry<Object, Object> entry = new Entry<Object, Object>(args[0], args[1]);
+ feedEntry = feedEntry(entry, provider.getItemClassType(),
+ provider.getItemXMLType(), provider.getMediator(), abderaFactory);
+ }
+
+ // Send an HTTP POST
+ PostMethod postMethod = new PostMethod(uri);
+ postMethod.setRequestHeader("Authorization", authorizationHeader);
+ boolean parsing = false;
+ try {
+
+ // Write the Atom entry
+ StringWriter writer = new StringWriter();
+ feedEntry.writeTo(writer);
+ // postMethod.setRequestHeader("Content-type", "application/atom+xml; charset=utf-8");
+ postMethod.setRequestHeader("Content-type", "application/atom+xml;type=entry");
+ postMethod.setRequestEntity(new StringRequestEntity(writer.toString()));
+
+ httpClient.executeMethod(postMethod);
+ int status = postMethod.getStatusCode();
+
+ // Read the Atom entry
+ if (status == 200 || status == 201) {
+ Document<org.apache.abdera.model.Entry> doc = abderaParser.parse(new InputStreamReader(postMethod.getResponseBodyAsStream()));
+ parsing = true;
+ org.apache.abdera.model.Entry createdEntry = doc.getRoot();
+
+ // Returns the created Atom entry ID
+ if (provider.supportsFeedEntries()) {
+
+ // Returns the created entry
+ msg.setBody(createdEntry);
+
+ } else {
+
+ // Returns the id of the created entry
+ msg.setBody(createdEntry.getId().toString());
+ }
+
+ } 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 {
+ if (!parsing) {
+ // Release the connection unless the Abdera parser is
+ // parsing the response, in this case it will release it
+ postMethod.releaseConnection();
+ }
+ }
+
+ return msg;
+ }
+ }
+
+ /**
+ * Put operation invoker
+ */
+ public static class PutInvoker extends AtomBindingInvoker {
+
+ public PutInvoker(Operation operation, String uri, HttpClient httpClient, String authorizationHeader, AtomReferenceBindingProvider bindingProvider) {
+ super(operation, uri, httpClient, authorizationHeader, bindingProvider);
+ }
+
+ @Override
+ public Message invoke(Message msg) {
+ // Put an entry
+ Object[] args = (Object[])msg.getBody();
+ String id;
+ org.apache.abdera.model.Entry feedEntry;
+ if (provider.supportsFeedEntries()) {
+
+ // Expect a key and Atom entry
+ id = (String)args[0];
+ feedEntry = (org.apache.abdera.model.Entry)args[1];
+ } else {
+
+ // Expect a key and data item
+ id = (String)args[0];
+ Entry<Object, Object> entry = new Entry<Object, Object>(id, args[1]);
+ feedEntry = feedEntry(entry, provider.getItemClassType(),
+ provider.getItemXMLType(), provider.getMediator(), abderaFactory);
+ }
+
+ // Send an HTTP PUT
+ PutMethod putMethod = new PutMethod(uri + "/" + id);
+ putMethod.setRequestHeader("Authorization", authorizationHeader);
+
+ try {
+
+ // Write the Atom entry
+ StringWriter writer = new StringWriter();
+ feedEntry.writeTo(writer);
+ putMethod.setRequestHeader("Content-type", "application/atom+xml; charset=utf-8");
+ putMethod.setRequestEntity(new StringRequestEntity(writer.toString()));
+
+ httpClient.executeMethod(putMethod);
+ int status = putMethod.getStatusCode();
+ if (status == 200 || status == 201 || status == 412) {
+
+ 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 {
+ putMethod.releaseConnection();
+ }
+
+ return msg;
+ }
+ }
+
+ /**
+ * Delete operation invoker
+ */
+ public static class DeleteInvoker extends AtomBindingInvoker {
+
+ public DeleteInvoker(Operation operation, String uri, HttpClient httpClient, String authorizationHeader, AtomReferenceBindingProvider bindingProvider) {
+ super(operation, uri, httpClient, authorizationHeader, bindingProvider);
+ }
+
+ @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();
+ 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, AtomReferenceBindingProvider bindingProvider) {
+ super(operation, uri, httpClient, authorizationHeader, bindingProvider);
+ }
+
+ @Override
+ public Message invoke(Message msg) {
+ // Get a feed
+
+ // Send an HTTP GET
+ GetMethod getMethod = new GetMethod(uri);
+ getMethod.setRequestHeader("Authorization", authorizationHeader);
+ boolean parsing = false;
+ try {
+ httpClient.executeMethod(getMethod);
+ int status = getMethod.getStatusCode();
+ // AtomBindingInvoker.printResponseHeader( getMethod );
+
+ // Read the Atom feed
+ if (status == 200) {
+ Document<Feed> doc = abderaParser.parse(new InputStreamReader(getMethod.getResponseBodyAsStream()));
+ parsing = true;
+ Feed feed = doc.getRoot();
+
+ if (provider.supportsFeedEntries()) {
+
+ // Returns the Atom feed
+ msg.setBody(feed);
+
+ } else {
+
+ // Returns an array of data entries
+ List<Entry<Object, Object>> entries = new ArrayList<Entry<Object,Object>>();
+ for (org.apache.abdera.model.Entry feedEntry: feed.getEntries()) {
+ Entry<Object, Object> entry = entry(feedEntry, provider.getItemClassType(),
+ provider.getItemXMLType(), provider.getMediator());
+ entries.add(entry);
+ }
+ msg.setBody(entries.toArray(new Entry[entries.size()]));
+ }
+
+ } 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 {
+ if (!parsing) {
+ // Release the connection unless the Abdera parser is
+ // parsing the response, in this case it will release it
+ getMethod.releaseConnection();
+ }
+ }
+
+ return msg;
+ }
+ }
+
+ /**
+ * Query operation invoker
+ */
+ public static class QueryInvoker extends AtomBindingInvoker {
+
+ public QueryInvoker(Operation operation, String uri, HttpClient httpClient, String authorizationHeader, AtomReferenceBindingProvider bindingProvider) {
+ super(operation, uri, httpClient, authorizationHeader, bindingProvider);
+ }
+
+ @Override
+ public Message invoke(Message msg) {
+ // Get a feed from a query
+ String queryString = (String)((Object[])msg.getBody())[0];
+
+ // Send an HTTP GET
+ GetMethod getMethod = new GetMethod(uri);
+ getMethod.setRequestHeader("Authorization", authorizationHeader);
+ getMethod.setQueryString(queryString);
+ boolean parsing = false;
+ try {
+ httpClient.executeMethod(getMethod);
+ int status = getMethod.getStatusCode();
+
+ // Read the Atom feed
+ if (status == 200) {
+ Document<Feed> doc = abderaParser.parse(new InputStreamReader(getMethod.getResponseBodyAsStream()));
+ parsing = true;
+ Feed feed = doc.getRoot();
+
+ if (provider.supportsFeedEntries()) {
+
+ // Returns the Atom feed
+ msg.setBody(feed);
+
+ } else {
+
+ // Returns an array of data entries
+ List<Entry<Object, Object>> entries = new ArrayList<Entry<Object,Object>>();
+ for (org.apache.abdera.model.Entry feedEntry: feed.getEntries()) {
+ Entry<Object, Object> entry = entry(feedEntry, provider.getItemClassType(),
+ provider.getItemXMLType(), provider.getMediator());
+ entries.add(entry);
+ }
+ msg.setBody(entries.toArray(new Entry[entries.size()]));
+ }
+
+ } 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 {
+ if (!parsing) {
+ // Release the connection unless the Abdera parser is
+ // parsing the response, in this case it will release it
+ getMethod.releaseConnection();
+ }
+ }
+
+ return msg;
+ }
+ }
+
+ /**
+ * PostMedia operation invoker
+ */
+ public static class PostMediaInvoker extends AtomBindingInvoker {
+
+ public PostMediaInvoker(Operation operation, String uri, HttpClient httpClient, String authorizationHeader, AtomReferenceBindingProvider bindingProvider) {
+ super(operation, uri, httpClient, authorizationHeader, bindingProvider);
+ }
+
+ @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, AtomReferenceBindingProvider bindingProvider) {
+ super(operation, uri, httpClient, authorizationHeader, bindingProvider);
+ }
+
+ @Override
+ public Message invoke(Message msg) {
+ // TODO implement
+ return super.invoke(msg);
+ }
+ }
+
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingListenerServlet.java b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingListenerServlet.java
new file mode 100644
index 0000000000..7cf087bb41
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingListenerServlet.java
@@ -0,0 +1,836 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.binding.atom.provider;
+
+import static org.apache.tuscany.sca.binding.atom.provider.AtomBindingUtil.entry;
+import static org.apache.tuscany.sca.binding.atom.provider.AtomBindingUtil.feedEntry;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+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.abdera.Abdera;
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.i18n.iri.IRI;
+import org.apache.abdera.model.Category;
+import org.apache.abdera.model.Collection;
+import org.apache.abdera.model.Document;
+import org.apache.abdera.model.Feed;
+import org.apache.abdera.model.Link;
+import org.apache.abdera.model.Service;
+import org.apache.abdera.model.Workspace;
+import org.apache.abdera.parser.ParseException;
+import org.apache.abdera.parser.Parser;
+import org.apache.abdera.writer.WriterFactory;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.tuscany.sca.binding.http.CacheContext;
+import org.apache.tuscany.sca.data.collection.Entry;
+import org.apache.tuscany.sca.databinding.Mediator;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.util.XMLType;
+import org.apache.tuscany.sca.invocation.InvocationChain;
+import org.apache.tuscany.sca.invocation.Invoker;
+import org.apache.tuscany.sca.invocation.Message;
+import org.apache.tuscany.sca.invocation.MessageFactory;
+import org.apache.tuscany.sca.runtime.RuntimeWire;
+
+/**
+ * A resource collection binding listener, implemented as a Servlet and
+ * registered in a Servlet host provided by the SCA hosting runtime.
+ *
+ * @version $Rev$ $Date$
+ */
+class AtomBindingListenerServlet extends HttpServlet {
+ private static final Logger logger = Logger.getLogger(AtomBindingListenerServlet.class.getName());
+ private static final long serialVersionUID = 1L;
+
+ private static final Factory abderaFactory = Abdera.getNewFactory();
+ private static final Parser abderaParser = Abdera.getNewParser();
+ private static final String ETAG = "ETag";
+ private static final String LASTMODIFIED = "Last-Modified";
+ private static final String LOCATION = "Location";
+ private static final String CONTENTLOCATION = "Content-Location";
+ private static final SimpleDateFormat dateFormat = new SimpleDateFormat( "EEE, dd MMM yyyy HH:mm:ss Z" ); // RFC 822 date time
+
+ private RuntimeWire wire;
+ private Invoker getFeedInvoker;
+ 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 title;
+ private Mediator mediator;
+ private DataType<?> itemClassType;
+ private DataType<?> itemXMLType;
+ private boolean supportsFeedEntries;
+
+ /**
+ * Constructs a new binding listener.
+ *
+ * @param wire
+ * @param messageFactory
+ * @param feedType
+ */
+ AtomBindingListenerServlet(RuntimeWire wire, MessageFactory messageFactory, Mediator mediator, String title) {
+ this.wire = wire;
+ this.messageFactory = messageFactory;
+ this.mediator = mediator;
+ this.title = title;
+
+ // 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 == org.apache.abdera.model.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
+
+ // Test for any cache info in the request
+ CacheContext cacheContext = null;
+ try {
+ cacheContext = CacheContext.getCacheContextFromRequest( request );
+ } catch ( java.text.ParseException e ) {
+ }
+ // System.out.println( "AtomBindingListener.doGet cache context=" + cacheContext );
+
+ // Get the request path
+ int servletPathLength = request.getContextPath().length() + request.getServletPath().length();
+ String path = URLDecoder.decode(request.getRequestURI().substring(servletPathLength), "UTF-8");
+
+ logger.fine("get " + request.getRequestURI());
+
+ // Handle an Atom request
+ if (path != null && path.equals("/atomsvc")) {
+ /*
+ <?xml version='1.0' encoding='UTF-8'?>
+ <service xmlns="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom">
+ <workspace>
+ <atom:title type="text">resource</atom:title>
+ <collection href="http://luck.ibm.com:8084/customer">
+ <atom:title type="text">entries</atom:title>
+ <accept>application/atom+xml;type=entry</accept>
+ <categories />
+ </collection>
+ </workspace>
+ </service>
+ */
+
+ // Return the Atom service document
+ response.setContentType("application/atomsvc+xml; charset=utf-8");
+
+ String href = request.getRequestURL().toString();
+ href = href.substring(0, href.length() - "/atomsvc".length());
+
+ String workspaceURL = new String( href );
+ int pathIndex = workspaceURL.indexOf( request.getServletPath() );
+ if ( -1 != pathIndex )
+ workspaceURL = workspaceURL.substring( 0, pathIndex ) + "/";
+
+ Service service = abderaFactory.newService();
+ //service.setText("service");
+
+ Workspace workspace = abderaFactory.newWorkspace();
+ if ( title != null )
+ workspace.setTitle(title);
+ else
+ workspace.setTitle("workspace");
+ workspace.setBaseUri( new IRI( workspaceURL ));
+
+ Collection collection = workspace.addCollection("collection", href );
+ Feed feed = getFeed( request );
+ if ( feed != null ) {
+ String title = feed.getTitle();
+ if ( title != null )
+ collection.setTitle(title);
+ else
+ collection.setTitle("entries");
+ collection.addAccepts("application/atom+xml;type=feed");
+ collection.addAccepts("application/json;type=feed");
+ collection.addAccepts("application/atom+xml;type=entry");
+ collection.addAccepts("application/json;type=entry");
+ List<Category> categories = feed.getCategories();
+ if ( categories != null ) {
+ collection.addCategories(categories, false, null);
+ } else
+ collection.addCategories().setFixed(false);
+
+ } else {
+ collection.setTitle("entries");
+ // collection.addAccepts("application/atom+xml;type=feed");
+ collection.addAccepts("application/atom+xml; type=entry");
+ collection.addAccepts("application/json;type=entry");
+ collection.addCategories().setFixed(false);
+ }
+ workspace.addCollection(collection);
+
+ service.addWorkspace(workspace);
+
+ //FIXME add prettyPrint support
+ try {
+ service.getDocument().writeTo(response.getOutputStream());
+ } catch (IOException ioe) {
+ throw new ServletException(ioe);
+ }
+
+ } else if (path == null || path.length() == 0 || path.equals("/")) {
+
+ // Return a feed containing the entries in the collection
+ Feed feed = getFeed( request );
+ if (feed != null) {
+ String feedETag = null;
+ if (feed.getId() != null)
+ feedETag = feed.getId().toString();
+ Date feedUpdated = feed.getUpdated();
+ // Test request for predicates.
+ String predicate = request.getHeader( "If-Match" );
+ if (( predicate != null ) && ( !predicate.equals(feedETag) )) {
+ // No match, should short circuit
+ response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
+ return;
+ }
+ predicate = request.getHeader( "If-None-Match" );
+ if (( predicate != null ) && ( predicate.equals(feedETag) )) {
+ // Match, should short circuit
+ response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
+ return;
+ }
+ if ( feedUpdated != null ) {
+ predicate = request.getHeader( "If-Unmodified-Since" );
+ if ( predicate != null ) {
+ try {
+ Date predicateDate = dateFormat.parse( predicate );
+ if ( predicateDate.compareTo( feedUpdated ) < 0 ) {
+ // Match, should short circuit
+ response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
+ return;
+ }
+ } catch ( java.text.ParseException e ) {
+ // Ignore and move on
+ }
+ }
+ predicate = request.getHeader( "If-Modified-Since" );
+ if ( predicate != null ) {
+ try {
+ Date predicateDate = dateFormat.parse( predicate );
+ if ( predicateDate.compareTo( feedUpdated ) > 0 ) {
+ // Match, should short circuit
+ response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
+ return;
+ }
+ } catch ( java.text.ParseException e ) {
+ // Ignore and move on
+ }
+ }
+ }
+ // Provide Etag based on Id and time if given.
+ // Ignore if not given. (Browser may cache if trivial ETag is given.)
+ if ( feedETag != null )
+ response.addHeader(ETAG, feedETag );
+ if ( feedUpdated != null )
+ response.addHeader(LASTMODIFIED, dateFormat.format( feedUpdated ));
+
+ // Content negotiation
+ String acceptType = request.getHeader( "Accept" );
+ String preferredType = getContentPreference( acceptType );
+ if (( preferredType != null ) && ((preferredType.indexOf( "json") > -1) || (preferredType.indexOf( "JSON") > -1 ))) {
+ // JSON response body
+ response.setContentType("application/json;type=feed");
+
+ try {
+ Abdera abdera = new Abdera();
+ WriterFactory wf = abdera.getWriterFactory();
+ org.apache.abdera.writer.Writer json = wf.getWriter("json");
+ feed.writeTo(json, response.getWriter());
+ } catch (Exception e) {
+ throw new ServletException(e);
+ }
+
+ } else {
+ // Write the Atom feed
+ response.setContentType("application/atom+xml;type=feed");
+ try {
+ feed.getDocument().writeTo(response.getOutputStream());
+ } catch (IOException ioe) {
+ throw new ServletException(ioe);
+ }
+ }
+ } else {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+
+ } else if (path.startsWith("/")) {
+ // Return a specific entry in the collection
+ org.apache.abdera.model.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
+ Entry<Object, Object> entry = new Entry<Object, Object>(id, responseMessage.getBody());
+ feedEntry = feedEntry(entry, itemClassType, itemXMLType, mediator, abderaFactory);
+ }
+ // Write the Atom entry
+ if (feedEntry != null) {
+ String entryETag = null;
+ if (feedEntry.getId() != null)
+ entryETag = feedEntry.getId().toString();
+ Date entryUpdated = feedEntry.getUpdated();
+ if ( entryUpdated != null )
+ response.addHeader(LASTMODIFIED, dateFormat.format( entryUpdated ));
+ // TODO Check If-Modified-Since If-Unmodified-Since predicates against LASTMODIFIED.
+ // If true return 304 and null body.
+
+ Link link = feedEntry.getSelfLink();
+ if (link != null) {
+ response.addHeader(LOCATION, link.getHref().toString());
+ } else {
+ link = feedEntry.getLink( "Edit" );
+ if (link != null) {
+ response.addHeader(LOCATION, link.getHref().toString());
+ }
+ }
+
+ // Test request for predicates.
+ String predicate = request.getHeader( "If-Match" );
+ if (( predicate != null ) && ( !predicate.equals(entryETag) )) {
+ // No match, should short circuit
+ response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
+ return;
+ }
+ predicate = request.getHeader( "If-None-Match" );
+ if (( predicate != null ) && ( predicate.equals(entryETag) )) {
+ // Match, should short circuit
+ response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
+ return;
+ }
+ if ( entryUpdated != null ) {
+ predicate = request.getHeader( "If-Unmodified-Since" );
+ if ( predicate != null ) {
+ try {
+ Date predicateDate = dateFormat.parse( predicate );
+ if ( predicateDate.compareTo( entryUpdated ) < 0 ) {
+ // Match, should short circuit
+ response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
+ return;
+ }
+ } catch ( java.text.ParseException e ) {
+ // Ignore and move on
+ }
+ }
+ predicate = request.getHeader( "If-Modified-Since" );
+ if ( predicate != null ) {
+ try {
+ Date predicateDate = dateFormat.parse( predicate );
+ if ( predicateDate.compareTo( entryUpdated ) > 0 ) {
+ // Match, should short circuit
+ response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
+ return;
+ }
+ } catch ( java.text.ParseException e ) {
+ // Ignore and move on
+ }
+ }
+ }
+ // Provide Etag based on Id and time if given.
+ // Ignore if not given. (Browser may cache if trivial ETag is given.)
+ if (entryETag != null)
+ response.addHeader(ETAG, entryETag );
+ if ( entryUpdated != null )
+ response.addHeader(LASTMODIFIED, dateFormat.format( entryUpdated ));
+
+ // Content negotiation
+ String acceptType = request.getHeader( "Accept" );
+ String preferredType = getContentPreference( acceptType );
+ if (( preferredType != null ) && ((preferredType.indexOf( "json") > -1) || (preferredType.indexOf( "JSON") > -1 ))) {
+ // JSON response body
+ response.setContentType("application/json;type=entry");
+ try {
+ Abdera abdera = new Abdera();
+ WriterFactory wf = abdera.getWriterFactory();
+ org.apache.abdera.writer.Writer json = wf.getWriter("json");
+ feedEntry.writeTo(json, response.getWriter());
+ } catch (Exception e) {
+ throw new ServletException(e);
+ }
+ } else {
+ // XML response body
+ response.setContentType("application/atom+xml;type=entry");
+ try {
+ feedEntry.writeTo(getWriter(response));
+ } catch (IOException ioe) {
+ throw new ServletException(ioe);
+ }
+ }
+ } else {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+ } else {
+ // Path doesn't match any known pattern
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+
+ }
+
+ protected Feed getFeed( HttpServletRequest request ) throws ServletException {
+ if (supportsFeedEntries) {
+ // The service implementation supports feed entries, invoke its getFeed operation
+ Message requestMessage = messageFactory.createMessage();
+ Message responseMessage;
+ if (request.getQueryString() != null) {
+ requestMessage.setBody(new Object[] {request.getQueryString()});
+ responseMessage = queryInvoker.invoke(requestMessage);
+ } else {
+ responseMessage = getFeedInvoker.invoke(requestMessage);
+ }
+ if (responseMessage.isFault()) {
+ throw new ServletException((Throwable)responseMessage.getBody());
+ }
+ return (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());
+ }
+ Entry<Object, Object>[] collection =
+ (Entry<Object, Object>[])responseMessage.getBody();
+ if (collection != null) {
+
+ // Create the feed
+ Feed feed = abderaFactory.newFeed();
+
+ // Set the feed title
+ if (title != null) {
+ feed.setTitle(title);
+ } else {
+ feed.setTitle("Feed");
+ }
+ // All feeds must provide Id and updated elements.
+ // However, some do not, so provide some program protection.
+ feed.setId( "Feed" + feed.hashCode());
+ Date responseLastModified = new Date( 0 );
+
+ // Add entries to the feed
+ for (Entry<Object, Object> entry: collection) {
+ org.apache.abdera.model.Entry feedEntry = feedEntry(entry, itemClassType, itemXMLType, mediator, abderaFactory);
+ // Use the most recent entry update as the feed update
+ Date entryUpdated = feedEntry.getUpdated();
+ if (( entryUpdated != null ) && (entryUpdated.compareTo( responseLastModified ) > 0 ))
+ responseLastModified = entryUpdated;
+ feed.addEntry(feedEntry);
+ }
+ // If no entries were newly updated,
+ if ( responseLastModified.compareTo( new Date( 0 ) ) == 0 )
+ responseLastModified = new Date();
+ return feed;
+ }
+ }
+ 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("/")) {
+ org.apache.abdera.model.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
+ org.apache.abdera.model.Entry feedEntry;
+ try {
+ Document<org.apache.abdera.model.Entry> doc = abderaParser.parse(request.getReader());
+ feedEntry = doc.getRoot();
+ } catch (ParseException pe) {
+ throw new ServletException(pe);
+ }
+
+ // 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();
+ Entry<Object, Object> entry = entry(feedEntry, itemClassType, itemXMLType, mediator);
+ 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 = feedEntry(entry, itemClassType, itemXMLType, mediator, abderaFactory);
+ }
+
+ } 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
+ IRI feedId = createdFeedEntry.getId();
+ if ( feedId != null )
+ response.addHeader(ETAG, "\"" + feedId.toString() + "\"" );
+ Date entryUpdated = createdFeedEntry.getUpdated();
+ if ( entryUpdated != null )
+ response.addHeader(LASTMODIFIED, dateFormat.format( entryUpdated ));
+ Link link = createdFeedEntry.getSelfLink();
+ if (link != null) {
+ response.addHeader(LOCATION, link.getHref().toString());
+ } else {
+ link = createdFeedEntry.getLink( "Edit" );
+ if (link != null) {
+ response.addHeader(LOCATION, link.getHref().toString());
+ }
+ }
+
+ // Write the created Atom entry
+ response.setStatus(HttpServletResponse.SC_CREATED);
+ response.setContentType("application/atom+xml;type=entry");
+ try {
+ createdFeedEntry.writeTo(getWriter(response));
+ } catch (ParseException pe) {
+ throw new ServletException(pe);
+ }
+
+ } 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 = request.getRequestURI().substring(request.getServletPath().length());
+
+ 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
+ org.apache.abdera.model.Entry feedEntry;
+ try {
+ Document<org.apache.abdera.model.Entry> doc = abderaParser.parse(request.getReader());
+ feedEntry = doc.getRoot();
+ } catch (ParseException pe) {
+ throw new ServletException(pe);
+ }
+
+ // 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();
+ Entry<Object, Object> entry = entry(feedEntry, itemClassType, itemXMLType, mediator);
+ 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 {
+
+ // FIXME temporarily disabling this as it doesn't work with all browsers
+ if (true)
+ return "admin";
+
+ 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
+ return ("admin".equals(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);
+ }
+
+ public static String getContentPreference( String acceptType ) {
+ if (( acceptType == null ) || ( acceptType.length() < 1 )) {
+ return "application/atom+xml";
+ }
+ StringTokenizer st = new StringTokenizer( acceptType, "," );
+ if ( st.hasMoreTokens() )
+ return st.nextToken();
+ return "application/atom+xml";
+ }
+
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingProviderFactory.java b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingProviderFactory.java
new file mode 100644
index 0000000000..2651324ccf
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/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.atom.provider;
+
+import org.apache.tuscany.sca.binding.atom.AtomBinding;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.FactoryExtensionPoint;
+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 a Binding provider factory for the Atom binding.
+ *
+ * @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);
+ FactoryExtensionPoint modelFactories = extensionPoints.getExtensionPoint(FactoryExtensionPoint.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, mediator);
+ }
+
+ 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/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingUtil.java b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingUtil.java
new file mode 100644
index 0000000000..62fde86122
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomBindingUtil.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.binding.atom.provider;
+
+import java.util.Date;
+
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Link;
+import org.apache.tuscany.sca.data.collection.Entry;
+import org.apache.tuscany.sca.data.collection.Item;
+import org.apache.tuscany.sca.databinding.Mediator;
+import org.apache.tuscany.sca.interfacedef.DataType;
+
+/**
+ * Utility methods used in this package.
+ *
+ * @version $Rev$ $Date$
+ */
+class AtomBindingUtil {
+
+ /**
+ * Create a data item from an Atom entry.
+ * @param feedEntry
+ * @param itemClassType
+ * @param itemXMLType
+ * @param mediator
+ * @return
+ */
+ static Entry<Object, Object> entry(org.apache.abdera.model.Entry feedEntry,
+ DataType<?> itemClassType, DataType<?> itemXMLType, Mediator mediator) {
+ if (feedEntry != null) {
+ if (itemClassType.getPhysical() == Item.class) {
+ String key = feedEntry.getId().toString();
+
+ Item item = new Item();
+ item.setTitle(feedEntry.getTitle());
+ item.setContents(feedEntry.getContent());
+
+ for (Link link : feedEntry.getLinks()) {
+ if (link.getRel() == null || "self".equals(link.getRel())) {
+ if (item.getLink() == null) {
+ item.setLink(link.getHref().toString());
+ }
+ } else if ("related".equals(link.getRel())) {
+ item.setRelated(link.getHref().toString());
+ } else if ("alternate".equals(link.getRel())) {
+ item.setAlternate(link.getHref().toString());
+ }
+ }
+
+ item.setDate(feedEntry.getUpdated());
+
+ return new Entry<Object, Object>(key, item);
+
+ } else {
+ String key = null;
+ if ( feedEntry.getId() != null) {
+ key = feedEntry.getId().toString();
+ }
+
+ // Create the item from XML
+ if (feedEntry.getContentElement().getElements().size() == 0) {
+ return null;
+ }
+
+ String value = feedEntry.getContent();
+ Object data = mediator.mediate(value, itemXMLType, itemClassType, null);
+
+ return new Entry<Object, Object>(key, data);
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Create an Atom entry for a key and item from a collection.
+ * @param entry
+ * @param itemClassType
+ * @param itemXMLType
+ * @param mediator
+ * @param factory
+ * @return
+ */
+ static org.apache.abdera.model.Entry feedEntry(Entry<Object, Object> entry,
+ DataType<?> itemClassType, DataType<?> itemXMLType, Mediator mediator,
+ Factory factory) {
+ Object key = entry.getKey();
+ Object data = entry.getData();
+ if (data instanceof Item) {
+ Item item = (Item)data;
+
+ org.apache.abdera.model.Entry feedEntry = factory.newEntry();
+ if (key != null) {
+ feedEntry.setId(key.toString());
+ }
+ feedEntry.setTitle(item.getTitle());
+ feedEntry.setContentAsHtml(item.getContents());
+
+ String href = item.getLink();
+ if (href == null && key != null) {
+ href = key.toString();
+ }
+
+ if (href != null) {
+ feedEntry.addLink(href);
+ }
+ String related = item.getRelated();
+ if (related != null) {
+ feedEntry.addLink(related, "related");
+ }
+ String alternate = item.getAlternate();
+ if (alternate != null) {
+ feedEntry.addLink(alternate, "alternate");
+ }
+
+ Date date = item.getDate();
+ if (date != null) {
+ feedEntry.setUpdated(date);
+ }
+ return feedEntry;
+
+ } else if (data != null) {
+ org.apache.abdera.model.Entry feedEntry = factory.newEntry();
+ feedEntry.setId(key.toString());
+ feedEntry.setTitle("item");
+
+
+ // Convert the item to XML
+ String value = mediator.mediate(data, itemClassType, itemXMLType, null).toString();
+
+ Content content = factory.newContent();
+ content.setContentType(Content.Type.XML);
+ content.setValue(value);
+
+ feedEntry.setContentElement(content);
+
+ feedEntry.addLink(key.toString());
+
+ return feedEntry;
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomReferenceBindingProvider.java b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomReferenceBindingProvider.java
new file mode 100644
index 0000000000..f2b1d1f72b
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomReferenceBindingProvider.java
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.binding.atom.provider;
+
+import java.net.URI;
+
+import javax.xml.namespace.QName;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpConnectionManager;
+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.atom.AtomBinding;
+import org.apache.tuscany.sca.databinding.Mediator;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+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.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;
+ private Mediator mediator;
+ private DataType<?> itemClassType;
+ private DataType<?> itemXMLType;
+ private boolean supportsFeedEntries;
+
+ /**
+ * Constructs a new AtomReferenceBindingProvider
+ * @param component
+ * @param reference
+ * @param binding
+ * @param mediator
+ */
+ AtomReferenceBindingProvider(RuntimeComponent component,
+ RuntimeComponentReference reference,
+ AtomBinding binding,
+ Mediator mediator) {
+ this.reference = reference;
+ this.binding = binding;
+ this.mediator = mediator;
+
+ // Prepare authorization header
+ String authorization = "admin" + ":" + "admin";
+ authorizationHeader = "Basic " + new String(Base64.encodeBase64(authorization.getBytes()));
+
+ // Create an HTTP client
+ HttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
+ connectionManager.getParams().setDefaultMaxConnectionsPerHost(10);
+ connectionManager.getParams().setConnectionTimeout(60000);
+ httpClient = new HttpClient(connectionManager);
+ }
+
+ public Invoker createInvoker(Operation operation) {
+
+ String operationName = operation.getName();
+ if (operationName.equals("get")) {
+
+ // Determine the collection item type
+ itemXMLType = new DataTypeImpl<Class<?>>(String.class.getName(), String.class, String.class);
+ Class<?> itemClass = operation.getOutputType().getPhysical();
+ DataType<XMLType> outputType = operation.getOutputType();
+ QName qname = outputType.getLogical().getElementName();
+ qname = new QName(qname.getNamespaceURI(), itemClass.getSimpleName());
+ itemClassType = new DataTypeImpl<XMLType>("java:complexType", itemClass, new XMLType(qname, null));
+ if (itemClassType.getPhysical() == org.apache.abdera.model.Entry.class) {
+ supportsFeedEntries = true;
+ }
+
+ return new AtomBindingInvoker.GetInvoker(operation, binding.getURI(), httpClient, authorizationHeader, this);
+
+ } else if (operationName.equals("post")) {
+ return new AtomBindingInvoker.PostInvoker(operation, binding.getURI(), httpClient, authorizationHeader, this);
+ } else if (operationName.equals("put")) {
+ return new AtomBindingInvoker.PutInvoker(operation, binding.getURI(), httpClient, authorizationHeader, this);
+ } else if (operationName.equals("delete")) {
+ return new AtomBindingInvoker.DeleteInvoker(operation, binding.getURI(), httpClient, authorizationHeader, this);
+ } else if (operationName.equals("getFeed") || operationName.equals("getAll")) {
+ return new AtomBindingInvoker.GetAllInvoker(operation, binding.getURI(), httpClient, authorizationHeader, this);
+ } else if (operationName.equals("postMedia")) {
+ return new AtomBindingInvoker.PostMediaInvoker(operation, binding.getURI(), httpClient, authorizationHeader, this);
+ } else if (operationName.equals("putMedia")) {
+ return new AtomBindingInvoker.PutMediaInvoker(operation, binding.getURI(), httpClient, authorizationHeader, this);
+ } else if (operationName.equals("query")) {
+ return new AtomBindingInvoker.QueryInvoker(operation, binding.getURI(), httpClient, authorizationHeader, this);
+ }
+
+ return new AtomBindingInvoker(operation, binding.getURI(), httpClient, authorizationHeader, this);
+ }
+
+ 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);
+
+ // Find the get operation on the reference interface
+ if (true) {
+ return;
+ }
+ }
+
+ public void stop() {
+
+ }
+
+ public boolean supportsOneWayInvocation() {
+ return false;
+ }
+
+ /**
+ * Returns the mediator.
+ * @return
+ */
+ Mediator getMediator() {
+ return mediator;
+ }
+
+ /**
+ * Returns the item class type.
+ * @return
+ */
+ DataType<?> getItemClassType() {
+ return itemClassType;
+ }
+
+ /**
+ * Returns the item XML type.
+ * @return
+ */
+ DataType<?> getItemXMLType() {
+ return itemXMLType;
+ }
+
+ /**
+ * Returns true if the invoker should work with Atom
+ * feed entries.
+ * @return
+ */
+ boolean supportsFeedEntries() {
+ return supportsFeedEntries;
+ }
+
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomServiceBindingProvider.java b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/provider/AtomServiceBindingProvider.java
new file mode 100644
index 0000000000..e1d470f5a3
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/main/java/org/apache/tuscany/sca/binding/atom/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.atom.provider;
+
+import org.apache.tuscany.sca.binding.atom.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);
+
+ AtomBindingListenerServlet servlet =
+ new AtomBindingListenerServlet(wire, messageFactory, mediator, binding.getTitle());
+
+ 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/modules/binding-atom-abdera/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory b/java/sca/modules/binding-atom-abdera/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory
new file mode 100644
index 0000000000..1b9052299c
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory
@@ -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 binding extension
+org.apache.tuscany.sca.binding.atom.provider.AtomBindingProviderFactory;model=org.apache.tuscany.sca.binding.atom.AtomBinding
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomDeleteTestCase.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomDeleteTestCase.java
new file mode 100644
index 0000000000..4e586a5510
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomDeleteTestCase.java
@@ -0,0 +1,109 @@
+package org.apache.tuscany.sca.binding.atom;
+
+import java.util.UUID;
+
+import junit.framework.Assert;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Entry;
+import org.apache.tuscany.sca.binding.atom.collection.Collection;
+import org.apache.tuscany.sca.node.Contribution;
+import org.apache.tuscany.sca.node.ContributionLocationHelper;
+import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.node.NodeFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class AtomDeleteTestCase {
+ protected static Node consumerNode;
+ protected static Node providerNode;
+ protected static CustomerClient testService;
+ protected static Abdera abdera;
+
+ @BeforeClass
+ public static void init() throws Exception {
+ try {
+ System.out.println(">>>AtomDeleteTestCase.init entry");
+ String contribution = ContributionLocationHelper.getContributionLocation(AtomDeleteTestCase.class);
+ providerNode =
+ NodeFactory.newInstance().createNode("org/apache/tuscany/sca/binding/atom/Provider.composite",
+ new Contribution("provider", contribution));
+ consumerNode =
+ NodeFactory.newInstance().createNode("org/apache/tuscany/sca/binding/atom/Consumer.composite",
+ new Contribution("consumer", contribution));
+ providerNode.start();
+ consumerNode.start();
+ testService = consumerNode.getService(CustomerClient.class, "CustomerClient");
+ abdera = new Abdera();
+ } catch (Exception e) {
+ e.printStackTrace();
+
+ }
+ }
+
+ @AfterClass
+ public static void destroy() throws Exception {
+ // System.out.println(">>>AtomDeleteTestCase.destroy entry");
+ consumerNode.stop();
+ consumerNode.destroy();
+ providerNode.stop();
+ providerNode.destroy();
+ }
+
+ @Test
+ public void testPrelim() throws Exception {
+ Assert.assertNotNull(providerNode);
+ Assert.assertNotNull(consumerNode);
+ Assert.assertNotNull(testService);
+ Assert.assertNotNull(abdera);
+ }
+
+ @Test
+ public void testAtomDelete() throws Exception {
+ Collection resourceCollection = testService.getCustomerCollection();
+ Assert.assertNotNull(resourceCollection);
+
+ Entry postEntry = postEntry("Sponge Bob");
+ System.out.println(">>> post entry= " + postEntry.getTitle());
+
+ Entry newEntry = resourceCollection.post(postEntry);
+ System.out.println("<<< Entry posted for " + newEntry.getTitle());
+
+ System.out.println(">>> get id=" + newEntry.getId());
+
+ resourceCollection.delete(newEntry.getId().toString());
+
+ }
+
+ @Test
+ public void testAtomDeleteException() throws Exception {
+ Collection resourceCollection = testService.getCustomerCollection();
+ Assert.assertNotNull(resourceCollection);
+
+ try {
+ // Generates custom ID
+ String id = "urn:uuid:customer-" + UUID.randomUUID().toString();
+ resourceCollection.delete(id);
+ } catch (Exception e) {
+ // ID doesn't match with the existing IDs and NotFoundException is
+ // thrown
+ Assert.assertEquals("NotFoundException", e.getClass().getSimpleName());
+ }
+
+ }
+
+ private Entry postEntry(String value) {
+ Entry entry = abdera.newEntry();
+ entry.setTitle("customer " + value);
+
+ Content content = abdera.getFactory().newContent();
+ content.setContentType(Content.Type.TEXT);
+ content.setValue(value);
+ entry.setContentElement(content);
+
+ return entry;
+ }
+
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomGetTestCase.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomGetTestCase.java
new file mode 100644
index 0000000000..eaa2bc4a97
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomGetTestCase.java
@@ -0,0 +1,107 @@
+package org.apache.tuscany.sca.binding.atom;
+
+import junit.framework.Assert;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Entry;
+import org.apache.tuscany.sca.binding.atom.collection.Collection;
+import org.apache.tuscany.sca.node.Contribution;
+import org.apache.tuscany.sca.node.ContributionLocationHelper;
+import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.node.NodeFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class AtomGetTestCase {
+ protected static Node consumerNode;
+ protected static Node providerNode;
+ protected static CustomerClient testService;
+ protected static Abdera abdera;
+
+ @BeforeClass
+ public static void init() throws Exception {
+ System.out.println(">>>AtomGetTestCase.init entry");
+ String contribution = ContributionLocationHelper.getContributionLocation(AtomDeleteTestCase.class);
+ providerNode = NodeFactory.newInstance().createNode(
+ "org/apache/tuscany/sca/binding/atom/Provider.composite", new Contribution("provider", contribution));
+ consumerNode = NodeFactory.newInstance().createNode(
+ "org/apache/tuscany/sca/binding/atom/Consumer.composite", new Contribution("consumer", contribution));
+ providerNode.start();
+ consumerNode.start();
+ testService = consumerNode.getService(CustomerClient.class, "CustomerClient");
+ abdera = new Abdera();
+ }
+
+ @AfterClass
+ public static void destroy() throws Exception {
+ // System.out.println(">>>AtomGetTestCase.destroy entry");
+ consumerNode.stop();
+ consumerNode.destroy();
+ providerNode.stop();
+ providerNode.destroy();
+ }
+
+ @Test
+ public void testPrelim() throws Exception {
+ Assert.assertNotNull(providerNode);
+ Assert.assertNotNull(consumerNode);
+ Assert.assertNotNull(testService);
+ Assert.assertNotNull(abdera);
+ }
+
+ @Test
+ public void testAtomGet() throws Exception {
+ Collection resourceCollection = testService.getCustomerCollection();
+ Assert.assertNotNull(resourceCollection);
+
+ Entry postEntry = postEntry("Sponge Bob");
+ System.out.println(">>> post entry= " + postEntry.getTitle());
+
+ Entry newEntry = resourceCollection.post(postEntry);
+ System.out.println("<<< Entry posted for " + newEntry.getTitle());
+
+ System.out.println(">>> get id=" + newEntry.getId());
+
+ Entry getEntry = resourceCollection.get(newEntry.getId().toString());
+
+ Assert.assertEquals(newEntry.getTitle(), getEntry.getTitle());
+ System.out.println("<<< get id=" + getEntry.getId() + " entry=" + getEntry.getTitle());
+ }
+
+ @Test
+ public void testAtomGetException() throws Exception {
+ Collection resourceCollection = testService.getCustomerCollection();
+ Assert.assertNotNull(resourceCollection);
+
+ Entry postEntry = postEntry("Sponge Bob");
+ System.out.println(">>> post entry= " + postEntry.getTitle());
+
+ Entry newEntry = resourceCollection.post(postEntry);
+ System.out.println("<<< Entry posted for " + newEntry.getTitle());
+ System.out.println(newEntry.getId());
+
+ // Delete the entry to force the Collection to throw NotFoundException
+ resourceCollection.delete(newEntry.getId().toString());
+
+ try {
+ resourceCollection.get(newEntry.getId().toString());
+ } catch (Exception e) {
+ Assert.assertEquals("NotFoundException", e.getClass().getSimpleName());
+ }
+ }
+
+ private Entry postEntry(String value) {
+ Entry entry = abdera.newEntry();
+ entry.setTitle("customer " + value);
+
+ Content content = abdera.getFactory().newContent();
+ content.setContentType(Content.Type.TEXT);
+ content.setValue(value);
+ entry.setContentElement(content);
+
+ return entry;
+ }
+
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomPostTestCase.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomPostTestCase.java
new file mode 100644
index 0000000000..ffe8a03f20
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomPostTestCase.java
@@ -0,0 +1,96 @@
+package org.apache.tuscany.sca.binding.atom;
+
+import junit.framework.Assert;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Entry;
+import org.apache.tuscany.sca.binding.atom.collection.Collection;
+import org.apache.tuscany.sca.node.Contribution;
+import org.apache.tuscany.sca.node.ContributionLocationHelper;
+import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.node.NodeFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class AtomPostTestCase {
+ protected static Node consumerNode;
+ protected static Node providerNode;
+ protected static CustomerClient testService;
+ protected static Abdera abdera;
+
+ @BeforeClass
+ public static void init() throws Exception {
+ System.out.println(">>>AtomPostTestCase.init entry");
+ String contribution = ContributionLocationHelper.getContributionLocation(AtomDeleteTestCase.class);
+ providerNode = NodeFactory.newInstance().createNode(
+ "org/apache/tuscany/sca/binding/atom/Provider.composite", new Contribution("provider", contribution));
+ consumerNode = NodeFactory.newInstance().createNode(
+ "org/apache/tuscany/sca/binding/atom/Consumer.composite", new Contribution("consumer", contribution));
+ providerNode.start();
+ consumerNode.start();
+ testService = consumerNode.getService(CustomerClient.class, "CustomerClient");
+ abdera = new Abdera();
+ }
+
+ @AfterClass
+ public static void destroy() throws Exception {
+ System.out.println(">>>AtomPostTestCase.destroy entry");
+ consumerNode.stop();
+ consumerNode.destroy();
+ providerNode.stop();
+ providerNode.destroy();
+ }
+
+ @Test
+ public void testPrelim() throws Exception {
+ Assert.assertNotNull(providerNode);
+ Assert.assertNotNull(consumerNode);
+ Assert.assertNotNull(testService);
+ Assert.assertNotNull(abdera);
+ }
+
+ @Test
+ public void testAtomPost() throws Exception {
+ Collection resourceCollection = testService.getCustomerCollection();
+ Assert.assertNotNull(resourceCollection);
+
+ Entry postEntry = postEntry("Sponge Bob");
+ System.out.println(">>> post entry= " + postEntry.getTitle());
+
+ Entry newEntry = resourceCollection.post(postEntry);
+
+ Assert.assertEquals(postEntry.getTitle(), newEntry.getTitle());
+
+ System.out.println("<<< new entry= " + newEntry.getTitle());
+
+ }
+
+ @Test
+ public void testAtomPostException() throws Exception {
+ Collection resourceCollection = testService.getCustomerCollection();
+ Assert.assertNotNull(resourceCollection);
+
+ Entry postEntry = postEntry("Exception_Test");
+
+ try {
+ resourceCollection.post(postEntry);
+ } catch (Exception e) {
+ Assert.assertEquals("HTTP status code: 500", e.getMessage());
+ }
+ }
+
+ private Entry postEntry(String value) {
+ Entry entry = abdera.newEntry();
+ entry.setTitle("customer " + value);
+
+ Content content = abdera.getFactory().newContent();
+ content.setContentType(Content.Type.TEXT);
+ content.setValue(value);
+ entry.setContentElement(content);
+
+ return entry;
+ }
+
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomPutTestCase.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomPutTestCase.java
new file mode 100644
index 0000000000..08c1ed7ac9
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomPutTestCase.java
@@ -0,0 +1,114 @@
+package org.apache.tuscany.sca.binding.atom;
+
+import java.util.UUID;
+
+import junit.framework.Assert;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Entry;
+import org.apache.tuscany.sca.binding.atom.collection.Collection;
+import org.apache.tuscany.sca.node.Contribution;
+import org.apache.tuscany.sca.node.ContributionLocationHelper;
+import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.node.NodeFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class AtomPutTestCase {
+ protected static Node consumerNode;
+ protected static Node providerNode;
+ protected static CustomerClient testService;
+ protected static Abdera abdera;
+
+ @BeforeClass
+ public static void init() throws Exception {
+ System.out.println(">>>AtomPutTestCase.init entry");
+ String contribution = ContributionLocationHelper.getContributionLocation(AtomDeleteTestCase.class);
+ providerNode = NodeFactory.newInstance().createNode(
+ "org/apache/tuscany/sca/binding/atom/Provider.composite", new Contribution("provider", contribution));
+ consumerNode = NodeFactory.newInstance().createNode(
+ "org/apache/tuscany/sca/binding/atom/Consumer.composite", new Contribution("consumer", contribution));
+ providerNode.start();
+ consumerNode.start();
+ testService = consumerNode.getService(CustomerClient.class, "CustomerClient");
+ abdera = new Abdera();
+ }
+
+ @AfterClass
+ public static void destroy() throws Exception {
+ // System.out.println(">>>AtomPutTestCase.destroy entry");
+ consumerNode.stop();
+ consumerNode.destroy();
+ providerNode.stop();
+ providerNode.destroy();
+ }
+
+ @Test
+ public void testPrelim() throws Exception {
+ Assert.assertNotNull(providerNode);
+ Assert.assertNotNull(consumerNode);
+ Assert.assertNotNull(testService);
+ Assert.assertNotNull(abdera);
+ }
+
+ @Test
+ public void testAtomPut() throws Exception {
+ Collection resourceCollection = testService.getCustomerCollection();
+ Assert.assertNotNull(resourceCollection);
+
+ Entry postEntry = postEntry("Sponge Bob");
+ System.out.println(">>> post entry= " + postEntry.getTitle());
+
+ Entry newEntry = resourceCollection.post(postEntry);
+ System.out.println("<<< Entry posted for " + newEntry.getTitle());
+ System.out.println(newEntry.getId());
+
+ System.out.println(">>> put id=" + newEntry.getId() + " entry=" + newEntry.getTitle());
+ resourceCollection.put(newEntry.getId().toString(), updateEntry(newEntry, "James Bond"));
+ System.out.println("<<< put id=" + newEntry.getId() + " entry=" + newEntry.getTitle());
+ }
+
+ @Test
+ public void testAtomPutException() throws Exception {
+ Collection resourceCollection = testService.getCustomerCollection();
+ Assert.assertNotNull(resourceCollection);
+
+ Entry postEntry = postEntry("Sponge Bob");
+ System.out.println(">>> post entry= " + postEntry.getTitle());
+
+ // Generate random ID to pass as parameter in PUT() --
+ String id = "urn:uuid:customer-" + UUID.randomUUID().toString();
+ try {
+ // ID doesn't match with the existing IDs and NotFoundException is thrown
+ resourceCollection.put(id, updateEntry(postEntry, "James Bond"));
+ } catch (Exception e) {
+ Assert.assertEquals("NotFoundException", e.getClass().getSimpleName());
+ }
+ }
+
+ private Entry postEntry(String value) {
+ Entry entry = abdera.newEntry();
+ entry.setTitle("customer " + value);
+
+ Content content = abdera.getFactory().newContent();
+ content.setContentType(Content.Type.TEXT);
+ content.setValue(value);
+ entry.setContentElement(content);
+
+ return entry;
+ }
+
+ private Entry updateEntry(Entry entry, String value) {
+ entry.setTitle("customer " + value);
+
+ Content content = abdera.getFactory().newContent();
+ content.setContentType(Content.Type.TEXT);
+ content.setValue(value);
+ entry.setContentElement(content);
+
+ return entry;
+ }
+
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomTestCaseUtils.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomTestCaseUtils.java
new file mode 100644
index 0000000000..6beed6881f
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/AtomTestCaseUtils.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.binding.atom;
+
+import java.io.IOException;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Base;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.protocol.client.ClientResponse;
+import org.apache.abdera.protocol.client.RequestOptions;
+import org.apache.abdera.writer.Writer;
+import org.apache.abdera.writer.WriterFactory;
+
+/**
+ * Utilities to help print and test various aspects of entity tag support.
+ */
+public class AtomTestCaseUtils {
+
+ public static void prettyPrint(Abdera abdera, Base doc) throws IOException {
+ WriterFactory factory = abdera.getWriterFactory();
+ Writer writer = factory.getWriter("prettyxml");
+ writer.writeTo(doc, System.out);
+ System.out.println();
+ }
+
+ public static void printRequestHeaders( String title, String indent, RequestOptions request ) {
+ System.out.println( title );
+ if ( request == null ) {
+ System.out.println( indent + " request is null");
+ return;
+ }
+ String [] headerNames = request.getHeaderNames();
+ for ( String headerName: headerNames) {
+ String header = request.getHeader(headerName);
+ System.out.println( indent + " header name,value=" + headerName + "," + header );
+ }
+ }
+
+ public static void printResponseHeaders( String title, String indent, ClientResponse response ) {
+ System.out.println( title );
+ if ( response == null ) {
+ System.out.println( indent + " response is null");
+ return;
+ }
+ String [] headerNames = response.getHeaderNames();
+ for ( String headerName: headerNames) {
+ String header = response.getHeader(headerName);
+ System.out.println( indent + " header name,value=" + headerName + "," + header );
+ }
+
+ }
+
+ public static Entry newEntry(String value) {
+ Abdera abdera = new Abdera();
+ Entry entry = abdera.newEntry();
+ entry.setTitle("customer " + value);
+
+ Content content = abdera.getFactory().newContent();
+ content.setContentType(Content.Type.TEXT);
+ content.setValue(value);
+ entry.setContentElement(content);
+
+ return entry;
+ }
+
+ public static Entry updateEntry(Entry entry, String value) {
+ Abdera abdera = new Abdera();
+ entry.setTitle("customer " + value);
+
+ Content content = abdera.getFactory().newContent();
+ content.setContentType(Content.Type.TEXT);
+ content.setValue(value);
+ entry.setContentElement(content);
+
+ return entry;
+ }
+
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/Consumer.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/Consumer.java
new file mode 100644
index 0000000000..5b4d995dc1
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/Consumer.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.binding.atom;
+
+import org.apache.tuscany.sca.node.Contribution;
+import org.apache.tuscany.sca.node.ContributionLocationHelper;
+import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.node.NodeFactory;
+
+public class Consumer {
+
+ public static void main(String[] args) throws Exception {
+
+ String contribution = ContributionLocationHelper.getContributionLocation(AtomDeleteTestCase.class);
+ Node node = NodeFactory.newInstance().createNode(
+ "org/apache/tuscany/sca/binding/atom/Consumer.composite", new Contribution("consumer", contribution));
+ node.start();
+
+ CustomerClient testService = node.getService(CustomerClient.class, "CustomerClient");
+ testService.testCustomerCollection();
+
+ node.stop();
+ node.destroy();
+ }
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ConsumerProviderAtomTestCase.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ConsumerProviderAtomTestCase.java
new file mode 100644
index 0000000000..383344f3cb
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ConsumerProviderAtomTestCase.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.binding.atom;
+
+import java.util.Date;
+
+import junit.framework.Assert;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.tuscany.sca.binding.atom.collection.Collection;
+import org.apache.tuscany.sca.node.Contribution;
+import org.apache.tuscany.sca.node.ContributionLocationHelper;
+import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.node.NodeFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Test case for the given package.
+ */
+public class ConsumerProviderAtomTestCase {
+
+ protected static Node consumerNode;
+ protected static Node providerNode;
+ protected static CustomerClient testService;
+ protected static Abdera abdera;
+
+ @BeforeClass
+ public static void init() throws Exception {
+ System.out.println(">>>AtomBindingIntegratedTestCase.init entry");
+ String contribution = ContributionLocationHelper.getContributionLocation(AtomDeleteTestCase.class);
+ providerNode = NodeFactory.newInstance().createNode(
+ "org/apache/tuscany/sca/binding/atom/Provider.composite", new Contribution("provider", contribution));
+ consumerNode = NodeFactory.newInstance().createNode(
+ "org/apache/tuscany/sca/binding/atom/Consumer.composite", new Contribution("consumer", contribution));
+ providerNode.start();
+ consumerNode.start();
+ testService = consumerNode.getService(CustomerClient.class, "CustomerClient");
+ abdera = new Abdera();
+ }
+
+ @AfterClass
+ public static void destroy() throws Exception {
+ System.out.println(">>>AtomBindingIntegratedTestCase.destroy entry");
+ consumerNode.stop();
+ consumerNode.destroy();
+ providerNode.stop();
+ providerNode.destroy();
+ }
+
+ @Test
+ public void testPrelim() throws Exception {
+ Assert.assertNotNull(providerNode);
+ Assert.assertNotNull(consumerNode);
+ Assert.assertNotNull(testService);
+ Assert.assertNotNull(abdera);
+ }
+
+ @Test
+ public void testEntry() throws Exception {
+ // System.out.println( getClass().getName() + ".testEntry entry" );
+ Entry entry = abdera.newEntry();
+ Assert.assertNotNull(entry);
+
+ String testTitle = "Sponge Bob";
+ entry.setTitle(testTitle);
+ Assert.assertEquals(testTitle, entry.getTitle());
+
+ String testContent = "This is the content";
+ entry.setContent(testContent);
+ Assert.assertEquals(testContent, entry.getContent());
+
+ Date now = new Date();
+ entry.setEdited(now);
+ Assert.assertEquals(now, entry.getEdited());
+
+ Date later = new Date();
+ entry.setPublished(later);
+ Assert.assertEquals(later, entry.getPublished());
+
+ String testSummary = "This is the summary";
+ entry.setSummary(testSummary);
+ Assert.assertEquals(testSummary, entry.getSummary());
+ }
+
+ @Test
+ public void testCustomerCollection() throws Exception {
+ System.out.println(getClass().getName() + ".testCustomerCollection entry");
+ Collection resourceCollection = testService.getCustomerCollection();
+ Assert.assertNotNull(resourceCollection);
+
+ 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().toString());
+ System.out.println("<<< get id=" + entry.getId() + " entry=" + entry.getTitle());
+
+ System.out.println(">>> put id=" + newEntry.getId() + " entry=" + entry.getTitle());
+ resourceCollection.put(entry.getId().toString(), 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().toString());
+ 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 = abdera.newEntry();
+ entry.setTitle("customer " + value);
+
+ Content content = abdera.getFactory().newContent();
+ content.setContentType(Content.Type.TEXT);
+ content.setValue(value);
+ entry.setContentElement(content);
+
+ return entry;
+ }
+
+ private Entry updateEntry(Entry entry, String value) {
+ entry.setTitle("customer " + value);
+
+ Content content = abdera.getFactory().newContent();
+ content.setContentType(Content.Type.TEXT);
+ content.setValue(value);
+ entry.setContentElement(content);
+
+ return entry;
+ }
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ContentNegotiationTest.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ContentNegotiationTest.java
new file mode 100644
index 0000000000..7ec9c1480e
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ContentNegotiationTest.java
@@ -0,0 +1,265 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.binding.atom;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Date;
+
+import junit.framework.Assert;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.i18n.iri.IRI;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Document;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.abdera.parser.Parser;
+import org.apache.abdera.protocol.Response.ResponseType;
+import org.apache.abdera.protocol.client.AbderaClient;
+import org.apache.abdera.protocol.client.ClientResponse;
+import org.apache.abdera.protocol.client.RequestOptions;
+import org.apache.tuscany.sca.node.Contribution;
+import org.apache.tuscany.sca.node.ContributionLocationHelper;
+import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.node.NodeFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Tests use of content negotiation for Atom binding in Tuscany. Uses the SCA
+ * provided Provider composite to act as a server. Uses the Abdera provided
+ * Client to act as a client.
+ */
+public class ContentNegotiationTest {
+ public final static String providerURI = "http://localhost:8084/customer";
+ protected static Node providerNode;
+ protected static Abdera abdera;
+ protected static AbderaClient client;
+ protected static Parser abderaParser;
+ protected static String lastId;
+
+ @BeforeClass
+ public static void init() throws Exception {
+ System.out.println(">>>ContentNegotiationTest.init");
+ String contribution = ContributionLocationHelper.getContributionLocation(AtomDeleteTestCase.class);
+ providerNode = NodeFactory.newInstance().createNode(
+ "org/apache/tuscany/sca/binding/atom/Provider.composite", new Contribution("provider", contribution));
+ providerNode.start();
+ abdera = new Abdera();
+ client = new AbderaClient(abdera);
+ abderaParser = Abdera.getNewParser();
+ }
+
+ @AfterClass
+ public static void destroy() throws Exception {
+ System.out.println(">>>ContentNegotiationTest.destroy");
+ providerNode.stop();
+ providerNode.destroy();
+ }
+
+ @Test
+ public void testPrelim() throws Exception {
+ Assert.assertNotNull(providerNode);
+ Assert.assertNotNull(client);
+ }
+
+ @Test
+ public void testPost() throws Exception {
+ System.out.println(">>>ContentNegotiationTest.testPost");
+ // Testing of entry creation
+ Factory factory = abdera.getFactory();
+ String customerName = "Fred Farkle";
+ Entry entry = factory.newEntry();
+ entry.setTitle("customer " + customerName);
+ entry.setUpdated(new Date());
+ entry.addAuthor("Apache Tuscany");
+ // ID created by collection.
+ Content content = abdera.getFactory().newContent();
+ content.setContentType(Content.Type.TEXT);
+ content.setValue(customerName);
+ entry.setContentElement(content);
+
+ RequestOptions opts = new RequestOptions();
+ final String contentType = "application/atom+xml; type=entry";
+ opts.setContentType(contentType);
+ // AtomTestCaseUtils.printRequestHeaders( "Post request headers", " ",
+ // opts );
+ IRI colUri = new IRI(providerURI).resolve("customer");
+ // res = client.post(colUri.toString() + "?test=foo", entry, opts);
+ ClientResponse res = client.post(colUri.toString(), entry, opts);
+
+ // Assert response status code is 201-OK.
+ // Assert response header Content-Type: application/atom+xml;
+ // charset=UTF-8
+ Assert.assertEquals(201, res.getStatus());
+ String returnedContentType = res.getContentType().toString().trim();
+ Assert.assertEquals(contentType, returnedContentType);
+
+ String eTag = res.getHeader("ETag");
+ if (eTag != null)
+ lastId = eTag.substring(1, eTag.length() - 1);
+
+ // AtomTestCaseUtils.printResponseHeaders(
+ // "Entry post response headers:", " ", res );
+ // System.out.println("Entry post response content:");
+ // AtomTestCaseUtils.prettyPrint(abdera, res.getDocument());
+ }
+
+ @Test
+ public void testXMLEntryGet() throws Exception {
+ System.out.println(">>>ContentNegotiationTest.testXMLEntryGet");
+ RequestOptions opts = new RequestOptions();
+ opts.setHeader("Accept", "application/atom+xml");
+
+ IRI colUri = new IRI(providerURI).resolve("customer");
+ ClientResponse res = client.get(colUri.toString() + "/" + lastId, opts);
+ Assert.assertEquals(200, res.getStatus());
+ String returnedContentType = res.getContentType().toString().trim();
+ // Assert.assertEquals(contentType, returnedContentType );
+ res.release();
+ }
+
+ @Test
+ public void testJSONEntryGet() throws Exception {
+ System.out.println(">>>ContentNegotiationTest.testJSONEntryGet");
+ RequestOptions opts = new RequestOptions();
+ opts.setHeader("Accept", "application/json");
+
+ IRI colUri = new IRI(providerURI).resolve("customer");
+ ClientResponse res = client.get(colUri.toString() + "/" + lastId, opts);
+ try {
+ Assert.assertEquals(200, res.getStatus());
+ // Abdera 0.4 throws exception on getContentType with
+ // application/json.
+ // System.out.println(
+ // "ContentNegotiationTest.testJSONEntryGet contentType=" +
+ // res.getContentType());
+ String contentType = res.getHeader("Content-Type");
+ Assert.assertTrue(-1 < contentType.indexOf("application/json"));
+ // Following is a poor man's JSONObject test to avoid dependency on
+ // JSON libs.
+ // JSONObject jsonResp = new JSONObject(res.);
+ // Assert.assertEquals(12345, jsonResp.getInt("result"));
+ String responseBody = readResponse(res.getReader());
+ Assert.assertTrue(responseBody.startsWith("{"));
+ Assert.assertTrue(responseBody.endsWith("}"));
+ Assert.assertTrue(-1 < responseBody.indexOf("\"id\""));
+ Assert.assertTrue(-1 < responseBody.indexOf("\"title\""));
+ Assert.assertTrue(-1 < responseBody.indexOf("\"updated\""));
+ // AtomTestCaseUtils.printResponseHeaders(
+ // "JSON Entry response headers:", " ", res );
+ // System.out.println(
+ // "ContentNegotiationTest.testJSONEntryGet JSON entry body=" +
+ // responseBody );
+ } finally {
+ res.release();
+ }
+ }
+
+ @Test
+ public void testXMLFeedGet() throws Exception {
+ System.out.println(">>>ContentNegotiationTest.testXMLFeedGet");
+ RequestOptions opts = new RequestOptions();
+ opts.setHeader("Accept", "application/atom+xml");
+
+ // Atom feed request
+ ClientResponse res = client.get(providerURI, opts);
+ Assert.assertNotNull(res);
+ try {
+ // Asser feed provided since no predicates
+ Assert.assertEquals(200, res.getStatus());
+ Assert.assertEquals(ResponseType.SUCCESS, res.getType());
+ // AtomTestCaseUtils.printResponseHeaders( "Feed response headers:",
+ // " ", res );
+ // System.out.println("Feed response content:");
+ // AtomTestCaseUtils.prettyPrint(abdera, res.getDocument());
+
+ // Perform other tests on feed.
+ Document<Feed> doc = res.getDocument();
+ Assert.assertNotNull(doc);
+ Feed feed = doc.getRoot();
+ Assert.assertNotNull(feed);
+ // RFC 4287 requires non-null id, title, updated elements
+ Assert.assertNotNull(feed.getId());
+ Assert.assertNotNull(feed.getTitle());
+ Assert.assertNotNull(feed.getUpdated());
+ // AtomTestCaseUtils.printFeed( "Feed values", " ", feed );
+ } finally {
+ res.release();
+ }
+ }
+
+ @Test
+ public void testJSONFeedGet() throws Exception {
+ System.out.println(">>>ContentNegotiationTest.testJSONFeedGet");
+ RequestOptions opts = new RequestOptions();
+ opts.setHeader("Accept", "application/json");
+
+ // JSON feed request
+ ClientResponse res = client.get(providerURI, opts);
+ Assert.assertNotNull(res);
+ try {
+ // Assert feed provided since no predicates
+ Assert.assertEquals(200, res.getStatus());
+ // Abdera 0.4 throws exception on getContentType with
+ // application/json.
+ // System.out.println(
+ // "ContentNegotiationTest.testJSONEntryGet contentType=" +
+ // res.getContentType());
+ String contentType = res.getHeader("Content-Type");
+ Assert.assertTrue(-1 < contentType.indexOf("application/json"));
+ // Following is a poor man's JSONObject test to avoid dependency on
+ // JSON libs.
+ // JSONObject jsonResp = new JSONObject(res.);
+ // Assert.assertEquals(12345, jsonResp.getInt("result"));
+ String responseBody = readResponse(res.getReader());
+ Assert.assertTrue(responseBody.startsWith("{"));
+ Assert.assertTrue(responseBody.endsWith("}"));
+ Assert.assertTrue(-1 < responseBody.indexOf("\"id\""));
+ Assert.assertTrue(-1 < responseBody.indexOf("\"title\""));
+ Assert.assertTrue(-1 < responseBody.indexOf("\"updated\""));
+ Assert.assertTrue(-1 < responseBody.indexOf("\"entries\""));
+ // AtomTestCaseUtils.printResponseHeaders(
+ // "JSON Entry response headers:", " ", res );
+ // System.out.println(
+ // "ContentNegotiationTest.testJSONEntryGet JSON entry body=" +
+ // responseBody );
+ } finally {
+ res.release();
+ }
+ }
+
+ protected String readResponse(Reader responseReader) {
+ if (responseReader == null)
+ return "";
+ StringBuffer sb = new StringBuffer(1024);
+ try {
+ int charValue = 0;
+ while ((charValue = responseReader.read()) != -1) {
+ // result = result + (char) charValue;
+ sb.append((char)charValue);
+ }
+ } catch (IOException e) {
+ }
+ return sb.toString();
+ }
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/CustomerClient.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/CustomerClient.java
new file mode 100644
index 0000000000..bc32b91367
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/CustomerClient.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.binding.atom;
+
+import org.apache.tuscany.sca.binding.atom.collection.Collection;
+
+public interface CustomerClient {
+
+ void testCustomerCollection() throws Exception;
+
+ Collection getCustomerCollection();
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/CustomerClientImpl.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/CustomerClientImpl.java
new file mode 100644
index 0000000000..3e5705b14c
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/CustomerClientImpl.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.binding.atom;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.tuscany.sca.binding.atom.collection.Collection;
+import org.osoa.sca.annotations.Reference;
+
+public class CustomerClientImpl implements CustomerClient {
+
+ protected final Abdera abdera = new Abdera();
+
+ @Reference
+ public Collection customerCollection;
+
+ public void testCustomerCollection() throws Exception {
+
+ Entry newEntry = newEntry("Sponge Bob");
+ System.out.println(">>> post entry=" + newEntry.getTitle());
+ newEntry = customerCollection.post(newEntry);
+ System.out.println("<<< post id=" + newEntry.getId() + " entry=" + newEntry.getTitle());
+
+ newEntry = newEntry("Jane Bond");
+ System.out.println(">>> post entry=" + newEntry.getTitle());
+ newEntry = customerCollection.post(newEntry);
+ System.out.println("<<< post id=" + newEntry.getId() + " entry=" + newEntry.getTitle());
+
+ System.out.println(">>> get id=" + newEntry.getId());
+ Entry entry = customerCollection.get(newEntry.getId().toString());
+ System.out.println("<<< get id=" + entry.getId() + " entry=" + entry.getTitle());
+
+ System.out.println(">>> put id=" + newEntry.getId() + " entry=" + entry.getTitle());
+ customerCollection.put(entry.getId().toString(), updateEntry(entry, "James Bond"));
+ System.out.println("<<< put id=" + entry.getId() + " entry=" + entry.getTitle());
+
+ System.out.println(">>> delete id=" + entry.getId());
+ customerCollection.delete(entry.getId().toString());
+ System.out.println("<<< delete id=" + entry.getId());
+
+ System.out.println(">>> get collection");
+ Feed feed = customerCollection.getFeed();
+ System.out.println("<<< get collection");
+ for (Object o : feed.getEntries()) {
+ Entry e = (Entry)o;
+ System.out.println("id = " + e.getId() + " entry = " + e.getTitle());
+ }
+ }
+
+ public Collection getCustomerCollection() {
+ return customerCollection;
+ }
+
+ private Entry newEntry(String value) {
+
+ Entry entry = this.abdera.newEntry();
+ entry.setTitle("customer " + value);
+
+ Content content = this.abdera.getFactory().newContent();
+ content.setContentType(Content.Type.TEXT);
+ content.setValue(value);
+
+ entry.setContentElement(content);
+
+ return entry;
+ }
+
+ private Entry updateEntry(Entry entry, String value) {
+
+ entry.setTitle("customer " + value);
+
+ Content content = this.abdera.getFactory().newContent();
+ content.setContentType(Content.Type.TEXT);
+ content.setValue(value);
+
+ entry.setContentElement(content);
+
+ return entry;
+ }
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/CustomerCollectionImpl.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/CustomerCollectionImpl.java
new file mode 100644
index 0000000000..db66b00a50
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/CustomerCollectionImpl.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.binding.atom;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.tuscany.sca.binding.atom.collection.Collection;
+import org.apache.tuscany.sca.binding.atom.collection.NotFoundException;
+import org.osoa.sca.annotations.Scope;
+
+@Scope("COMPOSITE")
+public class CustomerCollectionImpl implements Collection {
+ private final Abdera abdera = new Abdera();
+ private Map<String, Entry> entries = new HashMap<String, Entry>();
+ public Date lastModified = new Date();
+
+ /**
+ * Default constructor
+ */
+ public CustomerCollectionImpl() {
+
+ }
+
+ public Entry post(Entry entry) {
+ System.out.println(">>> CustomerCollectionImpl.post entry=" + entry.getTitle());
+
+ if(!("Exception_Test".equalsIgnoreCase(entry.getTitle())))
+ {
+ String id = "urn:uuid:customer-" + UUID.randomUUID().toString();
+ entry.setId(id);
+
+ entry.addLink("" + id, "edit");
+ entry.addLink("" + id, "alternate");
+ Date now = new Date();
+ entry.setUpdated(now);
+ lastModified = now;
+ entries.put(id, entry);
+
+ System.out.println(">>> CustomerCollectionImpl.post return id=" + id);
+
+ return entry;
+
+ }
+ else
+ {
+ throw new IllegalArgumentException("Exception in Post method");
+ }
+ }
+
+ public Entry get(String id) {
+ System.out.println(">>> CustomerCollectionImpl.get id=" + id);
+ return entries.get(id);
+ }
+
+ public void put(String id, Entry entry) throws NotFoundException {
+ System.out.println(">>> CustomerCollectionImpl.put id=" + id + " entry=" + entry.getTitle());
+ if(entries.containsKey(id)){
+ Date now = new Date();
+ entry.setUpdated(now);
+ lastModified = now;
+ entries.put(id, entry);
+ }
+ else {
+ throw new NotFoundException();
+ }
+ }
+
+ public void delete(String id) throws NotFoundException {
+ System.out.println(">>> CustomerCollectionImpl.delete id=" + id);
+ if(entries.containsKey(id)){
+ entries.remove(id);
+ lastModified = new Date();
+ }
+ else {
+ throw new NotFoundException();
+ }
+ }
+
+ public Feed getFeed() {
+ System.out.println(">>> CustomerCollectionImpl.getFeed");
+
+ Feed feed = this.abdera.getFactory().newFeed();
+ feed.setId("customers" + this.hashCode() ); // provide unique id for feed instance.
+ feed.setTitle("customers");
+ feed.setSubtitle("This is a sample feed");
+ feed.setUpdated(lastModified);
+ feed.addLink("");
+ feed.addLink("", "self");
+
+ for (Entry entry : entries.values()) {
+ feed.addEntry(entry);
+ }
+
+ return feed;
+ }
+
+ public Feed query(String queryString) {
+ System.out.println(">>> CustomerCollectionImpl.query collection " + queryString);
+ return getFeed();
+ }
+
+ // This method used for testing.
+ protected void testPut(String value) {
+ String id = "urn:uuid:customer-" + UUID.randomUUID().toString();
+
+ Entry entry = abdera.getFactory().newEntry();
+ entry.setId(id);
+ entry.setTitle("customer " + value);
+
+ Content content = this.abdera.getFactory().newContent();
+ content.setContentType(Content.Type.TEXT);
+ content.setValue(value);
+
+ entry.setContentElement(content);
+
+ entry.addLink("" + id, "edit");
+ entry.addLink("" + id, "alternate");
+
+ entry.setUpdated(new Date());
+
+ entries.put(id, entry);
+ System.out.println(">>> id=" + id);
+ }
+
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/Provider.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/Provider.java
new file mode 100644
index 0000000000..a881f2dd0a
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/Provider.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.binding.atom;
+
+import java.io.IOException;
+
+import org.apache.tuscany.sca.node.Contribution;
+import org.apache.tuscany.sca.node.ContributionLocationHelper;
+import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.node.NodeFactory;
+
+public class Provider {
+
+ public static void main(String[] args) {
+
+ String contribution = ContributionLocationHelper.getContributionLocation(AtomDeleteTestCase.class);
+ Node node = NodeFactory.newInstance().createNode(
+ "org/apache/tuscany/sca/binding/atom/Provider.composite", new Contribution("provider", contribution));
+ node.start();
+ System.out.println("Provider.composite ready...");
+
+ try {
+ System.in.read();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ node.stop();
+ node.destroy();
+ }
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderEntryEntityTagsTest.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderEntryEntityTagsTest.java
new file mode 100644
index 0000000000..bda697bcca
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderEntryEntityTagsTest.java
@@ -0,0 +1,477 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.binding.atom;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import junit.framework.Assert;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.i18n.iri.IRI;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.parser.Parser;
+import org.apache.abdera.protocol.client.AbderaClient;
+import org.apache.abdera.protocol.client.ClientResponse;
+import org.apache.abdera.protocol.client.RequestOptions;
+import org.apache.abdera.protocol.client.util.BaseRequestEntity;
+import org.apache.tuscany.sca.node.Contribution;
+import org.apache.tuscany.sca.node.ContributionLocationHelper;
+import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.node.NodeFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Tests use of server provided entry entity tags for Atom binding in Tuscany.
+ * Tests conditional gets (e.g. get if-none-match) or conditional posts (post
+ * if-match) using entity tags or last modified header entries. Uses the SCA
+ * provided Provider composite to act as a server. Uses the Abdera provided
+ * Client to act as a client.
+ */
+public class ProviderEntryEntityTagsTest {
+ public final static String providerURI = "http://localhost:8084/customer";
+ protected static Node providerNode;
+ protected static Abdera abdera;
+ protected static AbderaClient client;
+ protected static Parser abderaParser;
+ protected static String eTag;
+ protected static Date lastModified;
+ protected static final SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z"); // RFC
+ // 822
+ // date
+ // time
+
+ @BeforeClass
+ public static void init() throws Exception {
+ System.out.println(">>>ProviderEntryEntityTagsTest.init");
+ String contribution = ContributionLocationHelper.getContributionLocation(AtomDeleteTestCase.class);
+ providerNode = NodeFactory.newInstance().createNode(
+ "org/apache/tuscany/sca/binding/atom/Provider.composite", new Contribution("provider", contribution));
+ providerNode.start();
+ abdera = new Abdera();
+ client = new AbderaClient(abdera);
+ abderaParser = Abdera.getNewParser();
+ }
+
+ @AfterClass
+ public static void destroy() throws Exception {
+ System.out.println(">>>ProviderEntryEntityTagsTest.destroy");
+ providerNode.stop();
+ providerNode.destroy();
+ }
+
+ @Test
+ public void testPrelim() throws Exception {
+ Assert.assertNotNull(providerNode);
+ Assert.assertNotNull(client);
+ }
+
+ @Test
+ public void testEmptyCachePost() throws Exception {
+ // Pseudo-code
+ // 1) Example HTTP POST request (new entry put, new etag response)
+ // User client post request
+ // POST /myblog/entries HTTP/1.1
+ // Slug: First Post
+ //
+ // <?xml version="1.0" ?>
+ // <entry xmlns="http://www.w3.org/2005/Atom">
+ // <title>Atom-Powered Robots Run Amok</title>
+ // <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
+ // <updated>2007-02-123T17:09:02Z</updated>
+ // <author><name>Captain Lansing</name></author>
+ // <content>It's something moving... solid metal</content>
+ // </entry>
+
+ // Expected Atom server response (note unique ETag)
+ // HTTP/1.1 201 Created
+ // Date: Fri, 23 Feb 2007 21:17:11 GMT
+ // Content-Length: nnn
+ // Content-Type: application/atom+xml;type=entry
+ // Location: http://example.org/edit/first-post.atom
+ // Content-Location: http://example.org/edit/first-post.atom
+ // ETag: "e180ee84f0671b1"
+ // Last-Modified: Fri, 25 Jul 2008 14:36:44 -0500
+ //
+ // <?xml version="1.0" ?>
+ // <entry xmlns="http://www.w3.org/2005/Atom">
+ // <title>Atom-Powered Robots Run Amok</title>
+ // <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
+ // <updated>2007-02-123T17:09:02Z</updated>
+ // <author><name>Captain Lansing</name></author>
+ // <content>It's something moving... solid metal</content>
+ // </entry>
+
+ // Testing of entry creation
+ Factory factory = abdera.getFactory();
+ String customerName = "Fred Farkle";
+ Entry entry = factory.newEntry();
+ entry.setTitle("customer " + customerName);
+ entry.setUpdated(new Date());
+ entry.addAuthor("Apache Tuscany");
+ // ID created by collection.
+ // entry.setId(id); // auto-provided
+ // entry.addLink("" + id, "edit"); // auto-provided
+ // entry.addLink("" + id, "alternate"); // auto-provided
+ Content content = abdera.getFactory().newContent();
+ content.setContentType(Content.Type.TEXT);
+ content.setValue(customerName);
+ entry.setContentElement(content);
+
+ RequestOptions opts = new RequestOptions();
+ final String contentType = "application/atom+xml; type=entry";
+ opts.setContentType(contentType);
+ // AtomTestCaseUtils.printRequestHeaders( "Post request headers", " ",
+ // opts );
+ IRI colUri = new IRI(providerURI).resolve("customer");
+ // res = client.post(colUri.toString() + "?test=foo", entry, opts);
+ ClientResponse res = client.post(colUri.toString(), entry, opts);
+
+ // Assert response status code is 201-OK.
+ // Assert response header Content-Type: application/atom+xml;
+ // charset=UTF-8
+ // Assert response header Location:
+ // http://example.org/edit/first-post.atom
+ // Assert response header Content-Location:
+ // http://example.org/edit/first-post.atom
+ // Assert response header ETag: "e180ee84f0671b1"
+ // Assert response header Last-Modified: Fri, 25 Jul 2008 14:36:44 -0500
+ // Assert collection size is 1.
+ Assert.assertEquals(201, res.getStatus());
+ Assert.assertEquals(contentType, res.getContentType().toString().trim());
+ // Assert.assertNotNull( res.getLocation().toString() );
+ // Assert.assertEquals( "", res.getContentLocation().toString() );
+ // Save eTag for subsequent tests;
+ eTag = res.getHeader("ETag");
+ Assert.assertNotNull(eTag);
+ lastModified = res.getLastModified();
+ Assert.assertNotNull(lastModified);
+ }
+
+ @Test
+ public void testDirtyCachePut() throws Exception {
+ // 2) Conditional PUT request (post with etag. entry provided is stale)
+ // User client PUT request
+ // PUT /edit/first-post.atom HTTP/1.1
+ // > If-Match: "e180ee84f0671b1"
+ //
+ // <?xml version="1.0" ?>
+ // <entry xmlns="http://www.w3.org/2005/Atom">
+ // <title>Atom-Powered Robots Run Amok</title>
+ // <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
+ // <updated>2007-02-24T16:34:06Z</updated>
+ // <author><name>Captain Lansing</name></author>
+ // <content>Update: it's a hoax!</content>
+ // </entry>
+ // Testing of entry creation
+ Factory factory = abdera.getFactory();
+ String customerName = "Molly Ringwald";
+ Entry entry = factory.newEntry();
+ entry.setTitle("customer " + customerName);
+ entry.setUpdated(new Date());
+ entry.addAuthor("Apache Tuscany");
+ String id = eTag.substring(1, eTag.length() - 1);
+ entry.setId(id); // auto-provided
+ // entry.addLink("" + id, "edit"); // auto-provided
+ // entry.addLink("" + id, "alternate"); // auto-provided
+ Content content = abdera.getFactory().newContent();
+ content.setContentType(Content.Type.TEXT);
+ content.setValue(customerName);
+ entry.setContentElement(content);
+
+ RequestOptions opts = new RequestOptions();
+ final String contentType = "application/atom+xml; type=entry";
+ opts.setContentType(contentType);
+ opts.setHeader("If-None-Match", eTag);
+
+ AtomTestCaseUtils.printRequestHeaders("Put request headers", " ", opts);
+ IRI colUri = new IRI(providerURI).resolve("customer");
+ // res = client.post(colUri.toString() + "?test=foo", entry, opts);
+ id = eTag.substring(1, eTag.length() - 1);
+ // Warning. AbderaClient.put(String uri,Base base,RequestOptions
+ // options) caches on the client side.
+ // ClientResponse res = client.put(colUri.toString() + id, entry, opts);
+ ClientResponse res = client.put(colUri.toString() + "/" + id, new BaseRequestEntity(entry), opts);
+ // Expected Atom server response (item was edited by another user)
+ // > HTTP/1.1 412 Precondition Failed
+ // Date: Sat, 24 Feb 2007 16:34:11 GMT
+
+ // If-Match Assert response status code is 412. Precondition failed.
+ // If-None-Match Assert response status code is 200. OK
+ Assert.assertEquals(200, res.getStatus());
+ // Put provides null body and no etags.
+ res.release();
+ }
+
+ @Test
+ public void testETagMissGet() throws Exception {
+ // 4) Conditional GET example (get with etag. etag not in cache)
+ // User client GET request
+ // GET /edit/first-post.atom HTTP/1.1
+ // > If-None-Match: "e180ee84f0671b1"
+
+ RequestOptions opts = new RequestOptions();
+ final String contentType = "application/atom+xml; type=entry";
+ opts.setContentType(contentType);
+ opts.setHeader("If-None-Match", "123456");
+ opts.setHeader("Pragma", "no-cache"); // turn off client caching
+
+ IRI colUri = new IRI(providerURI).resolve("customer");
+ // res = client.post(colUri.toString() + "?test=foo", entry, opts);
+ String id = eTag.substring(1, eTag.length() - 1);
+ // Warning. AbderaClient.put(String uri,Base base,RequestOptions
+ // options) caches on the client side.
+ // ClientResponse res = client.put(colUri.toString() + id, entry, opts);
+ ClientResponse res = client.get(colUri.toString() + "/" + id, opts);
+ // Expected Atom server response (item was edited by another user)
+ // > HTTP/1.1 412 Precondition Failed
+ // Date: Sat, 24 Feb 2007 16:34:11 GMT
+
+ // Atom server response (item was up to date)
+ // > HTTP/1.1 200 OK
+ // Date: Sat, 24 Feb 2007 13:17:11 GMT
+ // > ETag: "bb4f5e86e92ddb8549604a0df0763581"
+ // > Last-Modified: Mon, 28 Jul 2008 10:25:37 -0500
+
+ // Assert response status code is 200 OK.
+ // Assert header Content-Type: application/atom+xml;type=entry
+ // Assert header Location: http://example.org/edit/first-post.atom
+ // Assert header Content-Location:
+ // http://example.org/edit/first-post.atom
+ // Assert header ETag: "555555" (etag response != etag request)
+ // Assert header Last-Modified: Fri, 25 Jul 2008 14:36:44 -0500
+ Assert.assertEquals(200, res.getStatus());
+ Assert.assertEquals(contentType, res.getContentType().toString().trim());
+ // Assert.assertNotNull( res.getLocation().toString() );
+ // Assert.assertEquals( "", res.getContentLocation().toString() );
+ Assert.assertNotNull(res.getHeader("ETag"));
+ lastModified = res.getLastModified();
+ Assert.assertNotNull(lastModified);
+ res.release();
+ }
+
+ @Test
+ public void testETagHitGet() throws Exception {
+ // 3) Conditional GET example (get with etag. etag match)
+ // User client GET request
+ // GET /edit/first-post.atom HTTP/1.1
+ // > If-None-Match: "e180ee84f0671b1"
+
+ RequestOptions opts = new RequestOptions();
+ final String contentType = "application/atom+xml; type=entry";
+ opts.setContentType(contentType);
+ opts.setHeader("If-None-Match", eTag);
+ opts.setHeader("Pragma", "no-cache"); // turn off client caching
+
+ IRI colUri = new IRI(providerURI).resolve("customer");
+ // res = client.post(colUri.toString() + "?test=foo", entry, opts);
+ String id = eTag.substring(1, eTag.length() - 1);
+ // Warning. AbderaClient.put(String uri,Base base,RequestOptions
+ // options) caches on the client side.
+ // ClientResponse res = client.put(colUri.toString() + id, entry, opts);
+ ClientResponse res = client.get(colUri.toString() + "/" + id, opts);
+ // Atom server response (item was up to date)
+ // > HTTP/1.1 304 Not Modified
+ // Date: Sat, 24 Feb 2007 13:17:11 GMT
+
+ // Assert response status code is 304 Not Modified.
+ // Assert header ETag: "e180ee84f0671b1"
+ // Assert header Last-Modified: Fri, 25 Jul 2008 14:36:44 -0500
+ // Assert.assertEquals(304, res.getStatus());
+ res.release();
+ }
+
+ @Test
+ public void testUpToDateGet() throws Exception {
+ // 3) Conditional GET example (get with If-Mod. entry is up to date)
+ // User client GET request
+ // GET /edit/first-post.atom HTTP/1.1
+ // > If-Modified-Since: Sat, 29 Oct 2025 19:43:31 GMT
+ RequestOptions opts = new RequestOptions();
+ final String contentType = "application/atom+xml; type=entry";
+ opts.setContentType(contentType);
+ opts.setHeader("If-Modified-Since", "Sat, 29 Oct 2025 19:43:31 GMT"); // "EEE,
+ // dd
+ // MMM
+ // yyyy
+ // HH
+ // :
+ // mm
+ // :
+ // ss
+ // Z
+ // /
+ // /
+ // RFC
+ // 822
+ // Date
+ opts.setHeader("Pragma", "no-cache"); // turn off client caching
+
+ IRI colUri = new IRI(providerURI).resolve("customer");
+ // res = client.post(colUri.toString() + "?test=foo", entry, opts);
+ String id = eTag.substring(1, eTag.length() - 1);
+ // Warning. AbderaClient.put(String uri,Base base,RequestOptions
+ // options) caches on the client side.
+ // ClientResponse res = client.put(colUri.toString() + id, entry, opts);
+ // Warning. AbderaClient.put(String uri,Base base,RequestOptions
+ // options) caches on the client side.
+ // ClientResponse res = client.get(colUri.toString() + "/" + id, opts);
+ ClientResponse res = client.execute("GET", colUri.toString(), (BaseRequestEntity)null, opts);
+
+ // Atom server response (item was up to date)
+ // > HTTP/1.1 304 Not Modified
+ // Date: Sat, 24 Feb 2007 13:17:11 GMT
+
+ // Assert response status code is 304 Not Modified.
+ Assert.assertEquals(304, res.getStatus());
+ res.release();
+ }
+
+ @Test
+ public void testOutOfDateGet() throws Exception {
+ // 4) Conditional GET example (get with If-Mod. entry is not to date)
+ // User client GET request
+ // GET /edit/first-post.atom HTTP/1.1
+ // > If-Modified-Since: Sat, 29 Oct 1844 19:43:31 GMT
+ RequestOptions opts = new RequestOptions();
+ final String contentType = "application/atom+xml; type=entry";
+ opts.setContentType(contentType);
+ opts.setHeader("If-Modified-Since", "Sat, 29 Oct 1844 19:43:31 GMT"); // "EEE,
+ // dd
+ // MMM
+ // yyyy
+ // HH
+ // :
+ // mm
+ // :
+ // ss
+ // Z
+ // /
+ // /
+ // RFC
+ // 822
+ // Date
+ opts.setHeader("Pragma", "no-cache"); // turn off client caching
+
+ IRI colUri = new IRI(providerURI).resolve("customer");
+ // res = client.post(colUri.toString() + "?test=foo", entry, opts);
+ String id = eTag.substring(1, eTag.length() - 1);
+ // Warning. AbderaClient.put(String uri,Base base,RequestOptions
+ // options) caches on the client side.
+ // ClientResponse res = client.put(colUri.toString() + id, entry, opts);
+ ClientResponse res = client.get(colUri.toString() + "/" + id, opts);
+
+ // Atom server response (item was up to date)
+ // > HTTP/1.1 200 OK
+ // Date: Sat, 24 Feb 2007 13:17:11 GMT
+ // > ETag: "bb4f5e86e92ddb8549604a0df0763581"
+ // > Last-Modified: Mon, 28 Jul 2008 10:25:37 -0500
+
+ // Assert response status code is 200 OK.
+ // Assert header ETag: "e180ee84f0671b1"
+ // Assert header Last-Modified: Greater than If-Mod
+ Assert.assertEquals(200, res.getStatus());
+ Assert.assertEquals(contentType, res.getContentType().toString().trim());
+ // Assert.assertNotNull( res.getLocation().toString() );
+ // Assert.assertEquals( "", res.getContentLocation().toString() );
+ Assert.assertNotNull(res.getHeader("ETag"));
+ lastModified = res.getLastModified();
+ Assert.assertNotNull(lastModified);
+ res.release();
+ }
+
+ @Test
+ public void testUpToDateUnModGet() throws Exception {
+ // 3) Conditional GET example (get with If-Unmod. entry is up to date)
+ // User client GET request
+ // GET /edit/first-post.atom HTTP/1.1
+ // > If-Unmodified-Since: Sat, 29 Oct 2025 19:43:31 GMT
+ RequestOptions opts = new RequestOptions();
+ final String contentType = "application/atom+xml; type=entry";
+ opts.setContentType(contentType);
+ opts.setHeader("If-Unmodified-Since", "Sat, 29 Oct 2050 19:43:31 GMT");
+ opts.setHeader("Pragma", "no-cache"); // turn off client caching
+
+ IRI colUri = new IRI(providerURI).resolve("customer");
+ // res = client.post(colUri.toString() + "?test=foo", entry, opts);
+ String id = eTag.substring(1, eTag.length() - 1);
+ // Warning. AbderaClient.put(String uri,Base base,RequestOptions
+ // options) caches on the client side.
+ // ClientResponse res = client.put(colUri.toString() + id, entry, opts);
+ ClientResponse res = client.get(colUri.toString() + "/" + id, opts);
+
+ // Atom server response (item was up to date)
+ // > HTTP/1.1 304 Not Modified
+ // Date: Sat, 24 Feb 2007 13:17:11 GMT
+
+ // Assert response status code is 304 Not Modified.
+ // Assert.assertEquals(304, res.getStatus());
+ // TODO Update when If-Unmodified-Since enabled.
+ Assert.assertEquals(200, res.getStatus());
+ res.release();
+ }
+
+ @Test
+ public void testOutOfDateUnModGet() throws Exception {
+ // 4) Conditional GET example (get with If-Unmod. entry is not to date)
+ // User client GET request
+ // GET /edit/first-post.atom HTTP/1.1
+ // Host: example.org
+ // > If-Unmodified-Since: Sat, 29 Oct 1844 19:43:31 GMT
+ RequestOptions opts = new RequestOptions();
+ final String contentType = "application/atom+xml; type=entry";
+ opts.setContentType(contentType);
+ opts.setHeader("If-Unmodified-Since", "Sat, 29 Oct 1844 19:43:31 GMT");
+ opts.setHeader("Pragma", "no-cache"); // turn off client caching
+
+ IRI colUri = new IRI(providerURI).resolve("customer");
+ // res = client.post(colUri.toString() + "?test=foo", entry, opts);
+ String id = eTag.substring(1, eTag.length() - 1);
+ // Warning. AbderaClient.put(String uri,Base base,RequestOptions
+ // options) caches on the client side.
+ // ClientResponse res = client.put(colUri.toString() + id, entry, opts);
+ ClientResponse res = client.get(colUri.toString() + "/" + id, opts);
+
+ // Atom server response (item was up to date)
+ // > HTTP/1.1 200 OK
+ // Date: Sat, 24 Feb 2007 13:17:11 GMT
+ // > ETag: "bb4f5e86e92ddb8549604a0df0763581"
+ // > Last-Modified: Mon, 28 Jul 2008 10:25:37 -0500
+
+ // Assert response status code is 200 OK.
+ // Assert header Content-Type: application/atom+xml;type=entry
+ // Assert header Location: http://example.org/edit/first-post.atom
+ // Assert header Content-Location:
+ // http://example.org/edit/first-post.atom
+ // Assert header ETag: "e180ee84f0671b1"
+ // Assert header Last-Modified: Less than If-Unmod
+ Assert.assertEquals(200, res.getStatus());
+ Assert.assertEquals(contentType, res.getContentType().toString().trim());
+ // Assert.assertNotNull( res.getLocation().toString() );
+ // Assert.assertEquals( "", res.getContentLocation().toString() );
+ Assert.assertNotNull(res.getHeader("ETag"));
+ lastModified = res.getLastModified();
+ Assert.assertNotNull(lastModified);
+ res.release();
+ }
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderFeedEntityTagsTest.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderFeedEntityTagsTest.java
new file mode 100644
index 0000000000..4c6c2a04c2
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderFeedEntityTagsTest.java
@@ -0,0 +1,365 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.binding.atom;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import junit.framework.Assert;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.i18n.iri.IRI;
+import org.apache.abdera.model.Collection;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Document;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.abdera.parser.Parser;
+import org.apache.abdera.protocol.Response.ResponseType;
+import org.apache.abdera.protocol.client.AbderaClient;
+import org.apache.abdera.protocol.client.ClientResponse;
+import org.apache.abdera.protocol.client.RequestOptions;
+import org.apache.tuscany.sca.node.Contribution;
+import org.apache.tuscany.sca.node.ContributionLocationHelper;
+import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.node.NodeFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Tests use of server provided feed entity tags for Atom binding in Tuscany.
+ * Tests conditional gets (e.g. get if-none-match) or conditional posts (post
+ * if-match) using entity tags and last modified entries in headers. Uses the
+ * SCA provided Provider composite to act as a server. Uses the Abdera provided
+ * Client to act as a client.
+ */
+public class ProviderFeedEntityTagsTest {
+ public final static String providerURI = "http://localhost:8084/customer";
+ protected static Node providerNode;
+ protected static Abdera abdera;
+ protected static AbderaClient client;
+ protected static Parser abderaParser;
+ protected static String eTag;
+ protected static Date lastModified;
+ protected static final SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z"); // RFC
+ // 822
+ // date
+ // time
+
+ @BeforeClass
+ public static void init() throws Exception {
+ System.out.println(">>>ProviderFeedEntityTagsTest.init");
+ String contribution = ContributionLocationHelper.getContributionLocation(AtomDeleteTestCase.class);
+ providerNode = NodeFactory.newInstance().createNode(
+ "org/apache/tuscany/sca/binding/atom/Provider.composite", new Contribution("provider", contribution));
+ providerNode.start();
+ abdera = new Abdera();
+ client = new AbderaClient(abdera);
+ abderaParser = Abdera.getNewParser();
+ }
+
+ @AfterClass
+ public static void destroy() throws Exception {
+ System.out.println(">>>ProviderFeedEntityTagsTest.destroy");
+ providerNode.stop();
+ providerNode.destroy();
+ }
+
+ @Test
+ public void testPrelim() throws Exception {
+ Assert.assertNotNull(providerNode);
+ Assert.assertNotNull(client);
+ }
+
+ @Test
+ public void testFeedBasics() throws Exception {
+ System.out.println(">>>ProviderFeedEntityTagsTest.testFeedBasics");
+ // Normal feed request
+ ClientResponse res = client.get(providerURI);
+ Assert.assertNotNull(res);
+ try {
+ // Asser feed provided since no predicates
+ Assert.assertEquals(200, res.getStatus());
+ Assert.assertEquals(ResponseType.SUCCESS, res.getType());
+ // AtomTestCaseUtils.printResponseHeaders( "Feed response headers:",
+ // " ", res );
+ // System.out.println("Feed response content:");
+ // AtomTestCaseUtils.prettyPrint(abdera, res.getDocument());
+
+ // Perform other tests on feed.
+ Document<Feed> doc = res.getDocument();
+ Assert.assertNotNull(doc);
+ Feed feed = doc.getRoot();
+ Assert.assertNotNull(feed);
+ printFeed("Feed values", " ", feed);
+ // RFC 4287 requires non-null id, title, updated elements
+ Assert.assertNotNull(feed.getId());
+ Assert.assertNotNull(feed.getTitle());
+ Assert.assertNotNull(feed.getUpdated());
+
+ eTag = res.getHeader("ETag");
+ Assert.assertNotNull(eTag);
+ lastModified = res.getLastModified();
+ Assert.assertNotNull(lastModified);
+ } finally {
+ res.release();
+ }
+ }
+
+ @Test
+ public void testUnmodifiedGetIfMatch() throws Exception {
+ System.out.println(">>>ProviderFeedEntityTagsTest.testFeedUnmodifiedGetIfMatch");
+ // Feed request with predicates
+ RequestOptions opts = new RequestOptions();
+ final String contentType = "application/atom+xml";
+ opts.setContentType(contentType);
+ opts.setHeader("If-Match", eTag);
+
+ ClientResponse res = client.get(providerURI, opts);
+ Assert.assertNotNull(res);
+ try {
+ String thisETag = res.getHeader("ETag");
+ Assert.assertNotNull(thisETag);
+ Date thisLastModified = res.getLastModified();
+ Assert.assertNotNull(thisLastModified);
+
+ // Should return 200 - Feed provided since it matches etag.
+ Assert.assertEquals(200, res.getStatus());
+ Assert.assertEquals(ResponseType.SUCCESS, res.getType());
+ // AtomTestCaseUtils.printResponseHeaders( "Feed response headers:",
+ // " ", res );
+ // System.out.println("Feed response content:");
+ // AtomTestCaseUtils.prettyPrint(abdera, res.getDocument());
+ } finally {
+ res.release();
+ }
+ }
+
+ @Test
+ public void testUnmodifiedGetIfNoneMatch() throws Exception {
+ System.out.println(">>>ProviderFeedEntityTagsTest.testFeedUnmodifiedGetIfNoneMatch");
+ // Feed request with predicates
+ RequestOptions opts = new RequestOptions();
+ final String contentType = "application/atom+xml";
+ opts.setContentType(contentType);
+ opts.setHeader("If-None-Match", eTag);
+
+ ClientResponse res = client.get(providerURI, opts);
+ Assert.assertNotNull(res);
+ try {
+ // Should return 304 - Feed not provided since it matches ETag.
+ Assert.assertEquals(304, res.getStatus());
+ } finally {
+ res.release();
+ }
+ }
+
+ @Test
+ public void testUnmodifiedGetIfUnModified() throws Exception {
+ System.out.println(">>>ProviderFeedEntityTagsTest.testFeedUnmodifiedGetIfUnModified");
+ // Feed request with predicates
+ RequestOptions opts = new RequestOptions();
+ final String contentType = "application/atom+xml";
+ opts.setContentType(contentType);
+ opts.setHeader("If-Unmodified-Since", dateFormat.format(new Date()));
+
+ ClientResponse res = client.get(providerURI, opts);
+ Assert.assertNotNull(res);
+ try {
+ // Should return 304 - Feed not provided since feed is modified
+ // since.
+ Assert.assertEquals(304, res.getStatus());
+ } finally {
+ res.release();
+ }
+ }
+
+ @Test
+ public void testUnmodifiedGetIfModified() throws Exception {
+ System.out.println(">>>ProviderFeedEntityTagsTest.testFeedUnmodifiedGetIfModified");
+ // Feed request with predicates
+ RequestOptions opts = new RequestOptions();
+ final String contentType = "application/atom+xml";
+ opts.setContentType(contentType);
+ opts.setHeader("If-Modified-Since", dateFormat.format(new Date(0)));
+
+ ClientResponse res = client.get(providerURI, opts);
+ Assert.assertNotNull(res);
+ try {
+ // Should return 200 - Feed provided since feed is changed.
+ Assert.assertEquals(200, res.getStatus());
+ Assert.assertEquals(ResponseType.SUCCESS, res.getType());
+
+ String thisETag = res.getHeader("ETag");
+ Assert.assertNotNull(thisETag);
+ Date thisLastModified = res.getLastModified();
+ Assert.assertNotNull(thisLastModified);
+ } finally {
+ res.release();
+ }
+ }
+
+ @Test
+ public void testModifiedGetIfNoneMatch() throws Exception {
+ System.out.println(">>>ProviderFeedEntityTagsTest.testFeedModifiedGetIfNoneMatch");
+ // Post some new content to the feed.
+ Factory factory = abdera.getFactory();
+ String customerName = "Fred Farkle";
+ Entry entry = factory.newEntry();
+ entry.setTitle("customer " + customerName);
+ entry.setUpdated(new Date());
+ entry.addAuthor("Apache Tuscany");
+ Content content = abdera.getFactory().newContent();
+ content.setContentType(Content.Type.TEXT);
+ content.setValue(customerName);
+ entry.setContentElement(content);
+
+ RequestOptions opts = new RequestOptions();
+ String contentType = "application/atom+xml; type=entry";
+ opts.setContentType(contentType);
+ IRI colUri = new IRI(providerURI).resolve("customer");
+ ClientResponse res = client.post(colUri.toString(), entry, opts);
+
+ // Feed request with predicates
+ opts = new RequestOptions();
+ contentType = "application/atom+xml";
+ opts.setContentType(contentType);
+ opts.setHeader("If-None-Match", eTag);
+
+ res = client.get(providerURI, opts);
+ Assert.assertNotNull(res);
+ try {
+ String thisETag = res.getHeader("ETag");
+ Assert.assertNotNull(thisETag);
+ Date thisLastModified = res.getLastModified();
+ Assert.assertNotNull(thisLastModified);
+
+ // Should return 200 - value since feed is changed
+ Assert.assertEquals(200, res.getStatus());
+ Assert.assertEquals(ResponseType.SUCCESS, res.getType());
+
+ // AtomTestCaseUtils.printResponseHeaders(
+ // "Feed modified if-none-match response headers:", " ", res );
+ // System.out.println("Feed response content:");
+ // AtomTestCaseUtils.prettyPrint(abdera, res.getDocument());
+ } finally {
+ res.release();
+ }
+ }
+
+ @Test
+ public void testModifiedGetIfMatch() throws Exception {
+ System.out.println(">>>ProviderFeedEntityTagsTest.testFeedModifiedGetIfMatch");
+ // Feed request with predicates
+ RequestOptions opts = new RequestOptions();
+ final String contentType = "application/atom+xml";
+ opts.setContentType(contentType);
+ opts.setHeader("If-Match", eTag);
+
+ ClientResponse res = client.get(providerURI, opts);
+ Assert.assertNotNull(res);
+ try {
+ // Should return 412 - Precondition failed since feed changed.
+ Assert.assertEquals(412, res.getStatus());
+ // AtomTestCaseUtils.printResponseHeaders( "Feed response headers:",
+ // " ", res );
+ // System.out.println("Feed response content:");
+ // AtomTestCaseUtils.prettyPrint(abdera, res.getDocument());
+ } finally {
+ res.release();
+ }
+ }
+
+ @Test
+ public void testModifiedGetIfUnModified() throws Exception {
+ System.out.println(">>>ProviderFeedEntityTagsTest.testFeedUnmodifiedGetIfUnModified");
+ // Feed request with predicates
+ RequestOptions opts = new RequestOptions();
+ final String contentType = "application/atom+xml";
+ opts.setContentType(contentType);
+ opts.setHeader("If-Unmodified-Since", dateFormat.format(new Date()));
+
+ ClientResponse res = client.get(providerURI, opts);
+ Assert.assertNotNull(res);
+ try {
+ // Should return 304 - Feed not provided since feed is modified
+ // since.
+ Assert.assertEquals(304, res.getStatus());
+ } finally {
+ res.release();
+ }
+ }
+
+ @Test
+ public void testModifiedGetIfModified() throws Exception {
+ System.out.println(">>>ProviderFeedEntityTagsTest.testFeedUnmodifiedGetIfModified");
+ // Feed request with predicates
+ RequestOptions opts = new RequestOptions();
+ final String contentType = "application/atom+xml";
+ opts.setContentType(contentType);
+ opts.setHeader("If-Modified-Since", dateFormat.format(lastModified));
+
+ ClientResponse res = client.get(providerURI, opts);
+ Assert.assertNotNull(res);
+ try {
+ // Should return 200 - Feed provided since feed is changed.
+ Assert.assertEquals(200, res.getStatus());
+ Assert.assertEquals(ResponseType.SUCCESS, res.getType());
+
+ String thisETag = res.getHeader("ETag");
+ Assert.assertNotNull(thisETag);
+ Date thisLastModified = res.getLastModified();
+ Assert.assertNotNull(thisLastModified);
+ } finally {
+ res.release();
+ }
+ }
+
+ public static void printFeed(String title, String indent, Feed feed) {
+ if (feed == null) {
+ System.out.println(title + " feed is null");
+ return;
+ }
+
+ System.out.println(title);
+ System.out.println(indent + "id=" + feed.getId());
+ System.out.println(indent + "title=" + feed.getTitle());
+ System.out.println(indent + "updated=" + feed.getUpdated());
+ System.out.println(indent + "author=" + feed.getAuthor());
+ Collection collection = feed.getCollection();
+ if (collection == null) {
+ System.out.println(indent + "collection=null");
+ } else {
+ System.out.println(indent + "collection=" + collection);
+ }
+ // System.out.println( indent + "collection size=" +
+ // feed.getCollection() );
+ // for (Collection collection : workspace.getCollections()) {
+ // if (collection.getTitle().equals("customers")) {
+ // String expected = uri + "customers";
+ // String actual = collection.getResolvedHref().toString();
+ // assertEquals(expected, actual);
+ // }
+ // }
+
+ }
+
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderServiceDocumentTest.java b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderServiceDocumentTest.java
new file mode 100644
index 0000000000..93cbf29766
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/java/org/apache/tuscany/sca/binding/atom/ProviderServiceDocumentTest.java
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.binding.atom;
+
+import junit.framework.Assert;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Document;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.abdera.model.Service;
+import org.apache.abdera.parser.Parser;
+import org.apache.abdera.protocol.Response.ResponseType;
+import org.apache.abdera.protocol.client.AbderaClient;
+import org.apache.abdera.protocol.client.ClientResponse;
+import org.apache.tuscany.sca.binding.atom.collection.Collection;
+import org.apache.tuscany.sca.node.Contribution;
+import org.apache.tuscany.sca.node.ContributionLocationHelper;
+import org.apache.tuscany.sca.node.Node;
+import org.apache.tuscany.sca.node.NodeFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Tests use of service documents provided by atom binding based collections.
+ * Uses the SCA provided Provider composite to act as a server. Uses the Abdera
+ * provided Client to act as a client.
+ */
+public class ProviderServiceDocumentTest {
+ public final static String providerURI = "http://localhost:8084/customer";
+ protected static Node providerNode;
+ protected static Node consumerNode;
+ protected static CustomerClient testService;
+ protected static Abdera abdera;
+ protected static AbderaClient client;
+ protected static Parser abderaParser;
+
+ @BeforeClass
+ public static void init() throws Exception {
+ String contribution = ContributionLocationHelper.getContributionLocation(AtomDeleteTestCase.class);
+ providerNode = NodeFactory.newInstance().createNode(
+ "org/apache/tuscany/sca/binding/atom/Provider.composite", new Contribution("provider", contribution));
+ consumerNode = NodeFactory.newInstance().createNode(
+ "org/apache/tuscany/sca/binding/atom/Consumer.composite", new Contribution("consumer", contribution));
+ providerNode.start();
+ consumerNode.start();
+ testService = consumerNode.getService(CustomerClient.class, "CustomerClient");
+ abdera = new Abdera();
+ client = new AbderaClient(abdera);
+ abderaParser = Abdera.getNewParser();
+ }
+
+ @AfterClass
+ public static void destroy() throws Exception {
+ providerNode.stop();
+ providerNode.destroy();
+ consumerNode.stop();
+ consumerNode.destroy();
+ }
+
+ @Test
+ public void testPrelim() throws Exception {
+ Assert.assertNotNull(providerNode);
+ Assert.assertNotNull(client);
+ }
+
+ @Test
+ public void testFeedBasics() throws Exception {
+ // Normal feed request
+ ClientResponse res = client.get(providerURI);
+ Assert.assertNotNull(res);
+ try {
+ // Assert feed provided since no predicates
+ Assert.assertEquals(200, res.getStatus());
+ Assert.assertEquals(ResponseType.SUCCESS, res.getType());
+ // AtomTestCaseUtils.printResponseHeaders( "Feed response headers:",
+ // " ", res );
+ // System.out.println("Feed response content:");
+ // AtomTestCaseUtils.prettyPrint(abdera, res.getDocument());
+
+ // Perform other tests on feed.
+ Document<Feed> doc = res.getDocument();
+ Assert.assertNotNull(doc);
+ Feed feed = doc.getRoot();
+ Assert.assertNotNull(feed);
+ // printFeed( "Feed values", " ", feed );
+ // RFC 4287 requires non-null id, title, updated elements
+ Assert.assertNotNull(feed.getId());
+ Assert.assertNotNull(feed.getTitle());
+ Assert.assertNotNull(feed.getUpdated());
+ } finally {
+ res.release();
+ }
+ }
+
+ @Test
+ public void testServiceDocumentGet() throws Exception {
+ Collection resourceCollection = testService.getCustomerCollection();
+ Assert.assertNotNull(resourceCollection);
+
+ Entry postEntry = postEntry("Sponge Bob");
+ Entry newEntry = resourceCollection.post(postEntry);
+ postEntry = postEntry("Austin Powers");
+ newEntry = resourceCollection.post(postEntry);
+ postEntry = postEntry("Count Dracula");
+ newEntry = resourceCollection.post(postEntry);
+
+ // Service document
+ ClientResponse res = client.get(providerURI + "/atomsvc");
+ Assert.assertNotNull(res);
+ try {
+ // Asser feed provided since no predicates
+ Assert.assertEquals(200, res.getStatus());
+ Assert.assertEquals(ResponseType.SUCCESS, res.getType());
+
+ // Perform other tests on feed.
+ // AtomTestCaseUtils.prettyPrint(abdera, res.getDocument());
+ Document<Service> serviceDoc = res.getDocument();
+ Service service = serviceDoc.getRoot();
+ Assert.assertNotNull(service);
+ org.apache.abdera.model.Collection collection = service.getCollection("workspace", "customers");
+ String title = collection.getTitle();
+ Assert.assertEquals("customers", title);
+ String href = collection.getHref().toString();
+ Assert.assertTrue(href.contains("customer"));
+ } finally {
+ res.release();
+ }
+ }
+
+ public static void printFeed(String title, String indent, Feed feed) {
+ if (feed == null) {
+ System.out.println(title + " feed is null");
+ return;
+ }
+
+ System.out.println(title);
+ System.out.println(indent + "id=" + feed.getId());
+ System.out.println(indent + "title=" + feed.getTitle());
+ System.out.println(indent + "updated=" + feed.getUpdated());
+ System.out.println(indent + "author=" + feed.getAuthor());
+ // Collection collection = feed.getCollection();
+ // if ( collection == null ) {
+ // System.out.println( indent + "collection=null" );
+ // } else {
+ // System.out.println( indent + "collection=" + collection );
+ // }
+ // System.out.println( indent + "collection size=" +
+ // feed.getCollection() );
+ // for (Collection collection : workspace.getCollections()) {
+ // if (collection.getTitle().equals("customers")) {
+ // String expected = uri + "customers";
+ // String actual = collection.getResolvedHref().toString();
+ // assertEquals(expected, actual);
+ // }
+ // }
+
+ }
+
+ private Entry postEntry(String value) {
+ Entry entry = abdera.newEntry();
+ entry.setTitle("customer " + value);
+
+ Content content = abdera.getFactory().newContent();
+ content.setContentType(Content.Type.TEXT);
+ content.setValue(value);
+ entry.setContentElement(content);
+
+ return entry;
+ }
+}
diff --git a/java/sca/modules/binding-atom-abdera/src/test/resources/org/apache/tuscany/sca/binding/atom/Consumer.composite b/java/sca/modules/binding-atom-abdera/src/test/resources/org/apache/tuscany/sca/binding/atom/Consumer.composite
new file mode 100644
index 0000000000..a2c50f872e
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/resources/org/apache/tuscany/sca/binding/atom/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.atom.CustomerClientImpl"/>
+ <reference name="customerCollection">
+ <tuscany:binding.atom uri="http://localhost:8084/customer"/>
+ </reference>
+ </component>
+
+</composite>
diff --git a/java/sca/modules/binding-atom-abdera/src/test/resources/org/apache/tuscany/sca/binding/atom/Provider.composite b/java/sca/modules/binding-atom-abdera/src/test/resources/org/apache/tuscany/sca/binding/atom/Provider.composite
new file mode 100644
index 0000000000..60097ee0f7
--- /dev/null
+++ b/java/sca/modules/binding-atom-abdera/src/test/resources/org/apache/tuscany/sca/binding/atom/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.atom.CustomerCollectionImpl"/>
+ </component>
+
+</composite>
diff --git a/java/sca/modules/binding-atom/LICENSE b/java/sca/modules/binding-atom/LICENSE
new file mode 100644
index 0000000000..6e529a25c4
--- /dev/null
+++ b/java/sca/modules/binding-atom/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/modules/binding-atom/META-INF/MANIFEST.MF b/java/sca/modules/binding-atom/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..4b58729aa2
--- /dev/null
+++ b/java/sca/modules/binding-atom/META-INF/MANIFEST.MF
@@ -0,0 +1,23 @@
+Manifest-Version: 1.0
+Export-Package: org.apache.tuscany.sca.binding.atom;uses:="org.apache.
+ tuscany.sca.assembly";version="1.4"
+Private-Package: org.apache.tuscany.sca.binding.atom.impl;version="1.4
+ "
+Tool: Bnd-0.0.255
+Bundle-Name: Apache Tuscany SCA Atom Feed Binding Extension
+Created-By: 1.6.0_07 (Sun Microsystems Inc.)
+Bundle-Vendor: The Apache Software Foundation
+Bundle-Version: 1.4
+Bnd-LastModified: 1225397253156
+Bundle-ManifestVersion: 2
+Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
+Bundle-Description: Apache Tuscany SCA Atom Feed Binding Extension
+Import-Package: javax.xml.stream;resolution:=optional,
+ org.apache.tuscany.sca.assembly;version="1.4",
+ org.apache.tuscany.sca.binding.atom;version="1.4",
+ org.apache.tuscany.sca.core;version="1.4";resolution:=optional,
+ org.apache.tuscany.sca.monitor;version="1.4";resolution:=optional,
+ org.apache.tuscany.sca.policy;version="1.4"
+Bundle-SymbolicName: org.apache.tuscany.sca.binding.atom
+Bundle-DocURL: http://www.apache.org/
+
diff --git a/java/sca/modules/binding-atom/NOTICE b/java/sca/modules/binding-atom/NOTICE
new file mode 100644
index 0000000000..1325efd8bf
--- /dev/null
+++ b/java/sca/modules/binding-atom/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/modules/binding-atom/pom.xml b/java/sca/modules/binding-atom/pom.xml
new file mode 100644
index 0000000000..413675787d
--- /dev/null
+++ b/java/sca/modules/binding-atom/pom.xml
@@ -0,0 +1,62 @@
+<?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>1.4-EQUINOX-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>tuscany-binding-atom</artifactId>
+ <name>Apache Tuscany SCA Atom Feed Binding Extension</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-assembly</artifactId>
+ <version>1.4-EQUINOX-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-assembly-xml</artifactId>
+ <version>1.4-EQUINOX-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-sca-api</artifactId>
+ <version>1.4-EQUINOX-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.5</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
diff --git a/java/sca/modules/binding-atom/src/main/java/org/apache/tuscany/sca/binding/atom/AtomBinding.java b/java/sca/modules/binding-atom/src/main/java/org/apache/tuscany/sca/binding/atom/AtomBinding.java
new file mode 100644
index 0000000000..807d6a8971
--- /dev/null
+++ b/java/sca/modules/binding-atom/src/main/java/org/apache/tuscany/sca/binding/atom/AtomBinding.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.binding.atom;
+
+import org.apache.tuscany.sca.assembly.Binding;
+
+/**
+ * Atom binding model.
+ *
+ * @version $Rev$ $Date$
+ */
+public interface AtomBinding extends Binding {
+
+ /**
+ * Returns the title of the Atom collection.
+ * @return
+ */
+ String getTitle();
+
+ /**
+ * Sets the title of the Atom collection.
+ * @param title
+ */
+ void setTitle(String title);
+
+}
diff --git a/java/sca/modules/binding-atom/src/main/java/org/apache/tuscany/sca/binding/atom/AtomBindingFactory.java b/java/sca/modules/binding-atom/src/main/java/org/apache/tuscany/sca/binding/atom/AtomBindingFactory.java
new file mode 100644
index 0000000000..6e5623e1a2
--- /dev/null
+++ b/java/sca/modules/binding-atom/src/main/java/org/apache/tuscany/sca/binding/atom/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.atom;
+
+/**
+ * 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/modules/binding-atom/src/main/java/org/apache/tuscany/sca/binding/atom/impl/AtomBindingFactoryImpl.java b/java/sca/modules/binding-atom/src/main/java/org/apache/tuscany/sca/binding/atom/impl/AtomBindingFactoryImpl.java
new file mode 100644
index 0000000000..ea06625d34
--- /dev/null
+++ b/java/sca/modules/binding-atom/src/main/java/org/apache/tuscany/sca/binding/atom/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.atom.impl;
+
+import org.apache.tuscany.sca.binding.atom.AtomBinding;
+import org.apache.tuscany.sca.binding.atom.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/modules/binding-atom/src/main/java/org/apache/tuscany/sca/binding/atom/impl/AtomBindingImpl.java b/java/sca/modules/binding-atom/src/main/java/org/apache/tuscany/sca/binding/atom/impl/AtomBindingImpl.java
new file mode 100644
index 0000000000..8b0b9451fb
--- /dev/null
+++ b/java/sca/modules/binding-atom/src/main/java/org/apache/tuscany/sca/binding/atom/impl/AtomBindingImpl.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.tuscany.sca.binding.atom.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tuscany.sca.assembly.Binding;
+import org.apache.tuscany.sca.assembly.Component;
+import org.apache.tuscany.sca.assembly.ComponentService;
+import org.apache.tuscany.sca.assembly.OptimizableBinding;
+import org.apache.tuscany.sca.binding.atom.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 String title;
+ 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 String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ 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;
+ }
+
+ 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/modules/binding-atom/src/main/resources/META-INF/services/org.apache.tuscany.sca.binding.atom.AtomBindingFactory b/java/sca/modules/binding-atom/src/main/resources/META-INF/services/org.apache.tuscany.sca.binding.atom.AtomBindingFactory
new file mode 100644
index 0000000000..a8117db8f3
--- /dev/null
+++ b/java/sca/modules/binding-atom/src/main/resources/META-INF/services/org.apache.tuscany.sca.binding.atom.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.atom.impl.AtomBindingFactoryImpl \ No newline at end of file
diff --git a/java/sca/modules/binding-atom/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor b/java/sca/modules/binding-atom/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor
new file mode 100644
index 0000000000..52e0e916f5
--- /dev/null
+++ b/java/sca/modules/binding-atom/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor
@@ -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 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.atom.AtomBinding,factory=org.apache.tuscany.sca.binding.atom.AtomBindingFactory \ No newline at end of file
diff --git a/java/sca/modules/binding-atom/src/test/java/org/apache/tuscany/sca/binding/atom/AtomBindingProcessorTestCase.java b/java/sca/modules/binding-atom/src/test/java/org/apache/tuscany/sca/binding/atom/AtomBindingProcessorTestCase.java
new file mode 100644
index 0000000000..1477554cd1
--- /dev/null
+++ b/java/sca/modules/binding-atom/src/test/java/org/apache/tuscany/sca/binding/atom/AtomBindingProcessorTestCase.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.atom;
+
+import java.io.StringReader;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.tuscany.sca.assembly.Composite;
+import org.apache.tuscany.sca.contribution.processor.DefaultStAXArtifactProcessorExtensionPoint;
+import org.apache.tuscany.sca.contribution.processor.ExtensibleStAXArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor;
+import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessorExtensionPoint;
+import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.apache.tuscany.sca.monitor.DefaultMonitorFactory;
+import org.apache.tuscany.sca.monitor.Monitor;
+import org.apache.tuscany.sca.monitor.MonitorFactory;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class AtomBindingProcessorTestCase {
+
+ private static final String COMPOSITE =
+ "<?xml version=\"1.0\" encoding=\"ASCII\"?>"
+ + "<composite xmlns=\"http://www.osoa.org/xmlns/sca/1.0\" xmlns:tuscany=\"http://tuscany.apache.org/xmlns/sca/1.0\" targetNamespace=\"http://binding-atom\" name=\"binding-atom\">"
+ + " <component name=\"HelloWorldComponent\">"
+ + " <implementation.java class=\"services.HelloWorld\"/>"
+ + " <service name=\"HelloWorldService\">"
+ + " <tuscany:binding.atom uri=\"http://localhost:8080/feed\" title=\"Feed Title\"/>"
+ + " </service>"
+ + " </component>"
+ + "</composite>";
+
+ private static XMLInputFactory inputFactory;
+ private static StAXArtifactProcessor<Object> staxProcessor;
+ private static Monitor monitor;
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ DefaultExtensionPointRegistry extensionPoints = new DefaultExtensionPointRegistry();
+ inputFactory = XMLInputFactory.newInstance();
+ // Create a monitor
+ UtilityExtensionPoint utilities = extensionPoints.getExtensionPoint(UtilityExtensionPoint.class);
+ MonitorFactory monitorFactory = new DefaultMonitorFactory();
+ if (monitorFactory != null) {
+ monitor = monitorFactory.createMonitor();
+ utilities.addUtility(monitorFactory);
+ }
+ StAXArtifactProcessorExtensionPoint staxProcessors = new DefaultStAXArtifactProcessorExtensionPoint(extensionPoints);
+ staxProcessor = new ExtensibleStAXArtifactProcessor(staxProcessors, inputFactory, null, monitor);
+ }
+
+ /**
+ * Test parsing valid composite definition. Valid composite populated with correct values expected.
+ * @throws Exception
+ */
+ @Test
+ public void testLoadValidComposite() throws Exception {
+ XMLStreamReader reader = inputFactory.createXMLStreamReader(new StringReader(COMPOSITE));
+
+ Composite composite = (Composite)staxProcessor.read(reader);
+ AtomBinding binding = (AtomBinding) composite.getComponents().get(0).getServices().get(0).getBindings().get(0);
+
+ Assert.assertNotNull(binding);
+ Assert.assertEquals("Feed Title", binding.getTitle());
+ Assert.assertEquals("http://localhost:8080/feed", binding.getURI());
+ }
+}