You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
354 lines
14 KiB
354 lines
14 KiB
/** |
|
* |
|
* 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. |
|
*/ |
|
|
|
// AMQ Ajax Adapter for jQuery |
|
// This class provides an adapter interface for the jquery library to perform |
|
// some of the library-dependent tasks...namely logging and ajax. |
|
|
|
var org = org || {}; |
|
org.activemq = org.activemq || {}; |
|
|
|
org.activemq.AmqAdapter = { |
|
|
|
init: function(options) { |
|
}, |
|
|
|
/** |
|
* Implement this method to make an AJAX call to the AjaxServlet. An |
|
* options object will accompany this class and will contain the properties |
|
* that describe the details of the AJAX call. The options object will |
|
* have the following properties: |
|
* |
|
* - method: 'get' or 'post' |
|
* - data: query data to accompany the post or get. |
|
* - success: A callback function that is invoked upon successful |
|
* completion of the AJAX call. The parameter is: |
|
* - data: The result of the AJAX call. In the case of XML |
|
* data should resolve to a Document element. |
|
* - error: A callback when some type of error occurs. The callback |
|
* function's parameters should be: |
|
* - xhr: The XmlHttpRequest object. |
|
* - status: A text string of the status. |
|
* - ex: The exception that caused the error. |
|
*/ |
|
ajax: function(uri, options) { |
|
if (options.method == 'post') { |
|
jQuery.ajax({ |
|
type: "POST", |
|
url: uri, |
|
data: options.data, |
|
success: options.success || function(){}, |
|
error: options.error || function(){}, |
|
beforeSend: function(xhr) { |
|
/* Force "Connection: close" for Mozilla browsers to work around |
|
* a bug where XMLHttpRequest sends an incorrect Content-length |
|
* header. See Mozilla Bugzilla #246651. |
|
*/ |
|
if (jQuery.browser.mozilla) |
|
xhr.setRequestHeader("Connection", 'close'); |
|
} |
|
}); |
|
} else { |
|
jQuery.ajax({ |
|
type: "GET", |
|
url: uri, |
|
data: options.data, |
|
success: options.success || function(){}, |
|
error: options.error || function(){}, |
|
dataType: 'xml' |
|
}); |
|
} |
|
}, |
|
|
|
log: function(message, exception) { |
|
if (typeof console != 'undefined' && console.log) |
|
console.log("AMQAJAX: " + message); |
|
} |
|
}; |
|
|
|
/** |
|
* |
|
* 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. |
|
*/ |
|
|
|
// AMQ Ajax handler |
|
// This class provides the main API for using the Ajax features of AMQ. It |
|
// allows JMS messages to be sent and received from javascript when used |
|
// with the org.apache.activemq.web.MessageListenerServlet. |
|
// |
|
// This version of the file provides an adapter interface for the jquery library |
|
// and a namespace for the Javascript file, private/public variables and |
|
// methods, and other scripting niceties. -- jim cook 2007/08/28 |
|
|
|
var org = org || {}; |
|
org.activemq = org.activemq || {}; |
|
|
|
org.activemq.Amq = function() { |
|
var connectStatusHandler; |
|
|
|
// Just a shortcut to eliminate some redundant typing. |
|
var adapter = org.activemq.AmqAdapter; |
|
|
|
if (typeof adapter == 'undefined') |
|
throw "An org.activemq.AmqAdapter must be loaded beforehand!"; |
|
|
|
// The URI of the AjaxServlet. |
|
var uri; |
|
|
|
// The number of seconds that the long-polling socket will stay connected. |
|
// Best to keep this to a value less than one minute. |
|
var timeout; |
|
|
|
// Poll delay. if set to positive integer, this is the time to wait in ms |
|
// before sending the next poll after the last completes. |
|
var pollDelay; |
|
|
|
// Inidicates whether logging is active or not. Not by default. |
|
var logging = false; |
|
|
|
// 5 second delay if an error occurs during poll. This could be due to |
|
// server capacity problems or a timeout condition. |
|
var pollErrorDelay = 5000; |
|
|
|
// Map of handlers that will respond to message receipts. The id used during |
|
// addListener(id, destination, handler) is used to key the callback |
|
// handler. |
|
var messageHandlers = {}; |
|
|
|
// Indicates whether an AJAX post call is in progress. |
|
var batchInProgress = false; |
|
|
|
// A collection of pending messages that accumulate when an AJAX call is in |
|
// progress. These messages will be delivered as soon as the current call |
|
// completes. The array contains objects in the format { destination, |
|
// message, messageType }. |
|
var messageQueue = []; |
|
|
|
/** |
|
* Iterate over the returned XML and for each message in the response, |
|
* invoke the handler with the matching id. |
|
*/ |
|
var messageHandler = function(data) { |
|
var response = data.getElementsByTagName("ajax-response"); |
|
if (response != null && response.length == 1) { |
|
connectStatusHandler(true); |
|
var responses = response[0].childNodes; // <response> |
|
for (var i = 0; i < responses.length; i++) { |
|
var responseElement = responses[i]; |
|
|
|
// only process nodes of type element..... |
|
if (responseElement.nodeType != 1) continue; |
|
|
|
var id = responseElement.getAttribute('id'); |
|
|
|
var handler = messageHandlers[id]; |
|
|
|
if (logging && handler == null) { |
|
adapter.log('No handler found to match message with id = ' + id); |
|
continue; |
|
} |
|
|
|
// Loop thru and handle each <message> element or (defragmented) text elements |
|
var text = ""; |
|
for (var j = 0; j < responseElement.childNodes.length; j++) { |
|
if (responseElement.childNodes[j].nodeType == 3 /* TextNode */) |
|
text += responseElement.childNodes[j].nodeValue; |
|
else { |
|
if (text != "") { |
|
handler(text); |
|
text = ""; |
|
} |
|
handler(responseElement.childNodes[j]); |
|
} |
|
} |
|
if (text != "") |
|
handler(text); |
|
} |
|
} |
|
}; |
|
|
|
var errorHandler = function(xhr, status, ex) { |
|
connectStatusHandler(false); |
|
if (logging) |
|
adapter.log('Error occurred in AJAX call. HTTP result: ' + xhr.status + ', status: ' + status); |
|
} |
|
|
|
var pollErrorHandler = function(xhr, status, ex) { |
|
connectStatusHandler(false); |
|
if (status === 'error' && xhr.status === 0) { |
|
if (logging) |
|
adapter.log('Server connection dropped.'); |
|
setTimeout(function() { sendPoll(); }, pollErrorDelay); |
|
return; |
|
} |
|
if (logging) |
|
adapter.log('Error occurred in AJAX call (poll). HTTP result: ' + xhr.status + ', status: ' + status); |
|
setTimeout(function() { sendPoll(); }, pollErrorDelay); |
|
} |
|
|
|
var pollHandler = function(data) { |
|
try { |
|
messageHandler(data); |
|
} catch(e) { |
|
if (logging) |
|
adapter.log('Exception in the poll handler: ' + data, e); |
|
throw(e); |
|
} finally { |
|
setTimeout(function() { sendPoll(); }, pollDelay); |
|
} |
|
}; |
|
|
|
var sendPoll = function() { |
|
// Workaround IE6 bug where it caches the response |
|
// Generate a unique query string with date and random |
|
var now = new Date(); |
|
var data = 'timeout=' + timeout * 1000 |
|
+ '&d=' + now.getTime() |
|
+ '&r=' + Math.random(); |
|
var options = { |
|
method: 'get', |
|
data: data, |
|
success: pollHandler, |
|
error: pollErrorHandler |
|
}; |
|
if (logging) |
|
adapter.log("AJAX call: method=GET uri=\"" + uri + "\" data=\"" + data + "\""); |
|
adapter.ajax(uri, options); |
|
}; |
|
|
|
var sendJmsMessage = function(destination, message, type) { |
|
if (batchInProgress) { |
|
// Add message to outbound queue |
|
messageQueue[messageQueue.length] = { |
|
destination: destination, |
|
message: message, |
|
messageType: type |
|
}; |
|
} else { |
|
org.activemq.Amq.startBatch(); |
|
var data = 'destination=' + encodeURIComponent(destination) + '&message=' + encodeURIComponent(message) + '&type=' + encodeURIComponent(type); |
|
if (logging) |
|
adapter.log("AJAX call: method=POST uri=\"" + uri + "\" data=\"" + data + "\""); |
|
adapter.ajax(uri, { |
|
method: 'post', |
|
data: data, |
|
error: errorHandler, |
|
success: org.activemq.Amq.endBatch |
|
}); |
|
} |
|
}; |
|
|
|
var buildParams = function(msgs) { |
|
var s = []; |
|
for (var i = 0, c = msgs.length; i < c; i++) { |
|
if (i != 0) |
|
s[s.length] = '&'; |
|
s[s.length] = ((i == 0) ? 'destination' : 'd' + i); |
|
s[s.length] = '='; |
|
s[s.length] = msgs[i].destination; |
|
s[s.length] = ((i == 0) ? '&message' : '&m' + i); |
|
s[s.length] = '='; |
|
s[s.length] = msgs[i].message; |
|
s[s.length] = ((i == 0) ? '&type' : '&t' + i); |
|
s[s.length] = '='; |
|
s[s.length] = msgs[i].messageType; |
|
} |
|
return s.join(''); |
|
} |
|
|
|
return { |
|
init: function(options) { |
|
connectStatusHandler = options.connectStatusHandler || function(connected){}; |
|
uri = options.uri || '/amq'; |
|
pollDelay = typeof options.pollDelay == 'number' ? options.pollDelay : 0; |
|
timeout = typeof options.timeout == 'number' ? options.timeout : 25; |
|
logging = options.logging; |
|
adapter.init(options); |
|
|
|
var data = 'destination=' + encodeURIComponent("topic://ActiveMQ.Ajax") + "&message=ping&type=send"; |
|
if (logging) |
|
adapter.log("AJAX call: method=POST uri=\"" + uri + "\" data=\"" + data + "\""); |
|
adapter.ajax(uri, { |
|
method: 'post', |
|
data: data, |
|
error: function () { |
|
adapter.log("FAILED TO SEND INITIAL PING MESSAGE"); |
|
}, |
|
success: function () { |
|
sendPoll(); |
|
if (typeof options.callback != "undefined") |
|
options.callback(); |
|
} |
|
}); |
|
}, |
|
|
|
startBatch: function() { |
|
batchInProgress = true; |
|
}, |
|
|
|
endBatch: function() { |
|
if (messageQueue.length > 0) { |
|
var body = buildParams(messageQueue); |
|
messageQueue.length = 0; |
|
org.activemq.Amq.startBatch(); |
|
if (logging) |
|
adapter.log("AJAX call: method=POST uri=\"" + uri + "\" data=\"" + body + "\""); |
|
adapter.ajax(uri, { |
|
method: 'post', |
|
data: body, |
|
success: org.activemq.Amq.endBatch, |
|
error: errorHandler |
|
}); |
|
} else { |
|
batchInProgress = false; |
|
} |
|
}, |
|
|
|
// Send a JMS message to a destination (eg topic://MY.TOPIC). Message |
|
// should be xml or encoded xml content. |
|
sendMessage: function(destination, message) { |
|
sendJmsMessage(destination, message, 'send'); |
|
}, |
|
|
|
// Listen on a channel or topic. |
|
// handler must be a function taking a message argument |
|
addListener: function(id, destination, handler) { |
|
messageHandlers[id] = handler; |
|
sendJmsMessage(destination, id, 'listen'); |
|
}, |
|
|
|
// remove Listener from channel or topic. |
|
removeListener: function(id, destination) { |
|
messageHandlers[id] = null; |
|
sendJmsMessage(destination, id, 'unlisten'); |
|
} |
|
}; |
|
}();
|
|
|