elif_core/examples/
module_example.rs

1/*!
2 * ServiceModule Integration Example
3 *
4 * This example demonstrates the complete ServiceModule system functionality,
5 * showing how modules can organize and register related services with dependency
6 * management and proper initialization order.
7 */
8
9use crate::container::binding::{ServiceBinder, ServiceBindings};
10use crate::container::ioc_builder::IocContainerBuilder;
11use crate::container::module::{ModuleId, ModuleRegistry, ServiceModule};
12use crate::errors::CoreError;
13
14// ===== Example Services =====
15
16/// User repository interface - would typically be a trait in a real application
17#[derive(Default, Debug)]
18pub struct UserRepository {
19    pub connection_string: String,
20}
21
22impl UserRepository {
23    pub fn find_user(&self, id: u32) -> Option<String> {
24        println!("UserRepository: Finding user {}", id);
25        Some(format!("User-{}", id))
26    }
27}
28
29/// User service that depends on UserRepository
30#[derive(Default, Debug)]
31pub struct UserService {
32    pub cache_enabled: bool,
33}
34
35impl UserService {
36    pub fn get_user(&self, id: u32) -> String {
37        println!("UserService: Getting user {}", id);
38        format!("UserService-{}", id)
39    }
40}
41
42/// Logging service for core infrastructure
43#[derive(Default, Debug)]
44pub struct LoggingService {
45    pub level: String,
46}
47
48impl LoggingService {
49    pub fn log(&self, message: &str) {
50        println!("[{}] {}", self.level, message);
51    }
52}
53
54/// Configuration service for core infrastructure
55#[derive(Default, Debug)]
56pub struct ConfigService {
57    pub environment: String,
58}
59
60// ===== Service Modules =====
61
62/// Core infrastructure module - provides logging, config, etc.
63pub struct CoreInfraModule;
64
65impl ServiceModule for CoreInfraModule {
66    fn name(&self) -> &str {
67        "Core Infrastructure Module"
68    }
69
70    fn description(&self) -> Option<&str> {
71        Some("Provides core infrastructure services like logging and configuration")
72    }
73
74    fn version(&self) -> Option<&str> {
75        Some("1.0.0")
76    }
77
78    fn configure(&self, services: &mut ServiceBindings) {
79        // Register core infrastructure services as singletons
80        services.bind_singleton::<LoggingService, LoggingService>();
81        services.bind_singleton::<ConfigService, ConfigService>();
82    }
83}
84
85/// Data access module - provides repositories and data services
86pub struct DataAccessModule;
87
88impl ServiceModule for DataAccessModule {
89    fn name(&self) -> &str {
90        "Data Access Module"
91    }
92
93    fn description(&self) -> Option<&str> {
94        Some("Provides data access repositories and database services")
95    }
96
97    fn version(&self) -> Option<&str> {
98        Some("2.1.0")
99    }
100
101    fn depends_on(&self) -> Vec<ModuleId> {
102        // Data access depends on core infrastructure
103        vec![ModuleId::of::<CoreInfraModule>()]
104    }
105
106    fn configure(&self, services: &mut ServiceBindings) {
107        // Register data access services
108        services.bind_singleton::<UserRepository, UserRepository>();
109    }
110}
111
112/// Business logic module - provides business services
113pub struct BusinessLogicModule;
114
115impl ServiceModule for BusinessLogicModule {
116    fn name(&self) -> &str {
117        "Business Logic Module"
118    }
119
120    fn description(&self) -> Option<&str> {
121        Some("Provides business logic and application services")
122    }
123
124    fn version(&self) -> Option<&str> {
125        Some("1.5.2")
126    }
127
128    fn depends_on(&self) -> Vec<ModuleId> {
129        // Business logic depends on both data access and core infrastructure
130        vec![
131            ModuleId::of::<DataAccessModule>(),
132            ModuleId::of::<CoreInfraModule>(),
133        ]
134    }
135
136    fn configure(&self, services: &mut ServiceBindings) {
137        // Register business services as transient (new instance per request)
138        services.bind::<UserService, UserService>();
139    }
140}
141
142// ===== Example Usage =====
143
144/// Demonstrates the complete ServiceModule integration
145pub fn demonstrate_module_system() -> Result<(), CoreError> {
146    println!("=== ServiceModule Integration Demo ===\n");
147
148    // 1. Create and configure the module registry
149    println!("1. Creating module registry...");
150    let mut registry = ModuleRegistry::new();
151
152    // Register modules in any order - dependency resolution will sort them
153    registry.register_module(BusinessLogicModule, None)?;
154    registry.register_module(CoreInfraModule, None)?;
155    registry.register_module(DataAccessModule, None)?;
156
157    println!(
158        "   ✓ Registered {} modules",
159        registry.get_all_loaded_modules().len()
160    );
161
162    // 2. Calculate load order based on dependencies
163    println!("\n2. Calculating dependency load order...");
164    let load_order = registry.calculate_load_order()?;
165
166    for (i, module_id) in load_order.iter().enumerate() {
167        if let Some(loaded_module) = registry.get_loaded_module(module_id) {
168            println!(
169                "   {}. {} (v{})",
170                i + 1,
171                loaded_module.metadata.name,
172                loaded_module
173                    .metadata
174                    .version
175                    .as_deref()
176                    .unwrap_or("unknown")
177            );
178        }
179    }
180
181    // 3. Configure all modules with a container builder
182    println!("\n3. Configuring services from modules...");
183    let mut container_builder = IocContainerBuilder::new();
184
185    registry.configure_all(&mut container_builder)?;
186    println!("   ✓ All modules configured");
187
188    // 4. Build the IoC container
189    println!("\n4. Building IoC container...");
190    let container = container_builder.build()?;
191    println!("   ✓ Container built successfully");
192
193    // 5. Initialize all modules (async lifecycle)
194    println!("\n5. Initializing modules...");
195    // Note: In a real application, you would await this
196    // registry.initialize_all(&container).await?;
197    println!("   ✓ All modules initialized (demo - not actually awaited)");
198
199    // 6. Demonstrate service resolution
200    println!("\n6. Demonstrating service resolution:");
201
202    // Resolve services registered by different modules
203    match container.resolve::<LoggingService>() {
204        Ok(logger) => {
205            logger.log("Logger service resolved from CoreInfraModule");
206        }
207        Err(e) => println!("   ❌ Failed to resolve LoggingService: {}", e),
208    }
209
210    match container.resolve::<ConfigService>() {
211        Ok(_config) => {
212            println!("   ✓ ConfigService resolved from CoreInfraModule");
213        }
214        Err(e) => println!("   ❌ Failed to resolve ConfigService: {}", e),
215    }
216
217    match container.resolve::<UserRepository>() {
218        Ok(repo) => {
219            let user = repo.find_user(123);
220            println!(
221                "   ✓ UserRepository resolved from DataAccessModule: {:?}",
222                user
223            );
224        }
225        Err(e) => println!("   ❌ Failed to resolve UserRepository: {}", e),
226    }
227
228    match container.resolve::<UserService>() {
229        Ok(service) => {
230            let user = service.get_user(456);
231            println!(
232                "   ✓ UserService resolved from BusinessLogicModule: {}",
233                user
234            );
235        }
236        Err(e) => println!("   ❌ Failed to resolve UserService: {}", e),
237    }
238
239    // 7. Show module information
240    println!("\n7. Module Status Summary:");
241    for loaded_module in registry.get_all_loaded_modules() {
242        println!(
243            "   • {} - {:?}",
244            loaded_module.metadata.name, loaded_module.state
245        );
246    }
247
248    println!("\n🎉 ServiceModule integration demo completed successfully!");
249    Ok(())
250}
251
252#[cfg(test)]
253mod tests {
254    use super::*;
255    use crate::container::module::ModuleState;
256
257    #[test]
258    fn test_module_integration_demo() {
259        let result = demonstrate_module_system();
260        assert!(
261            result.is_ok(),
262            "Module integration demo should complete successfully: {:?}",
263            result
264        );
265    }
266
267    #[test]
268    fn test_module_dependency_resolution() {
269        let mut registry = ModuleRegistry::new();
270
271        // Register modules in reverse dependency order
272        registry.register_module(BusinessLogicModule, None).unwrap();
273        registry.register_module(DataAccessModule, None).unwrap();
274        registry.register_module(CoreInfraModule, None).unwrap();
275
276        let load_order = registry.calculate_load_order().unwrap();
277
278        // Should be ordered: CoreInfra -> DataAccess -> BusinessLogic
279        assert_eq!(load_order.len(), 3);
280
281        let order_names: Vec<String> = load_order
282            .iter()
283            .map(|id| {
284                registry
285                    .get_loaded_module(id)
286                    .unwrap()
287                    .metadata
288                    .name
289                    .clone()
290            })
291            .collect();
292
293        assert_eq!(order_names[0], "Core Infrastructure Module");
294        assert_eq!(order_names[1], "Data Access Module");
295        assert_eq!(order_names[2], "Business Logic Module");
296    }
297
298    #[test]
299    fn test_service_registration_through_modules() {
300        let mut registry = ModuleRegistry::new();
301        registry.register_module(CoreInfraModule, None).unwrap();
302        registry.register_module(DataAccessModule, None).unwrap();
303
304        let mut container_builder = IocContainerBuilder::new();
305        registry.configure_all(&mut container_builder).unwrap();
306
307        let container = container_builder.build().unwrap();
308
309        // Services from CoreInfraModule should be available
310        assert!(container.resolve::<LoggingService>().is_ok());
311        assert!(container.resolve::<ConfigService>().is_ok());
312
313        // Services from DataAccessModule should be available
314        assert!(container.resolve::<UserRepository>().is_ok());
315    }
316
317    #[test]
318    fn test_module_state_tracking() {
319        let mut registry = ModuleRegistry::new();
320        registry.register_module(CoreInfraModule, None).unwrap();
321
322        // Initially should be registered
323        let module_id = ModuleId::of::<CoreInfraModule>();
324        let loaded_module = registry.get_loaded_module(&module_id).unwrap();
325        assert_eq!(loaded_module.state, ModuleState::Registered);
326
327        // After configuration should be configured
328        let mut container_builder = IocContainerBuilder::new();
329        registry.configure_all(&mut container_builder).unwrap();
330
331        let loaded_module = registry.get_loaded_module(&module_id).unwrap();
332        assert_eq!(loaded_module.state, ModuleState::Configured);
333    }
334}