Skip to content

By Programmer For Programmer

Here I lay down the useful tips, tricks and utilities for programmers like myself.

Archive

Category: Uncategorized

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
Three classes:
  • 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!

Just wanted to give props real quick to the awesome profiler JProfiler (http://www.ej-technologies.com/products/jprofiler/overview.html) for providing me with an open-source license to profile my open-source project HTML4Java (https://sourceforge.net/projects/html4java/). The open-source community is so friendly :) .

Ever wanted to continue from a doubly-nested for loop? How about break from a switch statement more than one level deep?

Simple! First you have to label your loop, and then put that label name after the break or continue keyword.

“continue” example:

fooloop: for(foo: foos) {
    ...
    barloop: for(bar : bars) {
        ...
        for (blotto : blottos) {
            ...
            if (next_innermost_loop)
                continue; //normal
            if (next_middle_loop)
                continue barloop; //goes to the next iteration of "barloop"
            if (next_outer_loop)
                continue fooloop; //goes to the next iteration of the outermost loop, "fooloop"
        }
    }
}

“break” example:

fooswitch: switch(foo) {
    case 1:
        ...
        break;
    case 2:
        ...
       switch(bar) {
            ...
            if (break_this_switch)
                break; //normal
            if (break_outer_switch)
                break fooswitch; // breaks out of the out switch, "fooswitch"
        }
}

While most might consider this bad practice, when writing some scratch code to do some one-off task that only you will ever use, sometimes it’s nice to use a shortcut :) .

I was getting the annoying error in Eclipse with Tomcat where it didn’t think it could publish an application since some files were locked, when they were locked by the javaw.exe process that eclipse.exe started. The fix for me was to not have “Use Tomcat installation” selected in my server configuration. When I switched back to the default of “Use workspace metadata”, the error stopped happening.