提交 d9ee958d 编写于 作者: C Chris Beams

Refactor JndiPropertySource

Prior to this change, JndiPropertySource worked directly against a JNDI
Context instance as its 'source' object.  This works well enough, but is
not nearly as fully-featured as Spring's existing JndiLocatorDelegate.

This change refactors JndiPropertySource from relying on an underlying
Context to relying on an underlying JndiLocatorDelegate.  By default,
the delegate's "resourceRef" property is set to true, meaning that the
implementation will always try to prepand a given name with
"java:comp/env/" before looking up the name, and upon failure will drop
back to the given name sans prefix.

See JndiPropertySource Javadoc for complete details.

Issue: SPR-8490
上级 ce0a0ff3
......@@ -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}.
*
* <p>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
* <a href="http://download.oracle.com/javase/jndi/tutorial/beyond/misc/policy.html">JNDI
* naming conventions</a>. 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}.
*
* <p>{@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<Context> {
public class JndiPropertySource extends PropertySource<JndiLocatorDelegate> {
/** 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}
* <p>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.
* <p>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;
}
}
/*
* 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"));
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册