Adding a Field to an Existing Interaction in Maximo

If you have ever worked on interactions in Maximo, you would know how easy it is to set up one and start fetching data from a webservice. It helps you avoid the hassle of writing and maintaining custom code with just a few configuration steps. Practically it does all the work for you – from creating objects and relationships to setting up the dialog box and sigoption to display the data.

But when it comes to adding a new attribute to be fetched and displayed from the webservice, it requires the entire thing to be created again. This means the interaction and all its configurations have to be scrapped and recreated with the new set of attributes. That’s a lot for just a field addition.

So I thought what if we manually add this attribute to the objects and to other configurations and see if it works out.

To explain this better, I have an interaction that fetches all the football matches that have been played in the city (which is the location record in Maximo). The data is just fetched from the webservice for display and not inserted or committed anywhere.

Soap_Response

2017-04-25 21_56_38-Locations

Now I want to show the ‘Result’ field in the dialog box from the webservice response but the problem is – this field was not initially selected while creating the interaction so it’s not present in the object that handles the webservice response. So to show this field in the dialog I did the following –

 

  1. Added the new attribute to the response object – The attribute name and the data type must be the same as that of the field in the webservice. The description of the attribute must be the path of the field in the response XML. This is what the description of my field looks like –ns0:GamesPerCityResponse/ns0:GamesPerCityResult/ns0:tGameInfo/ns0:sResult

    Soap_Result

    2017-04-25 22_12_23-Database Configuration

     

  2. Included the new attribute to the response object structure 

    2017-04-25 22_12_42-Interactions

    2017-04-25 22_16_13-Object Structures

     

  3. Added the new attribute to the dialog in the app designer

    2017-04-25 22_21_51-Locations 

But I noticed that still the data was not being fetched and shown in the field. So I did some more research and found that there is an OBP (Object Blue Print) field in the MAXINTERACTION table that keeps the xml schema of the request and response for the interaction. The new field needs to be added to that schema for it to work. So I updated the schema and Voila! it worked!

OBP

2017-04-25 22_59_21-Locations

Please note that this solution is applicable only if the field already exists in the webservice schema and only needs to be displayed in Maximo.

Enjoy!

Until next time!

Meter Change Out in Maximo for Transportation

I recently came across a feature in Maximo that can be really useful in scenarios where meter reset/meter changes are not so rare occurrences.

You may come across several scenarios where the meter on an asset is either replaced or reset due to certain maintenance activities. These maintenance activities could either be a scheduled maintenance like overhaul or be an unscheduled corrective maintenance due to a component or meter failure. In either case the meter reading of the meter in Maximo would have to be reset to a new value.

First thing that would strike you would be to enter the new reading on the asset through the enter meter reading option. But that wouldn’t work for continuous meters since if the new reading is less than the old reading, the meter reading will actually rollover and the life to date reading will show incorrect value. And if the new meter reading is more than the old reading, Maximo will accept the new meter reading but the life to date reading will still be incorrect.

2017-01-16-21_02_29-assets-tr2017-01-16-21_02_36-assets-tr

This is where the meter change out feature of the Asset(tr) application comes into picture. The meter change out functionality updates the last meter reading of the meter with the new reading and also maintains the life to date reading. You also have the option to update the life to date reading while performing the meter change. See how it works –

2017-01-16-23_44_28-assets-tr2017-01-16-23_44_33-assets-tr2017-01-16-23_45_15-assets-tr2017-01-16-23_46_04-assets-tr

Until next time!

Maximo, IBM CDC and its Limitation When Replicating Schema

A Little Background –

IBM Change Data Capture is part of the IBM Infosphere suite and is mainly used as part of the ETL process. It has great transformation and data replication capabilities and supports most of the enterprise databases products.

For replication, CDC captures changed data directly from database logs rather than querying the database which makes it quite efficient. It provides near real time replication but that is dependent on a lot of parameters like network latency, I/O, etc.

Since CDC has such great replication capabilities, its application can be more just the ETL process.

The Use Case –

In one such case, we are using CDC to replicate Maximo database to create replicas of Maximo for different sites. Using CDC, we are replicating just the site specific data to the replicas which helps in keeping the database size low compared to main data center.

These replicas act as standby instances of Maximo which helps maintain high availability of Maximo at site for critical assets.

Bidirectional replication is enabled to sync back data from replicas to data center in case standby instance is used as primary node due to unavailability of the data center Maximo.

The Problem Statement –

CDC replicates data very efficiently but when it comes to schema changes, its a problem. CDC does has the provision to replicate schema changes but it comes with a lot of limitations. I’ll discuss those limitations in detail for DB2 database but before that lets see what these changes are.

When a bug fix, enhancement or ifix is applied to Maximo, these have to be applied to the Maximo replicas as well. These patches may include schema changes like column length change or new stored procedure, triggers etc.

Let say we have 20 sites and we maintain a standby instance of Maximo for each of the sites. Applying these patches to all 20 instances would be a time consuming activity and would require a large amount of production downtime.

For CDC to replicate data, schema definition at both source and destination databases must be identical. So these patch deployments on all instances becomes a necessity.

We could try to replicate schema through CDC. Here are the considerations and limitations of replication schema through CDC for DB2 for LUW ver. 11.3.0–

Consideration –

The following InfoSphere CDC issues should be taken into consideration before you attempt DDL replication:

  • A table targeted for DDL replication cannot be involved in any other InfoSphere CDC table mapping. That is to say, you cannot mirror from two different source tables to a single target table.
  • Conflict Detection and Resolution is not supported for DDL replication.
  • Differential refresh and Refreshing a Subset of Rows are not supported for tables for which DDL operations are being replicated.
  • Derived columns and derived expressions are not supported for tables for which DDL operations are being replicated.
  • LOB columns are selected from the database at the time of replication using the key or unique index (if any) associated with the source table. Therefore, only the current image of a LOB column field in a source table will be sent at the time of replication. If latency is present for a subscription that is replicating DDL operations and there are changes to the list of columns which make up the key used for searching, the target column may contain a null value until the next DML change on that row. If latency is present and the key of the row changes, the target column may contain a null or incorrect value
  • Bidirectional replication is not supported for DDL replication.
  • When InfoSphere CDC encounters certain object types that cannot be replicated, such as UDTs (user-defined columns), the table will be parked. You will need to determine if the unsupported table is essential to your replication solution. If you decide that it is not essential, you should modify your rule set to exclude the table. If you determine that the table is essential, the table will have to be dropped, re-created and its structure changed in order to be supported for DDL replication.

Limitations –

The following types of DDL changes can be replicated by InfoSphere CDC for DB2 – 

  • CREATE TABLE
  • DROP TABLE
  • ALTER TABLE ADD COLUMN
  • ALTER TABLE ALTER COLUMN SET DATA TYPE

Table-related objects for which DDL replication is NOT supported by InfoSphere CDC for DB2 –

  • Views
  • Synonyms
  • Triggers
  • Materialized query tables
  • Tables containing user-defined types

Database-related objects for which DDL replication is NOT supported by InfoSphere CDC for DB2 –

  • Functions
  • Stored procedures
  • Packages
  • Java classes
  • Database links
  • Roles
  • Directories
  • Dimensions
  • Libraries
  • Profiles
  • Users
  • Sequences
  • Tablespaces
  • Schemas

Conclusion – 

With all these limitations, replication of schema through CDC is not a viable solution. A better approach would be to use deployment scripts for patch deployment on all the instances.

If you have any comments or opinions, do write them in the comments section.

Have a great day!

Data Restrictions and their impact on MBOSets

At some point in time every maximo developer or support engineer would have implemented data restrictions to hide data or make it un-editable for the users. Since they are fairly easy to implement and only require a sign out and sign in for them to take effect for a user, they are very widely used. However, if not implemented carefully, they can seriously impact performance.

I am going to explain how mbosets are impacted by data restrictions, the qualified type of data restriction in particular.

When a qualified type of data restriction is implemented on an object with a condition, the user will have access to only those records of that object which are fetched by the condition’s where clause i.e. those records which qualify the condition. This clause is applied over and above any exist clause.

When it comes to java customization, the impact of data restrictions on the mboset depend on the way the mboset has been fetched in the code. If the mboset has been fetched through MXServer then the data restrictions will apply (if you remember we pass the userinfo to fetch the set) but if the set is fetched through a relationship then the data restrictions don’t apply.

You may ask why this different behavior? That’s because when an mboset is fetched through relationship, it becomes a child mboset and the rule is – owner must have access to all it children. That’s why!

Let me explain this with an example. Let’s say there is a data restriction on the asset object to show only those assets that have their type as FACILITIES. When a user navigated to the asset application he would be shown only FACILITIES type assets. When he navigates to the subassembly section of any of these assets, he would be shown all child assets of that asset which may or may not be of the type FACILITIES. Seems justifying right!

Note: Subassembly section in assets is a relationship of asset with itself to show child assets.

2016-11-15-20_38_48-security-groups

2016-11-15-20_42_39-assets

2016-11-15-20_42_49-assets

Let see how and where does this impact –

Domains – Table domains are fetched using MXServer so data restrictions apply. But if you are creating a table domain through code and in the getList method you use relationship then data restriction wont apply.

Dialogs – Dialogs are mostly created using a relationship so data restrictions would not apply. In some cases, mboname is used instead of relationship, in that case data restrictions would apply.

Non-Persistent Fields – Non-persistent fields are populated through java code. If the code uses MXServer to fetch some data and populate the field, the non-persistent field might not get populated or might display incorrect data if data restriction exist on that fetched set.

