Application Framework

Application Lifecycle

See Choosing an Application Design for the function-based, event-driven, procedural, command-style, and application-part designs supported by this lifecycle.

Application retains non-owning access to the original narrow or wide argv vector supplied to its constructor. After option parsing, every suffix reported as sensitive text is overwritten in place with one star per existing byte or code unit. The terminating null and native buffer size are preserved. Its converted CommandLineArguments list uses exactly five stars for each sensitive value. Masking occurs for successful parsing and parser or validator errors.

The native pointers must remain valid for the application lifetime. This cleanup only reduces secrets retained in process memory; it cannot retract command-line values already exposed through process listings, the shell, operating-system facilities, logs, or earlier application code.

Service Lifecycle

enableServiceLifecycle() lets the same executable run interactively, as a foreground POSIX daemon, or as a Windows own-process service. On Linux and macOS, SIGTERM and SIGINT request the regular graceful application shutdown. On Windows, the application connects to the Service Control Manager when launched as a service and otherwise continues as an interactive console application. SCM stop and shutdown controls and interactive Ctrl+C or Ctrl+Break requests use the same application-part and event-loop shutdown path.

Startup is reported as complete immediately before main work begins. A slow initializer can call reportStartupPending(expectedTime) before that point and publish genuine progress with additional calls. It must call reportStartupComplete() when the application is ready. The default application-part lifecycle automatically keeps startup pending until all automatically started parts reach the running state.

See Creating Services and Foreground Daemons for complete examples and lifecycle details.

Application Parts

Application parts are dependency-aware, one-shot components with dedicated event threads. The detached ApplicationPartManager owns their graph and runtime, while Application can provide the same manager as a lazy application service. See Building an Application from Parts for application integration, Designing Application Parts for part design and lifecycle guidance, and Running Application Parts Independently for standalone manager operation.

Identifiers and Registration

ApplicationPartIdentifier stores a stable, case-sensitive name. A manager resolves identifiers by name, so separately created identifiers with identical names address the same registered part. The manager rejects invalid dependency graphs before constructing any part.

ApplicationPartIdentifierPtr and ApplicationPartIdentifierList provide the shared identifier and dependency list aliases. ApplicationPartPtr, ApplicationPartManagerPtr, ApplicationPartManagerAccessPtr, and ApplicationPartManagerAccessWeakPtr provide the corresponding ownership aliases.

Part Interfaces

ApplicationPart provides lifecycle hooks, command-line forwarding, the dedicated event target, and read-only manager access. Public service interfaces publish the same static identifier and can be combined with the implementation through ApplicationPartWithInterface.

Manager Access and Lifecycle

ApplicationPartManagerAccess provides thread-safe state, wait, and prepared-part lookup operations. The mutable manager interface adds registration, preparation, command-line forwarding, asynchronous lifecycle requests, callbacks, and ordered error retrieval.

Manager and part state callbacks execute on the manager’s control event source. Every started part receives a separate event thread. Dependencies gate startup and reverse the shutdown order. State observers are independent subscriptions. Retain the EventSubscription returned by events().addStateChanged() or events().addPartStateChanged() for as long as the observer shall remain active.

Compiled Resources

Application::resources() lazily creates the read-only compiled resource manager. The manager indexes statically linked descriptors on first access and caches decoded data and text independently. An application with no compiled descriptors receives an empty manager. See Compiling Resources into an Application or Library for CMake integration and lookup examples.

Logging

log() lazily creates the application-wide log manager, and logStream() returns its root stream. The application default routes information, warning, and error entries to its terminal-backed console writer. enableLastErrorDump() installs a retained-error writer that remains present across later configuration replacements. By default, final cleanup displays its nonempty snapshot only after a nonzero application exit code. Select LastErrorDumpMode::Always to display it after a successful run as well. The heading uses the application’s log.LastErrorDumpTitle display-text entry. See Choosing a Logging Setup for routing, trace sections, and standalone managers.

Interface

class Application

The core application framework.

You must create a single instance of this class or a derived class in your main() method.

Note

Important Information when using Erbsland Core under Windows in DLLs Be careful when creating a Windows application that static links Erbsland Core into DLLs that are used by the application. These DLLs do not automatically share the same Application instance. Create an exported not inlined method initializeMyDll(Application &app) in each DLL that used Erbsland Core, and call Application::linkWith(app) in this method. From main() call all these initialize...() methods of all DLLs that use Erbsland Core, just after creating the Application instance. Do not use application() or Application::instance() in static initialization in DLLs that link Erbsland Core.

