Using the List set() Method

It is important to note that the List set() method cannot be used for adding new items to a list, for example, if you have an empty list, you cannot add two elements like this:

bike.widgets.set(0, widgetA);	// This is wrong!
bike.widgets.set(1, widgetB); 	// This is wrong!

The reason this is wrong is that the set() method is for updating existing entries. The above will fail because the list is empty. Instead, the add() method must be used for adding new entries into a list. Existing entries can be directly updated, so set() may not even be needed:

var widget = bike.widgets.get(0);
widget.description = “Widget A”;

Removing an Item from a List or a Containment Relationship

In order to remove an item from a containment relationship or a list, the remove() method should be used. It can be used with the object to be removed, or the index of the object to be removed:

//Remove an object from a collection
order.orderlines.remove(orderline1);

or:

order.orderlines.remove(0);

Be careful using the first example above. The Business Object, or other value passed, must be the same Business Object instance that is in the list, and not a copy of it. This method checks to see if it is the same object that was added. It does not compare the contents of the objects.

If you don’t know which item you want to remove, you should use the Iterator’s remove method. To remove an item from a list means iterating through the list to find the item and then deleting it. This is done using the list iterator as we have done before:

// Iterate through the list of customers removing customers with large credit
// limit
for (var iterator=custlist.listIterator(); iterator.hasNext(); )
{
     var customer = iterator.next();
     // check if credit limit above 1,000,000	
     if (customer.creditLimit >= 1000000)
     {
        iterator.remove();
     }
}

Alternatively this can be done just using the methods on the List object:

// Iterate through the list of customers removing customers with large credit
// limit
for (var ix=0; ix < custlist.size(); ix++)
{
     var customer = custlist.get(ix);
     // check if credit limit above 1,000,000	
     if (customer.creditLimit >= 1000000)
     {
         custlist.remove(ix);
         ix--;  // decrement index so next iteration check the new nth item
      }
}

If the list index is managed in the script, as in the second example, you have to be careful not to skip past elements after an element that is remove by only incrementing the index if the item is not removed! So using the iterator is easier.

There is also a clear() method on Lists that can be used to remove all entries in the list, for example:

bike.widgets.clear();
custList.clear();

Scripting on Business Objects That Use Inheritance

Using BOM Editor, you can define BOM classes that inherit attributes from other classes. Another way of expressing this is to say that you can create BOM classes that specialize other classes.

An example of this is shown in the screenshot below:

In this example, there is a general Product type, and then there are two different types of Products:

  • Book, which additionally have an isbn attribute
  • Electrical, which additionally have a serialNumber attribute.

If we had a Process Data Field called orderline of type Orderline, then the containment of type Product, can be assigned Business Objects of type Product, Book, or Electrical:

var book = com_example_spec3_Factory.createBook();
orderline.product = book;	  // Set the product attribute to a Book
                           // Business Object
var elec = com_example_spec3_Factory.createElectrical();
orderline.product = elec;  // Set the product attribute to an
                           // Electrical Business Object
var prod = com_example_spec3_Factory.createProduct();
orderline.product = prod;  // Set the product attribute to a
                           // Product Business Object

Similarly, if we have a Process Data Field called productCatalog of type ProductCatalog, the products containment can contain many Product Business Objects, some of these which can Book Business Objects, some Electrical Business Objects, and some may just be Product Business Objects. For example, you can add all three types to the products list, as shown here:

var book = com_example_spec3_Factory.createBook();
var elec = com_example_spec3_Factory.createElectrical();
var prod = com_example_spec3_Factory.createProduct();
productCatalog.products.add(book);
productCatalog.products.add(elec);
productCatalog.products.add(prod);

If a Process Data Field productCatalog of type ProductCatalog type appears on a Form in a UserTask, it will just show the Product details. You will not be able to access the attributes of the Book or Electrical classes, however, it does allow you to add new instances of Book, Electrical, or the base type Product.

Similarly, in scripts, if you iterate through the products List, the Script Editor just gives you the content assist for the Product object. You will get an error if you attempt to access the isbn attribute of a Product Business Object, as shown below:

The above code sample shows an attempt to create a List of Text that contains the ISBN number of the Product instances that are Book subtype Book instances.

To get around this problem, we can create a variable called book, which we initialize to an object of type Book. Then we assign the Product Business Object to the book variable, after which TIBCO Business Studio allows access to the attributes of the Book class. However, a warning is given that the assignment may not work at runtime:

bookList = com_example_spec3_Factory.createISBNList();
for (var iter = productCatalog.products.listIterator(); iter.hasNext(); )
{
     var product = iter.next();
     if (ProductType.BOOK == product.type)
     {
         var book = com_example_spec3_Factory.createBook();
         book = product;	
         bookList.isbns.add(book.isbn);
     }
}

The TIBCO Business Studio Script Editor gives a warning about the assignment of a field that it thinks contains a Product to a field that it treats as holding a Book. However we know, from the test that we conducted previously, that in this case it is safe:

If we do not have the above check, then the above code can fail at runtime when attempting to access the isbn attribute if the product (and hence the book) was referring to a Product or an Electrical Business Object as these do not have the isbn attribute.

It is always OK to assign a sub-type (specialized type) object to a supertype (generalized) attribute or variable because you can say that the sub-type object satisfies the "is-a" relationship. In our example, Book "is-a" Product.

However, it is not always OK to do things the other way around. Assigning an attribute or process data field that is a Book type, from a variable or attribute of a Product type, will only work at runtime if the Product actually refers to an instance of the Book class (or a sub-type). If the Product field or attribute actually refers to a Product or Electrical Business Object, then it does not satisfy the "is-a" Book condition. The assignment will fail when the value is saved at the end of the task.

If, instead of building up a list of ISBN Text values, we wanted to create a List of Products that were also Books and, if the bookList is a Book type Process Data field, then we can write:

bookList = com_example_spec3_Factory.createBookList();
for (var iter = order.products.listIterator(); iter.hasNext(); )
{
    var product = iter.next();
    if (ProductType.BOOK == product.type)
    {
       bookList.add(product);
    }
}

However, if the booklist refers to a BookList type Business Object with an attribute or composition relationship called Books, then instead of writing:

bookList = com_example_spec3_Factory.createBookList();
for (var iter = order.products.listIterator(); iter.hasNext(); )
{
     var product = iter.next();
     if (ProductType.BOOK == product.type)
     {
         bookList.books.add(product);	// THIS IS WRONG
     }
}

We should write:

bookList = com_example_spec3_Factory.createBookList();
for (var iter = order.products.listIterator(); iter.hasNext(); )
{
     var product = iter.next();
     if (ProductType.BOOK == product.type)
     {
        bookList.books.add(ScriptUtil.copy(product));
     }
}

Otherwise, we are moving the Book Product out of the containment relationship with the order and products into the relationship with booklist/books. Remember that a contained Business Object can only be in one container at a time. To stop this from happening, you must make a copy of the object, and add that to the booklist/books containment relationship.

Working with Strings or Text Fields

String values can easily be assigned using either single or double quotation marks. However, they must be of the same type.

For example:

var firstString = "Hello World!";         // quoted using double quote character
var nextString = 'Hello Fred!';	           // quoted using single quote character
var thirdString = "Fred's World";         // includes single quote so used double
                                          // quote
var fourthString = ' "The Old House" ';   // includes double quote so used
                                          // single quote
var fifthString = "Fred's \"Old\" House"; // string includes both so need \
                                          // character to escape use of quote in
                                          // string

String values can be compared with the "==" operator, for example:

if (firstString == nextString)
{
    // do something
}
else
{
    // do something else
}

There are a number of methods on the String class that can be used to manipulate the value of the String object, for example, considering the following String variable:

var str = "Hello TIBCO!";

The following operations can be done on the String.

String Operations
Expression Result Comment
str.length
12 Returns length of string
str.substr(0,5)
Hello Return substring starting at offset 0, 5 characters long
str.substr(6)
TIBCO! Return substring starting at 6th position in string
str.slice(6,9)
TIB Returns substring starting at offset 6 and finishing before offset 9
str.slice(-6).toLowerCase();
tibco! Returns substring starting 6 characters from end of String and changes all letters to lowercase
str.slice(0, str.indexOf(" ")))
Hello Returns first word in string, or whole string if one word
str.slice(str.lastIndexOf(" ")+1)
TIBCO! Returns last word in String, or whole string if one word

For more information about String class methods, see Text (String) Methods.

Note: The String objects are immutable, so when one of the above functions returns a String value, it is a reference to a new String. The original String is not changed.

If you want to restrict what Strings can be put into certain Text fields, consider using the User-defined Types described in Working with Primitive Types.

Working with Booleans

Boolean fields can be simply assigned from constants, other Boolean fields, or expressions.

For example:

customer.initialized    = true;
customer.isOnCreditHold = false;
customer.staffDiscount  = memberOfStaff;
customer.isWholesale    = ! isRetailCustomer;

The exclamation mark "!" is the "not" operator, changing the sense of a true value to false, and a false value to true.

When attempting to convert a text field value to a Boolean (for example, from "true" to true), the ScriptUtil.createBoolean() method should be used. If the text field is not exactly true or false, attempting to assign a text field to a Boolean will generate an exception. Using the createBoolean() method if the value of the Text field is TRUE (in any case), then the Boolean result is true, otherwise it is false.

Similarly, if you want to convert a numeric value (0 or 1) to a Boolean, then the ScriptUtil.createBoolean() method should be used. For example:

Customer.isTrade = ScriptUtil.createBoolean(isTradeParameter);

can be used to convert from a text (true/false) or numeric (1/0) Boolean representation to the Boolean type. Values greater than or equal to 1 get converted to true, and values less than or equal to 0 get converted to false.

Boolean values can be compared with the "==" and "!=" operators, for example:

if (cust1.isWholesale == cust2.isWholesale)
{
   …

Boolean values can also be combined with the following logical operators.

Operators that can be used with Boolean Values
Operator Description Example
&& And – both are true cust.isWholesale && order.discountApplied
|| Or – either is true cust.isWholesale || order.discountApplied
! Not – reverses result !( cust.isWholesale && order.discountApplied)