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

Download (all) Scripts from Maximo / ICD to your Eclipse Project

In one of my last blogs I showed a very nice way how to upload Jython scripts from Eclipse to your Maximo / ICD environment. Now what about the situation that you already have a Maximo / ICD environment with tons of scripts in it? In this blog I will show you a simple way how you can include all these scripts to your Eclipse project within 15 minutes. This will also include the first comment lines needed for the later upload.

To achieve our goal the following steps are needed:

  • Setup an application export in the Autoscript application
  • Download a XML File including all scripts
  • Run a Jython script to extract all the unique scripts

Setup an application export in the Autoscript application

The application export will be configured using the “Object Structures” application. Launch:

Go To > Integration > Object Structures

In the Object Structures application search for the “MXSCRIPT” Object Structure and open it.

Selection_018

After opening select an action:

Select Action > Add/Modify Application Export Support

 

Menu_020

In the dialog box create a new row in the table using the values shown here:

Selection_021

Press OK. The export support now has been created. Next step is to grant the security rights to the user group which should use the tool. In my example I will grant the rights to the maxadmin group. Goto the following Menu:

Go To > Security > Security Groups

Now perform the following steps:

  1. Search and open the security group you want to grant the rights to.
  2. Change to the “Applications” Tab.
  3. Filter for the Application “Automation Scripts” and select the record.
  4. In the Options for Automation Scripts section enable the option “Application Export”.Selection_022
  5. Save the Security Group.
  6. Logoff and Logon again to Maximo / ICD. Be sure that all your user sessions are successfully logged of – otherwise the settings will not be activated.

Download a XML File including all scripts

To download a XML File which includes all scripts in your system you have to go to the Automation Scripts application.

Go To > System Configuration > Plattform Configuration > Automation Scripts

If the previous step worked correctly you should now see a new Icon in the iconbar Selection_023for the application export. Before you press this button you have to search for the scripts to export. If all scripts should be exported just press enter in the search field. Now press the icon.

In the “Application Export” Dialog you just can take all settings and press “OK”.

Selection_024

The XML File now will be downloaded to the download directory of your browser on your local PC.

Run a Jython script to extract all the unique scripts

First of all you have to have a project setup in Eclipse where you would like to store your downloaded scripts. This chapter requires a complete project-setup using Eclipse, Jython and PyDev like described in this blog. Copy the downloaded XML file to this directory and name it scripts.xml.

Now create a Jython script with the following code:

#AUTOSCRIPT:EXPORTSCRIPTS
#DESCRIPTION:Script to export all Jython Scripts on a Server
#LOGLEVEL:ERROR

from java.io import File
from org.jdom.input import SAXBuilder

xmlFile = File("scripts.xml")
builder = SAXBuilder()

document = builder.build(xmlFile)
wrap = document.getRootElement()
ns = wrap.getNamespace()
rootNode = wrap.getChild("MXSCRIPTSet", ns)

liste = rootNode.getChildren("AUTOSCRIPT",ns)
for i in range(0,liste.size()):
    node = liste.get(i)
    scriptName = node.getChildText("AUTOSCRIPT",ns)
    scriptDesc = node.getChildText("DESCRIPTION",ns)
    scriptVersion = node.getChildText("VERSION",ns)
    scriptDebug = node.getChildText("LOGLEVEL",ns)
    scriptCode = node.getChildText("SOURCE",ns).encode('utf-8')
    
    scriptFile = open(scriptName + ".py","w")
    scriptFile.write("#AUTOSCRIPT: " + scriptName + "\n")
    scriptFile.write("#DESCRIPTION:" + scriptDesc + "\n")
    scriptFile.write("#VERSION:    " + scriptVersion + "\n")
    scriptFile.write("#LOGLEVEL:   " + scriptDebug + "\n")
    scriptFile.write(scriptCode)
    scriptFile.close()

This scripts requires the Java JDOM Class. Please ensure that the jdom.jar file is included in your PYTHONPATH. You can check this by right-click on your Eclipse project and select the “Properties” Menu. Check under “PyDev – PYTHONPATH” if jdom.jar is existent. If not use the “Add zip/jar/egg” Button to add it.

Selection_025

Remark: If you don’t have a local version of jdom.jar you can find one on your Maximo / ICD Server in the following directory: %WEBSPHERE _DIR%\AppServer\profiles\ctgAppSrv01\installedApps\ctgCell01\MAXIMO.ear\lib

Everything is prepared now. You can run the Script now from Eclipse using the Run Icon Arrow  Selection_009 and then the following menu:

