When Firebug’s Console Object Cannot be Overridden

In my previous blog post, I’ve shown how to use Firebug’s console object to log debug messages. I’ve also shown how to perform graceful degradation if the console object is not available like when using a non-Firefox browser or if Firebug’s console is not enabled. This way, one can still retain the calls to console.log() without generating any error messages. However, there were still some issues I failed to address.

Production deployment

Normally, when you deploy code into production, you don’t want your debug calls to be included. You don’t want users to be getting those debug messages. There are two ways to fix this problem: 1) Add a step to your deployment process to search and remove all the debug calls in your code; or 2) Add some kind of a switch, say a global variable DEBUG, to decide whether to use Firebug’s console logger or redirect the call to a dummy console.log() that will not do anything. This functionality is similar to loggers like log4j in Java where you can set different settings (info, debug, etc.) to control logging without modifying the code.

Let’s say we wanted #2 above. The code below illustrates how this can be done.

    if (!window.DEBUG || typeof(console) == 'undefined') {
        console = {};
        console.log = function(msg) {
            return false;
        };
    }

If DEBUG is off (false), e.g., production, it will create the console object and implement a no-operation log() method. If the browser is Firefox, this will effectively override its console object, therefore, …

Wait, that is not correct. As of this writing (Firebug-v1.3.3), Firebug’s console object cannot be overridden! If you attempt to do so, you will get an error message of something like, “setting a property that has only a getter.”

Programming to an Interface and not an implementation

To fix this problem, what we should do instead is not use the Firebug console object directly to log messages. This is like the design pattern where one programs to an Interface and not an implementation.

Following this principle, we create our own implementation of the console object, let’s say mylogger. With this object, we can then control if we want to use Firebug’s console.log() or the dummy one depending on our DEBUG setting. Below is the modified version of the HTML page using mylogger.log().

<html>
  <head>
    <script type="text/javascript">
        DEBUG = true;

        // by default, set mylogger to do nothing
        mylogger = {};
        mylogger.log = function(msg) {
            return false;
        };

        // if DEBUG is true and Firebug console is available, use it for logging
        if (window.DEBUG && typeof(console) !== 'undefined') {
            mylogger = console;
	}
	    	    
        function demo() {
            // I did lots of things here          
            mylogger.log("I'm here!");
            // and a lot more          
        }
    </script>
  </head>
<body>
  <h1>Firebug's console.log() Demo</h1>
  <button onclick="demo();">Firebug console.log() demo</button>
</body>
</html>

The code above has a DEBUG switch that we set on the server side to true or false depending if we want to log messages or not. Instead of using the console.log() method directly in the demo() function, we use mylogger.log(). Since we cannot override Firebug’s console object, what we can do instead is make the decision whether to use it or not at runtime.

Advertisements

Debugging JavaScript Using Firebug’s Console Logger

Thanks to Firebug, debugging JavaScript has never been easier. Firebug is an add-on to the FireFox browser. It has many wonderful features. One of my favorite is the console logger. This is where you can call the function console.log() in your code to write log messages to the Firebug console. This is definitely much better than using the alert() function. It’s unobtrusive and transparent to the execution of your JavaScript program.

Below is a sample HTML page with JavaScript code demonstrating how to use this function.

<html>
  <head>
    <script type="text/javascript">
    function demo() {
        // do something          
        console.log("I'm here!");
        // do something          
    }
    </script>
  </head>
<body>
  <h1>Firebug's console.log() Demo</h1>
  <button onclick="demo();">Firebug console.log() demo</button>
</body>
</html>

The code above has a button element that will print out the message “I’m here!” to the Firebug console.

Graceful Degradation

Of course, console.log() only works with the Firefox browser, with Firebug installed, and the console is enabled. Otherwise, you’ll get an error saying the console object is not defined.

For browsers other than Firefox or if Firebug is not installed, you can still retain the console.log() calls in your code and avoid getting any error messages by redirecting this call to a no-operation. To do this, create a console object and an implementation of the log() method that does not do anything. Below is a sample implementation.

// if console is not defined, e.g., Firebug console is not enabled or Non-Firefox browser
if (typeof console == 'undefined') {
    var console = {};
    console.log = function(msg) {
        return;
    };
}

The code above shows that if the console object is not defined, like when using a browser other than FireFox, a console object will be created together with a method named log() that does not do anything. That console object will then be the one that will be used by your log() calls in non-Firefox browser or when Firebug console is not enabled, which will just fail silently.

The console.log() method also supports formatted messages similar to C or Perl’s printf function. For example:

console.log("This is loop %s", loop_counter);

Firebug’s console object is not limited to the log() method. It can do other cool things. You can learn more about them here – http://getfirebug.com/console.html

Many sites have discussed this topic with great examples and illustrations. Here’s a nice one – http://ajax.phpmagazine.net/2006/05/firebug_the_future_of_javascri.html.

Note: The solution presented here is not without problems. See my other post for details.
Alvin Abad

Send a Twitter Message from the Unix Command Line

If you are a fan of Twitter and also a Unix user who spends most of your waking hours on the command line, wouldn’t it be nice if you can send your Twitter update from the Unix command line? Twitter has an API that makes sending from the Unix command line easy. All you need is the curl command (which should be available nowadays on most Unix systems) and you can fire up your Twitter message like this:

    curl -u mytwitterusername:mypassword -d status="the server is up!" \
                  http://twitter.com/statuses/update.json

Note: The command above should be all in one line.

Easy, isn’t it?

But you might say, “Wow, that’s a lot of typing to do. BTW, is that my password in clear text?”

Well, this is where Unix scripting comes to the rescue. You can easily wrap this in a shell script and your usage could be as simple as this:

        twitter.sh "the server is up!"

The rest are inside the script where you can hide your username and password by making sure that only you can read it. For example:

#!/bin/sh
curl -u mytwitterusername:mypassword -d status="$*" \
      http://twitter.com/statuses/update.json

If you are not comfortable putting your password and username in the script, you can always make the script prompt for them. For example:

#!/bin/sh

echo -n "Enter username: "
read USERNAME

echo -n "Enter password: "
stty -echo
read PASSWORD
stty echo
echo

MESSAGE="$*"

curl -u $USERNAME:$PASSWORD -d status="$MESSAGE" \
     http://twitter.com/statuses/update.json
echo

For details about this API, see Twitter documentation: http://apiwiki.twitter.com/REST+API+Documentation

Alvin Abad

Administering WebSphere Using JMX

Although administering WebSphere is best done using the Wsadmin API (with scripting languages like Jython or Jacl), there may be situations when this is not a good option. One example is when your application is already using Java and calling out to an external program (wsadmin.sh) would make the application run slower or make your integration cumbersome.

If your application is already using Java, naturally, it’s best that you also use Java to administer WebSphere. And the recommended way of doing this is through the use of the JMX API for Websphere MBeans. Below is an example illustrating how to use Websphere’s JMX API to retrieve memory information of an application server JVM. The code below is composed of two classes (WASAdminClient.java,  JavaVirtualMachine.java) and a property file (soap_client.properties).

The key to the use of Websphere’s JMX API is to obtain a JMX client connection to your WebSphere’s Application Server and then use this connection to access WebSphere’s JMX MBean Interfaces.

The first step in the process is to establish a JMX client connection. This is the goal of the WASAdminClient class. This is achieved by obtaining the AdminClientFactory.createAdminClient(Properties props) object. The Properties object passed to the method contains the credentials and trustore information required to connect to your Websphere Application Server. The credentials are obtained from the soap_client.properties file while the trustore information is obtained from the files generated by Websphere.

WASAdminClient.java would have been simpler if security is not enabled. If security is not enabled in Websphere, credentials and trustore information won’t be needed to obtain the AdminClient object. However, in a real production setup, this is rarely done so I’d like to also show this process. This is probably the most crucial information you would want to hear. Using WebSphere’s JMX MBeans Interface is straightforward, however, getting the WAS AdminClient object with security enabled is what stumped a lot of people. As you can see in the code below, obtaining the adminclient is not as simple as passing the username and password. It also requires the ssl trustStore and keyStore files from a WebSphere installation. The other thing is that you just can’t get these files out of nowhere. They need to be validly generated from a WebSphere installation. Note: The WebSphere installation doesn’t need to be the server where you want to connect.

The WASAdminClient class has two options to obtain the username and password information. These can be obtained from the soap_client.properties file or from Websphere’s CONNECTOR_SOAP_CONFIG file.

Once you have an AdminClient object connection, you can now use this object to access WebSphere’s JMX MBean Interfaces. The JavaVirtualMachine class below demonstrates how to access some memory information of an application server like heap size, maximum memory, etc.

I have also included below a JUnit test case for the JavaVirtualMachine class. Several test cases are not implemented. I have only provided a couple just to show examples on how to use the two Java classes.

Alvin Abad


"WASAdminClient.java"
package admin.service;

import java.util.Properties;
import java.util.ResourceBundle;

import com.ibm.websphere.management.AdminClient;
import com.ibm.websphere.management.AdminClientFactory;
import com.ibm.websphere.management.exception.ConnectorException;

/**
 * Websphere JMX AdminClient Service
 * @author Alvin Abad
 *
 */
public class WASAdminClient {
	private String hostname = "localhost";    // default
	private String port = "8879";             // default

	private String username;
	private String password;
	private String connector_security_enabled;
	private String connector_soap_config;
	private String ssl_trustStore;
	private String ssl_keyStore;
	private String ssl_trustStorePassword;
	private String ssl_keyStorePassword;

	private ResourceBundle soapClient;
	private String soap_client_properties;

	private AdminClient adminClient;

	public WASAdminClient() throws ConnectorException {
		soap_client_properties = "soap_client";
	}

	public WASAdminClient(String soap_client_properties) throws ConnectorException {
		this.soap_client_properties = soap_client_properties;
	}

	public AdminClient getAdminClient() {
		return adminClient;
	}

	public AdminClient create() throws ConnectorException {
		getResourceBundle(soap_client_properties);

		Properties props = new Properties();
		props.setProperty(AdminClient.CONNECTOR_TYPE, AdminClient.CONNECTOR_TYPE_SOAP);
		props.setProperty(AdminClient.CONNECTOR_HOST, hostname);
		props.setProperty(AdminClient.CONNECTOR_PORT, port);
		props.setProperty(AdminClient.CACHE_DISABLED, "false");

		if (connector_security_enabled == "false") {
			adminClient = AdminClientFactory.createAdminClient(props);
			return adminClient;
		}

		props.setProperty(AdminClient.CONNECTOR_SECURITY_ENABLED, "true");
		props.setProperty(AdminClient.CONNECTOR_AUTO_ACCEPT_SIGNER, "true");
		props.setProperty("javax.net.ssl.trustStore", ssl_trustStore);
		props.setProperty("javax.net.ssl.keyStore", ssl_keyStore);
		props.setProperty("javax.net.ssl.trustStorePassword", ssl_trustStorePassword);
		props.setProperty("javax.net.ssl.keyStorePassword", ssl_keyStorePassword);

		// Use username and password or soap.client.props file
		if (username == null || password == null) {
			props.setProperty(AdminClient.CONNECTOR_SOAP_CONFIG, connector_soap_config);
		} else {
			props.setProperty(AdminClient.USERNAME, username);
			props.setProperty(AdminClient.PASSWORD, password);
		}

		adminClient = AdminClientFactory.createAdminClient(props);

		return adminClient;
	}

	public ResourceBundle getResourceBundle(String properties) {
		soapClient = ResourceBundle.getBundle(properties);

		hostname = soapClient.getString("hostname");
		port = soapClient.getString("port");
		connector_security_enabled = soapClient.getString("connector_security_enabled");
		ssl_trustStore = soapClient.getString("ssl_trustStore");
		ssl_keyStore = soapClient.getString("ssl_keyStore");
		ssl_trustStorePassword = soapClient.getString("ssl_trustStorePassword");
		ssl_keyStorePassword = soapClient.getString("ssl_keyStorePassword");

		if (soapClient.containsKey("connector_soap_config")) {
		    connector_soap_config = soapClient.getString("connector_soap_config");
		}

		if (soapClient.containsKey("username")) {
		    username = soapClient.getString("username");
		}

		if (soapClient.containsKey("password")) {
			password = soapClient.getString("password");
		}

		if (soapClient.containsKey("hostname")) {
			hostname = soapClient.getString("hostname");
		}

		if (soapClient.containsKey("port")) {
			port = soapClient.getString("port");
		}

		return soapClient;
	}

}

