MBOs in Automation Scripts: Update Attributes of an Mbo

In our previous posts in this series, we talked about how an MboSet is a collection of Mbo objects. This is analogous to a spreadsheet of data representing an MboSet, and a single row within that spreadsheet representing an Mbo. This article will discuss how to update single attributes on an Mbo, or in our spreadsheet analogy, update data within a single cell within a row.

To modify an object in the collection, the object must first be found. Most of the time, the launch points in automation scripts will supply an implicit variable called mbo that refers to the current record. Alternatively, you can get a handle to an Mbo from an MboSet as described in previous articles of this series – remember the setWhere() and moveFirst() methods. Once you have an Mbo, changes are made using the setValue() method. As is the case with other methods, setValue() is a member of both the Mbo and MboSet classes.

Our first example changes the description of the current Mbo (a work order) by calling the mbo variable’s version of the setValue() method.

mbo.setValue("DESCRIPTION", "Changed the description")

In the setValue() method, passing the second argument as a string works for all attributes, regardless of their underlying data types. For example, if an attribute is a numeric type, passing the string “1” is allowed. There are also setValue() method calls that take the long, int, Date, boolean, float, or double data types as the second argument.

This call will throw an exception if the underlying data type does not match the type of the value passed in the call. For example the following code does not work.

mbo.setValue("description", 1.0)

A call to set the value of a particular attribute may result in the values of other attributes changing. For example, setting the “assetnum” attribute of a work order may result in the “location” attribute being updated as well. To check the new value, getString() could be used on the “location” attribute.

Once all values have been modified, the save() method can then be called.

mbo.getThisMboSet().save()

This saves and commits all changes to the database. In most cases, an explicit call to save() is not necessary. In cases where the automation script fires before the save event, the save event will trigger automatically after the execution of the script.

If there is an error during the save, an exception is thrown and the changes are not saved. In that case, the collection is left in exactly the same state as prior to the save() call. This allows appropriate action to be taken and the save() call to be resubmitted.

There is a third argument that can be passed to the setValue() method, which is the Access Modifier. This should only be used when you are certain of the implications of using it. In essence, standard application logic can be bypassed by using access modifiers, which is why they should be used only when necessary. Standard access modifiers are:

  1. NOACCESSCHECK: Suppresses the “Field is Read Only” message and performs the update regardless of whether the field is editable or not.
  2. NOVALIDATION: Update the field without validating the data being entered.
  3. NOACTION: Do not perform related system actions when updating. For example, do not update the location on a work order when updating the asset.

These access modifiers can be used on an update by themselves or combined together. For example, to update a field even though Maximo has the field marked as read only:

mbo.setValue("DESCRIPTION", "Update a read only field", mbo.NOACCESSCHECK)

To update a field and not perform the validation and action events:

mbo.setValue("DESCRIPTION", "Update a field without validation or action", mbo.NOVALIDATION|mbo.NOACTION)

Putting all three together:

mbo.setValue("DESCRIPTION", "Please be careful doing this", mbo.NOACCESSCHECK|mbo.NOVALIDATION|mbo.NOACTION)

A list of attributes whose values may be modified and the objects to which they belong can be found in the MAXATTRIBUTE table in the MAXIMO database. The OBJECTNAME column of this table corresponds to the object name. The ATTRIBUTENAME column corresponds to the attribute name.

Our next article will focus on how to add new Mbo records into an MboSet.

Auto-Generating DBC Files

In the ongoing effort to use cool and interesting tools for application and database updating it has been very nice to see the geninsertdbc.bat tool put into practical use. Harnessing these tools to create DBC files can be very advantageous if you are still getting all the available commands and syntax down to master them. So, let’s look at a scenario where I needed to update a Maximo automation script.

The required solution is to update a pre-existing automation script with new code for the source field in the autoscript table as well as update the scriptlanguage field. The caveat is that the script language (python) requires proper formatting to execute correctly. In the first attempt I tried to update the automation script via a freeform insert in the DBC’s statements section using SQL line breaks and indentation syntax.

 

While this did achieve the outward appearance that I wanted Maximo was not “sold” on the line spacing and indentation of the ( CHAR(13) or CHAR(9) ) SQL syntax and the automation script would not run after the server(s) were restarted.

Now, to get to the fun part. An alternate method was suggested on how to get this information into Maximo via the geninsertdbc.bat tool. IBM has tools available that can auto generate DBC files based on parameters that you give the output tool at the command prompt. I reset the automation script’s source code with the python source code that was previously working, and I opened an administrative command prompt then navigated to the ..\maximo\tools\maximo\internal directory under the Maximo installation folders.

