Wednesday 22 November 2017

Using Interface Tables to Insert Records - Continuous Vs Sequential Queue

In our world, we come across different requirements and problem statements for which we need to provide solution. It is not necessary that each solution we design or implement would be agreed upon universally. We had this requirement to generate records automatically for one of the application in MAXIMO. At the same time, record needs to be created in the parent object as well as records need to be entered to its child object. So, definitely we need to think about Object Structure, Enterprise services, External Systems and off course Interface Tables to insert records to our MAXIMO main objects.

For this data import to MAXIMO through interface tables, we need to consider or keep in mind the following:
  1. Object Structure - The object structure with the required objects and parent-child relationships should be created. Exclude/Include fields should be used appropriately keeping in mind what columns need to be included in the interface table.
  2. Enterprise Service - Enterprise Service should be created with the above created object structure and the intended name of the Interface Table mentioned. You can check to enable message tracking.
  3. External System - You can create a new external system or use an existing one but ensure that end point selected is "MXIFACETABLE", sequential queues and continuous queues properly configured. 
    • Outbound Sequential Queue = jms/maximo/int/queues/sqout
    • Inbound Sequential Queue = jms/maximo/int/queues/sqin
    • Inbound Continuous Queue = jms/maximo/int/queues/cqin
    • In the Enterprise Services tab for this external system, add the above created enterprise service, check the "Enabled?" check box, check or uncheck the "Use Continuous Queue?" checkbox.
    • From action menu, now select the Create Interface Tables action. In the dialog, select the interface table name mentioned with the enterprise service and click on Create button. It will take a few seconds to process your request.
  4. Cron Task - In Cron Task Setup application, open "JMSQSEQCONSUMER" cron task and ensure that two cron task instances, one for sequential In and one for sequential Out are active. Next, open the "IFACETABLECONSUMER" cron task. A cron task instance should be present which is active with its scheduled defined. The properties for this cron task instance should have QUEUETABLE=MXIN_INTER_TRANS and END POINT=MXIFACETABLE.
  5. Writing data to Interface Table - At this stage, everything on the Maximo side has been set up, and we need to do to create some kind of routine to send data to the interface tables. The cron task IFACETABLECONSUMER, then polls the inbound interface queue table for new records to process as per the schedule set. 
    • Automation Script: For every record that needs to be added to the MAXIMO object, we need to add a new row to MXIN_INTER_TRANS object as well as to the Interface Table. For our convenience, we have used an automation script to include insert scripts for MXIN_INTER_TRANS and the interface table created above.
    • Cron Task: To trigger or initiate the above automation script, we have set up a new cron task with class=com.ibm.tivoli.maximo.script.ScriptCrontask. A new cron task instance also needs to be created with "Active?" checkbox checked and appropriate schedule defined. The properties for this cron task instance include SCRIPTARG=0 and SCRIPTNAME=<above automation script name>
With above configurations, we were able to create new records for the application, as stated above. Now, moving over to the confusion over using continuous queue or sequential queue for this approach. We had initially used continuous queue for this inbound processing of records to MAXIMO objects. If an incoming message gets stuck in sequential queue, other subsequent incoming messages are not processed until the error message is either reprocessed or deleted. To avoid this, we had gone ahead with continuous queue. It was working fine in our development instance. When this was moved to TEST and Production instance, we started facing an error of Database Error 1 in some of the incoming messages. 

I need to mention here that this database error 1 had come for primary key attribute of the main object in the object structure.We checked the logic in automation script to see if we were trying to insert any duplicate value to this attribute. This may have been due to continuous queue trying to insert two records with same ID generated. If we would reprocess the message with status=ERROR, it eventually gets processed. To handle this, we tried two approaches.
  1. We tried with increasing the Max Try Count, this issue got reduced but it was not fully resolved, i.e., the number of failed messages decreased but issue was still prevalent for a few messages. 
  2. We changed the inbound processing queue to sequential. We have never come across the database error 1 for our primary key attribute again and it has been seven to eight months since :) 
With the above experience, we can conclude that if the order of processing is important, like in our case above, we should use Sequential Queue rather than Continuous queue. Continuous inbound processing works better for transaction records like invoices, etc. Please do share your experiences and thoughts.



Saturday 22 April 2017

Exploring Automation Scripts and their migration

We have already explored Automation Scripts in Maximo 7.5 and 7.6 to customize as per our requirements from Object, Attribute and Action launch point. Needless to say, automation scripts have made life easier not in one but in many ways for developers. There are many bloggers who have jotted down their thoughts around using action automation script. You can refer the blogs listed below to know about how automation script can be used to control an action from a push-button. And these work perfectly as an action called from any escalation as well.

  1. Action Automation Script
  2. Automation Script to control its action from a pushbutton
We do have Attribute Launch Points which have made it easier to address field level validations as well. Whenever a value is specified for that field, it may be a change of value as well, this attribute launch point which is associated with the field gets eecuted. Automation Scripts have given us the flexibility to bind our desired IN/OUT/INOUT variables from the launch points to values to/from object attributes.

Let us consider below two examples for Attribute Launch points:
1. Say, we want to clear a value in one of the field 'ATTR2' based on the value of some other field 'ATTR1' of object, say, 'TAB1'

  • I will create an attribute launch point on Object=TAB1 and Attribute=ATTR1
  • I will keep the launch point even as run action.
  • Let us keep the script language=Jython and log level=ERROR.
  • I am not going to create any variable and in the automation script, I will write the following code snippet:

strAttr1 = mbo.getString("ATTR1")
if (strAttr1=='XYZ'):
mbo.getMboValue("ATTR2").setValueNull(2L)
                PS: I have used setValueNull(2L) because there is a data restriction on the field ATTR2.
2. Next say, we want to set the count frequency when we add/update the value of ABCType in an inventory record-

  • I will create the attribute launch point on Object=Inventory and Attribute=ABCTYPE.
  • I will keep the launch point event as run action.
  • I will keep the script language=Jython and log level=ERROR.
  • I will declare three INOUT variables var_AFreq, var_BFreq and var_CFreq, with binding type=MAXVAR (value source from a MAXVAR). As soon as I select MAXVAR in binding type. Global Binding Value becomes required. We can select ABC Breakpoint-cycle count frequency and associate A_CCF, B_CCF, C_CCF, respectively. We can also copy the value in Launch Point Biding Value field also.
  • I will declare one IN type variable, var_ABCType with binding type=ATTRIBUTE (value sourced from an attribute) and launch point attribute as ABCTYPE
  • I will declare one more variable of type=OUT, var_CCF with binding type=ATTRIBUTE and launch point attribute=CCF
  • In the automation script, following code snippet, I need to write:

        if var_ABCtype=='A':
            var_CCF=var_AFreq
        if var_ABCtype=='B':
var_CCF=var_BFreq
                    if var_ABCtype=='C':
                       var_CCF=var_CFreq


 Now, let us talk about migration of automation script with an Attribute launch point. Whenever we are migrating an automation script and attribute launch point which has an event other than validate say, Initialize Value or Run action, in the source environment, we found that on the target environment, the event for the attribute launch point is selected as Validate.
While creating the package in the source environment, we had selected OOB migration group SCRIPTCFG in the package definition. We had kept the script names in the where clause for migration object DMSCRIPT ad launch point names in the where clause for migration object DMLAUNCHPOINT as below

  •      autoscript in ('script1', 'script2'...)
  •      launchpointname in (launchpoint1', 'launchpoint2'...)


EVENTTYPE attribute in object SCRIPTLAUNCHPOINT is non-persistent but for different event types of Attribute launch point type records, OBJECTEVENT saves a different value in database table. For example,

  • for attribute launch point type records with event Validate, objectevent=0, 
  • for attribute launch point type records with event Run action, objectevent=1,
  • for attribute launch point type records with event Initialize Value, objectevent=2, etc.

So, if we keep the where clause for migration object DMLAUNCHPOINT as below, it might solve the above issue.

  • (launchpointname='launchpoint1' and objectevent=2) or (launchpointname='launchpoint2' and objectevent=1) or .....

This is not tried and tested, however, would like to know your suggestions/thoughts around this.