diff options
Diffstat (limited to 'sca-java-2.x/trunk/modules/binding-comet-runtime')
20 files changed, 1940 insertions, 0 deletions
diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/LICENSE b/sca-java-2.x/trunk/modules/binding-comet-runtime/LICENSE new file mode 100644 index 0000000000..6e529a25c4 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/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/sca-java-2.x/trunk/modules/binding-comet-runtime/META-INF/MANIFEST.MF b/sca-java-2.x/trunk/modules/binding-comet-runtime/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..61933424f3 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/META-INF/MANIFEST.MF @@ -0,0 +1,31 @@ +Manifest-Version: 1.0
+SCA-Version: 1.1
+Bundle-Name: Apache Tuscany SCA Comet Binding Model
+Bundle-Vendor: The Apache Software Foundation
+Bundle-Version: 2.0.0
+Bundle-ManifestVersion: 2
+Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
+Bundle-Description: Apache Tuscany SCA Comet Binding Model
+Import-Package: javax.servlet;version="2.5.0",
+ javax.servlet.http;version="2.5.0",
+ org.apache.commons.codec,
+ org.apache.commons.codec.net,
+ org.apache.http;version="4.0.1",
+ org.apache.http.client;version="4.0.0",
+ org.apache.http.client.methods;version="4.0.0",
+ org.apache.http.client.utils;version="4.0.0",
+ org.apache.http.conn;version="4.0.0",
+ org.apache.http.impl.client;version="4.0.0",
+ org.apache.tuscany.sca.assembly;version="2.0.0",
+ org.apache.tuscany.sca.binding.comet;version="2.0.0",
+ org.apache.tuscany.sca.core;version="2.0.0",
+ org.apache.tuscany.sca.host.http;version="2.0.0",
+ org.apache.tuscany.sca.interfacedef;version="2.0.0",
+ org.apache.tuscany.sca.invocation;version="2.0.0",
+ org.apache.tuscany.sca.provider;version="2.0.0",
+ org.apache.tuscany.sca.runtime;version="2.0.0",
+ org.codehaus.jackson,
+ org.codehaus.jackson.map
+Bundle-SymbolicName: org.apache.tuscany.sca.binding.comet.runtime
+Bundle-DocURL: http://www.apache.org/
+Bundle-RequiredExecutionEnvironment: J2SE-1.5,JavaSE-1.6 diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/NOTICE b/sca-java-2.x/trunk/modules/binding-comet-runtime/NOTICE new file mode 100644 index 0000000000..9ddba06a32 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/NOTICE @@ -0,0 +1,6 @@ +${pom.name}
+Copyright (c) 2005 - 2010 The Apache Software Foundation
+
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
+
diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/pom.xml b/sca-java-2.x/trunk/modules/binding-comet-runtime/pom.xml new file mode 100644 index 0000000000..3997479443 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/pom.xml @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. +--> +<project> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-modules</artifactId> + <version>2.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-binding-comet-runtime</artifactId> + <name>Apache Tuscany SCA Comet Binding Runtime</name> + <packaging>jar</packaging> + + <dependencies> + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-binding-comet</artifactId> + <version>2.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.atmosphere</groupId> + <artifactId>atmosphere-commons</artifactId> + <version>0.6.1</version> + </dependency> + <dependency> + <groupId>org.atmosphere</groupId> + <artifactId>atmosphere-runtime</artifactId> + <version>0.6.1</version> + </dependency> + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-host-http</artifactId> + <version>2.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-host-jetty</artifactId> + <version>2.0-SNAPSHOT</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-node-impl</artifactId> + <version>2.0-SNAPSHOT</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-implementation-java-runtime</artifactId> + <version>2.0-SNAPSHOT</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.tuscany.sca</groupId> + <artifactId>tuscany-sca-api</artifactId> + <version>2.0-SNAPSHOT</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>1.4</version> + </dependency> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-servlet_3.0_spec</artifactId> + <version>1.0</version> + <scope>provided</scope> + </dependency> + </dependencies> + + <repositories> + <repository> + <id>gson-googlecode-repository</id> + <url>http://google-gson.googlecode.com/svn/mavenrepo</url> + <snapshots> + <enabled>true</enabled> + </snapshots> + <releases> + <enabled>true</enabled> + </releases> + </repository> + <repository> + <id>maven2-repository.dev.java.net</id> + <name>Java.net Repository for Maven</name> + <url>http://download.java.net/maven/2/</url> + <layout>default</layout> + </repository> + <repository> + <id>glassfish-repository</id> + <url>http://download.java.net/maven/glassfish</url> + </repository> + </repositories> + +</project> diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometBindingProviderFactory.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometBindingProviderFactory.java new file mode 100644 index 0000000000..fc5fd9f371 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometBindingProviderFactory.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.binding.comet.runtime; + +import org.apache.tuscany.sca.binding.comet.CometBinding; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.host.http.ServletHost; +import org.apache.tuscany.sca.host.http.ServletHostHelper; +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.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; + +/** + * Factory for binding providers. + */ +public class CometBindingProviderFactory implements BindingProviderFactory<CometBinding> { + + /** + * Underlying servlet host. Injected by constructor. + */ + private final ServletHost servletHost; + + /** + * Constructor. + */ + public CometBindingProviderFactory(final ExtensionPointRegistry extensionPoints) { + this.servletHost = ServletHostHelper.getServletHost(extensionPoints); + } + + @Override + public Class<CometBinding> getModelType() { + return CometBinding.class; + } + + /** + * Creates a provider for a reference that has comet binding specified in + * the scdl. + */ + @Override + public ReferenceBindingProvider createReferenceBindingProvider(final RuntimeEndpointReference endpoint) { + return new CometReferenceBindingProvider(endpoint); + } + + /** + * Creates a provider for a service that has comet binding specified in the + * scdl. + */ + @Override + public ServiceBindingProvider createServiceBindingProvider(final RuntimeEndpoint endpoint) { + return new CometServiceBindingProvider(endpoint, this.servletHost); + } + +} diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometInvoker.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometInvoker.java new file mode 100644 index 0000000000..9353571cb1 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometInvoker.java @@ -0,0 +1,62 @@ +/* + * 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.comet.runtime; + +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; + +/** + * Invoker for a service binding. Invoking is made from client Javascript so no + * behavior is needed. + */ +public class CometInvoker implements Invoker { + + /** + * The invoked operation. + */ + protected Operation operation; + + /** + * The endpoint to which the operation belongs. + */ + protected EndpointReference endpoint; + + /** + * Default constructor. + * + * @param operation the operation + * @param endpoint the endpoint + */ + public CometInvoker(final Operation operation, final EndpointReference endpoint) { + this.operation = operation; + this.endpoint = endpoint; + } + + /** + * No behavior. + */ + @Override + public Message invoke(final Message msg) { + return null; + } + +} diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometReferenceBindingProvider.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometReferenceBindingProvider.java new file mode 100644 index 0000000000..17470e3738 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometReferenceBindingProvider.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.binding.comet.runtime; + +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.provider.ReferenceBindingProvider; + +/** + * Provider for references that have comet binding specified in the scdl. Not + * used as comet binding references would occur in client browser's Javascript. + */ +public class CometReferenceBindingProvider implements ReferenceBindingProvider { + + /** + * Endpoint for which the binding provider is created. + */ + private final EndpointReference endpoint; + + public CometReferenceBindingProvider(final EndpointReference endpoint) { + this.endpoint = endpoint; + } + + @Override + public Invoker createInvoker(final Operation operation) { + return new CometInvoker(operation, this.endpoint); + } + + /** + * No behavior. + */ + @Override + public void start() { + } + + /** + * No behavior. + */ + @Override + public void stop() { + } + + @Override + public InterfaceContract getBindingInterfaceContract() { + return null; + } + + @Override + public boolean supportsOneWayInvocation() { + return true; + } + +} diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometServiceBindingProvider.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometServiceBindingProvider.java new file mode 100644 index 0000000000..31c0b5b4d8 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometServiceBindingProvider.java @@ -0,0 +1,90 @@ +/* + * 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.comet.runtime; + +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.binding.comet.runtime.javascript.JavascriptGenerator; +import org.apache.tuscany.sca.host.http.ServletHost; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.provider.ServiceBindingProvider; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; + +/** + * Provider for services having comet binding specified in the scdl. + */ +public class CometServiceBindingProvider implements ServiceBindingProvider { + + /** + * Service's endpoint. + */ + private final RuntimeEndpoint endpoint; + + /** + * The underlying servlet host. + */ + private final ServletHost servletHost; + + /** + * Constructor. + * + * @param endpoint the given endpoint + * @param servletHost the given servlet host + */ + public CometServiceBindingProvider(final RuntimeEndpoint endpoint, final ServletHost servletHost) { + this.endpoint = endpoint; + this.servletHost = servletHost; + } + + /** + * This method is used to start the provider. + */ + @Override + public void start() { + ServletFactory.registerServlet(this.servletHost); + final ComponentService service = this.endpoint.getService(); + final Interface serviceInterface = service.getInterfaceContract().getInterface(); + JavascriptGenerator.generateServiceProxy(service); + for (final Operation operation : serviceInterface.getOperations()) { + JavascriptGenerator.generateMethodProxy(service, operation); + ServletFactory.addOperation(this.endpoint, operation); + } + } + + /** + * This method is used to stop the provider. + */ + @Override + public void stop() { + ServletFactory.unregisterServlet(this.servletHost); + } + + @Override + public InterfaceContract getBindingInterfaceContract() { + return null; + } + + @Override + public boolean supportsOneWayInvocation() { + return true; + } + +} diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/ServletFactory.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/ServletFactory.java new file mode 100644 index 0000000000..c1244b3183 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/ServletFactory.java @@ -0,0 +1,155 @@ +/* + * 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.comet.runtime; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.tuscany.sca.host.http.ServletHost; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.atmosphere.cpr.AtmosphereServlet; + +/** + * This class is used to create two servlets: one exposing all the comet + * services, the other one exposing the javascript toolkit. Exposing all comet + * services through a single servlet is needed as the browsers are undergone by + * the two http connection limit so all comet services should send their + * responses via the same http connection to the same client. Dispatching to the + * corresponding endpoint and operation is done internally using Jersey RESTful + * Web Services integration with the AtmosphereServlet. The Javascript toolkit + * servlet is unique as it is not tied to any of the services - it offers a + * global API. + */ +public final class ServletFactory { + + /** + * Init-param key for the AtmosphereServlet defining where to look for + * Jersey classes. + */ + private static final String PACKAGE_KEY = "com.sun.jersey.config.property.packages"; + + /** + * Package of the class handling dispatching to endpoints. + */ + private static final String PACKAGE_VALUE = "org.apache.tuscany.sca.binding.comet.runtime.handler"; + + /** + * Package of the class handling Javascript toolkit retrieval. + */ + private static final String JS_PACKAGE_VALUE = "org.apache.tuscany.sca.binding.comet.runtime.javascript"; + + /** + * Property in the ServletContext where endpoints are added incrementally as + * the Tuscany runtime calls the CometServiceBindingProvider for each comet + * service. + */ + public static final String ENDPOINTS_KEY = "org.apache.tuscany.sca.binding.comet.endpoints"; + + /** + * Property in the ServletContext where operations are added incrementally + * as the CometServiceBindingProvider is calling the registerServlet method + * for each comet service method. + */ + public static final String OPERATIONS_KEY = "org.apache.tuscany.sca.binding.comet.operations"; + + /** + * Path where services will be exposed. + */ + public static final String PATH = "/tuscany-comet/*"; + + /** + * Path where Javascript toolkit will be exposed. + */ + public static final String JS_PATH = "/org.apache.tuscany.sca.cometComponentContext.js/*"; + + /** + * The servlet that is exposing the comet services. + */ + private static AtmosphereServlet cometServlet = null; + + /** + * The servlet that is exposing the Javascript toolkit. + */ + private static AtmosphereServlet javascriptServlet = null; + + /** + * Private constructor for the singleton class. + */ + private ServletFactory() { + } + + /** + * Method called by CometServiceBindingProvider for each endpoint in order + * to create the two singleton servlets. + * + * @param servletHost the underlying servlet host + */ + public static synchronized void registerServlet(final ServletHost servletHost) { + if (ServletFactory.cometServlet == null) { + ServletFactory.cometServlet = new AtmosphereServlet(); + ServletFactory.cometServlet.addInitParameter(ServletFactory.PACKAGE_KEY, ServletFactory.PACKAGE_VALUE); + servletHost.addServletMapping(ServletFactory.PATH, ServletFactory.cometServlet); + // store operations and corresponding endpoint in the ServletContext + // so that they can be retrieved from inside the web service methods + final Map<String, RuntimeEndpoint> endpoints = new HashMap<String, RuntimeEndpoint>(); + ServletFactory.cometServlet.getServletContext().setAttribute(ServletFactory.ENDPOINTS_KEY, endpoints); + final Map<String, Operation> operations = new HashMap<String, Operation>(); + ServletFactory.cometServlet.getServletContext().setAttribute(ServletFactory.OPERATIONS_KEY, operations); + } + if (ServletFactory.javascriptServlet == null) { + ServletFactory.javascriptServlet = new AtmosphereServlet(); + ServletFactory.javascriptServlet.addInitParameter(ServletFactory.PACKAGE_KEY, + ServletFactory.JS_PACKAGE_VALUE); + servletHost.addServletMapping(ServletFactory.JS_PATH, ServletFactory.javascriptServlet); + } + } + + /** + * Method called by CometServiceBindingProvider for each endpoint operation + * in order to store all the operations the servlet will serve. + * + * @param endpoint the endpoint + * @param operation the operation + */ + public static synchronized void addOperation(final RuntimeEndpoint endpoint, final Operation operation) { + final String url = "/" + endpoint.getService().getName() + "/" + operation.getName(); + final Map<String, RuntimeEndpoint> endpoints = + (Map<String, RuntimeEndpoint>)ServletFactory.cometServlet.getServletContext() + .getAttribute(ServletFactory.ENDPOINTS_KEY); + endpoints.put(url, endpoint); + final Map<String, Operation> operations = + (Map<String, Operation>)ServletFactory.cometServlet.getServletContext() + .getAttribute(ServletFactory.OPERATIONS_KEY); + operations.put(url, operation); + } + + /** + * Method called by CometServiceBindingProvider for each endpoint operation + * in order to remove the two servlets. + * + * @param servletHost the underlying servlet host + */ + public static synchronized void unregisterServlet(final ServletHost servletHost) { + servletHost.removeServletMapping(ServletFactory.PATH); + servletHost.removeServletMapping(ServletFactory.JS_PATH); + } + +} diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/handler/CometBindingHandler.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/handler/CometBindingHandler.java new file mode 100644 index 0000000000..512b834840 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/handler/CometBindingHandler.java @@ -0,0 +1,174 @@ +/* + * 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.comet.runtime.handler; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletContext; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; + +import org.apache.tuscany.sca.binding.comet.runtime.ServletFactory; +import org.apache.tuscany.sca.interfacedef.DataType; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.atmosphere.annotation.Broadcast; +import org.atmosphere.cpr.Broadcaster; +import org.atmosphere.cpr.DefaultBroadcaster; +import org.atmosphere.jersey.Broadcastable; +import org.atmosphere.jersey.SuspendResponse; + +import com.google.gson.Gson; +import com.sun.jersey.spi.container.servlet.PerSession; + +/** + * Class serving calls coming for comet services and operations. + */ +@Path("/") +@Produces("text/html;charset=ISO-8859-1") +@PerSession +public class CometBindingHandler { + + /** + * The object used to suspend the response and send async responses back to + * client. + */ + private Broadcaster broadcaster; + + /** + * The service endpoints corresponding to each operation. + */ + private Map<String, RuntimeEndpoint> endpoints; + + /** + * The comet operations. + */ + private Map<String, Operation> operations; + + /** + * JSON converter. + */ + private Gson gson; + + /** + * The underlying servlet context. + */ + @Context + private ServletContext sc; + + /** + * Method called at comet connect time. This suspends the response and keeps + * the connection opened. + * + * @return the suspended response + */ + @GET + public SuspendResponse<String> connect() { + this.broadcaster = new DefaultBroadcaster(); + this.endpoints = (Map<String, RuntimeEndpoint>)this.sc.getAttribute(ServletFactory.ENDPOINTS_KEY); + this.operations = (Map<String, Operation>)this.sc.getAttribute(ServletFactory.OPERATIONS_KEY); + this.gson = new Gson(); + return new SuspendResponse.SuspendResponseBuilder<String>().broadcaster(this.broadcaster).outputComments(true) + .build(); + } + + /** + * Method called on service calls. + * + * @param service service called + * @param method operation called + * @param callbackMethod the callback method from Javascript + * @param jsonData arguments for the method sent as JSON array + * @return object used by the Broadcaster to send response through the + * persisted connection + * @throws InvocationTargetException if problems occur at service invocation + */ + @POST + @Path("/{service}/{method}") + @Broadcast + public Broadcastable callAndRespond(@PathParam("service") final String service, + @PathParam("method") final String method, + @FormParam("callback") final String callbackMethod, + @FormParam("params") final String jsonData) throws InvocationTargetException { + final String url = "/" + service + "/" + method; + final RuntimeEndpoint wire = this.endpoints.get(url); + final Operation operation = this.operations.get(url); + final Object[] args = new Object[operation.getInputType().getLogical().size()]; + final String[] json = this.parseArray(jsonData); + int index = 0; + // convert each argument to the corresponding class + for (final DataType<?> dataType : operation.getInputType().getLogical()) { + args[index] = this.gson.fromJson(json[index], dataType.getPhysical()); + index++; + } + // invoke the service operation + final Object response = wire.invoke(operation, args); + return new Broadcastable(callbackMethod + "($.secureEvalJSON('" + this.gson.toJson(response) + "'))", "", + this.broadcaster); + } + + /** + * Parse the JSON array containing the arguments for the method call in + * order to avoid converting JSON to Object[]. Converting each object + * separately to it's corresponding type avoids type mismatch problems at + * service invocation. + * + * @param jsonArray the JSON array + * @return an array of JSON formatted objects + */ + private String[] parseArray(final String jsonArray) { + final List<String> objects = new ArrayList<String>(); + int bracketNum = 0; + int parNum = 0; + int startPos = 1; + for (int i = 0; i < jsonArray.length(); i++) { + switch (jsonArray.charAt(i)) { + case '{': + bracketNum++; + break; + case '}': + bracketNum--; + break; + case '[': + parNum++; + break; + case ']': + parNum--; + break; + case ',': + if ((bracketNum == 0) && (parNum == 1)) { + objects.add(jsonArray.substring(startPos, i)); + startPos = i + 1; + } + } + } + // add last object + objects.add(jsonArray.substring(startPos, jsonArray.length() - 1)); + return objects.toArray(new String[] {}); + } +} diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/javascript/JavascriptGenerator.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/javascript/JavascriptGenerator.java new file mode 100644 index 0000000000..b1205596ea --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/javascript/JavascriptGenerator.java @@ -0,0 +1,107 @@ +/* + * 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.comet.runtime.javascript; + +import org.apache.tuscany.sca.assembly.ComponentService; +import org.apache.tuscany.sca.interfacedef.Operation; + +/** + * This class generates proxies for the comet services. + */ +public class JavascriptGenerator { + + /** + * Namespace for the Tuscany Comet Javascript toolkit. + */ + public static final String JS_NAMESPACE = "SCA"; + + /** + * Name for the SCA component context. + */ + private static final String COMPONENT_CONTEXT = "this.CometComponentContext"; + + /** + * Name for the object performing comet specific tasks. + */ + private static final String TUSCANY_COMET = "SCA.TuscanyComet"; + + /** + * Generated Javascript. + */ + private static StringBuffer javascript = new StringBuffer(); + + /** + * Default constructor for utility class. + */ + private JavascriptGenerator() { + } + + /** + * Getter for the generated Javascript. + * + * @return the generated Javascript + */ + public static StringBuffer getJavascript() { + return JavascriptGenerator.javascript; + } + + /** + * Generates the proxy for a service. + * + * @param service the service for which generation is performed + */ + public static void generateServiceProxy(final ComponentService service) { + JavascriptGenerator.javascript.append(JavascriptGenerator.COMPONENT_CONTEXT + "." + + service.getName() + + " = new Object();\n"); + } + + /** + * Generates the method inside the service proxy for the specified + * operation. + * + * @param service the service containing the operation + * @param operation the operation + */ + public static void generateMethodProxy(final ComponentService service, final Operation operation) { + JavascriptGenerator.javascript.append(JavascriptGenerator.COMPONENT_CONTEXT + "." + + service.getName() + + "." + + operation.getName() + + " = function("); + for (int i = 0; i < operation.getInputType().getLogical().size(); i++) { + JavascriptGenerator.javascript.append("p" + i + ", "); + } + JavascriptGenerator.javascript.append("callbackMethod) {\n"); + // send method argumets as JSON array + JavascriptGenerator.javascript.append(" var params = [];\n"); + for (int i = 0; i < operation.getInputType().getLogical().size(); i++) { + JavascriptGenerator.javascript.append(" params.push(p" + i + ");\n"); + } + JavascriptGenerator.javascript.append(" " + JavascriptGenerator.TUSCANY_COMET + + ".callAsync('" + + service.getName() + + "/" + + operation.getName() + + "', $.toJSON(params), callbackMethod);\n"); + JavascriptGenerator.javascript.append("}\n"); + } + +} diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/javascript/JavascriptResource.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/javascript/JavascriptResource.java new file mode 100644 index 0000000000..9274009803 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/javascript/JavascriptResource.java @@ -0,0 +1,63 @@ +/* + * 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.comet.runtime.javascript; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.SequenceInputStream; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; + +/** + * Class serving the calls performed to retrieve the Javascript toolkit. + */ +@Path("/") +@Produces("text/javascript") +public class JavascriptResource { + + /** + * Dependencies for the Tuscany Comet Javascript API. + */ + private static final String[] DEPENDENCIES = {"/jquery.atmosphere.js", "/jquery.json-2.2.min.js", + "/cometComponentContext.js"}; + + /** + * Method called when the Javascript toolkit is requested. + * + * @return InputStream containing the Javascript code. + */ + @GET + public InputStream getJavascript() { + InputStream stream = null; + // add dependencies in the specified order + for (final String dependency : JavascriptResource.DEPENDENCIES) { + if (stream == null) { + stream = this.getClass().getResourceAsStream(dependency); + } else { + stream = new SequenceInputStream(stream, this.getClass().getResourceAsStream(dependency)); + } + } + // add generated proxies + final String generatedJs = JavascriptGenerator.getJavascript().toString() + "\n}"; + return new SequenceInputStream(stream, new ByteArrayInputStream(generatedJs.getBytes())); + } +} diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory new file mode 100644 index 0000000000..cb6db39c4e --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory @@ -0,0 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Implementation class for the binding extension
+org.apache.tuscany.sca.binding.comet.runtime.CometBindingProviderFactory;model=org.apache.tuscany.sca.binding.comet.CometBinding
+
diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/cometComponentContext.js b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/cometComponentContext.js new file mode 100644 index 0000000000..9d9254199e --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/cometComponentContext.js @@ -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. + */ + +var SCA = new function() { + +this.TuscanyComet = { + appUrl: 'tuscany-comet', + connectedEndpoint : null, + connect : function(transport) { + $.atmosphere.subscribe(document.location.toString() + this.appUrl, + this.callback, + $.atmosphere.request = { + transport : transport + }); + this.connectedEndpoint = $.atmosphere.response; + }, + callAsync : function(url, params, callbackMethod) { + this.connectedEndpoint.push(document.location.toString() + + this.appUrl + '/' + url, + null, + $.atmosphere.request = { + method : 'POST', + data : 'callback=' + callbackMethod.name + '¶ms=' + params + }); + }, + callback : function(response) { + eval(response.responseBody); + } +}; + +this.CometComponentContext = new Object(); diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/jquery.atmosphere.js b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/jquery.atmosphere.js new file mode 100644 index 0000000000..eb94c9f6f5 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/jquery.atmosphere.js @@ -0,0 +1,534 @@ +/** + * 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. + */ +jQuery.atmosphere = function() +{ + var activeRequest; + $(window).unload(function() + { + if (activeRequest) + activeRequest.abort(); + }); + + return { + version : 0.7, + response : { + status: 200, + responseBody : '', + headers : [], + state : "messageReceived", + transport : "polling", + push : [], + error: null, + id : 0 + }, + + request : {}, + logLevel : 'info', + callbacks: [], + activeTransport : null, + websocket : null, + killHiddenIFrame : null, + + subscribe: function(url, callback, request) + { + jQuery.atmosphere.request = jQuery.extend({ + timeout: 300000, + method: 'GET', + headers: {}, + contentType : "text/html;charset=ISO-8859-1", + cache: true, + async: true, + ifModified: false, + callback: null, + dataType: '', + url : url, + data : '', + suspend : true, + maxRequest : 60, + lastIndex : 0, + logLevel : 'info', + requestCount : 0, + fallbackTransport : 'streaming', + transport : 'long-polling' + + }, request); + + logLevel = jQuery.atmosphere.request.logLevel || 'info'; + if (callback != null) { + jQuery.atmosphere.addCallback(callback); + jQuery.atmosphere.request.callback = callback; + } + + if (jQuery.atmosphere.request.transport != jQuery.atmosphere.activeTransport) { + jQuery.atmosphere.closeSuspendedConnection(); + } + jQuery.atmosphere.activeTransport = jQuery.atmosphere.request.transport; + + if (jQuery.atmosphere.request.transport != 'websocket') { + jQuery.atmosphere.executeRequest(); + } else if (jQuery.atmosphere.request.transport == 'websocket') { + if (!window.WebSocket) { + jQuery.atmosphere.log(logLevel, ["Websocket is not supported, using request.fallbackTransport"]); + jQuery.atmosphere.request.transport = jQuery.atmosphere.request.fallbackTransport; + jQuery.atmosphere.executeRequest(); + } + else { + jQuery.atmosphere.executeWebSocket(); + } + } + }, + + /** + * Always make sure one transport is used, not two at the same time except for Websocket. + */ + closeSuspendedConnection : function () { + if (activeRequest != null) { + activeRequest.abort(); + } + + if (jQuery.atmosphere.websocket != null) { + jQuery.atmosphere.websocket.close(); + jQuery.atmosphere.websocket = null; + } + }, + + executeRequest: function() + { + + if (jQuery.atmosphere.request.transport == 'streaming') { + if ($.browser.msie) { + jQuery.atmosphere.ieStreaming(); + return; + } else if ((typeof window.addEventStream) == 'function') { + jQuery.atmosphere.operaStreaming(); + return; + } + } + + if (jQuery.atmosphere.request.requestCount++ < jQuery.atmosphere.request.maxRequest) { + jQuery.atmosphere.response.push = function (url) + { + jQuery.atmosphere.request.callback = null; + jQuery.atmosphere.publish(url, null, jQuery.atmosphere.request); + }; + + var request = jQuery.atmosphere.request; + var response = jQuery.atmosphere.response; + if (request.transport != 'polling') { + response.transport = request.transport; + } + + var ajaxRequest; + var error = false; + if ($.browser.msie) { + var activexmodes = ["Msxml2.XMLHTTP", "Microsoft.XMLHTTP"] + for (var i = 0; i < activexmodes.length; i++) { + try { + ajaxRequest = new ActiveXObject(activexmodes[i]) + } + catch(e) { + } + } + } else if (window.XMLHttpRequest) { + ajaxRequest = new XMLHttpRequest(); + } + + if (request.suspend) { + activeRequest = ajaxRequest; + } + + ajaxRequest.open(request.method, request.url, true); + ajaxRequest.setRequestHeader("X-Atmosphere-Framework", jQuery.atmosphere.version); + ajaxRequest.setRequestHeader("X-Atmosphere-Transport", request.transport); + ajaxRequest.setRequestHeader("X-Cache-Date", new Date()); + + if (!$.browser.msie) { + ajaxRequest.onerror = function() + { + error = true; + try { + response.status = XMLHttpRequest.status; + } + catch(e) { + response.status = 404; + } + + response.state = "error"; + jQuery.atmosphere.invokeCallback(response); + ajaxRequest.abort(); + activeRequest = null; + } + } + + ajaxRequest.onreadystatechange = function() + { + var junkForWebkit = false; + var update = false; + if (ajaxRequest.readyState == 4) { + jQuery.atmosphere.request = request; + if (request.suspend && ajaxRequest.status == 200) { + jQuery.atmosphere.executeRequest(); + } + + if ($.browser.msie) { + update = true; + } + } else if (!$.browser.msie && ajaxRequest.readyState == 3 && ajaxRequest.status == 200) { + update = true; + } else { + clearTimeout(request.id); + } + + if (update) { + if (request.transport == 'streaming') { + response.responseBody = ajaxRequest.responseText.substring(request.lastIndex, ajaxRequest.responseText.length); + request.lastIndex = ajaxRequest.responseText.length; + + if (response.responseBody.indexOf("<!--") != -1) { + junkForWebkit = true; + } + + } else { + response.responseBody = ajaxRequest.responseText; + } + + if (response.responseBody.indexOf("parent.callback") != -1) { + var start = response.responseBody.indexOf("('") + 2; + var end = response.responseBody.indexOf("')"); + response.responseBody = response.responseBody.substring(start, end); + } + + if (junkForWebkit) return; + + try { + response.status = ajaxRequest.status; + response.headers = ajaxRequest.getAllResponseHeaders(); + } + catch(e) { + response.status = 404; + } + + if (request.suspend) { + response.state = "messageReceived"; + } else { + response.state = "messagePublished"; + } + jQuery.atmosphere.invokeCallback(response); + } + } + ajaxRequest.send(request.data); + + if (request.suspend) { + request.id = setTimeout(function() + { + ajaxRequest.abort(); + jQuery.atmosphere.subscribe(request.url, null, request); + + }, request.timeout); + } + } else { + jQuery.atmosphere.log(logLevel, ["Max re-connection reached."]); + } + }, + + operaStreaming: function() + { + + var url = jQuery.atmosphere.request.url; + var es = document.createElement('event-source'); + var response = jQuery.atmosphere.response; + + jQuery.atmosphere.response.push = function (url) + { + jQuery.atmosphere.request.transport = 'polling'; + jQuery.atmosphere.request.callback = null; + jQuery.atmosphere.publish(url, null, jQuery.atmosphere.request); + }; + + es.setAttribute('src', url); + // without this check opera 9.5 would make two connections. + if (opera.version() < 9.5) { + document.body.appendChild(es); + } + + var operaCallback = function (event) { + if (event.data) { + var junkForWebkit = false; + + response.responseBody = event.data; + if (event.data.indexOf("<!--") != -1) { + junkForWebkit = true; + } + + if (response.responseBody.indexOf("parent.callback") != -1) { + var start = response.responseBody.indexOf("('") + 2; + var end = response.responseBody.indexOf("')"); + response.responseBody = response.responseBody.substring(start, end); + } + + if (junkForWebkit) return; + + response.state = "messageReceived"; + jQuery.atmosphere.invokeCallback(response); + } + }; + + es.addEventListener('payload', operaCallback, false); + + }, + + ieStreaming : function() + { + var url = jQuery.atmosphere.request.url; + jQuery.atmosphere.response.push = function (url) + { + jQuery.atmosphere.request.transport = 'polling'; + jQuery.atmosphere.request.callback = null; + jQuery.atmosphere.publish(url, null, jQuery.atmosphere.request); + }; + + transferDoc = new ActiveXObject("htmlfile"); + transferDoc.open(); + transferDoc.close(); + var ifrDiv = transferDoc.createElement("div"); + transferDoc.body.appendChild(ifrDiv); + ifrDiv.innerHTML = "<iframe src='" + url + "'></iframe>"; + transferDoc.parentWindow.callback = jQuery.atmosphere.streamingCallback; + } + , + + streamingCallback : function(args) + { + var response = jQuery.atmosphere.response; + response.transport = "streaming"; + response.status = 200; + response.responseBody = args; + response.state = "messageReceived"; + + jQuery.atmosphere.invokeCallback(response); + } + , + + executeWebSocket : function() + { + var request = jQuery.atmosphere.request; + jQuery.atmosphere.log(logLevel, ["Invoking executeWebSocket"]); + jQuery.atmosphere.response.transport = "websocket"; + var url = jQuery.atmosphere.request.url; + var callback = jQuery.atmosphere.request.callback; + var location = url.replace('http:', 'ws:').replace('https:', 'wss:'); + + var websocket = new WebSocket(location); + jQuery.atmosphere.websocket = websocket; + + jQuery.atmosphere.response.push = function (url) + { + var data; + var ws = jQuery.atmosphere.websocket; + try { + data = jQuery.atmosphere.request.data; + ws.send(jQuery.atmosphere.request.data); + } catch (e) { + jQuery.atmosphere.log(logLevel, ["Websocket failed. Downgrading to Comet and resending " + data]); + // Websocket is not supported, reconnect using the fallback transport. + request.transport = request.fallbackTransport; + jQuery.atmosphere.request = request; + jQuery.atmosphere.executeRequest(); + + // Repost the data. + jQuery.atmosphere.request.suspend = false; + jQuery.atmosphere.request.method = 'POST'; + jQuery.atmosphere.request.data = data; + jQuery.atmosphere.response.state = 'messageReceived'; + jQuery.atmosphere.response.transport = request.fallbackTransport; + jQuery.atmosphere.publish(url, null, jQuery.atmosphere.request); + + ws.onclose = function(message) { + } + ws.close(); + } + }; + + websocket.onopen = function(message) + { + jQuery.atmosphere.response.state = 'openning'; + jQuery.atmosphere.invokeCallback(jQuery.atmosphere.response); + }; + + websocket.onmessage = function(message) + { + var data = message.data; + if (data.indexOf("parent.callback") != -1) { + var start = data.indexOf("('") + 2; + var end = data.indexOf("')"); + jQuery.atmosphere.response.responseBody = data.substring(start, end); + } + else { + jQuery.atmosphere.response.responseBody = data; + } + jQuery.atmosphere.invokeCallback(jQuery.atmosphere.response); + }; + + websocket.onerror = function(message) + { + jQuery.atmosphere.response.state = 'error'; + jQuery.atmosphere.invokeCallback(jQuery.atmosphere.response); + }; + + websocket.onclose = function(message) + { + jQuery.atmosphere.response.state = 'closed'; + jQuery.atmosphere.invokeCallback(jQuery.atmosphere.response); + }; + } + , + + addCallback: function(func) + { + if (jQuery.inArray(func, jQuery.atmosphere.callbacks) == -1) { + jQuery.atmosphere.callbacks.push(func); + } + } + , + + removeCallback: function(func) + { + if (jQuery.inArray(func, jQuery.atmosphere.callbacks) != -1) { + jQuery.atmosphere.callbacks.splice(index); + } + } + , + + invokeCallback: function(response) + { + var call = function (index, func) + { + func(response); + }; + + jQuery.atmosphere.log(logLevel, ["Invoking " + jQuery.atmosphere.callbacks.length + " callbacks"]); + if (jQuery.atmosphere.callbacks.length > 0) { + jQuery.each(jQuery.atmosphere.callbacks, call); + } + } + , + + publish: function(url, callback, request) + { + jQuery.atmosphere.request = jQuery.extend({ + connected: false, + timeout: 60000, + method: 'POST', + headers: {}, + cache: true, + async: true, + ifModified: false, + callback: null, + dataType: '', + url : url, + data : '', + suspend : false, + maxRequest : 60, + logLevel : 'info', + requestCount : 0, + transport: 'polling' + }, request); + + if (callback != null) { + jQuery.atmosphere.addCallback(callback); + } + jQuery.atmosphere.request.transport = 'polling'; + if (jQuery.atmosphere.request.transport != 'websocket') { + jQuery.atmosphere.executeRequest(); + } else if (jQuery.atmosphere.request.transport == 'websocket') { + if (!window.WebSocket) { + alert("WebSocket not supported by this browser"); + } + else { + jQuery.atmosphere.executeWebSocket(); + } + } + } + , + + unload: function (arg) { + if (window.addEventListener) { + document.addEventListener('unload', arg, false); + window.addEventListener('unload', arg, false); + } else { // IE + document.attachEvent('onunload', arg); + window.attachEvent('onunload', arg); + } + } + , + + kill_load_bar : function() { + if (jQuery.atmosphere.killHiddenIFrame == null) { + jQuery.atmosphere.killHiddenIFrame = document.createElement('iframe'); + var ifr = jQuery.atmosphere.killHiddenIFrame; + ifr.style.display = 'block'; + ifr.style.width = '0'; + ifr.style.height = '0'; + ifr.style.border = '0'; + ifr.style.margin = '0'; + ifr.style.padding = '0'; + ifr.style.overflow = 'hidden'; + ifr.style.visibility = 'hidden'; + } + document.body.appendChild(ifr); + ifr.src = 'about:blank'; + document.body.removeChild(ifr); + } + , + + log: function (level, args) + { + if (window.console) + { + var logger = window.console[level]; + if (typeof logger == 'function') + { + logger.apply(window.console, args); + } + } + } + , + + warn: function() + { + log('warn', arguments); + } + , + + + info :function() + { + if (logLevel != 'warn') + { + log('info', arguments); + } + } + , + + debug: function() + { + if (logLevel == 'debug') + { + log('debug', arguments); + } + } + } + +} + ();
\ No newline at end of file diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/jquery.json-2.2.min.js b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/jquery.json-2.2.min.js new file mode 100644 index 0000000000..bad4a0afa0 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/jquery.json-2.2.min.js @@ -0,0 +1,31 @@ + +(function($){$.toJSON=function(o) +{if(typeof(JSON)=='object'&&JSON.stringify) +return JSON.stringify(o);var type=typeof(o);if(o===null) +return"null";if(type=="undefined") +return undefined;if(type=="number"||type=="boolean") +return o+"";if(type=="string") +return $.quoteString(o);if(type=='object') +{if(typeof o.toJSON=="function") +return $.toJSON(o.toJSON());if(o.constructor===Date) +{var month=o.getUTCMonth()+1;if(month<10)month='0'+month;var day=o.getUTCDate();if(day<10)day='0'+day;var year=o.getUTCFullYear();var hours=o.getUTCHours();if(hours<10)hours='0'+hours;var minutes=o.getUTCMinutes();if(minutes<10)minutes='0'+minutes;var seconds=o.getUTCSeconds();if(seconds<10)seconds='0'+seconds;var milli=o.getUTCMilliseconds();if(milli<100)milli='0'+milli;if(milli<10)milli='0'+milli;return'"'+year+'-'+month+'-'+day+'T'+ +hours+':'+minutes+':'+seconds+'.'+milli+'Z"';} +if(o.constructor===Array) +{var ret=[];for(var i=0;i<o.length;i++) +ret.push($.toJSON(o[i])||"null");return"["+ret.join(",")+"]";} +var pairs=[];for(var k in o){var name;var type=typeof k;if(type=="number") +name='"'+k+'"';else if(type=="string") +name=$.quoteString(k);else +continue;if(typeof o[k]=="function") +continue;var val=$.toJSON(o[k]);pairs.push(name+":"+val);} +return"{"+pairs.join(", ")+"}";}};$.evalJSON=function(src) +{if(typeof(JSON)=='object'&&JSON.parse) +return JSON.parse(src);return eval("("+src+")");};$.secureEvalJSON=function(src) +{if(typeof(JSON)=='object'&&JSON.parse) +return JSON.parse(src);var filtered=src;filtered=filtered.replace(/\\["\\\/bfnrtu]/g,'@');filtered=filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']');filtered=filtered.replace(/(?:^|:|,)(?:\s*\[)+/g,'');if(/^[\],:{}\s]*$/.test(filtered)) +return eval("("+src+")");else +throw new SyntaxError("Error parsing JSON, source is not valid.");};$.quoteString=function(string) +{if(string.match(_escapeable)) +{return'"'+string.replace(_escapeable,function(a) +{var c=_meta[a];if(typeof c==='string')return c;c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"';} +return'"'+string+'"';};var _escapeable=/["\\\x00-\x1f\x7f-\x9f]/g;var _meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};})(jQuery);
\ No newline at end of file diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/test/java/org/apache/tuscany/sca/test/CometTestCase.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/test/java/org/apache/tuscany/sca/test/CometTestCase.java new file mode 100644 index 0000000000..56c6b9f4f1 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/test/java/org/apache/tuscany/sca/test/CometTestCase.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.test; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.apache.tuscany.sca.http.jetty.JettyServer; +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; + +/** + * Test case for the comet binding. + */ +public class CometTestCase extends TestCase { + + /** + * Test consisting in starting up a node containing services exposed via the + * comet binding. + */ + public void testComet() { + JettyServer.portDefault = 8085; + try { + final String location = ContributionLocationHelper.getContributionLocation("test.composite"); + final Node node = NodeFactory.newInstance().createNode("test.composite", new Contribution("c1", location)); + node.start(); + // System.out.println("Press any key to stop the node."); + // System.in.read(); + node.stop(); + } catch (final Exception e) { + e.printStackTrace(); + Assert.fail(); + } + } + +} diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/test/java/org/apache/tuscany/sca/test/StockService.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/test/java/org/apache/tuscany/sca/test/StockService.java new file mode 100644 index 0000000000..6d23479f30 --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/test/java/org/apache/tuscany/sca/test/StockService.java @@ -0,0 +1,28 @@ +/* + * 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.test; + +import org.oasisopen.sca.annotation.Remotable; + +@Remotable +public interface StockService { + + String getQuotes(); + +} diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/test/java/org/apache/tuscany/sca/test/StockServiceImpl.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/test/java/org/apache/tuscany/sca/test/StockServiceImpl.java new file mode 100644 index 0000000000..359d7dec0b --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/test/java/org/apache/tuscany/sca/test/StockServiceImpl.java @@ -0,0 +1,39 @@ +/* + * 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.test; + +import java.text.DecimalFormat; +import java.util.Date; +import java.util.Random; + +import org.oasisopen.sca.annotation.Service; + +@Service(StockService.class) +public class StockServiceImpl implements StockService { + + public static final int MAX_VALUE = 1000; + private final Random random = new Random(new Date().getTime()); + + @Override + public String getQuotes() { + final Double value = Math.abs(this.random.nextDouble() * this.random.nextInt(StockServiceImpl.MAX_VALUE)); + return "ASF" + "#" + Double.valueOf(new DecimalFormat("#.##").format(value)); + } + +} diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/test/resources/test.composite b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/test/resources/test.composite new file mode 100644 index 0000000000..15026167be --- /dev/null +++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/test/resources/test.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://docs.oasis-open.org/ns/opencsa/sca/200912" + xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.1" + targetNamespace="http://samples" + name="Stock"> + + <component name="test"> + <implementation.java class="org.apache.tuscany.sca.test.StockServiceImpl"/> + <service name="StockService"> + <interface.java interface="org.apache.tuscany.sca.test.StockService"/> + <tuscany:binding.comet/> + </service> + </component> + +</composite>
\ No newline at end of file |