Automation Scripting Basics

In this blog I would like to provide you an overview of the terms and capabilities used in context of Maximo automation scripting. With the Automation Scripts application, you can create scripts to automate tasks based on the events or attributes of a business object, or based on actions or custom conditions.

There are some basic components to understand in terms of automation scripting:

Automation Script: The automation script is a definition in the Maximo Database which defines the name, a description and some more attributes for a specific automation script. The Source code of the script is an important part of this definition.

The source code must be written in the languages that are supported by the following script engines:

  • Mozilla Rhino, version 1.6 release 2
  • Jython, Version 2.5.2 (Version 2.7 starting ICD/Maximo 7.6.1)

Launch point: A launch point defines the context and the trigger for an automation script. A launch point has a name and a description. An automation script can have multiple launch points defined as a trigger. On the opposite side an automation script can be triggered in different ways without a specific launch point. Read this blog for the possible ways to trigger a script.

Variables and binding Values: Specific variables are automatically (implicit) passed to and from the Maximo scripting framework to your automation script. In addition you can defined more user defined variables to be passed. Read this blog for details on implicit variables.

Agile testing of Launchpoint scripts using a Testsection

Did you ever had the problem that it is sometimes really time consuming when you have to test a more complex script which is called by a script launchpoint? You mostly have to click through the ICD/Maximo GUI to simulate some behaviour so your script gets launched in context of a Mbo.

In this post I will show you a way how you can improve your script with a Testsection and after that you can run it from the Automation Script Application.

What is the base issue we have? Why is it so difficult to just run a script directly from the application editor? In most cases the answer is, that our script requires the context of a Mbo Object which is provided by the implicit variable mbo. So one of our first lines will be normally look like this:

itemMbo = mbo @UndefinedVariable

From this point on we can take the itemMbo to get/set values, to navigate to different MboSet’s and so on.

The easy solution to our issue is, that we need to simulate the mbo variable. If we run the script from the Automation Script Application no implicit variables are defined at all and so no mbo variable is available. We can test on this situation and then initialize the mbo variable our self by getting a specifc Mbo via the MxServer context. The following script will show this in context of the Item Mbo:

from psdi.server import MXServer

mxServer = MXServer.getMXServer()
userInfo = mxServer.getSystemUserInfo()

# Section to test script from Scripteditor
try:
    mbo  # @UndefinedVariable
except NameError:
    mbo = None

if mbo is None:
    scriptHomeSet = mxServer.getMboSet("ITEM", userInfo)
    scriptHomeSet.setWhere("ITEMNUM='ITAMT61'")
    scriptHomeSet.reset()
    itemMbo = scriptHomeSet.getMbo(0)
else:
    # This is the normal Entrypoint via a Launchpoint since 
    # implicit variable mbo is defined.
    itemMbo = mbo  # @UndefinedVariable

itemNum = itemMbo.getString("ITEMNUM")
itemDesc = itemMbo.getString("DESCRIPTION")

You just have to change the selection criteria in line 14 to select the correct item record. After that run the script from the Automation Script Application (see here for details).

You can integrate this technique in basically any script initiated by a launchpoint. Only remember, that no implicit variables can be used in the script!

The UserInfo Object

In this Blog I would like to introduce the often used UserInfo Object in Maximo / ICD Scripting. There are a number of API method calls which require a UserInfo object as a parameter and therefore you need to know how you can get a reference to that object. In the second part of this Blog I will show you some method calls on utilizing the UserInfo yourself.

Get a reference to the UserInfo Object

When you run a Jython script there are several ways to get the UserInfo object.

Get the userInfo for the actual user the script is running in context of a Mbo

userInfo = mbo.getUserInfo()  # @UndefinedVariable

Get the userInfo for a specific user

from psdi.server import MXServer
mxServer = MXServer.getMXServer()
userInfo = mxServer.getUserInfo("maxadmin")

Get the userInfo for the System user (MAXADMIN)

from psdi.server import MXServer
mxServer = MXServer.getMXServer()
userInfo = mxServer.getSystemUserInfo()

Get a new userInfo from Migration Services (MAXINTADM)

from psdi.server import MXServer
from psdi.iface.mic import MicService

mxServer = MXServer.getMXServer()
micService = MicService(mxServer)
micService.init()
userInfo = micService.getNewUserInfo()

Usage of the UserInfo Object

Beside the fact that a lot of method calls of Maximo/ICD API’s require a valid UserInfo object it has a number of interesting Getter and Setter functions which might help in your script. I would like to show you only a small subset of these methods here in this Blog. A full list can be found in the JavaDoc documentation.

Here I have a small demonstration script for you which can be directly run from the Automation Scripts application (look here how to do this):


#AUTOSCRIPT:USERINFO
#DESCRIPTION:Example script showing capabilities of the UserInfo Object

from psdi.server import MXServer

mxServer = MXServer.getMXServer()
userInfo = mxServer.getSystemUserInfo()

print "User Name        : " + str(userInfo.getUserName())
print "User Display Name: " + str(userInfo.getDisplayName())
print "User ID          : " + str(userInfo.getLoginUserName())
print "e-Mail           : " + str(userInfo.getEmail())
print "Default Language : " + str(userInfo.getDefaultLang())
print "Current Language : " + str(userInfo.getLangCode())
print "Timezone         : " + str(userInfo.getTimeZone())

# Check if we are running in Interactive mode or from a System Job
if not userInfo.isInteractive():
    print "------"
    print "Setting Language code to EN"
    print "------"

    userInfo.setLangCode("EN")

    print "Current Language : " + str(userInfo.getLangCode())

The script basically will get the UserInfo Object for the System User and after that will print out a couple of information. To avoid Null Pointers I have convert all outputs to a String value. At the end it will change the current Language for the user to a different value.


User Name        : MAXADMIN
User Display Name: Max Admin
User ID          : MAXADMIN
e-Mail           : None
Default Language : DE
Current Language : DE
Timezone         : sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]]
------
Setting Language code to EN
------
Current Language : EN

Some obstacles in the output:

  1. The Timezone value is not a string, but another object of type sun.util.calendar.ZoneInfo. If you need that information you should access the value with the methods from the ZoneInfo object.
  2. I implemented a condition “userinfo.isInteractive()”. Interactive normally means, that a script runs based on an end user GUI Action, while “not interactive” means that the script runs from an escalation or automatic workflow. If we run the script manually from the Automation Script application the isInteractive() method returns false.

Run a Script interactively from ICD/Maximo

The Automation Script application provides the capability to directly run a script without having a launch point defined. This is useful to test some scripting capabilities or to run scripts performing maintenance tasks triggered by an user.

AttentionIf you are using Maximo or ICD in Version 7.6.x you might not find the “Launch Script” Action. In that case you should read this article to solve this issue first!

To test this behavior we will create a simple script without a launch point which lists all defined users from the ICD/Maximo system. Important is, that in this scenario no implicit variables are available and you have to initialize your MBO context manually based on the MXServer object. The scripts looks as follows:

#DESCRIPTION:Script to demonstrate usage of Run-Script function from GUI
from psdi.server import MXServer
from psdi.iface.mic import MicService

mxServer = MXServer.getMXServer()
micService = MicService(mxServer)
micService.init()
userInfo = micService.getNewUserInfo()

# Example: Loop over all Users....
userSet = mxServer.getMboSet('MAXUSER', userInfo)
userMbo = userSet.moveFirst()
while (userMbo != None):   
    print "User ",userMbo.getString("USERID")    
    userMbo = userSet.moveNext()

To run the script you should hit the following icon in the Taskbar of the Automation Script application:
Selection_042

The result should look as follows:
Selection_043

Deleting Mbo’s

So far we know how to insert, update and view our Mbo records, so the next step is to delete a record.

You delete Mbo’s by calling the delete() method. This method removes the current Mbo from an MboSet. Basically the Mbo is not delete when you call the delete method it is more over marked for deletion. The real delete operation is executed when the transaction is commit to the database. In general this is the save operation on the MboSet.

