Business Rules Scripting

From RemObjects Wiki

Jump to:navigation, search

This is a Data Abstract Features topic
Feel free to add your notes to this topic below.



Contents


See Also: Business Rules Scripting Overview | Business Rules Scripting API

Business Rules Scripting is a feature of Data Abstract that allows you to use EcmaScript (also known as JavaScript) code snippets to specify rules and business logic for your multi-tier data access, right inside your schema.

Traditionally, to add business logic (such as enforcement of data access restrictions and data consistency requirements) to your applications, you had to implement these so-called “business rules” as part of your custom server’s program logic, in the language and platform used to implement your server (be it one of the .NET languages or Delphi). This had several downsides. For one, the business rules were hardcoded inside the server executable, so updating or changing them meant compiling, testing and deploying a new version of the server executable. For another, it meant that the business rules were only applied on the server – to perform pre-check of rules compliance on the client, the rules needed to be manually duplicated in client code as well (potentially re-implemented in different languages or for different platforms), and to be kept in sync between client and server. This also meant frequently updating the client applications, if business rules changed.

With Data Abstract’s new EcmaScript based scripting, business rules can be written once, put inside the schema, and will automatically be enforced on the server and client. Changing the business rules means merely updating the schema on the server for the updated versions of the scripts to be applied.

The Case for Client and Server Side Rule Checking

There are good reasons for wanting to check business rules both on the server and on the client.

First of all, it is important to realize that, for any real security to be in place, rules must be enforced on the server. No matter what types of checks or input validation logic you have in place in your client application, the server should always treat your client as “untrusted”. Hackers or malicious users might hijack and adjust your client application, or might even implement their own client application that conforms to your server’s API to try and execute requests that they are not authorized to.

Imagine a scenario where different users of your system have access to different sets of data. Regular users might, for example, have access to partial employee records, while only top management has access to salary information. If this restriction was merely enforced by filtering the display on the client, a user could create a separate client application (or hack his existing client app), and make it display more data than should be available – using his regular and limited system login. Only by actually applying security checks and filtering data on the server, you can assure that a client will never be exposed to data it should not have access to. The same goes for enforcing integrity and restrictions on data manipulation, as well.

Rule #1: Do not trust the client application.

Why, then, would you even want to run business logic on the client at all? The main reason is convenience. If business logic is only enforced on the server, that means the client application (and the user) will only be informed of violating that logic when its changes are being sent to the server. The user might make changes to several records, unaware his modifications are invalid, and it is not until he applies his changes (which, when working offline, may not be until a point in the future) that he is confronted with a range of error messages. Even when your application is running “online”, it requires a roundtrip to the server and a failed attempt to apply his changes to inform the user of the problem. This is not good user experience.

The same goes for data requests: If a user does not have access to a specific set or subset of data, it’s better to not let him query for it – for example by graying out the relevant options – then to let him ask, and receive an error from the server.

Ideally, you want to present your user with warnings or validation messages as soon as possible, even while he is editing his data. This is what client-side business rules bring to the table.

Rule #2: Client-side validation is for user convenience only.

Data Abstract Business Rules Scripting allows you to define a shared set (or subset) of rules in a single place, that can be used both on the server to actually enforce the rules, and on the client to provide the convenience of verifying the rules during data entry.

Types of Business Rules Scripts

There are two different places, or scopes, where business rules scripts can be applied. The first is globally on a per-schema level, for events that apply to the entire schema. The second is on individual objects (such as data tables and commands) in the schema, for events that apply to specific commands. For example, the global beforeCommit() event will get fired whenever a transaction involving data in any table in the schema is committed. In contrast, the per-table beforeDelete() event will fire whenever a row in a specific data table is being deleted.

