Thursday, May 1, 2025

Maximo ACM - Asset Configuration Manager Add-On

Maximo ACM (Asset Configuration Manager) is an Add-On  for MAS Manage & Maximo 7.6.x earlier versions.

What is ACM used for ? 
Maximo ACM is designed to help manage the configurations of high-value, complex, and regulated assets such as aircraft, rail vehicles, engines, and weapon systems by tracking their configuration throughout their lifecycle.

Purpose of ACM
ACM helps ensure that assets remain compliant with their original design and maintenance requirements. It is essential in industries where safety, compliance, and traceability are critical.
 
Core Components of ACM
ACM is built with three key components:

1) Reference Data  
When we receive an Asset (Train/Locomotives/Aircraft) and its components, we must create engineering reference data (as designed) for it. The reference data specifies the configurations allowed for the asset and how it is maintained.

This defines the "as-designed" configuration of the asset, including:
  • Models
  • Positions
  • Items/Parts
  • Maintenance Programs
  • Meters
  • Configuration Rules
  • Variants 

2) Operational Data 
It refers to the data about production assets as they are maintained to perform their day-to-day operations.  

The "as-maintained" data includes:
  • Asset creation and tracking of sub-assemblies and serialized components
  • Installation/removal of components
  • Scheduled and unscheduled maintenance
  • Meter-based overhauls
  • Design modifications and upgrades
  • Maintenance history
3) Build Data Interpreter (BDI) 
BDI validates any operational changes to Configuration Managed (CM) Assets. It checks each position against the reference data and its configuration rules that are defined for the associated Model. 

It reports the status of non-compliant assets in the Assets (CM) application through color-coded data.  

Some key features of Maximo ACM:

Models (CM) 
A model can represent a top-level asset (aircraft or train), or an equipment assembly, such as an engine or HVAC sub-system. 
  • Installable? flag can denote whether this Model can be installed on another Model hierarchy. An Installable Model of a coach or car can be used in many other models like Train.
  • A Build Item is a part or an assembly of parts. In an aircraft model, a build item for an engine will contain a CM Item assembly that forms a hierarchy for engine.
BDI Cron Tasks 
BDI runs scheduled jobs via the Cron task PlusABDIAsyncImmediateJobCron to automate actions such as: 
  •  Change PM Status
  •  Generate PM records from Master PM 
  •  Create WO from PM using alert point
  •  Create PM records when Assets are created
Meter Readings For CM Assets
For CM-Managed Assets, Maximo don't support an "Accept Rolldown From" = ASSET or LOCATION for child assets/locations. It must be set to NONE. 
It's the default value when new ASSETMETER records are created for CM-Managed Assets. 

ACM uses a dynamic meter calculation for CM-Managed assets based on asset configuration history. As such
there is no need to roll down (duplicate) the meter readings on the sub-assembly assets.

This enables meter readings to be more easily altered or corrected and also if the configuration history is modified, for example, a child Asset is removed/installed, the dynamic calculation ensures the meter totals for these child Assets are accurate.

If you set "Accept Rolldown From" to ASSET or LOCATION, Maximo will record incorrect values by multiplying the Asset meter totals.

Work Types that resets Meters
ACM related Work Types: OVHL (Over Haul) , REP (Repair) & INSP (Inspection) when used in Work Order for an Asset will reset the Time Since (Over Haul, Repair & Inspection) Meter Reading to 0 on moving the Work Order status to Complete.




Technical Records
Technical Records (CM) application is used for upgrade or modifications campaigns, such as: 
  • Software Updates
  • Safety driven modifications
  • Part replacement
You can define: 
  • Narratives describing the change
  • Compliance status (mandatory or optional)
  • Associated models and variants
  • A CM Item to be upgraded and its position in the model hierarchy
  • An Inoperative Date that indicates when BDI should apply the upgrade
  • A Superseding CM Item, representing the new upgraded part
The "Apply Multiple Upgrades?" option allows grouping multiple asset upgrades into one Work Order. 
 
Technical Records do not perform automatic installation/removal of an Asset in the build hierarchy—it only updates the part number.

Courtesy: Nausheel

References: 

Thursday, February 27, 2025

Maximo Test Automation with Karate testing platform

Maximo Test Automation, using Karate. Karate is the only open-source testing platform that seamlessly combines UI testing, API testing, API performance testing, and API mocks in a single framework.

In today's Agile practices, Maximo consultants must collaborate closely with Business Analysts, Testers and DevOps to understand required testing and identify automation opportunities for successful releases. Every release needs to pass essential milestones, such as Performance impact tests, Critical regression test cases and Defect closures. 

Given these trends, it's essential for a Maximo Consultant to possess proficiency in testing frameworks for UI, Unit and Integration testing, as well as familiarity of how these frameworks are integrated into CI/CD pipelines.

Tests in Karate framework can be created by non-programmers using Behavior Driven Development (BDD)  syntax, which is similar to Gherkin. This approach enables test automation without the need for coding skills

The tasks involved in Karate Test automation are as follows: 
  • Installation
  • Maven Project
  • .feature file 
  • Test Execution & Results
Installation:
  • Install Java & Configure Java path in System Environment Variable
  • Install Maven & Eclipse IDE
Maven is open-source build automation tool, mainly used for Java projects. It assists developers in managing the entire project lifecycle, including building, testing, packaging and deployment. 

  • Install Cucumber Plugin from Eclipse Marketplace
Cucumber plugin helps identify and execute feature files efficiently
Cucumber is a tool that facilitates Behavior Driven Development (BDD). Each scenario in Cucumber feature file consists of a series of steps that the tool uses to verify if the software meets the specified requirements, generating a report that indicates whether each scenario passes or fails. 

Maven project:

Create a Maven project by configuring the Karate dependency in pom.xml file. 
Maven provides a standardized way to handle project dependencies and project configuration through a POM (Project Object Model) file.



By adding a dependency for karate in pom.xml, Maven will automatically download all the necessary dependencies required to run tests using Karate framework.


.feature File

A .feature file in the Karate framework (or other BDD tools like Cucumber) contains Gherkin-style syntax, which is a human-readable format for defining the steps of a test scenario. Each step is then linked to programming code that implements the actual behavior of the test. 

UI Testing Scenario .feature file is to test create Work Order by login into Maximo, navigate to Work Order application from Start Center, enter the mandatory field values and save the record. 


API Testing Scenario .feature file is to validate the XML response from Maximo PERSON REST API GET Query. 


Test Execution & Results:
  • In your project, navigate to .feature file which you want to run.
  • Right click on the file
  • In Eclipse, you will see an option: Run As -> Cucumber Feature
  • Once you select it, the IDE will execute the feature file, and you should see the results in the Console window of your IDE

  • Karate framework generates a detailed test results report.
  • The summary of the test execution is stored in an HTML file, which you can easily view in a browser.
  • By default, Karate framework generates the test results in following path: "target/karate-reports/karate-summary.html"

A sample project demonstrating API & UI testing is available in gitlab repository gitlab-KarateMaximoAutomation 


References:

Sunday, September 29, 2024

Maximo BIRT for Parent-Child Records with Costs

Maximo BIRT Sub report to View a Parent-Child Relationship and Costs

These type of reports are required to view parent - child records with their costs displaying individually for parent and child in separate sections. Users may need to know consolidated costs of the list of records for a period of time.

Let us create a sample report for Parent-child records - Work Order with its Actual Materials records

Create a new report of "Tivoli Maximo Subreport Template"


The parent and child data set are linked using a Data Set parameter. 
subDataSet defines a parameter "wonum" with Direction as Input.


 This parameter will take value from parent data set to subDataSet binding. row["wonum"] will get the value from parent layout in the design.



subDataSet query will get the value using the BIRT setQueryParameterValue method against ? place holders inside the sql query.


In report layout design we are displaying costs values of "WO Total Cost" and "Actual Material Line Cost".

WO total cost is displayed for each WOs and a consolidated WO total cost at footer section. 

Actual Material Line Cost is displayed for all WO Material lines below the sub section and a consolidated one for all WOs at footer. 

A couple of report global variables are created to calculate the consolidated sum for all WOs for the specific date range given in the report input parameter. 

Initialization of these report global variables are made in mainDataSet onCreate Script method. 



On data element of WO total cost & Material line cost fields, we add their values to global variable for displaying them at footer section using onCreate Script method. 



To display the consolidated value of all WOs, we using the onRender method of data element totwocost in footer section.



Report Output displays the WO Total Cost & Material Actual Cost at WO level and consolidated one at footer section.



Report design file woactualssubreport.rptdesign

Saturday, August 31, 2024

Maximo JSON Mapping

What is JSON Mapping ?
  • JSON Mapping is an application in Integration Module
  • A Mapper plugin  com.ibm.tivoli.maximo.fdmbo.JSONMapperExit used as Processing Class (or External Exit) in Publish Channel or Enterprise Service
Why it is used ?
        Used to convert messages of Maximo XML to JSON (Outbound) and JSON to Maximo XML (Inbound).

Applications support JSON
  • JMS Queues
  • Message Tracking & Message Reprocessing
  • Enterprise Services
  • Publish Channel
  • JSON Mapping Application
JMS Queues
  •        JMS Queues support JSON messages from Integration components like Enterprise Service or Publish Channel.
  •         Inbound JSON data is supported into JMS Queues using http/https end point or a direct update to JMS
  •        Not Supported - JSON data using Interface tables, Web Services or from a file upload
  •      Same JMS queue can be used for XML/JSON payload without any configuration
  •   Message driven Bean (MDB) and JMS Cron task psdi.iface.jms.JMSQueueCronTask will support the use of Selectors against queues with JSON data
  •      View Queue and Delete Queue that allows viewing or deleting of data in the queues will support messages in a JSON format
  •       JSON messages work for kafka topic because it  takes payload of base64 encoded compressed xml/json messages


Message Tracking  
        Message Tracking will save the payload in JSON format for Enterprise Services and Publish Channels where JSON Map is implemented.
        The Search and External Message IDs are supported using format -  $.header.attributeID   header is JSON object & attributeID is tag name with case sensitive

Sample JSON payload & its external message ID $.header.transactionId (case sensitive)

{
  "header": {   
    "reportedAsOfDateTime": "2024-04-24T00:00:00+05:30",
    "recordTotal": 1,  
    "transactionDateTime": "2024-04-29T03:30:00+05:30",
    "transactionId": "4a262629c1134b1eafed7b81dd50a6b",
  },  
  "data": {
    "assets": [
      {                     
        "assetId": 10000056,
        "assetLocationId": 10000062,      
        "assetCriticalityCode": 1,
        "assetStatusCode": "OPERATING",
        "assetStatusDate": "2022-06-06",
      }
    ]
  }
}


Message Reprocessing
        Message Reprocessing application supports both JSON and XML. Error Messages from Enterprise Services and Publish Channel with JSON Map can be viewed in the application as JSON. 
 
Enterprise Service
JSON Mapping for Enterprise Services can be used in a couple of scenarios: Asynchronous where ES is invoked with an inbound JSON message persisted to an inbound JMS queue or Synchronous http/https Call without JMS queue as an outbound response.

Enterprise Service using JSON Mapping need to have Processing Class (External Exit)  com.ibm.tivoli.maximo.fdmbo.JSONMapperExit or a Java class extending this class. This processing class is needed for both request and response side.

The mime type of content-type header parameter should be "application/json".

Publish Channel
JSON Mapping for Publish Channel to convert outbound XML message into JSON is used in scenarios: Data is pushed out by an Event/Data Export or triggered from an incoming message of an enterprise service (customization in java/scripting for Event Filter class is used to enable response to incoming message).

A JSON message placed in outbound queue can be processed by End points: HTTP/JMS/XML file. The XML file end point will create a file in JSON format.

JSON Mapping Application
JSON Mapping application is used for creation and configuration of a JSON Map used for Integration messages.
This application has fields for 
Mapping: This field need to be entered as per the Maximo naming convention for different Integration points. 
  • ExternalSytemName.EnterpriseServiceName.IN
  • ExternalSytemName.EnterpriseServiceName.RESPONSE (Outbound)
  • ExternalSytemName.PublishChannelName.OUT  
Object Structure: Object Structure of type INTEGRATION to map the JSON data
Direction: Inbound or Outbound Processing
End Point: Existing HTTP End point for JSON payload
URL: URL will be used to retrieve the sample JSON data for configuration. 

End point or URL should be able to access the sample JSON payload and populate the data in JSON document section. We are also allowed to manually enter the JSON data. It is recommended to have the content in simple editor like notepad before pasting in JSON document section as directly putting the content from browser will have junk character and cause problems on the mapping configuration. 

JSON Mapping Properties
Once we have pasted the content of the JSON data, we can proceed on the JSON object and its attribute mapping in the Properties tab of JSON Mapping application.

The JSON Mapping can be performed for Inbound and Outbound messages. 

Inbound JSON Message to Maximo XML mapping:
Please refer the steps documented in the reference link.

Maximo XML Message to Outbound JSON mapping:
We read the Interface specification document to know the expected JSON outbound message expected by external system. 

for example, we paste the sample message in JSON document section. 
{
  "header": {   
    "reportedAsOfDateTime": "2024-04-24T00:00:00+05:30",
    "recordTotal": 1,  
    "transactionDateTime": "2024-04-29T03:30:00+05:30",
    "transactionId": "4a262629c1134b1eafed7b81dd50a6b",
  },  
  "data": {
    "assets": [
      {                     
        "assetId": 10056,
        "assetLocationId": "POWERHOUSE",      
        "assetCriticalityCode": 1,
        "assetStatusCode": "OPERATING",
        "assetStatusDate": "2024-08-08"
      },
  {                     
        "assetId": 10058,
        "assetLocationId": "GARAGE",      
        "assetCriticalityCode": 1,
        "assetStatusCode": "DISPOSED",
"assetStatusDate": "2024-08-08",
        "disposalDate": "2024-06-06",
      }   
    ]
  }
}

Some rules to consider: 
assetStatusDate - date format should be yyyy-MM-dd
disposalDate - this field should be present only if assetStatusCode is DISPOSED or REPAIRED
assetLocationId - this value should be within an array even though we have single value in Maximo

Object Structure for this sample message is configured without any alias conflict:

JSON Mapping is defined for Outbound Asset data 

In the Properties tab, we set the JSON Object Mapping first. 






JSON Properties for Object Attributes: 
Process Order 1 and 3 are for header section only.

Simple Maximo XML field to JSON tag mapping

Formatting for Date field mapping


Conditional Values: Disposed Date field should be set only for statuses [DISPOSED & REPAIR]

We can have multiple conditions for the mapping of one field.


Valid Condition Syntax must align with JavaScript Notation. 
attr$STATUS=="DISPOSED" || attr$STATUS=="REPAIR"
attr$STATUS=="DISPOSED" && attr$STATUS=="REPAIR"


Concatenation of values in Source Attribute 

Limitations
  • Maximo accepts Array for JSON Objects level, but not at JSON Attribute level. So if the external system needs a JSON value within an Array, we need to convert it in User Exit class. for example, "location":["30045", "56789" , "67890"] It is considered as a single value and can't be pared in Maximo.   
  • JSON Map is not supported for Invocation Channel
References: 

Tuesday, July 30, 2024

Maximo Loggers and Appenders

What is Logging ?
  • Logging is required for investigating issues in Live system. 
  • Without logging, it's very difficult to identify the source of the problem for resolution
Maximo Logging
  • Maximo Uses Log4j. Log4j is an open source independent logging framework developed by Apache. It's not part of standard Java API.
  • Log4j provides the ability to selectively enable or disable logging requests based on Maximo logger.
  • Log4j allows logging requests to print to multiple destinations (or Maximo Appenders). 
Logging properties in Maximo
  • Logging properties are available inside Maximo application (System Configuration --> Platform Configuration --> Logging) and stored in the database.
  • There are 3 components on properties: Loggers, Log Appenders and Layout
What are Maximo Loggers ? 
  • Loggers are the component of Maximo that prepare log statements
  • It follows hierarchical naming rules with dot notation

How Log statements are handled ? 

         Log statements are either written to User Interface consoles or sent as output to log files.

What is Maximo Root Logger ? 
  • Root Loggers are at top application functional level or main subtopic of loggers.
  • A logger is said to be an parent of another logger if its name followed by a dot is a prefix of the child logger name.
  • Without root (or main) logger, no logging will work in Maximo.

What is a child logger ? 
  • Parents are root loggers and child loggers are the loggers that inherit the log message level of the root logger. 
  • They contain the name of the root logger in their names.
Can we deactivate loggers ? 
  • Root Loggers can't be deactivated, but child loggers can be deactivated.
  • System Users determine the size that is required for Appenders. 
What is an Appender ? 
  • An Appender is a log file or location created by Maximo where log information is written.
  • Each enabled logging request for a given logger will be forwarded to all the linked Appenders as well as the Appenders higher in the hierarchy.
  • Appenders are used to forward log messages to different destinations such as files, databases, console, cloud etc.,
  • Log4j appenders exist for the Console, files, GUI components, remote socket servers, JMS, NT Event Loggers, and remote UNIX Syslog daemons. 
  • Maximo uses only file type Appenders.  
Maximo has 3 predefined Appenders:
  • Console - Writes log information to Console or std.out (SystemOut.log file)
  • RollingWrites log information to specified file name and rolls to a new file when size is reached
  • Daily RollingWrites log information to specified file name and rolls to a new file by EOD
MX File Appender is Maximo's extension of Log4J Appenders: 
psdi.util.logging.MXDailyFileAppender.MXFileAppender psdi.util.logging.MXDailyFileAppender.MXDailyFileAppender

Log Appender Layout
  • Layout is used to format the log output written to a file.
  • A layout is associated with a Log4J appender
    • log4j.appender.Console.layout=psdi.util.logging.MaxPatternLayout
    • log4j.appender.Console.layout.ConversionPattern=%d{dd MMM yyyy HH:mm:ss:SSS} [%-2p] [%s] [%q] %m %n %C{1} %M{1} %L %t
    


      • %d - date format given inside brackets{ } 22 JUL 2024 16:40:57:636
      • %-2p - log level [INFO] priority of logging event, left justified to a width of 2 characters
      • %s - Maximo Server Name  [MXServer-UI1]
      • %q - Log correlation entries in format [CID-TYPE-NUMBER]. TYPE is CRON or UI. To enable this property, we need to activate a couple of system properties: mxe.logging.CorrelationEnabled=true Crontask & REST correlation will be enabled. A child property mxe.webclient.logging.CorrelationEnabled=false for enabling UI request Correlation. Logger pattern [%q] and System property both need to be enabled to display correlation log ID. Each Correlation type has its own set of properties and they are printed at end of correlation log. UI request correlation prints out app name, UI session id, UI event identifier, client IP, elapse time etc. Crontask action correlation prints out Crontask name, instance name and elapse time.
      • %m - Maximo message BMXAA6719I
      • %n - System independent new line separator
      • %C - fully qualified class name of the caller issuing the logging request psdi.app.actionscfg.CustomClass %C{1} - CustomClass
      • %L - line number of the code  psdi.app.actionscfg.CustomClass 272
      • %M - method name of the Class issuing the logging request
      • %t - thread name that generated the logging event
      • %F - File name 
      •      


How do Loggers and Appenders interact ? 
  • A Logger can have either one or multiple Appenders. 
  • An Appender can have output from either one or multiple loggers. 
Log Message Levels
  • Every loggers needs a log level There are 5 log message levels in Maximo: FATAL < ERROR < WARN < INFO < DEBUG
  • If a given logger is not assigned a level, then it inherits one from its closest ancestor with an assigned level
Logger in Automation Script
from psdi.util.logging import MXLoggerFactory  
logger = MXLoggerFactory.getLogger("maximo.script")

logger.debug ("Debug level log messages")
logger.info ("Info level log messages")
logger.warn ("Warn level log messages")
logger.error ("Error level log messages")
logger.fatal ("Fatal level log messages")
Impacts
  • Enabling UI correlation causes a delay because of light weight filter for UI events.
  • Enabling %C caller class name, %M method name, %L caller class line number and %F file location are extremely slow and should only be activated on critical investigation or performance is not an issue.
References:

Sunday, June 30, 2024

Automation Script as a Cron task

Automation Script can be used to create crontask without any Java customization file.
 
It's widely used option to avoid outage using Java Code for Cron task.

Cron task definition for an automation script has a Class file value and 2 parameters.
 
Class file value should be set to com.ibm.tivoli.maximo.script.ScriptCrontask

Cron task instance parameters: 
SCRIPTNAME - Name of the automation script without launch point
SCRIPTARG - Arguments to pass values to the Script
{"siteid": "BEDFORD","status": "'WAPPR','APPR','WMATL'"}


Automation Script - C_ASCRONTASK 
Script Name should be set as SCRIPTNAME parameter in Cron task
if arg is not None:
   args = service.tojsonobject(arg)
   
   assetSite = args.get('siteid')
   assetValidStatus = args.get('status')
   
   #service implicit variable is used to getMboSet since 7.6.1.2 . MXServer is not needed
   #runAsUserInfo is the userInfo of Cron task Instance
   assetSet = service.getMboSet("ASSET", runAsUserInfo)
   assetSet.setWhere("siteid='" + assetSite + "' and status in (" + assetValidStatus + ")" )
   assetSet.reset()
   
   assetMbo = assetSet.moveFirst()
   while (assetMbo): 
        # more logic 
	assetMbo = assetSet.moveNext()
   assetSet.save()
   assetSet.close()