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 */ 019package org.apache.shiro.jndi; 020 021import java.util.Properties; 022import javax.naming.NamingException; 023 024import org.slf4j.Logger; 025import 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 * @see #setJndiTemplate 038 * @see #setJndiEnvironment 039 * @see #setResourceRef 040 * @since 1.1 041 */ 042public class JndiLocator { 043 044 /** 045 * Private class log. 046 */ 047 private static final Logger log = LoggerFactory.getLogger(JndiLocator.class); 048 049 /** 050 * JNDI prefix used in a J2EE container 051 */ 052 public static final String CONTAINER_PREFIX = "java:comp/env/"; 053 054 private boolean resourceRef = false; 055 056 private JndiTemplate jndiTemplate = new JndiTemplate(); 057 058 059 /** 060 * Set the JNDI template to use for JNDI lookups. 061 * <p>You can also specify JNDI environment settings via "jndiEnvironment". 062 * 063 * @see #setJndiEnvironment 064 */ 065 public void setJndiTemplate(JndiTemplate jndiTemplate) { 066 this.jndiTemplate = (jndiTemplate != null ? jndiTemplate : new JndiTemplate()); 067 } 068 069 /** 070 * Return the JNDI template to use for JNDI lookups. 071 */ 072 public JndiTemplate getJndiTemplate() { 073 return this.jndiTemplate; 074 } 075 076 /** 077 * Set the JNDI environment to use for JNDI lookups. 078 * <p>Creates a JndiTemplate with the given environment settings. 079 * 080 * @see #setJndiTemplate 081 */ 082 public void setJndiEnvironment(Properties jndiEnvironment) { 083 this.jndiTemplate = new JndiTemplate(jndiEnvironment); 084 } 085 086 /** 087 * Return the JNDI environment to use for JNDI lookups. 088 */ 089 public Properties getJndiEnvironment() { 090 return this.jndiTemplate.getEnvironment(); 091 } 092 093 /** 094 * Set whether the lookup occurs in a J2EE container, i.e. if the prefix 095 * "java:comp/env/" needs to be added if the JNDI name doesn't already 096 * contain it. Default is "false". 097 * <p>Note: Will only get applied if no other scheme (e.g. "java:") is given. 098 */ 099 public void setResourceRef(boolean resourceRef) { 100 this.resourceRef = resourceRef; 101 } 102 103 /** 104 * Return whether the lookup occurs in a J2EE container. 105 */ 106 public boolean isResourceRef() { 107 return this.resourceRef; 108 } 109 110 111 /** 112 * Perform an actual JNDI lookup for the given name via the JndiTemplate. 113 * <p>If the name doesn't begin with "java:comp/env/", this prefix is added 114 * if "resourceRef" is set to "true". 115 * 116 * @param jndiName the JNDI name to look up 117 * @return the obtained object 118 * @throws javax.naming.NamingException if the JNDI lookup failed 119 * @see #setResourceRef 120 */ 121 protected Object lookup(String jndiName) throws NamingException { 122 return lookup(jndiName, null); 123 } 124 125 /** 126 * Perform an actual JNDI lookup for the given name via the JndiTemplate. 127 * <p>If the name doesn't begin with "java:comp/env/", this prefix is added 128 * if "resourceRef" is set to "true". 129 * 130 * @param jndiName the JNDI name to look up 131 * @param requiredType the required type of the object 132 * @return the obtained object 133 * @throws NamingException if the JNDI lookup failed 134 * @see #setResourceRef 135 */ 136 protected Object lookup(String jndiName, Class requiredType) throws NamingException { 137 if (jndiName == null) { 138 throw new IllegalArgumentException("jndiName argument must not be null"); 139 } 140 String convertedName = convertJndiName(jndiName); 141 Object jndiObject; 142 try { 143 jndiObject = getJndiTemplate().lookup(convertedName, requiredType); 144 } 145 catch (NamingException ex) { 146 if (!convertedName.equals(jndiName)) { 147 // Try fallback to originally specified name... 148 if (log.isDebugEnabled()) { 149 log.debug("Converted JNDI name [" + convertedName + 150 "] not found - trying original name [" + jndiName + "]. " + ex); 151 } 152 jndiObject = getJndiTemplate().lookup(jndiName, requiredType); 153 } else { 154 throw ex; 155 } 156 } 157 log.debug("Located object with JNDI name '{}'", convertedName); 158 return jndiObject; 159 } 160 161 /** 162 * Convert the given JNDI name into the actual JNDI name to use. 163 * <p>The default implementation applies the "java:comp/env/" prefix if 164 * "resourceRef" is "true" and no other scheme (e.g. "java:") is given. 165 * 166 * @param jndiName the original JNDI name 167 * @return the JNDI name to use 168 * @see #CONTAINER_PREFIX 169 * @see #setResourceRef 170 */ 171 protected String convertJndiName(String jndiName) { 172 // Prepend container prefix if not already specified and no other scheme given. 173 if (isResourceRef() && !jndiName.startsWith(CONTAINER_PREFIX) && jndiName.indexOf(':') == -1) { 174 jndiName = CONTAINER_PREFIX + jndiName; 175 } 176 return jndiName; 177 } 178 179}