Public Functions

Application()

Create an application without command line arguments.

Only create one instance, as the first action in your main() function.

Application(int argc, char *argv[])

Create an application from UTF-8 encoded command line arguments.

Only create one instance, as the first action in your main() function.

Application(int argc, wchar_t *argv[])

Create an application from wide command line arguments.

Only create one instance, as the first action in your main() function.

virtual ~Application()

Destroys the application after its lifecycle has completed.

void enableTerminal()

Enable advanced terminal output.

Call this immediately after constructing the Application object. Either from main or as one of the first lines in your custom initialize() method. In this call, a terminal instance is created for the lifetime of this application. The terminal is automatically shutdown when the program exits, do not call initialize() or shutdown() from your user code. If a tty is detected, el::stdOut() and el::stdErr() are redirected to the terminal. Output from el::stdOut() always resets the color to the default color while output from el::stdErr() is output in bright red. This is just for convenience to keep inferring output from these channels readable. The idea is that you use the terminal instance via terminal() for all your application output.

void enableServiceLifecycle()

Enable foreground-daemon and Windows service lifecycle integration.

Call this after construction and before run(). Repeated calls are ignored.

void reportStartupPending(time::TimeDelta expectedRemainingTime)

Report that startup is still in progress.

This disables automatic readiness until reportStartupComplete() is called. Repeated calls report progress.

Parameters:

expectedRemainingTime – Positive expected time until startup completes.

Throws:
  • err::LogicError – If service lifecycle support is not enabled or startup already completed.

  • err::ParameterError – If expectedRemainingTime is not positive.

void reportStartupComplete()

Report that application startup completed.

This operation is idempotent.

Throws:

err::LogicError – If service lifecycle support is not enabled.

int run()

Run the default application lifecycle.

This is calling the application methods in the following order:

  • initialize()

  • registerCommandLineOptions()

  • parseCommandLine()

  • main()

  • cleanup() Exceptions thrown from callbacks in the automatically managed main event loop use the same boundary. If any err::Exception is thrown from one of these methods or callbacks, it will be handled by calling cleanup() first, then printing the error to stdErr() and exiting the application with an exit code of 1. In case of an core::ApplicationError, the exit code from the exception will be used. Any non-err::Exception propagates out of this method.

void setInitializeFn(InitializeFn initializeFn)

Set the function called by the default initialize() implementation.

Use this to customize initialization without deriving from Application. A derived initialize() override must call Application::initialize() to invoke this function.

void setMainFn(MainFn mainFn)

Override the main function.

Use this to set a custom main function without deriving from Application.

const options::OptionsPtr &options() const noexcept

Get the global options configuration.

void releaseOptions() noexcept

Release the option configuration to free memory after startup.

ApplicationInfo &info() noexcept

Get mutable application information.

const ApplicationInfo &info() const noexcept

Get application information.

const CommandLineArguments &commandLineArguments() const noexcept

Get the converted command line arguments.

const options::OptionValuesPtr &optionValues() const noexcept

Get the option values.

ApplicationPartManagerPtr partManager()

Access the lazily created application-part manager.

template<ApplicationPartClass T>
inline void registerPart()

Register an application-part class before run().

Template Parameters:

T – The concrete application-part class.

template<ApplicationPartInterface T>
inline std::shared_ptr<T> part()

Access a prepared application part through its interface.

Template Parameters:

T – The abstract part interface.

Returns:

The prepared part implementing T.

random::Random &random()

Get the shared random generator for non-security use.

random::Random &secureRandom()

Get the shared secure random generator.

cryptology::CryptologyConfiguration &cryptologyConfiguration()

Get the shared cryptology configuration, creating it on first use.

log::LogManager &log()

Access the lazily created application log manager.

The first access installs the default information, warning, and error console route.

Returns:

The application-owned manager, which remains valid until application cleanup.

const log::LogStreamPtr &logStream()

Access the root application log stream.

This method lazily creates the same manager as log().

Returns:

The root producer stream of the application log manager.

void enableLastErrorDump(LastErrorDumpMode mode = LastErrorDumpMode::OnFailure)

Enable retaining and conditionally displaying recent error entries during final application cleanup.

The writer remains persistent across later logging configuration replacements. Repeated calls update the display mode without installing another writer.

Parameters:

mode – Select whether a nonempty snapshot is displayed only after failure or after every run.

const i18n::DisplayTextMapConstPtr &displayText() const

Access the application display texts. The returned pointer is always non-null.

void setDisplayTextMap(i18n::DisplayTextMapConstPtr displayText)

