use std::any::Any;
use std::collections::BTreeMap;
use std::sync::{Arc, Mutex};
use crate::context::CamelContext;
use crate::error::{CamelError, Result};
use crate::processor::pipeline::Pipeline;
use crate::spi::{Processor, Service};
pub trait ProcessorDefinition: Send + Sync + Any {
fn name(&self) -> &str;
fn create_processor(&self, rc: &RouteContext) -> Result<Arc<dyn Processor>>;
fn id(&self) -> Option<&str> {
None
}
fn set_id(&mut self, _id: String) {}
fn is_block(&self) -> bool {
false
}
fn add_output(&mut self, _def: Box<dyn ProcessorDefinition>) -> Result<()> {
Err(CamelError::illegal_state(format!("{} does not accept outputs", self.name())))
}
fn outputs(&self) -> Vec<&dyn ProcessorDefinition> {
Vec::new()
}
fn label(&self) -> String {
self.name().to_string()
}
fn wrap_in_channel(&self) -> bool {
true
}
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
#[macro_export]
macro_rules! impl_definition_boilerplate {
() => {
fn id(&self) -> Option<&str> {
self.id.as_deref()
}
fn set_id(&mut self, id: String) {
self.id = Some(id);
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
};
}
pub trait ChannelWrapper: Send + Sync {
fn wrap(&self, rc: &RouteContext, definition: &dyn ProcessorDefinition, processor: Arc<dyn Processor>) -> Result<Arc<dyn Processor>>;
}
pub struct RouteContext {
pub context: CamelContext,
pub route_id: String,
services: Mutex<Vec<Arc<dyn Service>>>,
pub channel_wrappers: Vec<Arc<dyn ChannelWrapper>>,
pub attributes: Mutex<BTreeMap<String, Arc<dyn Any + Send + Sync>>>,
node_counter: std::sync::atomic::AtomicUsize,
}
impl RouteContext {
pub fn new(context: CamelContext, route_id: impl Into<String>) -> Self {
RouteContext {
context,
route_id: route_id.into(),
services: Mutex::new(Vec::new()),
channel_wrappers: Vec::new(),
attributes: Mutex::new(BTreeMap::new()),
node_counter: std::sync::atomic::AtomicUsize::new(0),
}
}
pub fn add_service(&self, s: Arc<dyn Service>) {
self.services.lock().unwrap().push(s);
}
pub fn take_services(&self) -> Vec<Arc<dyn Service>> {
std::mem::take(&mut self.services.lock().unwrap())
}
pub fn next_node_id(&self, name: &str) -> String {
let n = self.node_counter.fetch_add(1, std::sync::atomic::Ordering::Relaxed) + 1;
format!("{}{}", name, n)
}
pub fn set_attribute<T: Any + Send + Sync>(&self, key: &str, v: T) {
self.attributes.lock().unwrap().insert(key.to_string(), Arc::new(v));
}
pub fn attribute<T: Any + Send + Sync>(&self, key: &str) -> Option<Arc<T>> {
self.attributes.lock().unwrap().get(key).cloned().and_then(|a| a.downcast::<T>().ok())
}
pub fn create_processor(&self, def: &dyn ProcessorDefinition) -> Result<Arc<dyn Processor>> {
let p = def.create_processor(self).map_err(|e| {
if e.kind == crate::error::kinds::FAILED_TO_CREATE_ROUTE {
e
} else {
CamelError::new(
crate::error::kinds::FAILED_TO_CREATE_ROUTE,
format!("Failed to create route {} at: >>> {} <<< because of {}", self.route_id, def.label(), e.message),
)
.with_cause(e)
}
})?;
if !def.wrap_in_channel() {
return Ok(p);
}
let mut wrapped = p;
for w in &self.channel_wrappers {
wrapped = w.wrap(self, def, wrapped)?;
}
Ok(wrapped)
}
pub fn create_child_processor(&self, defs: &[Box<dyn ProcessorDefinition>]) -> Result<Arc<dyn Processor>> {
let mut procs = Vec::with_capacity(defs.len());
for d in defs {
procs.push(self.create_processor(d.as_ref())?);
}
if procs.len() == 1 {
return Ok(procs.pop().unwrap());
}
Ok(Arc::new(Pipeline::new(procs)))
}
}
pub struct RouteDefinition {
pub id: Option<String>,
pub description: Option<String>,
pub group: Option<String>,
pub input: String,
pub outputs: Vec<Box<dyn ProcessorDefinition>>,
pub(crate) stack: Vec<Box<dyn ProcessorDefinition>>,
pub(crate) pending: Option<Box<dyn ProcessorDefinition>>,
pub auto_startup: bool,
pub startup_order: Option<i32>,
pub extensions: BTreeMap<String, Box<dyn Any + Send + Sync>>,
pub(crate) build_errors: Vec<CamelError>,
pub properties: BTreeMap<String, String>,
}
impl std::fmt::Debug for RouteDefinition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Route[{} -> {}]", self.input, self.dump_outputs(&self.outputs))
}
}
impl RouteDefinition {
pub fn new(input: impl Into<String>) -> Self {
RouteDefinition {
id: None,
description: None,
group: None,
input: input.into(),
outputs: Vec::new(),
stack: Vec::new(),
pending: None,
auto_startup: true,
startup_order: None,
extensions: BTreeMap::new(),
build_errors: Vec::new(),
properties: BTreeMap::new(),
}
}
fn dump_outputs(&self, outs: &[Box<dyn ProcessorDefinition>]) -> String {
let parts: Vec<String> = outs.iter().map(|o| dump_def(o.as_ref())).collect();
format!("[{}]", parts.join(", "))
}
pub(crate) fn flush_pending(&mut self) {
if let Some(def) = self.pending.take() {
match self.stack.last_mut() {
Some(top) => {
if let Err(e) = top.add_output(def) {
self.build_errors.push(e);
}
}
None => self.outputs.push(def),
}
}
}
pub fn add(&mut self, def: Box<dyn ProcessorDefinition>) -> &mut Self {
self.flush_pending();
if self.stack.is_empty() {
self.outputs.push(def);
} else {
self.pending = Some(def);
}
self
}
pub fn push_block(&mut self, def: Box<dyn ProcessorDefinition>) -> &mut Self {
self.flush_pending();
self.stack.push(def);
self
}
pub fn end(&mut self) -> &mut Self {
self.flush_pending();
if let Some(def) = self.stack.pop() {
self.add(def);
}
self
}
pub fn current_block_mut<T: 'static>(&mut self) -> Option<&mut T> {
self.flush_pending();
self.stack.last_mut().and_then(|b| b.as_any_mut().downcast_mut::<T>())
}
pub fn unwind_to_block<T: 'static>(&mut self) -> Option<&mut T> {
self.flush_pending();
let pos = self.stack.iter().rposition(|b| b.as_any().is::<T>())?;
while self.stack.len() > pos + 1 {
self.end();
}
self.current_block_mut::<T>()
}
pub fn last_mut(&mut self) -> Option<&mut Box<dyn ProcessorDefinition>> {
if self.pending.is_some() {
return self.pending.as_mut();
}
if let Some(top) = self.stack.last_mut() {
return Some(top);
}
self.outputs.last_mut()
}
pub fn add_build_error(&mut self, e: CamelError) {
self.build_errors.push(e);
}
pub fn finish(&mut self) -> Result<()> {
self.flush_pending();
while !self.stack.is_empty() {
self.end();
}
if let Some(e) = self.build_errors.first() {
return Err(e.clone());
}
Ok(())
}
pub fn extension<T: 'static>(&self, key: &str) -> Option<&T> {
self.extensions.get(key).and_then(|b| b.downcast_ref::<T>())
}
pub fn extension_mut<T: Any + Send + Sync + Default>(&mut self, key: &str) -> &mut T {
if !self.extensions.get(key).map(|b| b.is::<T>()).unwrap_or(false) {
self.extensions.insert(key.to_string(), Box::new(T::default()));
}
self.extensions.get_mut(key).unwrap().downcast_mut::<T>().unwrap()
}
pub fn dump(&self) -> String {
format!("from({}) -> {}", self.input, self.dump_outputs(&self.outputs))
}
}
fn dump_def(d: &dyn ProcessorDefinition) -> String {
let children = d.outputs();
if children.is_empty() {
d.label()
} else {
let parts: Vec<String> = children.into_iter().map(dump_def).collect();
format!("{}[{}]", d.label(), parts.join(", "))
}
}
#[derive(Default)]
pub struct OutputList {
pub outputs: Vec<Box<dyn ProcessorDefinition>>,
}
impl OutputList {
pub fn push(&mut self, d: Box<dyn ProcessorDefinition>) {
self.outputs.push(d)
}
pub fn refs(&self) -> Vec<&dyn ProcessorDefinition> {
self.outputs.iter().map(|o| o.as_ref()).collect()
}
}
pub struct CustomDefinition {
pub id: Option<String>,
pub name: String,
pub factory: Box<dyn Fn(&RouteContext) -> Result<Arc<dyn Processor>> + Send + Sync>,
}
impl ProcessorDefinition for CustomDefinition {
fn name(&self) -> &str {
&self.name
}
fn create_processor(&self, rc: &RouteContext) -> Result<Arc<dyn Processor>> {
(self.factory)(rc)
}
impl_definition_boilerplate!();
}