I ran the following command: C:\IBM\SMP\maximo\tools\maximo\internal>geninsertdbc.bat -tautoscript -w"autoscript = 'ITEMDELETION'" -ftest2 -ca3jgroup

To break this down lets look at the parameters given for the command.

-t: will pull from the table

-w: will specify a where clause

-f: will name the output file

-c: will point the file to a directory of your choosing

 

After the geninsertdbc.bat tool is run there will be an output file created which will look similar to this.

In this file we have the column information extracted from the database and formatted in the XML layout of a DBC file ready to be either edited or re-added to Maximo via the runscriptfile.bat command. What I was able to use from this file was the character string that the geninsertdbc.bat placed around the source string (
) which is the character string that allows for spacing and line breaks while inserting into databases via the DBC file method.

I then took this info and created a DBC file that would update as opposed to insert into the database. The source COLUMNVALUE took some effort to get the correct spacing and breaks in place, but when you run the script and restart the server(s) your automation script will run without any further efforts.

This really is just a scratch of the surface of what you can do with auto generating DBC files. Further uses can only truly be explored/acknowledged by trying this method on other tables to see the results that may come from it and applying the built-in functionality detailed in files like the script.dtd file for manipulating the data to be added/changed.

An outstanding source for learning about DBC files is located on this IBM Developer Works page. I encourage anyone interested in this to go through this content and then try to apply it to your day to day tasks.

MBOs in Automation Scripts: Reading Multiple Attributes of an MboSet

In our previous posts in this series, we talked about how an MboSet is a collection of Mbo objects. This is analogous to a spreadsheet of data representing an MboSet, and a single row within that spreadsheet representing an Mbo. This article will discuss how to read multiple attributes from an Mbo, or in our spreadsheet analogy, look at data within multiple cells within a single row.

Because most of the objects in Maximo possess many attributes, a long series of getString() method calls might be required to retrieve all the necessary information in a given situation. To make such retrieval more convenient, a method called getMboValueData() has been provided. It allows the programmer to fetch many data items in a single operation by specifying a list of attributes and, if desired, a set of rows in the collection. The result of such a call is a one- or two-dimensional array of MboValueData objects. Another advantage of this approach is that it speeds up processing over a network. When a number of data items are retrieved in a single call over a network rather than many, the efficiency advantages are self-evident.

The getMboValueData() method is available in several versions; as with many other methods it is a member of both the MboSet and the Mbo classes. The general syntax of the most-used version is as follows:

valueDataList = mbo.getThisMboSet().getMboValueData(attributes[])

or

valueDataList = mbo.getMboValueData(attributes[])

The attributes variable above is an array of strings containing a list of attribute names (e.g. “wonum”, “description”, “assetnum”, or “asset.description”). The “asset.description” attribute is an example of “dot notation” using Maximo relationships (more on relationships in a subsequent article). Dot notation is a shortcut that allows you to retrieve data from a related object without accessing the related object itself. For example, if a Work Order object has a value entered in its “assetnum” attribute, passing “asset.description” to either getString() or getMboValueData() will fetch the specified Asset’s description. Thus, by combining dot notation with getMboValueData(), data can be simultaneously retrieved in one method call even from objects that are in different Maximo Business Objects. This is an important part of the convenience that using getMboValueData() confers.

The return from the getMboValueData() method is an array of MboValueData objects. Each one contains the value of the attribute specified in the corresponding position in the attributes parameter. There are several methods which allow retrieval of this data value; the most often used, getData(), returns the data as a string. Not only can the data value be recovered; there are also methods which return information about the attribute itself, such as its maximum length, whether it is read-only, etc. This additional information is very useful in many situations.

A code sample follows:

attributeList = [ "wonum", "description", "assetnum", "asset.description" ]
// Assume the mbo is a Work Order and that the Work Order object has an Asset associated with it.
valueData = mbo.getMboValueData(attributeList);
print "The description of Work Order " + valueData[0].getData() + " is " + valueData[1].getData()
print "The Asset associated with Work Order " + valueData[0].getData() + " has identifier " + valueData[2].getData() + " and description " + valueData[3].getData()

If any of the attributes specified in the array of attribute names (attributeList in the above example) does not exist, a null value is placed in the corresponding position of the returned array. Similarly, if any of the dot notation entries in the list refer to nonexistent related objects, nulls are returned in those positions as well. In the above example, if the mbo variable has no value specified in its “assetnum” attribute, then null would be returned in the position where “asset.description” is entered in attributeList.

There are two other versions of the getMboValueData() method. One is a special case of the version described above. The syntax is:

valueData = mbo.getThisMboSet().getMboValueData(attribute)

or

valueData = mbo.getMboValueData(attribute)

The argument is a string which is a single attribute name and the return is a single MboValueData object. As above, this method is a member of both the MboSet and Mbo classes. Even though it returns less data than the more general versions, it may still be preferable in certain situations. For example, if the desired result is information about a single attribute (e.g. read-only, length, etc.) of some object, then it is sufficient to apply this method to that single attribute rather than many.

The remaining version is more general in nature. This is a member of only the MboSet class and allows the retrieval of data not only for multiple attributes but for multiple objects as well. It is used when many objects are to be processed at once, such as during the generation of a report or the filling of a table. The syntax is:

valueDataList = mbo.getThisMboSet().getMboValueData(firstRow, rowCount, attributes[])

The firstRow and rowCount variables are integer arguments; they specify the first row and the number of rows in the row set to be retrieved, respectively. The most commonly used values are 0 and mbo.getThisMboSet().count(), which fetch data for the entire collection.

The attributes variable is an array of strings containing a list of attribute names, as above. The return is a two-dimensional array of MboValueData objects. A code sample follows.

attributeList[] = [ "wonum", "description", "statusdate" ]
// Assume the woSet collection is non-empty
woCount = mbo.getThisMboSet().count()
valueData = mbo.getThisMboSet().getMboValueData(0, woCount, attributeList)
for i in range(len(valueData)):
    print "The description of Work Order " + valueData[i][0].getData() + " is " + valueData[i][1].getData()
    print "The Status Date of Work Order " + valueData[i][0].getData() + " is " + valueData[i][2].getData()
}

That’s it for now. Our next article will focus on how to modify attribute values of an Mbo in an MboSet.

MBOs in Automation Scripts: Reading Single Attributes of an MboSet

In our last post in this series, we talked about how an MboSet is a collection of Mbo objects. This is analogous to a spreadsheet of data representing an MboSet, and a single row within that spreadsheet representing an Mbo. This article will discuss how to read single attributes from an Mbo, or in our spreadsheet analogy, look at data within a single cell within a row.

Once an MboSet has been fetched, data associated with the individual objects it contains can be extracted. Attributes that are associated with character data types, such as ALN, UPPER, and LOWER, can be retrieved by using the getString() method.

The getString() method is a member of both the Mbo and MboSet classes. The Mbo version fetches data from the Mbo object itself; the MboSet version fetches data from the current member of the MboSet.

For example, here moveFirst() is called to set the current member pointer to the first object in the woSet collection. Since woSet was newly restricted from a new setWhere() call, moveFirst() also triggers the retrieval of the record from the server. The getString() method of the woSet object is called and the value of the description attribute of the current member is retrieved.

woSet = mbo.getThisMboSet()
woSet.setWhere("wonum='1100'")
woSet.moveFirst()
woDesc = woSet.getString("DESCRIPTION")

In the next example the moveFirst() call, in addition to the above functions, also returns the work order object which is the new current member of woSet. The getString() method is called through the object wo and the value of the description attribute is retrieved.

woSet = mbo.getThisMboSet()
woSet.setWhere("wonum='1100'")
wo = woSet.moveFirst()
woDesc = wo.getString("DESCRIPTION")

Next, moveFirst() is called to make the first object the current member. A reference to that member is then retrieved by a getMbo() call. The getString() method is then called as before.

woSet = mbo.getThisMboSet()
woSet.setWhere("wonum='1100'")
woSet.moveFirst()
wo = woSet.getMbo()
woDesc = wo.getString("DESCRIPTION")

Note that the result is the same in each of these three examples. Which combination of calls should be used to reach the result depends entirely on what is most convenient in a given situation.

The getString() method may be used on all attributes regardless of their data types.

There are also getDate(), getInt(), getLong(), getByte(), getBoolean(), getFloat() and getDouble() methods, which return the value of an attribute as something other than a string. An attempt to use these methods on an underlying attribute not of the correct type results in an exception being thrown. For example the following does not work because the attribute is not of type DATE or DATETIME.

woDate = woSet.getDate("DESCRIPTION")

A list of the attributes whose values may be retrieved and the objects to which they belong is listed in the MAXATTRIBUTE table in the Maximo database. The OBJECTNAME column of this table corresponds to the table name, while the ATTRIBUTENAME column corresponds to the column name.

For a complete description of all methods available, refer to the Mbo and MboSet JavaDocs on the IBM Asset Management Developer Center.

Our next article will focus on reading multiple attributes from the current record in an MboSet.