summaryrefslogtreecommitdiffstats
path: root/sca-java-2.x/trunk/modules/binding-comet-runtime
diff options
context:
space:
mode:
authorfmoga <fmoga@13f79535-47bb-0310-9956-ffa450edef68>2011-05-24 14:27:45 +0000
committerfmoga <fmoga@13f79535-47bb-0310-9956-ffa450edef68>2011-05-24 14:27:45 +0000
commite03b437442335d33ad52d31a750701933fb021d0 (patch)
tree7d77a8472ff525a2cbe2a05f91a5e85732f3f2e9 /sca-java-2.x/trunk/modules/binding-comet-runtime
parent17fb39cd0fe95baff5453bd12b2dab14d6018efc (diff)
Improve comet support. Add status to callback return type to determine when browser client has closed the page. Upgrade to atmosphere-jquery-0.7.1. Add support for multiple tabs. Fix and improve reliability of long polling technique.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1127080 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sca-java-2.x/trunk/modules/binding-comet-runtime')
-rw-r--r--sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometComponentContext.java5
-rw-r--r--sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometInvoker.java36
-rw-r--r--sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometMessageContext.java51
-rw-r--r--sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometServiceBindingProvider.java100
-rw-r--r--sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/callback/CometCallback.java4
-rw-r--r--sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/callback/Status.java5
-rw-r--r--sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/handler/CometBindingHandler.java46
-rw-r--r--sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/cometComponentContext.js38
-rw-r--r--sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/resources/jquery.atmosphere.js313
9 files changed, 374 insertions, 224 deletions
diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometComponentContext.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometComponentContext.java
index ce19da7e7b..9e93457c7e 100644
--- a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometComponentContext.java
+++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometComponentContext.java
@@ -24,9 +24,14 @@ import java.util.concurrent.ConcurrentHashMap;
import org.apache.tuscany.sca.interfacedef.Operation;
import org.apache.tuscany.sca.runtime.RuntimeEndpoint;
+import org.atmosphere.cpr.Broadcaster;
+
+import com.google.gson.Gson;
public class CometComponentContext {
+ public static Map<String, Broadcaster> broadcasters = new ConcurrentHashMap<String, Broadcaster>();
+ public static Gson gson = new Gson();
private Map<String, RuntimeEndpoint> endpoints;
private Map<String, Operation> operations;
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
index 5e6375480e..99eb30892e 100644
--- 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
@@ -20,11 +20,13 @@
package org.apache.tuscany.sca.binding.comet.runtime;
import org.apache.tuscany.sca.assembly.EndpointReference;
-import org.apache.tuscany.sca.binding.comet.runtime.handler.CometBindingHandler;
+import org.apache.tuscany.sca.binding.comet.runtime.callback.Status;
+import org.apache.tuscany.sca.core.invocation.Constants;
import org.apache.tuscany.sca.core.invocation.impl.MessageImpl;
import org.apache.tuscany.sca.interfacedef.Operation;
import org.apache.tuscany.sca.invocation.Invoker;
import org.apache.tuscany.sca.invocation.Message;
+import org.atmosphere.cpr.Broadcaster;
public class CometInvoker implements Invoker {
@@ -38,18 +40,28 @@ public class CometInvoker implements Invoker {
@Override
public Message invoke(final Message msg) {
- String operation = msg.getOperation().getName();
- CometMessageContext context = msg.getBindingContext();
- CometBindingHandler handler = context.getCometHandler();
- Message message = new MessageImpl();
- if (operation.equals("sendResponse")) {
- String callbackMethod = context.getCallbackMethod();
+ return handleSendMessage(msg);
+ }
+
+ private Message handleSendMessage(Message msg) {
+ String sessionId = (String) msg.getHeaders().get(Constants.RELATES_TO);
+ Broadcaster broadcaster = CometComponentContext.broadcasters.get(sessionId);
+ Message response = new MessageImpl();
+ if (broadcaster == null) {
+ System.out.println("Broadcaster already removed.");
+ response.setBody(Status.CLIENT_DISCONNECTED);
+ } else if (broadcaster.getAtmosphereResources().isEmpty()) {
+ System.out.println("Removing broadcaster " + sessionId + "...");
+ CometComponentContext.broadcasters.remove(sessionId);
+ response.setBody(Status.CLIENT_DISCONNECTED);
+ } else {
+ System.out.println("Using broadcaster " + sessionId + "...");
+ String callbackMethod = msg.getTo().getURI();
Object[] body = msg.getBody();
- handler.respondToClient(callbackMethod, body[0]);
- } else if (operation.equals("isClientConnected")) {
- message.setBody(handler.isClientConnected());
+ broadcaster.broadcast(callbackMethod + "($.secureEvalJSON('" + CometComponentContext.gson.toJson(body[0])
+ + "'))");
+ response.setBody(Status.OK);
}
- return message;
+ return response;
}
-
}
diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometMessageContext.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometMessageContext.java
deleted file mode 100644
index 21dcc9287f..0000000000
--- a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/CometMessageContext.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.runtime.handler.CometBindingHandler;
-
-public class CometMessageContext {
-
- private CometBindingHandler cometHandler;
-
- private String callbackMethod;
-
- public CometMessageContext(CometBindingHandler cometHandler, String callbackMethod) {
- this.cometHandler = cometHandler;
- this.callbackMethod = callbackMethod;
- }
-
- public CometBindingHandler getCometHandler() {
- return cometHandler;
- }
-
- public void setCometHandler(CometBindingHandler cometHandler) {
- this.cometHandler = cometHandler;
- }
-
- public String getCallbackMethod() {
- return callbackMethod;
- }
-
- public void setCallbackMethod(String callbackMethod) {
- this.callbackMethod = callbackMethod;
- }
-
-}
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
index 7b6a2f6e1b..96b688aa4f 100644
--- 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
@@ -33,59 +33,63 @@ import org.apache.tuscany.sca.runtime.RuntimeEndpoint;
*/
public class CometServiceBindingProvider implements ServiceBindingProvider {
- /**
- * Service's endpoint.
- */
- private final RuntimeEndpoint endpoint;
+ /**
+ * Service's endpoint.
+ */
+ private final RuntimeEndpoint endpoint;
- /**
- * The underlying servlet host.
- */
- private final ServletHost servletHost;
+ /**
+ * 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;
- }
+ /**
+ * 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() {
- String deployedURI = ServletFactory.registerServlet(this.servletHost);
- endpoint.setDeployedURI(deployedURI);
- 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.registerOperation(this.endpoint, operation);
- }
- }
+ /**
+ * This method is used to start the provider.
+ */
+ @Override
+ public void start() {
+ String deployedURI = ServletFactory.registerServlet(this.servletHost);
+ endpoint.setDeployedURI(deployedURI);
+ 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.registerOperation(this.endpoint, operation);
+ }
+ }
- /**
- * This method is used to stop the provider.
- */
- @Override
- public void stop() {
- ServletFactory.unregisterServlet(this.servletHost);
- }
+ /**
+ * This method is used to stop the provider.
+ */
+ @Override
+ public void stop() {
+ ServletFactory.unregisterServlet(this.servletHost);
+ }
- @Override
- public InterfaceContract getBindingInterfaceContract() {
- return endpoint.getService().getInterfaceContract();
- }
+ @Override
+ public InterfaceContract getBindingInterfaceContract() {
+ return endpoint.getService().getInterfaceContract();
+ }
- @Override
- public boolean supportsOneWayInvocation() {
- return true;
- }
+ @Override
+ public boolean supportsOneWayInvocation() {
+ // set to false so the runtime will add a nonBlocking interceptor to
+ // handle @OneWay calls
+ return false;
+ }
}
diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/callback/CometCallback.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/callback/CometCallback.java
index fb9facfd35..cf457e9d7b 100644
--- a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/callback/CometCallback.java
+++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/callback/CometCallback.java
@@ -24,8 +24,6 @@ import org.oasisopen.sca.annotation.Remotable;
@Remotable
public interface CometCallback {
- void sendResponse(Object response);
-
- boolean isClientConnected();
+ Status sendMessage(Object message);
}
diff --git a/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/callback/Status.java b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/callback/Status.java
new file mode 100644
index 0000000000..6c29d0fa2e
--- /dev/null
+++ b/sca-java-2.x/trunk/modules/binding-comet-runtime/src/main/java/org/apache/tuscany/sca/binding/comet/runtime/callback/Status.java
@@ -0,0 +1,5 @@
+package org.apache.tuscany.sca.binding.comet.runtime.callback;
+
+public enum Status {
+ OK, CLIENT_DISCONNECTED
+}
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
index a62d73d467..0d47b72f8b 100644
--- 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
@@ -32,24 +32,27 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
import org.apache.tuscany.sca.assembly.EndpointReference;
import org.apache.tuscany.sca.binding.comet.runtime.CometComponentContext;
-import org.apache.tuscany.sca.binding.comet.runtime.CometMessageContext;
import org.apache.tuscany.sca.binding.comet.runtime.ServletFactory;
import org.apache.tuscany.sca.core.assembly.impl.RuntimeEndpointImpl;
import org.apache.tuscany.sca.core.assembly.impl.RuntimeEndpointReferenceImpl;
+import org.apache.tuscany.sca.core.invocation.Constants;
import org.apache.tuscany.sca.core.invocation.impl.MessageImpl;
import org.apache.tuscany.sca.interfacedef.DataType;
import org.apache.tuscany.sca.interfacedef.Operation;
import org.apache.tuscany.sca.invocation.Message;
import org.apache.tuscany.sca.runtime.RuntimeEndpoint;
-import org.atmosphere.annotation.Broadcast;
+import org.atmosphere.cache.SessionBroadcasterCache;
import org.atmosphere.cpr.Broadcaster;
import org.atmosphere.cpr.DefaultBroadcaster;
+import org.atmosphere.cpr.DefaultBroadcasterFactory;
+import org.atmosphere.jersey.JerseyBroadcaster;
import org.atmosphere.jersey.SuspendResponse;
+import org.atmosphere.jersey.util.JerseyBroadcasterUtil;
-import com.google.gson.Gson;
import com.sun.jersey.spi.container.servlet.PerSession;
/**
@@ -67,11 +70,6 @@ public class CometBindingHandler {
private Broadcaster broadcaster;
/**
- * JSON converter.
- */
- private Gson gson = new Gson();
-
- /**
* The underlying servlet context.
*/
@Context
@@ -82,6 +80,15 @@ public class CometBindingHandler {
private CometComponentContext context;
+ @GET
+ @Path("/sessionId")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String establishSessionId() {
+ request.getSession().invalidate();
+ request.getSession(true);
+ return "OK";
+ }
+
/**
* Method called at comet connect time. This suspends the response and keeps
* the connection opened.
@@ -89,12 +96,14 @@ public class CometBindingHandler {
* @return the suspended response
*/
@GET
+ @Path("/connect")
public SuspendResponse<String> connect() {
System.out.println("-- connect -- Session Id: " + request.getSession().getId());
if (broadcaster == null) {
- broadcaster = new DefaultBroadcaster();
+ broadcaster = new JerseyBroadcaster();
context = (CometComponentContext) sc.getAttribute(ServletFactory.COMET_COMPONENT_CONTEXT_KEY);
}
+ CometComponentContext.broadcasters.put(request.getSession().getId(), broadcaster);
return new SuspendResponse.SuspendResponseBuilder<String>().broadcaster(this.broadcaster).outputComments(true)
.build();
}
@@ -117,7 +126,6 @@ public class CometBindingHandler {
*/
@POST
@Path("/{service}/{method}")
- @Broadcast
public void handleRequest(@PathParam("service") final String service, @PathParam("method") final String method,
@FormParam("callback") final String callbackMethod, @FormParam("params") final String jsonData)
throws InvocationTargetException {
@@ -128,6 +136,7 @@ public class CometBindingHandler {
final Object[] args = decodeJsonDataForOperation(jsonData, operation);
Message msg = createMessageWithMockedCometReference(args, callbackMethod);
+ System.out.println("CometBindingHandler thread id: " + Thread.currentThread().getId());
wire.invoke(operation, msg);
}
@@ -144,7 +153,7 @@ public class CometBindingHandler {
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());
+ args[index] = CometComponentContext.gson.fromJson(json[index], dataType.getPhysical());
index++;
}
return args;
@@ -161,11 +170,12 @@ public class CometBindingHandler {
*/
private Message createMessageWithMockedCometReference(Object[] args, String callbackMethod) {
Message msg = new MessageImpl();
+ msg.getHeaders().put(Constants.MESSAGE_ID, request.getSession().getId());
msg.setBody(args);
- CometMessageContext messageContext = new CometMessageContext(this, callbackMethod);
- msg.setBindingContext(messageContext);
EndpointReference re = new RuntimeEndpointReferenceImpl();
- re.setCallbackEndpoint(new RuntimeEndpointImpl());
+ RuntimeEndpointImpl callbackEndpoint = new RuntimeEndpointImpl();
+ callbackEndpoint.setURI(callbackMethod);
+ re.setCallbackEndpoint(callbackEndpoint);
msg.setFrom(re);
return msg;
}
@@ -211,12 +221,4 @@ public class CometBindingHandler {
return objects.toArray(new String[] {});
}
- public void respondToClient(String callbackMethod, Object response) {
- broadcaster.broadcast(callbackMethod + "($.secureEvalJSON('" + this.gson.toJson(response) + "'))");
- }
-
- public boolean isClientConnected() {
- return !broadcaster.getAtmosphereResources().isEmpty();
- }
-
}
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
index 9d9254199e..2518ee4367 100644
--- 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
@@ -1,21 +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
+ * 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
+ * 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.
+ * 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() {
@@ -24,10 +22,11 @@ this.TuscanyComet = {
appUrl: 'tuscany-comet',
connectedEndpoint : null,
connect : function(transport) {
- $.atmosphere.subscribe(document.location.toString() + this.appUrl,
+ $.atmosphere.subscribe(document.location.toString() + this.appUrl + "/connect",
this.callback,
$.atmosphere.request = {
- transport : transport
+ transport : transport,
+ maxRequest: 1000000000
});
this.connectedEndpoint = $.atmosphere.response;
},
@@ -45,4 +44,11 @@ this.TuscanyComet = {
}
};
+
+$.ajax({
+ url: document.location.toString() + this.TuscanyComet.appUrl + '/sessionId',
+ type: 'GET',
+ async: false,
+});
+
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
index eb94c9f6f5..a52e0793b7 100644
--- 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
@@ -3,7 +3,7 @@
* 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
+ * 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,
@@ -14,10 +14,18 @@
jQuery.atmosphere = function()
{
var activeRequest;
- $(window).unload(function()
+ jQuery(window).unload(function()
{
- if (activeRequest)
+ if (activeRequest){
activeRequest.abort();
+ }
+
+ if( !(typeof(transferDoc) == 'undefined') ){
+ if(transferDoc != null){
+ transferDoc = null;
+ CollectGarbage();
+ }
+ }
});
return {
@@ -34,6 +42,7 @@ jQuery.atmosphere = function()
},
request : {},
+ abordingConnection: false,
logLevel : 'info',
callbacks: [],
activeTransport : null,
@@ -46,7 +55,7 @@ jQuery.atmosphere = function()
timeout: 300000,
method: 'GET',
headers: {},
- contentType : "text/html;charset=ISO-8859-1",
+ contentType : '',
cache: true,
async: true,
ifModified: false,
@@ -57,10 +66,11 @@ jQuery.atmosphere = function()
suspend : true,
maxRequest : 60,
lastIndex : 0,
- logLevel : 'info',
+ logLevel : 'info',
requestCount : 0,
fallbackTransport : 'streaming',
- transport : 'long-polling'
+ transport : 'long-polling',
+ webSocketImpl: null
}, request);
@@ -78,9 +88,10 @@ jQuery.atmosphere = function()
if (jQuery.atmosphere.request.transport != 'websocket') {
jQuery.atmosphere.executeRequest();
} else if (jQuery.atmosphere.request.transport == 'websocket') {
- if (!window.WebSocket) {
+ if (jQuery.atmosphere.request.webSocketImpl == null && !window.WebSocket) {
jQuery.atmosphere.log(logLevel, ["Websocket is not supported, using request.fallbackTransport"]);
jQuery.atmosphere.request.transport = jQuery.atmosphere.request.fallbackTransport;
+ jQuery.atmosphere.response.transport = jQuery.atmosphere.request.fallbackTransport;
jQuery.atmosphere.executeRequest();
}
else {
@@ -93,6 +104,7 @@ jQuery.atmosphere = function()
* Always make sure one transport is used, not two at the same time except for Websocket.
*/
closeSuspendedConnection : function () {
+ jQuery.atmosphere.abordingConnection = true;
if (activeRequest != null) {
activeRequest.abort();
}
@@ -101,16 +113,24 @@ jQuery.atmosphere = function()
jQuery.atmosphere.websocket.close();
jQuery.atmosphere.websocket = null;
}
+ jQuery.atmosphere.abordingConnection = false;
+
+ if (!(typeof(transferDoc) == 'undefined')) {
+ if (transferDoc != null) {
+ transferDoc = null;
+ CollectGarbage();
+ }
+ }
},
executeRequest: function()
{
if (jQuery.atmosphere.request.transport == 'streaming') {
- if ($.browser.msie) {
+ if (jQuery.browser.msie) {
jQuery.atmosphere.ieStreaming();
return;
- } else if ((typeof window.addEventStream) == 'function') {
+ } else if (jQuery.browser.opera) {
jQuery.atmosphere.operaStreaming();
return;
}
@@ -131,8 +151,8 @@ jQuery.atmosphere = function()
var ajaxRequest;
var error = false;
- if ($.browser.msie) {
- var activexmodes = ["Msxml2.XMLHTTP", "Microsoft.XMLHTTP"]
+ if (jQuery.browser.msie) {
+ var activexmodes = ["Msxml2.XMLHTTP", "Microsoft.XMLHTTP"];
for (var i = 0; i < activexmodes.length; i++) {
try {
ajaxRequest = new ActiveXObject(activexmodes[i])
@@ -151,9 +171,17 @@ jQuery.atmosphere = function()
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());
+ ajaxRequest.setRequestHeader("X-Cache-Date", new Date().getTime());
- if (!$.browser.msie) {
+ if (jQuery.atmosphere.request.contentType != '') {
+ ajaxRequest.setRequestHeader("Content-Type", jQuery.atmosphere.request.contentType);
+ }
+
+ for(var x in request.headers) {
+ ajaxRequest.setRequestHeader(x, request.headers[x]);
+ }
+
+ if (!jQuery.browser.msie) {
ajaxRequest.onerror = function()
{
error = true;
@@ -173,6 +201,8 @@ jQuery.atmosphere = function()
ajaxRequest.onreadystatechange = function()
{
+ if (jQuery.atmosphere.abordingConnection) return;
+
var junkForWebkit = false;
var update = false;
if (ajaxRequest.readyState == 4) {
@@ -181,10 +211,10 @@ jQuery.atmosphere = function()
jQuery.atmosphere.executeRequest();
}
- if ($.browser.msie) {
+ if (jQuery.browser.msie) {
update = true;
}
- } else if (!$.browser.msie && ajaxRequest.readyState == 3 && ajaxRequest.status == 200) {
+ } else if (!jQuery.browser.msie && ajaxRequest.readyState == 3 && ajaxRequest.status == 200) {
update = true;
} else {
clearTimeout(request.id);
@@ -193,24 +223,24 @@ jQuery.atmosphere = function()
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;
- }
+ if (request.lastIndex == 0 && response.responseBody.indexOf("<!-- Welcome to the Atmosphere Framework.") != -1) {
+ var endOfJunk = "<!-- EOD -->";
+ var endOfJunkLenght = "<!-- EOD -->".length;
+ var junkEnd = response.responseBody.indexOf(endOfJunk) + endOfJunkLenght;
+ if (junkEnd != ajaxRequest.responseText.length) {
+ response.responseBody = response.responseBody.substring(junkEnd);
+ } else {
+ junkForWebkit = true;
+ }
+ }
+ request.lastIndex = ajaxRequest.responseText.length;
+ if (junkForWebkit) return;
} 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();
@@ -224,9 +254,22 @@ jQuery.atmosphere = function()
} else {
response.state = "messagePublished";
}
- jQuery.atmosphere.invokeCallback(response);
+
+ if (response.responseBody.indexOf("parent.callback") != -1) {
+ var index = 0;
+ var responseBody = response.responseBody;
+ while ( responseBody.indexOf("('", index) != -1) {
+ var start = responseBody.indexOf("('", index) + 2;
+ var end = responseBody.indexOf("')", index);
+ response.responseBody = responseBody.substring(start, end);
+ index = end + 2;
+ jQuery.atmosphere.invokeCallback(response);
+ }
+ } else {
+ jQuery.atmosphere.invokeCallback(response);
+ }
}
- }
+ };
ajaxRequest.send(request.data);
if (request.suspend) {
@@ -245,51 +288,54 @@ jQuery.atmosphere = function()
operaStreaming: function()
{
- var url = jQuery.atmosphere.request.url;
- var es = document.createElement('event-source');
- var response = jQuery.atmosphere.response;
+ jQuery.atmosphere.closeSuspendedConnection();
+ var url = jQuery.atmosphere.request.url;
+ var callback = jQuery.atmosphere.request.callback;
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);
+ function init()
+ {
+ var iframe = document.createElement("iframe");
+ iframe.style.width = "0px";
+ iframe.style.height = "0px";
+ iframe.style.border = "0px";
+ iframe.id = "__atmosphere";
+ document.body.appendChild(iframe);
+ var d;
+ if (iframe.contentWindow) {
+ d = iframe.contentWindow.document;
+ } else if (iframe.document) {
+ d = iframe.document;
+ } else if (iframe.contentDocument) {
+ d = iframe.contentDocument;
}
- };
- es.addEventListener('payload', operaCallback, false);
+ if (/\?/i.test(url)) url += "&";
+ else url += "?";
+ url += "callback=jquery.atmosphere.streamingCallback";
+ iframe.src = url;
+ }
+
+ init();
},
ieStreaming : function()
{
+
+ if (!(typeof(transferDoc) == 'undefined')) {
+ if (transferDoc != null) {
+ transferDoc = null;
+ CollectGarbage();
+ }
+ }
+
var url = jQuery.atmosphere.request.url;
jQuery.atmosphere.response.push = function (url)
{
@@ -298,6 +344,7 @@ jQuery.atmosphere = function()
jQuery.atmosphere.publish(url, null, jQuery.atmosphere.request);
};
+ //Must not use var here to avoid IE from disconnecting
transferDoc = new ActiveXObject("htmlfile");
transferDoc.open();
transferDoc.close();
@@ -323,13 +370,24 @@ jQuery.atmosphere = function()
executeWebSocket : function()
{
var request = jQuery.atmosphere.request;
+ var success = false;
jQuery.atmosphere.log(logLevel, ["Invoking executeWebSocket"]);
jQuery.atmosphere.response.transport = "websocket";
var url = jQuery.atmosphere.request.url;
var callback = jQuery.atmosphere.request.callback;
+
+ if (url.indexOf("http") == -1 && url.indexOf("ws") == -1) {
+ url = jQuery.atmosphere.parseUri(document.location, url);
+ }
var location = url.replace('http:', 'ws:').replace('https:', 'wss:');
- var websocket = new WebSocket(location);
+ var websocket = null;
+ if (jQuery.atmosphere.request.webSocketImpl != null) {
+ websocket = jQuery.atmosphere.request.webSocketImpl;
+ } else {
+ websocket = new WebSocket(location);
+ }
+
jQuery.atmosphere.websocket = websocket;
jQuery.atmosphere.response.push = function (url)
@@ -343,25 +401,19 @@ jQuery.atmosphere = function()
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.response.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)
{
+ success = true;
jQuery.atmosphere.response.state = 'openning';
jQuery.atmosphere.invokeCallback(jQuery.atmosphere.response);
};
@@ -388,8 +440,19 @@ jQuery.atmosphere = function()
websocket.onclose = function(message)
{
- jQuery.atmosphere.response.state = 'closed';
- jQuery.atmosphere.invokeCallback(jQuery.atmosphere.response);
+ if (!success) {
+ var data = jQuery.atmosphere.request.data;
+ 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.response.transport = request.fallbackTransport;
+
+ jQuery.atmosphere.request = request;
+ jQuery.atmosphere.executeRequest();
+ } else {
+ jQuery.atmosphere.response.state = 'closed';
+ jQuery.atmosphere.invokeCallback(jQuery.atmosphere.response);
+ }
};
}
,
@@ -430,6 +493,7 @@ jQuery.atmosphere = function()
connected: false,
timeout: 60000,
method: 'POST',
+ contentType : '',
headers: {},
cache: true,
async: true,
@@ -440,7 +504,7 @@ jQuery.atmosphere = function()
data : '',
suspend : false,
maxRequest : 60,
- logLevel : 'info',
+ logLevel : 'info',
requestCount : 0,
transport: 'polling'
}, request);
@@ -528,6 +592,111 @@ jQuery.atmosphere = function()
log('debug', arguments);
}
}
+ ,
+
+ close : function()
+ {
+ jQuery.atmosphere.closeSuspendedConnection();
+ },
+
+
+ parseUri : function( baseUrl , uri )
+ {
+ var protocol = window.location.protocol;
+ var host = window.location.host;
+ var path = window.location.pathname;
+ var parameters = {};
+ var anchor = '';
+ var pos;
+
+ if ( (pos = uri.search( /\:/ )) >= 0 )
+ {
+ protocol = uri.substring( 0, pos + 1 );
+ uri = uri.substring( pos + 1 );
+ }
+
+ if ( (pos = uri.search( /\#/ )) >= 0 )
+ {
+ anchor = uri.substring( pos + 1 );
+ uri = uri.substring( 0, pos );
+ }
+
+ if ( (pos = uri.search( /\?/ )) >= 0 )
+ {
+ var paramsStr = uri.substring( pos + 1 ) + '&;';
+ uri = uri.substring( 0, pos );
+ while ( (pos = paramsStr.search( /\&/ )) >= 0 )
+ {
+ var paramStr = paramsStr.substring( 0, pos );
+ paramsStr = paramsStr.substring( pos + 1 );
+
+ if ( paramStr.length )
+ {
+ var equPos = paramStr.search( /\=/ );
+ if ( equPos < 0 )
+ {
+ parameters[paramStr] = '';
+ }
+ else
+ {
+ parameters[paramStr.substring( 0, equPos )] =
+ decodeURIComponent( paramStr.substring( equPos + 1 ) );
+ }
+ }
+ }
+ }
+
+ if ( uri.search( /\/\// ) == 0 )
+ {
+ uri = uri.substring( 2 );
+ if ( (pos = uri.search( /\// )) >= 0 )
+ {
+ host = uri.substring( 0, pos );
+ path = uri.substring( pos );
+ }
+ else
+ {
+ host = uri;
+ path = '/';
+ }
+ } else if ( uri.search( /\// ) == 0 )
+ {
+ path = uri;
+ }
+
+ else // relative to directory
+ {
+ var p = path.lastIndexOf( '/' );
+ if ( p < 0 )
+ {
+ path = '/';
+ } else if ( p < path.length - 1 )
+ {
+ path = path.substring( 0, p + 1 );
+ }
+
+ while ( uri.search( /\.\.\// ) == 0 )
+ {
+ var p = path.lastIndexOf( '/', path.lastIndexOf( '/' ) - 1 );
+ if ( p>= 0 )
+ {
+ path = path.substring( 0, p + 1 );
+ }
+ uri = uri.substring( 3 );
+ }
+ path = path + uri;
+ }
+
+ var uri = protocol + '//' + host + path;
+ var div = '?';
+ for ( var key in parameters )
+ {
+ uri += div + key + '=' + encodeURIComponent( parameters[key] );
+ div = '&';
+ }
+ return uri;
+ }
+
}
}