Securing Attachments in IBM Maximo

Need help securing attachments in IBM Maximo?


So you have secured your IBM Maximo installation using SSL, perhaps by following one of the secure articles in our A3J Group blog library, and are feeling pretty comfortable that your IBM Maximo users are protected. Just as you are about ready to lean back in your chair and enjoy the fruits of your labor you receive an urgent communication with a screenshot showing an IBM Maximo attachment being served up with the unsecured HTTP rather than HTTPS. Sound familiar? Thankfully you will be back to your feeling of tranquility in no time as this fix is a piece of cake.

*Note you could have been prevented the above scenario from occurring by not binding IBM Maximo to an unsecure port. This would not have allowed the attachment to work but would have prevented an unsecure connection.

Creating an Automation Script End Point in IBM Maximo

The IBM Maximo Integration Framework offers a wide variety of capabilities for publishing or consuming information to or from external systems. Some of the available methods for communication are:

  • Flat File Exchange
  • XML File Exchange with XSLT Mapping
  • Database Table Exchange (both internal and external to Maximo)
  • HTTP or SOAP Service Consumption

However, there may be times when the available end point handlers do not fit exactly what you need. What options do you have to customize the way the data is exchanged (method, format, content, etc.)?

1. Java customizations: This is old and tired. However, it is possible to write your own Router Handler class to deliver an outbound message to its destination. It is also possible to deliver the message using one of the available handlers above, and then write a custom IBM Maximo cron task to move the message to its destination. For me, that is too many moving parts.

2. Third-party solutions: Implementing a third-party middleware solution, such as Node Red or MuleSoft, can be an option for removing specific system differences when exchanging information between two systems. This is especially useful in large enterprises where many systems are exchanging data. This can allow for a single source of business logic to exchange information across a wide range of systems. For smaller integrations however, this can just add another layer of management and skills necessary to support the organization.

3. Automation Scripts: This is an easy, simple way to build your own end point handler in IBM Maximo without introducing unnecessary Java customization. Luckily, IBM provides a hook that allows us to do just that.

To create an Automation Script End Point in IBM Maximo, you will first need to register the Script Router Handler class. Please note that this class was introduced in the IBM Maximo release. In the release, the SCRIPT handler was added by IBM, which means that these steps can be skipped if you are on or later. If you are running a version between and you can follow these steps to create the Script Router Handler in IBM Maximo:

  1. Log into IBM Maximo as an administrator
  2. Navigate to the Integration > End Points application
  3. Under the More Actions menu, choose the Add/Modify Handlers option
  4. Click the New Row button
    a. Handler: SCRIPT
    b. Consumed by: INTEGRATION
    c. Handler Class Name:
  5. Click the OK button

end point-autoscript-IBM Maximo-mif-automation scripting-integration-scripting-python-code-script-Maximo-customization

Once you have the SCRIPT handler, you can use it to register a new End Point in IBM Maximo:

  1. Log into IBM Maximo as an administrator
  2. Navigate to the Integration > End Points application
  3. Click the New End Point button
    a. End Point: TEST-SCRIPT
    c. Handler: SCRIPT
  4. After populating the Handler with SCRIPT, a SCRIPT property will appear
    a. Value: <The name of your Automation Script>, e.g. TEST-SCRIPT
  5. Click Save

end point-autoscript-IBM Maximo-mif-automation scripting-integration-scripting-python-code-script-Maximo-customization

At this point, you have an End Point that calls an Automation Script that has not yet been created. The next step is to define that Automation Script and implement your own logic:

  1. Log into IBM Maximo as an administrator
  2. Navigate to the System Configuration > Platform Configuration > Automation Scripts Application
  3. From the More Actions menu, choose the Create > Script option
  4. In the ensuing dialog, enter the basic script information:
    a. Script: TEST-SCRIPT
    c. Language: python
  5. Enter the source code from below and press the Create button

end point-autoscript-IBM Maximo-mif-automation scripting-integration-scripting-python-code-script-Maximo-customization

Source Code:
# ------------------
# This script will write a message to the file system 
# and FTP the file to another server for processing.
# Implicit Variables:
#   INTERFACE - the name of the triggered Publish Channel
#   requestData - the message payload
# Alex Walter
# 21 JAN 2021
# ------------------
from import File
from import FileWriter
from import FileUtils
from import FTPClient
from import FTPReply
from psdi.util.logging import MXLoggerFactory

