Maximo to AWS S3 Document Attachment

Lot of Lift and Shifts from on-prem to Cloud are happening these days as organizations catch up to the benefits of moving from limited on-prem resources to “un-limited” cloud potential and pay as you go and only pay for what makes you go.

Maximo on cloud for any organization which relies on their EAM systems to run their business needs to be fault tolerant, highly available and scalable.

We design architectures like Horizontal/Vertical or even Hybrid Application clusters but document attachments still are files on disk.

That disk now needs to be available to Multiple Nodes/Servers, Availability Zones (AWS terminology) and regions (if you have global presense).

Ok enough, read below how to get Maximo Document Attachments stored in AWS S3 bucket and served from there when user wants to view.

S3 buckets are cheap storage (glacier is cheaper but thats for less frequently accessed data, so more like archive), can be cross replicated across Regions, versioned, encrypted and has 99.9% availability SLA from AWS.

In picture the steps are below:



The thing that makes it most easy is the abstract class in Maximo specifically designed to aid in custom/bespoke Document Storage solutions:


I have extended this class and implemented the required abstract methods and one of the most important one is “createAttachment”. This is the method that will be called when any attachment is added to a record in Maximo.

There is a system property (if not there ADD it), “mxe.attachmentstorage”, this property holds the fully qualified class name of our custom implementation of AttachmentStorage Abstract class.

That’s how our custom class will be called when any attachment is added to maximo records.

Methods implemented if you just want to add attachments:


public abstract String getAttachmentQualifiedName(MboRemote paramMboRemote, String paramString)
throws RemoteException, MXException

public abstract void createAttachment(String paramString1, byte[] paramArrayOfByte, String paramString2)
throws RemoteException, MXException


We need to add a few system properties if we want to make our implementation configurable, below:

mxe.s3.accesskey – Access Key for AWS IAM user, with S3 bucket access

mxe.s3.secretkey – Shhhh…its the secret key, like a password

mxe.s3.bucket – like a folder where files will be stored

mxe.s3.region – Region, bucket resides,cross replication can put it anywhere

I am putting this working solution in a GITHUB repo (below), if interested just let me know.

There are a few prerequisites:

  1. Need all the library jars which AWS Java SDK needs
  2. IAM User and Bucket creation

Next Steps (wishlist):

  • Use TransferManager in AWS SDK so large files are transfered more efficiently and fast
  • Implement Aspera FASP file uploads ( to S3 – Did it for a bespoke application where-in large (GB) files were transferred 10x faster from local to S3 buckets
  • SharePoint Integration with Maximo attached documents
  • Implement for IBM CLoud and Google Cloud
  • Implement streaming (there is a method streamAttachment for that or maybe not) using Amazon Managed Streaming for Kafka for large files like video streams from Drones gone out for some inspections
  • Anything else???


Maximo Anywhere 7.5 beta – Exciting new mobility product from IBM


I had the pleasure of being allowed to participate for the Beta program for the upcoming Maximo Anywhere 7.5 product from IBM and just wanted to share some first impressions.

Maximo Anywhere 7.5 should be first available for Android devices and then followed by IOS.

For me any mobility tool must meet basic checklist to be a truly mobile solution.

My checklist goes like this:

1) Barcode Scanner

2) Offline Mode

3) Maps Integration

4) Cross Platform


Maximo Anywhere 7.5, which I will call Anywhere, has all these features.

It has a barcode scanner which is very useful and like fields have lookups, similarly fields will have a barcode lookup kind of control. Data scanned can be used to enter values in fields or search records based on scanned data.

Offline mode is my favorite as most of the big customers operate in remote regions whether it can be oil drilling, gas exploration, power plants, logistics etc and they rate that as a must have feature.

The ability to continue doing your job irrespective of connectivity would be rated very highly by the end users as well. Once back to civilization this data can be pushed to the server and job done.

Maps integration, needless to say is very important and Anywhere seamlessly integrates that as well.

Anywhere is based on IBM WorkLight platform. This will allow any developer without the knowledge of Android or IOS app development to customize this mobility solution.

Have a look at worklight if you have not already:

Worklight is based on Cordova (PhoneGap), so this legacy provides cross platform app delivery, whether its IOS or ANDROID (Even windows).

This cross platform allows the BYOD feature in Anywhere. By allowing the employee to bring their own devices it reduces cost of ownership burden to the company as well as I hate when maximo mobility tool does not allow me to play Angry Birds.

And, using Endpoint Manager for Mobile Devices can be used to make sure the BYOD device complies with security policies blah..blah ūüôā

Endpoint Manager for Mobile Devices helps you address the issues of security, complexity and bring your own device (BYOD) policies that challenge support for an increasingly mobile workforce.

I am very excited about Anywhere and hopefully I will get my hands on the full release version soon, can’t wait to see how it has been implemented in WorkLight, I am hoping it has been implemented as a worklight¬† adapter so that integrating other¬† external systems can be based on the similar template.





Site Specific MBO creation


I had the requirement from a Custom Cron task and I came across this so thought of sharing.

I wanted to add Workorders from my Cron based on the SiteID I was passing as a parameter. So, for each site I have a Cron instance.

What I did was use the setInsertSite, setInsertOrg method on the MboSet class.

So, before calling add I set the relevant SITE and ORG and then called add so it makes sure that only the appropriate sequence or autokey (based on site and org passed on MboSet) is updated.

Can be very useful in some scenarios so thought of sharing.


Run a Birt Report on click of a Button


I was asked this question by one of the visitor on my blog.

How do I run and view a report using bean class?

So, here is the way to execute any report on button click in maximo.

Tis method will be in a bean class and the mxevent value of that button will be runassetreport.

The only part which I think I need to explain in this is:“runtype”, “BIRT”);“appname”, “ASSET”);“reportname”, “asset_detail.rptdesign”);
String pageName = “reportd” + “1010”;

Because this solution talks about a BIRT Report the runtype is BIRT.

Appname is ASSET cause I am running azn asset detail report and this number 1010 is the reportnum from Report table.

As I was just doing a proof of concept I have hardcoded these values but ideally you will be using Report Mbo to get the relevant values.


    public int runassetreport() throws MXException, RemoteException, IOException, ServletException

¬†¬† ¬†¬†¬†¬† ReportAdminServiceRemote reportAdminServiceRemote = (ReportAdminServiceRemote)getMXSession().lookup(“BIRTREPORT”);
        int engineState = reportAdminServiceRemote.getReportEngineState();
        if (engineState == 2)
¬†¬† ¬†¬†¬†¬†¬†¬† this.clientSession.showMessageBox(this.clientSession.getCurrentEvent(), “Reports Overloaded”, getMessage(“reports”, “previewoverload”), 2);

          return 1;
        if (engineState == 1)
¬†¬† ¬†¬†¬†¬†¬†¬† this.clientSession.showMessageBox(this.clientSession.getCurrentEvent(), “Zero Concurrent Run”, this.clientSession.getMaxMessage(“reports”, “zeroConcurrentRun”).getMessage(), 2);

          return 1;
¬†¬† ¬†¬†¬†¬†¬†¬†“runtype”, “BIRT”);
¬†¬† ¬†¬†¬†¬†¬†¬†“appname”, “ASSET”);
¬†¬† ¬†¬†¬†¬†¬†¬†“reportname”, “asset_detail.rptdesign”);
¬†¬† ¬†¬†¬†¬†¬†¬† String pageName = “reportd” + “1010”;
          ControlHandler lookup = RequestHandler.findDialog(this.sessionContext, pageName);
          if (lookup == null)
            String[] params1 = { pageName };
¬†¬† ¬†¬†¬†¬†¬†¬†¬†¬† Utility.showMessageBox(this.sessionContext.getCurrentEvent(), “reports”, “repappnoxml”, params1);
            return 1;
          RequestHandler.showDialog(this.sessionContext, pageName);
        catch (MXException e)
        return 1;


A private util method to get the maxmessages used in the showMessageBox method:

private String getMessage(String msgGrp, String msgKey) throws RemoteException, MXException
        return MXServer.getMXServer().getMaxMessageCache().getMessage(msgGrp, msgKey, this.sessionContext.getUserInfo()).getMessage();






Setting field values to null from interface tables or flat files data sources


In some cases we need to set some values in maximo tables to null using maximo integration framework.


Normally, if you just leave the field blank in the incoming flat file maximo does not update the field with null just because the incoming data has null.


You need to set the incoming null value as ~NULL~ as per the article from IBM below:



Parameters to improve Maximo performance using WebSphere

IBM WebSphere changed parameters in the JDK in IBM JDK1.4.2 SR3. Any WebSphere version using IBM JDK 1.4.2 SR3 or greater is affected.

The change may cause WebSphere to hold onto unused objects for up to ten minutes after they are no longer needed. In high usage environments, this may act as a memory leak so that the application is starved for memory. There is a parameter to control this behavior, ackTimeout.

Some networks may also benefit from a parameter change in the JDK to set the default TCP/IP stack to V4. This can improve network performance by since the default behavior will be for the standard IP V4 and WebSphere will not need to determine the IP type programmatically. This parameter is


Invoking a webservice from MBo Classes WITHOUT MIF



Sometimes there can be a situation when you want to invoke a webservice on Mbo Save or delete or from a WorkFlow action class and do not want to go through building the integration components.

So, you straight away want to call this webservice from your custom code. One of the option in that case would be to use “WSCallClient”.

This class can be found in psdi.iface.webservices package.

OMElement respOME = callClient.invokeWebService(servicename,endPointUrl, omeObject, null, null, null, action, null, soapVersion, null, mxUsername,mxPassword, null);

The omeObject above is the service payload object.

In WebServicesUtil there are some utility methods like “convertToOMElement” where you can pass raw xml and it will give back an OMElement payload object.

Checkout maximo java docs for details on all the methods in WSCallClient and WebServicesUtil classes.



Aniruddh Panvalkar