Skip to main content

camel_core/
component_metadata_catalog.rs

1//! Runtime implementation of [`ComponentMetadataCatalog`].
2//!
3//! Thin wrapper around the component [`Registry`]'s `Arc<Mutex<Registry>>`
4//! that implements the query trait. Created on-demand via
5//! [`CamelContext::metadata_catalog`](crate::context::CamelContext::metadata_catalog).
6
7use std::sync::{Arc, Mutex};
8
9use camel_api::component_metadata::{ComponentMetadata, ComponentMetadataCatalog};
10
11use crate::shared::components::domain::Registry;
12
13/// Runtime catalog of component metadata backed by the live component
14/// [`Registry`].
15pub struct RuntimeComponentMetadataCatalog {
16    registry: Arc<Mutex<Registry>>,
17}
18
19impl RuntimeComponentMetadataCatalog {
20    /// Wrap an existing `Arc<Mutex<Registry>>` to expose it as a
21    /// [`ComponentMetadataCatalog`].
22    pub fn new(registry: Arc<Mutex<Registry>>) -> Self {
23        Self { registry }
24    }
25}
26
27impl ComponentMetadataCatalog for RuntimeComponentMetadataCatalog {
28    fn get_metadata(&self, scheme: &str) -> Option<ComponentMetadata> {
29        self.registry.lock().ok()?.get_metadata(scheme)
30    }
31
32    fn schemes(&self) -> Vec<String> {
33        self.registry
34            .lock()
35            .expect("mutex poisoned: another thread panicked while holding this lock") // allow-unwrap
36            .metadata_schemes()
37    }
38
39    fn all_metadata(&self) -> Vec<ComponentMetadata> {
40        self.registry
41            .lock()
42            .expect("mutex poisoned: another thread panicked while holding this lock") // allow-unwrap
43            .all_metadata()
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50    use camel_api::component_metadata::{CapabilityQuery, ComponentMetadataCatalog};
51    use camel_component_timer::TimerComponent;
52
53    #[test]
54    fn catalog_exposes_registered_metadata() {
55        let registry = Arc::new(Mutex::new(Registry::new()));
56        registry
57            .lock()
58            .expect("mutex poisoned: another thread panicked while holding this lock") // allow-unwrap
59            .register(Arc::new(TimerComponent::new()));
60
61        let catalog = RuntimeComponentMetadataCatalog::new(Arc::clone(&registry));
62
63        let meta = catalog.get_metadata("timer");
64        assert!(meta.is_some());
65        assert_eq!(meta.unwrap().scheme, "timer"); // allow-unwrap
66        assert_eq!(catalog.schemes(), vec!["timer".to_string()]);
67        assert_eq!(catalog.all_metadata().len(), 1);
68    }
69
70    #[test]
71    fn catalog_query_capabilities_default_impl() {
72        let registry = Arc::new(Mutex::new(Registry::new()));
73        registry
74            .lock()
75            .expect("mutex poisoned: another thread panicked while holding this lock") // allow-unwrap
76            .register(Arc::new(TimerComponent::new()));
77
78        let catalog = RuntimeComponentMetadataCatalog::new(Arc::clone(&registry));
79
80        // No constraints => all metadata returned via the trait default impl.
81        let results = catalog.query_capabilities(&CapabilityQuery::default());
82        assert_eq!(results.len(), 1);
83    }
84}