Menu_026

Hopefully after a refresh of your project/folder (F5) you will see a bunch of new scripts! Congratulations!

Upload Jython Scripts from Eclipse to Maximo/ICD

In this post I would like to introduce a cool feature to upload your Jython scripts developed in Eclipse directly to Maximo/ICD without the need to jump to the scripting application and doing some copy/paste actions. To Archive this objective we will utilize the Integration Framework and will write a small Jython script to be called from Eclipse and utilizing this interface. I will show you step by step the different configuration steps.

This is a quit complex configuration to do and there are a lot of places to introduce errors so that the complete system will not work. Please post me your experiences with the configuration as a comment so I can improve this article over time.

Prerequisites

What are the prerequisites for our project:

  1. An Eclipse Installation with PyDev integrated where you develop your Jython Scripts
  2. A local Jython 2.x installation (which should normally already be in place). Please consider that we need a full installation and it is not enough to just have a copy of the jython.jar file since we need some standard Jython libraries for our project.
  3. Access to a Maximo/ICD System

The solution currently only has been tested with local authorization. The Upload script might need slight modifications for LDAP authorization (comments welcome :-).

The solution currently only supports http protocol. If you are using https the upload script might need some modifications.

Preparations Integration Framework in Maximo/ICD

Create a new Object Structure

We need to create an own Object Structure based on the existing MXScript Structure.

  1. Go to menu Integration → Object Structure and search the MXScript Object Structure.
  2. Duplicate the Object Structure (Select Action → Duplicate Object Structure)
    jythoneclupl1
  3. The new Object Structure should be called JYSCRIPT unless you want to edit the upload script later on.
  4. Remove the Source Object „AUTOSCRIPT/VARSThe configuration for the duplicated Object Structure should now look like this:jyecli02
  5. Select Action → Exclude/Include Fields
    Exclude all fields except the following ones:
    • AUTOSCRIPT
    • DESCRIPTION
    • LOGLEVEL
    • SCRIPTLANGUAGE
    • SOURCE
    • VERSION

Create an Enterprise Service

A new Enterprise Service must be created.

  1. Go to menu Integration → Enterprise Services
  2. Create a new Record and fill in the following fields only:
    jyecli03
  3. Save the Enterprise Services

Create an External System

A new External System must be created by the following steps:

  1. Go to menu Integration → External Systems
  2. Create a new Record and fill in the System Tab with the following values:
    jyecli04
  3. Be sure all fields are filled in as shown
  4. Select the tab “Enterprise Services” and create a connection to the previously created Enterprise service. For this select the “New Row” button. Fill in the new line as follows:
    jyecli05
  5. Be sure that the enabled box is checked.
  6. Save the External System. The configuration on the Maximo/ICD side is now finished.

 Configuration of the Eclipse Side

The configuration of Eclipse consist of two steps:

  • Prepare Upload Script
  • Create a “Run entry” in the Run configuration.

Prepare Upload Script

Take the following script and store it in a place of a Eclipse project. The project should have a valid Jython Runtime configured. Please have a look to this article for proper Eclipse setup if you are unsure.

#-------------------------------------------------------------
# AUTOSCRIPT:         UPLOADSCRIPT
# DESCRIPTION:        Script to upload Jython Scripts from
#                     Eclipse to Maximo / ICD
# AUTHOR:             Matthias Stroske
# Created             25.11.15
# VERSION:            1.0
# COPYRIGHT:          (c) Matthias Stroske
# MAXIMO/ICD Version: 7.5 and higher
#-------------------------------------------------------------
# History of Changes
#
# Ver  Date      Name               Description
# 1.0  01.10.15  Matthias Stroske   Initial Version
# 1.1  25.11.15  Matthias Stroske   Improved Parameter Handling
#
#-------------------------------------------------------------
 
import sys
import httplib
import base64
import string
import re
from xml.sax.saxutils import escape
 
