1use crate::{BeanError, BeanProcessor};
2use camel_api::{CamelError, Exchange};
3use std::collections::HashMap;
4use std::sync::Arc;
5
6pub struct BeanRegistry {
7 beans: HashMap<String, Arc<dyn BeanProcessor>>,
8}
9
10impl BeanRegistry {
11 pub fn new() -> Self {
12 Self {
13 beans: HashMap::new(),
14 }
15 }
16
17 pub fn register<B>(&mut self, name: impl Into<String>, bean: B) -> Result<(), BeanError>
18 where
19 B: BeanProcessor + 'static,
20 {
21 let name = name.into();
22 if self.beans.contains_key(&name) {
23 return Err(BeanError::DuplicateName(name));
24 }
25 self.beans.insert(name, Arc::new(bean));
26 Ok(())
27 }
28
29 pub fn get(&self, name: &str) -> Option<Arc<dyn BeanProcessor>> {
30 self.beans.get(name).cloned()
31 }
32
33 pub async fn invoke(
34 &self,
35 bean_name: &str,
36 method: &str,
37 exchange: &mut Exchange,
38 ) -> Result<(), CamelError> {
39 let bean = self
40 .get(bean_name)
41 .ok_or_else(|| BeanError::NotFound(bean_name.to_string()))?;
42
43 if !bean.methods().iter().any(|m| m == method) {
44 return Err(BeanError::MethodNotFound(method.to_string()).into());
45 }
46
47 bean.call(method, exchange).await
48 }
49
50 pub fn len(&self) -> usize {
51 self.beans.len()
52 }
53
54 pub fn is_empty(&self) -> bool {
55 self.beans.is_empty()
56 }
57}
58
59impl Default for BeanRegistry {
60 fn default() -> Self {
61 Self::new()
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68 use async_trait::async_trait;
69 use camel_api::{Exchange, Message};
70
71 struct MockBean;
72
73 struct ErrorBean;
74
75 #[async_trait]
76 impl BeanProcessor for MockBean {
77 async fn call(&self, method: &str, _exchange: &mut Exchange) -> Result<(), CamelError> {
78 match method {
79 "process" => Ok(()),
80 _ => Err(BeanError::MethodNotFound(method.to_string()).into()),
81 }
82 }
83
84 fn methods(&self) -> Vec<String> {
85 vec!["process".to_string()]
86 }
87 }
88
89 #[async_trait]
90 impl BeanProcessor for ErrorBean {
91 async fn call(&self, _method: &str, _exchange: &mut Exchange) -> Result<(), CamelError> {
92 Err(CamelError::ProcessorError("boom".to_string()))
93 }
94
95 fn methods(&self) -> Vec<String> {
96 vec!["process".to_string()]
97 }
98 }
99
100 #[test]
101 fn test_default_is_empty() {
102 let registry = BeanRegistry::default();
103 assert!(registry.is_empty());
104 assert_eq!(registry.len(), 0);
105 }
106
107 #[test]
108 fn test_register_and_get() {
109 let mut registry = BeanRegistry::new();
110 registry.register("mock", MockBean).unwrap();
111
112 assert!(registry.get("mock").is_some());
113 assert!(registry.get("nonexistent").is_none());
114 }
115
116 #[test]
117 fn test_len_and_is_empty() {
118 let mut registry = BeanRegistry::new();
119 assert!(registry.is_empty());
120
121 registry.register("mock", MockBean).unwrap();
122 assert_eq!(registry.len(), 1);
123 assert!(!registry.is_empty());
124 }
125
126 #[test]
127 fn test_register_same_name_rejects() {
128 let mut registry = BeanRegistry::new();
129 registry.register("dup", MockBean).unwrap();
130 let result = registry.register("dup", ErrorBean);
131 assert!(result.is_err());
132 assert_eq!(registry.len(), 1);
133 }
134
135 #[test]
136 fn test_register_duplicate_returns_error() {
137 let mut registry = BeanRegistry::new();
138 registry.register("dup", MockBean).unwrap();
139 let err = registry.register("dup", ErrorBean).unwrap_err();
140 assert!(matches!(err, BeanError::DuplicateName(_)));
141 }
142
143 #[tokio::test]
144 async fn test_invoke_success() {
145 let mut registry = BeanRegistry::new();
146 registry.register("mock", MockBean).unwrap();
147
148 let mut exchange = Exchange::new(Message::default());
149 let result = registry.invoke("mock", "process", &mut exchange).await;
150
151 assert!(result.is_ok());
152 }
153
154 #[tokio::test]
155 async fn test_invoke_bean_not_found() {
156 let registry = BeanRegistry::new();
157 let mut exchange = Exchange::new(Message::default());
158
159 let result = registry
160 .invoke("nonexistent", "process", &mut exchange)
161 .await;
162 assert!(result.is_err());
163 }
164
165 #[tokio::test]
166 async fn test_invoke_method_not_found() {
167 let mut registry = BeanRegistry::new();
168 registry.register("mock", MockBean).unwrap();
169
170 let mut exchange = Exchange::new(Message::default());
171 let result = registry.invoke("mock", "unknown", &mut exchange).await;
172
173 assert!(result.is_err());
174 }
175
176 #[tokio::test]
177 async fn test_invoke_propagates_bean_error() {
178 let mut registry = BeanRegistry::new();
179 registry.register("err", ErrorBean).unwrap();
180
181 let mut exchange = Exchange::new(Message::default());
182 let result = registry.invoke("err", "process", &mut exchange).await;
183
184 assert!(matches!(result, Err(CamelError::ProcessorError(_))));
185 }
186}