logger = MXLoggerFactory.getLogger('maximo.script.a3jtutorial')
if logger.isDebugEnabled():
    logger.debug('Starting TEST-SCRIPT script')
    logger.debug('INTERFACE: ' + str(INTERFACE))

# If the file exists, then delete it and create it new
ftpFileName = "C:\Temp\ftpfile.xml"
ftpFile = File(ftpFileName)
if ftpFile.exists():

# Write the file to disk
fileWriter = None
	fileWriter = FileWriter(ftpFile)
	if fileWriter:

# Setup FTP variables - usually good idea to create System Properties
ftpHostName = ""
ftpUserName = "username"
ftpPassword = "password"

ftpClient = None
fileInput = None
	# Make an FTP connection
	ftpClient = FTPClient()
	reply = ftpClient.getReplyCode()
	if logger.isDebugEnabled():
		logger.debug('ftp reply: ' + str(reply))
	if not FTPReply.isPositiveCompletion(reply):
		if logger.isDebugEnabled():
			logger.debug('not a positive ftp reply')
		if logger.isDebugEnabled():
			logger.debug('positive ftp reply!')
		# Log into the FTP server
		if ftpClient.login(ftpUserName, ftpPassword):
			if logger.isDebugEnabled():
				logger.debug('Logged into FTP site')
			# ftpClient.setFileType(2);
			fileInput = FileUtils.openInputStream(ftpFile)
			# Put the file in the default directory
			ftpClient.storeFile(ftpFileName, fileInput)
			if logger.isDebugEnabled():
				logger.debug('File sent to Server')
		# Log out
		if logger.isDebugEnabled():
			logger.debug('Logged out of FTP site')
	if ftpClient:
	if fileInput:


NOTE: If you need help installing this automation script in your IBM Maximo, or have questions with other Maximo CMMS configurations don’t hesitate to reach out! Leave a comment below, or email


Opening an Attachment on List Tab in IBM Maximo

For this scenario I wanted an option to easily open attachments without having to go to each individual record, then the attachment icon, then waiting for the dialog to open then selecting the image to open it. I wanted to save time looking at attachments for a bunch of records. (Note: This only works if there is only one attachment that you can identify to open.)

In this case we took a meter reading and have an image that goes with that meter reading in Maximo. So, there is only one image per reading.

In order to do this, you need to go to Application Designer. Find the application you want to add an image link to. Find the table you want to use and add a new tablecol to that table. Open the tablecol properties and fill out the following fields:

Type: OPENURL (Note: This was done in the xml by exporting the application and updating the field and importing the application. This value is not an option in most IBM Maximo environments in the drop-down list for the type field)



opening-attachements-doclink-application designer-user interface-customization-relationship-attributeopening-attachements-doclink-application designer-user interface-customization-relationship-attribute


For the Attribute and URL Attribute you can append as many relationships as you need. For our scenario we added a relationship to the MEASUREMENT table called DOCLINKS with a Child Table of DOCLINKS table that has the image. The whereclause for that relationship is “ownertable = ‘MEASUREMENT’ and ownerid = :MEASUREMENTID”. The table that we are adding the tablecol to is MEASUREMENT.

Once you have updated the application. Save your changes and go to the application. You will see an update to your table that looks like:

opening-attachements-doclink-application designer-user interface-customization-relationship-attribute




The underline and the blue text indicate that you can click that and the attachment will open.

Maximo Bug with Start Center Result Set and Custom Application

I created a query and then added a result set to the Start Center for our custom application.   In the Result Set portlet the query was chosen but no fields were displaying in the Available List or objects in the Object List.

The reason for the empty fields was ultimately due to a database length field issue on two objects: RESULTSETCOLS and RSCONFIGSELECT.  The APP attribute field length is 10 but our custom application name length was 11.


Increasing the attribute length for APP in RESULTSETCOLS and RSCONFIGSELECT followed by a database configuration corrected the problem which resulted in the Object List and Available Fields list displaying the appropriate information.


This was in Maximo so the problem may already be corrected in a patch.




Automatically Email Vendor on Approval of Purchase Order in IBM Maximo

Automate emails to vendors from approved purchase orders in Maximo CMMS

This article will walk an IBM Maximo administrator through the steps necessary to send a purchase order by email to a vendor as an attachment. It is a common requirement by customers to be able to automatically send the purchase order to vendors through email. Some of the benefits of doing this are:

  • Standardize the way that approved purchase orders are communicated to vendors. A common template can be used for the email subject and body, as well as a common workflow for when the communication is sent.
  • Reduce the time taken by procurement agents in generating reports, saving them locally, finding appropriate contact information, and typing up an email.
  • When IBM Maximo sends the email, a copy of the email that was sent is stored in the Communication Log along with the purchase order. If you ever need to know when the email was sent and to whom, the documentation of the email is in IBM Maximo attached directly to the purchase order. No more searching through email to find the communication.

To achieve this, we will deploy an automation script in IBM Maximo that will generate the report and send the email. Before we get to the script, we need to ensure that the following prerequisites are met:

  1. The email address of the vendor should be recorded in the Companies application on the Contacts tab. The script below will use the email address of the Primary Contact (set on the Addresses tab) but can be adjusted to include a larger or more targeted set of email addresses. However, they must be accessible from somewhere in the system by the script.
  2. A Communication Template should be created and activated to be used as the email subject and body of the communication. By default, I’ve named the template POTOVENDOR, but you can name it anything you want and change it in the script.
  3. A BIRT report that represents the purchase order to be sent to vendors. By default, the auto script uses the poprint.rptdesign report that comes with IBM Maximo. This can be changed in the script to a custom report but be sure to match up the report parameters if necessary.

The trigger point for the script below is a status change of the purchase order to APPR. However, this could just as easily be triggered from IBM Maximo workflow, escalations, or other means.

Here is the automation script needed to make this happen:

from import ReportQueueService
from import ReportParameterData
from psdi.mbo import SqlFormat

# Get the current user's information
userInfo = mbo.getUserInfo()
locale = userInfo.getLocale()

# If the PO Vendor does not have a contact with email, then kindly exit
    emailTo = mbo.getString("VENDOR.PRIMARYCONTACT.EMAIL")
    # Append the current user's email address to the chain to ensure delivery
    if userInfo.getEmail() and not userInfo.getEmail() == "":
        emailTo = emailTo + ", " + userInfo.getEmail()
    # Create default message subject and body
    # These will be replaced by a communication template if one is found by the code below
    emailSubject = "Purchase Order"
    emailComments = "Please acknowledge receipt of this Purchase Order."
    # Change this value to a valid Maximo Communication Template ID
    commTemplateID = "POTOVENDOR"
    # Get the communication template
    commTemplateClause = SqlFormat(mbo, "templateid = :1")
    commTemplateClause.setObject(1, "COMMTEMPLATE", "TEMPLATEID", commTemplateID)
    commTemplateSet = mbo.getMboSet("$potovendor", "COMMTEMPLATE", commTemplateClause.format())
    commTemplateMbo = commTemplateSet.getMbo(0)
    if commTemplateMbo:
        # Build the email subject and body from the Communication Template
        sql = SqlFormat(mbo, commTemplateMbo.getString("SUBJECT"))
        emailSubject = sql.resolveContent()
        sql = SqlFormat(mbo, commTemplateMbo.getString("MESSAGE"))
        emailComments = sql.resolveContent()
    # Build the Report Parameters
    parameterData = ReportParameterData()
    parameterData.addParameter("appname", "PO")
    parameterData.addParameter("paramdelimiter", "")
    parameterData.addParameter("paramstring", "")
    parameterData.addParameter("where", "(po.poid = " + str(mbo.getLong("POID")) + ")")
    # Queue the Report to Run
    queueManager = ReportQueueService.getQueueService()
    queueManager.queueReport("poprint.rptdesign", "PO", userInfo.getUserName(), emailTo, emailSubject, emailComments, parameterData, locale.getCountry(), locale.getLanguage(), locale.getVariant(), userInfo.getTimeZone().getID(), userInfo.getLangCode(), long(0), userInfo)

Enable Logging to Capture Report Data Set Queries in Maximo 7.6

You upload your awesome new report in Maximo, click the Preview button or run the report and…. you get no results.  Is the problem in the Maximo Where clause, the report query or …?  Naturally you turn to the Maximo Logging application, crank up the SQL and Report loggers to DEBUG then sit back and comb through all those juicy log statements that pinpoint exactly where the problem resides.  Sound familiar?  

Of course not!  You crank up all that logging and comb through a whole bunch of nothing.   

This article will detail one way to coax Maximo into giving up all the information you need to properly diagnose your report running in Maximo 7.6.  You may not need to perform all these steps; however, I was not able to see exactly what I needed until I performed the last step.  

The report I was developing was based on the ASSET application and was rather complicated.  Consequently I wanted a lot of information ouof Maximo.  You may not need or want all these loggers running to diagnose your report so feel free to adjust these steps to suit your specific requirements. Keep in mind that if you do not see what you want in the log execute all these steps and get it working.  Then you can pare it down to be more efficient. 

Set appropriate loggers to DEBUG using the Maximo Logging application. 


As I mentioned, the report I was working on was based on ASSET. I wanted to see both ASSET object queries and report queries.  Navigate to the Logging application Maximo and filter the Logger list to show sql. 



Change the log level to Debug anApply Settings so the changes take effect. 

If you execute the report now all you will see is some SQL statements as you navigate around the ASSET object filtering the records for your eventual report.  While potentially useful in providing a complete picture of the data being requested it is most likely not what we need to figure out why our report is not displaying any records.  In order to see Birt and report related log statements we need to adjust the log level of the report logger. 

Filter the Logging application by report and adjust the log level to DEBUG for the report logger as well as the birt and directprint loggers.  Do not forget to Apply Settings. 


Setting additional Report loggers to DEBUG. 


If you, like me, run your report you still will not see what you want in the log.   

In order to see the report parameters, where clauseactual DataSet query being used and a whole bunch of other report information I had to execute the following sql statement against my Maximo database. 

update maxlogger set loglevel = ‘DEBUG’ where logkey like ‘; 

Be sure to commit the update if not using SQL Server.   

You will need to restart the Maximo application server after this update.  The logger update will not take effect until the Maximo application is restarted.   

Now if you run the report you will see the actual queries being executed from within Maximo.       

Turn up the Logs!

Whenever there is a problem in Maximo and you describe it to one of your co-workers the first thing they say to you is “what do the logs say?” Logs are the first place to look when you have a problem. There are some small issues with logs in that they are all over the place and some you will need to activate to access what can be logged. When you install Maximo (with WebSphere as it’s middleware) a couple of directories will become very familiar to you. They are the SMP and WebSphere directories. The logs are in there. Deep down in there. So, lets talk about making life a little bit easier. When you set up any environment you will go through some initial setup that we would call the foundational setup. Setting up your foundation is critical for managing and maintaining an environment that runs well and does not frustrate the hell out of you because everything is all over the place. Logs are almost always overlooked, and you end up having to go to all the standard locations to dig up the information that you are looking for when things go wrong. In this article I will show you how to set up your logs so that you can retrieve them in a more polished, sophisticated way that will exemplify how a well-built environment runs.

While researching information for this blog article I came across the usual suspects and for the Maximo users out there you know what I’m talking about. Log locations, log file sizes, amount/level of what will be logged. How Maximo uses the Log4j logger. Those are all great and form the foundations of how the application can be checked. I get the most info from the WebSphere logs though. Specifically, the SystemOut.log and the SystemErr.log. These are WebSphere’s logs that are writing information about the application that it is hosting (in our case Maximo).

The first thing you would consider when setting up your logs is where they are located.  The default path is going to be something like this (C:\IBM\WebSphere\AppServer\profiles\ctgAppSrv01\logs\MXServer). I’ve gotten quite used to that being the log location, but you may want to make life a bit easier and put it into a directory like C:\WebSphere_logs. The path (location) of the SystemOut.log and SystemErr.log can be changed. If you go to the servers and click on your server there will be a link on a right-hand navigation that will be called Logging and tracing under the Troubleshooting section.

When that page opens you will see a link called JVM logs. When clicked this will be a page most Maximo workers will know, and it gives you some very good options as to how you want your WebSphere logs set up.  As you can see from my screen capture below the log files were increased from the 1 MB standard to 5 MB, because even in environments that have very little traffic a 1 MB log will fill up quickly (like get your timer out quickly).