Here comes an example which deletes a specifc Workorder from the Workorder MboSet:

    # Example: Delete a specific Mbo
    woset = session.getMboSet('WORKORDER')
    woset.setWhere("WONUM = '2009'")
    woset.reset()
    wo = woset.moveFirst()
    
    if wo is not None:   
        # Mark Mbo for deletion
        wo.delete()

        # Real delete is done at this point
        woset.save()

Using field Flags to set attribute content

Each attribute in Maximo / ICD can have several Validation Java classes and Jython scripts associated which will trigger when a new value for an attribute is set. Field flags can control some of the conditions under which the attributes can be modified and prevent execution of that classes / scripts.

The following field Flags are commonly used:

  • NOACCESSCHECK is used to update the value even if the attribute is marked readonly
  • NOVALIDATION supressess checking of the value. Be sure you know what you do, because you will prevent the business logic from checking for a valid value.
  • DELAYVALIDATION does not perform any validation when the attribute is modified. The validation takes place on the save action. This can be useful if the validity of an attribute depends on other attributes.
  • NOACTION is used to bypass the execution of all business rules. Use it carefully!
  • NOVALIDATION_AND_NOACTION is a combination of the NOVALIDATION and NOACTION flag.

Now how do we use these flags in Jython? They are used in the setValue() Method as a third parameter. So sometimes you will see scripts like this:

itemMbo.setValue(description", "Hello World!", 1L)

In this 1L stands for NOVALIDATION and it is bad practise to write it in a numeric format. How about this style?

from psdi.mbo import MboConstants
itemMbo.setValue("description", "Hello World!", MboConstants.NOVALIDATION)
companyMbo.setValue("company", "COM1", MboConstants.NOVALIDATION_AND_NOACTION)

If multiple field flags should be combined for a field they could be combined by a bitwise or operation. See this example:

from psdi.mbo import MboConstants
itemMbo.setValue("description", "Hello World!", MboConstants.NOVALIDATION | MboConstants.NOACCESSCHECK)

So far we always used the setValue method to directly manipulate the field flag while we are setting a value to a field. In some cases it is also useful to just set the field flag without applying a new value. This can be done with the setFieldFlag method. You can set and remove certain flags from a field. Mostly taken is this for the read only state:

from psdi.mbo import MboConstants
itemMbo.setFieldFlag("description", MboConstants.READONLY,False)
itemMbo.setValue("description", "Hello World!")
itemMbo.setFieldFlag("description", MboConstants.READONLY,True)

The setFieldFlag method can also take a list of fields as a parameter, if you would like to modify a bunch of fields:

from psdi.mbo import MboConstants
fields = ['DESCRIPTION','ITEMTYPE', 'ORDERUNIT']
itemMbo.setFieldFlag(fields, MboConstants.READONLY,False)

Implicit launchpoint Variables

Implicit launchpoint variables are predefined if a script runs in the context of ICD (not if you are using the RMI Interface).

Overview of Implicit Variables

The following list describes the most commonly used variables:

Input Variables (incoming to the script):

mbo – The current Mbo in the context of the script execution. This is an object.
mboname – The name of the current Mbo in context of the script as a string.
app – Name of the ICD application which initiated the script execution
user – Name of the user whose action initiated the script execution.
interactive – Is true if script is executed interactive via UI and false if executed in background (e.g. scheduler, integration framework).
scriptName – name of the script
launchPoint – name of the launch point
action – Only for action launchpoints the name of the action that executed the script.
onAdd – Boolean variable. Is True if the Mbo in the script is added and a new Mbo (not yet saved). Very useful for conditional launchpoints, but may also be useful for Object and Attribute launchpoints.
onUpdate – Boolean variable indicating that related Mbo is being updated.
onDelete – Boolean variable indicating that related Mbo is marked for deletion.
wfinstance – Object of type psdi.workflow.WFInstance that indicates the current workflow from which the action was started. This is only valid for action launchpoints if the action is launched from a workflow.

Output Variables (Script provides them back to ICD)

errorkey – For throwing MXExceptions from the script
errorgroup – For throwing MXExceptions from the script
params – For throwing MXExceptions from the script. This is a Array of Strings
evalresult – evaluation result of the Condition Launch point

Usage patterns

When using implicit variables in your script you should first care about the fact that the variables are nowhere defined and therefor eclipse will throw you an error on the first usage. Please have a look to the “Undefined Variables” Section in this articel to solve the issue.

Perform different actions based on the Launchpoint executing the script

A Jython script could have more than one launchpoint to start its execution. Sometimes the script needs to perform different kind of actions depending on the launchpoint. Another use case for this pattern is to assign different values to variables based on the launchpoint to omit the usage of launchpoint variables. A sample for this is shown in the article “Tips for using Eclipse with Jython” in the section “Prevent Using Script In-/Out Variables”

Execute script actions only if running from GUI

It is sometimes a requirement that a script behaves differently if it is called from a User GUI Interaction or from a system interaction like a crontask, escalation or an Integration Framework call. The following pattern can solve this issue:

interactive = interactive # @UndefinedVariable

if interactive == True:
# Things to do if script is running in user Context
else:
# Things to do if script is called by Crontask, MIF, ...
.

Execute different script actions depending on the ICD Application

Sometimes it is required that a script executes different paths depending on the Maximo application it is executed from. The code pattern is quit simple in that case:

app = app  # @UndefinedVariable

if app == "ASSET":
    # Do actions if called from asset Application
if app == "ITEM":
    # Do actions if called from item Application

Throwing an exception from a script

The usage of the errorkey/errorgroup/params variables is shown in this article.

Jython Introduction

Jython is an implementation of the Python programming language designed to run on the Java Virtual Machine (JVM) and can be used for Maximo / ICD scripting development. The syntax of Jython is based on Python but Java libraries can be included and used in Jython. This is a major benefit when we use Jython for Maximo / ICD Development because on the one hand side you will find a lot of documentation especially for the Python language on the other hand side you can include all Java libraries used in Maximo / ICD. One of the most commonly used libraries is the businessobjects.jar file, which contains most of the business logic included in the product.

In Maximo and ICD up to release 7.6, there is a relatively old version 2.5.2 of Jython in use. If you develop your scripts you should keep this in mind as there is already Jython 2.7 available today which has some new features included. With Maximo & ICD 7.6.1 you will have Jython 2.7 available

In this blog, I will not provide a dedicated introduction into the Jython language since there is some very good stuff available on the internet. I will give you some links at this point:

  1. Official Jython Homepage – with references and tutorials
  2. The Definitive Guide to Jython – Very good book!
  3. Intro to Jython, Part 1: Java programming made easier – IBM Developer Works article
  4. The Jython Wiki

Setting up Eclipse for Maximo / ICD Jython development

Introduction

When you start developing Jython scripts in context of Maximo & ICD the first question is where to edit the scripts. The provided editor in the Web-interface of the product can only be seen as a “Paste-In” area, since it absolutely lacks any needed development features. Better alternatives at this point can be the usage of more professional editors like UltraEdit or Notepad++. If you only want to develop a small set of short Jython scripts this can be a starting point for you. If you plan to do a bit more development I would highly encourage the usage of a professional development environment. In this article I would like to show you how you can set up the Eclipse platform to perfectly act as a Maximo & ICD development environment. I will guarantee you that the benefits of this platform over time are major, even if it is a bit work to setup at the beginning.

Required Software

So before we start let’s figure out, which software is needed for the installation:

  • Eclipse Luna (Download) (64 Bit)
  • Java JRE or SDK V1.7 or V1.8 (64 Bit) *** please see notices below
  • Jython Interpreter V2.5.2 (Download) – Even it is quit old – this is the used Version in the product.

Notices on Java:
For the development of Jython scripts the used JRE or SDK is really important. For Maximo/SCCD 7.5.x (TPAE 7.5) you need at least a JRE Level of Version 1.6 for Maximo 7.6 (TPAE 7.6) you need at least a JRE Level Version 1.7. I personally always try to use the IBM Java in the version 1.7 and set the JRE Compliance level to 1.6 if needed. I will show you later on how to set this – don’t care for the moment.

The download of the IBM Java is a bit tricky to find. The base download page is can be found here. For Windows you need to download the complete “IBM Development Package for Eclipse”, extract it and take out the JRE directory. You should use Version 5.0 64-bit which includes Java 7.1 (1.7).

Installing the Prerequisites

The installation of the software is described in this section.

  1. Eclipse installation

For Eclipse no special installation is required. It basically only needs to be extracted to a folder of your choose. On the first start you can select the folder where you would like to store your eclipse workspace (data-directory).

  1. Java JRE (optional – you may use your system JRE)

Depending on the Java Version you have to either run a setup program or just copy some files. The installed Java does not have to be the system Java! This is important to know if you use different software on your computer which requires a certain version of Java.

If you use the “IBM Development Package for Eclipse” just extract the “ibm_sdk71” subfolder to a folder on your local harddisk for later usage.

  1. Jython 2.5.2 Installation

Jython Installation is quit straight forward using the setup program. During installation you are asked for the Java Home directory where you should be careful to select the one provided by the Java JRE Installation.

 

Configuration of the Java Environment (optional)

At this point we need to set up the correct Java Environment Eclipse should use.

  1. In Eclipse go to “Window –> Preferences”.
  2. In the left navigation pane go to “Java –> Installed JRE’s”. In the window on the right you should see the currently installed JRE selected. If you have installed an additional JRE and want to make this the default JRE select the Add button on the right.
  3. Select “Standard VM” and “Next…”
  4. The next screen requires the definition of the new JRE. If you select the correct installation directory for your JRE home the rest of the Fields should be filled in automatically:
    eclipsejre1
  5. After selecting “Finish” a new SDK is available. The SDK which is checked and bold is the default SDK.

At the end the right Java compiler must be selected:

  • Maximo 6: Java 1.4
  • Maximo 7: Java 1.5
  • Maximo 7.5.x: Java 1.6
  • Maximo 7.6: Java 1.7

Set it in Eclipse preferences: Windows –> Preferences –> Java –> Compiler  –> Compile compliance level.

eclipsejre2

Installing the maximo.ear

The maximo.ear contains most of the Java method’s to operate on all kinds of Mbo’s and MboSet’s within TPAE. One of the best features of using Eclipse in comparison to a simple text editor is, that we can include the businessobjects JAR file from your Maximo/ICD installation and that we have some syntax checking and input features for these classes. I will show you in a later post how we can utilize these features to make our life easier.

The best way to make the JAR file available is to create an own project in Eclipse for the referenced Java libraries.

  • Select “File –> New –> Java Project” in the Eclipse Workbench with the name “MaximoLibs”.
  • Copy [SMPDIR]\maximo\deployment\default\maximo.ear from your admin workstation into the new project.
  • Extract the following files from the maximo.ear file:
    • jar
    • war and extract the content to a directory named maximouiweb
    • lib/*.jar files to a directory lib
  • Refresh the project tree in Eclipse (F5). Your project should now looks like follow:
    eclipsejre3

Installing the PyDev Plug-In in Eclipse

After the initial start of Eclipse and the selection of a workspace directory you find yourself in the Welcome screen, which should be closed using the “Workbench” symbol in the upper right corner.

To install PyDev select the Menu “Help à Install new Software…”

  1. Enter the text http://pydev.org/updates into the Work with text box.
  2. Select only the PyDev checkbox
    pydev1
  3. Press the Next Button…
  4. You get the Installation Details displayed where you also can press “Next”
  5. Accept the License and press “Finish”. The installation starts.
  6. At the end of the installation you are asked to restart Eclipse. Please answer with “Yes”.

Configuring PyDev in Eclipse

To configure PyDev perform the following steps:

  1. After Restart, click Window and then click Preferences.
  2. Find the entry “Jython Interpreter” as shown in the picture and select “New…”
    pydev2
  1. Enter “Jython 2.5.2” as the Interpreter Name and find the jython.jar file from your previous Jython installation. Select “OK”.
    pydev3
  2. The configuration starts. Select OK in the dialog which appears.

At the End your Jython Interpreter Configuration should look similar to this one:

pydev4

Create a new PyDev project

Now create a new PyDev project where you can store you Jython sources.

  • Select: File –> New –> Project
  • Select the wizard PyDev Project and select Next
  • Enter a project Name and select the correct Project Type Jython and the Grammar Version 2.5 with your defined Interpreter.
    eclipsejre4
  • Press Finish.

You get a question if the associated PyDev perspective should be opened. Select Yes.

Congratulations you have your first Python/Jython project. There is still one little piece missing…

Referencing the Maximo Java libraries

In a previous step we have extracted the Maximo related Java libraries. To use them in our Jython project we need to reference them.

  • Right click to your new project in the PyDev Package Explorer window and select properties.
  • In the property window select the option “PyDev – PYTHONPATH”
  • Select the tab “External Libraries”.
  • Using the “Add zip/jar/egg” button you can add all required libraries from the referenced project. At least the businessobjects.jar file should be added, but all other jar files could be added in addition. At the end your configuration looks like this:
    pydev5

Creating your first Jython Script

To create the first Jython script right click on your newly created project and select New –> File in the Popup Menu. Select a filename of your choose with the extension “.py” and click on Finish.

You are asked for the Default Eclipse preferences for PyDev. Just click ok.

You are now ready to create your first Jython script, but this is a story for another post.

TPAE Scripting customization points

In this blog I will shortly document the different ways a Jython script can be triggered in TPAE. The following launch points and invocation methods are available to start a script:

Launch points

A launch point is a configuration objects which triggers an automation script if a certain condition occurs. When a launch point is deactivated, the script associated with that launch point does not run. The The following launch point types can be defined in TPAE:

Object Launch Point

  • Execute scripts on MBO events such as init, add, update, or delete (TPAE 7.5)
  • Starting from TPAE 7.6 this kind of Launch Point has a much more fine granular configuration.
  • Execute the script on:
    • Initialize Value: executed when the MBO is initialized
    • Validate Application: executed when the MBO is validated against business rules, but is not yet saved in the Database
    • Allow Object Creation: Indicates whether Maximo business objects can be created.
    • Allow Object Deletion: Indicates whether Maximo business objects can be deleted.
    • Save: executed in the process of saving the MBO. In this case more fine granular specifications about the execution time (before Save, after Save, After Commit) can be made.

Attribute Launch Point

  • Execute scripts based on the change of an attribute. This type of launchpoint is used for field validations or other actions.
  • Starting from TPAE 7.6 this kind of Launch Point has a much more fine granular configuration.
  • Execute the script on:
    • Initialize access restriction: Sets the access level for the attribute’s field. (Example: Read/Write to Read only)
    • Initialize value: Sets the initial value for the attribute’s field.
    • Validate: Checks whether the value in the attribute’s field is valid.
    • Retrieve list: Retrieves a list of valid values for the attribute’s field. For example, in an invoice, you can set up the supplier field to return a list of approved vendors.
    • Run action: Runs an action that is based on the value that is in the field.
  • Example can be found here

Action Launch Point

  • Execute scripts in the context of workflow/escalation actions
  • Execute scripts in the context of a Menu or Button (Sample here)

Custom condition Launch Point

  • Workflow conditions and conditional expressions can be utilized by Custom condition launch point

Other Methods

Manually Run from Scripting Application

  • Run a script without any launchpoint defined. (Sample here)

Remote Method Invocation (RMI)

  • Runs scripts from outside TPAE. See here for further details.

Interfaces (starting from Maximo 7.6)

  • Runs in context of Integration Framework to convert data