"JavaVirtualMachine.java"

package admin.service;

import java.util.Set;

import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;

import com.ibm.websphere.management.AdminClient;
import com.ibm.websphere.management.exception.ConnectorException;

/**
 * Websphere JMX JavaVirtualMachine Service
 * @author Alvin Abad
 *
 */
public class JavaVirtualMachine {
	private String heapSize;
	private String maxMemory;
	private Integer maxHeapDumpsOnDisk;
	private String freeMemory;

	private ObjectName mBean;
	private Set mBeans;
	private AdminClient adminClient;

	public JavaVirtualMachine() {
	}

	public JavaVirtualMachine(AdminClient adminClient) {
		this.adminClient = adminClient;
	}

	public AdminClient getAdminClient() {
		return adminClient;
	}

	public void setAdminClient(AdminClient adminClient) {
		this.adminClient = adminClient;
	}

	public Set queryMBeans() throws MalformedObjectNameException,
                                         NullPointerException, ConnectorException {
		String query = "WebSphere:type=JVM,*";
		ObjectName queryName = new ObjectName(query);
		mBeans = adminClient.queryNames(queryName, null);

		return mBeans;
	}

	public Set getMBeans() {
		return mBeans;
	}

	public void setMBeans(Set mBeans) {
		this.mBeans = mBeans;
	}

	public ObjectName getMBean() {
		return mBean;
	}

	public void setMBean(ObjectName mBean) {
		this.mBean = mBean;
	}

	public String getHeapSize(ObjectName mBean) throws AttributeNotFoundException,
	                                   InstanceNotFoundException,
	                                   MBeanException, ReflectionException,
	                                   ConnectorException {
		heapSize = (String) adminClient.getAttribute(mBean, "heapSize");
		return heapSize;
	}

	public String getMaxMemory(ObjectName mBean) throws AttributeNotFoundException,
                                        InstanceNotFoundException, MBeanException,
                                        ReflectionException, ConnectorException {
		maxMemory = (String) adminClient.getAttribute(mBean, "maxMemory");
		return maxMemory;
	}

	public Integer getMaxHeapDumpsOnDisk(ObjectName mBean) throws AttributeNotFoundException,
                                       InstanceNotFoundException, MBeanException,
                                       ReflectionException, ConnectorException {
		maxHeapDumpsOnDisk = (Integer) adminClient.getAttribute(mBean, "maxHeapDumpsOnDisk");
		return maxHeapDumpsOnDisk;
	}

	public String getFreeMemory(ObjectName mBean) throws AttributeNotFoundException,
                                        InstanceNotFoundException, MBeanException,
                                        ReflectionException, ConnectorException {
		freeMemory = (String) adminClient.getAttribute(mBean, "freeMemory");
		return freeMemory;
	}

}

"soap_client.properties"

# Optional parameters
username = wasuser
password = secret
hostname = localhost
port = 8879

connector_security_enabled = true
#connector_soap_config = build/soap.client.props
ssl_trustStore = /usr/IBM/WebSphere/profiles/my_dmgr/etc/DummyClientTrustFile.jks
ssl_keyStore = /usr/IBM/WebSphere/profiles/my_dmgr/etc/DummyClientKeyFile.jks

ssl_trustStorePassword = WebAS
ssl_keyStorePassword = WebAS

"JavaVirtualMachineTest.java"

package admin.service;

import static org.junit.Assert.*;

import java.util.Set;

import javax.management.MalformedObjectNameException;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.ibm.websphere.management.AdminClient;
import com.ibm.websphere.management.exception.ConnectorException;

/**
 * JavaVirtualMachine Test Case
 * @author Alvin Abad
 */
public class JavaVirtualMachineTest {
	AdminClient adminClient;
	JavaVirtualMachine jvm;

	@Before
	public void setUp() throws Exception {
		WASAdminClient wasAdminClient = new WASAdminClient();
		adminClient = wasAdminClient.create();
	}

	@After
	public void tearDown() throws Exception {
	}

	@Test
	public void testJavaVirtualMachine() {
		jvm = new JavaVirtualMachine();
		assertNull(jvm.getAdminClient());
	}

	@Test
	public void testJavaVirtualMachineAdminClient() {
		jvm = new JavaVirtualMachine(adminClient);
		assertNotNull(jvm.getAdminClient());
		assertTrue(jvm.getAdminClient() instanceof AdminClient);
	}

