August 31, 2012

MBO Performance Tip N.5 - Avoid using setQbe method, use setWhere instead

This entry is part of the Java MBO performance optimization golden rules series.

The MboSet.setQbe() method is designed to be used to build filters from the user interface. Using the MboSet.setQbe() method will automatically add jolly characters in text searches preventing the database server to be able to use indexes.
For example let's look at the following code snippet.

MboSetRemote assetMboSet = session.getMboSet("ASSET");
assetMboSet.setQbe("ASSETNUM", "1000");

This tells the TPAE server to execute an SQL query like this:

SELECT * FROM asset WHERE assetnum LIKE '%1000%'

This will lead to an inefficient table scan.
Therefore, where conditions on a MboSet should be set using the setWhere() method unless you explicitly need the functionality provided by setQbe().

August 30, 2012

MBO Performance Tip N.4 - Be careful when calling

This entry is part of the Java MBO performance optimization golden rules series.

This tip regards the correct handling of transactions in TPAE.

The important concept to understand is that MBOs obtained via relationship are included in the same transaction as the parent MBO set. When any MboSet in the transaction is saved, all MboSets in that same transaction will be saved. Any redundant call to method will affect performance and break the transaction chain.
Theoretically the must be called once after all the needed changes have been made to optimize performances and to correclty handle database transactions.

In the following example there is an unnecessary invocation of the save() method.

MboSetRemote pos = MXServer.getMXServer().getMboSet("PO", userInfo);
MboRemote po = pos.moveFirst();
po.setValue("VALUE1", newValue1);;  // this is a redundant save
MboSetRemote polines = po.getMboSet("POLINE");
for(MboRemote poline=polines.moveFirst(); poline!=null; poline=polines.moveNext())

The redundant save() call can be removed without problem invoking only the method at the end.

MboSetRemote pos = MXServer.getMXServer().getMboSet("PO", userInfo);
MboRemote po = pos.moveFirst();
po.setValue("VALUE1", newValue1);
MboSetRemote polines = po.getMboSet("POLINE");
for(MboRemote poline=polines.moveFirst(); poline!=null; poline=polines.moveNext())
};  // this saves all the updates

Since the polines MboSet is retrieved from the pos MboSet, the invocation will also commit all the updates on the child objects retrieved through a relationship.

Sometimes it may be a good idea to avoid keeping transactions open for long periods of time. To achieve this you can fetch MBOs using a new transaction using MXServer.getMboSet() method.

MboSetRemote mboSet = MXServer.getMXServer().getMboSet(setname, getUserInfo());

Caution! Keep in mind that transactions will be kept open longer if you delay calling save. You need to decide whether this tradeoff is worth the performance benefit in your code.

August 29, 2012

MBO Performance Tip N.3 - Be light in Mbo initialization methods

This entry is part of the Java MBO performance optimization golden rules series.

The initValue() method is the first method executed after the MBO constructor. It is typically used to initialize attributes on new records and to set default values.
The init() method is called after initValue(). It is typically used to set current attribute as read-only based on some condition.
Do not query the database or do any other expensive logic in the initValue() and init() methods.
Setting MBO or field flags that require expensive operation or fetching other needed MBOs should be done in initFieldFlagsOnMbo().

This rule should also be applied in field initialization methods. Do not initialize the value of a field in the initValue() method of another field. Each field should initialize itself in its own initValue() method.

August 28, 2012

MBO Performance Tip N.2 - Use discardable MBOs when possible

This entry is part of the Java MBO performance optimization golden rules series.

If an MboSet is used for traversing forward only and not to be saved make it discardable by setting the DISCARDABLE flag.
The following snippet shows how to do it.

MboSetRemote mboSet = getMboSet("ASSET");
mboSet.setFlag(MboConstants.DISCARDABLE, true);
MboRemote mbo=null;
for(int i=0; (mbo=mboSet.getMbo(i))!=null; i++)

Using a discardable MboSet does not cache the MBOs as it fetches from the database thus minimizing JVM memory usage.
Note that discardable mbos are always read-only.

August 27, 2012

Interacting with an Object Structure Service through HTTP

This entry is part of the Maximo Integration Framework series.

In this tutorial I will show how easy it is to query and update data in Maximo using the Integration Framework (MIF) Object Structure Services using a simple HTTP client.

