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

import org.springframework.aop.TargetSource;

/**
 * AOP {@link org.springframework.aop.TargetSource} that provides
 * configurable JNDI lookups for <code>getTarget()</code> 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>
 * &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</code> 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</code>.
 *
 * <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;

	private Object cachedObject;

	private Class targetClass;


	/**
	 * 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".
	 * <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;
	}

	public void afterPropertiesSet() throws NamingException {
		super.afterPropertiesSet();
		if (this.lookupOnStartup) {
			Object object = lookup();
			if (this.cache) {
				this.cachedObject = object;
			}
			else {
				this.targetClass = object.getClass();
			}
		}
	}


	public Class getTargetClass() {
		return (this.cachedObject != null ? this.cachedObject.getClass() : this.targetClass);
	}

	public boolean isStatic() {
		return (this.cachedObject != null);
	}

	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);
		}
	}

	public void releaseTarget(Object target) {
	}

}

@@ -3785,30 +3785,26 @@
 Class() %7B%0A%09%09
-return
+if
  (this.cache
@@ -3810,34 +3810,45 @@
 edObject != null
- ?
+) %7B%0A%09%09%09return
  this.cachedObje
@@ -3864,29 +3864,126 @@
 ss()
- : this.targetClass);
+;%0A%09%09%7D%0A%09%09else if (this.targetClass != null) %7B%0A%09%09%09return this.targetClass;%0A%09%09%7D%0A%09%09else %7B%0A%09%09%09return getExpectedType();%0A%09%09%7D
 %0A%09%7D%0A

return the specified "expectedType" as target class if no JNDI object has been obtained yet