- Documentation
- Server & Plug-In Development
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:
- id — The unique plug-in identifier. May only contain
ASCII alphanumeric characters without spaces or separators.
- name — The plug-in name as presented to the users.
- version — The plug-in version number. This number is
automatically modified by the default build tools (in share/plugin).
- date — The plug-in build date. This number is
automatically set by the default build tools (in share/plugin).
- description — The optional description text that
explains the functionality provided by the plug-in.
- copyright — The optional copyright statement text.
- className — The optional fully qualified name of
a Java class that handles the plug-in life-cycle. The class must be a
subclass of org.rapidcontext.core.type.Plugin.
- post-install — The optional procedure that should be
called after each installation (for validation, upgrade or similar).
The plug-in configuration is the first file to write when developing a
plug-in. An example plugin.properties file is shown below:
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.
- procedure — The base procedure type, only used by
procedures implemented directly in Java code.
- procedure/javascript — The JavaScript procedure type,
used for creating a procedure in JavaScript (usually to provide business
logic and smarts for more basic procedures).
- procedure/cmdline/exec — The command-line execution
procedure type, used for running shell commands on the server. Procedure
arguments can used as arguments on the command-line.
- procedure/http/request — The HTTP request procedure type,
used for fetching from or posting to a URL. Procedure arguments can be
inserted into either the request headers and/or data payload.
- procedure/jdbc/query — The JDBC query procedure type,
used for SQL SELECT queries returning results. Procedure arguments may be
inserted as literals into the SQL text.
- procedure/jdbc/statement — The JDBC statement procedure
type, used for SQL INSERT, UPDATE and DELETE statements (among others).
Procedure arguments may be inserted as literals into the SQL text.
5.4 Procedure Editing
Using the Settings app, it is possible to create or edit
procedures of any type (except built-in). Navigate to the
Procedures
tab and edit an existing procedure or select
Add procedure
. 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:
- data — The binding value is a string constant
that may or may not span multiple lines. Typically contains SQL text or
JavaScript code.
- 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.
- 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.
- 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
Settings 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:
function hasContext(thread) {
return thread.context != null;
}
function getProcName(thread) {
return thread.context.procedure;
}
var threads = listThreads();
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:
- 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.
- 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.
- 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.
- 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.
- 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:
- Debugging — When creating or modifying JavaScript
procedures, it is often very helpful to review the trace logging available
when calling procedures from the Settings app.
- Connection Reservation — All connections required
by a procedure (and its referenced sub-procedures) are reserved before
execution starts. This guarantees that resources are available, but might
be wasteful in some circumstances.