The Remus Application Framework is a typescript based framework for the realization of complex applications. It consists of various components. Some of them can be used independently from each other.
Components
The Logger
Provides a convenient source code interface for logging tasks. Log messages are created using a method chaining approach and may use various properties such as the log level, ids, source references, origin (environment) references, etc. Different appenders are available, e.g. a ColourConsoleAppender and a FileAppender. It is possible to configure the Loggers in a way that log messages can be filtered by their properties and piped to designated appenders and in a way that logger instances can be configured to propagate various properties into their log messages so that they either act as default properties that, thus, do not need to be specified on each log call, or the final property values are determined by the logger instance and the concrete values provided to the log call.
The Command Line Interface
Provides a complex feature for the modeling of an application's command line interface. In contrast to other existing node command line parsers, it provides the following additional features:
-
A scriptable internal API for modeling the CLI: Most libraries out there consume one object containing the CLI description without the chance to alter the model afterwards which may be necessary due to asynchronous things going on on application start.
-
A multi-paradime approach: Depending on the needs, a command is a simple executable entity that may or may not provide options or sub-commands. However, a command could also be seen as the combination of a verb (do something) and an entity (with what). When using verbs, a slightly different approach for their registration is to be used: verbs shall be globally defined and yet dis- and enableable for each individual entity or entity type whilst having a different meaning on each entity.
-
A comprehensive and detailed execution flow: Calls to an application may use an arbitrarily complex structure of commands, subcommands, verbs, and options. In order to have things ready for a subcommand, a superordinate command may need to do things within the environment prior to the execution of the subcommand, depending on its options. In turn, processing options in the context of a command may be done prior to this. For that, the execution model provides different lifecycle hooks that are executed in the sequence that is given by the concrete command line arguments and the configured CLI model.
-
An extension API that enables the efficient reuse of commands and their options: Software is not monolithic, it is devided into modules and plugins the structure of which may not be determined at development time. Plugins can hook into existing commands, add, alter, or hide options, or extend and replace existing commands. For that, an internal command registry is used that allow such extension, e.g. using JavaScript decorators. Moreover that, the internal registry serves to validate all registered commands, e.g. after plugins have been installed, or provides reflection features for the configured CLI. This is to support the reuse of configured commands in other APIs such as WebSocket-connections or REST-APIs.
-
An included, and thus, standardized, yet customizable help text generator.
The Utils
Provides the common utilities, for example:
- JSON-serialization and deserialization with the ability to handle circular objects, thus, being able to process arbitrary objects. There are Annotations available for the type-specific handling of properties and for the registration of classes for deserialization.
- Features for performing model and system validations and reporting results in a structured manner.
To be extended!
Das Remus Anwendungs-Framework ist eine TypeScript-basierte Sammlung von Paketen für die Realisierung komplexer Anwendungen. Die Pakete realisieren verschiedene häufig verwendete Komponenten, die teils unabhängig voneinander verwendet werden können.
Komponenten
Der Logger
Der Logger bietet eine einfach zu verwendende Schnittstelle für Log-Aufgaben. Logeinträge werden unter Verwendung verketteter Methodenaufrufe erstellt womit verschiedene Parameter einer Lognachricht, wie das Log-Level, IDs, Quellverweise, Verweise auf die Ursprungsumgebung usw. gesetzt werden können. Für die Verarbeitung der Nachrichten stehen Konsumentenklassen zur Verfügung, wie gestaltete Konsolenausgaben oder Datei-Logger. Es ist möglich Logger so zu konfigurieren, dass Lognachrichten anhang ihrer Eigenschaften gefiltert werden, um sie an die gewünschten Konsumenten bzw. Transportkanäle weitergeleitet werden. Außerdem können verschiedene Logger-Instanzen so konfiguriert werden, dass verschiedene Eigenschaften in die erstellten Lognachrichten propagiert werden. Diese agieren entweder als Standardwerte oder, sofern eine Nachricht konkrete Werte vorgibt, in geeigneter Weise mit den konkreten Werten kombiniert wird. So müssen bestimmte Eigenschaften einer Nachricht nur spezifiziert werden, wenn diese von den vorkonfigurierten Werden abweichen oder diese konkretisieren.
Die Kommandozeilenschnittstelle (CLI)
Das Paket der Kommandozeilenschnittstelle stellt komplexe Funktionen bereit, um die Schnittstellen von Anwendungen und damit auch die Anwendungen selbst modellieren zu können. Im Gegensatz zu anderen CLIs bzw. Kommandozeilenparsern im Umfeld von Node.js und Typescript zeichnet sich dieses Paket durch folgende Eigenschaften aus:
-
Eine dynamisch programmierbare interne API: Die meisten verfügbaren Bibliotheken konsumieren zu ihrer Konfiguration ein Objekt mit der CLI-Beschreibung, ohne dass dieses Modell anschließend programmatisch verändert oder erweitert werden kann. Das ist jedoch manchmal nötig, wenn asynchrone Prozesse, wie bspw. eine Plugin-Schnittstelle berücksichtigt werden muss.
-
Ein Mehrparadigmen-Ansatz: Abhängig von den konkreten Erfordernissen ist ein Kommando eine simple ausführbare Einheit, die ggf. lediglich Optionen oder Unterkomponenten hat. Andererseits kann ein Kommando aber auch als komplexere Entität bestehend aus einem Verb (Was soll gemacht werden) und einem Subjekt (Womit soll es gemacht werden). Wenn Verben verwendet werden sollen, ist ein leicht abweichender Ansatz zu deren Registrierung nötig, da Verben zwar global definierbar und beschreibbar sein sollen, jedoch abhängig vom Subjekt verfügbar ist oder nicht und auch unterschiedliche Bedeutung haben kann.
-
Ein umfassend konfigurierbarer Ablauf der Kommandoausführung und Verarbeitung von Optionen: Aufrufe von Anwendungen können beliebig komplexe Strukturen von Kommandos, Unterkommandos, Verben, Optionen, und Parametern haben. Um für die Ausführung eines Kommandos alle Voraussetzungen zu erfüllen, müssen Optionen, Parameter und übergeordnete Kommandos vorverarbeitet werden, konkret aufgerufene Kommandos müssen den Code von übergeordneten Kommandos einbinden und wiederverwenden können und alle vorverarbeiteten Elemente müssen ggf. wieder nachbearbeitet werden. Hierfür stehen für Kommandozeilenelemente verschiedene Erweiterungspunkte bereit, um sie in definierter Reihenfolge auszuführen. Dazu wird sowohl das konfigurierte Anwendungsmodell herangezogen, als auch der konkret per Kommandozeile erfolgte Programmaufruf.
-
Eine Erweiterungsschnittstelle, die es ermöglicht vorhandene Kommandos und ihre Optionen effizient wiederverwenden, abzuändern oder erweitern zu können: Anwendungen sind nicht monolithisch, sondern in verschiedene Komponenten, Module oder Plugins aufgeteilt, deren konkrete Struktur zur Entwicklungszeit noch nicht unbedingt feststeht. Erweiterungen können existierende Kommandos erweitern, ändern, nutzen oder unterbinden, Optionen ab- oder zuschalten. Hierfür steht eine interne Registrierung bereit, die entsprechende Erweiterungen realisieren kann. Ferner dient sie der Validierung, zum Beispiel, wenn Plugins installiert werden, sowie der Reflektion. Denn: Kommandos sollten nicht nur über die Kommandozeile aufrufbar sein, sondern auch über andere APIs, wie etwa Websocket-Verbindungen oder REST-APIs.
-
Ein bereits eingebundener und daher standardisierter jedoch auch konfigurierbarer Generator für Hilfetexte.
Das Unterstützungspaket
Stellt wiederverwendbare und überall nützliche Komponenten bereit, wie zum Beispiel:
- JSON Serialisierung und Deserialisierung mit der Fähigkeit zirkuläre Referenzen in Objektstrukturen zu handhaben und so beliebige Objekte verarbeiten zu können. Es stehen Annotationen zur Verfügung, die die typspezifische Verarbeitung ermöglichen sowie die Instanziierung von Klassen bei der Deserialisierung.
- Funktionen, um System- und Modellvalidierungen durchführen und deren Ergebnisse strukturiert darstellen zu können.