def main():
    if len(sys.argv) < 5:
        print "USAGE: UploadScript.py <inDatei> <host> <user> <password>"
        sys.exit()
 
    inDatei = sys.argv[1]
    host = sys.argv[2]
    user = sys.argv[3]
    password = sys.argv[4]
     
    # Set Defaults as far as possible
    scriptName = None
    scriptDescription = None
    logLevel = "ERROR"
    version = "1.0"
 
    httpUrl = "http://" + host + "/meaweb/es/JYSCRIPT/JYSCRIPT"
 
    try:
        f = open(inDatei)
        fileContent = f.read()
    except Exception,ex:
        print ("Error reading the input file!")
        print ("Exception:" + str(ex))
    else:
        f.close
 
    firstLines = fileContent.split("\n", 15)
    for line in firstLines:
        matchObj = re.match(r'^#\s*DESCRIPTION:(.*)',line, re.I)
        if matchObj:
            scriptDescription = matchObj.group(1)
        matchObj = re.match(r'^#\s*AUTOSCRIPT:(.*)', line, re.I)
        if matchObj:
            scriptName = matchObj.group(1)
        matchObj = re.match(r'^#\s*LOGLEVEL:(.*)', line, re.I)
        if matchObj:
            logLevel = matchObj.group(1)
        # Simple Style
        matchObj = re.match(r'^#\s*VERSION:(.*)', line, re.I)
        if matchObj:
            version = matchObj.group(1)
        # CVS Style
        matchObj = re.match(r'^#\s*Revision:(.*)', line, re.I)
        if matchObj:
            version = matchObj.group(1)
             
 
    if scriptName is None or scriptDescription is None:
        print "ScriptName and ScriptDescription have to be specified in first Script Lines!"
        sys.exit()
 
    print "Script Name       = " + scriptName.strip()
    print "DESCRIPTION       = " + scriptDescription.strip()
    print "LOGLEVEL          = " + logLevel.strip()
    print "VERSION           = " + version.strip()
          
    message = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
    message += "<SyncJYSCRIPT xmlns=\"http://www.ibm.com/maximo\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"
    message += "<JYSCRIPTSet>\n"
    message += "<AUTOSCRIPT>\n"
    message += "<AUTOSCRIPT>" + scriptName.strip() + "</AUTOSCRIPT>\n"
    message += "<DESCRIPTION>" + scriptDescription.strip() + "</DESCRIPTION>\n"
    message += "<LOGLEVEL>" + logLevel.strip() + "</LOGLEVEL>\n"
    message += "<SCRIPTLANGUAGE>jython</SCRIPTLANGUAGE>\n"
    message += "<VERSION>" + version.strip() + "</VERSION>\n"
    message += "<SOURCE>\n"
    message += escape(fileContent)
    #message += "pass\n"
    message += "</SOURCE>\n"
    message += "</AUTOSCRIPT>\n"
    message += "</JYSCRIPTSet>\n"
    message += "</SyncJYSCRIPT>\n"
    message += "\n"
 
    contentType = "application/soap+xml;charset=UTF-8;action=\"urn:processDocument\""
    auth = 'Basic ' + string.strip(base64.encodestring( user + ':' + password))
     
    webservice = httplib.HTTPConnection(host)
    #webservice.set_debuglevel(5) 
    headers = {"Content-type": contentType, "Content-Length": len(message), "Authorization": auth}
    webservice.request("POST", httpUrl, message, headers)
             
    # get the response
    res = webservice.getresponse()
     
    if res.status == 200:
        print "Script upload successful!"
    else:
        print "Script upload completed with RC = " + str(res.status)
     
    webservice.close()
    return
      
if __name__ == "__main__":
    main()

Eclipse External Tools configuration

To run the script in context of Eclipse you need to do an additional configuration step in Eclipse.

Find the following Icon in the Eclipse iconbar:   Selection_004

Select the little arrow beside the icon to expand the menu and select “External Tools Configurations…”

Menu_016

In the following Window fill in the Head section with the Name of the configuration.

Continue to fill in the  Main tab with the following values:

  • Location: The location of your locally installed Jython interpreter.
  • Working Directory: should be ${workspace_loc:/<ProjectName}
  • Arguments: 5 Arguments for the Jython interpreter to run.
    1. Name of Jython Upload Script: e.G. ${workspace_log:/Blog/UloadScript.py}
    2. Name of the Script to be uploaded: Best we can specify here is always: ${workspace_loc}${selected_resource_path}
    3. Maximo / ICD Host: IP Adress or Hostname of the Maximo Server
    4. Username in Maximo / ICD
    5. Password in Maximo / ICD  *** yes I know it is not good to store the PW in clear-text. With little modifications you could store it base64 encoded here if you modify the Jython script slightly.

Selection_017

Preparing your script and using the new tool

Preparing your script

To use the new tool your script must follow a little convention. The first 15 lines must include relevant information which are required to synchronize the script with Maximo/ICD.

#AUTOSCRIPT: UPLOADSCRIPT
#DESCRIPTION: PYTHON UPLOAD SCRIPT 2
#LOGLEVEL: ERROR
#VERSION: 1.0