Other Customizations – Certain logic may fail due to data restriction if these logics are not implemented keeping data restrictions in mind and specially if MXServer is used to implement these logics.

Developer must keep in mind the impact of data restrictions while implementing logics. I am not saying MXServer is a strict no-no, but if data restrictions are going to be placed the impact must be considered.

On the good side even if qualified data restrictions are applied, they are majorly applied on main objects isn’t so!

Cheers!

Conditionally Changing the Lookup on an Attribute

Whenever I travel, I either read or I write. These days I am travelling a lot and I am on a writing spree, so you would be seeing quite a few posts from me.

That brings me to this unique requirement to display different lookups on a field based on a condition. A simple example of this is displaying a location lookup on a field if, lets say the orgid is EAGLENA else display an asset lookup on the same field.

This can be achieved through conditional UI in application designer.

The images below show how to setup this through conditional UI on a field EQ1 on ASSET.

2016-11-19-14_34_39-application-designer

2016-11-19-14_32_21-application-designer

2016-11-19-14_32_28-application-designer

2016-11-19-14_39_46-assets

2016-11-19-14_39_55-assets

2016-11-19-14_40_22-assets

2016-11-19-14_40_25-assets

Have a great day!

Recursive Queries, Maximo Lookups and Deadlocks

There are several scenarios where you have a requirement to present data that cannot be queried through a simple select statement but requires looping through the table as the data resides in a parent child hierarchy in the table. Work order hierarchy is one such example where a work order record has its parent listed in one of its column, and the parent’s record would have its own parent listed in its record and so on. So to find all the child work orders to the leaf level under a work order, looping would be required.

Note: Although ANCESTOR tables maintain the complete ancestor hierarchy but at times they can have incorrect data.

This is typically achieved in a relational database through a recursive query and the traditional way is to use CTE or Common Table Expression which uses the ‘WITH’ statement to construct recursive queries. I will not go into details of how to construct or use CTE, their detailed documentation is readily available online.

Oracle has introduced a much simpler syntax to execute recursive queries – the START WITH, CONNECT BY statement. It has a lot of limitation compared to the traditional CTE method but for simple querying its gets the work done in a lot less effort. The START WITH, CONNECT BY statement can also be used in DB2 by enabling the oracle compatibility mode 08.

When it comes to table domains in Maximo, using the traditional CTE is a challenge since in table domains only the where clause can be specified and querying using CTE has an entirely different syntax so it cannot be specified in the listwhereclause. The START WITH, CONNECT BY on the contrary, has the syntax similar to the traditional select statement and can be used in the table domains to query data. Here is an example of the START WITH, CONNECT BY statement that lists all the child work orders of the work order WO-1990 till the leaf level.

SELECT * FROM WORKORDER
START WITH WONUM = ‘WO-1990’
CONNECT BY PRIOR WONUM = PARENT AND ISTAKS = 0;

A little bit about table domains, when you open a lookup in Maximo which displays data through table domain, it doesn’t fetch the entire result set in one go but only that no. of rows that are displayed on the first page of the lookup. When you click the next page on the lookup, the next set of records is fetched and so on. What that means is if the lookup is configured to display only 10 rows at a time, when the lookup is opened, only first 10 records are fetched from the database, now if the next button on the lookup is clicked, the next 10 records are fetched and so on.

This is where it gets interesting, what I have observed is if you use the START WITH, CONNECT BY statement in a domain, when the lookup for this domain is opened, it holds a lock on the table(row level lock) till the time that lookup is closed. This is not the case with non-recursive queries, they never hold a lock, even complex queries with joins and sub-selects.

This is where the problem lies, when the lookup with the START WITH, CONNECT BY statement is opened in one application and another user or the same user in another application tries to do a transaction (update or delete) on the same set of rows as queried by the lookup, the user doing the transaction is presented with a deadlock error. Overriding the isolation level for the recursive query also doesn’t help.

db_error_911

The image above shows an error presented to the user in a similar scenario but in this case the lookup and the transaction performed was on the LOCHIERARCHY object.

So it is better to avoid using START WITH, CONNECT BY statement in lookups and use alternate solutions like ANCESTOR tables or views to display data. Some of the lookups can be tricky and may require lot of effort to avoid using START WITH, CONNECT BY statement but if there are deadlock issues, it’s worth the effort.

Cheers!

Import Export Multiple XMLs in Maximo

Did you know that maximo support multi XML import export?

If you want to export a bunch of application xmls from one environment to another or may be you want to edit more than one xml and then import them back into maximo, this functionality can come in handy.

To use this functionality, filter the list of applications to be exported on the list tab of the application designer and click the export button on the toolbar. Maximo will export a single xml containing all the applications filtered on the list tab. This xml can be imported back in the same environment or other environments as per your need.

