All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.configuration2.JNDIConfiguration Maven / Gradle / Ivy

Go to download

Tools to assist in the reading of configuration/preferences files in various formats

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.commons.configuration2;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameClassPair;
import javax.naming.NameNotFoundException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.NotContextException;

import org.apache.commons.configuration2.event.ConfigurationErrorEvent;
import org.apache.commons.configuration2.io.ConfigurationLogger;
import org.apache.commons.lang3.StringUtils;

/**
 * This Configuration class allows you to interface with a JNDI datasource. A JNDIConfiguration is read-only, write
 * operations will throw an UnsupportedOperationException. The clear operations are supported but the underlying JNDI
 * data source is not changed.
 */
public class JNDIConfiguration extends AbstractConfiguration {
    /** The prefix of the context. */
    private String prefix;

    /** The initial JNDI context. */
    private Context context;

    /** The base JNDI context. */
    private Context baseContext;

    /** The Set of keys that have been virtually cleared. */
    private final Set clearedProperties = new HashSet<>();

    /**
     * Creates a JNDIConfiguration using the default initial context as the root of the properties.
     *
     * @throws NamingException thrown if an error occurs when initializing the default context
     */
    public JNDIConfiguration() throws NamingException {
        this((String) null);
    }

    /**
     * Creates a JNDIConfiguration using the specified initial context as the root of the properties.
     *
     * @param context the initial context
     */
    public JNDIConfiguration(final Context context) {
        this(context, null);
    }

    /**
     * Creates a JNDIConfiguration using the specified initial context shifted by the specified prefix as the root of the
     * properties.
     *
     * @param context the initial context
     * @param prefix the prefix
     */
    public JNDIConfiguration(final Context context, final String prefix) {
        this.context = context;
        this.prefix = prefix;
        initLogger(new ConfigurationLogger(JNDIConfiguration.class));
        addErrorLogListener();
    }

    /**
     * Creates a JNDIConfiguration using the default initial context, shifted with the specified prefix, as the root of the
     * properties.
     *
     * @param prefix the prefix
     *
     * @throws NamingException thrown if an error occurs when initializing the default context
     */
    public JNDIConfiguration(final String prefix) throws NamingException {
        this(new InitialContext(), prefix);
    }

