Category: MXServer

BMXAA4017E Error when running custom code

The “Object cannot be saved” error

A client hired me to do a bit of house-cleaning and provide minor enhancements for their Maximo system. It has some pieces of buggy Java code and I took the opportunities to de-customize the Java code by rewriting the logic with Automation Script. For one piece of logic, it worked well in the Development environment. However, when deployed to Production, it did not work.

The automation script is triggered when the user saves a record, but it executes at the post commit launch point. Thus, this script does not give any error on the frontend. However, there is an error “BMXAA4017E object cannot be saved with the data that was provided” in the SystemOut.log file. The error came from the mbo.checkQualifiedRestriction method

Error BMXAA4017E object cannot be saved with the data that was provided

Background Information

The BMXAA4017E error is a common error. It often occurs because of a QUALIFIED rule setup in security restriction preventing an user to interact with data he/she should not have access to.

However, this client has an interesting environment with four satelite Maximo servers located in Antarctica synchronized to a central server via satellite using a data sync solution provided by SRO. Although the number of active users is low, they have 500-600 users across nearly 20 logical sites. There are many data restriction rules configured at various levels: global, site, security group etc.

This issue gave me a chill down the spine during the deployment to Production because I simply couldn’t think of where to start looking. When I was almost announcing it a failed deployment, a random thought came up and it helped me solve the problem.

Problem and Solution

In short, the problem is, to update a record, I fetched the MboSet from the database using the MXServer.getMboSet() method. I passed in the SystemUserInfo to this method as I always do, thinking it is linked to the MAXADMIN account, and it has the ultimate access right. Below is the code:

The getSystemUserInfo() method is the cause of the problem

That is where the problem comes about, that “SystemUser” profile does not belong to any Security Group or listed in any security restriction rules. One of those rules must have failed and caused the error. To fix it, I changed the code to use the current logged in user’s security profile as follows:

Changing to getUserInfo fixed the issue

To be honest, I still haven’t figured out why the same code using SystemUserInfo
works in the DEV and TEST environments, and not works in PROD. But as an engineer, not a scientist, I guess it is ok to not knowing the Why sometimes. As long as it works, everyone is happy 😊

OutOfMemory error when deploying Maximo in Websphere

For every client I work with, I always keep a copy of the SMP folder if I can. And every time I need a standard demo instance with the same configuration as the client, I simply deploy it on my local Websphere and Oracle DB.

My current Websphere version is 8.5.5.3, and I had problems whenever I deploy a Maximo 7.6 instance with lots of add-ons. I gave up the attempt the last few times as I didn’t really need it.

Recently, as I was working with Maximo Flex (on the cloud), having a local instance is necessary as Maximo on the cloud has lots of limitations in terms of what you can do. As such, when I had the same problem deploying Maximo, I had to investigate and fix the issue.

OutOfMemory when deploying big Maximo.ear file to Websphere

Turned out it is an OutOfMemory issue during the deployment process and it took me quite a bit of time to fix it, so I leave the note here as I’m sure many others will have similar problems.

  • PROBLEM: when deploying Maximo 7.6 with many add-ons, Websphere keeps running or stops with a failure.
  • TROUBLESHOOT: if it takes more than 1 hour, I restart the system and re-deploy Maximo. In many cases, it immediately returns a failure. If it returns a failure, I look at the SystemOut.log file under
[Websphere Home]/AppServer/profiles/ctgDmgr01/logs/dmgr/
  • SOLUTION: if the problem is an OutOfMemory error, it can be tricky as there are many different processes in Websphere using Java. I ended up employing the spray and pray approach:
    • Increase heap size for WAS Admin console to 2GB: edit the wsadmin.bat under [Websphere Home]/AppServer/bin to update this parameter: PERFJAVAOPTION=-Xms512m -Xmx1024m –Xquickstart
    • Increase Application Server heap size: in Websphere admin console, go to Servers section (on the left side menu) -> Server Types -> Websphere Applicaton Servers -> [MXServer] -> Java Process Management (link on the right side menu) -> Process Definition -> Java Virtual Machine. Set both Initial and Maximum heap size to 2048 MB
    • Increase deployment manager heap size: in Websphere admin console, go to System Administration section (on the left side menu) -> Deployment manager -> Java and Process management -> Process definition -> Java Virtual Machine. Set both initial and maximum heap size to 2048 MB
    • Increase heap for deploy tool: edit the ejbdeploy.bat file under [Websphere Home]/AppServer/deploy/tool/itp to update this parameter: EJBDEPLOY_JVM_HEAP=-Xms512  -Xmx1024m

With these updates, I managed to deploy the EAR file. But Maximo and Websphere alone consume 6GB of my laptop memory. I had to remind myself to reduce them back to probably 1024MB each to save valuable real estate.

Creating high performance service using MaximoCache

Sometimes in our application, we need to build custom services that run when Maximo starts. We can extend the psdi.server.AppService class and register it with MXServer by inserting a new entry into the MAXSERVICE table. If the service executes slow-running queries, it is a good idea to cache the data in memory to improve performance. We can implement MaximoCache interface for this purpose. By doing this, we can initialize the service when MXServer starts and pre-load all data required by the service into JVM memory. When the service is called, it will only use cached data to provide instant response which gives a much better user experience. 
 
Below are the steps to create a sample service that loads all Location’s descriptions into memory. The service will provide a function to check if an input string matches a location’s description or not. We will call this check when the user enters an Item’s description and it will throw an error whenever the input matches with the description of any existing Location. This is not a very good use case. But for the sake of simplicity, I hope it gives you an idea of how it can be implemented.

1. Create a LocationCache class, implementing psdi.mbo.MaximoCache
interface:
  • For the getName() function, set a name for the cache, such as “LOCATION_CACHE”.
  • Create method loadData() to query and load all locations’
    description into a HashSet
  • Call the loadData() method in the init(), reload(), reload(String)
    function overridden from the MaximoCache interface
  • Create function isLocationExist(String) to check if an
    input String matches with a description contained in the HashSet

2. Create a LocationCheck class extending the psdi.server.AppService
class. Override the init() method to initialize a new LocationCache object and
add it to the MXServer’s cache.

 
3. Insert a new entry into the MAXSERVICE table to register with MXServer to initialize the service when Maximo starts. Sample SQL statement to insert the record as follows:

4. Extend the LocationSet class to override the fireEventsAfterDBCommit() method. Essentially this method will reload the cache whenever there is a change to location data. This will ensure that the information stored in the cache will always be in sync with the new update.

5. Create a FldDescription class to override the validate()
method, and associate it with the Item.Description field. In the validate()
method, we will check if the description entered is the same as a location’s description stored inside the cache and throw an error dialog if there is a
match.

You can view or download the full sample code from this GitHub repository: link

After deploying the code and associating the LocationSet to
the Location object and the FldDescription class the Description field of the
Item object, to test if the code works, open an Item and enter a description
that matches the description of a location, it should throw an error
message as in the image below:

To check if the cache is reloaded properly, create a new location or update an existing one, enter the description of the updated location to an item’s description, it should also throw an error message.