001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019 package org.apache.shiro.jndi;
020
021 import java.util.Properties;
022 import javax.naming.NamingException;
023
024 import org.slf4j.Logger;
025 import org.slf4j.LoggerFactory;
026
027 /**
028 * Convenient superclass for JNDI accessors, providing "jndiTemplate"
029 * and "jndiEnvironment" bean properties.
030 *
031 * <p>Note that this implementation is an almost exact combined copy of the Spring Framework's 'JndiAccessor' and
032 * 'JndiLocatorSupport' classes from their 2.5.4 distribution - we didn't want to re-invent the wheel, but not require
033 * a full dependency on the Spring framework, nor does Spring make available only its JNDI classes in a small jar, or
034 * we would have used that. Since Shiro is also Apache 2.0 licensed, all regular licenses and conditions and
035 * authors have remained in tact.
036 *
037 * @author Juergen Hoeller
038 * @see #setJndiTemplate
039 * @see #setJndiEnvironment
040 * @see #setResourceRef
041 * @since 1.1
042 */
043 public class JndiLocator {
044
045 /**
046 * Private class log.
047 */
048 private static final Logger log = LoggerFactory.getLogger(JndiLocator.class);
049
050 /**
051 * JNDI prefix used in a J2EE container
052 */
053 public static final String CONTAINER_PREFIX = "java:comp/env/";
054
055 private boolean resourceRef = false;
056
057 private JndiTemplate jndiTemplate = new JndiTemplate();
058
059
060 /**
061 * Set the JNDI template to use for JNDI lookups.
062 * <p>You can also specify JNDI environment settings via "jndiEnvironment".
063 *
064 * @see #setJndiEnvironment
065 */
066 public void setJndiTemplate(JndiTemplate jndiTemplate) {
067 this.jndiTemplate = (jndiTemplate != null ? jndiTemplate : new JndiTemplate());
068 }
069
070 /**
071 * Return the JNDI template to use for JNDI lookups.
072 */
073 public JndiTemplate getJndiTemplate() {
074 return this.jndiTemplate;
075 }
076
077 /**
078 * Set the JNDI environment to use for JNDI lookups.
079 * <p>Creates a JndiTemplate with the given environment settings.
080 *
081 * @see #setJndiTemplate
082 */
083 public void setJndiEnvironment(Properties jndiEnvironment) {
084 this.jndiTemplate = new JndiTemplate(jndiEnvironment);
085 }
086
087 /**
088 * Return the JNDI environment to use for JNDI lookups.
089 */
090 public Properties getJndiEnvironment() {
091 return this.jndiTemplate.getEnvironment();
092 }
093
094 /**
095 * Set whether the lookup occurs in a J2EE container, i.e. if the prefix
096 * "java:comp/env/" needs to be added if the JNDI name doesn't already
097 * contain it. Default is "false".
098 * <p>Note: Will only get applied if no other scheme (e.g. "java:") is given.
099 */
100 public void setResourceRef(boolean resourceRef) {
101 this.resourceRef = resourceRef;
102 }
103
104 /**
105 * Return whether the lookup occurs in a J2EE container.
106 */
107 public boolean isResourceRef() {
108 return this.resourceRef;
109 }
110
111
112 /**
113 * Perform an actual JNDI lookup for the given name via the JndiTemplate.
114 * <p>If the name doesn't begin with "java:comp/env/", this prefix is added
115 * if "resourceRef" is set to "true".
116 *
117 * @param jndiName the JNDI name to look up
118 * @return the obtained object
119 * @throws javax.naming.NamingException if the JNDI lookup failed
120 * @see #setResourceRef
121 */
122 protected Object lookup(String jndiName) throws NamingException {
123 return lookup(jndiName, null);
124 }
125
126 /**
127 * Perform an actual JNDI lookup for the given name via the JndiTemplate.
128 * <p>If the name doesn't begin with "java:comp/env/", this prefix is added
129 * if "resourceRef" is set to "true".
130 *
131 * @param jndiName the JNDI name to look up
132 * @param requiredType the required type of the object
133 * @return the obtained object
134 * @throws NamingException if the JNDI lookup failed
135 * @see #setResourceRef
136 */
137 protected Object lookup(String jndiName, Class requiredType) throws NamingException {
138 if (jndiName == null) {
139 throw new IllegalArgumentException("jndiName argument must not be null");
140 }
141 String convertedName = convertJndiName(jndiName);
142 Object jndiObject;
143 try {
144 jndiObject = getJndiTemplate().lookup(convertedName, requiredType);
145 }
146 catch (NamingException ex) {
147 if (!convertedName.equals(jndiName)) {
148 // Try fallback to originally specified name...
149 if (log.isDebugEnabled()) {
150 log.debug("Converted JNDI name [" + convertedName +
151 "] not found - trying original name [" + jndiName + "]. " + ex);
152 }
153 jndiObject = getJndiTemplate().lookup(jndiName, requiredType);
154 } else {
155 throw ex;
156 }
157 }
158 log.debug("Located object with JNDI name '{}'", convertedName);
159 return jndiObject;
160 }
161
162 /**
163 * Convert the given JNDI name into the actual JNDI name to use.
164 * <p>The default implementation applies the "java:comp/env/" prefix if
165 * "resourceRef" is "true" and no other scheme (e.g. "java:") is given.
166 *
167 * @param jndiName the original JNDI name
168 * @return the JNDI name to use
169 * @see #CONTAINER_PREFIX
170 * @see #setResourceRef
171 */
172 protected String convertJndiName(String jndiName) {
173 // Prepend container prefix if not already specified and no other scheme given.
174 if (isResourceRef() && !jndiName.startsWith(CONTAINER_PREFIX) && jndiName.indexOf(':') == -1) {
175 jndiName = CONTAINER_PREFIX + jndiName;
176 }
177 return jndiName;
178 }
179
180 }