Replace the application display texts. A null pointer restores the English defaults.

system::UserLookup &userLookup()

Get the shared user and group lookup service.

const resource::Resources &resources()

Access the lazily initialized compiled-resource manager.

const cterm::TerminalPtr &terminal() const

Access the application-shared terminal instance.

Must be enabled via enableTerminal().

const cterm::TerminalDocumentStyle &systemOutputStyle() const noexcept

Get the style used for application-rendered system output.

void setSystemOutputStyle(cterm::TerminalDocumentStyle style) noexcept

Set the style used for application-rendered system output.

event::EventsPtr events()

Access the target interface of the main event loop.

Use these events to post/schedule events and calls that shall run in the main thread.

event::EventRegistry &eventRegistry()

Access the event registry.

event::ManagedEventThreadPtr createEventThread()

Create a managed event thread.

void quit(unit::ExitCode exitCode = unit::ExitCode::success()) noexcept

Quit the main event loop, and the event loops of all registered threads.

Public Static Functions

static Application &instance()

Get the application instance.

static void linkWith(Application &app)

Link this application instance with another one.

Only call this method from initializeMyDll(Application &app) methods in DLLs that static link Erbsland Core to synchronize the singleton across DLL borders.

static unit::Version libraryVersion() noexcept

Get the build-time library version.

static text::String libraryVersionText() noexcept

Get the build-time library version text.

Application &erbsland::core::application()

Access the global application instance, creating a default one on first use.

class ApplicationError : public erbsland::err::RuntimeError

A generic application error that is meant to terminate a running application with the given message and exit code.

Public Functions

inline explicit ApplicationError(text::String reason, const std::exception_ptr &cause, const unit::ExitCode exitCode = unit::ExitCode::failure()) noexcept

Create an application error with the given reason and exit-code.

Parameters:
  • reason – The reason for the error.

  • cause – The diagnostic cause.

  • exitCode – The exit code to use when terminating the application.

inline explicit ApplicationError(ApplicationErrorContext context, const std::exception_ptr &cause = {}) noexcept

Create an application error with the given reason and exit-code.

Parameters:
  • context – The context with error details.

  • cause – The diagnostic cause.

inline explicit ApplicationError(text::String reason, const unit::ExitCode exitCode = unit::ExitCode::failure()) noexcept

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

virtual err::DiagnosticConstPtr diagnostic() const override

Convert the error with all its details into a structured diagnostic.

inline const text::String &title() const noexcept

Get the title of the error.

inline const text::String &description() const noexcept

Get the description of the error.

inline const text::String &sourceName() const noexcept

Get the name of the source that caused the error.

inline const text::String &sourcePath() const noexcept

Get the path of the source that caused the error.

inline unit::CodeLocation codeLocation() const noexcept

Get the code location of the source that caused the error.

inline unit::ExitCode exitCode() const noexcept

Get the exit code to end the application.

inline const ApplicationErrorContext &context() const noexcept

Get the error context.

class ApplicationInfo

Optional application metadata used by command line rendering.

Public Functions

inline const text::String &applicationName() const noexcept

Get the application name.

inline void setApplicationName(text::String applicationName)

Set the application name.

inline const unit::Version &applicationVersion() const noexcept

Get the application version.

inline void setApplicationVersion(unit::Version applicationVersion) noexcept

Set the application version.

inline const text::String &authorName() const noexcept

Get the author or organization name.

inline void setAuthorName(text::String authorName)

Set the author or organization name.

inline const text::String &copyrightLine() const noexcept

Get the copyright line.

inline void setCopyrightLine(text::String copyrightLine)

Set the copyright line.

inline const text::String &licenseText() const noexcept

Get the license text.

inline void setLicenseText(text::String licenseText)

Set the license text.

class ApplicationPart : public erbsland::core::ApplicationPartCommandLine

Base class for an independently managed application component.

Lifecycle hooks run on the part’s dedicated event thread except automaticStart(), which runs on the manager control event source, and the command-line hooks, which run synchronously on their caller’s thread.

See: Application Framework

Subclassed by erbsland::core::ApplicationPartWithInterface< T >

Public Functions

inline ApplicationPartState state() const noexcept

Get the current lifecycle state.

ApplicationPartManagerAccess &partManager() const

Access the manager-local part registry.

Throws:

err::LogicError – If this part was not prepared by a manager.

event::EventsPtr events() const

Access this part’s event target.

Throws:

err::LogicError – If the part has not started yet.

virtual void registerCommandLineOptions(const options::OptionsPtr &options) override

