~ubuntu-branches/ubuntu/saucy/commons-configuration/saucy

« back to all changes in this revision

Viewing changes to src/main/java/org/apache/commons/configuration/JNDIConfiguration.java

  • Committer: Package Import Robot
  • Author(s): Emmanuel Bourg
  • Date: 2013-07-01 16:29:44 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20130701162944-98waq5gogha5gpn1
Tags: 1.9-1
* New upstream release
* debian/control:
  - Updated Standards-Version to 3.9.4 (no changes)
  - Use canonical URLs for the Vcs-* fields
  - Added new build dependencies (libjavacc-maven-plugin-java, junit4)
  - Upgraded the dependency on the Servlet API (2.5 -> 3.0)
  - Removed the dependency on the Activation Framework (glassfish-activation)
  - Replaced the dependency on glassfish-mail with libgnumail-java
  - Removed the unused dependencies:
    liblog4j1.2-java-doc, libmaven-assembly-plugin-java
  - Replaced the dependency on libcommons-jexl-java by libcommons-jexl2-java
* debian/watch: Changed to point the official Apache distribution server
* Removed the obsolete file debian/ant.properties
* Installed the upstream changelog in the binary packages
* Added the report plugins to maven.ignoreRules
* Added the classpath attribute to the jar manifest

Show diffs side-by-side

added added

removed removed

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