1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.configuration2;
19
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.HashSet;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Set;
26
27 import javax.naming.Context;
28 import javax.naming.InitialContext;
29 import javax.naming.NameClassPair;
30 import javax.naming.NameNotFoundException;
31 import javax.naming.NamingEnumeration;
32 import javax.naming.NamingException;
33 import javax.naming.NotContextException;
34
35 import org.apache.commons.configuration2.event.ConfigurationErrorEvent;
36 import org.apache.commons.configuration2.io.ConfigurationLogger;
37 import org.apache.commons.lang3.StringUtils;
38
39
40
41
42
43
44 public class JNDIConfiguration extends AbstractConfiguration {
45
46 private String prefix;
47
48
49 private Context context;
50
51
52 private Context baseContext;
53
54
55 private final Set<String> clearedProperties = new HashSet<>();
56
57
58
59
60
61
62 public JNDIConfiguration() throws NamingException {
63 this((String) null);
64 }
65
66
67
68
69
70
71
72
73
74 public JNDIConfiguration(final String prefix) throws NamingException {
75 this(new InitialContext(), prefix);
76 }
77
78
79
80
81
82
83 public JNDIConfiguration(final Context context) {
84 this(context, null);
85 }
86
87
88
89
90
91
92
93
94 public JNDIConfiguration(final Context context, final String prefix) {
95 this.context = context;
96 this.prefix = prefix;
97 initLogger(new ConfigurationLogger(JNDIConfiguration.class));
98 addErrorLogListener();
99 }
100
101
102
103
104
105
106
107
108
109
110
111 private void recursiveGetKeys(final Set<String> keys, final Context context, final String prefix, final Set<Context> processedCtx) throws NamingException {
112 processedCtx.add(context);
113 NamingEnumeration<NameClassPair> elements = null;
114
115 try {
116 elements = context.list("");
117
118
119 while (elements.hasMore()) {
120 final NameClassPair nameClassPair = elements.next();
121 final String name = nameClassPair.getName();
122 final Object object = context.lookup(name);
123
124
125 final StringBuilder keyBuilder = new StringBuilder();
126 keyBuilder.append(prefix);
127 if (keyBuilder.length() > 0) {
128 keyBuilder.append(".");
129 }
130 keyBuilder.append(name);
131
132 if (object instanceof Context) {
133
134 final Context subcontext = (Context) object;
135 if (!processedCtx.contains(subcontext)) {
136 recursiveGetKeys(keys, subcontext, keyBuilder.toString(), processedCtx);
137 }
138 } else {
139
140 keys.add(keyBuilder.toString());
141 }
142 }
143 } finally {
144
145 if (elements != null) {
146 elements.close();
147 }
148 }
149 }
150
151
152
153
154
155
156 @Override
157 protected Iterator<String> getKeysInternal() {
158 return getKeysInternal("");
159 }
160
161
162
163
164
165
166
167 @Override
168 protected Iterator<String> getKeysInternal(final String prefix) {
169
170 final String[] splitPath = StringUtils.split(prefix, ".");
171
172 final List<String> path = Arrays.asList(splitPath);
173
174 try {
175
176 final Context context = getContext(path, getBaseContext());
177
178
179 final Set<String> keys = new HashSet<>();
180 if (context != null) {
181 recursiveGetKeys(keys, context, prefix, new HashSet<>());
182 } else if (containsKey(prefix)) {
183
184 keys.add(prefix);
185 }
186
187 return keys.iterator();
188 } catch (final NameNotFoundException e) {
189
190 return new ArrayList<String>().iterator();
191 } catch (final NamingException e) {
192 fireError(ConfigurationErrorEvent.READ, ConfigurationErrorEvent.READ, null, null, e);
193 return new ArrayList<String>().iterator();
194 }
195 }
196
197
198
199
200
201
202
203
204
205
206 private Context getContext(final List<String> path, final Context context) throws NamingException {
207
208 if (path == null || path.isEmpty()) {
209 return context;
210 }
211
212 final String key = path.get(0);
213
214
215 NamingEnumeration<NameClassPair> elements = null;
216
217 try {
218 elements = context.list("");
219 while (elements.hasMore()) {
220 final NameClassPair nameClassPair = elements.next();
221 final String name = nameClassPair.getName();
222 final Object object = context.lookup(name);
223
224 if (object instanceof Context && name.equals(key)) {
225 final Context subcontext = (Context) object;
226
227
228 return getContext(path.subList(1, path.size()), subcontext);
229 }
230 }
231 } finally {
232 if (elements != null) {
233 elements.close();
234 }
235 }
236
237 return null;
238 }
239
240
241
242
243
244
245 @Override
246 protected boolean isEmptyInternal() {
247 try {
248 NamingEnumeration<NameClassPair> enumeration = null;
249
250 try {
251 enumeration = getBaseContext().list("");
252 return !enumeration.hasMore();
253 } finally {
254
255 if (enumeration != null) {
256 enumeration.close();
257 }
258 }
259 } catch (final NamingException e) {
260 fireError(ConfigurationErrorEvent.READ, ConfigurationErrorEvent.READ, null, null, e);
261 return true;
262 }
263 }
264
265
266
267
268
269
270
271
272
273
274 @Override
275 protected void setPropertyInternal(final String key, final Object value) {
276 throw new UnsupportedOperationException("This operation is not supported");
277 }
278
279
280
281
282
283
284 @Override
285 protected void clearPropertyDirect(final String key) {
286 clearedProperties.add(key);
287 }
288
289
290
291
292
293
294
295 @Override
296 protected boolean containsKeyInternal(String key) {
297 if (clearedProperties.contains(key)) {
298 return false;
299 }
300 key = key.replace('.', '/');
301 try {
302
303 getBaseContext().lookup(key);
304 return true;
305 } catch (final NameNotFoundException e) {
306
307 return false;
308 } catch (final NamingException e) {
309 fireError(ConfigurationErrorEvent.READ, ConfigurationErrorEvent.READ, key, null, e);
310 return false;
311 }
312 }
313
314
315
316
317
318
319 public String getPrefix() {
320 return prefix;
321 }
322
323
324
325
326
327
328 public void setPrefix(final String prefix) {
329 this.prefix = prefix;
330
331
332 baseContext = null;
333 }
334
335
336
337
338
339
340
341 @Override
342 protected Object getPropertyInternal(String key) {
343 if (clearedProperties.contains(key)) {
344 return null;
345 }
346
347 try {
348 key = key.replace('.', '/');
349 return getBaseContext().lookup(key);
350 } catch (final NameNotFoundException | NotContextException nctxex) {
351
352 return null;
353 } catch (final NamingException e) {
354 fireError(ConfigurationErrorEvent.READ, ConfigurationErrorEvent.READ, key, null, e);
355 return null;
356 }
357 }
358
359
360
361
362
363
364
365
366
367
368 @Override
369 protected void addPropertyDirect(final String key, final Object obj) {
370 throw new UnsupportedOperationException("This operation is not supported");
371 }
372
373
374
375
376
377
378
379 public Context getBaseContext() throws NamingException {
380 if (baseContext == null) {
381 baseContext = (Context) getContext().lookup(prefix == null ? "" : prefix);
382 }
383
384 return baseContext;
385 }
386
387
388
389
390
391
392 public Context getContext() {
393 return context;
394 }
395
396
397
398
399
400
401 public void setContext(final Context context) {
402
403 clearedProperties.clear();
404
405
406 this.context = context;
407 }
408 }