Register this part’s command-line options.

Parameters:

options – The shared application option definitions.

virtual void parseCommandLine(const options::OptionValuesPtr &values) override

Receive successfully parsed command-line values.

Parameters:

values – The parsed option values.

Public Static Functions

static inline ApplicationPartIdentifierList dependencies()

Return an empty dependency list.

using erbsland::core::ApplicationPartErrorHandler = std::function<ApplicationPartErrorAction(ApplicationPartIdentifierPtr identifier, std::exception_ptr error)>

A callback deciding how a manager handles a part failure.

using erbsland::core::ApplicationPartManagerStateChangedFn = std::function<void(ApplicationPartManagerState state)>

A callback observing manager state transitions.

using erbsland::core::ApplicationPartStateChangedFn = std::function<void(ApplicationPartIdentifierPtr identifier, ApplicationPartState state)>

A callback observing part state transitions.

class ApplicationPartCommandLine

Command-line lifecycle hooks implemented by application parts.

Subclassed by erbsland::core::ApplicationPart

Public Functions

virtual void registerCommandLineOptions(const options::OptionsPtr &options) = 0

Register this part’s command-line options.

Parameters:

options – The shared application option definitions.

virtual void parseCommandLine(const options::OptionValuesPtr &values) = 0

Receive successfully parsed command-line values.

Parameters:

values – The parsed option values.

enum class erbsland::core::ApplicationPartErrorAction : uint8_t

The manager action after an application-part failure.

Values:

enumerator Continue

Stop the failed branch and keep unrelated parts running.

enumerator StopAll

Stop every part and finish the manager in Failed state.

class ApplicationPartIdentifier

A stable, named identifier for an application part.

Identifier names are authoritative. Implementations may cache manager-local lookup information without exposing mutable state through this interface.

See: Application Framework

Subclassed by erbsland::core::impl::ApplicationPartIdentifier

Public Functions

virtual const text::String &name() const noexcept = 0

Get the stable identifier name.

inline text::String toString() const noexcept

Convert this identifier to text.

Public Static Functions

static ApplicationPartIdentifierPtr create(text::String name)

Create an application-part identifier.

Parameters:

name – A non-empty ASCII reverse-domain token using letters, digits, ., _, and -.

Throws:

err::ParameterError – If name is invalid or longer than 200 characters.

Returns:

A new identifier with no manager-local cache.

class ApplicationPartManager : public erbsland::core::ApplicationPartManagerAccess

A detached manager for dependency-aware application parts.

See: Application Framework

Subclassed by erbsland::core::impl::ApplicationPartManager

Public Functions

template<ApplicationPartClass T>
inline void registerPart()

Defer registration of an application-part class.

Template Parameters:

T – The concrete application-part class.

Throws:

err::LogicError – If preparation already started.

virtual void prepare() = 0

Validate registrations, construct all parts, and enter Ready.

virtual void registerCommandLineOptions(const options::OptionsPtr &options) = 0

Forward command-line option registration to prepared parts.

Parameters:

options – The shared option definitions.

virtual void parseCommandLine(const options::OptionValuesPtr &values) = 0

Forward successfully parsed command-line values to prepared parts.

Parameters:

values – The parsed option values.

virtual void start() = 0

Begin initial automatic startup asynchronously.

virtual void start(const ApplicationPartIdentifierPtr &identifier) = 0

Start a part and its inactive dependency closure asynchronously.

Parameters:

identifier – The part to start.

virtual void stop(const ApplicationPartIdentifierPtr &identifier) = 0

Stop a part and its active dependent closure asynchronously.

Parameters:

identifier – The part to stop.

virtual void stop() = 0

Stop all parts asynchronously.

virtual ApplicationPartManagerEventEditor &events() noexcept = 0

Access the stable manager-owned lifecycle event editor.

virtual void setErrorHandler(ApplicationPartErrorHandler handler) = 0

Set the part-error policy callback.

virtual bool hasError() const noexcept = 0

Test whether an error is queued.

virtual std::exception_ptr takeError() noexcept = 0

Take the oldest queued error.

Public Static Functions

static ApplicationPartManagerPtr create(event::EventsPtr controlEvents = {})

Create a detached application-part manager.

If controlEvents is null, the manager creates and owns a dedicated control event thread.

Parameters:

controlEvents – Optional externally owned control event target.

Returns:

A new application-part manager.

class ApplicationPartManagerAccess

Thread-safe read and wait access to an application-part manager.

See: Application Framework

Subclassed by erbsland::core::ApplicationPartManager

