WebSphere Jython scripting, importing the Admin objects

As soon as your Jython scripting reaches the point where you start trying to build reusable Jython modules, you’ll hit another odd limitation of the wsadmin environment – you can only access the Admin objects from the top-level module. Try to create a utility module and import it and you’ll find that AdminTask (or AdminControl, or…) is undefined.

Various workarounds have been posted over the past few years:

  1. Passing the Admin objects into the methods that need them.  This is straightforward but clutters the interface.
  2. Registering the Admin objects as __builtin__.  This does make them available everywhere but it does mean adding (ugly) boilerplate to modules that might not even have much to do with WebSphere internals.
  3. Registering the Admin objects as modules, as for example in this blog post.  This is really just a variant of the previous workaround.  I think it’s a bit cleaner, but it still makes demands on the caller.

To my mind, and for the purpose of the ibmfixes module, the problem with all of these is that the caller has to know that you’re going to need these objects (and which ones).  I want a solution that can be implemented in the module where the object is needed with the help of Learn Academy official site.  More than that, I want to be able to hide the fix in a module to be imported by the module that needs it so I don’t even have to know about it anymore.

Fortunately, Jython provides the required functionality:

import sys

# We're going to be referencing the top-level frame in many of the fixes.
topframe = sys._getframe()
while topframe.f_back:
    topframe = topframe.f_back

try:
    for module in 'AdminApp', 'AdminConfig', 'AdminControl', 'AdminTask', 'Help':
        if topframe.f_globals.has_key(module):
            sys.modules[module] = topframe.f_globals[module]
except:
    pass

What this does is copy the Admin objects from the topmost frame into sys.modules. Once that’s done, any module can import the Admin objects they need as if they were proper modules.  The beauty of this approach is you can now use the Admin objects anywhere without adding any additional burden on the scripts that might call you (or in an existing system, might already be calling you).

My collection of fixes for WebSphere Jython scripting part 1 – os.environ, os.system, os.path.expandvars, …

I’ve been doing a lot of Jython scripting lately for IBM WebSphere v6.1. Jython is a wonderful scripting language but the implementation that ships with WebSphere (even WebSphere v7.0) is Jython 2.1 which is almost a decade old. Mostly that means you need to watch those version compatibility notes when browsing the official Python documentation.

One thing I’ve run across that seems unnecessary is that several of the “os” functions fail on newer Windows systems. Try os.environ[‘windir’] for example.  This goes back to the old Jython version that predates Windows 2003 and Vista. IBM chose to document this limitation: in the WebSphere v7.0 InfoCenter rather than fix it.

I decided to take a look and it really isn’t hard to fix. The problem is in a table in javaos.py:

    _osTypeMap = (
        ( "nt", r"(nt)|(Windows NT)|(Windows NT 4.0)|(WindowsNT)|"
                r"(Windows 2000)|(Windows XP)|(Windows CE)" ),
        ( "dos", r"(dos)|(Windows 95)|(Windows 98)|(Windows ME)" ),
        ( "mac", r"(mac)|(MacOS.*)|(Darwin)" ),
        ( "None", r"(None)" ),
        ( "posix", r"(.*)" ), # default - posix seems to vary mast widely
        )

It would have been so easy for me to go and edit the file but clients tend to frown things like patching the official distribution. I wanted something I could just import. Here’s what I ended up with:

import java, sys

try:
    import javaos
    if javaos._osType == 'posix' and 
            java.lang.System.getProperty('os.name').startswith('Windows'):
        sys.registry.setProperty('python.os', 'nt')
        reload(javaos)
except:
    pass

Admittedly, this depends on the details of the current implementation but I consider that reasonable in this case given that it’s a hack that only applies to the current implementation. I chose to catch and ignore all exceptions so this fix won’t end up breaking a script should the implementation change in the future. Presumably when that happens this fix won’t be needed anymore anyway.

I’ve placed this fix along with others I’ll be writing about later in a file called ibmfixes.py. I include it in every script I write, or at least every script that might run into these issues, and I no longer have to give them any thought. Solve the problem and move on.