Server Scripts

Application Composer supports Groovy as the scripting language that you use to enhance your applications. There are many different contexts in which you can use Groovy scripts.

This topic illustrates the use of validation rules, triggers, and object functions, which you can define using the Server Scripts node for any standard or custom object. For a more detailed explanation of Groovy scripting using Application Composer, see the Groovy Scripting Reference guide.

The server scripts that you can define for any standard or custom object include the following:

  • Validation rules

    Write a script to validate either a field or an object.

  • Triggers

    Write trigger scripts to automatically execute an action whenever a specific trigger event occurs.

  • Object functions

    Write a function that can be reused in multiple contexts. For example, you can reuse an object function inside a trigger or validation rule.

Tip: Server scripts are executed synchronously, which could potentially impact performance if the scripts are long-running or performance-intensive. Before implementing such logic, always consider whether the same logic can be executed in an asynchronous way. For example, you can instead use an object workflow with a Groovy Script action.

Validation Rules

Validation rules are constraints that you can define on either a field or on an object. Write an expression or a longer script to validate a field or object before it can be saved. Define validation rules using the Server Scripts node for any standard or custom object.

  • If your requirement involves a single field, use field-level validation.

    A field-level validation rule is a constraint you can define on any standard or custom field. The rule is evaluated at runtime whenever the corresponding field's value is set and the user tabs out of the field. When the rule executes, the field's value hasn't been assigned yet and your rule acts as a gatekeeper until its successful assignment. Covering the validation logic at the field level reduces overhead of Groovy executions when saving. Use this option whenever possible.

    Note: Dynamic choice lists don't support field-level validation rules.

    For example, consider a custom TroubleTicket object with a Priority field. You can set a field-level validation rule to validate that the number entered is between 1 and 5.

    The expression (or longer script) you write must return a Boolean value that indicates whether the value is valid.

    • If the rule returns true, then the field assignment will succeed so long as all other field-level rules on the same field also return true.

    • If the rule returns false, then this prevents the field assignment from occurring. Also, the invalid field is visually highlighted in the UI, and the configured error message is displayed to the end user. Because the assignment fails in this situation, the field retains its current value (possibly null, if the value was null before). However, the UI component in the web page allows the users to see and correct their invalid entry to try again.

    See "Defining a Field-Level Validation Rule" in the Groovy Scripting Reference guide.

  • When validation is needed across multiple related fields in an object, use object-level validation rules. This is a constraint you can define on any standard or custom object.

    Use object-level rules to enforce conditions that depend on two or more fields in the object. This ensures that regardless of the order in which the user assigns the values, the rule will be consistently enforced. The rule is evaluated whenever the framework attempts to validate the object. This validation can occur, for example, when submitting changes in a Web form, when navigating from one row to another, as well as when changes to an object are saved. (Rules aren't evaluated if the user saves a record without making changes.)

    For example, consider a TroubleTicket object with Priority and AssignedTo fields, where the latter is a dynamic choice list field referencing Contact objects whose Type field is a Staff Member. You can set an object-level validation rule to validate that a trouble ticket of priority 1 or 2 can't be saved without being assigned to a staff member.

    The expression (or longer script) you write must return a Boolean value that indicates whether the object is valid:

    • If the rule returns true, then the object validation will succeed so long as all other object-level rules on the same object return true.

    • If the rule returns false, then this result prevents the object from being saved, and the configured error message is displayed to the end user.

    See "Defining an Object-Level Validation Rule" in the Groovy Scripting Reference guide.

Note: When defining a validation rule, don't implement business logic other than:

Triggers

Triggers are scripts that you can write to complement the default processing logic for a standard or custom object. When a specific event occurs, triggers automatically execute an action that you specify in the trigger definition. You can define triggers both at the object level and at the field level using the Server Scripts node for any standard or custom object. Define object triggers to extend standard processing logic, such as record creation, updates, and deletions.

When you define a trigger, you select the specific event that causes your script to automatically run. This specific event is also referred to as a trigger. Oracle supplies a set number of these trigger events that you can pick from when defining your trigger "scripts."

Choose the correct triggering point when defining your trigger:

  • Field-level triggers are scripts that you write to execute an action in response to a change in another field's value. When you define a trigger at the field level, you select the After Field Changed trigger and the field that this trigger is watching. You then define the action that you want to happen when the field's value changes.

    The After Field Changed trigger calculates other derived field values when the value of the field that you specify changes. Don't use a field-level validation rule to achieve this purpose because while your field-level validation rule may succeed, other field-level validation rules may fail and stop the field's value from actually being changed. Generally, because you want your field-change derivation logic to run only when the field's value changes, the After Field Changed trigger guarantees that you get this behavior.

    See "Defining a Field-Level Trigger to React to Value Changes" in the Groovy Scripting Reference guide.

  • Similarly, object-level triggers are scripts that execute an action when a specific event occurs. In the case of object-level triggers, you have many more trigger "events" to pick from, such as:

    • After Create

      Fires when a new object record is created. Commonly used to set default values for fields.

    • Before Invalidate

      Fires on the parent object when one of its child object records is created, updated, or deleted. For building in relationship logic.

    • Before Remove

      Fires when an attempt is made to delete an object record. Can be used to create conditions that prevent deletes.

    • Before Insert in Database

      Fires before a new object is inserted into the database. Can be used to ensure a dependent record exists or check for duplicates.

    • Before Update in Database

      Fires before an existing object is modified in the database. Could be used to check dependent record values.

    • Before Delete in Database

      Fires before an existing object is deleted from the database. Could be used to check dependent record values.

    • Before Rollback in Database

    • After Changes Posted to Database

      Fires after all changes have been posted to the database, but before they're permanently committed. Could be used to make additional changes that will be saved as part of the current transaction.

    For example, consider a Contact object with an OpenTroubleTickets field that needs to be updated any time a trouble ticket is created. You can create a trigger on the TroubleTicket object using the After Changes Posted to the Database trigger event. When an event occurs, your trigger can automatically update the OpenTroubleTickets field with a new count.

    For a complete list of the trigger "events" that you can pick from, see "Defining an Object-Level Trigger to Complement Default Processing" in the Groovy Scripting Reference guide.

For optimal performance, follow these guidelines when using triggers:

  • Don't exceed 10 triggers per object.

  • Combine logically-related actions inside a single trigger. A single trigger produces better performance than multiple triggers.

  • When defining a trigger, choose the correct triggering point.

  • Avoid using validation logic inside triggers. Instead, use validation rules for any validation logic.

  • Before using the newView() API, check to see if related objects or related collection accessors already exist.

    If a relationship already exists, then don't use newView() to query an object. This avoids the firing of additional queries.

  • When querying objects programmatically, select an efficient view criteria so that the underlying query is limited.

Object Functions and Global Functions

You can write reusable code as either an object function or global function. Use a function if you anticipate calling the same code from multiple different contexts. Object functions can be called by any script in the same object, or even triggered by a button in the user interface. Global functions can be called from scripts in any object or from other global functions.

  • Object functions are useful for code that encapsulates business logic specific to a given object. You can call object functions by name from any other script related to the same object. In addition, you can call them using a button or link in the user interface.

    The supported return types and optional parameter types are the same as for global functions. For a list of the most common types for function return values and parameters, see "Defining Utility Code in a Global Function" in the Groovy Scripting Reference guide.

    See also "Defining Reusable Behavior with an Object Function" in the Groovy Scripting Reference guide.

  • Global functions are useful for code that multiple objects want to share. Write user-defined functions using Groovy scripts, which can be referenced in all Groovy script editors throughout Application Composer. For example, you could create two global functions to define standard helper routines to log the start of a block of Groovy script and to log a diagnostic message.

    To call a global function, preface the function name with the adf.util. prefix. When defining a function, you specify a return value and can optionally specify one or more typed parameters that the caller will be required to pass when invoked.

    For a list of the most common types for function return values and parameters, see "Defining Utility Code in a Global Function" in the Groovy Scripting Reference guide.

  • For optimal performance, the maximum number of records that can be fetched is restricted to 500 records. If the data size chosen causes the job to fail with ExprTimeoutException, reduce the data size using setMaxFetchSize. Or, use selective filtering to filter the number of records fetched though the view object to less than 500 records.

Privileged Functions

When you define either an object function or global function, the function might run on an object where the runtime user has no privileges to create or update records. Allow users without access to an object's data to run a function with full access, by doing two things:

  1. While defining the function, check the Privileged check box to indicate that the function is privileged.

  2. Confirm that the Privileged Script Administration role has the right level of access so that the object function can execute successfully. Access to objects isn't given automatically. Instead, you must grant access using the Application Composer security UI.

At runtime, when a user invokes a privileged function from the UI, a temporary login session is activated with the privileged role, Privileged Script Administration (ORA_CRM_EXTN_PRIVILEGE_SCRIPT_ROLE). This privileged role has access to the object in your function, so no permission issues exist. The temporary login session lasts only for the duration of the single function call or anything that function calls internally.

For example, a sales representative has access to opportunity records only, not account records. When a sales representative edits an opportunity, there is a button that updates a related account using a privileged Groovy script. Even though the sales representative doesn't have update privileges for the account object, when the sales representative clicks the button, the privileged Groovy script executes by switching to the privileged role context to complete the update to the account record.

To make this happen, use the Application Composer security UI to grant account access to the privileged role, Privileged Script Administration.