Public Functions

virtual ApplicationPartManagerState state() const noexcept = 0

Get the manager lifecycle state.

virtual ApplicationPartState partState(const ApplicationPartIdentifierPtr &identifier) const = 0

Get one part’s lifecycle state.

Parameters:

identifier – The part identifier to resolve by name.

Throws:

err::LogicError – If the manager is not prepared or the identifier is unknown.

Returns:

The current part state.

virtual bool waitForRunning() = 0

Wait until the manager runs or reaches a terminal state.

Returns:

true if Running was reached; false for terminal failure or shutdown.

virtual bool waitForStopped() = 0

Wait until the manager stops or fails.

Returns:

true for Stopped; false for Failed.

virtual bool waitForRunning(const ApplicationPartIdentifierPtr &identifier) = 0

Wait until one part runs or reaches a terminal state.

Parameters:

identifier – The part identifier to resolve by name.

Returns:

true if Running was reached; false for terminal failure or shutdown.

virtual bool waitForStopped(const ApplicationPartIdentifierPtr &identifier) = 0

Wait until one part stops or fails.

Parameters:

identifier – The part identifier to resolve by name.

Returns:

true for Stopped; false for Failed.

virtual ApplicationPartPtr part(const ApplicationPartIdentifierPtr &identifier) const = 0

Access one prepared part by identifier.

Parameters:

identifier – The part identifier to resolve by name.

Throws:

err::LogicError – If the manager is not prepared or the identifier is unknown.

Returns:

The prepared application part.

template<ApplicationPartInterface T>
inline std::shared_ptr<T> part() const

Access one prepared part through its public interface.

Template Parameters:

T – The abstract part interface.

Throws:

err::LogicError – If the manager is not prepared, the identifier is unknown, or the registered part does not implement T.

Returns:

The prepared part implementing T.

class ApplicationPartManagerEventEditor

Editor for application-part manager lifecycle observers.

The manager owns this stable editor. Each added callback remains active while its returned subscription is retained.

Subclassed by erbsland::core::impl::ApplicationPartManager

Public Functions

virtual event::EventSubscription addStateChanged(ApplicationPartManagerStateChangedFn callback) = 0

Add a manager-state observer.

Parameters:

callback – The callback invoked for later manager-state transitions.

Returns:

A subscription retaining the observer.

virtual event::EventSubscription addPartStateChanged(ApplicationPartStateChangedFn callback) = 0

Add a part-state observer.

Parameters:

callback – The callback invoked for later part-state transitions.

Returns:

A subscription retaining the observer.

enum class erbsland::core::ApplicationPartManagerState : uint8_t

The lifecycle state of an application-part manager.

Values:

enumerator Uninitialized

Parts may still be registered.

enumerator Ready

The graph and all part instances are prepared.

enumerator Starting

Automatic startup is in progress.

enumerator Running

Automatic startup settled.

enumerator Stopping

Complete manager shutdown is in progress.

enumerator Stopped

The manager completed normal shutdown.

enumerator Failed

The manager completed shutdown after a fatal failure.

enum class erbsland::core::ApplicationPartState : uint8_t

The lifecycle state of an application part.

Values:

enumerator Uninitialized

The part was prepared but not started.

enumerator Starting

The part thread is running startup hooks.

enumerator Running

The part completed startup.

enumerator Stopping

The part is performing graceful shutdown.

enumerator Stopped

The part completed a normal one-shot lifecycle.

enumerator Failed

The part completed its lifecycle after a failure.

template<typename T>
concept ApplicationPartInterface
#include <erbsland/core/ApplicationPartTraits.hpp>

A public interface that identifies its application part.

template<typename T>
concept ApplicationPartClass
#include <erbsland/core/ApplicationPartTraits.hpp>

A concrete class that can be registered as an application part.

template<ApplicationPartInterface T>
class ApplicationPartWithInterface : public erbsland::core::ApplicationPart, public erbsland::core::T

An application-part base implementing one public interface.

Template Parameters:

T – The abstract part interface.

using erbsland::core::CommandLineArguments = text::StringList

A list of command line arguments.

using erbsland::core::InitializeFn = std::function<void()>

A initialize function override for an application.

enum class erbsland::core::LastErrorDumpMode : uint8_t

Select when an enabled retained-error snapshot is displayed during final application cleanup.

Values:

enumerator OnFailure

Display retained errors only after a nonzero application exit code.

enumerator Always

Display retained errors after every application run.

using erbsland::core::MainFn = std::function<unit::ExitCode()>

A main function override for an application.