HTTP test client setup
A great tool for creating sample test HTTP requests is a great Google Chrome add-on called Postman REST Client. I strongly suggest to add it to your Chrome browser. If you are a Firefox user then you may try HTTPRequester.

Querying People data
Login to Maximo, open Object Structures application under the Integration module and search for MXPERSON object.
In the Action menu select Generate Schema/View XML and select the Query operation in this dialog.

On the left side you can see a sample XML for querying people. On the right side there is a sample response.
Removing all the unnecessary elements and attributes from the request we get the following XML.

<max:QueryMXPERSON xmlns:max="">

Now open Postman (or any other HTTP test client) and type into the address the following URL:
  • URL: http://[MAXIMOHOST]/meaweb/os/MXPERSON
  • Method: POST
  • Request type: Raw
  • Request: Paste the previous XML sample request

Where [MAXIMOHOST] is the hostname of your Maximo server.
This is how Postman client should look like.

Now click on 'Send' button and you will see all your people listed.
If you get an error try to look in the logs.

Simplify the Object Structure
In real integration scenarios you typically do not need all the attributes of an object. It also a good practice to  remove unneeded attributes and child objects to improve performances.
First of all let's remove unnecessary child objects. Go to Integration - Object Structures application and search for MXPERSON object. Duplicate the Object Structure and call it MXSIMPLEPERSON. Remove the child objects PHONE, EMAIL, SMS and save it. Now you should have only one row in the 'Source Objects' table.
The next step is to remove unnecessary fields. Let's say we are only interested in the name of each person. Open the MXSIMPLEPERSON object and select 'Exclude/Include Fields' from the Action menu. Tick the Exclude checkbox on all the rows except the following:
  • PERSONID (primary key)

Save the MXSIMPLEPERSON Object Structure and open Postman the HTTP client. Change the Object name in the URL to MXSIMPLEPERSON and update the request as follows.

<max:QueryMXSIMPLEPERSON xmlns:max="">

Now you have a much simpler response from the MXSIMPLEPERSON Object Structure Service.

Take you time and review carefully the information contained in the response XML.

Filtering output using a WHERE clause
If you want to retrieve a subset of the records you can specify an 'SQL where clause' in the WHERE element of the XML. The following example will list all the people with first name starting with the letter 'A'.

<max:QueryMXSIMPLEPERSON xmlns:max="">
  <max:WHERE>upper(FIRSTNAME) like 'A%'</max:WHERE>

Filtering output using XML elements
The alternative approach is to specify the PERSON (or any other filter) in the XML like this. The following example will list all the people whose first name is 'Andrews'.

<max:QueryMXSIMPLEPERSON xmlns:max="">
   <max:FIRSTNAME operator="=">Andrew</max:FIRSTNAME>

Create and update an object
The Sync operation allows to create or update an existing object. To see the structure of the XML, open the MXSIMPLEPERSON Object Structure open the Action menu and select Generate Schema/View XML and select the Sync operation.
Now let's see how to create a new person record. Paste the following HTTP request in your HTTP client.

<max:SyncMXSIMPLEPERSON xmlns:max="">

The same Sync operation can also update records. If you change the first name in the previous XML and leave everything unchanged, the TEST1 person record will be updated.

<max:SyncMXSIMPLEPERSON xmlns:max="">

Where do we go from here
We have covered few of the user scenarios that can be fulfilled with the Object Structure Services. For more information please refer to the Integration Guide.

August 25, 2012

MBO Performance Tip N.1 - Avoid using MboSet.count() method in loops

This entry is part of the Java MBO performance optimization golden rules series.

I think this is one of the most common errors when developing Java MBO code.
The MboSet.count() method issues a "SELECT COUNT(*) from ..." SQL query to retrieve the number of records in the database table.
This can be a big problem especially when used in loop statements like this:

MboSetRemote mboSet = getMboSet("ASSET");
for (int i=0; i < mboSet.count(); i++)
  MboRemote mbo = mboSet.getMbo(i);

The previous code snippet will issue a new SQL count statement for every iteration of the loop.
A better approach is the following.
MboSetRemote mboSet = getMboSet("ASSET");
MboRemote mbo=null;
for(int i=0; (mbo=mboSet.getMbo(i))!=null; i++)
I have already tackled this argument in this post where I also describe a more elegant way of looping through an MboSet.

