diff --git a/org.springframework.context/src/main/java/org/springframework/jndi/JndiPropertySource.java b/org.springframework.context/src/main/java/org/springframework/jndi/JndiPropertySource.java index 734a6a0762..071d728b3b 100644 --- a/org.springframework.context/src/main/java/org/springframework/jndi/JndiPropertySource.java +++ b/org.springframework.context/src/main/java/org/springframework/jndi/JndiPropertySource.java @@ -16,97 +16,110 @@ package org.springframework.jndi; -import java.util.Properties; - -import javax.naming.Context; -import javax.naming.InitialContext; import javax.naming.NamingException; import org.springframework.core.env.PropertySource; /** - * {@link PropertySource} implementation that reads properties from a JNDI - * {@link Context}. All properties retrieved through {@link #getProperty(String)} will - * automatically be prefixed with "java:comp/env/" when executing the actual - * {@link Context#lookup(String)} call. This default can be overridden using - * {@link #setJndiPrefix(String)} property. + * {@link PropertySource} implementation that reads properties from an underlying Spring + * {@link JndiLocatorDelegate}. + * + *

By default, the underlying {@code JndiLocatorDelegate} will be configured with its + * {@link JndiLocatorDelegate#setResourceRef(boolean) "resourceRef"} property set to + * {@code true}, meaning that names looked up will automatically be prefixed with + * "java:comp/env/" in alignment with published + * JNDI + * naming conventions. To override this setting or to change the prefix, manually + * configure a {@code JndiLocatorDelegate} and provide it to one of the constructors here + * that accepts it. The same applies when providing custom JNDI properties. These should + * be specified using {@link JndiLocatorDelegate#setJndiEnvironment(java.util.Properties)} + * prior to construction of the {@code JndiPropertySource}. + * + *

{@link org.springframework.web.context.support.StandardServletEnvironment + * StandardServletEnvironment} allows for declaratively including a + * {@code JndiPropertySource} through its support for a {@link + * org.springframework.web.context.support.StandardServletEnvironment#JNDI_PROPERTY_SOURCE_ENABLED + * JNDI_PROPERTY_SOURCE_ENABLED} context-param, but any customization of the underlying + * {@link JndiLocatorDelegate} will typically be done within an {@link + * org.springframework.context.ApplicationContextInitializer ApplicationContextInitializer} + * or {@link org.springframework.web.WebApplicationInitializer WebApplicationInitializer}. * * @author Chris Beams * @author Juergen Hoeller * @since 3.1 - * @see Context#lookup(String) + * @see JndiLocatorDelegate + * @see org.springframework.context.ApplicationContextInitializer + * @see org.springframework.web.WebApplicationInitializer * @see org.springframework.web.context.support.StandardServletEnvironment */ -public class JndiPropertySource extends PropertySource { +public class JndiPropertySource extends PropertySource { /** JNDI context property source name: {@value} */ public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiPropertySource"; /** * Create a new {@code JndiPropertySource} with the default name - * {@value #JNDI_PROPERTY_SOURCE_NAME} and create a new {@link InitialContext} - * as the source object. - * @throws JndiLookupFailureException if a new {@link InitialContext} - * cannot be created. + * {@value #JNDI_PROPERTY_SOURCE_NAME} and a {@link JndiLocatorDelegate} configured + * to prefix any names with "java:comp/env/". */ - public JndiPropertySource() throws JndiLookupFailureException { - this(JNDI_PROPERTY_SOURCE_NAME, createInitialContext(null)); + public JndiPropertySource() { + this(JNDI_PROPERTY_SOURCE_NAME); } /** - * Create a new {@code JndiPropertySource} with the given name and - * create a new {@link InitialContext} as the source object. - * @throws JndiLookupFailureException if a new {@link InitialContext} - * cannot be created. + * Create a new {@code JndiPropertySource} with the given name + * and a {@link JndiLocatorDelegate} configured to prefix any names with + * "java:comp/env/". */ - public JndiPropertySource(String name) throws JndiLookupFailureException { - this(name, createInitialContext(null)); + public JndiPropertySource(String name) { + this(name, createDefaultJndiLocator()); } /** - * Create a new {@code JndiPropertySource} with the given name and - * use the given jndiEnvironment properties to create a new - * {@link InitialContext} as the source object. - * @throws JndiLookupFailureException if a new {@link InitialContext} - * cannot be created. + * Create a new {@code JndiPropertySource} with the default name + * {@value #JNDI_PROPERTY_SOURCE_NAME} and the given {@code JndiLocatorDelegate}. */ - public JndiPropertySource(String name, Properties jndiEnvironment) throws JndiLookupFailureException { - this(name, createInitialContext(jndiEnvironment)); + public JndiPropertySource(JndiLocatorDelegate jndiLocator) { + this(JNDI_PROPERTY_SOURCE_NAME, jndiLocator); } /** - * Create a new {@code JndiPropertySource} with the given name and - * JNDI {@link Context}. + * Create a new {@code JndiPropertySource} with the given name and the given + * {@code JndiLocatorDelegate}. */ - public JndiPropertySource(String name, Context source) { - super(name, source); + public JndiPropertySource(String name, JndiLocatorDelegate jndiLocator) { + super(name, jndiLocator); } /** * {@inheritDoc} - *

This implementation looks up and returns the given name from the source JNDI - * {@link Context}. If a {@link NamingException} is thrown during the call to - * {@link Context#lookup(String)}, returns {@code null} and issue a DEBUG-level log - * statement with the exception message. + *

This implementation looks up and returns the value associated with the given + * name from the underlying {@link JndiLocatorDelegate}. If a {@link NamingException} + * is thrown during the call to {@link JndiLocatorDelegate#lookup(String)}, returns + * {@code null} and issues a DEBUG-level log statement with the exception message. */ @Override public Object getProperty(String name) { try { Object value = this.source.lookup(name); - logger.debug("Context#lookup(" + name + ") returned: [" + value + "]"); + logger.debug("JNDI lookup for name [" + name + "] returned: [" + value + "]"); return value; } catch (NamingException ex) { - logger.debug("Context#lookup(" + name + ") threw NamingException with message: " + ex.getMessage()); + logger.debug("JNDI lookup for name [" + name + "] threw NamingException " + + "with message: " + ex.getMessage() + ". Returning null."); return null; } } - private static Context createInitialContext(Properties jndiEnvironment) { - try { - return new InitialContext(jndiEnvironment); - } catch (NamingException ex) { - throw new JndiLookupFailureException("unable to create InitialContext", ex); - } + /** + * Configure a {@code JndiLocatorDelegate} with its "resourceRef" property set to true + * meaning that all names will be prefixed with "java:comp/env/". + * @return + */ + private static JndiLocatorDelegate createDefaultJndiLocator() { + JndiLocatorDelegate jndiLocator = new JndiLocatorDelegate(); + jndiLocator.setResourceRef(true); + return jndiLocator; } } diff --git a/org.springframework.context/src/test/java/org/springframework/jndi/JndiPropertySourceTests.java b/org.springframework.context/src/test/java/org/springframework/jndi/JndiPropertySourceTests.java new file mode 100644 index 0000000000..7cb1cdcf53 --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/jndi/JndiPropertySourceTests.java @@ -0,0 +1,81 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed 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.springframework.jndi; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +import javax.naming.Context; +import javax.naming.NamingException; + +import org.junit.Test; +import org.springframework.mock.jndi.SimpleNamingContext; + +/** + * Unit tests for {@link JndiPropertySource}. + * + * @author Chris Beams + * @since 3.1 + */ +public class JndiPropertySourceTests { + + @Test + public void nonExistentProperty() { + JndiPropertySource ps = new JndiPropertySource(); + assertThat(ps.getProperty("bogus"), nullValue()); + } + + @Test + public void nameBoundWithoutPrefix() { + final SimpleNamingContext context = new SimpleNamingContext(); + context.bind("p1", "v1"); + + JndiTemplate jndiTemplate = new JndiTemplate() { + @Override + protected Context createInitialContext() throws NamingException { + return context; + } + }; + JndiLocatorDelegate jndiLocator = new JndiLocatorDelegate(); + jndiLocator.setResourceRef(true); + jndiLocator.setJndiTemplate(jndiTemplate); + + JndiPropertySource ps = new JndiPropertySource(jndiLocator); + assertThat((String)ps.getProperty("p1"), equalTo("v1")); + } + + @Test + public void nameBoundWithPrefix() { + final SimpleNamingContext context = new SimpleNamingContext(); + context.bind("java:comp/env/p1", "v1"); + + JndiTemplate jndiTemplate = new JndiTemplate() { + @Override + protected Context createInitialContext() throws NamingException { + return context; + } + }; + JndiLocatorDelegate jndiLocator = new JndiLocatorDelegate(); + jndiLocator.setResourceRef(true); + jndiLocator.setJndiTemplate(jndiTemplate); + + JndiPropertySource ps = new JndiPropertySource(jndiLocator); + assertThat((String)ps.getProperty("p1"), equalTo("v1")); + } + +}