5. Server-side & Plug-In Development

5.1. Plug-in Structure

All RapidContext server functionality is provided by plug-ins. The plug-ins are distributed as ZIP files named [plugin identifier]-[version].plugin and contain an internal directory structure like this (mirroring the overall storage structure):

The directories are names according to the type of objects contained. The exceptions being files/ and lib/ that are handled in a special way. The files/ directory contains all the JavaScript code and images available for web browsers.

5.2. Plug-in Configuration

Each plug-in must contain a plugin.properties configuration file. It is the only mandatory content of a plug-in and consists of the following fields:

The plug-in configuration is the first file to write when developing a plug-in. An example plugin.properties file is shown below:

# General properties
id = example
name = Example Plug-in
version = 1.0
date =
description = Provides tests and examples for the platform.
className = org.rapidcontext.app.plugin.example.ExamplePlugin
  

Once the plugin.properties file has been created, the Ant script in plugin-build.xml can be used for packaging the plug-in.

5.3. Procedures & Procedure Types

Server-side operations can be added by creating procedures. Procedures can be invoked from the client or from other procedures and may take arguments, modify data and/or return values.

Each procedure has a specific type (or kind). The procedure type defines which Java code is used to execute the procedure, similar to a templating engine. Since most server-side operations are very similar, only a few different procedure types are needed. The built-in and standard plug-in procedure types are listed below, but more can be added by installing additional plug-ins.

5.4. Procedure Editing

Using the Admin app, it is easy to create or edit procedures of any type (except built-in). The screenshot below shows the location of the + icon for adding a new procedure. Just next to it is the edit icon.

After clicking the add or edit icon, the following dialog is shown:

Each procedure can have a number of custom configuration properties that control their execution. A property has one of four types, each with different semantics and expected values:

  1. Argument — The value should contain the procedure argument description (as later shown in the Admin app). Note that both the number and order of arguments are important. During procedure execution, the property identifier is bound to the value provided in the call.
  2. Connection — The value should contain a connection identifier (connection reference). The connection will be reserved before calling the procedure. For JavaScript procedures, the connection object allows direct calls to methods such as commit() or similar.
  3. Data — The value is a data string constant that may or may not span multiple lines. Mostly useful for JavaScript procedures.
  4. Procedure — The value contains a procedure identifier (procedure reference). Only used for JavaScript procedures, where it enables calling other procedures as functions.

Procedures created or edited are stored to the procedure/ directory inside the local plug-in. The files there can be copied to the corresponding plug-in development directory for packaging.

5.5. JavaScript Procedures

The javascript procedure type allows creating generic server-side logic with minimum effort. The procedure consists of JavaScript code, which is compiled upon the first call. Additional procedure properties are exposed as variables in the global scope and can be accessed or called directly.

The JavaScript environment provided is compatible with EcmaScript 5.1 and allows the creation of helper functions and comments to keep the code readable. See the example below for a JavaScript procedure that calls another procedure and filters its result:

// Helper: Check if server thread has context
function hasContext(thread) {
    return thread.context != null;
}

// Helper: Extract procedure name from server thread context
function getProcName(thread) {
    return thread.context.procedure;
}

// Using property bound to 'System.Thread.List' procedure
var threads = listThreads();

// Filter threads and extract procedure names,
return threads.filter(hasContext).map(getProcName);
  

JavaScript procedures is a powerful tool for post-processing data in various situations. It is also often easier and more efficient to put this type of functionality into a procedure, than to perform it in the web browser. Especially when the data set is large or when many separate queries are required. Here are a number of recommended uses for JavaScript procedures:

  1. Data Filtering — Perform additional checks to remove items from a list is easy with the JavaScript filter() method. Some checks are also much easier to express in JavaScript than in SQL or similar.
  2. Data Merging — Merging data from multiple queries and/or data sources is straight-forward in JavaScript. The easiest way is of course to just return a new object with all results as properties.
  3. Data Transformation — Transforming data from one format to another is often easy with a bit of JavaScript. Using a simple for or while loop, any data list can easily be transformed into a lookup table for example.
  4. Higher-Order Searches — Using a bit of JavaScript, it is possible to build higher-order searches that use the results from one query as input to the next one. Since a JavaScript procedure can use many other procedures, results can be tailored in any way.
  5. Statistics — If the data source itself cannot perform adequate statistical functions, the next best option is to use a procedure. The transfer of large quantities of data is costly, so processing closer to the data source is faster.

A few additional tips to consider when developing JavaScript procedures: