4. Plug-Ins & Storage

4.1 Plug-ins & Server Files

All RapidContext server functionality is provided by plug-ins. The plug-in ZIP files are stored in the plugin/ directory on the server. The figure below illustrates the directory structure:

As seen above, most plug-ins are stored as packed ZIP files in the plugin/ directory. Only the local plug-in is stored in unpacked form by default. There are two special plug-ins that cannot be removed or unloaded:

The list of plug-ins to load on startup is stored in the config.properties file (in the plugin/local/ directory). The plug-in order in that file also controls the order in which plug-ins are loaded.

4.2 Storage Overview

The plug-ins are managed by the RapidContext storage subsystem. The server storage provides a unified view of all objects in the system, similar to a virtual file system. It has a number of important features:

4.3 Storage Tree

The storage tree can be browsed and inspected directly (requires admin role) from the rapidcontext/storage/ path on the server. The directory tree is structured into directories based on the object types, as seen below:

.storage/ Mount-points for storage providers (plug-ins, etc)
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)
plugin/ Currently loaded plug-ins
procedure/ Procedure configuration files
role/ Role configuration files
session/ Currently active sessions
type/ Storage type configuration files
vault/ External value vault configurations
user/ User configuration files

All plug-ins are mounted to the storage tree, under the storage/ directory. Active (loaded) plug-ins are also overlaid onto the root storage tree. Each plug-in therefore shares some parts of the overall directory layout (outlined above). The plug-in storages may also “shadow” objects in the tree from other plug-ins, which is used when modifying objects.

The built-in storage mount points are structured as shown in the figure below:

4.4 Storage Data Types

The objects retrieved from storage all have a storage data type. The data types can be divided into three categories that cover everything:

The first two categories of objects expose their storage data type in the type property, e.g. connection/jdbc for a JDBC connection object. The data types themselves are also objects that can be retrieved from the type/[type identifier] storage path. The example below shows parts of the JDBC connection data type (in YAML format):

id: connection/jdbc
type: type
description: >-
    The JDBC connection type. JDBC connections allows execution of SQL queries
    and statements to any JDBC data source. Connections may be pooled for
    maximum resource utilization.
initializer: org.rapidcontext.app.plugin.jdbc.JdbcConnection
property:
  - name: url
    description: |-
        The JDBC connection URL. (...)
    required: true
  ...
  

The object type initializer property links a data object to a Java object. Whenever such an object is retrieved from storage, the corresponding Java object will be automatically created and put into the storage cache. The Java objects in the storage cache may remain there indefinitely, but roughly every 30 seconds a cache cleanup job will destroy any objects reporting an inactive status.

4.5 Hidden & Computed Properties

Sensitive data such as passwords or access tokens can be stored in a hidden property which is prefixed by a . character. Such properties are filtered out whenever an object is returned via a procedure or similar. They remain available for Java implementations of connections, procedures, etc.

The example below shows how the password property is hidden for user objects by default:

id: johndoe
type: user
name: John Doe
description: A simple example user
enabled: true
realm: RapidContext
.password: secret
  

Some properties are calculated or transient and should not be written to storage. These computed properties are prefixed by a _ character. Any operation that writes to storage will filter these out.

4.6 Value Expansion, Vaults & Secrets

Secrets or external property values can be auto-expanded when loaded from storage. Value expansion uses a ${secret-key} syntax, and is supported for all serialization formats (properties, json, yaml, xml).

The value lookup for the expansion keys are handled via one or more of the configured vaults. By default, the env and prop vaults are available (for looking up values via system environment variables or Java system properties). When expanding variables, a specific vault can be specified instead of a global lookup; e.g. ${env!SECRET_TOKEN}.

Default values for missing keys can be specified after the key, e.g. ${prop!key:default}. If no default is specified, any missing reference will be expanded to an empty string.

Security Notice

  • Unlimited Expansion — Property expansion is unlimited, meaning that references will be expanded for any storable object in the tree.
  • Read-Write Asymmetry — Any user with write access to storage objects can save data with property expansion references. When reading the data back, the value references are expanded.
  • Secret Extraction — Users with object write access can thus extract secrets by referencing their keys when storing data. A special block for this is implemented for user settings.