The screenshot below shows 3 applications being exported. The exported xml shows 1 expanded application presentation and other 2 collapsed.

2016-04-05 21_39_08-Application Designer.png

2016-04-05 21_38_59-eamserver_9080_maximo_ui_presentationset.xml_event=exportall&uisessionid=3&csrft.png

Adding custom attribute to asset template and copying it to the asset

When it comes to adding a custom attribute to asset template and getting it copied to the asset, one might think that this may require extending the asset template class and adding the code to get the field copied or probably configuring a cross over domain. But its way easier than that!

Just creating the custom attribute in asset template and in asset with the same name gets the job done. When the asset is created from the asset template, the data from the custom field in asset template gets copied over to the field with the same name in asset. I did a quick check on this and it works as expected. Have a look –

2016-02-14 10_52_35-Asset Templates.png

2016-02-14 10_55_09-Asset Templates.png

2016-02-14 10_55_44-Assets.png

When using MXServer for fetching MboSet

There are two ways of fetching a MboSet in java code, either using a relationship or through MXserver. There are different benefits for using either of these and different scenarios may need one of these ways to be used. For now, we are going to talk about MboSet fetched from MXServer.

When fetching a MboSet from MXServer, there are a few things that one needs to be careful about. Poor knowledge of these may result in performance issues, poor memory management and undesirable outcomes.

There are six simple rules to keep in mind when fetching MboSet from MXserver. These rules are as follows –

  1. Always use setWhere() and reset() on the set fetched from MXServer. The where clause that you give in the setWhere will reduce the no. of MBOs fetched in the set. The reset will get the data from the database using the where clause. If the setWhere is not used, the entire set is fetched from the database which means the entire table is fetched into the memory.
MboSetRemote assetSet = MXServer.getMXServer().getMboSet("ASSET", getUserInfo());
assetSet.setWhere("LOCATION = 'BEDFORD'");
assetSet.reset();
  1. If the set is being fetched just to add new MBOs and not for traversing then use 1=0 as where clause in the setWhere. This will fetch an empty set.
assetSet.setWhere("1=0");
assetSet.reset();
  1. If the set is being fetched just for traversing and not for any addition or updates set DISCARDABLE flag as true on the MboSet. Discardable MboSets are not cached in memory, they can only be traversed in forward direction and cannot be saved.
assetSet.setFlag(DISCARDABLE, true);
  1. If MboSet is fetched for readonly purpose, set NOSAVE flag as true. This way the MboSet won’t be added to the MXTransaction which would shortens the looping time of the transaction.
assetSet.setFlag(NOSAVE, true);
  1. If an add or update transaction is being performed on an MboSet, do not forget to call save(). Contrary to popular belief that save shouldn’t be called explicitly in java code, MboSet fetched from MXServer must be saved before the set is closed otherwise the changes would be lost. MboSets fetched from relationship do not require a save to be called explicitly because their save is called when their parent is saved. Hence the belief.
  1. Always call clear() and close() on the MboSet fetched from MXServer once it is certain that it is not required anymore. This releases the memory and the database resources. If the set is not closed, it will remain in memory till it is collected by the garbage collector which could be a long time.
assetSet.clear();
assetSet.close(); 

clear and close shouldn’t be called on an MBOSet fetched from a relationship. This will give undesirable results.

So keep in mind these simple rules next time when you are fetching a set from MXServer.

In my next post I will try to explain you the difference between clear(), cleanup() & close(). Stay tuned.. 🙂

Calculation for Units to Go in Preventive Maintenance (CM)

Needless to say, the calculation of units to go in ACM is a bit trickier than how it’s calculated in base Maximo. People who have worked on it can understand where I am coming from.

plusalfevent

Units to Go is calculated based on the PLUSALFEVENT (Maintenance Event) record which is created when the PM is made ACTIVE. These are the records displayed in the Maintenance Plan tab in the Asset (CM) application.

It is these PLUSALFEVENT records that are utilized by the BDI process to decide when Work Orders should be created from the PMs and also to decide whether the PM is overdue, past its warning point etc.

The ‘Left’ value on the Maintenance Plan tab is essentially the units to go for the associated PM in Assets (CM).

The calculation for units to go is:

Units to Go = Due Count – Current Count

Where Due Count = Active Count + PM Meter Frequency

The Active Count is the meter count calculated at the Active Date of maintenance event (PLUSALFEVENT.ACTIVEDATE).

Every time a work order for a maintenance event is completed, a new maintenance event (PLUSALFEVENT) entry is created with an Active Date same as that of the work order completion date. The same date is stamped as inactive date on the old maintenance event record.

So every time the active date from the most recent maintenance event record is used to calculate the Due Count for the PM.

The Current Count is the meter count at the current system date and time.