	@Test
	public void testGetAdminClient() {
		jvm = new JavaVirtualMachine(adminClient);
		assertEquals(jvm.getAdminClient(), adminClient);
	}

	@Test
	public void testSetAdminClient() {
		jvm = new JavaVirtualMachine();
		jvm.setAdminClient(adminClient);
		assertEquals(jvm.getAdminClient(), adminClient);
	}

	@Test
	public void testQueryMBeans() throws MalformedObjectNameException,
                                   NullPointerException, ConnectorException {
		jvm = new JavaVirtualMachine();
		Set mBeans = jvm.queryMBeans();
		assertTrue(mBeans.size() > 0);
	}

	@Test
	public void testGetMBeans() {
		fail("Not yet implemented");
	}

	@Test
	public void testSetMBeans() {
		fail("Not yet implemented");
	}

	@Test
	public void testGetMBean() {
		fail("Not yet implemented");
	}

	@Test
	public void testSetMBean() {
		fail("Not yet implemented");
	}

	@Test
	public void testGetHeapSize() {
		fail("Not yet implemented");
	}

	@Test
	public void testGetMaxMemory() {
		fail("Not yet implemented");
	}

	@Test
	public void testGetMaxHeapDumpsOnDisk() {
		fail("Not yet implemented");
	}

	@Test
	public void testGetFreeMemory() {
		fail("Not yet implemented");
	}

}

A Simple Cross-Domain Ajax

In spite of the power of the XMLHttpRequest API, its usage is limited by the “same-origin” policy. What this means is that the hostname of the url you are sending the XMLHttpRequest cannot be different from the hostname of the web server.

Understandably, the reason behind this is security. However, there are legitimate reasons why you would need to call out to other domains, for example, you have a site with multiple domains or sub-domains and you would need to call XMLHttpRequest to these different domains.

One way to get around this issue is to let the server-side, on behalf of the client browser, perform the HTTP request to the external site. This functionality is best explained here. But this doesn’t sound like the true Ajax we imagined because we wanted to use the same idea of XMLHttpRequest where you can call out a URL from the browser, with the only difference that it can be a different domain.

So how does one perform an Ajax request using a different domain?

Below is a simple example of a cross-domain Ajax:

<html>
<head>
<script type="text/javascript">
    function xss_ajax(url) {
        var script_id = null;
        var script = document.createElement('script');
        script.setAttribute('type', 'text/javascript');
        script.setAttribute('src', url);
        script.setAttribute('id', 'script_id');

        script_id = document.getElementById('script_id');
        if(script_id){
            document.getElementsByTagName('head')[0].removeChild(script_id);
        }

        // Insert <script> into DOM
        document.getElementsByTagName('head')[0].appendChild(script);
    }

    function callback(data) {
        var txt = '';
        for(var key in data) {
            txt += key + " = " + data[key];
            txt += "\n";
        }
        alert(txt);
    }

    var url = "http://alvin-samplejson.appspot.com/callback_json.php";

</script>
<title>Simple Cross Domain Ajax</title>
</head>
<body>
<h1>Simple Cross Domain Ajax</h1>
<button onclick="xss_ajax(url);">Get Data</button>
</body>
</html>

The JavaScript code above has two functions: xss_ajax() and callback(). The first function, xss_ajax(), performs the HTTP request given a URL. This function mimics the XMLHttpRequest’s open() and send() methods combined. The URL passed to it is not limited by the same-origin policy, thus, it can be any domain name. The second function, callback(), is a function that processes the data returned by the HTTP request performed by xss_ajax().

In the HTML body, I have included a button element to demonstrate a call to the xss_ajax() function.

To try out this example, simply save this code into a file, load it into your browser, e.g., file:///C:/simpleCrossDomainAjax.html, and hit the “Get Data” button.

