verdure_context/lib.rs
1//! Verdure Application Context - Context Management for the Verdure Ecosystem
2//!
3//! This crate provides application context management as a core part of the Verdure ecosystem
4//! framework. It serves as the central hub for application-wide state, configuration,
5//! and environment management that integrates with all other Verdure modules.
6//!
7//! This module provides the foundation
8//! for configuration-driven development and environment-aware component behavior
9//! across the entire Verdure ecosystem.
10//!
11//! # Core Features
12//!
13//! * **Application Context**: Centralized application state management
14//! * **Configuration Management**: Hierarchical configuration system with multiple sources
15//! * **Event Broadcasting**: Application-wide event system for decoupled communication
16//! * **IoC Integration**: Seamless integration with the Verdure IoC container
17//! * **Type-Safe Configuration**: Strongly-typed configuration value access
18//!
19//! # Quick Start
20//!
21//! ## Basic Usage
22//!
23//! ```rust
24//! use verdure_context::{ApplicationContext, ConfigSource};
25//! use std::collections::HashMap;
26//!
27//! // Create and configure application context
28//! let context = ApplicationContext::builder()
29//! .with_property("app.name", "MyApp")
30//! .with_property("app.port", "8080")
31//! .build()
32//! .unwrap();
33//!
34//! // Initialize the context
35//! context.initialize().unwrap();
36//!
37//! // Access configuration
38//! let app_name = context.get_config("app.name");
39//! let port: i64 = context.get_config_as("app.port").unwrap();
40//!
41//! println!("Starting {} on port {}", app_name, port);
42//! ```
43//!
44//! ## Configuration from Files
45//!
46//! Verdure Context supports multiple configuration file formats:
47//!
48//! ### TOML Configuration
49//!
50//! ```rust,no_run
51//! use verdure_context::ApplicationContext;
52//!
53//! let context = ApplicationContext::builder()
54//! .with_toml_config_file("config/app.toml")
55//! .build()
56//! .unwrap();
57//! ```
58//!
59//! ### YAML Configuration
60//!
61//! ```rust,no_run
62//! use verdure_context::ApplicationContext;
63//!
64//! let context = ApplicationContext::builder()
65//! .with_yaml_config_file("config/app.yaml")
66//! .build()
67//! .unwrap();
68//! ```
69//!
70//! ### Properties Configuration
71//!
72//! ```rust,no_run
73//! use verdure_context::ApplicationContext;
74//!
75//! let context = ApplicationContext::builder()
76//! .with_properties_config_file("config/app.properties")
77//! .build()
78//! .unwrap();
79//! ```
80//!
81//! ### Auto-Detection
82//!
83//! ```rust,no_run
84//! use verdure_context::ApplicationContext;
85//!
86//! // Format is auto-detected based on file extension
87//! let context = ApplicationContext::builder()
88//! .with_config_file("config/app.yaml") // YAML
89//! .with_config_file("config/db.properties") // Properties
90//! .with_config_file("config/server.toml") // TOML
91//! .build()
92//! .unwrap();
93//! ```
94//!
95//! ## Event System
96//!
97//! ```rust
98//! use verdure_context::{ApplicationContext, Event, EventListener};
99//! use std::any::Any;
100//!
101//! // Define an event
102//! #[derive(Debug, Clone)]
103//! struct UserRegisteredEvent {
104//! pub user_id: u64,
105//! pub email: String,
106//! }
107//!
108//! impl Event for UserRegisteredEvent {
109//! fn name(&self) -> &'static str {
110//! "UserRegistered"
111//! }
112//!
113//! fn as_any(&self) -> &dyn Any {
114//! self
115//! }
116//!
117//! fn into_any(self: Box<Self>) -> Box<dyn Any> {
118//! self
119//! }
120//! }
121//!
122//! // Create event listener
123//! struct EmailNotificationListener;
124//!
125//! impl EventListener<UserRegisteredEvent> for EmailNotificationListener {
126//! fn on_event(&self, event: &UserRegisteredEvent) {
127//! println!("Sending welcome email to user {} ({})",
128//! event.user_id, event.email);
129//! }
130//! }
131//!
132//! // Set up context with event handling
133//! let mut context = ApplicationContext::new();
134//! context.subscribe_to_events(EmailNotificationListener);
135//!
136//! // Publish events
137//! let event = UserRegisteredEvent {
138//! user_id: 123,
139//! email: "user@example.com".to_string(),
140//! };
141//! context.publish_event(&event);
142//! ```
143//!
144//! ## IoC Container Integration
145//!
146//! ```rust
147//! use verdure_context::ApplicationContext;
148//! use std::sync::Arc;
149//!
150//! #[derive(Debug)]
151//! struct DatabaseService {
152//! connection_url: String,
153//! }
154//!
155//! let context = ApplicationContext::builder()
156//! .with_property("database.url", "postgres://localhost/myapp")
157//! .build()
158//! .unwrap();
159//!
160//! // Register components with the container
161//! let db_service = Arc::new(DatabaseService {
162//! connection_url: context.get_config("database.url"),
163//! });
164//! context.container().register_component(db_service);
165//!
166//! // Retrieve components
167//! let retrieved: Option<Arc<DatabaseService>> = context.get_component();
168//! assert!(retrieved.is_some());
169//! ```
170//!
171//! # Advanced Features
172//!
173//! ## Configuration Sources Priority
174//!
175//! Configuration sources are resolved in the following order (highest to lowest precedence):
176//!
177//! 1. **Runtime Properties**: Values set via `set_config()`
178//! 2. **Configuration Sources**: Sources added via `add_config_source()` (last added wins)
179//! 3. **Environment Variables**: System environment variables
180//! 4. **Configuration Files**: Files loaded via various methods (last added wins)
181//! - TOML files (`.toml`)
182//! - YAML files (`.yaml`, `.yml`)
183//! - Properties files (`.properties`)
184//!
185//! ## Supported Configuration Formats
186//!
187//! ### TOML Format Example
188//!
189//! ```toml
190//! # app.toml
191//! [app]
192//! name = "MyApplication"
193//! port = 8080
194//! debug = true
195//!
196//! [database]
197//! host = "localhost"
198//! port = 5432
199//! name = "myapp"
200//! ```
201//!
202//! ### YAML Format Example
203//!
204//! ```yaml
205//! # app.yaml
206//! app:
207//! name: MyApplication
208//! port: 8080
209//! debug: true
210//! features:
211//! - auth
212//! - logging
213//!
214//! database:
215//! host: localhost
216//! port: 5432
217//! name: myapp
218//! ```
219//!
220//! ### Properties Format Example
221//!
222//! ```properties
223//! # app.properties
224//! app.name=MyApplication
225//! app.port=8080
226//! app.debug=true
227//!
228//! database.host=localhost
229//! database.port=5432
230//! database.name=myapp
231//! ```
232//!
233//! All formats are converted to a flat key-value structure using dot notation
234//! (e.g., `app.name`, `database.host`) for consistent access patterns.
235//!
236//! # Ecosystem Context Events
237//!
238//! The context system publishes several built-in events that applications can listen to.
239//! There are two ways to listen to events:
240//!
241//! 1. **Regular Event Listeners**: Receive only the event data
242//! 2. **Context-Aware Event Listeners**: Receive both the event and ApplicationContext reference
243//!
244//! ## Built-in Lifecycle Events
245//!
246//! ### ContextInitializingEvent
247//!
248//! **When**: Fired at the very beginning of context initialization, before any actual work begins.
249//! **Purpose**: Allows listeners to prepare for context startup or log initialization start.
250//! **Data**: Configuration sources count, active profiles count, and timestamp.
251//!
252//! ### ContextInitializedEvent
253//!
254//! **When**: Fired after the context is fully initialized, including all configuration sources, profiles, and IoC container.
255//! **Purpose**: Ideal for application startup tasks that require a fully configured context.
256//! **Data**: Final configuration sources count, active profiles count, and timestamp.
257//!
258//! ### ProfileActivatedEvent
259//!
260//! **When**: Fired whenever a profile is activated during context building.
261//! **Purpose**: Allows listeners to react to environment changes or profile-specific setup.
262//! **Data**: Profile name, properties count in the profile, and timestamp.
263//!
264//! ### ConfigurationChangedEvent
265//!
266//! **When**: Fired when configuration values are updated at runtime after context initialization.
267//! **Purpose**: Enables reactive configuration updates and change tracking.
268//! **Data**: Configuration key, old value (if any), new value, and timestamp.
269//!
270//! ## Context-Aware Event Listeners (Recommended for Lifecycle Events)
271//!
272//! Context-aware listeners can access the ApplicationContext during event handling,
273//! making them perfect for lifecycle events where you need to interact with the context:
274//!
275//! ```rust
276//! use verdure_context::{ApplicationContext, ContextInitializedEvent, ContextAwareEventListener};
277//!
278//! struct StartupTasks;
279//!
280//! impl ContextAwareEventListener<ContextInitializedEvent> for StartupTasks {
281//! fn on_context_event(&self, event: &ContextInitializedEvent, context: &ApplicationContext) {
282//! println!("🚀 Context initialized with {} sources!", event.config_sources_count);
283//!
284//! // Access configuration
285//! let app_name = context.get_config("app.name");
286//! println!("📱 Starting application: {}", app_name);
287//!
288//! // Access IoC container for dependency injection setup
289//! let container = context.container();
290//! // Setup your components...
291//!
292//! // Check environment
293//! let env = context.environment();
294//! println!("🌍 Running in {} environment", env);
295//! }
296//! }
297//!
298//! let mut context = ApplicationContext::builder()
299//! .with_property("app.name", "MyApp")
300//! .build()
301//! .unwrap();
302//!
303//! context.subscribe_to_context_events(StartupTasks);
304//! context.initialize().unwrap(); // Triggers the context-aware listener
305//! ```
306//!
307//! ## ContextInitializingEvent Usage
308//!
309//! Listen to preparation phases before initialization:
310//!
311//! ```rust
312//! use verdure_context::{ApplicationContext, ContextInitializingEvent, ContextAwareEventListener};
313//!
314//! struct PreStartupListener;
315//!
316//! impl ContextAwareEventListener<ContextInitializingEvent> for PreStartupListener {
317//! fn on_context_event(&self, event: &ContextInitializingEvent, context: &ApplicationContext) {
318//! println!("🔧 Context initializing with {} sources...",
319//! event.config_sources_count);
320//!
321//! // Pre-initialization tasks
322//! let startup_time = event.timestamp;
323//! println!("⏰ Startup began at: {:?}", startup_time);
324//! }
325//! }
326//! ```
327//!
328//!
329//! ## ConfigurationChangedEvent Usage
330//!
331//! Track runtime configuration changes:
332//!
333//! ```rust
334//! use verdure_context::{ApplicationContext, ConfigurationChangedEvent, EventListener};
335//!
336//! struct ConfigListener;
337//!
338//! impl EventListener<ConfigurationChangedEvent> for ConfigListener {
339//! fn on_event(&self, event: &ConfigurationChangedEvent) {
340//! match &event.old_value {
341//! Some(old) => println!("⚙️ Configuration '{}' changed from '{}' to '{}'",
342//! event.key, old, event.new_value),
343//! None => println!("➕ Configuration '{}' set to '{}'",
344//! event.key, event.new_value),
345//! }
346//! }
347//! }
348//!
349//! let mut context = ApplicationContext::new();
350//! context.subscribe_to_events(ConfigListener);
351//! context.set_config("app.mode", "production");
352//! ```
353//!
354//! ## Event System Architecture
355//!
356//! The event system supports both regular and context-aware listeners simultaneously:
357//!
358//! - **Regular listeners** (`EventListener<T>`) receive only the event data
359//! - **Context-aware listeners** (`ContextAwareEventListener<T>`) receive both event data and ApplicationContext reference
360//! - Both types can be registered for the same event type
361//! - Events are published to all registered listeners of the appropriate type
362//! - Lifecycle events automatically provide context access for enhanced integration capabilities
363
364pub mod config;
365pub mod context;
366pub mod error;
367pub mod event;
368
369// Re-export main types for convenience
370pub use config::{ConfigManager, ConfigSource, ConfigValue};
371pub use context::{ApplicationContext, ApplicationContextBuilder};
372pub use error::{ContextError, ContextResult};
373pub use event::{
374 AnyContextAwareEventListener, AnyEventListener, ConfigurationChangedEvent,
375 ContextAwareEventListener, ContextInitializedEvent, ContextInitializingEvent, Event,
376 EventListener, EventPublisher,
377};