camel_core/shared/components/domain/
registry.rs1use std::collections::HashMap;
2use std::sync::Arc;
3
4use camel_api::CamelError;
5use camel_api::component_metadata::ComponentMetadata;
6use camel_component_api::Component;
7
8pub struct Registry {
15 components: HashMap<String, Arc<dyn Component>>,
16 metadata: HashMap<String, ComponentMetadata>,
17}
18
19impl Registry {
20 pub fn new() -> Self {
22 Self {
23 components: HashMap::new(),
24 metadata: HashMap::new(),
25 }
26 }
27
28 pub fn register(&mut self, component: Arc<dyn Component>) {
35 let scheme = component.scheme().to_string();
36 let mut metadata = component.metadata();
37 if let Err(e) = metadata.validate_scheme(&scheme) {
38 tracing::warn!(scheme = %scheme, error = %e, "metadata scheme mismatch, normalizing");
39 metadata.scheme = scheme.clone();
40 }
41 self.metadata.insert(scheme.clone(), metadata);
42 self.components.insert(scheme, component);
43 }
44
45 pub fn get(&self, scheme: &str) -> Option<Arc<dyn Component>> {
47 self.components.get(scheme).cloned()
48 }
49
50 pub fn get_or_err(&self, scheme: &str) -> Result<Arc<dyn Component>, CamelError> {
52 self.get(scheme)
53 .ok_or_else(|| CamelError::ComponentNotFound(scheme.to_string()))
54 }
55
56 pub fn get_metadata(&self, scheme: &str) -> Option<ComponentMetadata> {
58 self.metadata.get(scheme).cloned()
59 }
60
61 pub fn all_metadata(&self) -> Vec<ComponentMetadata> {
63 self.metadata.values().cloned().collect()
64 }
65
66 pub fn metadata_schemes(&self) -> Vec<String> {
68 self.metadata.keys().cloned().collect()
69 }
70
71 pub fn len(&self) -> usize {
73 self.components.len()
74 }
75
76 pub fn is_empty(&self) -> bool {
78 self.components.is_empty()
79 }
80}
81
82impl Default for Registry {
83 fn default() -> Self {
84 Self::new()
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use camel_api::component_metadata::ComponentMetadata;
92 use camel_component_log::LogComponent;
93 use camel_component_timer::TimerComponent;
94
95 #[test]
96 fn registry_starts_empty() {
97 let registry = Registry::new();
98 assert!(registry.is_empty());
99 assert_eq!(registry.len(), 0);
100 assert!(registry.get("timer").is_none());
101 }
102
103 #[test]
104 fn registry_registers_and_gets_components() {
105 let mut registry = Registry::new();
106 registry.register(Arc::new(TimerComponent::new()));
107 registry.register(Arc::new(LogComponent::new()));
108
109 assert_eq!(registry.len(), 2);
110 assert!(registry.get("timer").is_some());
111 assert!(registry.get("log").is_some());
112 assert!(!registry.is_empty());
113 }
114
115 #[test]
116 fn registry_get_or_err_reports_missing_component() {
117 let mut registry = Registry::new();
118 registry.register(Arc::new(TimerComponent::new()));
119
120 let err = match registry.get_or_err("missing") {
121 Ok(_) => panic!("must fail"),
122 Err(err) => err,
123 };
124 assert!(matches!(err, CamelError::ComponentNotFound(_)));
125 }
126
127 #[test]
128 fn registry_replaces_component_with_same_scheme() {
129 let mut registry = Registry::new();
130 registry.register(Arc::new(TimerComponent::new()));
131 registry.register(Arc::new(TimerComponent::new()));
132
133 assert_eq!(registry.len(), 1);
134 assert!(registry.get("timer").is_some());
135 assert_eq!(registry.all_metadata().len(), 1);
136 }
137
138 #[test]
139 fn registry_harvests_metadata_on_register() {
140 let mut registry = Registry::new();
141 registry.register(Arc::new(TimerComponent::new()));
142
143 let meta = registry.get_metadata("timer");
144 assert!(meta.is_some());
145 let meta = meta.unwrap(); assert_eq!(meta.scheme, "timer");
147 assert_eq!(meta.schema_version, ComponentMetadata::SCHEMA_VERSION);
148 }
149
150 #[test]
151 fn registry_all_metadata_returns_all_schemes() {
152 let mut registry = Registry::new();
153 registry.register(Arc::new(TimerComponent::new()));
154 registry.register(Arc::new(LogComponent::new()));
155
156 let all = registry.all_metadata();
157 assert_eq!(all.len(), 2);
158 }
159
160 #[test]
161 fn registry_metadata_schemes_lists_all_keys() {
162 let mut registry = Registry::new();
163 registry.register(Arc::new(TimerComponent::new()));
164 registry.register(Arc::new(LogComponent::new()));
165
166 let mut schemes = registry.metadata_schemes();
167 schemes.sort();
168 assert_eq!(schemes, vec!["log".to_string(), "timer".to_string()]);
169 }
170}