001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.jndi;
018:
019: import javax.naming.NamingException;
020:
021: import org.springframework.aop.TargetSource;
022:
023: /**
024: * AOP {@link org.springframework.aop.TargetSource} that provides
025: * configurable JNDI lookups for <code>getTarget()</code> calls.
026: *
027: * <p>Can be used as alternative to {@link JndiObjectFactoryBean}, to allow for
028: * relocating a JNDI object lazily or for each operation (see "lookupOnStartup"
029: * and "cache" properties). This is particularly useful during development, as it
030: * allows for hot restarting of the JNDI server (for example, a remote JMS server).
031: *
032: * <p>Example:
033: *
034: * <pre>
035: * <bean id="queueConnectionFactoryTarget" class="org.springframework.jndi.JndiObjectTargetSource">
036: * <property name="jndiName" value="JmsQueueConnectionFactory"/>
037: * <property name="lookupOnStartup" value="false"/>
038: * </bean>
039: *
040: * <bean id="queueConnectionFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
041: * <property name="proxyInterfaces" value="javax.jms.QueueConnectionFactory"/>
042: * <property name="targetSource" ref="queueConnectionFactoryTarget"/>
043: * </bean></pre>
044: *
045: * A <code>createQueueConnection</code> call on the "queueConnectionFactory" proxy will
046: * cause a lazy JNDI lookup for "JmsQueueConnectionFactory" and a subsequent delegating
047: * call to the retrieved QueueConnectionFactory's <code>createQueueConnection</code>.
048: *
049: * <p><b>Alternatively, use a {@link JndiObjectFactoryBean} with a "proxyInterface".</b>
050: * "lookupOnStartup" and "cache" can then be specified on the JndiObjectFactoryBean,
051: * creating a JndiObjectTargetSource underneath (instead of defining separate
052: * ProxyFactoryBean and JndiObjectTargetSource beans).
053: *
054: * @author Juergen Hoeller
055: * @since 1.1
056: * @see #setLookupOnStartup
057: * @see #setCache
058: * @see org.springframework.aop.framework.ProxyFactoryBean#setTargetSource
059: * @see JndiObjectFactoryBean#setProxyInterface
060: */
061: public class JndiObjectTargetSource extends JndiObjectLocator implements
062: TargetSource {
063:
064: private boolean lookupOnStartup = true;
065:
066: private boolean cache = true;
067:
068: private Object cachedObject;
069:
070: private Class targetClass;
071:
072: /**
073: * Set whether to look up the JNDI object on startup. Default is "true".
074: * <p>Can be turned off to allow for late availability of the JNDI object.
075: * In this case, the JNDI object will be fetched on first access.
076: * @see #setCache
077: */
078: public void setLookupOnStartup(boolean lookupOnStartup) {
079: this .lookupOnStartup = lookupOnStartup;
080: }
081:
082: /**
083: * Set whether to cache the JNDI object once it has been located.
084: * Default is "true".
085: * <p>Can be turned off to allow for hot redeployment of JNDI objects.
086: * In this case, the JNDI object will be fetched for each invocation.
087: * @see #setLookupOnStartup
088: */
089: public void setCache(boolean cache) {
090: this .cache = cache;
091: }
092:
093: public void afterPropertiesSet() throws NamingException {
094: super .afterPropertiesSet();
095: if (this .lookupOnStartup) {
096: Object object = lookup();
097: if (this .cache) {
098: this .cachedObject = object;
099: } else {
100: this .targetClass = object.getClass();
101: }
102: }
103: }
104:
105: public Class getTargetClass() {
106: if (this .cachedObject != null) {
107: return this .cachedObject.getClass();
108: } else if (this .targetClass != null) {
109: return this .targetClass;
110: } else {
111: return getExpectedType();
112: }
113: }
114:
115: public boolean isStatic() {
116: return (this .cachedObject != null);
117: }
118:
119: public Object getTarget() {
120: try {
121: if (this .lookupOnStartup || !this .cache) {
122: return (this .cachedObject != null ? this .cachedObject
123: : lookup());
124: } else {
125: synchronized (this ) {
126: if (this .cachedObject == null) {
127: this .cachedObject = lookup();
128: }
129: return this .cachedObject;
130: }
131: }
132: } catch (NamingException ex) {
133: throw new JndiLookupFailureException(
134: "JndiObjectTargetSource failed to obtain new target object",
135: ex);
136: }
137: }
138:
139: public void releaseTarget(Object target) {
140: }
141:
142: }
|