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