001/*
002 * Copyright 2002-2016 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.jndi;
018
019import javax.naming.NamingException;
020
021import org.springframework.core.env.PropertySource;
022import org.springframework.lang.Nullable;
023
024/**
025 * {@link PropertySource} implementation that reads properties from an underlying Spring
026 * {@link JndiLocatorDelegate}.
027 *
028 * <p>By default, the underlying {@code JndiLocatorDelegate} will be configured with its
029 * {@link JndiLocatorDelegate#setResourceRef(boolean) "resourceRef"} property set to
030 * {@code true}, meaning that names looked up will automatically be prefixed with
031 * "java:comp/env/" in alignment with published
032 * <a href="https://download.oracle.com/javase/jndi/tutorial/beyond/misc/policy.html">JNDI
033 * naming conventions</a>. To override this setting or to change the prefix, manually
034 * configure a {@code JndiLocatorDelegate} and provide it to one of the constructors here
035 * that accepts it. The same applies when providing custom JNDI properties. These should
036 * be specified using {@link JndiLocatorDelegate#setJndiEnvironment(java.util.Properties)}
037 * prior to construction of the {@code JndiPropertySource}.
038 *
039 * <p>Note that {@link org.springframework.web.context.support.StandardServletEnvironment
040 * StandardServletEnvironment} includes a {@code JndiPropertySource} by default, and any
041 * customization of the underlying {@link JndiLocatorDelegate} may be performed within an
042 * {@link org.springframework.context.ApplicationContextInitializer
043 * ApplicationContextInitializer} or {@link org.springframework.web.WebApplicationInitializer
044 * WebApplicationInitializer}.
045 *
046 * @author Chris Beams
047 * @author Juergen Hoeller
048 * @since 3.1
049 * @see JndiLocatorDelegate
050 * @see org.springframework.context.ApplicationContextInitializer
051 * @see org.springframework.web.WebApplicationInitializer
052 * @see org.springframework.web.context.support.StandardServletEnvironment
053 */
054public class JndiPropertySource extends PropertySource<JndiLocatorDelegate> {
055
056        /**
057         * Create a new {@code JndiPropertySource} with the given name
058         * and a {@link JndiLocatorDelegate} configured to prefix any names with
059         * "java:comp/env/".
060         */
061        public JndiPropertySource(String name) {
062                this(name, JndiLocatorDelegate.createDefaultResourceRefLocator());
063        }
064
065        /**
066         * Create a new {@code JndiPropertySource} with the given name and the given
067         * {@code JndiLocatorDelegate}.
068         */
069        public JndiPropertySource(String name, JndiLocatorDelegate jndiLocator) {
070                super(name, jndiLocator);
071        }
072
073
074        /**
075         * This implementation looks up and returns the value associated with the given
076         * name from the underlying {@link JndiLocatorDelegate}. If a {@link NamingException}
077         * is thrown during the call to {@link JndiLocatorDelegate#lookup(String)}, returns
078         * {@code null} and issues a DEBUG-level log statement with the exception message.
079         */
080        @Override
081        @Nullable
082        public Object getProperty(String name) {
083                if (getSource().isResourceRef() && name.indexOf(':') != -1) {
084                        // We're in resource-ref (prefixing with "java:comp/env") mode. Let's not bother
085                        // with property names with a colon it since they're probably just containing a
086                        // default value clause, very unlikely to match including the colon part even in
087                        // a textual property source, and effectively never meant to match that way in
088                        // JNDI where a colon indicates a separator between JNDI scheme and actual name.
089                        return null;
090                }
091
092                try {
093                        Object value = this.source.lookup(name);
094                        if (logger.isDebugEnabled()) {
095                                logger.debug("JNDI lookup for name [" + name + "] returned: [" + value + "]");
096                        }
097                        return value;
098                }
099                catch (NamingException ex) {
100                        if (logger.isDebugEnabled()) {
101                                logger.debug("JNDI lookup for name [" + name + "] threw NamingException " +
102                                                "with message: " + ex.getMessage() + ". Returning null.");
103                        }
104                        return null;
105                }
106        }
107
108}