use alloc::format;
use alloc::string::String;
use alloc::vec;
use alloc::vec::Vec;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ConnectorImplementation {
pub original_interface: String,
pub client_instance: String,
pub artifact_path: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImplementationDescriptor {
pub label: String,
pub uuid: String,
pub artifacts: Vec<String>,
pub realizes: String,
}
impl ImplementationDescriptor {
#[must_use]
pub fn for_connector(impl_: &ConnectorImplementation) -> Self {
let connector_name = format!("AMI4CCM_{}_Connector", impl_.original_interface);
Self {
label: format!("{connector_name}_Impl"),
uuid: format!(
"ami4ccm-{}-impl-uuid",
impl_.original_interface.to_lowercase()
),
artifacts: vec![impl_.artifact_path.clone()],
realizes: format!("IDL:omg.org/CCM_AMI/{connector_name}:1.0"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PlanInstance {
pub name: String,
pub implementation: String,
pub co_locate_with: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ConnectorPlanFragment {
pub implementation: ImplementationDescriptor,
pub instance: PlanInstance,
}
impl ConnectorPlanFragment {
#[must_use]
pub fn build(impl_: &ConnectorImplementation) -> Self {
let implementation = ImplementationDescriptor::for_connector(impl_);
let instance = PlanInstance {
name: format!("{}_AMI4CCM_Connector", impl_.client_instance),
implementation: implementation.label.clone(),
co_locate_with: Some(impl_.client_instance.clone()),
};
Self {
implementation,
instance,
}
}
#[must_use]
pub fn is_co_located(&self) -> bool {
self.instance.co_locate_with.is_some()
}
#[must_use]
pub fn to_dnc_xml(&self) -> String {
let mut xml = String::new();
xml.push_str("<deploymentPlan>\n");
xml.push_str(" <implementation>\n");
xml.push_str(&format!(" <name>{}</name>\n", self.implementation.label));
xml.push_str(&format!(" <UUID>{}</UUID>\n", self.implementation.uuid));
for art in &self.implementation.artifacts {
xml.push_str(&format!(" <artifact>{art}</artifact>\n"));
}
xml.push_str(&format!(
" <realizes>{}</realizes>\n",
self.implementation.realizes
));
xml.push_str(" </implementation>\n");
xml.push_str(" <instance>\n");
xml.push_str(&format!(" <name>{}</name>\n", self.instance.name));
xml.push_str(&format!(
" <implementation>{}</implementation>\n",
self.instance.implementation
));
if let Some(ref c) = self.instance.co_locate_with {
xml.push_str(&format!(" <coLocateWith>{c}</coLocateWith>\n"));
}
xml.push_str(" </instance>\n");
xml.push_str("</deploymentPlan>\n");
xml
}
}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
mod tests {
use super::*;
fn sample_impl() -> ConnectorImplementation {
ConnectorImplementation {
original_interface: "StockManager".to_string(),
client_instance: "TraderClient".to_string(),
artifact_path: "lib/ami4ccm_stockmanager.so".to_string(),
}
}
#[test]
fn idd_realizes_correct_repository_id() {
let impl_ = sample_impl();
let idd = ImplementationDescriptor::for_connector(&impl_);
assert_eq!(
idd.realizes,
"IDL:omg.org/CCM_AMI/AMI4CCM_StockManager_Connector:1.0"
);
assert!(!idd.artifacts.is_empty());
}
#[test]
fn plan_fragment_is_co_located() {
let impl_ = sample_impl();
let frag = ConnectorPlanFragment::build(&impl_);
assert!(frag.is_co_located());
assert_eq!(
frag.instance.co_locate_with.as_deref(),
Some("TraderClient")
);
}
#[test]
fn plan_instance_name_combines_client_and_connector() {
let impl_ = sample_impl();
let frag = ConnectorPlanFragment::build(&impl_);
assert_eq!(frag.instance.name, "TraderClient_AMI4CCM_Connector");
}
#[test]
fn xml_roundtrip_includes_co_location() {
let impl_ = sample_impl();
let frag = ConnectorPlanFragment::build(&impl_);
let xml = frag.to_dnc_xml();
assert!(xml.contains("<deploymentPlan>"));
assert!(xml.contains("<coLocateWith>TraderClient</coLocateWith>"));
assert!(xml.contains("AMI4CCM_StockManager_Connector"));
}
#[test]
fn xml_lists_all_artifacts() {
let mut impl_ = sample_impl();
impl_.artifact_path = "lib/a.so".into();
let frag = ConnectorPlanFragment::build(&impl_);
let xml = frag.to_dnc_xml();
assert!(xml.contains("<artifact>lib/a.so</artifact>"));
}
}