What size your log files should be is going to be a call you’ll have to make.  Take into consideration things like your server environment, your usage of cron tasks, automation scripts, escalations, and integrations.  These are all likely to be written to the SystemOut.log file if you are running them or increasing log levels to find out what they are doing.  You can also set how many “rolling” logs you want to keep under the Maximum Number of Historical Log Files field.  On this same page you can click on the Runtime tab and you will have the option to change the path the SystemOut and SystemErr files are written to.  This is where you can change the default repository for your logs to something that is not as buried as the original location.

Now, let’s go a bit deeper into what WebSphere can do for us when logging application information.  When the standard information that the SystemOut and SystemErr is not showing anything from the errors you are receiving it may be time to “turn up” logging. As I mentioned before Maximo is an application hosted by WebSphere, and as any developer knows tracing an application will provide step by step information as to what the application is doing. WebSphere allows you to turn on tracing of its applications. This is not on by default and you will want to turn it off once you are finished due to the amount of resources that will get chewed up while tracing an application. On the same server page (Application servers > MXServer > MXserver) where we went into to access the JVM logs there is a link for Change Log Detail Levels.  Here we can “turn up” tracing. This will allow for deeper diving into the actual applications that WebSphere is running.  The default setting is *=info.  This is going to be plenty good enough for 90% of your troubleshooting. Now, let’s say strange problems are going on with your hosted applications (Maximo) you may want to “trace” the applications inputs and outputs and as you know that’s all programs are. An interface for input and it spits an output as a result of what it was given.  If you increase the level to *=fine, *=finer, or *=finest you will now get a trace.log to pop up in that good old default directory. What this will relate to you will be a trace of what the application is doing.  Depending on the components you add the more “granular” a set of detail you can log.


IBM has a very good article on their Knowledge Center entitled Log Level settings which details levels that can be traced.  (  You are not going to want to leave your WebSphere system in this state because this of course will chew up resources at a much greater rate than just a few rolling logs that are written to every minute (the SystemErr.log doesn’t necessarily write every minute.)

Let’s take into account when systems need to run lean and clean and have to push the system’s resources (otherwise known as processor and available memory) to their maximum potential.  So, you’re hosting Maximo on your raspberry pi and you know you will have 200 concurrent connections at any given time editing work orders, creating purchase requisitions, firing automation scripts from custom built apps and you know that 1.2GHz quad core processor is going to be working hard, you may benefit from altering your logging system. WebSphere has the ability to log in HPEL mode.  High Performance Extensibility Logs are the exact same thing as your SystemOut, SystemErr, and trace logs, but they are not written to a nice easily accessible text file with the .log extension. These logs are written in binary and I am not even geeky enough to read that. I’ll need a translator to read binary. Lucky for me the HPEL logs can be accessed with a tool called logViewer.bat (or in the case of your raspberry pi This tool can translate the binary and bring back the information to you in either a shell scripting tool or command prompt as well as give you the ability to take the retrieved data and have a text file created out of it. Is it hardcore? The answer is absolutely, but as an old saying goes extreme situations require extreme measures.

When you go to set this up you will see a statement from WebSphere saying “Advised for most installations.” I would venture to say this is not recommended for most installations. Your choice is to have the system use some memory and processor threads to write to a text file that you can set to roll over and be readily available to check out or use a command line tool to extract the binary data and present it to you or create the text file on demand. I’m going to go with having a nicer system that has more memory and bigger processor so that I can easily read my log file.

In a final parting statement, it is a best practice to return the logs back to the state you found them in. If you have “turned up” logging, “turn it down”. It’s just going to convolute the next person that has to see a lot of excess info when they are opening the logs to troubleshoot. This topic can be extensive, and I encourage everyone to read up on what logs you may need to use in your endeavors. I could keep rambling and rambling, but my goal is to pique your interest not put you to sleep.  Stay tuned for more blog articles and go get those problems fixed by seeing what it says in the logs!

MBOs in Automation Scripts: Exception Handling

In our previous posts in this series, we talked about how an MboSet is a collection of Mbo objects. In this article, we’ll analyze the different types of exceptions that can be thrown and how each can be utilized.

Most methods that can be called through the Business Components can throw either a RemoteException and/or an MXException.

A RemoteException is thrown by the Java RMI system when an error occurs during remote communication. The exact nature of the error may be determined by checking the Exception object’s class – which may be one of seventeen subclasses of RemoteException.

For more details of these exceptions, refer to the documentation in the Java Development Kit.

The MXException is similar to the RemoteException in that the MXException is a super class for all related exceptions. The actual exceptions thrown will be instances of one of the following subclasses:

  • This is usually a fatal error from which the client cannot recover. It is usually a problem with either the server configuration or the database configuration. Examples of errors causing this exception are “Out of Memory on Server” or a SQL error. Two subclasses of this class have also been introduced:
    • Thrown when a client or server asks for a Mbo that is not known to the system. This is a fatal error that normally points to a bug in the system or an incorrectly configured data dictionary.
    • Thrown when the server, which should have an object running, does not respond. This is usually caused by an incorrect configuration of the remote configuration file or indicates that the server running the object is unavailable for some reason.
  • This is thrown as a result of any of the many possible application-level errors, most of which are not fatal. Such exceptions should be caught by the client and rectified by the logic of the calling program. Examples of reasons why this exception might be thrown are:
    • Trying to set the value of a date attribute to the characters “ABC”.
    • Trying to set the “eqnum” attribute in a WO object to an invalid equipment number.
  • Thrown when an attempt is made to set an attribute that is read only or access a method that is currently not available. Methods may be unavailable because of security restrictions or because the object is not currently in the correct state.

More information about an exception can be retrieved by accessing the getMessage(), getErrorGroup() and getErrorKey() methods in the thrown object. These methods constitute two different approaches to identifying the exact cause of the exception.

The getMessage() method returns a string which contains a message describing the nature of the error. A message from a nested exception, if there was one, is included here as well. Such messages are intended to be for the benefit of human users. If the intention is that the code itself should handle the recovery from the error, then it is more appropriate to call the other two methods.

The error group, returned by getErrorGroup(), usually corresponds to the name of a text file in the RESOURCES\DEFAULTS directory. For example, if the error group is “workorder”, then the textual error description is in resources\default\workorder.txt.

The error key, returned by getErrorKey(), identifies an exact line in the text file that describes the error. For example, “addstatus” identifies a line in workorder.txt that has the line of text “addstatus=WorkOrder status cannot be added without a work order”.

When the intention is that the code itself should recover from an error, it is far easier to use an error key as input for a condition statement than a message. Note that the error description pointed to by the error key is not necessarily the same as the message returned by getMessage().

Exceptions may also provide greater detail in the form of parameters. These are used to supply information for a more general type of exception. For example, if an attempt is made to call the setValue() method using an invalid attribute name then the error group “system” and the error key “noattribute” would be returned. The exception thrown would also contain as part of its parameter list the name of the attribute that could not be found. To access these parameters, use the methods hasParameters() and getParameters().

An MXException may be thrown as the result of another exception occurring in the system. An example of this is a SQLException. These exceptions are not thrown directly from the methods because it would make method signatures complicated. The programmer can gain access to the nested exception by referencing the member “detail”, which is public, of the thrown exception.

A code sample demonstrating the use of an MXException follows:

MXSession s = MXSession.getSession(); s.setHost(hostname); s.setUserName(username); s.setPassword(password); // Display any problems with the connect to the user. try { System.out.println(“Connecting to (” + s.getHost() + “/”+ s.getServer() + “)” ); s.connect(); } catch(MXAccessException ma) { String group = ma.getErrorGroup(); String key = ma.getErrorKey(); System.out.println(“Group : ” + group + “ Key : ” + key + “ Message :” + ma.getMessage()); }

Top 6 Things To Check When Your Integration Is Not Working

In the spirit of all those top however many number lists we see populate the internet these days I have complied a top 6 list of things to check if your integration is not working in Maximo. So, no, this is not an article on how to set it up and if you follow these steps it all works great! This is the uncommon article that addresses what to do when something might have gone wrong.

Number 1: Logs, Logs, Logs, Logs, Logs

The very first thing you should check when anything in Maximo is not working are the Logs.  Specifically, the WebSphere SystemOut.log and the SystemErr.log logs.  These files are a running tally of what is going on in Maximo and a running list of what is erroring in Maximo.  They are the first source to find out what is actually going on in the system.  Also, if you need something more specific, go to Maximo’s logging application and look up the Integration Root Logger.  Set it to DEBUG (remember to go back and set it to a lower level) then get those logs ready and test your integration!

Number 2: Admin Mode is on

I know, everyone knows this one. It’s that old saying that is redundantly used and we have heard any number of times in life.  “Did you do/check this?”  Just double check it, especially if the integration was worked on recently.  You and your colleagues may have been working in the system as well as on the integration and it could have been turned on.  As you know the Cron Tasks are not going to run with Admin Mode on.

Number 3:  Cron Tasks are not running

Many, many working parts go into the creation of an integration.  Cron Tasks are an integral part in that.  They control the processing of queues or the processing of flat file transfers.  Checking the JMSQSEQCONSUMER Cron Task if you are using WebSphere messaging queues or one of the file consumer (FLATFILECONSUMER and XMLFILECONSUMER) Cron Tasks is one of the first places to check if things are not processing.  If you are in a clustered environment check to make sure the Cron Task is not stuck on a specific server.  Do not runs may be set up and the server the Cron Task is running on may not be doing it.  One of the very reasons I wrote this article stemmed from a general discussion we had where an integration was not running.  A question was asked “Could the Do Not Run system properties be in the file?”  That’s right folks, those can be passed to the system through the properties file and it is quite possibly the trickiest place to find something stopping an integration from working.  Cron Tasks can get stuck and can sometimes stop running at their designated time.  Stopping and starting them is the first thing to try, but sometimes you need to check that server to see why the Cron Task may not be running.

Number 4: WebSphere messaging queues

The WebSphere messaging queues go hand in hand with the Cron Tasks for processing or checking the queue traffic.  Many times, your Cron Tasks are running, but you see no changes to the data in the system.  The queues may be receiving data but not pushing them out of the queue itself and they are piling up messages.  Checking your queues can be done in two places.  First and foremost, the queues can be checked under the intjmsbus in WebSphere (you remember those buses you set up right.)  If you built out your integration with more than one intjmsbus then you will have to check the other ones you have created to confirm where the messages may be sticking in the queues.  If you just created one intjmsbus then you will only need to check one place.  In trouble shooting a tricky integration that does not want to work this is where creating more than one intjmsbus can be tremendously helpful in pinpointing where a breakdown may be as well as limiting the effect of a poorly performing integration.  I would highly recommend this strategy in a Maximo environment that would be clustered and built to handle integrations.  When you navigate into WebSphere and look at the queues for your bus or buses if you see one (whether its inbound or outbound) with the numbers piling up that is where the “bottleneck” is.

That is not the only place to check the queues.  One can check the queues that have been used in an integration in Maximo under the Integration’s module.  This leads me into the last section which is a kind of an add on from WebSphere’s queues, but these things tend to build from Cron Tasks to Queues, to application message tracking and processing.

Number 5: Message Tracking and Reprocessing

In the Integrations module whether you set up a Published channel or an Enterprise Service under the More Actions menu you will see a choice for Message Tracking.  Once you have opened the dialog box and checked off the Enable Message Tracking option Maximo will retain a record in the database.  This is very useful option for tracking what it is going on with your integration.  In the External Systems app of the Integration module if you build out an External System with you Published Channels or Enterprise Services under the More Actions menu you have the option of choosing Add/Modify Queues.  This will show you what kind of queues have been built out in WebSphere and can show you the same data that is buried in the intjmsbus of the WebSphere administration site.  This menu choice has the ability to allow you to see message data as well as clear queue data.  So, you can operate your message queues from Maximo much the same way you can in WebSphere.  Message Tracking goes hand in hand with Message Reprocessing, which will work in with your queues the way you set them up.  If you built the queue to try to process the message 5 times it will try to process a message that many times before dropping it, and you can see the messages awaiting reprocessing in the Message Reprocessing application.

Number 6: Endpoints

Endpoints and their handlers are what actually deliver the messages to the destination side of an integration.  One of the things that trips people up is managing the different Endpoints between the environments.  Meaning DEV, TEST, and PROD environments usually will have different systems they are bound to and when creating your integrations each environment points to a unique server acting as the Endpoint for an integration.  Getting your Endpoint set up can be a challenge but pointing one system to the other system’s Endpoint will just result in questions of why this integration is not working.


Each one of these topics can get much more in depth and I encourage everyone to dive right into that depth, but the next time you’ve got an integration not working think about these points and see if that may be affecting your integration.