    /**
     * 

* This operation is not supported and will throw an UnsupportedOperationException. *

* * @param key the key * @param obj the value * @throws UnsupportedOperationException always thrown as this method is not supported */ @Override protected void addPropertyDirect(final String key, final Object obj) { throw new UnsupportedOperationException("This operation is not supported"); } /** * Removes the specified property. * * @param key the key of the property to remove */ @Override protected void clearPropertyDirect(final String key) { clearedProperties.add(key); } /** * Checks whether the specified key is contained in this configuration. * * @param key the key to check * @return a flag whether this key is stored in this configuration */ @Override protected boolean containsKeyInternal(String key) { if (clearedProperties.contains(key)) { return false; } key = key.replace('.', '/'); try { // throws a NamingException if JNDI doesn't contain the key. getBaseContext().lookup(key); return true; } catch (final NameNotFoundException e) { // expected exception, no need to log it return false; } catch (final NamingException e) { fireError(ConfigurationErrorEvent.READ, ConfigurationErrorEvent.READ, key, null, e); return false; } } /** * Tests whether this configuration contains one or more matches to this value. This operation stops at first match * but may be more expensive than the containsKey method. * @since 2.11.0 */ @Override protected boolean containsValueInternal(final Object value) { return contains(getKeys(), value); } /** * Gets the base context with the prefix applied. * * @return the base context * @throws NamingException if an error occurs */ public Context getBaseContext() throws NamingException { if (baseContext == null) { baseContext = (Context) getContext().lookup(prefix == null ? "" : prefix); } return baseContext; } /** * Gets the initial context used by this configuration. This context is independent of the prefix specified. * * @return the initial context */ public Context getContext() { return context; } /** * Because JNDI is based on a tree configuration, we need to filter down the tree, till we find the Context specified by * the key to start from. Otherwise return null. * * @param path the path of keys to traverse in order to find the context * @param context the context to start from * @return The context at that key's location in the JNDI tree, or null if not found * @throws NamingException if JNDI has an issue */ private Context getContext(final List path, final Context context) throws NamingException { // return the current context if the path is empty if (path == null || path.isEmpty()) { return context; } final String key = path.get(0); // search a context matching the key in the context's elements NamingEnumeration elements = null; try { elements = context.list(""); while (elements.hasMore()) { final NameClassPair nameClassPair = elements.next(); final String name = nameClassPair.getName(); final Object object = context.lookup(name); if (object instanceof Context && name.equals(key)) { final Context subcontext = (Context) object; // recursive search in the sub context return getContext(path.subList(1, path.size()), subcontext); } } } finally { if (elements != null) { elements.close(); } } return null; } /** * Gets an iterator with all property keys stored in this configuration. * * @return an iterator with all keys */ @Override protected Iterator getKeysInternal() { return getKeysInternal(""); } /** * Gets an iterator with all property keys starting with the given prefix. * * @param prefix the prefix * @return an iterator with the selected keys */ @Override protected Iterator getKeysInternal(final String prefix) { // build the path final String[] splitPath = StringUtils.split(prefix, "."); final List path = Arrays.asList(splitPath); try { // find the context matching the specified path final Context context = getContext(path, getBaseContext()); // return all the keys under the context found final Set keys = new HashSet<>(); if (context != null) { recursiveGetKeys(keys, context, prefix, new HashSet<>()); } else if (containsKey(prefix)) { // add the prefix if it matches exactly a property key keys.add(prefix); } return keys.iterator(); } catch (final NameNotFoundException e) { // expected exception, no need to log it return new ArrayList().iterator(); } catch (final NamingException e) { fireError(ConfigurationErrorEvent.READ, ConfigurationErrorEvent.READ, null, null, e); return new ArrayList().iterator(); } } /** * Gets the prefix. * * @return the prefix */ public String getPrefix() { return prefix; } /** * Gets the value of the specified property. * * @param key the key of the property * @return the value of this property */ @Override protected Object getPropertyInternal(String key) { if (clearedProperties.contains(key)) { return null; } try { key = key.replace('.', '/'); return getBaseContext().lookup(key); } catch (final NameNotFoundException | NotContextException nctxex) { // expected exception, no need to log it return null; } catch (final NamingException e) { fireError(ConfigurationErrorEvent.READ, ConfigurationErrorEvent.READ, key, null, e); return null; } } /** * Returns a flag whether this configuration is empty. * * @return the empty flag */ @Override protected boolean isEmptyInternal() { try { NamingEnumeration enumeration = null; try { enumeration = getBaseContext().list(""); return !enumeration.hasMore(); } finally { // close the enumeration if (enumeration != null) { enumeration.close(); } } } catch (final NamingException e) { fireError(ConfigurationErrorEvent.READ, ConfigurationErrorEvent.READ, null, null, e); return true; } } /** * This method recursive traverse the JNDI tree, looking for Context objects. When it finds them, it traverses them as * well. Otherwise it just adds the values to the list of keys found. * * @param keys All the keys that have been found. * @param context The parent context * @param prefix What prefix we are building on. * @param processedCtx a set with the so far processed objects * @throws NamingException If JNDI has an issue. */ private void recursiveGetKeys(final Set keys, final Context context, final String prefix, final Set processedCtx) throws NamingException { processedCtx.add(context); NamingEnumeration elements = null; try { elements = context.list(""); // iterates through the context's elements while (elements.hasMore()) { final NameClassPair nameClassPair = elements.next(); final String name = nameClassPair.getName(); final Object object = context.lookup(name); // build the key final StringBuilder keyBuilder = new StringBuilder(); keyBuilder.append(prefix); if (keyBuilder.length() > 0) { keyBuilder.append("."); } keyBuilder.append(name); if (object instanceof Context) { // add the keys of the sub context final Context subcontext = (Context) object; if (!processedCtx.contains(subcontext)) { recursiveGetKeys(keys, subcontext, keyBuilder.toString(), processedCtx); } } else { // add the key keys.add(keyBuilder.toString()); } } } finally { // close the enumeration if (elements != null) { elements.close(); } } } /** * Sets the initial context of the configuration. * * @param context the context */ public void setContext(final Context context) { // forget the removed properties clearedProperties.clear(); // change the context this.context = context; } /** * Sets the prefix. * * @param prefix The prefix to set */ public void setPrefix(final String prefix) { this.prefix = prefix; // clear the previous baseContext baseContext = null; } /** *

* This operation is not supported and will throw an UnsupportedOperationException. *

* * @param key the key * @param value the value * @throws UnsupportedOperationException always thrown as this method is not supported */ @Override protected void setPropertyInternal(final String key, final Object value) { throw new UnsupportedOperationException("This operation is not supported"); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy