Object launch point
Object launch point
This launch point lets you invoke scripts for the MBO events, init and save point ones, add, update and delete.
In addition to those events, this launch point also taps into the pre-add or
can add and pre-delete
can delete events which can control whether an MBO can be added or deleted.
A launch point can be configured to listen to one or more of these events at the
same time. The script will have access to the event MBO using the implicit variable
`mbo’, the MboSet as well as all the related MBOs.
To design scripts using Object launch point, start the following Create Scripts with Object Launch Point wizard:
The initialization event based scripts can be used to set calculated fields, set fields as readonly, required, hidden or set conditional defaults to MBO attributes. The save point event-based scripts can be used to implement save point object validations as well as save point actions. The following example will demonstrate an initialization point script and the next one would demonstrate a save point script. Suppose you want to customize the Asset application to display the total spare part quantity in a new non-persistent Asset object attribute called sparepartqty. This boils down to the requirement, whenever an Asset MBO gets initialized the sparepartqty will display the sum of all the spare part quantities associated with that asset. So it is evident that it will be a Object Launch Point for the object Asset and you must attach the script to the initialization event of the Asset object. To do this, you should launch the Create Scripts with Object Launch Point wizard. Once the wizard is launched the first thing you do is to create a launch point as shown in the following screenshot. The “initialize” event is what you want to use for launching this script.
You will need variables for this customization. First, there is a variable called sptqt which binds to the new Asset MBO attribute
sparepartqty. All you must do is set the value of this attribute and therefore this
variable would be of type OUT. Next you should get all the quantities from the
related Sparepart MBOs of the Asset. To do that you use the array variable
* to get an array of quantity values from the related sparepart MboSet.
Consider that the array variable is qtys and its bind value would be
sparepart relation name>.<attribute name>* which is
at the end indicates the array nature of this variable and also instructs
the framework to form the array using the specified relationship.
Array variables are always of type IN and that is perfect for this as you are not modifying the quantities, but you are merely summing that up. So with these basic variables defined you will now attempt to write the following script:
if qtys is not None:sptqt = sum(qtys)
It is a two-line script, which validates if there are in fact sparepart MBOs and if they exist, then sum them up and set it to the sptqt variable. The scripting framework picks that up and sets the value back to the binding of the sptqt or sparepartqty. So the amount of Java coding done here is nothing, because it is a pure jyhton script. Now going by the nature of the calculated fields, the sparepartqty should be always read-only. The script is the best place to set it to read-only, which embodies the Asset initialization event. The following final script adds the code to set the sparepartqty attribute to read-only.
sptqt_readonly=Trueif qtys is not None:sptqt = sum(qtys)
Once you click Create in the last wizard step to create the script, a successful creation of the script and the launch point will generate the following response:
In case of a compilation error you would be forced to stay back on the last page until you cancel or fix this script.
The benefit of the implicit variable concept is that when you bound sptqt to sparepartqty attribute, the scripting framework injected not only the variable sptqt at run time, but also some implicit variables like sptqt_readonly, sptqt_required and sptqt_hidden. Each of these variables are of type boolean and caters to the read-only, required, and hidden flags of the MBO attribute.
Another way to do the same is by leveraging the MBO APIs:
from psdi.mbo import MboConstantsmbo.setValue("sparepartqty",mbo.getMboSet("SPAREPART").sum("quantity"))mbo.setFieldFlag("sparepartqty",MboConstants.READONLY, true)
App Validate event
Leverage this Object launch point to do the validation routines for the full object. Compared to the Attribute launch point “validate” event, which is geared towards individual attribute validations, this point offers the full MBO to validate. The implicit variables available at this script point are identical to the ones available for the save event, which is the “before save” script point. It is recommended to leverage this point for validation compared to the “before save” script point. Often application/framework code will call the MBO validate routine. In such cases, this script point is going to get invoked and the “before save” will not be invoked. So while the before save is good to handle save point actions, validation should ideally be handled in this script point.
Save point validations will help demonstrate more features of this framework.
The use case here is a need to customize the Asset MBO to enforce a naming convention for assets [assetnum] based on their types [assettype]. This effectively boils down to the requirement that whenever we are creating Assets we have to follow a naming convention for the assetnum. The key words here are in blocks which help us identify the launch point type and the event point in that type. It is an object launch point for the Asset MBOs add event. So you should use the Object Launch point wizard to create and deploy this custom logic. To start with You must figure out the variables and their bindings. From the requirement it is clear that you require the two input values from the assetnum and assettype. So there are Two IN variables called anum and atype which are bound to those attributes respectively. Those are the only two variables that youneed to do this task. The following script code [in Jython] is a demonstration::
if atype_internal=='FACILITIES' and not anum.startswith('FT'):service.error('asset','invalidassetprefix',['FT'])elif atype_internal=='FLEET' and not anum.startswith('FL'):service.error('asset','invalidassetprefix',['FL'])elif atype_internal=='IT' and not anum.startswith('IT'):service.error('asset','invalidassetprefix',['IT'])elif atype_internal=='PRODUCTION' and not anum.startswith('PR'):service.error('asset','invalidassetprefix',['PR'])
This could also be achieved without defining those variables and just using the implicit variable
mbo and leveraging the Maximo SDK for internal values in the following way:
from psdi.server import MXServeratypeinternal = MXServer.getMXServer().getMaximoDD().getTranslator().toInternalString('ASSETTYPE', mbo.getString('assettype'));anum=mbo.getString('assetnum')
The scripting framework is used to support another way to throw errors by setting the implicit variables
params. This way has been deprecated as it was not real-time. When the script code is executing the exception would be thrown only
after the script code has completed execution. At the end of the script execution, the framework would detect that an error flag is set and it will throw the
corresponding Maximo exception for that error group or key combination. So you should consider the fact that even after setting the error flags in the script, the
script execution will continue, unless you have adequate checks in your script code to bypass that code, if the error flag is set.
This is not the recommended approach and instead you should use the real-time error approach.
Another way to throw error would have been to use the following MXException API directly:
from psdi.util import MXApplicationExceptionif <some condition>:params = [prefix,assettype]raise MXApplicationException('asset','invalidassetprefix', params)
As before the scripting framework takes care of all the plumbing behind the scenes. Once you are done submitting your script using the wizard you can come to the Asset app and try to save a test asset. You should see that your validation routine gets executed immediately without restarting, rebuilding, or redeploying.
This is similar to the “on add” with all the implicit variables remaining the same. Use this to customize the business logic for MBO updates.
This is similar to the “on add” with all the implicit variables remaining the same. Use this to customize the business logic for MBO updates. On Delete should be leveraged to customize business logic when an MBO delete happens and not to prevent or allow an MBO delete. You should leverage the “can delete” event for that.
Before Save, After Save and After Commit Event in Object Launch Point
Scripting in Maximo 7.5 supported only the “Before Save” events in the Object launch point. Although that is the most common place for customizations, it may be necessary to attach some customizations at the after save and after commit events, mostly when you are doing some actions that need to be done after the MBO has been saved or committed. After save is the phase when the MBO’s sql insert, update, or delete statement has been triggered, but the commit has not happened. The commit stage happens, when the MBO in the transaction has been committed or the database commit has been successfully executed. After save events are good for writing to an external storage. For example, Maximo Integration Events are processed at the after save event. In this phase if the write fails, you can always roll back the MBO transaction. Also at this stage, all MBO validations have passed and hence the chances of failure due to Maximo business logic failure is very low.
After commit events are good for actions that require your Maximo data to be committed. For example, you may want to send an SMS only when an Asset has been reported “BROKEN”. You can access the “mbo” variable at all of the script points here.
Can Add Event
You can control whether you can add an MBO using scripting Object Launch point “Allow Object Creation”. “Allow Object Creation” is an Object Launch point where you can control whether you can add a new MBO, given the current state of the system. This point pairs up with the canAdd callback in the MboSet framework.
If you want to validate that a POLINE can be added to a PO only when the PO has the vendor information set, use the following script code:
if mboset.getOwner() is not None and mboset.getOwner().getName()=="PO" and mboset.getOwner().isNull("vendor"):service.error("po","novendor_noline")
There is no implicit variable called “mbo” as the launch point is invoked before the MBO is created. At that point all you have is the MboSet (implicit variable “mboset”) for the POLINE. If you are wondering why this cannot be done using the init Object launch point, the answer is that it is too late. At this point, the MBO has already been created and added to the set. Rejecting it at this point will not be helpful. Also, the usage of the global “service” variable to throw the error in real time effectively replaces setting the errorgrp and errorkey variables to throw error.
Can Delete Event
Similar to the “Can Add”, this Object Launch Point helps validate whether an MBO can be deleted or not. Going with the POLINE object, for example, you want to enforce a validation that the line should not be deleted, if the PO is of priority 1, you can use the following code:
if mbo.getOwner() is not None and mbo.getOwner().getName()=="PO" and !mbo.getOwner().isNull("priority") and and mbo.getOwner().getInt("priority")==1:service.error("po","nolinedelete_forpriority1")
In this case, the MBO, which we are trying to validate for deletion is already there, and hence we can leverage the implicit variable MBO to do the validation.
Adding validation to the virtual (aka Nonpersistent) MBOs (on execute)
In this sample you are going use the change status dialog from the Asset Application to validate if the memo is filled in when the Asset status is set to BROKEN.
You will write an Object launch point script, MEMOREQD, which will validate that a memo is required for status BROKEN, on clicking OK. The event will be “save/add”. This will map to the “execute” call back for Nonpersistent MBOs. The object name would be ASCHANGESTATUS. The following sample uses Python.
if mboset.getMbo(0).getString("status")=="BROKEN" and mboset.getMbo(0).isNull("pluscmemo"):service.error("memo","reqd")
mboset variable is leveraged to get the current MBO at 0 index. Now you can
try the change status dialog to see if it throws the memo#reqd error when you do not specify the
“memo” for BROKEN.
Adding setup logic for virtual (aka Nonpersistent) MBOs (on setup)
Non-persistent MBOSETS will get a callback from the Maximo framework for loading the MBOs from whatever data source the application programmer planned on using to load the data for this MBOSET. There is a script point to handle this very use case.
The Object “init” launch point event for non-persistent objects would provide two callbacks. The first callback would be for this “setup” event.
The script developer can check for the
onsetup implicit variable (boolean). For setup events, this variable will be set to true. The script can then use the
mboset variable to fill it up with MBOs. The script point executes after the MBOSETS default setup has been called. There is no script point for a “before setup” event.
if onsetup:mbo = mboset.add()mbo.setValue("attr1","value1")mbo.setValue("attr2","value2")
The example shows how the “setup” event is leveraged to set up the non-persistent MBO. You can use a loop to setup the set with multiple MBO records too.
setup callback is not turned on by default, for backward compatibility. To turn it on, set the Maximo property
mxe.script.callsetuponinit to 1.
Since the script cache must get refreshed for this property change to take effect, it is recommended to bounce the Maximo server instances for this or refresh the script cache by modifying the script. For example, you can update the description of the script.