Jython Script Templates

In this post I would like to provide you simple script templates which can be used for your next project and which are compatible to the Eclipse to Maximo/ICD Upload Script described in this blog.

The following Template is for general usage in a Launchpoint script:

#-------------------------------------------------------------
# AUTOSCRIPT:         SIMPLETEMPLATE
# DESCRIPTION:        Sample template for usage in Launchpoints   
# AUTHOR:             Matthias Stroske
# Created             01.10.15
# LOGLEVEL:           ERROR
# VERSION:            3.0
# COPYRIGHT:          (c) Matthias Stroske
# MAXIMO/ICD Version: 7.6
#-------------------------------------------------------------
# History of Changes
#
# Ver  Date      Name               Description
# 1.0  01.10.15  Matthias Stroske   Initial Version
#
#-------------------------------------------------------------

mbo  # @UndefinedVariable

If you are using a CVS System to check in your scripts you can use the following template. A couple of sections like $Author: $, $Revision: $ and so on are automatically filled in when you check in your code. Specially the $Revision: $ tag is very nasty in combination with the Maximo Script upload, because it automatically sets the Verion of the Script in Maximo to the CVS Revision. Here the full template:

#-------------------------------------------------------------
# AUTOSCRIPT:         SIMPLETEMPLATE
# DESCRIPTION:        Sample template for usage in Launchpoints with CVS Integration
# LOGLEVEL:           ERROR
# COPYRIGHT:          (c) Matthias Stroske
# MAXIMO/ICD Version: 7.6
#-------------------------------------------------------------
# $Author: $
# $Revision: $
# $Date: $
#-------------------------------------------------------------
# History of Changes
#
# $Log: $
#
#-------------------------------------------------------------

mbo  # @UndefinedVariable

MboValueAdapter – Initial, Previous and Current Value of a Field

The Theory

Sometimes when you work with a Mbo in a MboSet and you change fields in a Mbo it can be useful to get the original value of the field before the change or the last value of the field before the change. So basically a field can have three different values we can ask for:

valudata2

For that purpose we can use the MboValueAdapter and MboValue classes which are automatically initialized with every Mbo retrieved from the system

The CurrentValue of  a field usually can be red by the following Method via a Mbo:

wonum = mbo.getString("WONUM") # wonum is of type string

The same action can also be achived using the MboValueAdapter:

mboValue = mbo.getMboValue("WONUM") # mboValue is of Type mboValue 
currentValue = mboValue.getCurrentValue() # currentValue is of type MaxType
wonum = currentValue.asString() # wonum is of type string

# The previous 3 lines can be merged to a shorter Version:
wonum = mbo.getMboValue("WONUM").getCurrentValue().asString()

Now the short version to get the PreviousValue which can only be get via the MboValueAdapter:

wonum = mbo.getMboValue("WONUM").getPreviousValue().asString()

And the InitialValue which represents the state of the field when the MboSet was initialized:

# Version via Mbo:
wonum = mbo.getDatabaseValue("WONUM")

# Version via ValueAdapter
wonum = mbo.getMboValue("WONUM").getInitialValue().asString()

 

A practical Example

The scenario I will show you in this blog is based on the Item Mbo and the description field. I will change this field several times and always show you the initial, previous and current value of this field. Precisely we will do the following:

valuedata

As you can see we have 3 point where we verify our output. The following script can be easily created as a new Automation Script without launchpoint. Just take it and try it out! You can run the Script directly from the Automation Script Application.

#AUTOSCRIPT:MBOVALUEADAPTER
#DESCRIPTION:Demo to show usage of mboValueAdapter
#LOGLEVEL:ERROR
from psdi.server import MXServer
from psdi.iface.mic import MicService

# Initialize some stuff
mxServer = MXServer.getMXServer()
micService = MicService(mxServer)
micService.init()
userInfo = micService.getNewUserInfo()

itemSet = mxServer.getMboSet('ITEM', userInfo)
itemMbo = itemSet.moveFirst()
 
# Get Value for Field Description
stringValue = itemMbo.getString("DESCRIPTION")
itemMbo.setValue("DESCRIPTION", stringValue + "_new")

