scf_core/facade/
mod.rs

1//! facade tools for user
2
3use lang_extension::any::*;
4use std::sync::Arc;
5
6use crate::manager::default::*;
7use crate::manager::*;
8use crate::property::default::*;
9use crate::property::*;
10use crate::source::default::*;
11use crate::source::*;
12
13/// facade to create new managers
14pub struct ConfigurationManagers;
15
16impl ConfigurationManagers {
17    pub fn new_config_builder() -> Box<dyn ConfigurationManagerConfigBuilder> {
18        Box::new(DefaultConfigurationManagerConfigBuilder::new())
19    }
20
21    pub fn new_manager(
22        config: Box<dyn ConfigurationManagerConfig>,
23    ) -> Box<dyn ConfigurationManager> {
24        Box::new(DefaultConfigurationManager::new(config))
25    }
26}
27
28/// facade to create new properties
29#[derive(PartialEq, Debug, Clone)]
30pub struct ConfigurationProperties {
31    manager: Arc<Box<dyn ConfigurationManager>>,
32}
33
34unsafe impl Sync for ConfigurationProperties {}
35unsafe impl Send for ConfigurationProperties {}
36
37impl ConfigurationProperties {
38    pub fn new_config_builder<K: ?Sized + KeyConstraint, V: ?Sized + ValueConstraint>()
39    -> Box<dyn PropertyConfigBuilder<K, V>> {
40        Box::new(DefaultPropertyConfigBuilder::new())
41    }
42
43    pub fn new(manager: Box<dyn ConfigurationManager>) -> Self {
44        Self {
45            manager: Arc::new(manager),
46        }
47    }
48
49    pub fn get_manager(&self) -> &dyn ConfigurationManager {
50        self.manager.as_ref().as_ref()
51    }
52
53    pub fn get_property<K: ?Sized + KeyConstraint, V: ?Sized + ValueConstraint>(
54        &self,
55        config: &dyn PropertyConfig<K, V>,
56    ) -> Box<dyn Property<K, V>> {
57        let p = self
58            .manager
59            .get_property(RawPropertyConfig::as_trait_ref(config));
60        Property::to_boxed(DefaultProperty::from_raw(p.as_ref()))
61    }
62
63    pub fn get_property_value<K: ?Sized + KeyConstraint, V: ?Sized + ValueConstraint>(
64        &self,
65        config: &dyn PropertyConfig<K, V>,
66    ) -> Option<Box<V>> {
67        match self
68            .manager
69            .get_property_value(RawPropertyConfig::as_trait_ref(config))
70        {
71            Some(v) => match v.as_ref().as_any_ref().downcast_ref::<V>() {
72                Some(v) => Some(Box::new(v.clone())),
73                None => None,
74            },
75            None => None,
76        }
77    }
78}
79
80/// facade to create new sources
81pub struct ConfigurationSources;
82
83impl ConfigurationSources {
84    pub fn new_config_builder() -> Box<dyn ConfigurationSourceConfigBuilder> {
85        Box::new(DefaultConfigurationSourceConfigBuilder::new())
86    }
87
88    pub fn new_config(name: &str) -> Box<dyn ConfigurationSourceConfig> {
89        DefaultConfigurationSourceConfigBuilder::new()
90            .set_name(name)
91            .build()
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98    use crate::tests::init_log;
99    use lang_extension::convert::*;
100    use std::any::*;
101    use std::collections::HashMap;
102    use std::sync::atomic::*;
103    use std::sync::*;
104
105    fn new_source(
106        config: Box<dyn ConfigurationSourceConfig>,
107        property_provider: PropertyProvider,
108    ) -> Box<dyn ConfigurationSource> {
109        ConfigurationSource::to_boxed(DefaultConfigurationSource::new(config, property_provider))
110    }
111
112    #[test]
113    fn new_property_config() {
114        let c =
115            DefaultTypeConverter::<String, i32>::new(Box::new(move |v| match v.parse::<i32>() {
116                Ok(v) => Ok(Box::new(v)),
117                Err(err) => Err(Box::new(err)),
118            }));
119        let f = DefaultValueFilter::new(Box::new(move |v| {
120            if *v > 10 {
121                Some(Box::new(*v + 1))
122            } else if *v >= 0 {
123                Some(v)
124            } else {
125                None
126            }
127        }));
128
129        let mut builder = ConfigurationProperties::new_config_builder::<String, i32>();
130        let config = builder
131            .set_key(Box::new("test".to_string()))
132            .set_default_value(Box::new(0))
133            .set_value_filter(ValueFilter::to_boxed(f))
134            .add_value_converter(RawTypeConverter::to_boxed(c))
135            .build();
136        println!("property config: {:?}", config);
137        assert_eq!("test".to_string(), *config.get_key());
138        assert_eq!(0.type_id(), config.get_value_type());
139        assert_eq!(Some(Box::new(0)), config.get_default_value());
140        assert_eq!(
141            Some(Value::to_boxed(12)),
142            config
143                .get_value_filter()
144                .unwrap()
145                .filter_raw(Value::to_boxed(11))
146        );
147        assert_eq!(
148            Ok(Value::to_boxed(10)),
149            config
150                .get_value_converters()
151                .get(0)
152                .unwrap()
153                .convert_raw(Value::as_trait_ref(&"10".to_string()))
154        );
155    }
156
157    #[test]
158    fn new_source_config() {
159        let mut builder = ConfigurationSources::new_config_builder();
160        let config = builder.set_name("test").build();
161        println!("source config: {:?}", config);
162        assert_eq!("test", config.get_name());
163    }
164
165    #[test]
166    fn new_source_test() {
167        init_log();
168
169        let mut builder = ConfigurationSources::new_config_builder();
170        let config = builder.set_name("test").build();
171        let property_provider: PropertyProvider = Arc::new(Box::new(|k| {
172            if k.equals("10".to_string().as_any_ref()) {
173                Some(Value::to_boxed(10))
174            } else {
175                None
176            }
177        }));
178        let source = new_source(config, property_provider);
179        println!("configuration source: {:?}", source);
180        assert_eq!("test", source.get_config().get_name());
181        let property_config = ConfigurationProperties::new_config_builder::<String, i32>()
182            .set_key(Box::new("10".to_string()))
183            .build();
184        assert_eq!(
185            Some(Value::to_boxed(10)),
186            source.get_property_value(RawPropertyConfig::as_trait_ref(property_config.as_ref()))
187        );
188        let property_config = ConfigurationProperties::new_config_builder::<String, i32>()
189            .set_key(Box::new("11".to_string()))
190            .build();
191        assert_eq!(
192            None,
193            source.get_property_value(RawPropertyConfig::as_trait_ref(property_config.as_ref()))
194        );
195    }
196
197    #[test]
198    fn new_manager_config() {
199        let mut builder = ConfigurationSources::new_config_builder();
200        let config = builder.set_name("test").build();
201        let property_provider: PropertyProvider = Arc::new(Box::new(|k| {
202            if k.equals("10".to_string().as_any_ref()) {
203                Some(Value::to_boxed(10))
204            } else {
205                None
206            }
207        }));
208        let source = new_source(config, property_provider);
209        let mut builder = ConfigurationManagers::new_config_builder();
210        let config = builder
211            .set_name("test-manager")
212            .add_source(1, source)
213            .build();
214        println!("manager config: {:?}", config);
215        assert_eq!("test-manager", config.get_name());
216        assert_eq!(1, config.get_sources().len());
217        let changed = Arc::new(AtomicBool::default());
218        let changed_clone = changed.clone();
219        let action: Box<dyn Fn()> = Box::new(move || {
220            changed_clone.swap(true, Ordering::Relaxed);
221            println!("OK");
222        });
223        config.get_task_executor()(&action);
224        assert_eq!(true, changed.fetch_and(true, Ordering::Relaxed));
225    }
226
227    #[test]
228    fn new_manager() {
229        init_log();
230
231        let mut builder = ConfigurationSources::new_config_builder();
232        let source_config = builder.set_name("test").build();
233        let property_provider: PropertyProvider = Arc::new(Box::new(|k| {
234            if k.equals("10".to_string().as_any_ref()) {
235                Some(Value::to_boxed(10))
236            } else {
237                None
238            }
239        }));
240        let source = new_source(source_config, property_provider);
241        let mut builder = ConfigurationManagers::new_config_builder();
242        let config = builder
243            .set_name("test-manager")
244            .add_source(1, source)
245            .build();
246        let manager = ConfigurationManagers::new_manager(config);
247        println!("manager: {:?}", manager);
248        assert_eq!("test-manager", manager.get_config().get_name());
249
250        let c =
251            DefaultTypeConverter::<String, i32>::new(Box::new(move |v| match v.parse::<i32>() {
252                Ok(v) => Ok(Box::new(v)),
253                Err(err) => Err(Box::new(err)),
254            }));
255        let f = DefaultValueFilter::new(Box::new(move |v| {
256            if *v > 10 {
257                Some(Box::new(*v + 1))
258            } else if *v >= 0 {
259                Some(v)
260            } else {
261                None
262            }
263        }));
264        let mut builder = ConfigurationProperties::new_config_builder::<String, i32>();
265        let property_config = builder
266            .set_key(Box::new("10".to_string()))
267            .set_default_value(Box::new(0))
268            .set_value_filter(ValueFilter::to_boxed(f))
269            .add_value_converter(RawTypeConverter::to_boxed(c))
270            .build();
271        let property =
272            manager.get_property(RawPropertyConfig::as_trait_ref(property_config.as_ref()));
273        assert_eq!(Some(Value::to_boxed(10)), property.get_raw_value());
274
275        let value =
276            manager.get_property_value(RawPropertyConfig::as_trait_ref(property_config.as_ref()));
277        assert_eq!(Some(Value::to_boxed(10)), value);
278    }
279
280    #[test]
281    fn properties() {
282        init_log();
283
284        let mut builder = ConfigurationSources::new_config_builder();
285        let source_config = builder.set_name("test").build();
286        let property_provider: PropertyProvider = Arc::new(Box::new(|k| {
287            if k.equals("key_ok".to_string().as_any_ref()) {
288                Some(Value::to_boxed(20))
289            } else {
290                None
291            }
292        }));
293        let source = new_source(source_config, property_provider);
294
295        let memory_map = Arc::new(RwLock::new(HashMap::<String, String>::new()));
296        memory_map
297            .write()
298            .unwrap()
299            .insert("key_ok".to_string(), "10".to_string());
300        memory_map
301            .write()
302            .unwrap()
303            .insert("key_error".to_string(), "error".to_string());
304        let memory_map2 = memory_map.clone();
305        let source_config2 = ConfigurationSources::new_config_builder()
306            .set_name("dynamic_source")
307            .build();
308        let source2 = DefaultConfigurationSource::new(
309            source_config2,
310            Arc::new(Box::new(move |o| -> Option<Box<dyn Value>> {
311                match o.as_any_ref().downcast_ref::<String>() {
312                    Some(k) => memory_map2
313                        .read()
314                        .unwrap()
315                        .get(k)
316                        .map(|v| Value::clone_boxed(v)),
317                    None => None,
318                }
319            })),
320        );
321
322        let mut builder = ConfigurationManagers::new_config_builder();
323        let config = builder
324            .set_name("test-manager")
325            .add_source(1, source)
326            .add_source(2, Box::new(source2.clone()))
327            .build();
328        let manager = ConfigurationManagers::new_manager(config);
329        let properties = ConfigurationProperties::new(manager);
330        println!("properties: {:?}", properties);
331
332        let c =
333            DefaultTypeConverter::<String, i32>::new(Box::new(move |v| match v.parse::<i32>() {
334                Ok(v) => Ok(Box::new(v)),
335                Err(err) => Err(Box::new(err)),
336            }));
337        let f = DefaultValueFilter::new(Box::new(move |v| {
338            if *v > 10 {
339                Some(Box::new(*v + 1))
340            } else if *v >= 0 {
341                Some(v)
342            } else {
343                None
344            }
345        }));
346        let mut builder = ConfigurationProperties::new_config_builder::<String, i32>();
347        let property_config = builder
348            .set_key(Box::new("key_ok".to_string()))
349            .set_default_value(Box::new(0))
350            .set_value_filter(ValueFilter::clone_boxed(&f))
351            .add_value_converter(RawTypeConverter::clone_boxed(&c))
352            .set_doc("for test")
353            .build();
354        let property = properties.get_property(property_config.as_ref());
355        let value = properties.get_property_value(property_config.as_ref());
356        assert_eq!(Some(Box::new(10)), property.get_value());
357        assert_eq!(Some(Box::new(10)), value);
358
359        let mut builder = ConfigurationProperties::new_config_builder::<String, i32>();
360        let property_config2 = builder
361            .set_key(Box::new("key_error".to_string()))
362            .set_value_filter(ValueFilter::to_boxed(f))
363            .add_value_converter(RawTypeConverter::to_boxed(c))
364            .build();
365        let property2 = properties.get_property(property_config2.as_ref());
366        let value2 = properties.get_property_value(property_config2.as_ref());
367        assert_eq!(None, property2.get_value());
368        assert_eq!(None, value2);
369
370        let changed = Arc::new(AtomicBool::new(false));
371        let changed_clone = changed.clone();
372        property.add_change_listener(Arc::new(Box::new(move |e| {
373            println!("changed: {:?}", e);
374            changed_clone.swap(true, Ordering::Relaxed);
375        })));
376        memory_map
377            .write()
378            .unwrap()
379            .insert("key_ok".to_string(), "12".to_string());
380        source2.raise_change_event();
381        assert_eq!(Some(Box::new(13)), property.get_value());
382        assert!(changed.fetch_and(true, Ordering::Relaxed));
383
384        memory_map.write().unwrap().remove(&"key_ok".to_string());
385        source2.raise_change_event();
386        assert_eq!(Some(Box::new(21)), property.get_value());
387    }
388}