Some events can run on both the client and the server (such as the aforementioned beforeDelete()), while others may run on the server only (such as the also before-mentioned beforeCommit()) or on the client only (such as onNewRow()). This is owed to the fact that some events only make sense on the server (the client does not know about transactions, delta processing, error handling, and various other concepts) or on the client (in the client application, onNewRow() may be used to initialize/pre-fill a new row with default values before the user begins editing; this concept does not apply to the server, which will only see the finished row).

Finally, some events are specific to Relativity server, and beyond the scope of this article.

The Business Rules Scripting Events topic lists all available events in detail, and also specifies whether they apply to Client, Server, Client & Server or Relativity, and whether they are schema-wide or per object.

Adding Business Rules Scripts to your Schema

Business Rules Scripts can be added to your schemas in two ways, either by setting them in code or – more conveniently – by specifying them in your schemas right inside Schema Modeler. For this article, we’ll use Schema Modeler.

The quickest way to access the Business Rules Scripts in Schema Modeler is to select a table (or command) on the left-hand pane, and click the “Business Rules Script” button to open the Business Rules Script editor, shown below.

As you can see, the editor provides two tabs, to edit Server and Client & Server scripts, respectively.

Make sure to select “JavaScript” as language, as selecting “Pascal Script” will use legacy server-side scripting support available in Data Abstract for Delphi only, a feature that is being deprecated in favor of the new EcmaScript based scripting, available cross-platform.

Any event code placed in the Server tab will be kept private to the server, and only be executed there. This includes server-specific events, but also any events that would be available on the client, as well. For example, even though beforeDelete() is supported on both client and server, if you provide a handler on the Server tab, this handler will only execute on the server.

Any event code placed on the Client & Server tab will – as the name implies – run both on the client and server. If you implement beforeDelete() on this tab, it will run on both sides.

Events not available on a particular side will be ignored, if present. For example, if you implement a server-only event on the Client & Server tab, it will of course not run client side; if you implement a client-only event, it will be ignored on the server. In theory, you could implement all your events on the Client & Server tab, and it would work fine. The main reason to move server-specific events to the Server tab is to keep them private from clients, as only the Client & Server script will be sent out and available to clients.

For events running on both client and server, the global isServer API can be used to distinguish between the two, if slightly different code paths are needed for client vs. server. For example, you might provide a single event handler, but have more advanced and complicated checks run on the server, by embracing them in a “if (isServer) { … }” clause.

Implementing Event Handlers

Events are handled by providing an event handler for them, in form of a JavaScript function with a specific name and signature matching the event you want to handle. Once again, the Data Abstract Scripting Events topic provides a complete overview and documentation of the available event handler types.

The easiest way to do this is to use the Events dropdown button in Schema Modeler to select the appropriate event from the list and have Schema Modeler automatically insert a complete method body with the proper name and signature into your script.

Inside the function body, you have full access to the JavaScript language and the standard JavaScript APIs to write the logic for your event handler. Please refer to generally available JavaScript literature and specifications for details (see reference at the bottom of this article).

In addition to the standard JavaScript APIs, Data Abstract makes a range of additional object types and global APIs available. This is comparable to how, for example, web browsers would expand the JavaScript API to provide access to the web page’s document object model.

The Global Object topic provides a complete list of all global APIs, while Data Abstract Scripting API provides documentation for all object types available through the global API, as well as those exposed via event handler parameters.

The most commonly used global variables are session, which gives you access to the current Session object to access information about the logged-in user (if any) and lda, which provides a LocalDataAdapter object that can be used to run additional local queries on the server. The aforementioned isServer variable can be used on both client and server to distinguish between client and server, respectively. Also available on both client and server, the schema variable exposes a Schema object that gives access to information from the current schema, such as available data tables and their fields, etc.

Additional objects are available though the event handler’s parameters. For example, the beforeProcessDelta() event handler receives a Delta object that can be used to inspect, validate and adjust the actual changes received from the server.

