001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.wicket.spring;
018:
019: import java.lang.ref.WeakReference;
020:
021: import org.apache.wicket.proxy.IProxyTargetLocator;
022: import org.apache.wicket.util.lang.Classes;
023: import org.apache.wicket.util.lang.Objects;
024: import org.springframework.beans.factory.BeanFactoryUtils;
025: import org.springframework.beans.factory.NoSuchBeanDefinitionException;
026: import org.springframework.context.ApplicationContext;
027:
028: /**
029: * Implementation of {@link IProxyTargetLocator} that can locate beans within a
030: * spring application context. Beans are looked up by the combination of name
031: * and type, if name is omitted only type is used.
032: *
033: * @author Igor Vaynberg (ivaynberg)
034: * @author Istvan Devai
035: */
036: public class SpringBeanLocator implements IProxyTargetLocator {
037: // Weak reference so we don't hold up WebApp classloader garbage collection.
038: private transient WeakReference/*<Class>*/beanTypeCache;
039:
040: private String beanTypeName;
041:
042: private String beanName;
043:
044: private ISpringContextLocator springContextLocator;
045:
046: private Boolean singletonCache = null;
047:
048: /**
049: * Constructor
050: *
051: * @param beanType
052: * bean class
053: * @param locator
054: * spring context locator
055: */
056: public SpringBeanLocator(Class beanType,
057: ISpringContextLocator locator) {
058: this (null, beanType, locator);
059: }
060:
061: /**
062: * Constructor
063: *
064: * @param beanName
065: * bean name
066: * @param beanType
067: * bean class
068: * @param locator
069: * spring context locator
070: */
071: public SpringBeanLocator(String beanName, Class beanType,
072: ISpringContextLocator locator) {
073: if (locator == null) {
074: throw new IllegalArgumentException(
075: "[locator] argument cannot be null");
076: }
077: if (beanType == null) {
078: throw new IllegalArgumentException(
079: "[beanType] argument cannot be null");
080: }
081:
082: this .beanTypeCache = new WeakReference(beanType);
083: this .beanTypeName = beanType.getName();
084: this .springContextLocator = locator;
085: this .beanName = beanName;
086: this .springContextLocator = locator;
087: }
088:
089: /**
090: * Returns the name of the Bean as registered to Spring. Throws IllegalState
091: * exception if none or more then one beans are found.
092: *
093: * @param ctx
094: * spring application context
095: * @param clazz
096: * bean class
097: * @throws IllegalStateException
098: * @return spring name of the bean
099: */
100: private final String getBeanNameOfClass(ApplicationContext ctx,
101: Class clazz) {
102: String[] names = BeanFactoryUtils
103: .beanNamesForTypeIncludingAncestors(ctx, clazz);
104: if (names.length == 0) {
105: throw new IllegalStateException("bean of type ["
106: + clazz.getName() + "] not found");
107: }
108: if (names.length > 1) {
109: throw new IllegalStateException(
110: "more then one bean of type ["
111: + clazz.getName()
112: + "] found, you have to specify the name of the bean (@SpringBean(name=\"foo\")) in order to resolve this conflict");
113: }
114: return names[0];
115: }
116:
117: /**
118: * @return returns whether the bean (the locator is supposed to istantiate)
119: * is a singleton or not
120: */
121: public boolean isSingletonBean() {
122: if (singletonCache == null) {
123: singletonCache = Boolean.valueOf(getSpringContext()
124: .isSingleton(getBeanName()));
125: }
126: return singletonCache.booleanValue();
127: }
128:
129: /**
130: * @return bean class this locator is configured with
131: */
132: public Class getBeanType() {
133: Class clazz = beanTypeCache == null ? null
134: : (Class) beanTypeCache.get();
135: if (clazz == null) {
136: beanTypeCache = new WeakReference(clazz = Classes
137: .resolveClass(beanTypeName));
138: if (clazz == null) {
139: throw new RuntimeException(
140: "SpringBeanLocator could not find class ["
141: + beanTypeName
142: + "] needed to locate the ["
143: + ((beanName != null) ? (beanName)
144: : ("bean name not specified"))
145: + "] bean");
146: }
147: }
148: return clazz;
149: }
150:
151: /**
152: * @see org.apache.wicket.proxy.IProxyTargetLocator#locateProxyTarget()
153: */
154: public Object locateProxyTarget() {
155: final ApplicationContext context = getSpringContext();
156:
157: if (beanName != null && beanName.length() > 0) {
158: return lookupSpringBean(context, beanName, getBeanType());
159: } else {
160: return lookupSpringBean(context, getBeanType());
161: }
162: }
163:
164: private ApplicationContext getSpringContext() {
165: final ApplicationContext context = springContextLocator
166: .getSpringContext();
167:
168: if (context == null) {
169: throw new IllegalStateException(
170: "spring application context locator returned null");
171: }
172: return context;
173: }
174:
175: /**
176: * @return bean name this locator is configured with
177: */
178: public final String getBeanName() {
179: if (beanName == null || "".equals(beanName)) {
180: beanName = getBeanNameOfClass(getSpringContext(),
181: getBeanType());
182:
183: }
184: return beanName;
185: }
186:
187: /**
188: * @return context locator this locator is configured with
189: */
190: public final ISpringContextLocator getSpringContextLocator() {
191: return springContextLocator;
192: }
193:
194: /**
195: * Looks up a bean by its class. Throws IllegalState exception if none or
196: * more then one beans are found.
197: *
198: * @param ctx
199: * spring application context
200: *
201: * @param clazz
202: * bean class
203: * @throws IllegalStateException
204: * @return found bean
205: */
206: private final Object lookupSpringBean(ApplicationContext ctx,
207: Class clazz) {
208: return lookupSpringBean(ctx, getBeanNameOfClass(ctx, clazz),
209: clazz);
210: }
211:
212: /**
213: * Looks up a bean by its name and class. Throws IllegalState exception if
214: * bean not found.
215: *
216: * @param ctx
217: * spring application context
218: *
219: * @param name
220: * bean name
221: * @param clazz
222: * bean class
223: * @throws IllegalStateException
224: * @return found bean
225: */
226: private static Object lookupSpringBean(ApplicationContext ctx,
227: String name, Class clazz) {
228: try {
229: return ctx.getBean(name, clazz);
230: } catch (NoSuchBeanDefinitionException e) {
231: throw new IllegalStateException("bean with name [" + name
232: + "] and class [" + clazz.getName() + "] not found");
233: }
234: }
235:
236: /**
237: * @see java.lang.Object#equals(java.lang.Object)
238: */
239: public boolean equals(Object obj) {
240: if (obj instanceof SpringBeanLocator) {
241: SpringBeanLocator other = (SpringBeanLocator) obj;
242: return beanTypeName.equals(other.beanTypeName)
243: && Objects.equal(beanName, other.beanName);
244: }
245: return false;
246: }
247:
248: /**
249: * @see java.lang.Object#hashCode()
250: */
251: public int hashCode() {
252: int hashcode = beanTypeName.hashCode();
253: if (beanName != null) {
254: hashcode = hashcode + (127 * beanName.hashCode());
255: }
256: return hashcode;
257: }
258: }
|