Skip to main content

camel_api/
exchange.rs

1use std::collections::HashMap;
2
3use uuid::Uuid;
4
5use crate::error::CamelError;
6use crate::message::Message;
7use crate::value::Value;
8
9/// The exchange pattern (fire-and-forget or request-reply).
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
11pub enum ExchangePattern {
12    /// Fire-and-forget: message sent, no reply expected.
13    #[default]
14    InOnly,
15    /// Request-reply: message sent, reply expected.
16    InOut,
17}
18
19/// An Exchange represents a message being routed through the framework.
20///
21/// It contains the input message, an optional output message,
22/// properties for passing data between processors, and error state.
23#[derive(Debug, Clone)]
24pub struct Exchange {
25    /// The input (incoming) message.
26    pub input: Message,
27    /// The output (response) message, populated for InOut patterns.
28    pub output: Option<Message>,
29    /// Exchange-scoped properties for passing data between processors.
30    pub properties: HashMap<String, Value>,
31    /// Error state, if processing failed.
32    pub error: Option<CamelError>,
33    /// The exchange pattern.
34    pub pattern: ExchangePattern,
35    /// Unique correlation ID for distributed tracing.
36    pub correlation_id: String,
37}
38
39impl Exchange {
40    /// Create a new exchange with the given input message.
41    pub fn new(input: Message) -> Self {
42        Self {
43            input,
44            output: None,
45            properties: HashMap::new(),
46            error: None,
47            pattern: ExchangePattern::default(),
48            correlation_id: Uuid::new_v4().to_string(),
49        }
50    }
51
52    /// Create a new exchange with the InOut pattern.
53    pub fn new_in_out(input: Message) -> Self {
54        Self {
55            input,
56            output: None,
57            properties: HashMap::new(),
58            error: None,
59            pattern: ExchangePattern::InOut,
60            correlation_id: Uuid::new_v4().to_string(),
61        }
62    }
63
64    /// Get the correlation ID for this exchange.
65    pub fn correlation_id(&self) -> &str {
66        &self.correlation_id
67    }
68
69    /// Get a property value.
70    pub fn property(&self, key: &str) -> Option<&Value> {
71        self.properties.get(key)
72    }
73
74    /// Set a property value.
75    pub fn set_property(&mut self, key: impl Into<String>, value: impl Into<Value>) {
76        self.properties.insert(key.into(), value.into());
77    }
78
79    /// Check if the exchange has an error.
80    pub fn has_error(&self) -> bool {
81        self.error.is_some()
82    }
83
84    /// Set an error on this exchange.
85    pub fn set_error(&mut self, error: CamelError) {
86        self.error = Some(error);
87    }
88}
89
90impl Default for Exchange {
91    fn default() -> Self {
92        Self::new(Message::default())
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn test_exchange_new() {
102        let msg = Message::new("test");
103        let ex = Exchange::new(msg);
104        assert_eq!(ex.input.body.as_text(), Some("test"));
105        assert!(ex.output.is_none());
106        assert!(!ex.has_error());
107        assert_eq!(ex.pattern, ExchangePattern::InOnly);
108    }
109
110    #[test]
111    fn test_exchange_in_out() {
112        let ex = Exchange::new_in_out(Message::default());
113        assert_eq!(ex.pattern, ExchangePattern::InOut);
114    }
115
116    #[test]
117    fn test_exchange_properties() {
118        let mut ex = Exchange::default();
119        ex.set_property("key", Value::Bool(true));
120        assert_eq!(ex.property("key"), Some(&Value::Bool(true)));
121        assert_eq!(ex.property("missing"), None);
122    }
123
124    #[test]
125    fn test_exchange_error() {
126        let mut ex = Exchange::default();
127        assert!(!ex.has_error());
128        ex.set_error(CamelError::ProcessorError("test".into()));
129        assert!(ex.has_error());
130    }
131
132    #[test]
133    fn test_exchange_lifecycle() {
134        let mut ex = Exchange::new(Message::new("input data"));
135        assert_eq!(ex.input.body.as_text(), Some("input data"));
136
137        // Set some properties
138        ex.set_property("processed", Value::Bool(true));
139
140        // Set output
141        ex.output = Some(Message::new("output data"));
142        assert!(ex.output.is_some());
143
144        // Verify no error
145        assert!(!ex.has_error());
146    }
147}