# Get the new Value again
stringValueNew = itemMbo.getString("DESCRIPTION")
itemMbo.setValue("DESCRIPTION", stringValue + "_new_new")

# Get the new Value again
stringValueNewNew = itemMbo.getString("DESCRIPTION")

print "Original Value              = " + stringValue
print "Value after 1. Change       = " + stringValueNew
print "Value after 2. Change       = " + stringValueNewNew


# Now work with the new MboValue Class
mboValue = itemMbo.getMboValue("DESCRIPTION")
initialValueAsString = mboValue.getInitialValue().asString()
previousValueAsString = mboValue.getPreviousValue().asString()
currentValueAsString = mboValue.getCurrentValue().asString()

print "-----------------------------------------------------------------"
print "Now Mbo Value Results"
print "-----------------------------------------------------------------"
print "Initial Value               = " + initialValueAsString
print "Previous Value before 2. change = " + previousValueAsString
print "Current Value from MboValue = " + currentValueAsString

itemSet.save()

print "-----------------------------------------------------------------"
print "Now After itemSet.save()"
print "-----------------------------------------------------------------"

mboValue = itemMbo.getMboValue("DESCRIPTION")
initialValueAsString = mboValue.getInitialValue().asString()
previousValueAsString = mboValue.getPreviousValue().asString()
currentValueAsString = mboValue.getCurrentValue().asString()

print "Initial Value               = " + initialValueAsString
print "Previous Value before 2. change = " + previousValueAsString
print "Current Value from MboValue = " + currentValueAsString

itemSet.reset()
itemSet = mxServer.getMboSet('ITEM', userInfo)
itemMbo = itemSet.moveFirst()

print "-----------------------------------------------------------------"
print "Now After itemSet.reset()"
print "-----------------------------------------------------------------"

mboValue = itemMbo.getMboValue("DESCRIPTION")
initialValueAsString = mboValue.getInitialValue().asString()
previousValueAsString = mboValue.getPreviousValue().asString()
currentValueAsString = mboValue.getCurrentValue().asString()

print "Initial Value               = " + initialValueAsString
print "Previous Value before 2. change = " + previousValueAsString
print "Current Value from MboValue = " + currentValueAsString

The output should look similar to the following:

Original Value              = IT Services
Value after 1. Change       = IT Services_new
Value after 2. Change       = IT Services_new_new
-----------------------------------------------------------------
Now Mbo Value Results
-----------------------------------------------------------------
Initial Value               = IT Services
Previous Value before 2. change = IT Services_new
Current Value from MboValue = IT Services_new_new
-----------------------------------------------------------------
Now After itemSet.save()
-----------------------------------------------------------------
Initial Value               = IT Services
Previous Value before 2. change = IT Services_new
Current Value from MboValue = IT Services_new_new
-----------------------------------------------------------------
Now After itemSet.reset()
-----------------------------------------------------------------
Initial Value               = IT Services_new_new
Previous Value before 2. change = IT Services_new_new
Current Value from MboValue = IT Services_new_new

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.

Using Maximo messages in multi-language environments

Your first question could be in this context: “Why should I read translations from the message system? Messages for Message boxes are always displayed in the correct user language!”. This is correct, but let’s assume the case that you would like to fill in a String field in a MBO Record with a text string which should be in the correct language of the user who is using the system. In that case we are not using the message system of Maximo in it’s original form, but more as a translation vehicle which we can ask: “I have a user with German language settings here. Please provide me the the defined translation for message <msggroup> <msgkey>.”. This is cool.

I will show you with a short script how you can display the content of messages in different languages:

#DESCRIPTION:Translate messages in the User-Language
from psdi.server import MXServer

mxServer = MXServer.getMXServer()
userInfo = mxServer.getUserInfo("maxadmin")

def getMessage(group, key):
    return MXServer.getMXServer().getMessage(group, key, userInfo.getLangCode())

userInfo.setLangCode("EN")  
print getMessage("access", "DBConnectFail")
print "--------------------------------------------------------"

