«    »

Getting Started with WebSphere Configuration Scripting

Deploying Java EE applications into a WebSphere application server typically requires configuration within WebSphere of settings such as data sources, thread pool sizes, and maximum heap size. The WebSphere Administration Console provides a graphical user interface for easily doing this setup, but the fatal flaw of this approach is that it is manual - repeating the same setup in other environments is potentially error-prone extra manual effort. A better approach is to automate this configuration through scripting.

Tooling

WebSphere provides the wsadmin command-line interface for interfacing with WebSphere servers. Two scripting languages can be used: JACL (the default) and Jython, a Java-based version of Python. Invoke wsadmin with the argument "-lang jython" to use Jython. I recommend the use of Jython for two reasons. First, it is a more mainstream language. Second, the WebSphere Admin Console shows scripting commands in Jython equivalent to the GUI operations you last performed. See the screenshot below for an example:

WAS Admin Console showing Jython command equivalent to last action

You may think that since the Admin Console provides equivalent scripting commands to GUI actions that you could just copy and paste these commands into a script and you would be set. Unfortunately if you want the script to be re-runnable (on a given server) or reusable (on other servers), you will almost always need to make modifications. Certain operations, like creating a data source, will fail if there is an existing data source with the same name. So to have a re-runnable script you will need to add logic to your script to first detect if the data source you want to create already exists. Many commands use a hard-coded configuration id to refer to a particular item to be configured. This id generally consists of the item's name, directory path to the configuration file, name of the XML configuration file, and XML ID of the item within the file. While the first three are constant, the XML ID appears to be a numerically generated ID that will vary between servers. So you need to change the script to look up the configuration id.

The changes required to adapt the script for broader use are not trivial and require use of WebSphere APIs - in particular the AdminConfig and AdminTask objects provided to Jython scripts that are executed within wsadmin. The best tooling I have found for writing these scripts is to use Rational Application Developer which includes a Jython editor that includes wsadmin objects as part of the content assist. See the screenshot below for an example:
RAD Jython editor showing content assist

Examples

With the tooling in place let us look at some examples. The following scripts all assume a simple WebSphere topology of a single node with a single server that we are setting up - no clusters or multiple servers to worry about.
A number of settings require the configuration id or name of the server or node, so here's how to look them up:

nodeConfigId = AdminConfig.getid('/Node:/')
nodeName = AdminConfig.showAttribute(nodeConfigId, 'name')
serverConfigId = AdminConfig.getid('/Server:/')
serverName = AdminConfig.showAttribute(serverConfigId, 'name')

AdminConfig.getid() is one of the primary methods to use to look up configuration ids. But what is that "/Server:/" syntax used as an argument? That is called a containment path, which is a XPath-like syntax for looking up configuration ids. For more important details on containment paths and configuration ids read this excellent article by Vincent Partington.
As mentioned above, this only works when there is a single server defined on the node - with multiple servers, the call AdminConfig.getid('/Server:/') would return multiple server config ids separated by newlines. In this case if you want to configure a specific server you can look up the server configuration id by name as follows:

serverName = "testserver1"
serverConfigId = AdminConfig.getid('/Server:' + serverName + '/')

Having a configuration id is a start, but we still have not changed any settings. So here's a basic example of setting the maximum heap size to 1 GB:

maxHeapMb = 1024
jvmConfigId=AdminConfig.getid('/JavaVirtualMachine:/')
AdminConfig.modify(jvmConfigId, '[ [maximumHeapSize "' + maxHeapMb + '"]  ]')

This follows the standard pattern of first obtaining the configuration id and then changing the setting. I obtained the code for the AdminConfig.modify call from the Admin Console. But how did I figure out the AdminConfig call, in particular which containment path to use? This was painful initially to figure out. The hard-coded configuration id provided within the AdminConfig.modify call was "(cells/Node1Cell/nodes/Node1/servers/Server1|server.xml#JavaVirtualMachine_1183121908656)". The prefix "JavaVirtualMachine" on the XML id is the key type to use in the containment path.

Not all configuration commands require a configuration id. The AdminTask object typically takes arguments specifying the server and node name. Here's an example that prevents applications from accessing internal WebSphere classes:

AdminTask.setJVMProperties('[-serverName ' + serverName + 
' -nodeName ' + nodeName + ' -internalClassAccessMode RESTRICT]') 

The last step in any configuration script is to save the configuration changes. This is straightforward:

AdminConfig.save()

Resources

Here are some useful resources for this topic:

Happy scripting!

If you find this article helpful, please make a donation.

«    »