Author: oheger
Date: Thu Jun 21 12:57:25 2007
New Revision: 549591
URL: http://svn.apache.org/viewvc?view=rev&rev=549591
Log:
CONFIGURATION-281: Cycles in the JNDI tree no longer cause a stack overflow in
JNDIConfiguration
Modified:
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/JNDIConfiguration.java
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/MockInitialContextFactory.java
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestJNDIConfiguration.java
jakarta/commons/proper/configuration/trunk/xdocs/changes.xml
Modified:
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/JNDIConfiguration.java
URL:
http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/JNDIConfiguration.java?view=diff&rev=549591&r1=549590&r2=549591
==============================================================================
---
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/JNDIConfiguration.java
(original)
+++
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/JNDIConfiguration.java
Thu Jun 21 12:57:25 2007
@@ -115,10 +115,12 @@
* @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(Set keys, Context context, String prefix)
throws NamingException
+ private void recursiveGetKeys(Set keys, Context context, String prefix,
Set processedCtx) throws NamingException
{
+ processedCtx.add(context);
NamingEnumeration elements = null;
try
@@ -145,7 +147,11 @@
{
// add the keys of the sub context
Context subcontext = (Context) object;
- recursiveGetKeys(keys, subcontext, key.toString());
+ if (!processedCtx.contains(subcontext))
+ {
+ recursiveGetKeys(keys, subcontext, key.toString(),
+ processedCtx);
+ }
}
else
{
@@ -202,7 +208,7 @@
Set keys = new HashSet();
if (context != null)
{
- recursiveGetKeys(keys, context, prefix);
+ recursiveGetKeys(keys, context, prefix, new HashSet());
}
else if (containsKey(prefix))
{
Modified:
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/MockInitialContextFactory.java
URL:
http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/MockInitialContextFactory.java?view=diff&rev=549591&r1=549590&r2=549591
==============================================================================
---
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/MockInitialContextFactory.java
(original)
+++
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/MockInitialContextFactory.java
Thu Jun 21 12:57:25 2007
@@ -39,12 +39,21 @@
*/
public class MockInitialContextFactory implements InitialContextFactory
{
+ /**
+ * Constant for the use cycles environment property. If this property is
+ * present in the environment, a cyclic context will be created.
+ */
+ public static final String PROP_CYCLES = "useCycles";
+
/** Constant for the lookup method. */
private static final String METHOD_LOOKUP = "lookup";
/** Constant for the list method. */
private static final String METHOD_LIST = "list";
+ /** Constant for the close method.*/
+ private static final String METHOD_CLOSE = "close";
+
/** Constant for the name of the missing property. */
private static final String MISSING_PROP = "/missing";
@@ -75,7 +84,10 @@
*/
public Context getInitialContext(Hashtable env) throws NamingException
{
+ boolean useCycles = env.containsKey(PROP_CYCLES);
+
Mock mockTopCtx = createCtxMock(PREFIX);
+ Mock mockCycleCtx = createCtxMock("");
Mock mockPrfxCtx = createCtxMock("");
Mock mockBaseCtx = new Mock(Context.class);
mockBaseCtx.matchAndReturn(METHOD_LOOKUP, C.eq(""),
mockTopCtx.proxy());
@@ -83,12 +95,33 @@
.proxy());
mockTopCtx.matchAndReturn(METHOD_LOOKUP, C.eq("test"), mockPrfxCtx
.proxy());
- mockTopCtx.matchAndReturn(METHOD_LIST, C.eq(""), createEnumMock(
- mockTopCtx, new String[]
- { "test" }, new Object[]
- { mockPrfxCtx.proxy() }).proxy());
mockPrfxCtx.matchAndReturn(METHOD_LIST, C.eq(""), createEnumMock(
mockPrfxCtx, PROP_NAMES, PROP_VALUES).proxy());
+
+ if (useCycles)
+ {
+ mockTopCtx.matchAndReturn(METHOD_LOOKUP, C.eq("cycle"),
+ mockCycleCtx.proxy());
+ mockTopCtx.matchAndReturn(METHOD_LIST, C.eq(""), createEnumMock(
+ mockTopCtx, new String[]
+ { "test", "cycle" }, new Object[]
+ { mockPrfxCtx.proxy(), mockCycleCtx.proxy() }).proxy());
+ Mock mockEnum = createEnumMock(mockCycleCtx, PROP_NAMES,
+ PROP_VALUES, false);
+ addEnumPair(mockEnum, "cycleCtx", mockCycleCtx.proxy());
+ closeEnum(mockEnum);
+ mockCycleCtx
+ .matchAndReturn(METHOD_LIST, C.eq(""), mockEnum.proxy());
+ mockCycleCtx.matchAndReturn(METHOD_LOOKUP, C.eq("cycleCtx"),
+ mockCycleCtx.proxy());
+ }
+ else
+ {
+ mockTopCtx.matchAndReturn(METHOD_LIST, C.eq(""), createEnumMock(
+ mockTopCtx, new String[]
+ { "test" }, new Object[]
+ { mockPrfxCtx.proxy() }).proxy());
+ }
return (Context) mockBaseCtx.proxy();
}
@@ -112,6 +145,8 @@
{
bindError(mockCtx, MISSING_NAMES[i]);
}
+ mockCtx.matchAndReturn("hashCode",
System.identityHashCode(mockCtx.proxy()));
+
return mockCtx;
}
@@ -146,20 +181,61 @@
* @param mockCtx the mock representing the context
* @param names the names contained in the iteration
* @param values the corresponding values
+ * @param close a flag whether the enumeration should expect to be closed
* @return the mock for the enumeration
*/
- private Mock createEnumMock(Mock mockCtx, String[] names, Object[] values)
+ private Mock createEnumMock(Mock mockCtx, String[] names, Object[] values,
+ boolean close)
{
Mock mockEnum = new Mock(NamingEnumeration.class);
for (int i = 0; i < names.length; i++)
{
- NameClassPair ncp = new NameClassPair(names[i], values[i]
- .getClass().getName());
- mockEnum.expectAndReturn("hasMore", true);
- mockEnum.expectAndReturn("next", ncp);
+ addEnumPair(mockEnum, names[i], values[i]);
+ }
+ if (close)
+ {
+ closeEnum(mockEnum);
}
- mockEnum.expectAndReturn("hasMore", false);
- mockEnum.expect("close");
return mockEnum;
+ }
+
+ /**
+ * Creates and initializes a mock for a naming enumeration that expects to
+ * be closed. This is a shortcut of createEnumMock(mockCtx, names, values,
+ * true);
+ *
+ * @param mockCtx the mock representing the context
+ * @param names the names contained in the iteration
+ * @param values the corresponding values
+ * @return the mock for the enumeration
+ */
+ private Mock createEnumMock(Mock mockCtx, String[] names, Object[] values)
+ {
+ return createEnumMock(mockCtx, names, values, true);
+ }
+
+ /**
+ * Adds a new name-and-value pair to an enum mock.
+ *
+ * @param mockEnum the enum mock
+ * @param name the name
+ * @param value the value
+ */
+ private void addEnumPair(Mock mockEnum, String name, Object value)
+ {
+ NameClassPair ncp = new NameClassPair(name,
value.getClass().getName());
+ mockEnum.expectAndReturn("hasMore", true);
+ mockEnum.expectAndReturn("next", ncp);
+ }
+
+ /**
+ * Closes an enumeration mock.
+ *
+ * @param mockEnum the mock
+ */
+ private void closeEnum(Mock mockEnum)
+ {
+ mockEnum.expectAndReturn("hasMore", false);
+ mockEnum.expect(METHOD_CLOSE);
}
}
Modified:
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestJNDIConfiguration.java
URL:
http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestJNDIConfiguration.java?view=diff&rev=549591&r1=549590&r2=549591
==============================================================================
---
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestJNDIConfiguration.java
(original)
+++
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/TestJNDIConfiguration.java
Thu Jun 21 12:57:25 2007
@@ -17,6 +17,8 @@
package org.apache.commons.configuration;
+import java.util.Hashtable;
+
import junit.framework.TestCase;
import javax.naming.Context;
@@ -259,6 +261,18 @@
}
/**
+ * Tests the getKeys() method when there are cycles in the tree.
+ */
+ public void testGetKeysWithCycles() throws NamingException
+ {
+ Hashtable env = new Hashtable();
+ env.put(MockInitialContextFactory.PROP_CYCLES, Boolean.TRUE);
+ InitialContext initCtx = new InitialContext(env);
+ conf = new JNDIConfiguration(initCtx);
+ conf.getKeys("cycle");
+ }
+
+ /**
* A special JNDI configuration implementation that can be configured to
* throw an exception when accessing the base context. Used for testing the
* exception handling.
@@ -271,6 +285,11 @@
public PotentialErrorJNDIConfiguration() throws NamingException
{
super();
+ }
+
+ public PotentialErrorJNDIConfiguration(Context ctx) throws
NamingException
+ {
+ super(ctx);
}
public Context getBaseContext() throws NamingException
Modified: jakarta/commons/proper/configuration/trunk/xdocs/changes.xml
URL:
http://svn.apache.org/viewvc/jakarta/commons/proper/configuration/trunk/xdocs/changes.xml?view=diff&rev=549591&r1=549590&r2=549591
==============================================================================
--- jakarta/commons/proper/configuration/trunk/xdocs/changes.xml (original)
+++ jakarta/commons/proper/configuration/trunk/xdocs/changes.xml Thu Jun 21
12:57:25 2007
@@ -23,6 +23,10 @@
<body>
<release version="1.5-SNAPSHOT" date="in SVN" description="">
+ <action dev="oheger" type="fix" issue="CONFIGURATION-281">
+ Cycles in the JNDI tree no longer cause a stack overflow in
+ JNDIConfiguration.
+ </action>
<action dev="oheger" type="add" issue="CONFIGURATION-277">
The base implementation of clear() in AbstractConfiguration now checks
for a potential UnsupportedOperationException when iterating over the
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]