1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.configuration;
18
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNull;
21 import static org.junit.Assert.assertSame;
22 import static org.junit.Assert.assertTrue;
23
24 import java.io.File;
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.NoSuchElementException;
30 import java.util.Set;
31
32 import org.apache.commons.collections.CollectionUtils;
33 import org.apache.commons.configuration.event.ConfigurationEvent;
34 import org.apache.commons.configuration.event.ConfigurationListener;
35 import org.apache.commons.configuration.interpol.ConfigurationInterpolator;
36 import org.apache.commons.configuration.reloading.FileAlwaysReloadingStrategy;
37 import org.apache.commons.configuration.tree.ConfigurationNode;
38 import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
39 import org.apache.commons.lang.text.StrLookup;
40 import org.junit.Before;
41 import org.junit.Rule;
42 import org.junit.Test;
43 import org.junit.rules.TemporaryFolder;
44
45
46
47
48
49
50
51
52
53 public class TestSubnodeConfiguration
54 {
55
56 private static final String[] TABLE_NAMES =
57 { "documents", "users" };
58
59
60 private static final String[][] TABLE_FIELDS =
61 {
62 { "docid", "docname", "author", "dateOfCreation", "version", "size" },
63 { "userid", "uname", "firstName", "lastName" } };
64
65
66 private static final String NEW_TABLE_NAME = "newTable";
67
68
69 @Rule
70 public TemporaryFolder folder = new TemporaryFolder();
71
72
73 HierarchicalConfiguration parent;
74
75
76 SubnodeConfiguration config;
77
78
79 int nodeCounter;
80
81 @Before
82 public void setUp() throws Exception
83 {
84 parent = setUpParentConfig();
85 nodeCounter = 0;
86 }
87
88
89
90
91 @Test
92 public void testInitSubNodeConfig()
93 {
94 setUpSubnodeConfig();
95 assertSame("Wrong root node in subnode", getSubnodeRoot(parent), config
96 .getRoot());
97 assertSame("Wrong parent config", parent, config.getParent());
98 }
99
100
101
102
103
104 @Test(expected = IllegalArgumentException.class)
105 public void testInitSubNodeConfigWithNullParent()
106 {
107 config = new SubnodeConfiguration(null, getSubnodeRoot(parent));
108 }
109
110
111
112
113
114 @Test(expected = IllegalArgumentException.class)
115 public void testInitSubNodeConfigWithNullNode()
116 {
117 config = new SubnodeConfiguration(parent, null);
118 }
119
120
121
122
123 @Test
124 public void testGetProperties()
125 {
126 setUpSubnodeConfig();
127 assertEquals("Wrong table name", TABLE_NAMES[0], config
128 .getString("name"));
129 List<Object> fields = config.getList("fields.field.name");
130 assertEquals("Wrong number of fields", TABLE_FIELDS[0].length, fields
131 .size());
132 for (int i = 0; i < TABLE_FIELDS[0].length; i++)
133 {
134 assertEquals("Wrong field at position " + i, TABLE_FIELDS[0][i],
135 fields.get(i));
136 }
137 }
138
139
140
141
142
143 @Test
144 public void testSetProperty()
145 {
146 setUpSubnodeConfig();
147 config.setProperty(null, "testTable");
148 config.setProperty("name", TABLE_NAMES[0] + "_tested");
149 assertEquals("Root value was not set", "testTable", parent
150 .getString("tables.table(0)"));
151 assertEquals("Table name was not changed", TABLE_NAMES[0] + "_tested",
152 parent.getString("tables.table(0).name"));
153
154 parent.setProperty("tables.table(0).fields.field(1).name", "testField");
155 assertEquals("Field name was not changed", "testField", config
156 .getString("fields.field(1).name"));
157 }
158
159
160
161
162 @Test
163 public void testAddProperty()
164 {
165 setUpSubnodeConfig();
166 config.addProperty("[@table-type]", "test");
167 assertEquals("parent.createNode() was not called", 1, nodeCounter);
168 assertEquals("Attribute not set", "test", parent
169 .getString("tables.table(0)[@table-type]"));
170
171 parent.addProperty("tables.table(0).fields.field(-1).name", "newField");
172 List<Object> fields = config.getList("fields.field.name");
173 assertEquals("New field was not added", TABLE_FIELDS[0].length + 1,
174 fields.size());
175 assertEquals("Wrong last field", "newField", fields
176 .get(fields.size() - 1));
177 }
178
179
180
181
182 @Test
183 public void testGetKeys()
184 {
185 setUpSubnodeConfig();
186 Set<String> keys = new HashSet<String>();
187 CollectionUtils.addAll(keys, config.getKeys());
188 assertEquals("Incorrect number of keys", 2, keys.size());
189 assertTrue("Key 1 not contained", keys.contains("name"));
190 assertTrue("Key 2 not contained", keys.contains("fields.field.name"));
191 }
192
193
194
195
196
197 @Test(expected = NoSuchElementException.class)
198 public void testSetThrowExceptionOnMissing()
199 {
200 parent.setThrowExceptionOnMissing(true);
201 setUpSubnodeConfig();
202 assertTrue("Exception flag not fetchted from parent", config
203 .isThrowExceptionOnMissing());
204 config.getString("non existing key");
205 }
206
207
208
209
210 @Test
211 public void testSetThrowExceptionOnMissingAffectsParent()
212 {
213 parent.setThrowExceptionOnMissing(true);
214 setUpSubnodeConfig();
215 config.setThrowExceptionOnMissing(false);
216 assertTrue("Exception flag reset on parent", parent
217 .isThrowExceptionOnMissing());
218 }
219
220
221
222
223
224 @Test
225 public void testSetDelimiterParsingDisabled()
226 {
227 parent.setDelimiterParsingDisabled(true);
228 setUpSubnodeConfig();
229 parent.setDelimiterParsingDisabled(false);
230 assertTrue("Delimiter parsing flag was not received from parent",
231 config.isDelimiterParsingDisabled());
232 config.addProperty("newProp", "test1,test2,test3");
233 assertEquals("New property was splitted", "test1,test2,test3", parent
234 .getString("tables.table(0).newProp"));
235 parent.setDelimiterParsingDisabled(true);
236 config.setDelimiterParsingDisabled(false);
237 assertTrue("Delimiter parsing flag was reset on parent", parent
238 .isDelimiterParsingDisabled());
239 }
240
241
242
243
244
245 @Test
246 public void testSetListDelimiter()
247 {
248 parent.setListDelimiter('/');
249 setUpSubnodeConfig();
250 parent.setListDelimiter(';');
251 assertEquals("List delimiter not obtained from parent", '/', config
252 .getListDelimiter());
253 config.addProperty("newProp", "test1,test2/test3");
254 assertEquals("List was incorrectly splitted", "test1,test2", parent
255 .getString("tables.table(0).newProp"));
256 config.setListDelimiter(',');
257 assertEquals("List delimiter changed on parent", ';', parent
258 .getListDelimiter());
259 }
260
261
262
263
264 @Test
265 public void testSetExpressionEngine()
266 {
267 parent.setExpressionEngine(new XPathExpressionEngine());
268 setUpSubnodeConfig();
269 assertEquals("Wrong field name", TABLE_FIELDS[0][1], config
270 .getString("fields/field[2]/name"));
271 Set<String> keys = new HashSet<String>();
272 CollectionUtils.addAll(keys, config.getKeys());
273 assertEquals("Wrong number of keys", 2, keys.size());
274 assertTrue("Key 1 not contained", keys.contains("name"));
275 assertTrue("Key 2 not contained", keys.contains("fields/field/name"));
276 config.setExpressionEngine(null);
277 assertTrue("Expression engine reset on parent", parent
278 .getExpressionEngine() instanceof XPathExpressionEngine);
279 }
280
281
282
283
284 @Test
285 public void testConfiguarationAt()
286 {
287 setUpSubnodeConfig();
288 SubnodeConfiguration sub2 = config
289 .configurationAt("fields.field(1)");
290 assertEquals("Wrong value of property", TABLE_FIELDS[0][1], sub2
291 .getString("name"));
292 assertEquals("Wrong parent", config.getParent(), sub2.getParent());
293 }
294
295
296
297
298
299 @Test
300 public void testInterpolation()
301 {
302 parent.addProperty("tablespaces.tablespace.name", "default");
303 parent.addProperty("tablespaces.tablespace(-1).name", "test");
304 parent.addProperty("tables.table(0).tablespace",
305 "${tablespaces.tablespace(0).name}");
306 assertEquals("Wrong interpolated tablespace", "default", parent
307 .getString("tables.table(0).tablespace"));
308
309 setUpSubnodeConfig();
310 assertEquals("Wrong interpolated tablespace in subnode", "default",
311 config.getString("tablespace"));
312 }
313
314
315
316
317
318 @Test
319 public void testInterpolationFromConfigurationAt()
320 {
321 parent.addProperty("base.dir", "/home/foo");
322 parent.addProperty("test.absolute.dir.dir1", "${base.dir}/path1");
323 parent.addProperty("test.absolute.dir.dir2", "${base.dir}/path2");
324 parent.addProperty("test.absolute.dir.dir3", "${base.dir}/path3");
325
326 Configuration sub = parent.configurationAt("test.absolute.dir");
327 for (int i = 1; i < 4; i++)
328 {
329 assertEquals("Wrong interpolation in parent", "/home/foo/path" + i,
330 parent.getString("test.absolute.dir.dir" + i));
331 assertEquals("Wrong interpolation in subnode",
332 "/home/foo/path" + i, sub.getString("dir" + i));
333 }
334 }
335
336
337
338
339
340 @Test
341 public void testLocalInterpolationFromConfigurationAt()
342 {
343 parent.addProperty("base.dir", "/home/foo");
344 parent.addProperty("test.absolute.dir.dir1", "${base.dir}/path1");
345 parent.addProperty("test.absolute.dir.dir2", "${dir1}");
346
347 Configuration sub = parent.configurationAt("test.absolute.dir");
348 assertEquals("Wrong interpolation in subnode",
349 "/home/foo/path1", sub.getString("dir1"));
350 assertEquals("Wrong local interpolation in subnode",
351 "/home/foo/path1", sub.getString("dir2"));
352 }
353
354
355
356
357 @Test
358 public void testInterpolator()
359 {
360 parent.addProperty("tablespaces.tablespace.name", "default");
361 parent.addProperty("tablespaces.tablespace(-1).name", "test");
362
363 setUpSubnodeConfig();
364 InterpolationTestHelper.testGetInterpolator(config);
365 }
366
367 @Test
368 public void testLocalLookupsInInterpolatorAreInherited() {
369 parent.addProperty("tablespaces.tablespace.name", "default");
370 parent.addProperty("tablespaces.tablespace(-1).name", "test");
371 parent.addProperty("tables.table(0).var", "${brackets:x}");
372
373 ConfigurationInterpolator interpolator = parent.getInterpolator();
374 interpolator.registerLookup("brackets", new StrLookup(){
375
376 @Override
377 public String lookup(String key) {
378 return "(" + key +")";
379 }
380
381 });
382 setUpSubnodeConfig();
383 assertEquals("Local lookup was not inherited", "(x)", config.getString("var", ""));
384 }
385
386
387
388
389
390
391 @Test
392 public void testParentReloadNotSupported() throws ConfigurationException
393 {
394 Configuration c = setUpReloadTest(false);
395 assertEquals("Name changed in sub config", TABLE_NAMES[1], config
396 .getString("name"));
397 assertEquals("Name not changed in parent", NEW_TABLE_NAME, c
398 .getString("tables.table(1).name"));
399 }
400
401
402
403
404
405 @Test
406 public void testParentReloadSupported() throws ConfigurationException
407 {
408 Configuration c = setUpReloadTest(true);
409 assertEquals("Name not changed in sub config", NEW_TABLE_NAME, config
410 .getString("name"));
411 assertEquals("Name not changed in parent", NEW_TABLE_NAME, c
412 .getString("tables.table(1).name"));
413 }
414
415
416
417
418 @Test
419 public void testParentReloadEvents() throws ConfigurationException
420 {
421 setUpReloadTest(true);
422 ConfigurationListenerTestImpl l = new ConfigurationListenerTestImpl();
423 config.addConfigurationListener(l);
424 config.getString("name");
425 assertEquals("Wrong number of events", 2, l.events.size());
426 boolean before = true;
427 for (ConfigurationEvent e : l.events)
428 {
429 assertEquals("Wrong configuration", config, e.getSource());
430 assertEquals("Wrong event type",
431 HierarchicalConfiguration.EVENT_SUBNODE_CHANGED, e
432 .getType());
433 assertNull("Got a property name", e.getPropertyName());
434 assertNull("Got a property value", e.getPropertyValue());
435 assertEquals("Wrong before flag", before, e.isBeforeUpdate());
436 before = !before;
437 }
438 }
439
440
441
442
443
444
445 @Test
446 public void testParentReloadSupportAccessParent()
447 throws ConfigurationException
448 {
449 Configuration c = setUpReloadTest(true);
450 assertEquals("Name not changed in parent", NEW_TABLE_NAME, c
451 .getString("tables.table(1).name"));
452 assertEquals("Name not changed in sub config", NEW_TABLE_NAME, config
453 .getString("name"));
454 }
455
456
457
458
459 @Test
460 public void testParentReloadSubSubnode() throws ConfigurationException
461 {
462 setUpReloadTest(true);
463 SubnodeConfiguration sub = config.configurationAt("fields", true);
464 assertEquals("Wrong subnode key", "tables.table(1).fields", sub
465 .getSubnodeKey());
466 assertEquals("Changed field not detected", "newField", sub
467 .getString("field(0).name"));
468 }
469
470
471
472
473
474 @Test
475 public void testParentReloadSubSubnodeNoChangeSupport()
476 throws ConfigurationException
477 {
478 setUpReloadTest(false);
479 SubnodeConfiguration sub = config.configurationAt("fields", true);
480 assertNull("Sub sub config is attached to parent", sub.getSubnodeKey());
481 assertEquals("Changed field name returned", TABLE_FIELDS[1][0], sub
482 .getString("field(0).name"));
483 }
484
485
486
487
488
489
490
491
492
493 private XMLConfiguration setUpReloadTest(boolean supportReload)
494 throws ConfigurationException
495 {
496 try
497 {
498 File testFile = folder.newFile();
499 XMLConfiguration xmlConf = new XMLConfiguration(parent);
500 xmlConf.setFile(testFile);
501 xmlConf.save();
502 config = xmlConf.configurationAt("tables.table(1)", supportReload);
503 assertEquals("Wrong table name", TABLE_NAMES[1],
504 config.getString("name"));
505 xmlConf.setReloadingStrategy(new FileAlwaysReloadingStrategy());
506
507 XMLConfiguration confUpdate = new XMLConfiguration(testFile);
508 confUpdate.setProperty("tables.table(1).name", NEW_TABLE_NAME);
509 confUpdate.setProperty("tables.table(1).fields.field(0).name",
510 "newField");
511 confUpdate.save();
512 return xmlConf;
513 }
514 catch (IOException ioex)
515 {
516 throw new ConfigurationException(ioex);
517 }
518 }
519
520
521
522
523
524
525 @Test
526 public void testParentChangeDetach()
527 {
528 final String key = "tables.table(1)";
529 config = parent.configurationAt(key, true);
530 assertEquals("Wrong subnode key", key, config.getSubnodeKey());
531 assertEquals("Wrong table name", TABLE_NAMES[1], config
532 .getString("name"));
533 parent.clearTree(key);
534 assertEquals("Wrong table name after change", TABLE_NAMES[1], config
535 .getString("name"));
536 assertNull("Sub config was not detached", config.getSubnodeKey());
537 }
538
539
540
541
542
543
544 @Test
545 public void testParentChangeDetatchException()
546 {
547 config = parent.configurationAt("tables.table(1)", true);
548 parent.setExpressionEngine(new XPathExpressionEngine());
549 assertEquals("Wrong name of table", TABLE_NAMES[1], config
550 .getString("name"));
551 assertNull("Sub config was not detached", config.getSubnodeKey());
552 }
553
554
555
556
557
558
559
560 protected HierarchicalConfiguration setUpParentConfig()
561 {
562 HierarchicalConfiguration conf = new HierarchicalConfiguration()
563 {
564
565
566
567 private static final long serialVersionUID = 1L;
568
569
570
571 @Override
572 protected Node createNode(String name)
573 {
574 nodeCounter++;
575 return super.createNode(name);
576 }
577 };
578 for (int i = 0; i < TABLE_NAMES.length; i++)
579 {
580 conf.addProperty("tables.table(-1).name", TABLE_NAMES[i]);
581 for (int j = 0; j < TABLE_FIELDS[i].length; j++)
582 {
583 conf.addProperty("tables.table.fields.field(-1).name",
584 TABLE_FIELDS[i][j]);
585 }
586 }
587 return conf;
588 }
589
590
591
592
593
594
595
596
597 protected ConfigurationNode getSubnodeRoot(HierarchicalConfiguration conf)
598 {
599 ConfigurationNode root = conf.getRoot();
600 return root.getChild(0).getChild(0);
601 }
602
603
604
605
606 protected void setUpSubnodeConfig()
607 {
608 config = new SubnodeConfiguration(parent, getSubnodeRoot(parent));
609 }
610
611
612
613
614
615 private static class ConfigurationListenerTestImpl implements ConfigurationListener
616 {
617
618 final List<ConfigurationEvent> events = new ArrayList<ConfigurationEvent>();
619
620 public void configurationChanged(ConfigurationEvent event)
621 {
622 events.add(event);
623 }
624 }
625 }