1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.configuration2.builder;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertNotSame;
22 import static org.junit.jupiter.api.Assertions.assertSame;
23 import static org.junit.jupiter.api.Assertions.assertThrows;
24 import static org.junit.jupiter.api.Assertions.assertTrue;
25 import static org.mockito.Mockito.mock;
26 import static org.mockito.Mockito.verify;
27 import static org.mockito.Mockito.verifyNoMoreInteractions;
28 import static org.mockito.Mockito.when;
29
30 import java.util.Collection;
31 import java.util.HashMap;
32 import java.util.HashSet;
33 import java.util.Map;
34 import java.util.Set;
35 import java.util.concurrent.CountDownLatch;
36 import java.util.concurrent.TimeUnit;
37
38 import org.apache.commons.configuration2.BaseConfiguration;
39 import org.apache.commons.configuration2.BaseHierarchicalConfiguration;
40 import org.apache.commons.configuration2.Configuration;
41 import org.apache.commons.configuration2.Initializable;
42 import org.apache.commons.configuration2.PropertiesConfiguration;
43 import org.apache.commons.configuration2.XMLConfiguration;
44 import org.apache.commons.configuration2.beanutils.BeanCreationContext;
45 import org.apache.commons.configuration2.beanutils.BeanDeclaration;
46 import org.apache.commons.configuration2.beanutils.BeanFactory;
47 import org.apache.commons.configuration2.beanutils.BeanHelper;
48 import org.apache.commons.configuration2.beanutils.DefaultBeanFactory;
49 import org.apache.commons.configuration2.beanutils.XMLBeanDeclaration;
50 import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
51 import org.apache.commons.configuration2.convert.ListDelimiterHandler;
52 import org.apache.commons.configuration2.event.ConfigurationErrorEvent;
53 import org.apache.commons.configuration2.event.ConfigurationEvent;
54 import org.apache.commons.configuration2.event.ErrorListenerTestImpl;
55 import org.apache.commons.configuration2.event.EventListener;
56 import org.apache.commons.configuration2.event.EventListenerRegistrationData;
57 import org.apache.commons.configuration2.event.EventListenerTestImpl;
58 import org.apache.commons.configuration2.ex.ConfigurationException;
59 import org.apache.commons.configuration2.ex.ConfigurationRuntimeException;
60 import org.apache.commons.configuration2.reloading.ReloadingController;
61 import org.apache.commons.configuration2.reloading.ReloadingDetector;
62 import org.junit.jupiter.api.BeforeAll;
63 import org.junit.jupiter.api.Test;
64
65
66
67
68 public class TestBasicConfigurationBuilder {
69
70
71
72
73 private static final class AccessBuilderThread extends Thread {
74
75
76 private final CountDownLatch startLatch;
77
78
79 private final CountDownLatch endLatch;
80
81
82 private final ConfigurationBuilder<?> builder;
83
84
85 private volatile Object result;
86
87
88
89
90
91
92
93
94 public AccessBuilderThread(final CountDownLatch lstart, final CountDownLatch lend, final ConfigurationBuilder<?> bldr) {
95 startLatch = lstart;
96 endLatch = lend;
97 builder = bldr;
98 }
99
100 @Override
101 public void run() {
102 try {
103 startLatch.await();
104 result = builder.getConfiguration();
105 } catch (final Exception ex) {
106 result = ex;
107 } finally {
108 endLatch.countDown();
109 }
110 }
111 }
112
113
114
115
116 private static final class BasicConfigurationBuilderInitFailImpl extends BasicConfigurationBuilder<PropertiesConfiguration> {
117 public BasicConfigurationBuilderInitFailImpl(final boolean allowFailOnInit) {
118 super(PropertiesConfiguration.class, null, allowFailOnInit);
119 }
120
121
122
123
124 @Override
125 protected void initResultInstance(final PropertiesConfiguration obj) throws ConfigurationException {
126 throw new ConfigurationException("Initialization test exception.");
127 }
128 }
129
130
131
132
133 public static class InitializableConfiguration extends BaseConfiguration implements Initializable {
134
135
136 private String initProperty;
137
138 public String getInitProperty() {
139 return initProperty;
140 }
141
142
143
144
145
146 @Override
147 public void initialize() {
148 initProperty = "Initialized with flag " + isThrowExceptionOnMissing();
149 }
150 }
151
152
153 private static ListDelimiterHandler listHandler;
154
155
156
157
158
159
160 @SuppressWarnings("unchecked")
161 private static EventListener<ConfigurationEvent> createEventListener() {
162 return mock(EventListener.class);
163 }
164
165
166
167
168
169
170 private static Map<String, Object> createTestParameters() {
171 final Map<String, Object> params = new HashMap<>();
172 params.put("throwExceptionOnMissing", Boolean.TRUE);
173 params.put("listDelimiterHandler", listHandler);
174 return params;
175 }
176
177 @BeforeAll
178 public static void setUpBeforeClass() throws Exception {
179 listHandler = new DefaultListDelimiterHandler(';');
180 }
181
182
183
184
185 @Test
186 void testAddConfigurationListener() throws ConfigurationException {
187 final EventListener<ConfigurationEvent> l1 = createEventListener();
188 final EventListener<ConfigurationEvent> l2 = createEventListener();
189 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class);
190 builder.addEventListener(ConfigurationEvent.ANY, l1);
191 final PropertiesConfiguration config = builder.getConfiguration();
192 builder.addEventListener(ConfigurationEvent.ANY, l2);
193 final Collection<EventListener<? super ConfigurationEvent>> listeners = config.getEventListeners(ConfigurationEvent.ANY);
194 assertTrue(listeners.contains(l1));
195 assertTrue(listeners.contains(l2));
196 }
197
198
199
200
201 @Test
202 void testAddParameters() {
203 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class,
204 createTestParameters());
205 final Map<String, Object> params = createTestParameters();
206 params.put("anotherParameter", "value");
207 assertSame(builder, builder.addParameters(params));
208 final Map<String, Object> params2 = builder.getParameters();
209 assertTrue(params2.keySet().containsAll(createTestParameters().keySet()));
210 assertEquals("value", params2.get("anotherParameter"));
211 }
212
213
214
215
216 @Test
217 void testAddParametersNull() {
218 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class,
219 createTestParameters());
220 final Map<String, Object> params = builder.getParameters();
221 builder.addParameters(null);
222 assertEquals(params, builder.getParameters());
223 }
224
225
226
227
228 @Test
229 void testBeanHelperInConfiguration() throws ConfigurationException {
230 final Set<Class<?>> classesPassedToFactory = new HashSet<>();
231 final BeanFactory factory = new DefaultBeanFactory() {
232 @Override
233 public Object createBean(final BeanCreationContext bcc) throws Exception {
234 classesPassedToFactory.add(bcc.getBeanClass());
235 return super.createBean(bcc);
236 }
237 };
238 final BeanHelper helper = new BeanHelper(factory);
239 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class);
240 builder.configure(new BasicBuilderParameters().setBeanHelper(helper));
241 final PropertiesConfiguration config = builder.getConfiguration();
242 assertTrue(classesPassedToFactory.contains(config.getClass()));
243 }
244
245
246
247
248 @Test
249 void testConfigure() {
250 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class)
251 .configure(new BasicBuilderParameters().setListDelimiterHandler(listHandler).setThrowExceptionOnMissing(true));
252 final Map<String, Object> params2 = new HashMap<>(builder.getParameters());
253 assertEquals(createTestParameters(), params2);
254 }
255
256
257
258
259 @Test
260 void testConnectToReloadingController() throws ConfigurationException {
261 final ReloadingDetector detector = mock(ReloadingDetector.class);
262 final ReloadingController controller = new ReloadingController(detector);
263 final BasicConfigurationBuilder<Configuration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class);
264 final Configuration configuration = builder.getConfiguration();
265
266 when(detector.isReloadingRequired()).thenReturn(Boolean.TRUE);
267
268 builder.connectToReloadingController(controller);
269 controller.checkForReloading(null);
270 assertTrue(controller.isInReloadingState());
271 assertNotSame(configuration, builder.getConfiguration());
272 assertFalse(controller.isInReloadingState());
273
274 verify(detector).isReloadingRequired();
275 verify(detector).reloadingPerformed();
276 verifyNoMoreInteractions(detector);
277 }
278
279
280
281
282 @Test
283 void testConnectToReloadingControllerNull() {
284 final BasicConfigurationBuilder<Configuration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class);
285 assertThrows(IllegalArgumentException.class, () -> builder.connectToReloadingController(null));
286 }
287
288
289
290
291 @Test
292 void testCopyEventListeners() throws ConfigurationException {
293 final EventListener<ConfigurationEvent> l1 = createEventListener();
294 final EventListener<ConfigurationEvent> l2 = createEventListener();
295 final EventListener<ConfigurationErrorEvent> l3 = new ErrorListenerTestImpl(null);
296 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class);
297 builder.addEventListener(ConfigurationEvent.ANY, l1);
298 builder.addEventListener(ConfigurationEvent.ANY_HIERARCHICAL, l2);
299 builder.addEventListener(ConfigurationErrorEvent.ANY, l3);
300 final BasicConfigurationBuilder<XMLConfiguration> builder2 = new BasicConfigurationBuilder<>(XMLConfiguration.class);
301 builder.copyEventListeners(builder2);
302 final XMLConfiguration config = builder2.getConfiguration();
303 Collection<EventListener<? super ConfigurationEvent>> listeners = config.getEventListeners(ConfigurationEvent.ANY);
304 assertEquals(1, listeners.size());
305 assertTrue(listeners.contains(l1));
306 listeners = config.getEventListeners(ConfigurationEvent.ANY_HIERARCHICAL);
307 assertEquals(2, listeners.size());
308 assertTrue(listeners.contains(l1));
309 assertTrue(listeners.contains(l2));
310 final Collection<EventListener<? super ConfigurationErrorEvent>> errListeners = config.getEventListeners(ConfigurationErrorEvent.ANY);
311 assertEquals(1, errListeners.size());
312 assertTrue(errListeners.contains(l3));
313 }
314
315
316
317
318 @Test
319 void testEventListenerConfiguration() throws ConfigurationException {
320 final EventListenerTestImpl listener1 = new EventListenerTestImpl(null);
321 final EventListenerRegistrationData<ConfigurationErrorEvent> regData = new EventListenerRegistrationData<>(ConfigurationErrorEvent.WRITE,
322 new ErrorListenerTestImpl(null));
323 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class)
324 .configure(new EventListenerParameters().addEventListener(ConfigurationEvent.ANY, listener1).addEventListener(regData));
325 final PropertiesConfiguration config = builder.getConfiguration();
326 assertTrue(config.getEventListeners(ConfigurationEvent.ANY).contains(listener1));
327 assertTrue(config.getEventListeners(regData.getEventType()).contains(regData.getListener()));
328 }
329
330
331
332
333 @Test
334 void testGetConfiguration() throws ConfigurationException {
335 final PropertiesConfiguration config = new BasicConfigurationBuilder<>(PropertiesConfiguration.class)
336 .configure(new BasicBuilderParameters().setListDelimiterHandler(listHandler).setThrowExceptionOnMissing(true)).getConfiguration();
337 assertTrue(config.isThrowExceptionOnMissing());
338 assertEquals(listHandler, config.getListDelimiterHandler());
339 }
340
341
342
343
344 @Test
345 void testGetConfigurationConcurrently() throws Exception {
346 final int threadCount = 32;
347 final CountDownLatch startLatch = new CountDownLatch(1);
348 final CountDownLatch endLatch = new CountDownLatch(threadCount);
349 final ConfigurationBuilder<?> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class);
350 final AccessBuilderThread[] threads = new AccessBuilderThread[threadCount];
351 for (int i = 0; i < threadCount; i++) {
352 threads[i] = new AccessBuilderThread(startLatch, endLatch, builder);
353 threads[i].start();
354 }
355 startLatch.countDown();
356 assertTrue(endLatch.await(5, TimeUnit.SECONDS));
357 final Set<Object> results = new HashSet<>();
358 for (final AccessBuilderThread t : threads) {
359 results.add(t.result);
360 }
361 assertEquals(1, results.size());
362 }
363
364
365
366
367 @Test
368 void testGetParametersModify() {
369 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class,
370 createTestParameters());
371 final Map<String, Object> parameters = builder.getParameters();
372 assertThrows(UnsupportedOperationException.class, parameters::clear);
373 }
374
375
376
377
378 @Test
379 void testGetResultDeclarationInvalidBeanClass() {
380 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<PropertiesConfiguration>(PropertiesConfiguration.class,
381 createTestParameters()) {
382 @Override
383 protected BeanDeclaration createResultDeclaration(final Map<String, Object> params) {
384 return new XMLBeanDeclaration(new BaseHierarchicalConfiguration(), "bean", true, Object.class.getName());
385 }
386 };
387 assertThrows(ConfigurationRuntimeException.class, builder::getConfiguration);
388 }
389
390
391
392
393 @Test
394 void testInitializableCalled() throws ConfigurationException {
395 final BasicConfigurationBuilder<InitializableConfiguration> builder = new BasicConfigurationBuilder<>(InitializableConfiguration.class);
396 builder.configure(new BasicBuilderParameters().setThrowExceptionOnMissing(true));
397 final InitializableConfiguration config = builder.getConfiguration();
398 assertEquals("Initialized with flag true", config.getInitProperty());
399 }
400
401
402
403
404 @Test
405 void testInitializationErrorAllowed() throws ConfigurationException {
406 final BasicConfigurationBuilderInitFailImpl builder = new BasicConfigurationBuilderInitFailImpl(true);
407 final PropertiesConfiguration config = builder.getConfiguration();
408 assertTrue(config.isEmpty());
409 }
410
411
412
413
414 @Test
415 void testInitializationErrorNotAllowed() {
416 final BasicConfigurationBuilderInitFailImpl builder = new BasicConfigurationBuilderInitFailImpl(false);
417 assertThrows(ConfigurationException.class, builder::getConfiguration);
418 }
419
420
421
422
423 @Test
424 void testInitNoClass() {
425 assertThrows(IllegalArgumentException.class, () -> new BasicConfigurationBuilder<Configuration>(null));
426 }
427
428
429
430
431 @Test
432 void testInitWithParameters() {
433 final Map<String, Object> params = createTestParameters();
434 final BasicConfigurationBuilder<Configuration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class, params);
435 final Map<String, Object> params2 = new HashMap<>(builder.getParameters());
436 assertEquals(createTestParameters(), params2);
437 }
438
439
440
441
442 @Test
443 void testInitWithParametersDefensiveCopy() {
444 final Map<String, Object> params = createTestParameters();
445 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class, params);
446 params.put("anotherParameter", "value");
447 final Map<String, Object> params2 = new HashMap<>(builder.getParameters());
448 assertEquals(createTestParameters(), params2);
449 }
450
451
452
453
454 @Test
455 void testInitWithParametersNull() {
456 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class, null);
457 assertTrue(builder.getParameters().isEmpty());
458 }
459
460
461
462
463 @Test
464 void testRemoveConfigurationListener() throws ConfigurationException {
465 final EventListener<ConfigurationEvent> l1 = createEventListener();
466 final EventListener<ConfigurationEvent> l2 = createEventListener();
467 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class);
468 builder.addEventListener(ConfigurationEvent.ANY_HIERARCHICAL, l1);
469 builder.addEventListener(ConfigurationEvent.ANY, l2);
470 assertTrue(builder.removeEventListener(ConfigurationEvent.ANY, l2));
471 final PropertiesConfiguration config = builder.getConfiguration();
472 assertFalse(config.getEventListeners(ConfigurationEvent.ANY).contains(l2));
473 assertTrue(config.getEventListeners(ConfigurationEvent.ANY_HIERARCHICAL).contains(l1));
474 builder.removeEventListener(ConfigurationEvent.ANY_HIERARCHICAL, l1);
475 assertFalse(config.getEventListeners(ConfigurationEvent.ANY_HIERARCHICAL).contains(l1));
476 }
477
478
479
480
481
482 @Test
483 void testRemoveConfigurationListenersOnReset() throws ConfigurationException {
484 final EventListenerTestImpl listener = new EventListenerTestImpl(null);
485 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class)
486 .configure(new EventListenerParameters().addEventListener(ConfigurationEvent.ANY, listener));
487 final PropertiesConfiguration config = builder.getConfiguration();
488 builder.resetResult();
489 config.addProperty("foo", "bar");
490 listener.done();
491 }
492
493
494
495
496 @Test
497 void testReservedParameter() throws ConfigurationException {
498 final Map<String, Object> params = new HashMap<>();
499 params.put("throwExceptionOnMissing", Boolean.TRUE);
500 params.put("config-test", "a test");
501 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class, params);
502 final PropertiesConfiguration config = builder.getConfiguration();
503 assertTrue(config.isThrowExceptionOnMissing());
504 }
505
506
507
508
509 @Test
510 void testReset() throws ConfigurationException {
511 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class,
512 createTestParameters());
513 final PropertiesConfiguration config = builder.getConfiguration();
514 builder.reset();
515 final PropertiesConfiguration config2 = builder.getConfiguration();
516 assertNotSame(config, config2);
517 assertFalse(config2.isThrowExceptionOnMissing());
518 }
519
520
521
522
523 @Test
524 void testResetParameters() {
525 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class,
526 createTestParameters());
527 builder.resetParameters();
528 assertTrue(builder.getParameters().isEmpty());
529 }
530
531
532
533
534 @Test
535 void testResetResult() throws ConfigurationException {
536 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class,
537 createTestParameters());
538 final PropertiesConfiguration config = builder.getConfiguration();
539 builder.resetResult();
540 final PropertiesConfiguration config2 = builder.getConfiguration();
541 assertNotSame(config, config2);
542 assertTrue(config2.isThrowExceptionOnMissing());
543 }
544
545
546
547
548 @Test
549 void testSetParameters() {
550 final Map<String, Object> params1 = new HashMap<>();
551 params1.put("someParameter", "value");
552 final BasicConfigurationBuilder<PropertiesConfiguration> builder = new BasicConfigurationBuilder<>(PropertiesConfiguration.class, params1);
553 assertSame(builder, builder.setParameters(createTestParameters()));
554 final Map<String, Object> params2 = new HashMap<>(builder.getParameters());
555 assertEquals(createTestParameters(), params2);
556 }
557 }