Calling MboSet.count() method is not always a bad practice. If you only need to ensure that there are a certain number of records in an MboSet, the count() method is better than trying to fetch the MboSet records. Note that this somewhat is in contrast with what the IBM Maximo wiki suggests.

August 24, 2012

Java MBO performance optimization golden rules

This entry is part of the Maximo Java Development series.

In this post I have collected the most important Maximo Business Objects (MBO) development performance tips and suggestions that I have learned during my job as a Maximo Consultant.
These suggestions are partly distilled from the IBM Maximo wiki page trying to organize and simplify the information contained in it. I have also added few new tips based on my professional experience.

Here are the 8 Java Maximo Business Objects (MBO) performance optimization golden rules:
  1. Avoid using MboSet.count() method in loops
  2. Use discardable MBOs when possible
  3. Be light in MBO initialization methods
  4. Be careful when calling
  5. Avoid using setQBE method
  6. Free resources as soon as possible
  7. Use efficient SQL
  8. Access the database via JDBC when performance is critical

August 22, 2012

Maximo supported web browsers

What web browsers can be used to access Maximo?
Roughly speaking, Maximo supports only Microsoft Internet Explorer and Mozilla Firefox. Said that... I currently use Google Chrome with Maximo. Pages load faster and it works perfectly 99% of the times (except for reports).
The following table gives a quick overview of the current supported web browser versions.

Base Services version 6.2 6.2.5 7.1 7.5
Internet Explorer 6
Internet Explorer 7
Internet Explorer 8
Internet Explorer 9
Mozilla Firefox 3.0
Mozilla Firefox 3.5
Mozilla Firefox 3.6
Mozilla Firefox 4
Mozilla Firefox 10
Google Chrome

