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
Applicationinstance. Create an exported not inlined methodinitializeMyDll(Application &app)in each DLL that used Erbsland Core, and callApplication::linkWith(app)in this method. Frommain()call all theseinitialize...()methods of all DLLs that use Erbsland Core, just after creating theApplicationinstance. Do not useapplication()orApplication::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
mainor as one of the first lines in your custominitialize()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 callinitialize()orshutdown()from your user code. If a tty is detected,el::stdOut()andel::stdErr()are redirected to the terminal. Output fromel::stdOut()always resets the color to the default color while output fromel::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 viaterminal()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
expectedRemainingTimeis 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 anyerr::Exceptionis thrown from one of these methods or callbacks, it will be handled by callingcleanup()first, then printing the error tostdErr()and exiting the application with an exit code of 1. In case of ancore::ApplicationError, the exit code from the exception will be used. Any non-err::Exceptionpropagates 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 derivedinitialize()override must callApplication::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.
-
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.
-
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.
Access a prepared application part through its interface.
- Template Parameters:
T – The abstract part interface.
- Returns:
The prepared part implementing
T.
-
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 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.
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.
-
Application()
-
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 &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 const ApplicationErrorContext &context() const noexcept
Get the error context.
-
inline explicit ApplicationError(text::String reason, const std::exception_ptr &cause, const unit::ExitCode exitCode = unit::ExitCode::failure()) noexcept
-
class ApplicationInfo
Optional application metadata used by command line rendering.
-
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.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.
-
inline ApplicationPartState state() const noexcept
-
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.
-
virtual void registerCommandLineOptions(const options::OptionsPtr &options) = 0
-
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
Failedstate.
-
enumerator Continue
-
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.
Subclassed by erbsland::core::impl::ApplicationPartIdentifier
Public Functions
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
nameis invalid or longer than 200 characters.- Returns:
A new identifier with no manager-local cache.
-
static ApplicationPartIdentifierPtr create(text::String name)
-
class ApplicationPartManager : public erbsland::core::ApplicationPartManagerAccess
A detached manager for dependency-aware application parts.
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
controlEventsis 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.
-
template<ApplicationPartClass T>
-
class ApplicationPartManagerAccess
Thread-safe read and wait access to an application-part manager.
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:
trueifRunningwas reached;falsefor terminal failure or shutdown.
-
virtual bool waitForStopped() = 0
Wait until the manager stops or fails.
- Returns:
trueforStopped;falseforFailed.
-
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:
trueifRunningwas reached;falsefor 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:
trueforStopped;falseforFailed.
-
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.
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.
-
virtual ApplicationPartManagerState state() const noexcept = 0
-
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.
-
virtual event::EventSubscription addStateChanged(ApplicationPartManagerStateChangedFn callback) = 0
-
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.
-
enumerator Uninitialized
-
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.
-
enumerator Uninitialized
-
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.
-
enumerator OnFailure