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):

app/ App configuration files
connection/ Connection configuration files
environment/ Environment configuration files
files/ Contains files to serve via HTTP (maps directly to URL:s)
lib/ Java JAR libraries to load (server-side)
procedure/ Procedure configuration files
role/ Role configuration files
user/ User configuration files
plugin.properties The plug-in configuration file (mandatory, see below)

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 public files (images, CSS, JavaScript and HTML) available to 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 build tools in share/plugin can be used for packaging the plug-in (using a Makefile or an Ant build.xml file).

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 (its storage type). 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 is configured with a number of bindings (properties) that control the execution. Each binding has a type that controls how the binding is used during execution:

  1. data — The binding value is a string constant that may or may not span multiple lines. Typically contains SQL text or JavaScript code.
  2. connection — The binding value is a connection identifier (i.e. a storage path without the connection/ prefix). The connection will automatically be reserved before calling the procedure. For JavaScript procedures, a connection object exposes an API for direct calls to commit() or other methods.
  3. procedure — The binding value is a procedure identifier (i.e. a storage path without the procedure/ prefix). Only used for JavaScript procedures, where it exposes these as callable functions.
  4. argument — The binding value is normally not set, but must be provided when the procedure is called. A binding description contains the argument description (as shown in the Admin app). Note that both the number and order of arguments are important. During execution the binding name variable is set to the value provided in the call.

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 procedure/javascript 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: