Running code in an entirely new bundle

Typical Gosu code interacts with database transactions by using the current bundle set up for rules execution, plugin code, or PCF user interface code. In such cases, PolicyCenter automatically manage the low level parts of database transactions. Only in rare cases your code must create or commit a bundle explicitly, such as batch processes, WS-I web service implementation classes, and actions triggered from workflows.

In rare cases, you need to run Gosu code in an entirely new transaction, so you create a new bundle. You might need a new transaction because there is no current bundle or because you need changes in a different transaction from the current transaction.

Create your own bundle only in the following cases:

  • If your code modifies entities to commit independent of the success of the surrounding code. For example, some workflow asynchronous actions or unusual PCF user interface code might need to create a new bundle.
  • If your code represents a separate asynchronous actions from surrounding code.
  • If your Gosu calls Java code that spawns a new thread within the server, such as a timer or scheduled event. It is important that no two threads share a bundle.

To run code within a separate transaction, you must create a Gosu block, which is an in-line function that you define in-line within another function. You can pass a block to other functions to invoke as appropriate.

To create a new bundle, call the static method runWithNewBundle on the gw.transaction.Transaction class. As a method argument, pass a Gosu block that takes one argument, which is a bundle (Bundle). Gosu creates an entirely new bundle just for your code within the block.

The syntax is:

uses gw.transaction.Transaction

...

Transaction.runWithNewBundle( \ bundle -> YOUR_BLOCK_CODE_HERE )

Your Gosu code within the block can add entity instances to the bundle by using the bundle.add(entity) method. Remember to save the return result of the add method.

Gosu immediately runs this code synchronously. If the block succeeds with no exceptions, runWithNewBundle commits the new bundle after your code completes. For the most concise and readable code, Guidewire encourages you to use this automatic commit behavior rather than committing the bundle explicitly.

If your code detects error conditions, throw an exception from the Gosu block. Gosu discards the bundle and does not commit the changes.

The following example demonstrates how to create a new bundle to run code that creates a new entity instance and modifies some fields. The current transaction is an argument to the block.

If you are adding entity instances, in typical code you do not need to use the bundle explicitly. Gosu sets the current bundle inside the block to this new block automatically. You can use the no-argument version of the new operator for entity types, which creates the object in the current bundle:

gw.transaction.Transaction.runWithNewBundle( \b -> {
  var me = new MyEntity()

  me.FirstName = firstName
  me.LastName = lastName
  me.PrimaryAddress = address
  me.EmailAddress1 = email
  me.WorkPhone = workPhone
  me.PrimaryPhone = primaryPhoneType
  me.TaxID = taxId
  me.FaxPhone = faxPhone
} )

If you perform database queries, you can use the bundle reference to add entity instances to the new writable bundle.

Warning: Only commit a bundle if you are sure that it is appropriate for that programming context. Otherwise, you could causes data integrity problems. For example, in Rule sets or PCF code, it is typically dangerous to commit a bundle explicitly, including with this API. Contact Customer Support if you have questions.

Using variable capturing in your block

The following example method from a web service implementation demonstrates how to create a new bundle to call a utility function that does the core part of the work.

...

public function myAction(customerID : String) : void {
  Transaction.runWithNewBundle( \ bundle -> MyClass.doSomething(customerID, bundle))
}

...

This apparently simple block is not self-contained because the code uses customerID, which is the argument to the myAction method and is declared outside the scope of the block. The ability of a block to use variables from its creation context is called variable capturing.

In some cases, you need to return information from your block. You can return information by more advanced use of variable capturing. The following example demonstrates variable capturing by creating a local variable in the outer scope (myAction) and then setting its value from within the block. The outer scope can use that value as a return value from the method.

public function myAction(customerID : String) : boolean {
  var res : boolean

  // The local variable "res" and the parameter "customerID" are captured by the block. 
  // Both variables are shared between the calling function and the block
  Transaction.runWithNewBundle( \ bundle -> { res = MyClass.doSomething(customerID, bundle) })

  // Return the value that was set in the block using the shared (captured) variable
  return res 
}

See also