This are fields which map to the appropriate fields in Maximo/ICD. The AUTOSCRIPT field is the Name of the Autoscript in Maximo/ICD. With the upload you can create new automation scripts, but you can not create or modify any launchpoints. When you change the DESCRIPTION,VERSION or LOGLEVEL field later on these fields are modified in Maximo/ICD.

I have created a base template for your code, which can be found in this blog.

Using the new Tool

To use the tool we assume, that you are now editing your custom Maximo/ICD Jython script with the information lines included and some Jython Code. From this place you just need to run the Upload Script by Clicking the Run external Symbol in the iconbar again. Selection_004 A script with the name you have chosen during configuration should appear in the drop down list.

After some second you will hopefully get a response “Script upload successful”  in the Console View of Eclipse. Otherwise you’ll get an error with the http Return Code.

Selection_046

I hope the solution will work in your environment!

Tips for using Eclipse with Jython

After you hopefully read the article about setting up Eclipse for Maximo Jython development, there are some Tips & Tricks to get the best results from using Eclipse in combination with Jython. A short summary can be found here:

Undefined Variables

You often use so called implicit variables when you program in context of a launchpoint. The best known variable is mbo which is used quit often. If you use this variable in context of Eclipse it will throw an error in the GUI, because it has never been declared in context of the script.

undefinedvariable1

My best practice is to assign these variables at the beginning of the script to another variable even using a more meaningful variable name (or even the same name) and using the @UndefinedVariable tag. The above sample would now looks like this and will not throw any error:

workorderMbo = mbo  # @UndefinedVariable
workorderMbo.getString("wonum") 

Prevent Using Script In-/Out Variables

Maximo provides you the opportunity to define In-/Out Variables in context of a launchpoint. Variables defined in that way can be accessed as regular variables in Jython but will seamlessly read/change the content of an MBO attribute. This looks very handy at the beginning, but will make reading of scripts much harder, because you can never be sure which attribute a variable is really bound to. In addition you get much more issues with Undefined Variables in eclipse. So in fact of clarity I am a big fan of not using In-/Out Variables. I will show you the programming alternative to this:

In-Variables

assetNum = mbo.getString(“ASSETNUM”)

Out-Variables

mbo.setValue(“ASSETNUM”,assetNum)

Now you could say that the Maximo mechanism will provide you the benefit to assign different values to a variable based on its launchpoint. The situation can also be handled quit simple using some script code:

launchPoint = launchPoint  # @UndefinedVariable
if launchPoint == ‘MYLAUNCHPOINT1’:
    assetNum = mbo.getString(“ALTASSETNUM”)

So I hope you will not see any uncovered situations but your script has now all clarity at one place.

Let Eclipse organize your Imports

Have you ever seen a Jython script which starts like this:

from java.io import *
from java.rmi import *
from psdi.mbo import *

This is really bad style because you will import the complete classes from which you only need a small piece. Much better:

from java.io import files
from java.rmi import RemoteException
from psdi.mbo import MboConstants

But how can you easily maintain the shown list? Quit easy: Don’t care about – Eclipse will help you. Never define an Import manually!
Just write your code using an method from a class library. When you use an method not yet imported Eclipse will help you with an error. Just place your mouse over the error and you will get a hint like this:

undefinedvariable2
Now press the CTRL-1 one key and Eclipse will show you how it might solve the issue:
undefinedvariable3

By selecting the first option “Import MXServer (psdi.server)” Eclipse will create the import statement for you:

from psdi.server import MXServer

On the other hand side, when you no longer need an import Eclipse will show a warning on that import:

undefinedvariable4

You can just delete the line. Even when you delete a line to much you now know an easy way to restore the imports.

Use a Revision Control System

I think it is agreed best practice to have a Revision Control System in place when you develop more than some small scripts. But sometimes you do not have a choose and there is no tool available in your environment. For that case there is a cool, but not well known function within Eclipse. The Team function provides a local history of your edits within the last 7 days. You do not have to activate it, it’s just there!

To get an older file version right click on the File and select Team > Show Local History…

undefinedvariable5

You can now right click an entry and either open it directly or compare an old version with the current version. That is a very nice feature.

How about the 7 days? You may want a longer retention period for your files.

Select: Window > Preferences in the menu.

In the tabs on the left select: General > Workspace > Local History

In this configuration page you can either completely remove time limits for this function or extend the number of days and size for the history.

undefinedvariable6