As you will see, even if the origin is a local file, it can still perform an HTTP request to a different domain and be able to return a response. (http://alvin-samplejson.appspot.com/callback_json.php)

One thing that is different from the XMLHttpRequest API is that the response of our http request cannot be a true JSON object (or XML). Instead, it needs to be constructed with a string-like function call, where its parameter will be the true format of the object you wish to return.

Viewing the sample URL:
http://alvin-samplejson.appspot.com/callback_json.php

the response of the PHP page will look like this:

callback({"firstname":"John","lastname":"Smith","email":"john.smith@johnsmith.com"});

Below is the PHP code that is used for the HTTP request:

<?php
$obj = array();
$obj['firstname'] = "John";
$obj['lastname'] = "Smith";
$obj['email'] = "john.smith@johnsmith.com";

$response = "callback(" . json_encode($obj) . ");";
print $response;

/**
  Browser prints this out as:
  callback({"firstname":"John", "lastname":"Smith", "email":"john.smith@johnsmith.com"});
**/
?>

The “callback” function string as returned by the HTTP request triggers the call to the callback() function.

The magic behind all this is in the usage of the <script> DOM element. As we all know, a web browser can load a JavaScript source file from a different domain. For example:

<script type="text/javascript"
  src="http://external-domain.com/myjavascript.js"></script>

What this code is doing is performing an HTTP request to external-domain.com, fetching the file myjavascript.js, and loading its content.

If this can be done to a javascript file, then it can be done as well to a regular HTML file, or to any type of HTTP requests, e.g. cgi, php, jsp, etc. For example:

<script type="text/javascript" src="http://external-domain.com/mypage.html"></script>
<script type="text/javascript" src="http://external-domain.com/mypage.cgi"></script>
<script type="text/javascript" src="http://external-domain.com/mypage.php"></script>
<script type="text/javascript" src="http://external-domain.com/mypage.xml"></script>

Based on this principle, in order to mimic an XMLHttpRequest kind of call, all we need to do is programmatically create a script element at runtime every time the browser needs to perform an HTTP request. Line numbers 6 to 9 in the xss_ajax() function above performs this dynamic creation of the script element. Line number 17 is when the script element is inserted into the DOM that will trigger the actual execution of the script tag.

Since the script element tag expects a JavaScript code, the response of the URL specified must be executable like a JavaScript code. That is why our PHP code above returns a “callback()” string instead of the raw JSON object. When the script-tag gets created, the browser will see this function-call-like string and will execute it.

The example above only performs a simple HTTP request without any parameters. What if we need to send request parameters? Since the script-tag follows the same principle of making an HTTP GET request, passing request parameters would be the same thing as adding the query-strings to the URL, For example:

<script type="text/javascript"
  src="http://otherdomain.com/mypage.php?name=JOHN&password=secret"></script>

Therefore, to make our xss_ajax() support request parameters, all we need to do is simply add the request parameters to the URL.

Alvin Abad

Extending JavaScript’s String Object

If you are the kind of programmer who works on multiple projects using different languages at the same time, I bet you sometimes can’t help mix things together and subconsciously expect that a method/function you commonly use in one language is also available in the other. And when this happens, you suddenly pause and realize that the function you are about to type doesn’t exist in the language you are currently writing. What could be worse is when you cannot instantly remember the syntax of the method you want to use and you have to scramble and look up the API documentation. The interruption can be annoying. Wouldn’t it be nice if you can simply use the same method that you are always familiar with in the other language?

The good news is that when it comes to JavaScript, this language is so flexible and powerful it can easily fix this problem.

For example in Java, there is this method s.trim() that you call on a string object s to remove any leading and trailing whitespaces. Unfortunately in JavaScript, this method is not available. Of course you can always write a separate function to implement this method, for example, mytrim(s). But wouldn’t it be nice if you can use it the same way you use it in Java? This way, you wouldn’t have to consciously remember about your mystrim(s) function and just let your fingers do the thinking and type it like the way you always do: s.trim().

Fortunately, JavaScript is a very powerful object-oriented programming language. You can easily extend the String object to add a method. This is accomplished by creating a function implementing the functionality you desire and attaching it to String.prototype. Below is a sample implementation of the trim() method.

String.prototype.trim = function () {
    return this.replace(/^\s+|\s+$/g, "");
};

After loading the code above, you can now use s.trim(); where s is the string object.

Below is a sample html page where you can try out this feature. Create this html file and load it into your browser.

<html>
<head>
<title>Extending String object</title>
<script type="text/javascript">
    String.prototype.trim = function () {
        return this.replace(/^\s+|\s+$/g, "");
    };

    var mystring = "       hello, world        ";
    document.writeln("
<pre>");
    document.writeln("Has leading and trailing spaces: [" + mystring + "]");
    document.writeln("Spaces removed: [" + mystring.trim() + "]");
    document.writeln("</pre>
");
</script>
</head>
<body>
</body>
</html>

You should see the output like this:

Has leading and trailing spaces: [       hello, world        ]
Spaces removed: [hello, world]

If you are coming from Python and are used to the upper() method to convert characters to uppercase, you can implement the same method in JavaScript. JavaScript already has this method but it is called toUpperCase(). But if you prefer the Python way, so that you can just let your fingers do the thinking, the technique to accomplish this is the same:

String.prototype.upper = function () {
    return this.toUpperCase();
};

As you can see above, we didn’t have to write our own implementation. We simply use JavaScript’s built-in toUpperCase() function to duplicate it.

Extending JavaScript’s String object is not for everyone. This may not be a good idea to some people because this can cause confusion if one is not aware that an extension has been introduced. Some people would rather prefer implementing the functionality using a separate namespace, e.g., MyStringUtil.trim(s), instead of extending the string object. This makes it clear that an external API is being used.

Five Easy Steps to Learn JsUnit

If you already know JUnit or PyUnit, it shouldn’t take you more than ten minutes to learn how to use JsUnit. JsUnit is a Unit Testing Framework for Javascript. It is a JavaScript version of JUnit.

Below are five easy steps you can follow to quickly learn JsUnit.

Step 1. Download JsUnit zip file and extract it to a local directory.

http://jsunit.net/
http://downloads.sourceforge.net/jsunit/

Step 2. Create a sample function that you will use to test using JsUnit.

For example, let’s create a function that adds two numbers. Save this code into a file and name it “myAdd.js”.

// myAdd.js
function add(x, y) {
    return (x+y);
}

Step 3. Create an HTML file and name it “testMyAdd.html”.

In the HEAD section of this file, include the JsUnit source code and your myAdd.js file. In the BODY section, write your testcase functions as shown below. Similar to JUnit and PyUnit, the names of testcase functions must begin with “test”.

“testAdd.html”

<html>
<head>
    <title>Test Add Function</title>

    <script type="text/javascript" src="junit/jsUnitCore.js"></script>
    <script type="text/javascript" src="myAdd.js"></script>

</head>
<body>
<script type="text/javascript">
    function setUp() {
        // fixture setup before running a testcase
    }

    function tearDown() {
        // anything to cleanup after running a testcase
    }

    function testAdd() {
        assertEquals("", 3, add(2, 1));
    }

    function testAdd2() {
        assertNotEquals("", 0, add(2, 1));
    }
</script>
</body>
</html>

Step 4. Using a browser, locate the file “jsunit/testRunner.html” and load it.

Step 5. On the testRunner.html page, enter the testpage URL (testAdd.html) and click on the RUN button.

When JsUnit loads the testpage, it will automatically find all testcase functions and run them in sequence.

That’s it! You now have a working JsUnit testcase. Of course, JsUnit has more to offer than this simple example. But this should get you started as you explore more features of JsUnit. See online doc for more details: http://jsunit.net/documentation/index.html

Unit Testing Wsadmin Jython Scripts

You can use the unittest module from Python to write unit testing for Websphere’s wsadmin Jython scripts. As of WASv61, this module comes shipped with the product so there is no need to refer externally to your CPython library.

To illustrate, let’s say you want to create a unittest for the Cell.py module below:

“Cell.py”

class Cell:
    def __init__(self, AdminControl=None):
        self.AdminControl = AdminControl

    def getName(self):
        return self.AdminControl.getCell()

Here’s a simple class that implements a method to retrieve the name of your Websphere cell.

To write a test case class, you simply create a class that extends unittest.TestCase. Below is an example.

“CellTest.py”

import unittest
from Cell import Cell

class CellTest(unittest.TestCase):
    def setUp(self):
        self.cell = Cell(AdminControl=AdminControl)

    def tearDown(self):
        pass

    def testGetName1(self):
        self.assertNotEqual(None, self.cell.getName())

    def testGetName2(self):
        id = AdminConfig.list('Cell')
        name = AdminConfig.showAttribute(id, 'name')
        self.assertEqual(name, self.cell.getName())

    def testGetName3(self):
        c = Cell()
        self.assertRaises(AttributeError, c.getName)

if __name__ == '__main__' or __name__ == 'main':
    #unittest.main() # not supported by wsadmin jython

    # alternative way of running this test
    suite = unittest.TestLoader().loadTestsFromTestCase(CellTest)
    unittest.TextTestRunner().run(suite)

    # other ways of running this test
    #suite = unittest.TestSuite()
    #suite.addTest(unittest.makeSuite(CellTest))
    #unittest.TextTestRunner().run(suite)

You will notice that I have commented out the line calling unittest.main(). This method call (as of WASv61) does not work with WebSphere’s wsadmin Jython. Fortunately, there are other ways to run a test case, as shown in the code above.

Also, you will notice that there is this odd __name__ == ‘main’ condition. In wsadmin Jython, this is what is being used and not ‘__main__’. For some reason, IBM chose not to use the standard.

Even though Websphere doesn’t support ‘__main__’, I still make it a habit of including it in my test cases for portability reasons. I wanted to have the flexibility of running my test cases using the standard CPython or Jython interpreter, if I need to, like using mock AdminConfig or AdminControl objects. This is also the reason why I chose to inject the AdminControl object into the Cell class instead of importing the module. [1] This easily allows the use of mock Admin* objects.

[1] Importing Websphere Admin* objects is not available by default. You have to set it up. See my other post on how to accomplish this – Websphere administrative objects not accessible from imported Jython modules.

Links to IBM WebSphere Application Server Documentations

In spite of Google’s power, finding information about WebSphere is still a chore. I can’t really blame Google because IBM WebSphere documentation is huge.

Until search results get better or I figure out how to find things faster on the IBM site directly, I am organizing my bookmarks here so that I can immediately refer to documentations I always use.

  1. WebSphere Application Server, Version 6.1 Information Center – Everything should be under here about WebSphere Application Server.
  2. IBM WebSphere Application Server, Release 6 API Specification – Javadoc to all Websphere APIs. This is under the Infocenter documentation but this will save you the trouble of searching where the Javadocs of the API reside.
  3. WebSphere Application Server Release 6.1 Public MBean Interfaces – Javadoc to WebSphere MBeans.
  4. WebSphere Extended Deployment (XD) Release 6.1 Public JMX MBean Interfaces
  5. Server Configuration Interfaces
  6. WebSphere Configuration Documentation – Documentation to WebSphere’s XML files
  7. WSADMIN Scripting

WebSphere Administrative Objects Not Accessible from Imported Jython Modules

In Websphere Jython (as of WAS6.1), the administrative objects are not automatically accessible from imported modules, unlike when you call them from your main script. It is also not possible to import them either since they are not defined in sys.modules.

“myModule.py”

print AdminConfig.types()

For example, the code above will break if this Jython module is imported from the main script or another module. If this is executed as the main script it would work right off the bat even without importing anything.

To fix this problem, you need to add the administrative objects to the “sys.modules” dictionary in the main script so that they will be visible to all imported modules. Once the administrative objects are available in “sys.modules”, your imported modules can then call the import command for those object to access them.

For example, in your main script, you need to construct the lines shown below before you can import any modules that will require access to the WebSphere administrative objects:

“myMain.py”

    import sys
    sys.modules['AdminConfig'] = AdminConfig
    sys.modules['AdminControl'] = AdminControl
    sys.modules['AdminApp'] = AdminApp
    sys.modules['AdminTask'] = AdminTask
    sys.modules['Help'] = Help

    # now you can import your module
    import myModule

Your imported modules can then call the import command to access these objects. The module below shows import commands for each WebSphere Administrative object.

“myModule.py”

    try:
        import AdminConfig
        import AdminControl
        import AdminApp
        import AdminTask
        import Help
    except:
        pass

    # this works now even if this module is imported
    print AdminConfig.types()

The try-except clause above is used to prevent the module from failing if you tried to run this as your main script. If you tried to run this in your main wsadmin script and the sys.modules were not set, this would simply ignore the exceptions and should be able to proceed to run any administrative commands directly.

I hope someday IBM will fix this problem by simply adding the administrative objects to the sys.modules by default so that we won’t need to do this ourselves.