Preamble
I shared this with the DWR mailing list, and the guys thought it was useful, so I’m posting here to share with the world.
Feel free to use this code under the Open Software License v. 3.0 (OSL-3.0).
Background
I wanted to have a “show technical details” link on our error popup that said what happened when an error occurred.
Environment:
- DWR 2.0.5
- ExtJS 3.3.1
- BatchMapObtainer - This class retrieves the “batch map” from the current error handler callstack
- BatchMapWrapper - Wraps the “batch map” in order to wrap DWR-specific details
- ErrorHelper - Uses the above in order to construct a message for the user
The Code
FILE: BatchMapObtainer.js
Ext.ns('jx.core.dwr');
/**
* @class jx.core.dwr.BatchMapObtainer
* @static
*/
jx.core.dwr.BatchMapObtainer = function() {
var isArgDwrBatch = function(arg) {
return Ext.isDefined(arg.httpMethod) && Ext.isDefined(arg.map);
};
var getDwrBatchFromArguments = function(args) {
for (var i=0; i<args.length; i++) {
if (isArgDwrBatch(args[i])) {
return args[i];
}
}
return null;
};
var getBatchMapFromCallStack = function() {
var currentFn = arguments.callee;
var dwrBatch;
var visitedFunctions = [];
while (currentFn && !dwrBatch) {
dwrBatch = getDwrBatchFromArguments((currentFn.caller && currentFn.caller.arguments) || []);
if (visitedFunctions.indexOf(currentFn) !== -1) {
currentFn = null;
}
else {
visitedFunctions.push(currentFn);
currentFn = currentFn.caller;
}
}
return dwrBatch && dwrBatch.map;
};
return {
/**
* @method buildFromCallStack
* @static
* Tries to obtain a DWR batch map from the current call stack.
*/
obtainFromCallStack: function() {
return getBatchMapFromCallStack();
}
};
}();
FILE: BatchMapWrapper.js
Ext.ns('jx.core.dwr');
/**
* @class jx.core.dwr.BatchMapWrapper
* @extends Object
* Use to parse parameters from the DWR batch map.
*/
jx.core.dwr.BatchMapWrapper = Ext.extend(Object, {
batchMap: null,
constructor: function(batchMap) {
this.batchMap = batchMap;
},
getBatchId: function() {
return this.batchMap.batchId;
},
getBatchMap: function() {
return this.batchMap;
},
/**
* @return Array of call details. Each detail has "method" and "params" attributes
*/
getDwrCallDetails: function() {
var callDetails = [];
for (var i=0; this.hasCallDetailsFor(i); i++) {
var params = [];
for (var j=0; this.isParamDefined(i, j); j++) {
params.push(this.getParamAt(i, j));
}
callDetails.push({
method: this.getDwrCallNameFor(i),
params: params
});
}
return callDetails;
},
// private
hasCallDetailsFor: function(callIndex) {
return Ext.isDefined(this.batchMap['c' + callIndex + '-id']);
},
// private
isParamDefined: function(callIndex, paramIndex) {
return Ext.isDefined(this.getParamAt(callIndex, paramIndex));
},
// private
getParamAt: function(callIndex, paramIndex) {
return this.batchMap['c' + callIndex + '-param' + paramIndex];
},
// private
getDwrCallNameFor: function(callIndex) {
return this.getScripNameFor(callIndex) + '.' + this.getMethodNameFor(callIndex);
},
// private
getScripNameFor: function(callIndex) {
return this.batchMap['c' + callIndex + '-scriptName'];
},
// private
getMethodNameFor: function(callIndex) {
return this.batchMap['c' + callIndex + '-methodName'];
}
});
/**
* @method buildFromCallStack
* @static
* Tries to obtain a BatchMapWrapper wrapped around the "batch map" for the current call stack
*/
jx.core.dwr.BatchMapWrapper.buildFromCallStack = function() {
var batchMap = jx.core.dwr.BatchMapObtainer.obtainFromCallStack();
return batchMap ? new jx.core.dwr.BatchMapWrapper(batchMap) : null;
};
FILE: ErrorHelper.js
Ext.ns('jx.core.dwr');
/**
* @class jx.core.dwr.ErrorHelper
* @static
* Helper to gain information about DWR calls.
*/
jx.core.dwr.ErrorHelper = function() {
var getBaseDwrCallMessage = function(batchMapWrapper) {
var message = '';
var dwrCallDetails = batchMapWrapper.getDwrCallDetails();
if (Ext.isArray(dwrCallDetails)) {
for (var i=0; i<dwrCallDetails.length; i++) {
var details = dwrCallDetails[i];
message += "DWR Call: " + details.method + "\nParams: " + Ext.util.JSON.encode(details.params);
}
}
return message;
};
var getFullBatchMapMessage = function(batchMapWrapper) {
var message = "Batch Map:";
var batchMap = batchMapWrapper.getBatchMap();
for (var key in batchMap) {
if (!Ext.isFunction(batchMap[key])) {
message += "\n " + key + ": " + batchMap[key];
}
}
return message;
};
return {
getDwrCallDetailsFromCallStack: function() {
var batchMapWrapper = jx.core.dwr.BatchMapWrapper.buildFromCallStack();
return batchMapWrapper && batchMapWrapper.getDwrCallDetails();
},
buildDwrCallDetailsMessageFromCallStack: function() {
var message = '';
var batchMapWrapper = jx.core.dwr.BatchMapWrapper.buildFromCallStack();
if (batchMapWrapper) {
message += getBaseDwrCallMessage(batchMapWrapper);
message += "\n\n";
message += getFullBatchMapMessage(batchMapWrapper);
message += "\n\n";
}
return message;
}
};
}();
Example Usage:
In DWR errorHandler, simply:
var msg = jx.core.dwr.ErrorHelper.buildDwrCallDetailsMessageFromCallStack();
var id = Ext.id();
var html = '<a href="" onclick="document.getElementById(\'' + id + '\').style.display=\'block\'; return false;">' +
'Show Technical Details</a><br />' +
'<div id="' + id + '" style="display: none;"><textarea style="width: 100%; height: 150px;">' + msg +
'</textarea></div>';
Ext.Msg.alert("Error", html);
Good luck!