Hi, I noticed the Simian report complained about similarities between JNDIConfiguration and AsbtractConfiguration, because JNDIConfiguration doesn't extend AsbtractConfiguration (yet). This patch should remedy the issue, it performs the following changes:
- extend AbstractConfiguration instead of BaseConfiguration - rename getValueFromJNDI into getPropertyDirect - add a setPropertyDirect method throwing an UnsupportedOperationException - throw an UnsupportedOperationException on write operations instead of a java.lang.Error - remove the default constructor - clearedProperties is now a Set instead of a List - more tests for subset(), clearProperty(), getKeys() and isEmpty(). - minor javadoc & style changes
Most tests are ok once the patch is applied, but the test on getKeys() still fails. It seems the listBindings() method of our test JNDI context is broken.
Emmanuel Bourg
Index: src/java/org/apache/commons/configuration/JNDIConfiguration.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons/configuration/src/java/org/apache/commons/configuration/JNDIConfiguration.java,v
retrieving revision 1.9
diff -u -r1.9 JNDIConfiguration.java
--- src/java/org/apache/commons/configuration/JNDIConfiguration.java 13 Mar 2004
17:30:42 -0000 1.9
+++ src/java/org/apache/commons/configuration/JNDIConfiguration.java 23 Mar 2004
12:55:08 -0000
@@ -1,4 +1,3 @@
-package org.apache.commons.configuration;
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
@@ -14,65 +13,69 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Properties;
+
+package org.apache.commons.configuration;
+
import javax.naming.Binding;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Properties;
+import java.util.Set;
+
import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* 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.
+ *
* @version $Id: JNDIConfiguration.java,v 1.9 2004/03/13 17:30:42 epugh Exp $
*/
-public class JNDIConfiguration
- extends BaseConfiguration
- implements Configuration
+public class JNDIConfiguration extends AbstractConfiguration
{
private static Log log = LogFactory.getLog(JNDIConfiguration.class);
+
+ /** The prefix of the context. */
private String prefix;
- private Context envCtx;
- private List clearedProperties = new ArrayList();
- /**
- * Creates an empty JNDIConfiguration object which can then
- * be added some other Configuration files
- */
- public JNDIConfiguration()
- {
- }
+
+ /** The JNDI context. */
+ private Context context;
+
+ /** The Set of keys that have been virtually cleared. */
+ private Set clearedProperties = new HashSet();
+
/**
- * JNDIConfigurations can not be added to
+ * JNDIConfigurations can not be added to.
*
* @param key The Key to add the property to.
* @param token The Value to add.
*/
public void addProperty(String key, Object token)
{
- throw new Error("This operation is not supported");
+ throw new UnsupportedOperationException("This operation is not supported");
}
+
/**
* 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 enum An enumeration of all the elements found at a specific context
* @param key What key we are building on.
* @throws NamingException If JNDI has an issue.
*/
- private void recursiveGetKeys(
- List keys,
- NamingEnumeration enum,
- String key)
- throws NamingException
+ private void recursiveGetKeys(List keys, NamingEnumeration enum, String key)
throws NamingException
{
while (enum.hasMoreElements())
{
@@ -86,9 +89,8 @@
newKey.append(binding.getName());
if (binding.getObject() instanceof Context)
{
- Context c = (Context) binding.getObject();
- NamingEnumeration enum2 = c.listBindings("");
- recursiveGetKeys(keys, enum2, newKey.toString());
+ Context context = (Context) binding.getObject();
+ recursiveGetKeys(keys, context.listBindings(""), newKey.toString());
}
else
{
@@ -99,9 +101,9 @@
}
}
}
+
/**
- * Get the list of the keys contained in the configuration
- * repository.
+ * Get the list of the keys contained in the configuration repository.
*
* @return An Iterator.
*/
@@ -109,6 +111,7 @@
{
return getKeys("");
}
+
/**
* Get the list of the keys contained in the configuration
* repository that match a passed in beginning pattern.
@@ -126,23 +129,22 @@
{
keys.add(splitKeys[i]);
}
+
Context context = null;
- if (keys.size() == 0)
+
+ if (keys.isEmpty())
{
context = getContext();
}
else
{
- context =
- getStartingContextPoint(
- keys,
- getContext().listBindings(""));
+ context = getStartingContextPoint(keys,
getContext().listBindings(""));
}
+
if (context != null)
{
-
NamingEnumeration enum = context.listBindings("");
-
+
recursiveGetKeys(keys, enum, key);
}
}
@@ -150,19 +152,20 @@
{
log.warn(ne);
}
+
return keys.iterator();
}
+
/**
* 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.
+ * tree, till we find the Context specified by the key to start from.
* Otherwise return null.
- *
+ *
* @param The key (or name) of the Context we are looking 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 getStartingContextPoint(List keys, NamingEnumeration enum)
- throws NamingException
+ private Context getStartingContextPoint(List keys, NamingEnumeration enum) throws
NamingException
{
String keyToSearchFor = (String) keys.get(0);
log.debug("Key to search for is " + keyToSearchFor);
@@ -181,7 +184,7 @@
{
keys.remove(0);
Context c = (Context) binding.getObject();
- if (keys.size() > 0)
+ if (!keys.isEmpty())
{
return getStartingContextPoint(keys, c.listBindings(""));
}
@@ -193,22 +196,20 @@
}
return null;
}
+
/**
- * Get a list of properties associated with the given
- * configuration key.
+ * Get a list of properties associated with the given configuration key.
*
* @param key The configuration key.
* @return The associated properties if key is found.
- * @throws ClassCastException is thrown if the key maps to an
- * object that is not a String/List.
- * @throws IllegalArgumentException if one of the tokens is
- * malformed (does not contain an equals sign).
- * @see #getProperties(String, Properties)
+ * @throws ClassCastException is thrown if the key maps to an object that is not
a String/List.
+ * @throws IllegalArgumentException if one of the tokens is malformed (does not
contain an equals sign).
*/
public Properties getProperties(String key)
{
- throw new Error("This operation is not supported");
+ throw new UnsupportedOperationException("This operation is not supported");
}
+
public boolean isEmpty()
{
try
@@ -222,45 +223,44 @@
return true;
}
}
+
/**
- * Gets a property from the configuration.
+ * Gets a property from the configuration.
*
- * @param key property to retrieve
- * @return value as object. Will return user value if exists,
+ * @param key property to retrieve
+ * @return value as object. Will return user value if exists,
* if not then default value if exists, otherwise null
*/
public Object getProperty(String key)
{
- return getValueFromJNDI(key);
+ return getPropertyDirect(key);
}
+
/**
- * Set a property, this will replace any previously
- * set values. Set values is implicitly a call
- * to clearProperty(key), addProperty(key,value).
+ * Set a property, this will replace any previously set values. Set values
+ * is implicitly a call to clearProperty(key), addProperty(key,value).
*
* @param key
* @param value
*/
public void setProperty(String key, Object value)
{
- throw new Error("This operation is not supported");
+ throw new UnsupportedOperationException("This operation is not supported");
}
+
/**
- * Clear a property in the configuration. Just marks it as cleared,
+ * Clear a property in the configuration. Just marks it as cleared,
* doesn't change the underlying JNDI data source.
*
* @param key the key to remove along with corresponding value.
*/
public void clearProperty(String key)
{
- if (!clearedProperties.contains(key))
- {
- clearedProperties.add(key);
- }
+ clearedProperties.add(key);
}
+
/**
- * check if the configuration contains the key, or the key
- * has been removed.
+ * Check if the configuration contains the key, or the key has been removed.
*/
public boolean containsKey(String key)
{
@@ -275,354 +275,12 @@
getContext().lookup(key);
return true;
}
- catch (javax.naming.NamingException ne)
+ catch (NamingException ne)
{
return false;
}
}
-
- /**
- * Get a boolean associated with the given configuration key.
- *
- * @param key The configuration key.
- * @param defaultValue The default value.
- * @return The associated boolean if key is found and has valid
- * format, default value otherwise.
- * @throws ClassCastException is thrown if the key maps to an
- * object that is not a Boolean.
- */
- public Boolean getBoolean(String key, Boolean defaultValue)
- {
- Object value = getValueFromJNDI(key);
- if (value instanceof Boolean)
- {
- return (Boolean) value;
- }
- else if (value instanceof String)
- {
- return BooleanUtils.toBooleanObject((String) value);
- }
- else if (value == null)
- {
- return defaultValue;
- }
- else
- {
- throw new ClassCastException(
- '\'' + key + "' doesn't map to a Boolean object");
- }
- }
-
- /**
- * Get a byte associated with the given configuration key.
- *
- * @param key The configuration key.
- * @param defaultValue The default value.
- * @return The associated byte if key is found and has valid format, default
- * value otherwise.
- * @throws ClassCastException is thrown if the key maps to an object that
- * is not a Byte.
- * @throws NumberFormatException is thrown if the value mapped by the key
- * has not a valid number format.
- */
- public Byte getByte(String key, Byte defaultValue)
- {
- Object value = getValueFromJNDI(key);
- if (value instanceof Byte)
- {
- return (Byte) value;
- }
- else if (value instanceof String)
- {
- Byte b = new Byte((String) value);
- return b;
- }
- else if (value == null)
- {
- return defaultValue;
- }
- else
- {
- throw new ClassCastException(
- '\'' + key + "' doesn't map to a Byte object");
- }
- }
-
- /**
- * Get a double associated with the given configuration key.
- *
- * @param key The configuration key.
- * @param defaultValue The default value.
- * @return The associated double if key is found and has valid
- * format, default value otherwise.
- * @throws ClassCastException is thrown if the key maps to an
- * object that is not a Double.
- * @throws NumberFormatException is thrown if the value mapped
- * by the key has not a valid number format.
- */
- public Double getDouble(String key, Double defaultValue)
- {
- Object value = this.getValueFromJNDI(key);
- if (value instanceof Double)
- {
- return (Double) value;
- }
- else if (value instanceof String)
- {
- Double d = new Double((String) value);
- return d;
- }
- else if (value == null)
- {
- return defaultValue;
- }
- else
- {
- throw new ClassCastException(
- '\'' + key + "' doesn't map to a Double object");
- }
- }
-
- /**
- * Get a float associated with the given configuration key.
- *
- * @param key The configuration key.
- * @param defaultValue The default value.
- * @return The associated float if key is found and has valid
- * format, default value otherwise.
- * @throws ClassCastException is thrown if the key maps to an
- * object that is not a Float.
- * @throws NumberFormatException is thrown if the value mapped
- * by the key has not a valid number format.
- */
- public Float getFloat(String key, Float defaultValue)
- {
- Object value = getValueFromJNDI(key);
- if (value instanceof Float)
- {
- return (Float) value;
- }
- else if (value instanceof String)
- {
- Float f = new Float((String) value);
- return f;
- }
- else if (value == null)
- {
- return defaultValue;
- }
- else
- {
- throw new ClassCastException(
- '\'' + key + "' doesn't map to a Float object");
- }
- }
-
- /**
- * Get a int associated with the given configuration key.
- *
- * @param key The configuration key.
- * @param defaultValue The default value.
- * @return The associated int if key is found and has valid format, default
- * value otherwise.
- * @throws ClassCastException is thrown if the key maps to an object that
- * is not a Integer.
- * @throws NumberFormatException is thrown if the value mapped by the key
- * has not a valid number format.
- */
- public Integer getInteger(String key, Integer defaultValue)
- {
- Object value = getValueFromJNDI(key);
- if (value instanceof Integer)
- {
- return (Integer) value;
- }
- else if (value instanceof String)
- {
- Integer i = new Integer((String) value);
- return i;
- }
- else if (value == null)
- {
- return defaultValue;
- }
- else
- {
- throw new ClassCastException(
- '\'' + key + "' doesn't map to a Integer object");
- }
- }
-
- /**
- * Get a long associated with the given configuration key.
- *
- * @param key The configuration key.
- * @param defaultValue The default value.
- * @return The associated long if key is found and has valid
- * format, default value otherwise.
- * @throws ClassCastException is thrown if the key maps to an
- * object that is not a Long.
- * @throws NumberFormatException is thrown if the value mapped
- * by the key has not a valid number format.
- */
- public Long getLong(String key, Long defaultValue)
- {
- Object value = getValueFromJNDI(key);
- if (value instanceof Long)
- {
- return (Long) value;
- }
- else if (value instanceof String)
- {
- Long l = new Long((String) value);
- return l;
- }
- else if (value == null)
- {
- return defaultValue;
- }
- else
- {
- throw new ClassCastException(
- '\'' + key + "' doesn't map to a Long object");
- }
- }
-
- /**
- * Get a short associated with the given configuration key.
- *
- * @param key The configuration key.
- * @param defaultValue The default value.
- * @return The associated short if key is found and has valid
- * format, default value otherwise.
- * @throws ClassCastException is thrown if the key maps to an
- * object that is not a Short.
- * @throws NumberFormatException is thrown if the value mapped
- * by the key has not a valid number format.
- */
- public Short getShort(String key, Short defaultValue)
- {
- Object value = getValueFromJNDI(key);
- if (value instanceof Short)
- {
- return (Short) value;
- }
- else if (value instanceof String)
- {
- Short s = new Short((String) value);
- return s;
- }
- else if (value == null)
- {
- return defaultValue;
- }
- else
- {
- throw new ClassCastException(
- '\'' + key + "' doesn't map to a Short object");
- }
- }
-
- /**
- * Get a string associated with the given configuration key.
- *
- * @param key The configuration key.
- * @param defaultValue The default value.
- * @return The associated string if key is found, default value otherwise.
- * @throws ClassCastException is thrown if the key maps to an object that
- * is not a String.
- */
- public String getString(String key, String defaultValue)
- {
- try
- {
- Object o = getValueFromJNDI(key);
- if (o == null)
- {
- return defaultValue;
- }
- else
- {
- return (String) o;
- }
- }
- catch (NoSuchElementException nsee)
- {
- return defaultValue;
- }
- }
- /**
- * Get an array of strings associated with the given configuration
- * key.
- *
- * @param key The configuration key.
- * @return The associated string array if key is found.
- * @throws ClassCastException is thrown if the key maps to an
- * object that is not a String/List of Strings.
- */
- public String[] getStringArray(String key)
- {
- Object value = getValueFromJNDI(key);
- String[] tokens;
- if (value instanceof String)
- {
- tokens = new String[1];
- tokens[0] = interpolate((String) value);
- }
- else if (value instanceof Container)
- {
- tokens = new String[((Container) value).size()];
- for (int i = 0; i < tokens.length; i++)
- {
- tokens[i] = interpolate((String) ((Container) value).get(i));
- }
- }
- else if (value == null)
- {
- tokens = new String[0];
- }
- else
- {
- throw new ClassCastException(
- '\'' + key + "' doesn't map to a String/List object");
- }
- return tokens;
- }
-
- /**
- * Get a List of strings associated with the given configuration key.
- * Typically this will be just a single item, as you can't have multiple
- * properties with the same name.
- *
- * @param key The configuration key.
- * @param defaultValue The default value.
- * @return The associated List.
- */
- public List getList(String key, List defaultValue)
- {
- try
- {
- Object value = this.getValueFromJNDI(key);
- if (value != null)
- {
- List list = new ArrayList(1);
- list.add(value.toString());
- return list;
- }
- else
- {
- if (defaultValue == null)
- {
- defaultValue = new ArrayList();
- }
- return defaultValue;
- }
- }
- catch (NoSuchElementException nsse)
- {
- return defaultValue;
- }
- }
+
/**
* @return String
*/
@@ -630,26 +288,30 @@
{
return prefix;
}
+
/**
* Sets the prefix.
+ *
* @param prefix The prefix to set
*/
public void setPrefix(String prefix)
{
this.prefix = prefix;
}
- private Object getValueFromJNDI(String key)
+
+ protected Object getPropertyDirect(String key)
{
if (clearedProperties.contains(key))
{
return null;
}
+
try
{
key = StringUtils.replace(key, ".", "/");
return getContext().lookup(key);
}
- catch (java.util.NoSuchElementException nsse)
+ catch (NoSuchElementException nsse)
{
return null;
}
@@ -658,13 +320,18 @@
return null;
}
}
+
+ protected void addPropertyDirect(String key, Object obj) {
+ throw new UnsupportedOperationException("This operation is not supported");
+ }
+
private Context getContext() throws NamingException
{
- if (envCtx == null)
+ if (context == null)
{
Context initCtx = new InitialContext();
- envCtx = (Context) initCtx.lookup(getPrefix());
+ context = (Context) initCtx.lookup(getPrefix());
}
- return envCtx;
+ return context;
}
}
Index: src/test/org/apache/commons/configuration/TestJNDIConfiguration.java
===================================================================
RCS file:
/home/cvspublic/jakarta-commons/configuration/src/test/org/apache/commons/configuration/TestJNDIConfiguration.java,v
retrieving revision 1.5
diff -u -r1.5 TestJNDIConfiguration.java
--- src/test/org/apache/commons/configuration/TestJNDIConfiguration.java 27 Feb
2004 17:41:34 -0000 1.5
+++ src/test/org/apache/commons/configuration/TestJNDIConfiguration.java 23 Mar
2004 12:55:09 -0000
@@ -1,5 +1,3 @@
-package org.apache.commons.configuration;
-
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
@@ -16,129 +14,125 @@
* limitations under the License.
*/
-import java.util.Iterator;
+package org.apache.commons.configuration;
import junit.framework.TestCase;
+import java.util.Iterator;
+
/**
* test if non-string properties are handled correctly
*
* @version $Id: TestJNDIConfiguration.java,v 1.5 2004/02/27 17:41:34 epugh Exp $
*/
-public class TestJNDIConfiguration extends TestCase
-{
- private Configuration conf;
- private NonStringTestHolder nonStringTestHolder;
-
-
-
- public void setUp() throws Exception
- {
- //InitialContext context = new InitialContext();
- //assertNotNull(context);
-
- JNDIConfiguration jndiConfiguration = new JNDIConfiguration();
- jndiConfiguration.setPrefix("");
- conf = jndiConfiguration;
+public class TestJNDIConfiguration extends TestCase {
+
+ private JNDIConfiguration conf;
+ private NonStringTestHolder nonStringTestHolder;
+
+ public void setUp() throws Exception {
+ //InitialContext context = new InitialContext();
+ //assertNotNull(context);
+
+ conf = new JNDIConfiguration();
+ conf.setPrefix("");
+
nonStringTestHolder = new NonStringTestHolder();
nonStringTestHolder.setConfiguration(conf);
+ }
+
+ public void testBoolean() throws Exception {
+ nonStringTestHolder.testBoolean();
+ }
+
+ public void testBooleanDefaultValue() throws Exception {
+ nonStringTestHolder.testBooleanDefaultValue();
+ }
+
+ public void testByte() throws Exception {
+ nonStringTestHolder.testByte();
+ }
+
+ public void testDouble() throws Exception {
+ nonStringTestHolder.testDouble();
+ }
+
+ public void testDoubleDefaultValue() throws Exception {
+ nonStringTestHolder.testDoubleDefaultValue();
+ }
+ public void testFloat() throws Exception {
+ nonStringTestHolder.testFloat();
}
-
- public void testBoolean() throws Exception
- {
- nonStringTestHolder.testBoolean();
- }
-
- public void testBooleanDefaultValue() throws Exception
- {
- nonStringTestHolder.testBooleanDefaultValue();
- }
-
- public void testByte() throws Exception
- {
- nonStringTestHolder.testByte();
- }
-
- public void testDouble() throws Exception
- {
- nonStringTestHolder.testDouble();
- }
-
- public void testDoubleDefaultValue() throws Exception
- {
- nonStringTestHolder.testDoubleDefaultValue();
- }
-
- public void testFloat() throws Exception
- {
- nonStringTestHolder.testFloat();
- }
-
- public void testFloatDefaultValue() throws Exception
- {
- nonStringTestHolder.testFloatDefaultValue();
-
- }
-
- public void testInteger() throws Exception
- {
- nonStringTestHolder.testInteger();
- }
-
- public void testIntegerDefaultValue() throws Exception
- {
- nonStringTestHolder.testIntegerDefaultValue();
- }
-
- public void testLong() throws Exception
- {
- nonStringTestHolder.testLong();
- }
- public void testLongDefaultValue() throws Exception
- {
- nonStringTestHolder.testLongDefaultValue();
- }
-
- public void testShort() throws Exception
- {
- nonStringTestHolder.testShort();
- }
-
- public void testShortDefaultValue() throws Exception
- {
- nonStringTestHolder.testShortDefaultValue();
- }
-
- public void testListMissing() throws Exception
- {
- nonStringTestHolder.testListMissing();
- }
- public void testSubset() throws Exception
- {
- // seems to always be failing.
- //nonStringTestHolder.testSubset();
-
- }
-
- public void testProperties() throws Exception{
- Object o = conf.getProperty("test.boolean");
- assertNotNull(o);
- assertEquals("true",o.toString());
-
- }
-
- /**
- * Currently failing in that we don't get back any keys!
- * @throws Exception
- */
- public void testGetKeys() throws Exception{
- Iterator i = conf.getKeys();
- for (;i.hasNext();){
- System.out.println(i.next());
- }
- }
-
+ public void testFloatDefaultValue() throws Exception {
+ nonStringTestHolder.testFloatDefaultValue();
+ }
+
+ public void testInteger() throws Exception {
+ nonStringTestHolder.testInteger();
+ }
+
+ public void testIntegerDefaultValue() throws Exception {
+ nonStringTestHolder.testIntegerDefaultValue();
+ }
+
+ public void testLong() throws Exception {
+ nonStringTestHolder.testLong();
+ }
+
+ public void testLongDefaultValue() throws Exception {
+ nonStringTestHolder.testLongDefaultValue();
+ }
+
+ public void testShort() throws Exception {
+ nonStringTestHolder.testShort();
+ }
+
+ public void testShortDefaultValue() throws Exception {
+ nonStringTestHolder.testShortDefaultValue();
+ }
+
+ public void testListMissing() throws Exception {
+ nonStringTestHolder.testListMissing();
+ }
+
+ public void testSubset() throws Exception {
+ nonStringTestHolder.testSubset();
+ }
+
+ public void testProperties() throws Exception {
+ Object o = conf.getProperty("test.boolean");
+ assertNotNull(o);
+ assertEquals("true", o.toString());
+ }
+
+ /**
+ * Currently failing in that we don't get back any keys!
+ * @throws Exception
+ */
+ public void testGetKeys() throws Exception {
+
+ boolean found = false;
+ Iterator it = conf.getKeys();
+
+ assertTrue("no key found", it.hasNext());
+
+ while (it.hasNext() && !found) {
+ found = "test.boolean".equals(it.next());
+ }
+
+ assertTrue("'test.boolean' key not found", found);
+ }
+
+ public void testClearProperty() {
+ assertNotNull("null boolean for the 'test.boolean' key",
conf.getBoolean("test.boolean", null));
+ conf.clearProperty("test.boolean");
+ assertNull("'test.boolean' property not cleared",
conf.getBoolean("test.boolean", null));
+ }
+
+ public void testIsEmpty() {
+ assertFalse("the configuration shouldn't be empty", conf.isEmpty());
+ }
}--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