userInfo.setLangCode("DE")
print getMessage("access", "DBConnectFail")

The result from running this script directly in the Automation Script Application (see here for details how to run a script) should look as follows:

Selection_045

Quit cool. Instead of printing out the message you could assign it to a variable and do some work on it…

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

Use a Button to launch an action script

A very common usage of automation scripting is to develop the action logic when a button is pressed in an application. The concept I will describe in this blog is principal the same for the following three scenarios:

  • A button included in the application with the application designer (I will show this in this blog)
  • A Toolbar Menu entry (Icon Toolbar)
  • A Action Menu entry

So what are the steps to create a button and run the script on it?

  • Create a new Signature Option and assign it to the appropriate user group.
  • Create the new Button, Toolbar Menu or Action Menu in Application Designer.
  • Create a new Automation Script with an Action launchpoint.

I would like to take a demo scenario with very simple scripting so we can concentrate mainly on the other stuff. In the Item Master Application when a new item is created the Commodity Group and Commodity Code has to be selected for each item. Let’s say you are mostly entering new Laptop items and you would like to get a “Default Commodity” button to fill in these two fields with default values like this:

Selection_028

That’s basically all, so lets start.

Create a new Signature Option and assign it to the appropriate user group

To create a new Signature Option we need to go the the Application Designer:

  • Go To > System Configuration > Platform Configuration > Application Designer
  • Select the application ITEM (Item Master) in the List View.
  • Now you go the “Select Action” menu and select the “Add/Modify Signature Options” entry.

Menu_030

  • In the dialog which opens hit the “New Row” button to add a new Signature Option.
  • Create a new Option with a name and a comment like follows:

Selection_031

And now the important part!!! Did you recognized the “Advanced Signature Options” section which is closed by default? Open it and check the following point:

Selection_032

If you forget to check this entry your button will never work and your script will never run.

  • Click on OK to close the dialog.
  • Assign the new Signature Option to a Security Group where your user is in (e.G. MAXADMIN for testing). You will find the new signature Option in the ITEM Application section:Selection_033
  • Don’t forget to logoff / logon to the Server before you proceed.

Create the new Button in Application Designer

After a new logon proceed in the Application Designer:

 

  • Go To > System Configuration > Platform Configuration > Application Designer
  • Select the application ITEM (Item Master) in the List View.
  • In the Application design screen select the “Item” Tab from the application.
    Selection_035
  • Open the Control Palette dialog in the Toolbar: Selection_034
  • From the Control Palette Drag and Drop the “Button Group” symbol to the “Commodity Group” Text. The button group should occur above the Commodity Group.
  • Right Click on the “pushbutton…” and select the properties Menu
  • Enter the following Values:
    • Label: “Default Commodity”
    • Event: “DEFCOMM” (This is the Name of the Action we will define later)
    • Signature Option (on page two): DEFCOMM (the one you created before)
      Selection_036

That is basically all you need to do in Application Designer. Your Button should now look as follows:

Selection_037

Save your work.

 

Create and test the automation Script

The new script will be created in:

Go To > System Configuration > Plattform Configuration > Automation Scripts

In the Select “Select Action” box select “Create > Script with Action Launchpoint”.

Menu_038

Fill in the dialog as follows and press “Next” when done:

Selection_039

Interesting here is the Object field. This field is the MBO Object your are in and which your script will get as the implicit “mbo” Variable.

In the next dialog we need to fill in some more values. It is always good practise to name the action, launchpoint and script the same (unless you will have multiple launchpoints with different meanings for a script).

Selection_040

Press the “Next” button when filled in.

In the last dialog you will have to paste in the following script code:

itemMbo = mbo  # @UndefinedVariable
itemMbo.setValue("COMMODITYGROUP", "43211500")
itemMbo.setValue("COMMODITY", "43211503")

Press “Create” to create the automation script. The Action object will be automatically created in background. Don’t forget this when you need to transport your development to another system.

Test the new solution

To test your new button:

Go To > Inventory > Item Master

Create a new Item and press the new Button. The Commodity Group and Code should be automatically be filled in. Congratulations!

Selection_041