We often tend to think that the default system setup is optimized for better performance. But sometimes the default setups are constrained by backward compatibility concerns. Retaining MBOs across the length of the Publish Channel is one such feature, which is enabled by default purely for backward compatibility reasons. Turning off that switch will most certainly lead to better performance especially when you are exporting large volume of data [MBOs] using the channel. We are going to discuss the effects of turning it on and off below.
Inside the Publish Channel
Publish channel is used to get Maximo [Tpae] application data outbound. The source [as well as the content and the structure] of the data is defined by the Object Structure used for that Publish Channel. Object structures as you already might know is the configuration that holds the definition of a graph of related MBOs. Publish channel in essence publishes the data represented by that Object structure in an XML format. Publish channel can be triggered either by an MBO event or by an export data request. Event mode is turned on when we enable listener on the channel and at least one of the External systems for the channel is enabled.
A high level listing of the logical steps that happen inside the Publish channel to publish the data is provided below.
- Triggering the Channel - MBO or a collection of MBOs [MBOSet] is identified to be published [either via MBO event or explicit call for export]
- XML Generation - The MBO/MBOSet graph is serialized to an XML message.
- XML Transformation - The XML message is passed through the rules defined [if any] for the channel as well as the user exits [if any] and the adapter exits [also known as channel processing classes - if any] which potentially can modify the XML message.
- Message Queuing - The resulting XML message is embedded into a JMS message and written to the outbound queue.
- Message Routing - The message is picked up from the queue and routed to the designated end point for the External system + Publish Channel combination.
Retain MBOs Flag
The "Retain MBOs" flag plays a part in steps #2 and #3. In context of performance and memory these are the 2 most expensive steps in the process of publishing data using the channel. Lets take an example to understand the implications of this flag. Our example channel is the MXPOInterface which is based on the MXPO Object Structure, as shown in the following diagram.
For the sake of discussion let's assume a data export was requested by the user for 100 PO's using this channel. We will follow the steps that we described earlier to see what happens when such a request is made with the "Retain MBOs" flag is set to true.
In step#1 the export request will fetch an MBOSet [collection of unique MBOs] that points to a ResultSet [database cursor] referencing the 100 PO records [Note - the records are not converted to a MBO yet - so its still an empty MBOSet].
In step#2 the serialization process will load the first [PO] MBO and serialize the graph defined by the MXPO Object Structure into the XML stream. So at this point all the MBOs [PO,POLINE,POCOST,POTERM] for the first PO are loaded in memory. The serialization process will now shift to the next PO in the set and serialize the whole graph as before. This process continues till it's done serializing all the 100 PO's along with all its related objects as defined in MXPO. So at this point there is a huge bloat of MBOs in memory. If we have an average of 2 POLINE's each having 1 POCOST and 6 POTERM's per PO, the process would have loaded 100+100*2+100*2+100*6 = 1100 whopping MBOs in memory! All because it was instructed to retain the MBOs as they were getting serialized to XML. This puts tremendous pressure on memory and results in performance degradation [and possible Out of Memory errors] for exports as we start increasing the number of MBOs in the export. The number of MBOs for performance plateau [or OOM error] is dependent of the size of the MBO too. So for WORKORDER's it will plateau earlier than for say TICKET or PERSON MBOs. Also make no mistake - the same degradation or OOM error can happen if you are trying to export say one PO with 1000 lines. The number of MBOs in memory would be 1+1000 [POLINE]+1000*1[POCOST say average 1 per line]+6 [POTERMS]=2007 MBOs!.
The primary motivation behind doing such a thing would be to safe guard against any MBO based rules down the line or the user exits/adapter exits needing those MBOs down the line in step#3. Traditionally this feature [allowing MBO access in exits/rules] was there in version 5 and 6 and hence was retained for backward compatibility.
If on the other hand we had the "Retain MBOs" flag set to false, the serialization process would load the first PO, serialize it to the XML stream and then discard it. It will then load child MBOs [POLINE,POCOST and POTERM] in sequence and serialize and discard them [as they get serialized to XML]. Note that the parent MBO is not garbage collected till all its child MBOs are discarded. So in this case the PO MBO will not be removed from memory until all its children have been discarded. This process continues till it's done serializing all the 100 PO's along with all its related objects as defined in MXPO. At no point there will be more than one PO MBO in memory. The total number of MBOs in memory at any point in this step will not exceed the maximum depth of the Object Structure. So for MXPO - the maximum depth is 3 [PO->POLINE->POCOST]. So no matter whether we are exporting 100 PO's having a 2 POLINE's each having 1 POCOST OR 1 PO having 1000 POLINE's each having 1 POCOST, the maximum number of MBOs in memory at a given instant will never exceed 3. This gives a very linear performance graph - no matter how many MBOs are getting exported as part of one request.
However this rule [of "Retain MBOs"] does not apply to MBOs when channel is triggered for an event. In the case of events the MBO is live and even if the channel has "Retain MBOs" flag turned off the MBOs are not discarded. Discarding the live MBOs would potentially create a transaction hazard as the MBO modification/creation transaction has not yet been committed in the database. So "Retain MBOs" flag is overlooked [assumed to be "true"] when the channel is triggered via a MBO event. The same channel when triggered via an export call would use the configured value of the "Retain MBOs" flag to discard or retain MBOs.
Alternatives To Retaining MBOs
Having discussed the perils of setting "Retain MBOs" to be "true," we need to cover alternate ways of getting the same job done while turning that flag off. The difference between setting it true or false is whether the exits/rules have access to the MBOs or not. So lets see how some common tasks can be achieved without using MBOs in the exit/rules layer. So if you do not have any exit/rules that need to access MBOs then you should set that flag to false right away. The discussion below assumes that you had exit code or rules accessing MBOs.
The most common use case for accessing MBOs in the exits/rules is to get more information from related MBOs [which are not part of the Object Structure] into the transformed XML message that will be sent out to the External System. For example say you need to access vendor [COMPANIES] information for the PO in the exits There are couple of ways the same can be achieved without having to access MBOs in the exit/rules layer.
From performance and usability point of view the best alternative would be to have a Object Launch point bound automation script [for the init/add/update event] to set the attribute values from the related MBO [COMPANIES] to the PO. For more on how to do this you might want to read the "Maximo Scripting" blog.
Another alternative would be extend the Object Structure Definition Class [say for the MXPO] and access the COMPANIES MBO from there. An example is shown below:
checkBusinessRules(MBORemote MBO, MosDetailInfo mosDetInfo, Map<String, Object> ovrdColValueMap)
{
if( mosDetInfo.getObjectName().equals("PO") && )
{
if(!mbo.isNull("vendor"))
{
MboRemote companiesMbo = mbo.getMboSet("VENDOR").getMbo(0);
}
else {
return MosConstants.SKIPMBO; }
}
...
...
The negative here is the JAVA code you end up writing for this; but it's efficient and performs great. We hopefully one day will have the rules support in this layer to support a configured logic approach as opposed to raw JAVA code.
Another alternative would be to get the information as part of the serialization process. You can, for example, add the COMPANIES to the object structure as shown in the following diagram.
You can even customize what attributes you need from the COMPANIES to trim [using include/exclude functionality] this structure for your specific use case. Now you can access the vendor information in your exits from the XML element for COMPANIES for your XML transformation. This however would modify your Object Structure, which might not be desirable if you are using this same Object Structure for inbound processing.
Another common usage [of MBOs in exit/rules layer] is in the Publish Channel Integration MBO rules - where the rules use the MBO attribute values or related MBOs/attribute values to determine if the MBO [ie PO for MXPO] xml should be skipped from the XML message. Say you want to skip a PO record processing if there was no associated vendor for the PO. The same can be achieved by extending the Definition Class for the Object Structure [MXPO in this case]. In the code above look at the else block; that is one efficient way to get this done.
So, as it turns out, it's better to use exits for the purpose they are supposed to be used for, that is data transformation, and not for accessing more MBOs [which should be done prior to the exits at the MBO layer or at the definition class object structure XML creation as shown in Step #2].