As you can see, many of these objects made available through the scripting API reflect already familiar classes from the platform-specific .NET, Objective-C and Delphi APIs, such as the Local Data Adapters, Schemas or Deltas. These objects expose much the same APIs (or a subset thereof) as their big siblings, but are tailored for use from JavaScript. They allow you to implement business logic in much the same ways as you would traditionally have implemented them within your .NET or Delphi server code.

Note: Depending on the platform, you may also have access to additional platform specific APIs, such as .NET Framework classes published by the scripting engine, objects exposed by Microsoft’s ActiveScript (Delphi) or JavaScriptCore (Xcode). To keep your EcmaScript business rules platform agnostic, it is best to refrain from using such APIs. IDEA: Should we add a platform identifier method, parallel to isServer?

Enabling Scripting in Your Application

To enable business rules scripts to run in a Data Abstract application, both client and server side, a Scripting Provider is needed

For Data Abstract for .NET, simply drop an EcmaScriptProvider component on your data service (server side) or next to your Remote Data Adapter. Both the service and the RDA have a ScriptProvider property that you can connect to the dropped component.

Scripting support for Xcode and Delphi will come soon (see below for details). In the meantime, Data Abstract for Delphi still supports Legacy Business Rules Scripting with Pascal Script

Three Examples

To round off this article, let’s take a look at a few examples of business rules scripts.

First, a client-side onNewRow() may be used to pre-fill a new row with some default values before it is presented to the user for filling. Here, we populate the “id” field with a new GUID, and set the “name” to a default value:

function onNewRow(row)
{
  row["id"] = newGuid();
  row["name"] = "New Customer"
}

Next, a beforeProcessDeltaChange() handler validates if the current user has the right to delete rows, before allowing a specific change. The handler checks the session for a specific value (ostensibly set by some other part of the application), and refuses any “DELETE” change, if the “canDelete” value is not present:

function beforeProcessDeltaChange(delta, change, wasRefreshed, canRemove)
{
  if (change.isDelete && session["CAN_DELETE"] != "YES")
    fail("You are not allowed to delete rows for this table.")
  return canRemove;
}

Lastly, we use the Local Data Adapter to make some additional changes to our database after a change has been processed successfully. More specifically, we store date, user ID and the row ID in a “History” table:

function afterProcessDeltaChange(delta, change, wasRefreshed)
{
  lda.insert("History", { Date = new Date(), RowID = change["ID"], UserID = session.["UserID"] } );
}

Current Limitations of Scripting Support

Business Rules Scripting via EcmaScript is a new feature, and a work in progress. In its first incarnation with the Summer 2010 releases, we support it for Data Abstract for .NET and Relativity Server (which is based on .NET but available for all three editions). Scripting in Data Abstract for .NET is provided through our open source RemObjects Script for .NET EcmaScript engine.

The Spring 2011 release adds JavaScript-based Business Rules Scripting to Data Abstract for Delphi (Win32 only), replacing the old Pascal Script based scripting support (which is still available, but not cross-platform and now considered legacy).

We are working on expanding that support to Data Abstract for Xcode, using the native JavaScriptCore framework for Mac OS X. We are evaluating options to support client scripting on the iOS platform with Data Abstract for Xcode, but currently JavaScriptCore is a private API in iOS 4, so its use is not permitted as per Apple’s developer agreement, nor is the use of custom JavaScript/EcmaScript runtimes. We will continue to review this, as iOS progresses, and we might provide support for using the JavaScriptCore framework for internal non-AppStore applications (such as enterprise-deployed solutions)

At this stage, we have no plans to support EcmaScript scripting in Data Abstract for Delphi for non-Windows platforms (via Free Pascal or future cross-platform support in Delphi), due to lack of available options for scripting engines. But this is an area we will be keeping under review.

See Also


Da-48.png

Product: RemObjects Data Abstract
Available Editions: Data Abstract for .NET, Xcode, Delphi, Java and JavaScript

Glossary   — ArticlesFeaturesLibrarySamples

Navigation
products
platforms
special
Toolbox