%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.commons.configuration.JNDIConfiguration |
|
|
1 | /* |
|
2 | * Copyright 2001-2005 The Apache Software Foundation. |
|
3 | * |
|
4 | * Licensed under the Apache License, Version 2.0 (the "License") |
|
5 | * you may not use this file except in compliance with the License. |
|
6 | * You may obtain a copy of the License at |
|
7 | * |
|
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 | * |
|
10 | * Unless required by applicable law or agreed to in writing, software |
|
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 | * See the License for the specific language governing permissions and |
|
14 | * limitations under the License. |
|
15 | */ |
|
16 | ||
17 | package org.apache.commons.configuration; |
|
18 | ||
19 | import java.util.ArrayList; |
|
20 | import java.util.HashSet; |
|
21 | import java.util.Iterator; |
|
22 | import java.util.List; |
|
23 | import java.util.Set; |
|
24 | ||
25 | import javax.naming.Context; |
|
26 | import javax.naming.InitialContext; |
|
27 | import javax.naming.NameClassPair; |
|
28 | import javax.naming.NameNotFoundException; |
|
29 | import javax.naming.NamingEnumeration; |
|
30 | import javax.naming.NamingException; |
|
31 | ||
32 | import org.apache.commons.lang.StringUtils; |
|
33 | import org.apache.commons.logging.Log; |
|
34 | import org.apache.commons.logging.LogFactory; |
|
35 | ||
36 | /** |
|
37 | * This Configuration class allows you to interface with a JNDI datasource. |
|
38 | * A JNDIConfiguration is read-only, write operations will throw an |
|
39 | * UnsupportedOperationException. The clear operations are supported but the |
|
40 | * underlying JNDI data source is not changed. |
|
41 | * |
|
42 | * @author <a href="mailto:epugh@upstate.com">Eric Pugh</a> |
|
43 | * @version $Id: JNDIConfiguration.java 295090 2005-10-05 19:36:15Z oheger $ |
|
44 | */ |
|
45 | 27 | public class JNDIConfiguration extends AbstractConfiguration |
46 | { |
|
47 | /** Logger. */ |
|
48 | 27 | private static Log log = LogFactory.getLog(JNDIConfiguration.class); |
49 | ||
50 | /** The prefix of the context. */ |
|
51 | private String prefix; |
|
52 | ||
53 | /** The initial JNDI context. */ |
|
54 | private Context context; |
|
55 | ||
56 | /** The base JNDI context. */ |
|
57 | private Context baseContext; |
|
58 | ||
59 | /** The Set of keys that have been virtually cleared. */ |
|
60 | 144 | private Set clearedProperties = new HashSet(); |
61 | ||
62 | /** |
|
63 | * Creates a JNDIConfiguration using the default initial context as the |
|
64 | * root of the properties. |
|
65 | * |
|
66 | * @throws NamingException thrown if an error occurs when initializing the default context |
|
67 | */ |
|
68 | public JNDIConfiguration() throws NamingException |
|
69 | { |
|
70 | 138 | this((String) null); |
71 | 138 | } |
72 | ||
73 | /** |
|
74 | * Creates a JNDIConfiguration using the default initial context, shifted |
|
75 | * with the specified prefix, as the root of the properties. |
|
76 | * |
|
77 | * @param prefix the prefix |
|
78 | * |
|
79 | * @throws NamingException thrown if an error occurs when initializing the default context |
|
80 | */ |
|
81 | public JNDIConfiguration(String prefix) throws NamingException |
|
82 | { |
|
83 | 138 | this(new InitialContext(), prefix); |
84 | 138 | } |
85 | ||
86 | /** |
|
87 | * Creates a JNDIConfiguration using the specified initial context as the |
|
88 | * root of the properties. |
|
89 | * |
|
90 | * @param context the initial context |
|
91 | */ |
|
92 | public JNDIConfiguration(Context context) |
|
93 | { |
|
94 | 3 | this(context, null); |
95 | 3 | } |
96 | ||
97 | /** |
|
98 | * Creates a JNDIConfiguration using the specified initial context shifted |
|
99 | * by the specified prefix as the root of the properties. |
|
100 | * |
|
101 | * @param context the initial context |
|
102 | * @param prefix the prefix |
|
103 | */ |
|
104 | public JNDIConfiguration(Context context, String prefix) |
|
105 | 144 | { |
106 | 144 | this.context = context; |
107 | 144 | this.prefix = prefix; |
108 | 144 | } |
109 | ||
110 | /** |
|
111 | * This method recursive traverse the JNDI tree, looking for Context objects. |
|
112 | * When it finds them, it traverses them as well. Otherwise it just adds the |
|
113 | * values to the list of keys found. |
|
114 | * |
|
115 | * @param keys All the keys that have been found. |
|
116 | * @param context The parent context |
|
117 | * @param prefix What prefix we are building on. |
|
118 | * @throws NamingException If JNDI has an issue. |
|
119 | */ |
|
120 | private void recursiveGetKeys(Set keys, Context context, String prefix) throws NamingException |
|
121 | { |
|
122 | 27 | NamingEnumeration elements = null; |
123 | ||
124 | try |
|
125 | { |
|
126 | 27 | elements = context.list(""); |
127 | ||
128 | // iterates through the context's elements |
|
129 | 243 | while (elements.hasMore()) |
130 | { |
|
131 | 189 | NameClassPair nameClassPair = (NameClassPair) elements.next(); |
132 | 189 | String name = nameClassPair.getName(); |
133 | 189 | Object object = context.lookup(name); |
134 | ||
135 | // build the key |
|
136 | 189 | StringBuffer key = new StringBuffer(); |
137 | 189 | key.append(prefix); |
138 | 189 | if (key.length() > 0) |
139 | { |
|
140 | 180 | key.append("."); |
141 | } |
|
142 | 189 | key.append(name); |
143 | ||
144 | 189 | if (object instanceof Context) |
145 | { |
|
146 | // add the keys of the sub context |
|
147 | 9 | Context subcontext = (Context) object; |
148 | 9 | recursiveGetKeys(keys, subcontext, key.toString()); |
149 | } |
|
150 | else |
|
151 | { |
|
152 | // add the key |
|
153 | 180 | keys.add(key.toString()); |
154 | } |
|
155 | } |
|
156 | 27 | } |
157 | finally |
|
158 | { |
|
159 | // close the enumeration |
|
160 | 0 | if (elements != null) |
161 | { |
|
162 | 27 | elements.close(); |
163 | } |
|
164 | } |
|
165 | 27 | } |
166 | ||
167 | /** |
|
168 | * Returns an iterator with all property keys stored in this configuration. |
|
169 | * |
|
170 | * @return an iterator with all keys |
|
171 | */ |
|
172 | public Iterator getKeys() |
|
173 | { |
|
174 | 9 | return getKeys(""); |
175 | } |
|
176 | ||
177 | /** |
|
178 | * Returns an iterator with all property keys starting with the given |
|
179 | * prefix. |
|
180 | * |
|
181 | * @param prefix the prefix |
|
182 | * @return an iterator with the selected keys |
|
183 | */ |
|
184 | public Iterator getKeys(String prefix) |
|
185 | { |
|
186 | // build the path |
|
187 | 30 | String[] splitPath = StringUtils.split(prefix, "."); |
188 | ||
189 | 30 | List path = new ArrayList(); |
190 | ||
191 | 63 | for (int i = 0; i < splitPath.length; i++) |
192 | { |
|
193 | 33 | path.add(splitPath[i]); |
194 | } |
|
195 | ||
196 | try |
|
197 | { |
|
198 | // find the context matching the specified path |
|
199 | 30 | Context context = getContext(path, getBaseContext()); |
200 | ||
201 | // return all the keys under the context found |
|
202 | 30 | Set keys = new HashSet(); |
203 | 30 | if (context != null) |
204 | { |
|
205 | 18 | recursiveGetKeys(keys, context, prefix); |
206 | } |
|
207 | 12 | else if (containsKey(prefix)) |
208 | { |
|
209 | // add the prefix if it matches exactly a property key |
|
210 | 6 | keys.add(prefix); |
211 | } |
|
212 | ||
213 | 30 | return keys.iterator(); |
214 | } |
|
215 | catch (NamingException e) |
|
216 | { |
|
217 | 0 | log.error(e.getMessage(), e); |
218 | 0 | return new ArrayList().iterator(); |
219 | } |
|
220 | } |
|
221 | ||
222 | /** |
|
223 | * Because JNDI is based on a tree configuration, we need to filter down the |
|
224 | * tree, till we find the Context specified by the key to start from. |
|
225 | * Otherwise return null. |
|
226 | * |
|
227 | * @param path the path of keys to traverse in order to find the context |
|
228 | * @param context the context to start from |
|
229 | * @return The context at that key's location in the JNDI tree, or null if not found |
|
230 | * @throws NamingException if JNDI has an issue |
|
231 | */ |
|
232 | private Context getContext(List path, Context context) throws NamingException |
|
233 | { |
|
234 | // return the current context if the path is empty |
|
235 | 45 | if (path == null || path.isEmpty()) |
236 | { |
|
237 | 18 | return context; |
238 | } |
|
239 | ||
240 | 27 | String key = (String) path.get(0); |
241 | ||
242 | // search a context matching the key in the context's elements |
|
243 | 27 | NamingEnumeration elements = null; |
244 | ||
245 | try |
|
246 | { |
|
247 | 27 | elements = context.list(""); |
248 | 120 | while (elements.hasMore()) |
249 | { |
|
250 | 81 | NameClassPair nameClassPair = (NameClassPair) elements.next(); |
251 | 81 | String name = nameClassPair.getName(); |
252 | 81 | Object object = context.lookup(name); |
253 | ||
254 | 81 | if (object instanceof Context && name.equals(key)) |
255 | { |
|
256 | 15 | Context subcontext = (Context) object; |
257 | ||
258 | // recursive search in the sub context |
|
259 | 15 | return getContext(path.subList(1, path.size()), subcontext); |
260 | } |
|
261 | } |
|
262 | 12 | } |
263 | finally |
|
264 | { |
|
265 | 0 | if (elements != null) |
266 | { |
|
267 | 27 | elements.close(); |
268 | } |
|
269 | } |
|
270 | ||
271 | 12 | return null; |
272 | } |
|
273 | ||
274 | /** |
|
275 | * Returns a flag whether this configuration is empty. |
|
276 | * |
|
277 | * @return the empty flag |
|
278 | */ |
|
279 | public boolean isEmpty() |
|
280 | { |
|
281 | try |
|
282 | { |
|
283 | 6 | NamingEnumeration enumeration = null; |
284 | ||
285 | try |
|
286 | { |
|
287 | 6 | enumeration = getBaseContext().list(""); |
288 | 6 | return !enumeration.hasMore(); |
289 | } |
|
290 | finally |
|
291 | { |
|
292 | // close the enumeration |
|
293 | 0 | if (enumeration != null) |
294 | { |
|
295 | 6 | enumeration.close(); |
296 | } |
|
297 | } |
|
298 | } |
|
299 | catch (NamingException e) |
|
300 | { |
|
301 | 0 | log.error(e.getMessage(), e); |
302 | 0 | return true; |
303 | } |
|
304 | } |
|
305 | ||
306 | /** |
|
307 | * <p><strong>This operation is not supported and will throw an |
|
308 | * UnsupportedOperationException.</strong></p> |
|
309 | * |
|
310 | * @param key the key |
|
311 | * @param value the value |
|
312 | * @throws UnsupportedOperationException |
|
313 | */ |
|
314 | public void setProperty(String key, Object value) |
|
315 | { |
|
316 | 0 | throw new UnsupportedOperationException("This operation is not supported"); |
317 | } |
|
318 | ||
319 | /** |
|
320 | * Removes the specified property. |
|
321 | * |
|
322 | * @param key the key of the property to remove |
|
323 | */ |
|
324 | public void clearProperty(String key) |
|
325 | { |
|
326 | 12 | clearedProperties.add(key); |
327 | 12 | } |
328 | ||
329 | /** |
|
330 | * Checks whether the specified key is contained in this configuration. |
|
331 | * |
|
332 | * @param key the key to check |
|
333 | * @return a flag whether this key is stored in this configuration |
|
334 | */ |
|
335 | public boolean containsKey(String key) |
|
336 | { |
|
337 | 30 | if (clearedProperties.contains(key)) |
338 | { |
|
339 | 3 | return false; |
340 | } |
|
341 | 27 | key = StringUtils.replace(key, ".", "/"); |
342 | try |
|
343 | { |
|
344 | // throws a NamingException if JNDI doesn't contain the key. |
|
345 | 27 | getBaseContext().lookup(key); |
346 | 15 | return true; |
347 | } |
|
348 | catch (NameNotFoundException e) |
|
349 | { |
|
350 | // expected exception, no need to log it |
|
351 | 12 | return false; |
352 | } |
|
353 | catch (NamingException e) |
|
354 | { |
|
355 | 0 | log.error(e.getMessage(), e); |
356 | 0 | return false; |
357 | } |
|
358 | } |
|
359 | ||
360 | /** |
|
361 | * Returns the prefix. |
|
362 | * @return the prefix |
|
363 | */ |
|
364 | public String getPrefix() |
|
365 | { |
|
366 | 0 | return prefix; |
367 | } |
|
368 | ||
369 | /** |
|
370 | * Sets the prefix. |
|
371 | * |
|
372 | * @param prefix The prefix to set |
|
373 | */ |
|
374 | public void setPrefix(String prefix) |
|
375 | { |
|
376 | 6 | this.prefix = prefix; |
377 | ||
378 | // clear the previous baseContext |
|
379 | 6 | baseContext = null; |
380 | 6 | } |
381 | ||
382 | /** |
|
383 | * Returns the value of the specified property. |
|
384 | * |
|
385 | * @param key the key of the property |
|
386 | * @return the value of this property |
|
387 | */ |
|
388 | public Object getProperty(String key) |
|
389 | { |
|
390 | 180 | if (clearedProperties.contains(key)) |
391 | { |
|
392 | 9 | return null; |
393 | } |
|
394 | ||
395 | try |
|
396 | { |
|
397 | 171 | key = StringUtils.replace(key, ".", "/"); |
398 | 171 | return getBaseContext().lookup(key); |
399 | } |
|
400 | catch (NameNotFoundException e) |
|
401 | { |
|
402 | // expected exception, no need to log it |
|
403 | 21 | return null; |
404 | } |
|
405 | catch (NamingException e) |
|
406 | { |
|
407 | 21 | log.error(e.getMessage(), e); |
408 | 21 | return null; |
409 | } |
|
410 | } |
|
411 | ||
412 | /** |
|
413 | * <p><strong>This operation is not supported and will throw an |
|
414 | * UnsupportedOperationException.</strong></p> |
|
415 | * |
|
416 | * @param key the key |
|
417 | * @param obj the value |
|
418 | * @throws UnsupportedOperationException |
|
419 | */ |
|
420 | protected void addPropertyDirect(String key, Object obj) |
|
421 | { |
|
422 | 0 | throw new UnsupportedOperationException("This operation is not supported"); |
423 | } |
|
424 | ||
425 | /** |
|
426 | * Return the base context with the prefix applied. |
|
427 | * |
|
428 | * @return the base context |
|
429 | * @throws NamingException if an error occurs |
|
430 | */ |
|
431 | public Context getBaseContext() throws NamingException |
|
432 | { |
|
433 | 234 | if (baseContext == null) |
434 | { |
|
435 | 138 | baseContext = (Context) getContext().lookup(prefix == null ? "" : prefix); |
436 | } |
|
437 | ||
438 | 234 | return baseContext; |
439 | } |
|
440 | ||
441 | /** |
|
442 | * Return the initial context used by this configuration. This context is |
|
443 | * independent of the prefix specified. |
|
444 | * |
|
445 | * @return the initial context |
|
446 | */ |
|
447 | public Context getContext() |
|
448 | { |
|
449 | 138 | return context; |
450 | } |
|
451 | ||
452 | /** |
|
453 | * Set the initial context of the configuration. |
|
454 | * |
|
455 | * @param context the context |
|
456 | */ |
|
457 | public void setContext(Context context) |
|
458 | { |
|
459 | // forget the removed properties |
|
460 | 3 | clearedProperties.clear(); |
461 | ||
462 | // change the context |
|
463 | 3 | this.context = context; |
464 | 3 | } |
465 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |