/*
 * Copyright 2002-2017 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
 *
 *      https://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 javax.naming.NamingException;

import org.springframework.aop.TargetSource;
import org.springframework.lang.Nullable;

AOP TargetSource that provides configurable JNDI lookups for getTarget() calls.

Can be used as alternative to JndiObjectFactoryBean, to allow for relocating a JNDI object lazily or for each operation (see "lookupOnStartup" and "cache" properties). This is particularly useful during development, as it allows for hot restarting of the JNDI server (for example, a remote JMS server).

Example:

<bean id="queueConnectionFactoryTarget" class="org.springframework.jndi.JndiObjectTargetSource">
  <property name="jndiName" value="JmsQueueConnectionFactory"/>
  <property name="lookupOnStartup" value="false"/>
</bean>
<bean id="queueConnectionFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="proxyInterfaces" value="javax.jms.QueueConnectionFactory"/>
  <property name="targetSource" ref="queueConnectionFactoryTarget"/>
</bean>
A createQueueConnection call on the "queueConnectionFactory" proxy will cause a lazy JNDI lookup for "JmsQueueConnectionFactory" and a subsequent delegating call to the retrieved QueueConnectionFactory's createQueueConnection.

Alternatively, use a JndiObjectFactoryBean with a "proxyInterface". "lookupOnStartup" and "cache" can then be specified on the JndiObjectFactoryBean, creating a JndiObjectTargetSource underneath (instead of defining separate ProxyFactoryBean and JndiObjectTargetSource beans).

Author:Juergen Hoeller
See Also:
Since:1.1
/** * AOP {@link org.springframework.aop.TargetSource} that provides * configurable JNDI lookups for {@code getTarget()} calls. * * <p>Can be used as alternative to {@link JndiObjectFactoryBean}, to allow for * relocating a JNDI object lazily or for each operation (see "lookupOnStartup" * and "cache" properties). This is particularly useful during development, as it * allows for hot restarting of the JNDI server (for example, a remote JMS server). * * <p>Example: * * <pre class="code"> * &lt;bean id="queueConnectionFactoryTarget" class="org.springframework.jndi.JndiObjectTargetSource"&gt; * &lt;property name="jndiName" value="JmsQueueConnectionFactory"/&gt; * &lt;property name="lookupOnStartup" value="false"/&gt; * &lt;/bean&gt; * * &lt;bean id="queueConnectionFactory" class="org.springframework.aop.framework.ProxyFactoryBean"&gt; * &lt;property name="proxyInterfaces" value="javax.jms.QueueConnectionFactory"/&gt; * &lt;property name="targetSource" ref="queueConnectionFactoryTarget"/&gt; * &lt;/bean&gt;</pre> * * A {@code createQueueConnection} call on the "queueConnectionFactory" proxy will * cause a lazy JNDI lookup for "JmsQueueConnectionFactory" and a subsequent delegating * call to the retrieved QueueConnectionFactory's {@code createQueueConnection}. * * <p><b>Alternatively, use a {@link JndiObjectFactoryBean} with a "proxyInterface".</b> * "lookupOnStartup" and "cache" can then be specified on the JndiObjectFactoryBean, * creating a JndiObjectTargetSource underneath (instead of defining separate * ProxyFactoryBean and JndiObjectTargetSource beans). * * @author Juergen Hoeller * @since 1.1 * @see #setLookupOnStartup * @see #setCache * @see org.springframework.aop.framework.ProxyFactoryBean#setTargetSource * @see JndiObjectFactoryBean#setProxyInterface */
public class JndiObjectTargetSource extends JndiObjectLocator implements TargetSource { private boolean lookupOnStartup = true; private boolean cache = true; @Nullable private Object cachedObject; @Nullable private Class<?> targetClass;
Set whether to look up the JNDI object on startup. Default is "true".

Can be turned off to allow for late availability of the JNDI object. In this case, the JNDI object will be fetched on first access.

See Also:
  • setCache
/** * Set whether to look up the JNDI object on startup. Default is "true". * <p>Can be turned off to allow for late availability of the JNDI object. * In this case, the JNDI object will be fetched on first access. * @see #setCache */
public void setLookupOnStartup(boolean lookupOnStartup) { this.lookupOnStartup = lookupOnStartup; }
Set whether to cache the JNDI object once it has been located. Default is "true".

Can be turned off to allow for hot redeployment of JNDI objects. In this case, the JNDI object will be fetched for each invocation.

See Also:
  • setLookupOnStartup
/** * Set whether to cache the JNDI object once it has been located. * Default is "true". * <p>Can be turned off to allow for hot redeployment of JNDI objects. * In this case, the JNDI object will be fetched for each invocation. * @see #setLookupOnStartup */
public void setCache(boolean cache) { this.cache = cache; } @Override public void afterPropertiesSet() throws NamingException { super.afterPropertiesSet(); if (this.lookupOnStartup) { Object object = lookup(); if (this.cache) { this.cachedObject = object; } else { this.targetClass = object.getClass(); } } } @Override @Nullable public Class<?> getTargetClass() { if (this.cachedObject != null) { return this.cachedObject.getClass(); } else if (this.targetClass != null) { return this.targetClass; } else { return getExpectedType(); } } @Override public boolean isStatic() { return (this.cachedObject != null); } @Override @Nullable public Object getTarget() { try { if (this.lookupOnStartup || !this.cache) { return (this.cachedObject != null ? this.cachedObject : lookup()); } else { synchronized (this) { if (this.cachedObject == null) { this.cachedObject = lookup(); } return this.cachedObject; } } } catch (NamingException ex) { throw new JndiLookupFailureException("JndiObjectTargetSource failed to obtain new target object", ex); } } @Override public void releaseTarget(Object target) { } }