2
* Licensed to the Apache Software Foundation (ASF) under one or more
3
* contributor license agreements. See the NOTICE file distributed with
4
* this work for additional information regarding copyright ownership.
5
* The ASF licenses this file to You under the Apache License, Version 2.0
6
* (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
9
* http://www.apache.org/licenses/LICENSE-2.0
11
* Unless required by applicable law or agreed to in writing, software
12
* distributed under the License is distributed on an "AS IS" BASIS,
13
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
* See the License for the specific language governing permissions and
15
* limitations under the License.
18
package org.apache.commons.configuration;
21
import java.io.FileReader;
22
import java.io.FileWriter;
23
import java.io.IOException;
24
import java.io.Reader;
25
import java.io.Writer;
27
import junit.framework.TestCase;
29
import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
30
import org.apache.commons.lang.text.StrLookup;
32
public class TestDynamicCombinedConfiguration extends TestCase
34
private static String PATTERN = "${sys:Id}";
35
private static String PATTERN1 = "target/test-classes/testMultiConfiguration_${sys:Id}.xml";
36
private static String DEFAULT_FILE = "target/test-classes/testMultiConfiguration_default.xml";
37
private static final File MULTI_TENENT_FILE = new File(
38
"conf/testMultiTenentConfigurationBuilder4.xml");
39
private static final File MULTI_DYNAMIC_FILE = new File(
40
"conf/testMultiTenentConfigurationBuilder5.xml");
42
/** Constant for the number of test threads. */
43
private static final int THREAD_COUNT = 3;
45
/** Constant for the number of loops in the multi-thread tests. */
46
private static final int LOOP_COUNT = 100;
48
public void testConfiguration() throws Exception
50
DynamicCombinedConfiguration config = new DynamicCombinedConfiguration();
51
XPathExpressionEngine engine = new XPathExpressionEngine();
52
config.setExpressionEngine(engine);
53
config.setKeyPattern(PATTERN);
54
config.setDelimiterParsingDisabled(true);
55
MultiFileHierarchicalConfiguration multi = new MultiFileHierarchicalConfiguration(PATTERN1);
56
multi.setExpressionEngine(engine);
57
config.addConfiguration(multi, "Multi");
58
XMLConfiguration xml = new XMLConfiguration();
59
xml.setExpressionEngine(engine);
60
xml.setDelimiterParsingDisabled(true);
61
xml.setFile(new File(DEFAULT_FILE));
63
config.addConfiguration(xml, "Default");
65
verify("1001", config, 15);
66
verify("1002", config, 25);
67
verify("1003", config, 35);
68
verify("1004", config, 50);
69
assertEquals("a,b,c", config.getString("split/list3/@values"));
70
assertEquals(0, config.getMaxIndex("split/list3/@values"));
71
assertEquals("a\\,b\\,c", config.getString("split/list4/@values"));
72
assertEquals("a,b,c", config.getString("split/list1"));
73
assertEquals(0, config.getMaxIndex("split/list1"));
74
assertEquals("a\\,b\\,c", config.getString("split/list2"));
77
public void testConcurrentGetAndReload() throws Exception
79
System.getProperties().remove("Id");
80
DefaultConfigurationBuilder factory = new DefaultConfigurationBuilder();
81
factory.setFile(MULTI_TENENT_FILE);
82
CombinedConfiguration config = factory.getConfiguration(true);
84
assertEquals(config.getString("rowsPerPage"), "50");
85
Thread testThreads[] = new Thread[THREAD_COUNT];
86
int failures[] = new int[THREAD_COUNT];
88
for (int i = 0; i < testThreads.length; ++i)
90
testThreads[i] = new ReloadThread(config, failures, i, LOOP_COUNT, false, null, "50");
91
testThreads[i].start();
94
int totalFailures = 0;
95
for (int i = 0; i < testThreads.length; ++i)
97
testThreads[i].join();
98
totalFailures += failures[i];
100
assertTrue(totalFailures + " failures Occurred", totalFailures == 0);
103
public void testConcurrentGetAndReload2() throws Exception
105
System.getProperties().remove("Id");
106
DefaultConfigurationBuilder factory = new DefaultConfigurationBuilder();
107
factory.setFile(MULTI_TENENT_FILE);
108
CombinedConfiguration config = factory.getConfiguration(true);
110
assertEquals(config.getString("rowsPerPage"), "50");
112
Thread testThreads[] = new Thread[THREAD_COUNT];
113
int failures[] = new int[THREAD_COUNT];
114
System.setProperty("Id", "2002");
115
assertEquals(config.getString("rowsPerPage"), "25");
116
for (int i = 0; i < testThreads.length; ++i)
118
testThreads[i] = new ReloadThread(config, failures, i, LOOP_COUNT, false, null, "25");
119
testThreads[i].start();
122
int totalFailures = 0;
123
for (int i = 0; i < testThreads.length; ++i)
125
testThreads[i].join();
126
totalFailures += failures[i];
128
System.getProperties().remove("Id");
129
assertTrue(totalFailures + " failures Occurred", totalFailures == 0);
132
public void testConcurrentGetAndReloadMultipleClients() throws Exception
134
System.getProperties().remove("Id");
135
DefaultConfigurationBuilder factory = new DefaultConfigurationBuilder();
136
factory.setFile(MULTI_TENENT_FILE);
137
CombinedConfiguration config = factory.getConfiguration(true);
139
assertEquals(config.getString("rowsPerPage"), "50");
141
Thread testThreads[] = new Thread[THREAD_COUNT];
142
int failures[] = new int[THREAD_COUNT];
143
String[] ids = new String[] {null, "2002", "3001", "3002", "3003"};
144
String[] expected = new String[] {"50", "25", "15", "25", "50"};
145
for (int i = 0; i < testThreads.length; ++i)
147
testThreads[i] = new ReloadThread(config, failures, i, LOOP_COUNT, true, ids[i], expected[i]);
148
testThreads[i].start();
151
int totalFailures = 0;
152
for (int i = 0; i < testThreads.length; ++i)
154
testThreads[i].join();
155
totalFailures += failures[i];
157
System.getProperties().remove("Id");
158
if (totalFailures != 0)
160
System.out.println("Failures:");
161
for (int i = 0; i < testThreads.length; ++i)
163
System.out.println("Thread " + i + " " + failures[i]);
166
assertTrue(totalFailures + " failures Occurred", totalFailures == 0);
169
public void testConcurrentGetAndReloadFile() throws Exception
171
final int threadCount = 25;
172
System.getProperties().remove("Id");
173
// create a new configuration
174
File input = new File("target/test-classes/testMultiDynamic_default.xml");
175
File output = new File("target/test-classes/testwrite/testMultiDynamic_default.xml");
177
output.getParentFile().mkdir();
178
copyFile(input, output);
180
DefaultConfigurationBuilder factory = new DefaultConfigurationBuilder();
181
factory.setFile(MULTI_DYNAMIC_FILE);
182
CombinedConfiguration config = factory.getConfiguration(true);
184
assertEquals(config.getString("Product/FIIndex/FI[@id='123456781']"), "ID0001");
186
ReaderThread testThreads[] = new ReaderThread[threadCount];
187
for (int i = 0; i < testThreads.length; ++i)
189
testThreads[i] = new ReaderThread(config);
190
testThreads[i].start();
195
input = new File("target/test-classes/testMultiDynamic_default2.xml");
196
copyFile(input, output);
199
String id = config.getString("Product/FIIndex/FI[@id='123456782']");
200
assertNotNull("File did not reload, id is null", id);
201
String rows = config.getString("rowsPerPage");
202
assertTrue("Incorrect value for rowsPerPage", "25".equals(rows));
204
for (int i = 0; i < testThreads.length; ++i)
206
testThreads[i].shutdown();
207
testThreads[i].join();
209
for (int i = 0; i < testThreads.length; ++i)
211
assertFalse(testThreads[i].failed());
213
assertEquals("ID0002", config.getString("Product/FIIndex/FI[@id='123456782']"));
218
private class ReloadThread extends Thread
220
CombinedConfiguration combined;
228
ReloadThread(CombinedConfiguration config, int[] failures, int index, int count,
229
boolean useId, String id, String expected)
232
this.failures = failures;
235
this.expected = expected;
245
ThreadLookup.setId(id);
247
for (int i = 0; i < count; i++)
251
String value = combined.getString("rowsPerPage", null);
252
if (value == null || !value.equals(expected))
265
private class ReaderThread extends Thread
267
private boolean running = true;
268
private boolean failed = false;
269
CombinedConfiguration combined;
271
public ReaderThread(CombinedConfiguration c)
280
String bcId = combined.getString("Product/FIIndex/FI[@id='123456781']");
281
if ("ID0001".equalsIgnoreCase(bcId))
285
System.out.println("Thread failed, but recovered");
296
public boolean failed()
301
public void shutdown()
308
private void verify(String key, DynamicCombinedConfiguration config, int rows)
310
System.setProperty("Id", key);
311
assertTrue(config.getInt("rowsPerPage") == rows);
314
private void copyFile(File input, File output) throws IOException
316
Reader reader = new FileReader(input);
317
Writer writer = new FileWriter(output);
318
char[] buffer = new char[4096];
320
while (-1 != (n = reader.read(buffer)))
322
writer.write(buffer, 0, n);
328
public static class ThreadLookup extends StrLookup
330
private static ThreadLocal id = new ThreadLocal();
334
public ThreadLookup()
339
public static void setId(String value)
344
public String lookup(String key)
346
if (key == null || !key.equals("Id"))
350
String value = System.getProperty("Id");
355
return (String)id.get();