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