Thus we can draw the following considerations:
  • Internet Explorer 7 is currently supported by ALL versions of Maximo.
  • Firefox has a less extensive support but it generally performs better than IE.
  • Google Chrome is currently the most used web browser but it is still not supported by IBM :-(

August 20, 2012

Maximo Integration Framework first setup

This entry is part of the Maximo Integration Framework series.

If you have never used the Maximo Integration Framework you have to check the MIF configuration before being able to play with it.

System Properties

All the configuration parameters for MIF can be managed from the System Properties  application: GoTo -> System Configuration -> Platform Configuration -> System Properties. ->*

The most important property to check is This property specifies the root folder where all the integration configuration files are located. If this value is null, the folders are created under the directory from which the application server is started, or from the current working directory of the application server (e.g. C:\IBM\WebSphere\AppServer\profiles\AppSrv01).

Other important properties that need to be set before using MIF are:
  • This specifies the integration Web application URL. The syntax is http://[HOST]:[PORT]/meaweb/maximo.
  • Email address to which the integration framework sends notification of message processing errors.

JMS Queue Setup

Java Message Service (JMS) is used for routing messages from the processing layers to the external systems.
To verify that the JMS Queues are correctly installed login to the WebSphere Integrated Solutions Console and go to Resources - JMS - Queues. Ensure the following queues are enabled:
  • cqin : Continuous Inbound Queue
  • sqin : Sequential Inbound Queue
  • sqout : Sequential Outbound Queue

CRON Tasks

There are several CRON tasks that must be active. Go to System Configuration - Platform Configuration - Cron Task Setup and ensure that the following Cron Tasks are enabled:
  • JMSQSEQCONSUMERThis cron task pulls records from JMS Queues for processing.
  • IFACETABLECONSUMER to regularly poll the interface tables
  • FLATFILECONSUMER to use flat files for inbound data import
  • XMLFILECONSUMER to use XML file for inbound data import

Continuous JMS Queue Configuration

The continuous JMS queues (CQIN and CQERR) requires some additional steps that requires to rebuild and redeploy the Maximo EAR. However this step can be skipped if you are willing to use only the sequential queues.

Edit maximo/applications/maximo/mboejb/ejbmodule/meta-inf/ejb-jar.xml file and make sure the following four sections are uncommented to look like below:

<!-- MEA MDB -->
<message-driven id="MessageDriven_JMSContQueueProcessor_1">
<!-- MEA MDB for error queue -->
<message-driven id="MessageDriven_JMSContQueueProcessor_2">
<!-- MEA MDB -->
<!-- MEA MDB for error queue -->

Edit maximo/applications/maximo/mboejb/ejbmodule/meta-inf/ibm-ejb-jar-bnd.xmi and make sure the following two sections are uncommented to look like below:

<!-- MEA MDB -->
<ejbBindings xmi:type="ejbbnd:MessageDrivenBeanBinding" xmi:id="MessageDrivenBeanBinding_1" activationSpecJndiName="intjmsact">
<enterpriseBean xmi:type="ejb:MessageDriven" href="META-INF/ejb-jar.xml#MessageDriven_JMSContQueueProcessor_1"/>
<!-- MEA MDB for error queue -->
<ejbBindings xmi:type="ejbbnd:MessageDrivenBeanBinding" xmi:id="MessageDrivenBeanBinding_1" activationSpecJndiName="intjmsacterr">
<enterpriseBean xmi:type="ejb:MessageDriven" href="META-INF/ejb-jar.xml#MessageDriven_JMSContQueueProcessor_2"/>

Now rebuild and deploy the maximo.ear.

August 15, 2012

Maximo Glossary

In the following table I have listed the most important terms and acronyms that are commonly used in the Maximo/TPAE world.

BIRTBusiness Intelligence and Reporting Tools is an Open Source software embedded in TPAE that provides reporting.
CCMDBIBM Tivoli Change and Configuration Management Database (official product page).
EAMEnterprise Asset Management.
KPIKey Performance Indicators. Visual indicators displaying status against predefined targets.
MAMMaximo Asset Management.
MaximoIt was the original product developed by MRO and acquired by IBM in August 2006. The term 'Maximo is commonly used both to identify IBM Maximo Asset Management product and the underlying infrastructure on which many IBM Service Management products are built.Additional details here.
MBOMaximo Business Objects are data beans provided by TPAE and used to access data. The MBO term is generally used to indicate the TPAE business object layer.
MEAMaximo Enterprise Adapter. MEA has been renamed in release 7.1 to Maximo Integration Framework (MIF).
MIFMaximo Integration Framework (previously Maximo Enterprise Adapter).
QBEQuery By Example. Using your application’s filter and/or query, you can immediately generate reports and download the results.
SCCDSmartCloud Control Desk (official product page). The new IBM SmartCloud Control Desk is the merge of TSRM, TAMIT and CCMDB in a single solution for IT service management.
TAMITTivoli Asset Management for IT (official product page).
TPAETivoli Process Automation Engine also known as Base Services. Additional details here.
TSRMIBM Tivoli Service Request Manager (official product page).

Do you see mistakes or missing items? Send me your requests and I will improve this listing.

August 13, 2012

Rapid Java class deployment on WebSphere

This entry is part of the Maximo Java Development series.

In this post I will describe how to minimize the time needed to redeploy the custom Java code in Maximo running on WebSphere during the development phase.

Note: The techniques explained in this article (except the first one) are recommended only for development environments.

Here are the four methods I know to perform this task (the last is the fastest).

Rebuild and redeploy (30 minutes)

The standard procedure of updating custom Java classes in WebSphere is VERY time consuming and consists of the following steps:
  1. Copy the custom Java classes under [SMPDIR]\maximo\applications\maximo folder.
  2. Rebuild Maximo EAR.
  3. Redeploy the EAR.

Use sync-websphere-maximo.cmd script (10 minutes)

There is a well hidden script named sync-websphere-maximo.cmd under [SMPDIR]\applications\maximo directory that takes the classes in the businessobjects, maximouiweb, mboweb, meaweb and lib directories and roughly copies them to the WAS MAXIMO.ear folder.
First of all you have to configure the script editing sync-websphere-maximo.xml file and set maximo.websphere.dir property.
  1. Copy the custom Java classes under [SMPDIR]\maximo\applications\maximo folder.
  2. Run the sync-websphere-maximo.cmd script.
  3. Restart Maximo application server.

Rapid approach (6 minutes)

A fast technique that I use is to directly copy java class files in the MAXIMO.ear directory under WebSphere tree. In a typical deployment it is located under [WSDIR]\AppServer\profiles\ctgAppSrv01\installedApps\ctgCell01\MAXIMO.ear.
The little trick is to use a good file archiver tool like 7-Zip to dynamically add/replace files in the businessobjects.jar file without having to extract and rebuild it.
This is the exact sequence to follow.
  1. Stop Maximo application server (do this before modifying businessobjects.jar file to avoid corrupting it).
  2. Copy the custom Java classes into MAXIMO.ear folder.
    1. If the class files belongs to maximouiweb module I just copy them in the maximouiweb.war\WEB-INF\classes directory.
    2. If the class files belongs to businessobjects module I open the businessobjects.jar file with 7-Zip (with a right click) and drag and drop the custom class files into the right folders.
  3. Start Maximo application server.

Super-fast approach (5 minutes)

The previous technique can be further improved with a little trick (thanks Diego for the tip).
First of all you have to force Websphere to load the unpacked businessobjects.jar:
  1. Stop Maximo application server.
  2. Go in MAXIMO.ear folder and unzip the businessobjects.jar file into a directory named businessobjects.jar.
  3. Rename the businessobjects.jar file (e.g. businessobjects.orig.jar)
  4. Start Maximo application server and check everything is ok.

After having performed this configuration you can copy your class files directly in the 'exploded EAR' with this procedure.
  1. Stop Maximo application server.
  2. Copy the custom Java classes into businessobjects.jar or maximouiweb.war subdirectories of MAXIMO.ear folder.
  3. Start Maximo application server.
Note that step 2 can be automated setting the Eclipse destination directory directly to businessobjects.jar directory (unchecking the 'scrub output dir' in the project options under Java - Compiler - Building). However this may worth a separate article...

Speed-of-light approach (seconds)

We can further improve the 'super-fast' approach leveraging the WebSphere automatic class reload (thanks to Bartosz).
  1. Stop Maximo application server.
  2. Go in MAXIMO.ear folder and unzip the businessobjects.jar file into a directory named businessobjects.jar.
  3. Rename the businessobjects.jar file (e.g. businessobjects.orig.jar)
  4. Change WebSphere configuration
    1.  Log into the WebSphere web console.
    2. GoTo "Enterprise Application" - MAXIMO - "Class loading and update detection".
    3. Set "Reload classes when application files are updated" checkbox and set "Pooling interval for updated files" to 5 seconds.
    4. Ensure "Debug Mode" is also enabled on MXServer application server.
  5. Start Maximo application server and check if everything is ok.

After these changes you can modify java classes and if you would like to refresh classes on WebSphere server you only need to copy the file into the businessobjects.jar or maximouiweb.war folder. WebSphere will automatically recognize new classes and will reload them so you don’t need to restart Maximo application.
If you are using Eclipse to develop the changes you can create simple ant builder which will responsible for copying updated files to businessobjects.jar and maximouiweb.war folders.

August 11, 2012

Flags for setValue methods

This entry is part of the Maximo Java Development series.

The Mbo class exposes a lot of setValue methods but we can categorize them in two big groups. The first group accepts only two arguments that are the name of the attribute to be set and its value. The second group of methods have three arguments that allows to pass an additional accessModifier flag.
The values that can be passed into this flag are defined in the MboConstants interface and Mbo class. The most important values are the following:
  • NOVALIDATION (1) - Suppress validation
  • NOACCESSCHECK (2) - Suppress access control checks
  • NOACTION (8) - Suppress action
  • NOVALIDATION_AND_NOACTION (9) - Suppress validation and action

Those values can be 'merged' using the Java bitwise OR operator "|". For example, if you want to suppress the validation and action you can use the NOVALIDATION|NOACTION constant.

August 10, 2012

How to set the default value of a field in Maximo

There are five ways to set the default value of a field in Maximo.

Database Configuration

The first way is to set the default value at the database level using Database Configuration.
All you have to do is the object and then the attribute for which the default is to be set. In the right hand side of the Details section there is a Default field. This is where you would enter your literal value for the default value.
Some system constants can be used:
  • &AUTOKEY& - This is used for attributes that are set to autonumber to default to the next autonumber value.
  • &SYSDATE& - This will default a field with the current system date/time
  • &USERNAME& - This will default a field to the current USERID value
  • &PERSONID& - This will default the current user's PERSONID value.
Note: These system defaults can be used only in Database Configuration.

Application Designer

The second way to set a field default in Maximo is by using a Default Object in Application Designer.
Launch Application Designer and select the application in which you want to set a default.
From the Select Action menu, select the Toggle/Show All Controls option.
Select the Tab of the application the field exists on.
Select the Control Palette icon and drag and drop a Default Object object to the section the field you want to set the default on exists in.
Highlight the defaultvalue… and select the Control Properties icon.
Enter the attribute for the field you want to set the default value for, this value can be found by looking at the properties for the field. Also enter the default value for the field.
Save and test your application...


The third method requires the use of a SQL tool. There is an APPFIELDDEFAULTS table in Maximo which allows you to set a default by application, group and/or user. The object and default values are required, but you can then specify a certain app that uses that object or security group or user you want to have a particular default value.
Once your record(s) are inserted in the APPFIELDDEFAULTS table, you will need to restart the Maximo application server for your changes to take effect.
See this IBM technote.


Any example?


If you are running on TPAE 7.5 you have the scripting alternative.
Go To > System Configuration > Platform Configuration > Automation Scripts
Create Script with Object Launch Point.
  • Launch point: ENI-INCNEW - Incident creation
  • Object: INCIDENT
  • Active: yes
  • Events: Add

New Script
  • Script: ENI-INCSITEID - Set default SITEID
  • Script Language: jython

Paste the following script.

from psdi.mbo import MboConstants
mbo.getMboValue("SITEID").setValue("GLOBAL", MboConstants.NOACCESSCHECK | MboConstants.NOVALIDATION)

August 8, 2012

Variables for Dynamic Queries in Conditional Expressions

Conditional Expressions can be used in TPAE applications in several ways. One powerful feature of Conditional Expressions is the capability of creating dynamic queries using substitution variables. Here is the complete list of variables available in Maximo.
  • :YES – True
  • :NO – False
  • :&DATE& – Current date
  • :&DATETIME& – Current date/time
  • :&USER& – Logged in user (or &USERNAME&)
  • :&PERSONID& – Person ID of the logged in user
  • :&APPNAME& – Application name
  • :&MBONAME& – Name of the current business object
  • :&OWNERNAME& – Name of the owner business object
  • :[relationshipname].[attrname] – Value of an attribute of a related business object of the current business object
  • :&OWNER&.[attrname]  – Value of an attribute of the owner business object
  • :&OWNER&.[relationshipname].[attrname]  – Value of an attribute of the related business object of the owner business object
  • :$OLD_[attrname]  – The initial value of the attribute

Sample Expressions

Here is a small set of examples that can help to understand how those variables can be used.
  • :wostatus='APPR'
  • :type='EM'
  • :ownerid=:&user&
  • :supervisor!=:&personid&
  • :asset.assettype = 'IT' and :&personid&=:owner
  • :reportby=:&personid&
  • :assetspec.classstructureid = 1221
  • :po.poline.receivedqty=0
  • :&owner&.jobplan.priority>:&owner&.priority
  • :&owner&.po.$old_description like '%Turbin%'

August 6, 2012

IBM EMEA Tivoli and Security Technical Conference 2012

Are you looking to increase your personal skills in the Asset Management and Service Management arena?
Are you responsible for a team of Tivoli professionals who need to delve deeper into the products?
Would you or your team benefit from learning deep technical skills from real experts in their fields?
Then the EMEA Tivoli & Security Technical Conference 2012 is just what you need!

I really think that ETSTC conference will be a great opportunity to improve your knowledge IBM Tivoli products and solutions and to network with IBM products experts, Business Partners and fellow participants.

I will present the following 3 sessions:
  • Extending Maximo Business Objects (Presentation and Hands On Lab)
  • IBM Maximo Integration Framework
  • IBM Maximo Mobile
Please leave a comment here if you are going to attend the event.

August 1, 2012

Detect if an MBO method has been invoked by an user session or by a background process

You are in the middle of a Mbo class and you have to perform some logic only if your piece of code is invoked by a user sitting in front of of Maximo UI.
How would you understand if the Mbo method has been invoked by an interactive user session or by a background process like an escalation, crontask or MIF?
Here is a Java snippet to retrieve this information.

boolean isInteractive = getUserInfo().isInteractive();

Just put it in your Java method and use the isIntercative flag as you want.