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.scripting.support;
018:
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.Map;
022:
023: import net.sf.cglib.asm.Type;
024: import net.sf.cglib.core.Signature;
025: import net.sf.cglib.proxy.InterfaceMaker;
026: import org.apache.commons.logging.Log;
027: import org.apache.commons.logging.LogFactory;
028:
029: import org.springframework.aop.TargetSource;
030: import org.springframework.aop.framework.AopInfrastructureBean;
031: import org.springframework.aop.framework.ProxyFactory;
032: import org.springframework.aop.support.DelegatingIntroductionInterceptor;
033: import org.springframework.beans.BeanUtils;
034: import org.springframework.beans.PropertyValue;
035: import org.springframework.beans.factory.BeanClassLoaderAware;
036: import org.springframework.beans.factory.BeanCreationException;
037: import org.springframework.beans.factory.BeanDefinitionStoreException;
038: import org.springframework.beans.factory.BeanFactory;
039: import org.springframework.beans.factory.BeanFactoryAware;
040: import org.springframework.beans.factory.DisposableBean;
041: import org.springframework.beans.factory.FactoryBean;
042: import org.springframework.beans.factory.config.BeanDefinition;
043: import org.springframework.beans.factory.config.BeanPostProcessor;
044: import org.springframework.beans.factory.config.ConfigurableBeanFactory;
045: import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
046: import org.springframework.beans.factory.support.AbstractBeanDefinition;
047: import org.springframework.beans.factory.support.DefaultListableBeanFactory;
048: import org.springframework.beans.factory.support.GenericBeanDefinition;
049: import org.springframework.context.ResourceLoaderAware;
050: import org.springframework.core.Conventions;
051: import org.springframework.core.Ordered;
052: import org.springframework.core.io.DefaultResourceLoader;
053: import org.springframework.core.io.ResourceLoader;
054: import org.springframework.scripting.ScriptFactory;
055: import org.springframework.scripting.ScriptSource;
056: import org.springframework.util.ClassUtils;
057: import org.springframework.util.ObjectUtils;
058: import org.springframework.util.StringUtils;
059:
060: /**
061: * {@link org.springframework.beans.factory.config.BeanPostProcessor} that
062: * handles {@link org.springframework.scripting.ScriptFactory} definitions,
063: * replacing each factory with the actual scripted Java object generated by it.
064: *
065: * <p>This is similar to the
066: * {@link org.springframework.beans.factory.FactoryBean} mechanism, but is
067: * specifically tailored for scripts and not built into Spring's core
068: * container itself but rather implemented as an extension.
069: *
070: * <p><b>NOTE:</b> The most important characteristic of this post-processor
071: * is that constructor arguments are applied to the
072: * {@link org.springframework.scripting.ScriptFactory} instance
073: * while bean property values are applied to the generated scripted object.
074: * Typically, constructor arguments include a script source locator and
075: * potentially script interfaces, while bean property values include
076: * references and config values to inject into the scripted object itself.
077: *
078: * <p>The following {@link ScriptFactoryPostProcessor} will automatically
079: * be applied to the two
080: * {@link org.springframework.scripting.ScriptFactory} definitions below.
081: * At runtime, the actual scripted objects will be exposed for
082: * "bshMessenger" and "groovyMessenger", rather than the
083: * {@link org.springframework.scripting.ScriptFactory} instances. Both of
084: * those are supposed to be castable to the example's <code>Messenger</code>
085: * interfaces here.
086: *
087: * <pre class="code"><bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
088: *
089: * <bean id="bshMessenger" class="org.springframework.scripting.bsh.BshScriptFactory">
090: * <constructor-arg value="classpath:mypackage/Messenger.bsh"/>
091: * <constructor-arg value="mypackage.Messenger"/>
092: * <property name="message" value="Hello World!"/>
093: * </bean>
094: *
095: * <bean id="groovyMessenger" class="org.springframework.scripting.bsh.GroovyScriptFactory">
096: * <constructor-arg value="classpath:mypackage/Messenger.groovy"/>
097: * <property name="message" value="Hello World!"/>
098: * </bean></pre>
099: *
100: * <p><b>NOTE:</b> Please note that the above excerpt from a Spring
101: * XML bean definition file uses just the <bean/>-style syntax
102: * (in an effort to illustrate using the {@link ScriptFactoryPostProcessor} itself).
103: * In reality, you would never create a <bean/> definition for a
104: * {@link ScriptFactoryPostProcessor} explicitly; rather you would import the
105: * tags from the <code>'lang'</code> namespace and simply create scripted
106: * beans using the tags in that namespace... as part of doing so, a
107: * {@link ScriptFactoryPostProcessor} will implicitly be created for you.
108: *
109: * <p>The Spring reference documentation contains numerous examples of using
110: * tags in the <code>'lang'</code> namespace; by way of an example, find below
111: * a Groovy-backed bean defined using the <code>'lang:groovy'</code> tag.
112: *
113: * <pre class="code">
114: * <?xml version="1.0" encoding="UTF-8"?>
115: * <beans xmlns="http://www.springframework.org/schema/beans"
116: * xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
117: * xmlns:lang="http://www.springframework.org/schema/lang">
118: *
119: * <!-- this is the bean definition for the Groovy-backed Messenger implementation -->
120: * <lang:groovy id="messenger" script-source="classpath:Messenger.groovy">
121: * <lang:property name="message" value="I Can Do The Frug" />
122: * </lang:groovy>
123: *
124: * <!-- an otherwise normal bean that will be injected by the Groovy-backed Messenger -->
125: * <bean id="bookingService" class="x.y.DefaultBookingService">
126: * <property name="messenger" ref="messenger" />
127: * </bean>
128: *
129: * </beans></pre>
130: *
131: * @author Juergen Hoeller
132: * @author Rob Harrop
133: * @author Rick Evans
134: * @author Mark Fisher
135: * @since 2.0
136: */
137: public class ScriptFactoryPostProcessor extends
138: InstantiationAwareBeanPostProcessorAdapter implements
139: BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware,
140: DisposableBean, Ordered {
141:
142: /**
143: * The {@link org.springframework.core.io.Resource}-style prefix that denotes
144: * an inline script.
145: * <p>An inline script is a script that is defined right there in the (typically XML)
146: * configuration, as opposed to being defined in an external file.
147: */
148: public static final String INLINE_SCRIPT_PREFIX = "inline:";
149:
150: public static final String REFRESH_CHECK_DELAY_ATTRIBUTE = Conventions
151: .getQualifiedAttributeName(
152: ScriptFactoryPostProcessor.class,
153: "refreshCheckDelay");
154:
155: private static final String SCRIPT_FACTORY_NAME_PREFIX = "scriptFactory.";
156:
157: private static final String SCRIPTED_OBJECT_NAME_PREFIX = "scriptedObject.";
158:
159: /** Logger available to subclasses */
160: protected final Log logger = LogFactory.getLog(getClass());
161:
162: private long defaultRefreshCheckDelay = -1;
163:
164: private ClassLoader beanClassLoader = ClassUtils
165: .getDefaultClassLoader();
166:
167: private ConfigurableBeanFactory beanFactory;
168:
169: private ResourceLoader resourceLoader = new DefaultResourceLoader();
170:
171: final DefaultListableBeanFactory scriptBeanFactory = new DefaultListableBeanFactory();
172:
173: /** Map from bean name String to ScriptSource object */
174: private final Map scriptSourceCache = new HashMap();
175:
176: /**
177: * Set the delay between refresh checks, in milliseconds.
178: * Default is -1, indicating no refresh checks at all.
179: * <p>Note that an actual refresh will only happen when
180: * the {@link org.springframework.scripting.ScriptSource} indicates
181: * that it has been modified.
182: * @see org.springframework.scripting.ScriptSource#isModified()
183: */
184: public void setDefaultRefreshCheckDelay(
185: long defaultRefreshCheckDelay) {
186: this .defaultRefreshCheckDelay = defaultRefreshCheckDelay;
187: }
188:
189: public void setBeanClassLoader(ClassLoader classLoader) {
190: this .beanClassLoader = classLoader;
191: }
192:
193: public void setBeanFactory(BeanFactory beanFactory) {
194: if (!(beanFactory instanceof ConfigurableBeanFactory)) {
195: throw new IllegalStateException(
196: "ScriptFactoryPostProcessor doesn't work with a BeanFactory "
197: + "which does not implement ConfigurableBeanFactory: "
198: + beanFactory.getClass());
199: }
200: this .beanFactory = (ConfigurableBeanFactory) beanFactory;
201:
202: // Required so that references (up container hierarchies) are correctly resolved.
203: this .scriptBeanFactory.setParentBeanFactory(this .beanFactory);
204:
205: // Required so that all BeanPostProcessors, Scopes, etc become available.
206: this .scriptBeanFactory.copyConfigurationFrom(this .beanFactory);
207:
208: // Filter out BeanPostProcessors that are part of the AOP infrastructure,
209: // since those are only meant to apply to beans defined in the original factory.
210: for (Iterator it = this .scriptBeanFactory
211: .getBeanPostProcessors().iterator(); it.hasNext();) {
212: BeanPostProcessor postProcessor = (BeanPostProcessor) it
213: .next();
214: if (postProcessor instanceof AopInfrastructureBean) {
215: it.remove();
216: }
217: }
218: }
219:
220: public void setResourceLoader(ResourceLoader resourceLoader) {
221: this .resourceLoader = resourceLoader;
222: }
223:
224: public int getOrder() {
225: return Integer.MIN_VALUE;
226: }
227:
228: public Class predictBeanType(Class beanClass, String beanName) {
229: // We only apply special treatment to ScriptFactory implementations here.
230: if (!ScriptFactory.class.isAssignableFrom(beanClass)) {
231: return null;
232: }
233:
234: BeanDefinition bd = this .beanFactory
235: .getMergedBeanDefinition(beanName);
236: String scriptFactoryBeanName = SCRIPT_FACTORY_NAME_PREFIX
237: + beanName;
238: String scriptedObjectBeanName = SCRIPTED_OBJECT_NAME_PREFIX
239: + beanName;
240: prepareScriptBeans(bd, scriptFactoryBeanName,
241: scriptedObjectBeanName);
242:
243: ScriptFactory scriptFactory = (ScriptFactory) this .scriptBeanFactory
244: .getBean(scriptFactoryBeanName, ScriptFactory.class);
245: ScriptSource scriptSource = getScriptSource(
246: scriptFactoryBeanName, scriptFactory
247: .getScriptSourceLocator());
248: Class[] interfaces = scriptFactory.getScriptInterfaces();
249:
250: Class scriptedType = null;
251: try {
252: scriptedType = scriptFactory
253: .getScriptedObjectType(scriptSource);
254: } catch (Exception ex) {
255: if (logger.isDebugEnabled()) {
256: logger.debug(
257: "Could not determine the scripted object type for script factory ["
258: + scriptFactory + "]", ex);
259: }
260: }
261:
262: if (scriptedType != null) {
263: return scriptedType;
264: } else if (ObjectUtils.isEmpty(interfaces)) {
265: if (bd.isSingleton()) {
266: return this .scriptBeanFactory.getBean(
267: scriptedObjectBeanName).getClass();
268: } else {
269: return null;
270: }
271: } else {
272: return (interfaces.length == 1 ? interfaces[0]
273: : createCompositeInterface(interfaces));
274: }
275: }
276:
277: public Object postProcessBeforeInstantiation(Class beanClass,
278: String beanName) {
279: // We only apply special treatment to ScriptFactory implementations here.
280: if (!ScriptFactory.class.isAssignableFrom(beanClass)) {
281: return null;
282: }
283:
284: BeanDefinition bd = this .beanFactory
285: .getMergedBeanDefinition(beanName);
286: String scriptFactoryBeanName = SCRIPT_FACTORY_NAME_PREFIX
287: + beanName;
288: String scriptedObjectBeanName = SCRIPTED_OBJECT_NAME_PREFIX
289: + beanName;
290: prepareScriptBeans(bd, scriptFactoryBeanName,
291: scriptedObjectBeanName);
292:
293: ScriptFactory scriptFactory = (ScriptFactory) this .scriptBeanFactory
294: .getBean(scriptFactoryBeanName, ScriptFactory.class);
295: ScriptSource scriptSource = getScriptSource(
296: scriptFactoryBeanName, scriptFactory
297: .getScriptSourceLocator());
298: boolean isFactoryBean = false;
299: try {
300: Class scriptedObjectType = scriptFactory
301: .getScriptedObjectType(scriptSource);
302: // returned type may be null if the factory is unable to determine
303: if (scriptedObjectType != null) {
304: isFactoryBean = FactoryBean.class
305: .isAssignableFrom(scriptedObjectType);
306: }
307: } catch (Exception e) {
308: throw new BeanCreationException(
309: "Unable to create scripted object: " + beanName, e);
310: }
311:
312: long refreshCheckDelay = resolveRefreshCheckDelay(bd);
313: if (refreshCheckDelay >= 0) {
314: Class[] interfaces = scriptFactory.getScriptInterfaces();
315: RefreshableScriptTargetSource ts = new RefreshableScriptTargetSource(
316: this .scriptBeanFactory, scriptedObjectBeanName,
317: scriptSource, isFactoryBean);
318: ts.setRefreshCheckDelay(refreshCheckDelay);
319: return createRefreshableProxy(ts, interfaces);
320: }
321:
322: if (isFactoryBean) {
323: scriptedObjectBeanName = BeanFactory.FACTORY_BEAN_PREFIX
324: + scriptedObjectBeanName;
325: }
326: return this .scriptBeanFactory.getBean(scriptedObjectBeanName);
327: }
328:
329: /**
330: * Prepare the script beans in the internal BeanFactory that this
331: * post-processor uses. Each original bean definition will be split
332: * into a ScriptFactory definition and a scripted object definition.
333: * @param bd the original bean definition in the main BeanFactory
334: * @param scriptFactoryBeanName the name of the internal ScriptFactory bean
335: * @param scriptedObjectBeanName the name of the internal scripted object bean
336: */
337: protected void prepareScriptBeans(BeanDefinition bd,
338: String scriptFactoryBeanName, String scriptedObjectBeanName) {
339:
340: // Avoid recreation of the script bean definition in case of a prototype.
341: synchronized (this .scriptBeanFactory) {
342: if (!this .scriptBeanFactory
343: .containsBeanDefinition(scriptedObjectBeanName)) {
344:
345: this .scriptBeanFactory.registerBeanDefinition(
346: scriptFactoryBeanName,
347: createScriptFactoryBeanDefinition(bd));
348: ScriptFactory scriptFactory = (ScriptFactory) this .scriptBeanFactory
349: .getBean(scriptFactoryBeanName,
350: ScriptFactory.class);
351: ScriptSource scriptSource = getScriptSource(
352: scriptFactoryBeanName, scriptFactory
353: .getScriptSourceLocator());
354: Class[] interfaces = scriptFactory
355: .getScriptInterfaces();
356:
357: Class[] scriptedInterfaces = interfaces;
358: if (scriptFactory.requiresConfigInterface()
359: && !bd.getPropertyValues().isEmpty()) {
360: Class configInterface = createConfigInterface(bd,
361: interfaces);
362: scriptedInterfaces = (Class[]) ObjectUtils
363: .addObjectToArray(interfaces,
364: configInterface);
365: }
366:
367: BeanDefinition objectBd = createScriptedObjectBeanDefinition(
368: bd, scriptFactoryBeanName, scriptSource,
369: scriptedInterfaces);
370: long refreshCheckDelay = resolveRefreshCheckDelay(bd);
371: if (refreshCheckDelay >= 0) {
372: objectBd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
373: }
374:
375: this .scriptBeanFactory.registerBeanDefinition(
376: scriptedObjectBeanName, objectBd);
377: }
378: }
379: }
380:
381: /**
382: * Get the refresh check delay for the given {@link ScriptFactory} {@link BeanDefinition}.
383: * If the {@link BeanDefinition} has a
384: * {@link org.springframework.core.AttributeAccessor metadata attribute}
385: * under the key {@link #REFRESH_CHECK_DELAY_ATTRIBUTE} which is a valid {@link Number}
386: * type, then this value is used. Otherwise, the the {@link #defaultRefreshCheckDelay}
387: * value is used.
388: * @param beanDefinition the BeanDefinition to check
389: * @return the refresh check delay
390: */
391: protected long resolveRefreshCheckDelay(
392: BeanDefinition beanDefinition) {
393: long refreshCheckDelay = this .defaultRefreshCheckDelay;
394: Object attributeValue = beanDefinition
395: .getAttribute(REFRESH_CHECK_DELAY_ATTRIBUTE);
396: if (attributeValue instanceof Number) {
397: refreshCheckDelay = ((Number) attributeValue).longValue();
398: } else if (attributeValue instanceof String) {
399: refreshCheckDelay = Long.parseLong((String) attributeValue);
400: } else if (attributeValue != null) {
401: throw new BeanDefinitionStoreException(
402: "Invalid refresh check delay attribute ["
403: + REFRESH_CHECK_DELAY_ATTRIBUTE
404: + "] with value [" + attributeValue
405: + "]: needs to be of type Number or String");
406: }
407: return refreshCheckDelay;
408: }
409:
410: /**
411: * Create a ScriptFactory bean definition based on the given script definition,
412: * extracting only the definition data that is relevant for the ScriptFactory
413: * (that is, only bean class and constructor arguments).
414: * @param bd the full script bean definition
415: * @return the extracted ScriptFactory bean definition
416: * @see org.springframework.scripting.ScriptFactory
417: */
418: protected BeanDefinition createScriptFactoryBeanDefinition(
419: BeanDefinition bd) {
420: GenericBeanDefinition scriptBd = new GenericBeanDefinition();
421: scriptBd.setBeanClassName(bd.getBeanClassName());
422: scriptBd.getConstructorArgumentValues().addArgumentValues(
423: bd.getConstructorArgumentValues());
424: return scriptBd;
425: }
426:
427: /**
428: * Obtain a ScriptSource for the given bean, lazily creating it
429: * if not cached already.
430: * @param beanName the name of the scripted bean
431: * @param scriptSourceLocator the script source locator associated with the bean
432: * @return the corresponding ScriptSource instance
433: * @see #convertToScriptSource
434: */
435: protected ScriptSource getScriptSource(String beanName,
436: String scriptSourceLocator) {
437: synchronized (this .scriptSourceCache) {
438: ScriptSource scriptSource = (ScriptSource) this .scriptSourceCache
439: .get(beanName);
440: if (scriptSource == null) {
441: scriptSource = convertToScriptSource(
442: scriptSourceLocator, this .resourceLoader);
443: this .scriptSourceCache.put(beanName, scriptSource);
444: }
445: return scriptSource;
446: }
447: }
448:
449: /**
450: * Convert the given script source locator to a ScriptSource instance.
451: * <p>By default, supported locators are Spring resource locations
452: * (such as "file:C:/myScript.bsh" or "classpath:myPackage/myScript.bsh")
453: * and inline scripts ("inline:myScriptText...").
454: * @param scriptSourceLocator the script source locator
455: * @param resourceLoader the ResourceLoader to use (if necessary)
456: * @return the ScriptSource instance
457: */
458: protected ScriptSource convertToScriptSource(
459: String scriptSourceLocator, ResourceLoader resourceLoader) {
460: if (scriptSourceLocator.startsWith(INLINE_SCRIPT_PREFIX)) {
461: return new StaticScriptSource(scriptSourceLocator
462: .substring(INLINE_SCRIPT_PREFIX.length()));
463: } else {
464: return new ResourceScriptSource(resourceLoader
465: .getResource(scriptSourceLocator));
466: }
467: }
468:
469: /**
470: * Create a config interface for the given bean definition, defining setter
471: * methods for the defined property values as well as an init method and
472: * a destroy method (if defined).
473: * <p>This implementation creates the interface via CGLIB's InterfaceMaker,
474: * determining the property types from the given interfaces (as far as possible).
475: * @param bd the bean definition (property values etc) to create a
476: * config interface for
477: * @param interfaces the interfaces to check against (might define
478: * getters corresponding to the setters we're supposed to generate)
479: * @return the config interface
480: * @see net.sf.cglib.proxy.InterfaceMaker
481: * @see org.springframework.beans.BeanUtils#findPropertyType
482: */
483: protected Class createConfigInterface(BeanDefinition bd,
484: Class[] interfaces) {
485: InterfaceMaker maker = new InterfaceMaker();
486: PropertyValue[] pvs = bd.getPropertyValues()
487: .getPropertyValues();
488: for (int i = 0; i < pvs.length; i++) {
489: String propertyName = pvs[i].getName();
490: Class propertyType = BeanUtils.findPropertyType(
491: propertyName, interfaces);
492: String setterName = "set"
493: + StringUtils.capitalize(propertyName);
494: Signature signature = new Signature(setterName,
495: Type.VOID_TYPE, new Type[] { Type
496: .getType(propertyType) });
497: maker.add(signature, new Type[0]);
498: }
499: if (bd instanceof AbstractBeanDefinition) {
500: AbstractBeanDefinition abd = (AbstractBeanDefinition) bd;
501: if (abd.getInitMethodName() != null) {
502: Signature signature = new Signature(abd
503: .getInitMethodName(), Type.VOID_TYPE,
504: new Type[0]);
505: maker.add(signature, new Type[0]);
506: }
507: if (abd.getDestroyMethodName() != null) {
508: Signature signature = new Signature(abd
509: .getDestroyMethodName(), Type.VOID_TYPE,
510: new Type[0]);
511: maker.add(signature, new Type[0]);
512: }
513: }
514: return maker.create();
515: }
516:
517: /**
518: * Create a composite interface Class for the given interfaces,
519: * implementing the given interfaces in one single Class.
520: * <p>The default implementation builds a JDK proxy class
521: * for the given interfaces.
522: * @param interfaces the interfaces to merge
523: * @return the merged interface as Class
524: * @see java.lang.reflect.Proxy#getProxyClass
525: */
526: protected Class createCompositeInterface(Class[] interfaces) {
527: return ClassUtils.createCompositeInterface(interfaces,
528: this .beanClassLoader);
529: }
530:
531: /**
532: * Create a bean definition for the scripted object, based on the given script
533: * definition, extracting the definition data that is relevant for the scripted
534: * object (that is, everything but bean class and constructor arguments).
535: * @param bd the full script bean definition
536: * @param scriptFactoryBeanName the name of the internal ScriptFactory bean
537: * @param scriptSource the ScriptSource for the scripted bean
538: * @param interfaces the interfaces that the scripted bean is supposed to implement
539: * @return the extracted ScriptFactory bean definition
540: * @see org.springframework.scripting.ScriptFactory#getScriptedObject
541: */
542: protected BeanDefinition createScriptedObjectBeanDefinition(
543: BeanDefinition bd, String scriptFactoryBeanName,
544: ScriptSource scriptSource, Class[] interfaces) {
545:
546: GenericBeanDefinition objectBd = new GenericBeanDefinition(bd);
547: objectBd.setFactoryBeanName(scriptFactoryBeanName);
548: objectBd.setFactoryMethodName("getScriptedObject");
549: objectBd.getConstructorArgumentValues().clear();
550: objectBd.getConstructorArgumentValues()
551: .addIndexedArgumentValue(0, scriptSource);
552: objectBd.getConstructorArgumentValues()
553: .addIndexedArgumentValue(1, interfaces);
554: return objectBd;
555: }
556:
557: /**
558: * Create a refreshable proxy for the given AOP TargetSource.
559: * @param ts the refreshable TargetSource
560: * @param interfaces the proxy interfaces (may be <code>null</code> to
561: * indicate proxying of all interfaces implemented by the target class)
562: * @return the generated proxy
563: * @see RefreshableScriptTargetSource
564: */
565: protected Object createRefreshableProxy(TargetSource ts,
566: Class[] interfaces) {
567: ProxyFactory proxyFactory = new ProxyFactory();
568: proxyFactory.setTargetSource(ts);
569:
570: if (interfaces == null) {
571: interfaces = ClassUtils.getAllInterfacesForClass(ts
572: .getTargetClass());
573: }
574: proxyFactory.setInterfaces(interfaces);
575:
576: DelegatingIntroductionInterceptor introduction = new DelegatingIntroductionInterceptor(
577: ts);
578: introduction.suppressInterface(TargetSource.class);
579: proxyFactory.addAdvice(introduction);
580:
581: return proxyFactory.getProxy(this .beanClassLoader);
582: }
583:
584: /**
585: * Destroy the inner bean factory (used for scripts) on shutdown.
586: */
587: public void destroy() {
588: this.scriptBeanFactory.destroySingletons();
589: }
590:
591: }
|