D language utility library and modular application framework
The main package contains only two modules;
which is generated by the build and not stored in the
which contains globally defined
The rest of the library is broken into subpackages.
Building the libraries
The packages may be built using dale:
dub run dale -- build
Run the Example:
dub run dale -- runexample
Run the unittest:
dub run dale -- test
dale is built, you can run it directly
(unless dale.d has been updated):
Or, just run the project:
dub run --config=shi_sha -- test
This builds on the utility library (see below) to provide a structured application framework.
Application access to the configuration variables
defined in the
The values are of type
Variant are taken from:
- finally, a global array of default values.
This allows for types and parameters to be auto-registered with the injection container.
The mixin template
registerComponent is used
to register a type that inherits from
RuntimeComponents class takes a variadic
parameter list. This list is parsed by the Injection
wrapper, and classes and parameters registered in
The principle is that applications, rather than register classes directly with the injector, instead provide a method in the runtime component that provides an instance of the type. Then, another application can extend the component type, and override the method to provide a different implementation of the registered type.
This is the default runtime component for generic applications.
PlatformComponents describes the
types that are available in this component.
PlatformRuntime extends the default
runtime component class, and takes the same parameter
Classes in the client may extend
to override the defaults, or to add their own
PlatformJob interface and
abstract class are provided by the platform module.
Important types registered by this component are:
A notifying job runner with status events.
Notifying workflow model and job type. Clients create workflow elements, and these are instantiated and added to a workflow object.
The workflow object may be loaded from a definitions at compile time, or at runtime.
Workflow elements take configuration settings and would use the injector to access local parameters.
The workflow can then be attached to a
wich is created by the
Plugins are dynamic modules with a class activator.
A plugin application may create a
PluginDefault, and override
the activation methods.
Plugins may be loaded into an application using
The plugin broadcasts lifecyle notifications, as does the plugin loader.
Core Utility Library
Stores key / value pairs defined during compilation as runtime constants, so that we can compare versions at runtime, in a dynamic library for example.
There are two classes;
Constants which contains the
enums and aliases which define each constant, and
RTConstants which contains constant variable definitions
for each constant.
The local application configuration is available at runtime in a static
__gshared array of
The values are loaded from the file
dxx.ini file at compilation time, and are assumed to remain constant
during the application lifecycle.
The ini data is defined in the module as
and an application can override this, or merge
This array is used to configure the
application components, and is exposed via the class
The injection tooling is a wrapper around aedi.
The library provides an application local injection container may be created by a client. This is initialised using template parameters.
The values passed in to the template are either component classes, which are scanned by the injection container, or property tuples, which are used to declare properties accessible to the application.
The property values are loaded into the injector when the container is initialised.
The property values can come from local configuration files, environment variables, and command line parameters.
TODO we want to reload the injection container transparently without breaking things. Or, more breaking them. Breaking them morely. More so.
A simple notification framework. Notifications may be synchronous or asynchronous.
Listeners implement the
A user-defined struct may be passed as an argument to a notification event, which is passed on to all listeners.
Clients may extend the
which handles re-casting the notification parameter.
A simple string externalisation feature, allowing key-based translation files. The language is specified at compile time.
A notifying logger that also uses the injector.
We can hot-load dynamic libraries from files, using the reloaded library.
Our module loader takes care of version-checking of the dxx library at runtime.
This is because we want to build in a notification callback system for our application plugin framework.
The callbacks rely on matching structs defined in the core library, and these may vary between library versions.