Skip to main content

camel_bean/
registry.rs

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}