Skip to main content

verdure_context/
context.rs

1//! Application context implementation
2//!
3//! This module provides the main `ApplicationContext` implementation that serves as the
4//! central hub for application-wide state, configuration, environment management, and
5//! integration with the IoC container.
6
7use crate::config::{ConfigFactory, ConfigManager, ConfigSource, ConfigValue};
8use crate::error::{ContextError, ContextResult};
9use crate::event::{
10    ConfigurationChangedEvent, ContextAwareEventListener, ContextInitializedEvent,
11    ContextInitializingEvent, Event, EventListener, EventPublisher,
12};
13use dashmap::DashMap;
14use std::path::Path;
15use std::sync::Arc;
16use verdure_ioc::{ComponentContainer, ComponentFactory, ComponentInstance};
17
18/// Application context builder
19///
20/// `ApplicationContextBuilder` provides a fluent API for constructing
21/// an `ApplicationContext` with various configuration sources, profiles,
22/// and settings.
23///
24/// # Examples
25///
26/// ```rust
27/// use verdure_context::ApplicationContextBuilder;
28///
29/// let context = ApplicationContextBuilder::new()
30///     .with_property("app.name", "MyApp")
31///     .build()
32///     .unwrap();
33/// ```
34#[derive(Debug)]
35pub struct ApplicationContextBuilder {
36    config_sources: Vec<ConfigSource>,
37    properties: std::collections::HashMap<String, String>,
38}
39
40impl ApplicationContextBuilder {
41    /// Creates a new application context builder
42    ///
43    /// # Examples
44    ///
45    /// ```rust
46    /// use verdure_context::ApplicationContextBuilder;
47    ///
48    /// let builder = ApplicationContextBuilder::new();
49    /// ```
50    pub fn new() -> Self {
51        Self {
52            config_sources: Vec::new(),
53            properties: std::collections::HashMap::new(),
54        }
55    }
56
57    /// Adds a configuration source
58    ///
59    /// # Arguments
60    ///
61    /// * `source` - The configuration source to add
62    ///
63    /// # Examples
64    ///
65    /// ```rust
66    /// use verdure_context::{ApplicationContextBuilder, ConfigSource};
67    /// use std::collections::HashMap;
68    ///
69    /// let builder = ApplicationContextBuilder::new()
70    ///     .with_config_source(ConfigSource::Environment);
71    /// ```
72    pub fn with_config_source(mut self, source: ConfigSource) -> Self {
73        self.config_sources.push(source);
74        self
75    }
76
77    /// Loads configuration from a TOML file
78    ///
79    /// # Arguments
80    ///
81    /// * `path` - Path to the TOML configuration file
82    ///
83    /// # Examples
84    ///
85    /// ```rust
86    /// use verdure_context::ApplicationContextBuilder;
87    ///
88    /// let builder = ApplicationContextBuilder::new()
89    ///     .with_toml_config_file("config/app.toml");
90    /// ```
91    pub fn with_toml_config_file<P: AsRef<Path>>(mut self, path: P) -> Self {
92        let path_str = path.as_ref().to_string_lossy().to_string();
93        self.config_sources.push(ConfigSource::TomlFile(path_str));
94        self
95    }
96
97    /// Loads configuration from a YAML file
98    ///
99    /// # Arguments
100    ///
101    /// * `path` - Path to the YAML configuration file
102    ///
103    /// # Examples
104    ///
105    /// ```rust
106    /// use verdure_context::ApplicationContextBuilder;
107    ///
108    /// let builder = ApplicationContextBuilder::new()
109    ///     .with_yaml_config_file("config/app.yaml");
110    /// ```
111    pub fn with_yaml_config_file<P: AsRef<Path>>(mut self, path: P) -> Self {
112        let path_str = path.as_ref().to_string_lossy().to_string();
113        self.config_sources.push(ConfigSource::YamlFile(path_str));
114        self
115    }
116
117    /// Loads configuration from a Properties file
118    ///
119    /// # Arguments
120    ///
121    /// * `path` - Path to the Properties configuration file
122    ///
123    /// # Examples
124    ///
125    /// ```rust
126    /// use verdure_context::ApplicationContextBuilder;
127    ///
128    /// let builder = ApplicationContextBuilder::new()
129    ///     .with_properties_config_file("config/app.properties");
130    /// ```
131    pub fn with_properties_config_file<P: AsRef<Path>>(mut self, path: P) -> Self {
132        let path_str = path.as_ref().to_string_lossy().to_string();
133        self.config_sources
134            .push(ConfigSource::PropertiesFile(path_str));
135        self
136    }
137
138    /// Loads configuration from a file with automatic format detection
139    ///
140    /// The format is detected based on the file extension:
141    /// - `.toml` -> TOML format
142    /// - `.yaml` or `.yml` -> YAML format  
143    /// - `.properties` -> Properties format
144    /// - Others -> Attempts to parse as TOML first, then YAML, then Properties
145    ///
146    /// # Arguments
147    ///
148    /// * `path` - Path to the configuration file
149    ///
150    /// # Examples
151    ///
152    /// ```rust
153    /// use verdure_context::ApplicationContextBuilder;
154    ///
155    /// let builder = ApplicationContextBuilder::new()
156    ///     .with_config_file("config/app.yaml")
157    ///     .with_config_file("config/database.properties")
158    ///     .with_config_file("config/server.toml");
159    /// ```
160    pub fn with_config_file<P: AsRef<Path>>(mut self, path: P) -> Self {
161        let path_str = path.as_ref().to_string_lossy().to_string();
162        self.config_sources.push(ConfigSource::ConfigFile(path_str));
163        self
164    }
165
166    /// Sets a property value
167    ///
168    /// # Arguments
169    ///
170    /// * `key` - The property key
171    /// * `value` - The property value
172    ///
173    /// # Examples
174    ///
175    /// ```rust
176    /// use verdure_context::ApplicationContextBuilder;
177    ///
178    /// let builder = ApplicationContextBuilder::new()
179    ///     .with_property("app.name", "MyApplication");
180    /// ```
181    pub fn with_property(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
182        self.properties.insert(key.into(), value.into());
183        self
184    }
185
186    /// Builds the application context
187    ///
188    /// # Returns
189    ///
190    /// A new `ApplicationContext` instance configured with the specified settings
191    ///
192    /// # Errors
193    ///
194    /// Returns an error if context initialization fails
195    ///
196    /// # Examples
197    ///
198    /// ```rust
199    /// use verdure_context::ApplicationContextBuilder;
200    ///
201    /// let context = ApplicationContextBuilder::new()
202    ///     .with_property("app.name", "MyApp")
203    ///     .build()
204    ///     .unwrap();
205    /// ```
206    pub fn build(self) -> ContextResult<ApplicationContext> {
207        let context = ApplicationContext::new();
208
209        // Add configuration sources
210        for source in self.config_sources {
211            context.config_manager.add_source(source)?;
212        }
213
214        // Add properties as a configuration source
215        if !self.properties.is_empty() {
216            context
217                .config_manager
218                .add_source(ConfigSource::Properties(self.properties))?;
219        }
220
221        Ok(context)
222    }
223}
224
225impl Default for ApplicationContextBuilder {
226    fn default() -> Self {
227        Self::new()
228    }
229}
230
231/// Main application context
232///
233/// `ApplicationContext` serves as the central hub for application-wide services,
234/// configuration, environment management, and integration with the IoC container.
235/// It provides a unified interface for accessing all framework services.
236///
237/// # Examples
238///
239/// ```rust
240/// use verdure_context::ApplicationContext;
241///
242/// let context = ApplicationContext::builder()
243///     .with_property("app.name", "MyApp")
244///     .build()
245///     .unwrap();
246///
247/// // Access configuration
248/// let app_name = context.get_config("app.name");
249///
250/// // Access IoC container
251/// let container = context.container();
252/// ```
253pub struct ApplicationContext {
254    /// Configuration manager
255    config_manager: Arc<ConfigManager>,
256    /// Event publisher for application-wide events
257    event_publisher: EventPublisher,
258    /// IoC container integration
259    container: Arc<ComponentContainer>,
260    /// Application properties cache
261    properties_cache: DashMap<String, ConfigValue>,
262}
263
264impl ApplicationContext {
265    /// Creates a new application context
266    ///
267    /// # Examples
268    ///
269    /// ```rust
270    /// use verdure_context::ApplicationContext;
271    ///
272    /// let context = ApplicationContext::new();
273    /// ```
274    pub fn new() -> Self {
275        Self {
276            config_manager: Arc::new(ConfigManager::new()),
277            event_publisher: EventPublisher::new(),
278            container: Arc::new(ComponentContainer::new()),
279            properties_cache: DashMap::new(),
280        }
281    }
282
283    /// Creates a builder for constructing an application context
284    ///
285    /// # Examples
286    ///
287    /// ```rust
288    /// use verdure_context::ApplicationContext;
289    ///
290    /// let context = ApplicationContext::builder()
291    ///     .with_property("app.version", "1.0.0")
292    ///     .build()
293    ///     .unwrap();
294    /// ```
295    pub fn builder() -> ApplicationContextBuilder {
296        ApplicationContextBuilder::new()
297    }
298    fn initialize_early(&self) -> ContextResult<()> {
299        self.container.register_component(self.config_manager.clone());
300
301        for factory in inventory::iter::<ConfigFactory> {
302            let config_component = (factory.create_fn)(self.config_manager.clone())?;
303            self.container.register_component(config_component);
304        }
305        Ok(())
306    }
307    /// Initializes the application context
308    ///
309    /// This method initializes the IoC container and performs any other
310    /// necessary initialization steps.
311    ///
312    /// # Returns
313    ///
314    /// `Ok(())` if initialization succeeds, an error otherwise
315    ///
316    /// # Examples
317    ///
318    /// ```rust
319    /// use verdure_context::ApplicationContext;
320    ///
321    /// let context = ApplicationContext::new();
322    /// context.initialize().unwrap();
323    /// ```
324    pub fn initialize(&self) -> ContextResult<()> {
325        self.initialize_early()?;
326        // Publish context-initializing event at the start
327        let initializing_event = ContextInitializingEvent {
328            config_sources_count: self.config_manager.sources_count(),
329            timestamp: std::time::SystemTime::now(),
330        };
331        self.event_publisher
332            .publish_with_context(&initializing_event, self);
333
334        // Initialize the IoC container
335        self.container.initialize().map_err(|e| {
336            ContextError::initialization_failed(format!(
337                "IoC container initialization failed: {}",
338                e
339            ))
340        })?;
341
342        // Publish context initialized event at the end
343        let initialized_event = ContextInitializedEvent {
344            config_sources_count: self.config_manager.sources_count(),
345            timestamp: std::time::SystemTime::now(),
346        };
347        self.event_publisher
348            .publish_with_context(&initialized_event, self);
349
350        Ok(())
351    }
352
353    /// Gets a configuration value by key
354    ///
355    /// # Arguments
356    ///
357    /// * `key` - The configuration key
358    ///
359    /// # Returns
360    ///
361    /// The configuration value as a string, or an empty string if not found
362    ///
363    /// # Examples
364    ///
365    /// ```rust
366    /// use verdure_context::{ApplicationContext, ConfigSource};
367    /// use std::collections::HashMap;
368    ///
369    /// let mut context = ApplicationContext::new();
370    ///
371    /// let mut props = HashMap::new();
372    /// props.insert("app.name".to_string(), "MyApp".to_string());
373    /// context.add_config_source(ConfigSource::Properties(props)).unwrap();
374    ///
375    /// assert_eq!(context.get_config("app.name"), "MyApp");
376    /// ```
377    pub fn get_config(&self, key: &str) -> String {
378        self.config_manager.get_string_or_default(key, "")
379    }
380
381    /// Gets a configuration value as a specific type
382    ///
383    /// # Arguments
384    ///
385    /// * `key` - The configuration key
386    ///
387    /// # Returns
388    ///
389    /// The configuration value parsed as the requested type
390    ///
391    /// # Errors
392    ///
393    /// Returns an error if the key is not found or cannot be parsed as the requested type
394    ///
395    /// # Examples
396    ///
397    /// ```rust
398    /// use verdure_context::{ApplicationContext, ConfigSource};
399    /// use std::collections::HashMap;
400    ///
401    /// let mut context = ApplicationContext::new();
402    ///
403    /// let mut props = HashMap::new();
404    /// props.insert("app.port".to_string(), "8080".to_string());
405    /// context.add_config_source(ConfigSource::Properties(props)).unwrap();
406    ///
407    /// let port: i64 = context.get_config_as("app.port").unwrap();
408    /// assert_eq!(port, 8080);
409    /// ```
410    pub fn get_config_as<T>(&self, key: &str) -> ContextResult<T>
411    where
412        T: std::str::FromStr,
413        T::Err: std::fmt::Display,
414    {
415        let value = self.config_manager.get_string(key)?;
416        value
417            .parse::<T>()
418            .map_err(|e| ContextError::invalid_configuration(key, e.to_string()))
419    }
420
421    /// Gets a configuration value with a default
422    ///
423    /// # Arguments
424    ///
425    /// * `key` - The configuration key
426    /// * `default` - The default value to return if key is not found
427    ///
428    /// # Examples
429    ///
430    /// ```rust
431    /// use verdure_context::ApplicationContext;
432    ///
433    /// let context = ApplicationContext::new();
434    /// let port = context.get_config_or_default("app.port", "8080");
435    /// assert_eq!(port, "8080");
436    /// ```
437    pub fn get_config_or_default(&self, key: &str, default: &str) -> String {
438        self.config_manager.get_string_or_default(key, default)
439    }
440
441    /// Sets a configuration property
442    ///
443    /// # Arguments
444    ///
445    /// * `key` - The configuration key
446    /// * `value` - The configuration value
447    ///
448    /// # Examples
449    ///
450    /// ```rust
451    /// use verdure_context::ApplicationContext;
452    ///
453    /// let mut context = ApplicationContext::new();
454    /// context.set_config("runtime.property", "runtime.value");
455    ///
456    /// assert_eq!(context.get_config("runtime.property"), "runtime.value");
457    /// ```
458    /// Sets a configuration property
459    pub fn set_config(&self, key: &str, value: &str) {
460        let old_value = self.get_config(key);
461        let old_value_opt = if old_value.is_empty() {
462            None
463        } else {
464            Some(old_value)
465        };
466
467        self.config_manager
468            .set(key, ConfigValue::String(value.to_string()));
469
470        let event = ConfigurationChangedEvent {
471            key: key.to_string(),
472            old_value: old_value_opt,
473            new_value: value.to_string(),
474            timestamp: std::time::SystemTime::now(),
475        };
476        self.event_publisher.publish(&event);
477    }
478
479    /// Adds a configuration source
480    pub fn add_config_source(&self, source: ConfigSource) -> ContextResult<()> {
481        self.config_manager.add_source(source)
482    }
483
484    /// Gets the IoC container
485    ///
486    /// # Returns
487    ///
488    /// A reference to the IoC container
489    ///
490    /// # Examples
491    ///
492    /// ```rust
493    /// use verdure_context::ApplicationContext;
494    ///
495    /// let context = ApplicationContext::new();
496    /// let container = context.container();
497    /// ```
498    pub fn container(&self) -> Arc<ComponentContainer> {
499        self.container.clone()
500    }
501    
502    /// Gets a shared reference to the ConfigManager for IoC registration
503    pub fn config_manager(&self) -> Arc<ConfigManager> {
504        self.config_manager.clone()
505    }
506
507    /// Gets a component from the IoC container
508    ///
509    /// # Returns
510    ///
511    /// The requested component if found
512    ///
513    /// # Examples
514    ///
515    /// ```rust
516    /// use verdure_context::ApplicationContext;
517    /// use std::sync::Arc;
518    ///
519    /// #[derive(Debug)]
520    /// struct MyService {
521    ///     name: String,
522    /// }
523    ///
524    /// let context = ApplicationContext::new();
525    ///
526    /// // First register the component
527    /// let service = Arc::new(MyService {
528    ///     name: "TestService".to_string(),
529    /// });
530    /// context.container().register_component(service);
531    ///
532    /// // Then retrieve it
533    /// let retrieved: Option<Arc<MyService>> = context.get_component();
534    /// assert!(retrieved.is_some());
535    /// ```
536    pub fn get_component<T: 'static + Send + Sync>(&self) -> Option<Arc<T>> {
537        self.container.get_component()
538    }
539    /// Registers a pre-created component instance with the context container
540    pub fn register_component(&self, instance: ComponentInstance) {
541        self.container.register_component(instance)
542    }
543
544    /// Publishes an event
545    ///
546    /// # Arguments
547    ///
548    /// * `event` - The event to publish
549    ///
550    /// # Examples
551    ///
552    /// ```rust
553    /// use verdure_context::{ApplicationContext, Event};
554    /// use std::any::Any;
555    ///
556    /// #[derive(Debug, Clone)]
557    /// struct MyEvent {
558    ///     message: String,
559    /// }
560    ///
561    /// impl Event for MyEvent {
562    ///     fn name(&self) -> &'static str { "MyEvent" }
563    ///     fn as_any(&self) -> &dyn Any { self }
564    ///     fn into_any(self: Box<Self>) -> Box<dyn Any> { self }
565    /// }
566    ///
567    /// let context = ApplicationContext::new();
568    /// let event = MyEvent {
569    ///     message: "Hello, World!".to_string(),
570    /// };
571    ///
572    /// context.publish_event(&event);
573    /// ```
574    pub fn publish_event<T: Event + 'static>(&self, event: &T) {
575        self.event_publisher.publish(event);
576    }
577
578    /// Subscribes to events with context access
579    ///
580    /// Context-aware listeners receive both the event and a reference to the ApplicationContext,
581    /// allowing them to interact with the context during event handling.
582    ///
583    /// # Arguments
584    ///
585    /// * `listener` - The context-aware event listener to register
586    ///
587    /// # Examples
588    ///
589    /// ```rust
590    /// use verdure_context::{ApplicationContext, ContextInitializedEvent, ContextAwareEventListener};
591    ///
592    /// struct StartupListener;
593    ///
594    /// impl ContextAwareEventListener<ContextInitializedEvent> for StartupListener {
595    ///     fn on_context_event(&self, event: &ContextInitializedEvent, context: &ApplicationContext) {
596    ///         println!("Context initialized! App name: {}", context.get_config("app.name"));
597    ///         println!("Environment: {}", context.environment());
598    ///     }
599    /// }
600    ///
601    /// let mut context = ApplicationContext::new();
602    /// context.subscribe_to_context_events(StartupListener);
603    /// ```
604    /// Subscribes to events with context access
605    pub fn subscribe_to_context_events<
606        T: Event + 'static,
607        L: ContextAwareEventListener<T> + 'static,
608    >(
609        &self,
610        listener: L,
611    ) {
612        self.event_publisher.subscribe_context_aware(listener);
613    }
614    ///
615    /// # Arguments
616    ///
617    /// * `listener` - The event listener to register
618    ///
619    /// # Examples
620    ///
621    /// ```rust
622    /// use verdure_context::{ApplicationContext, Event, EventListener};
623    /// use std::any::Any;
624    ///
625    /// #[derive(Debug, Clone)]
626    /// struct TestEvent;
627    ///
628    /// impl Event for TestEvent {
629    ///     fn name(&self) -> &'static str { "TestEvent" }
630    ///     fn as_any(&self) -> &dyn Any { self }
631    ///     fn into_any(self: Box<Self>) -> Box<dyn Any> { self }
632    /// }
633    ///
634    /// struct TestListener;
635    ///
636    /// impl EventListener<TestEvent> for TestListener {
637    ///     fn on_event(&self, _event: &TestEvent) {
638    ///         println!("Event received!");
639    ///     }
640    /// }
641    ///
642    /// let mut context = ApplicationContext::new();
643    /// context.subscribe_to_events(TestListener);
644    /// ```
645    /// Subscribes to events
646    pub fn subscribe_to_events<T: Event + 'static, L: EventListener<T> + 'static>(
647        &self,
648        listener: L,
649    ) {
650        self.event_publisher.subscribe(listener);
651    }
652
653    /// Gets environment information
654    ///
655    /// # Returns
656    ///
657    /// A string representing the current environment
658    ///
659    /// # Examples
660    ///
661    /// ```rust
662    /// use verdure_context::ApplicationContext;
663    ///
664    /// let context = ApplicationContext::new();
665    /// println!("Environment: {}", context.environment());
666    /// ```
667    pub fn environment(&self) -> String {
668        "default".to_string()
669    }
670}
671
672impl Default for ApplicationContext {
673    fn default() -> Self {
674        Self::new()
675    }
676}
677
678#[cfg(test)]
679mod tests {
680    use super::*;
681    use std::collections::HashMap;
682
683    #[test]
684    fn test_application_context_creation() {
685        let context = ApplicationContext::new();
686        // Context created successfully
687        assert_eq!(context.environment(), "default");
688    }
689
690    #[test]
691    fn test_application_context_builder() {
692        let context = ApplicationContext::builder()
693            .with_property("app.name", "TestApp")
694            .build()
695            .unwrap();
696
697        assert_eq!(context.get_config("app.name"), "TestApp");
698    }
699
700    #[test]
701    fn test_configuration_management() {
702        let context = ApplicationContext::new();
703
704        let mut props = HashMap::new();
705        props.insert(
706            "database.url".to_string(),
707            "postgres://localhost/test".to_string(),
708        );
709        props.insert("server.port".to_string(), "3000".to_string());
710        props.insert("debug.enabled".to_string(), "true".to_string());
711
712        context
713            .add_config_source(ConfigSource::Properties(props))
714            .unwrap();
715
716        assert_eq!(
717            context.get_config("database.url"),
718            "postgres://localhost/test"
719        );
720
721        let port: i64 = context.get_config_as("server.port").unwrap();
722        assert_eq!(port, 3000);
723
724        let debug: bool = context.get_config_as("debug.enabled").unwrap();
725        assert_eq!(debug, true);
726    }
727
728    #[test]
729    fn test_configuration_with_defaults() {
730        let context = ApplicationContext::new();
731
732        assert_eq!(context.get_config("missing.key"), "");
733        assert_eq!(
734            context.get_config_or_default("missing.key", "default"),
735            "default"
736        );
737    }
738
739    #[test]
740    fn test_runtime_configuration() {
741        let context = ApplicationContext::new();
742
743        context.set_config("runtime.property", "runtime.value");
744        assert_eq!(context.get_config("runtime.property"), "runtime.value");
745    }
746
747
748    #[test]
749    fn test_environment_default() {
750        let context = ApplicationContext::new();
751        assert_eq!(context.environment(), "default");
752    }
753
754    #[test]
755    fn test_container_integration() {
756        let context = ApplicationContext::new();
757        let container = context.container();
758
759        // Test that we can access the container
760        assert!(container.get_component::<String>().is_none());
761    }
762
763    // Test event system integration
764    use std::any::Any;
765
766    #[derive(Debug, Clone)]
767    struct TestContextEvent {
768        message: String,
769    }
770
771    impl Event for TestContextEvent {
772        fn name(&self) -> &'static str {
773            "TestContextEvent"
774        }
775
776        fn as_any(&self) -> &dyn Any {
777            self
778        }
779
780        fn into_any(self: Box<Self>) -> Box<dyn Any> {
781            self
782        }
783    }
784
785    struct TestContextListener {
786        received: Arc<std::sync::Mutex<Vec<String>>>,
787    }
788
789    impl EventListener<TestContextEvent> for TestContextListener {
790        fn on_event(&self, event: &TestContextEvent) {
791            let mut received = self.received.lock().unwrap();
792            received.push(event.message.clone());
793        }
794    }
795
796    #[test]
797    fn test_event_system_integration() {
798        let received = Arc::new(std::sync::Mutex::new(Vec::new()));
799        let listener = TestContextListener {
800            received: received.clone(),
801        };
802
803        let context = ApplicationContext::new();
804        context.subscribe_to_events(listener);
805
806        let event = TestContextEvent {
807            message: "test message".to_string(),
808        };
809
810        context.publish_event(&event);
811
812        let received_messages = received.lock().unwrap();
813        assert_eq!(received_messages.len(), 1);
814        assert_eq!(received_messages[0], "test message");
815    }
816
817    #[test]
818    fn test_built_in_context_events() {
819        use crate::event::{
820            ConfigurationChangedEvent, ContextInitializedEvent, ContextInitializingEvent,
821        };
822        use std::sync::{Arc, Mutex};
823
824        // Event collectors
825        let initializing_events = Arc::new(Mutex::new(Vec::new()));
826        let initialized_events = Arc::new(Mutex::new(Vec::new()));
827        let config_events = Arc::new(Mutex::new(Vec::new()));
828
829        // Event listeners
830        struct InitializingListener(Arc<Mutex<Vec<ContextInitializingEvent>>>);
831        impl EventListener<ContextInitializingEvent> for InitializingListener {
832            fn on_event(&self, event: &ContextInitializingEvent) {
833                let mut events = self.0.lock().unwrap();
834                events.push(event.clone());
835            }
836        }
837
838        struct InitializedListener(Arc<Mutex<Vec<ContextInitializedEvent>>>);
839        impl EventListener<ContextInitializedEvent> for InitializedListener {
840            fn on_event(&self, event: &ContextInitializedEvent) {
841                let mut events = self.0.lock().unwrap();
842                events.push(event.clone());
843            }
844        }
845
846        struct ConfigListener(Arc<Mutex<Vec<ConfigurationChangedEvent>>>);
847        impl EventListener<ConfigurationChangedEvent> for ConfigListener {
848            fn on_event(&self, event: &ConfigurationChangedEvent) {
849                let mut events = self.0.lock().unwrap();
850                events.push(event.clone());
851            }
852        }
853
854        // Create context with configuration
855        let context = ApplicationContext::builder()
856            .with_property("initial.key", "initial.value")
857            .build()
858            .unwrap();
859
860        // Subscribe to events BEFORE initialization
861        context.subscribe_to_events(InitializingListener(initializing_events.clone()));
862        context.subscribe_to_events(InitializedListener(initialized_events.clone()));
863        context.subscribe_to_events(ConfigListener(config_events.clone()));
864
865        // Initialize context (should fire both ContextInitializingEvent and ContextInitializedEvent)
866        context.initialize().unwrap();
867
868        // Change configuration (should fire ConfigurationChangedEvent)
869        context.set_config("runtime.key", "runtime.value");
870        context.set_config("initial.key", "updated.value");
871
872        // Verify initializing events were fired
873        let initializing_events = initializing_events.lock().unwrap();
874        assert_eq!(initializing_events.len(), 1);
875        assert!(initializing_events[0].config_sources_count > 0);
876
877        // Verify initialized events were fired
878        let initialized_events = initialized_events.lock().unwrap();
879        assert_eq!(initialized_events.len(), 1);
880        assert!(initialized_events[0].config_sources_count > 0);
881
882        // Verify the initializing event was fired before the initialized event
883        assert!(initializing_events[0].timestamp <= initialized_events[0].timestamp);
884
885        let config_events = config_events.lock().unwrap();
886        assert_eq!(config_events.len(), 2);
887
888        // First config change (new key)
889        assert_eq!(config_events[0].key, "runtime.key");
890        assert_eq!(config_events[0].old_value, None);
891        assert_eq!(config_events[0].new_value, "runtime.value");
892
893        // Second config change (update existing key)
894        assert_eq!(config_events[1].key, "initial.key");
895        assert_eq!(
896            config_events[1].old_value,
897            Some("initial.value".to_string())
898        );
899        assert_eq!(config_events[1].new_value, "updated.value");
900    }
901
902    #[test]
903    fn test_context_aware_event_listeners() {
904        use crate::event::{ContextAwareEventListener, ContextInitializedEvent};
905        use std::sync::{Arc, Mutex};
906
907        // Track events and context access
908        let events_received = Arc::new(Mutex::new(Vec::new()));
909        let context_data_accessed = Arc::new(Mutex::new(Vec::new()));
910
911        // Context-aware event listener
912        struct ContextAwareListener {
913            events: Arc<Mutex<Vec<String>>>,
914            context_data: Arc<Mutex<Vec<String>>>,
915        }
916
917        impl ContextAwareEventListener<ContextInitializedEvent> for ContextAwareListener {
918            fn on_context_event(
919                &self,
920                event: &ContextInitializedEvent,
921                context: &crate::context::ApplicationContext,
922            ) {
923                // Record the event
924                let mut events = self.events.lock().unwrap();
925                events.push(format!(
926                    "Initialized with {} sources",
927                    event.config_sources_count
928                ));
929
930                // Access context data
931                let mut context_data = self.context_data.lock().unwrap();
932                context_data.push(context.get_config("test.key"));
933                context_data.push(context.environment());
934            }
935        }
936
937        // Create context with some configuration
938        let context = ApplicationContext::builder()
939            .with_property("test.key", "test.value")
940            .with_property("app.name", "TestApp")
941            .build()
942            .unwrap();
943
944        // Register context-aware listener
945        let listener = ContextAwareListener {
946            events: events_received.clone(),
947            context_data: context_data_accessed.clone(),
948        };
949        context.subscribe_to_context_events(listener);
950
951        // Initialize context - this should trigger the context-aware event
952        context.initialize().unwrap();
953
954        // Verify the context-aware listener received the event and could access context
955        let events = events_received.lock().unwrap();
956        assert_eq!(events.len(), 1);
957        assert!(events[0].contains("Initialized with"));
958
959        let context_data = context_data_accessed.lock().unwrap();
960        assert_eq!(context_data.len(), 2);
961        assert_eq!(context_data[0], "test.value"); // Successfully accessed config
962        assert_eq!(context_data[1], "default"); // Successfully accessed environment
963    }
964}