001: /*
002: * Created on Sep 18, 2005
003: */
004: package uk.org.ponder.rsac;
005:
006: import java.beans.PropertyChangeEvent;
007: import java.lang.reflect.Method;
008: import java.util.HashMap;
009: import java.util.Iterator;
010: import java.util.Map;
011:
012: import org.apache.log4j.Level;
013: import org.springframework.beans.BeanInstantiationException;
014: import org.springframework.beans.BeansException;
015: import org.springframework.beans.TypeMismatchException;
016: import org.springframework.beans.factory.BeanCurrentlyInCreationException;
017: import org.springframework.beans.factory.BeanFactoryAware;
018: import org.springframework.beans.factory.BeanNameAware;
019: import org.springframework.beans.factory.DisposableBean;
020: import org.springframework.beans.factory.FactoryBean;
021: import org.springframework.beans.factory.InitializingBean;
022: import org.springframework.beans.factory.NoSuchBeanDefinitionException;
023: import org.springframework.beans.factory.config.BeanDefinition;
024: import org.springframework.beans.factory.config.BeanPostProcessor;
025: import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
026: import org.springframework.context.ApplicationContext;
027: import org.springframework.context.ApplicationContextAware;
028: import org.springframework.context.ConfigurableApplicationContext;
029:
030: import uk.org.ponder.beanutil.BeanUtil;
031: import uk.org.ponder.beanutil.FallbackBeanLocator;
032: import uk.org.ponder.beanutil.WriteableBeanLocator;
033: import uk.org.ponder.reflect.ReflectUtils;
034: import uk.org.ponder.reflect.ReflectiveCache;
035: import uk.org.ponder.saxalizer.AccessMethod;
036: import uk.org.ponder.saxalizer.MethodAnalyser;
037: import uk.org.ponder.saxalizer.SAXalizerMappingContext;
038: import uk.org.ponder.springutil.BeanDefinitionSource;
039: import uk.org.ponder.springutil.TLABPostProcessor;
040: import uk.org.ponder.stringutil.StringList;
041: import uk.org.ponder.util.Denumeration;
042: import uk.org.ponder.util.EnumerationConverter;
043: import uk.org.ponder.util.Logger;
044: import uk.org.ponder.util.ObjectFactory;
045: import uk.org.ponder.util.RunnableInvoker;
046: import uk.org.ponder.util.UniversalRuntimeException;
047:
048: /**
049: * The central class managing the Request Scope Application Context.
050: * <p>
051: * The principal method useful to users is <code>getBeanLocator()</code> which
052: * returns a BeanLocator holding the request context for the current thread. For
053: * each thread entering an RSAC request, it must call
054: * <code>startRequest()</code> before acquiring any request beans, and
055: * <code>endRequest()</code> at the end of its cycle (the latter is most
056: * important).
057: * <p>
058: * In a "pure RSAC" application, the request logic will be defined by the
059: * getting of a single "root bean" from the BeanLocator, although initial setup
060: * and any proxies may require additional calls to <code>getBeanLocator()</code>.
061: * <p>
062: * This class will be due for some refactoring as soon as the next piece of
063: * functionality gets added, getting on for 400 lines. Please note that this
064: * class currently illegally casts BeanDefinitions received from Spring to
065: * AbstractBeanDefinition, which is a potential dependency weakness. This
066: * approach is known to work with Spring 1.1.2 through 2.0.
067: *
068: * @author Antranig Basman (antranig@caret.cam.ac.uk)
069: *
070: */
071:
072: public class RSACBeanLocatorImpl implements ApplicationContextAware,
073: BeanDefinitionSource, RSACBeanLocator {
074:
075: private static CreationMarker BEAN_IN_CREATION_OBJECT = new CreationMarker(
076: 0);
077: private static String REQUEST_STARTED_KEY = ".request started";
078: private ConfigurableApplicationContext blankcontext;
079: private ApplicationContext parentcontext;
080: private SAXalizerMappingContext smc;
081: private ReflectiveCache reflectivecache;
082: private TLABPostProcessor tlabpp;
083:
084: public void setBlankContext(
085: ConfigurableApplicationContext blankcontext) {
086: this .blankcontext = blankcontext;
087: }
088:
089: // NB - currently used only for leafparsers, which are currently JVM-static.
090: public void setMappingContext(SAXalizerMappingContext smc) {
091: this .smc = smc;
092: }
093:
094: public void setApplicationContext(
095: ApplicationContext applicationContext) {
096: parentcontext = applicationContext;
097: }
098:
099: public void setReflectiveCache(ReflectiveCache reflectivecache) {
100: this .reflectivecache = reflectivecache;
101: }
102:
103: // private ThreadLocal threadlocal = new ThreadLocal() {
104: // public Object initialValue() {
105: // return new PerRequestInfo(RSACBeanLocator.this, lazysources);
106: // }
107: // };
108: // We do not use initialValue here because of bug
109: // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5025230 which corrupts
110: // the table when initialising a further ThreadLocal from within
111: // initialValue().
112: // in this case the ThreadLocal is created within CGLib while instantiating
113: // the RSACLazyTargetSource proxies.
114: private ThreadLocal threadlocal = new ThreadLocal();
115:
116: private PerRequestInfo getPerRequest() {
117: PerRequestInfo pri = (PerRequestInfo) threadlocal.get();
118: if (pri == null) {
119: pri = new PerRequestInfo(RSACBeanLocatorImpl.this ,
120: lazysources, tlabpp);
121: threadlocal.set(pri);
122: }
123: return pri;
124: }
125:
126: /**
127: * Starts the request-scope container for the current thread.
128: */
129:
130: public void startRequest() {
131: if (isStarted()) {
132: throw UniversalRuntimeException.accumulate(
133: new IllegalStateException(),
134: "RSAC container has already been started: ");
135: }
136: GlobalBeanAccessor.startRequest(parentcontext);
137: PerRequestInfo pri = getPerRequest();
138: pri.beans.set(REQUEST_STARTED_KEY, BEAN_IN_CREATION_OBJECT);
139: }
140:
141: /**
142: * Determines whether the container has already been started for the current
143: * thread.
144: */
145:
146: public boolean isStarted() {
147: PerRequestInfo pri = getPerRequest();
148: return pri.beans.locateBean(REQUEST_STARTED_KEY) != null;
149: }
150:
151: private void assertIsStarted() {
152: if (!isStarted()) {
153: throw UniversalRuntimeException.accumulate(
154: new IllegalStateException(),
155: "RSAC container has not been started properly: ");
156: }
157: }
158:
159: /**
160: * Called at the end of a request. I advise doing this in a finally block.
161: */
162: public void endRequest() {
163: assertIsStarted();
164: PerRequestInfo pri = getPerRequest();
165: Runnable lazarusList = (Runnable) pri.beans
166: .locateBean("RSACLazarusList");
167: GlobalBeanAccessor.endRequest(); // cannot throw
168:
169: for (int i = 0; i < pri.todestroy.size(); ++i) {
170: String todestroyname = pri.todestroy.stringAt(i);
171: RSACBeanInfo destroybean = (RSACBeanInfo) rbimap
172: .get(todestroyname);
173: Object todestroy = null;
174: try {
175: todestroy = getBean(pri, todestroyname, false);
176: if (todestroy instanceof DisposableBean) {
177: ((DisposableBean) todestroy).destroy();
178: } else {
179: reflectivecache.invokeMethod(todestroy,
180: destroybean.destroymethod);
181: }
182: }
183: // must try to destroy as many beans as possible, cannot propagate
184: // exception in a finally block in any case.
185: catch (Throwable e) { // must NOT propagate any exceptions through a finally block
186: Logger.log.error("Error destroying bean " + todestroy
187: + " with name " + todestroyname, e);
188: }
189: }
190: // System.out.println(pri.cbeans + " beans were created");
191: // Give the garbage collector a head start
192: pri.clear();
193: if (lazarusList != null) {
194: lazarusList.run();
195: }
196: }
197:
198: // this is a map of bean names to RSACBeanInfo
199: private Map rbimap;
200: // this is a list of the beans of type RSACLazyTargetSources
201: private StringList lazysources;
202: // this is a list of "fallback" beans that have already been queried
203: private StringList fallbacks;
204: // this is a map of alias names to "canonical" bean names
205: private Map aliasMap;
206:
207: public void init() {
208: // at this point we actually expect that the "Dead" factory is FULLY
209: // CREATED. This checks that all dependencies are resolvable (if this
210: // has not already been checked by the IDE).
211: String[] beanNames = blankcontext.getBeanDefinitionNames();
212: ConfigurableListableBeanFactory factory = blankcontext
213: .getBeanFactory();
214: // prepare our list of dependencies.
215: rbimap = new HashMap();
216: lazysources = new StringList();
217: fallbacks = new StringList();
218: aliasMap = new HashMap();
219:
220: RBIBeanDefConverter converter = new RBIBeanDefConverter(
221: factory, smc);
222:
223: for (int i = 0; i < beanNames.length; i++) {
224: String beanname = beanNames[i];
225: BeanDefinition beandef = factory
226: .getBeanDefinition(beanname);
227: try {
228: converter.convertBeanDef(beandef, beanname, false);
229: } catch (Exception e) {
230: Logger.log.error("Error loading definition for bean "
231: + beanname, e);
232: }
233: }
234: for (int i = 0; i < converter.rbilist.size(); ++i) {
235: RSACBeanInfo rbi = (RSACBeanInfo) converter.rbilist.get(i);
236: String beanname = rbi.beanname;
237: rbimap.put(beanname, rbi);
238: for (int j = 0; j < rbi.aliases.length; ++j) {
239: aliasMap.put(rbi.aliases[j], beanname);
240: }
241: }
242:
243: // Make a last-ditch attempt to infer bean types.
244: for (int i = 0; i < converter.rbilist.size(); ++i) {
245: RSACBeanInfo rbi = (RSACBeanInfo) converter.rbilist.get(i);
246: String beanname = rbi.beanname;
247: if (rbi.beanclass == null) {
248: rbi.beanclass = getBeanClass(beanname);
249: }
250: if (rbi.beanclass != null) {
251: if (rbi.islazyinit) {
252: lazysources.add(beanname);
253: }
254: if (FallbackBeanLocator.class
255: .isAssignableFrom(rbi.beanclass)
256: && !rbi.isabstract) {
257: fallbacks.add(beanname);
258: }
259: rbi.isfactorybean = FactoryBean.class
260: .isAssignableFrom(rbi.beanclass);
261: }
262: }
263: BracketerPopulator.populateBracketers(parentcontext, rbimap);
264:
265: // we must add this manually because it expects a DIFFERENT applicationContext
266: // to the real one. Also the lifecycle is somewhat different.
267: tlabpp = new TLABPostProcessor();
268: tlabpp.setMappingContext(smc);
269: tlabpp.setApplicationContext(blankcontext);
270: }
271:
272: /**
273: * Returns a list of bean names which are known to correspond to beans
274: * implementing or derived from the supplied class. RSAC has tried slightly
275: * harder to resolve bean classes than Spring generally does, through walking
276: * chains of factory-methods.
277: *
278: * @param clazz A class or interface class to be searched for.
279: * @return A list of derived bean names.
280: */
281: public String[] beanNamesForClass(Class clazz) {
282: StringList togo = new StringList();
283: String[] beanNames = blankcontext.getBeanDefinitionNames();
284: for (int i = 0; i < beanNames.length; i++) {
285: String beanname = beanNames[i];
286: RSACBeanInfo rbi = (RSACBeanInfo) rbimap.get(beanname);
287: if (rbi.beanclass != null && !rbi.isabstract
288: && clazz.isAssignableFrom(rbi.beanclass)) {
289: togo.add(beanname);
290: }
291: }
292: return togo.toStringArray();
293: }
294:
295: /**
296: * Returns the class of this bean, if it can be statically determined,
297: * <code>null</code> if it cannot (i.e. this bean is the product of a
298: * factory-method of a class which is not yet known)
299: *
300: * @param beanname
301: * @return
302: */
303: public Class getBeanClass(String beanname) {
304: RSACBeanInfo rbi = (RSACBeanInfo) rbimap.get(beanname);
305: if (rbi == null) {
306: return parentcontext.getType(beanname);
307: } else if (rbi.beanclass != null) {
308: return rbi.beanclass;
309: } else if (rbi.factorymethod != null && rbi.factorybean != null) {
310: try {
311: Class factoryclass = getBeanClass(rbi.factorybean);
312: Method m = ReflectiveCache.getMethod(factoryclass,
313: rbi.factorymethod);
314: if (m != null) {
315: rbi.beanclass = m.getReturnType();
316: }
317: } catch (Exception e) {
318: Logger.log
319: .info("Error reflecting for factory method "
320: + rbi.factorymethod
321: + " in bean "
322: + rbi.factorybean
323: + " however, it may be present in the concrete bean type");
324: }
325: }
326: // Noone could possibly say we didn't do our best to work out the type of
327: // this bean.
328: return rbi.beanclass;
329: }
330:
331: public void addPostProcessor(BeanPostProcessor beanpp) {
332: getPerRequest().postprocessors.add(beanpp);
333: }
334:
335: private String getTransformedBeanName(String beanname) {
336: String alias = (String) aliasMap.get(beanname);
337: return alias == null ? beanname : alias;
338: }
339:
340: private Object getLocalBean(PerRequestInfo pri, String beanname,
341: boolean nolazy) {
342: beanname = getTransformedBeanName(beanname);
343: Object bean = pri.beans.locateBean(beanname);
344: if (bean instanceof CreationMarker) {
345: throw new BeanCurrentlyInCreationException(beanname);
346: } else if (bean == null) {
347: FactoryBean pfb = (FactoryBean) pri.lazysources
348: .get(beanname);
349: if (pfb != null && !nolazy) {
350: try {
351: return pfb.getObject();
352: } catch (Exception e) {
353: throw UniversalRuntimeException.accumulate(e,
354: "Error getting proxied bean");
355: }
356: } else {
357: bean = createBean(pri, beanname,
358: BEAN_IN_CREATION_OBJECT);
359: }
360: }
361: return bean;
362: }
363:
364: // package access ensures visibility from RSACLazarusList
365: Map getSeedMap() {
366: return getPerRequest().seedbeans;
367: }
368:
369: // package access ensures visibility from RSACBeanFactory
370: Map getRBIMap() {
371: return rbimap;
372: }
373:
374: ConfigurableApplicationContext getBlankContext() {
375: return blankcontext;
376: }
377:
378: // package access ensures visibility from RSACLazyTargetSource
379: Object getBean(PerRequestInfo pri, String beanname, boolean nolazy) {
380: Object bean = null;
381: // NOTES on parentage: We actually WOULD like to make the "blank" context
382: // a child context of the parent, so that we could resolve parents across
383: // the gap - the problem is the line below, where we distinguish local beans
384: // from parent ones. Revisit this when we have a sensible idea about parent
385: // contexts.
386: // NB - we check the container since some fiend might have thrown it in
387: // manually on inchuck - but actually this is faster than Spring anyway.
388: if (pri.beans.locateBean(beanname) != null
389: || rbimap.containsKey(beanname)) {
390: bean = getLocalBean(pri, beanname, nolazy);
391: } else {
392: if (bean == null
393: && this .parentcontext.containsBean(beanname)) {
394: bean = this .parentcontext.getBean(beanname);
395: }
396: }
397: return bean;
398: }
399:
400: /** Return a list of names of beans of type FallbackBeanLocator **/
401: public StringList getFallbackBeans() {
402: return fallbacks;
403: }
404:
405: private Object assembleVectorProperty(PerRequestInfo pri,
406: StringList beannames, Class declaredType) {
407: Object deliver = ReflectUtils.instantiateContainer(
408: declaredType, beannames.size(), reflectivecache);
409: Denumeration den = EnumerationConverter.getDenumeration(
410: deliver, reflectivecache);
411: for (int i = 0; i < beannames.size(); ++i) {
412: String this beanname = beannames.stringAt(i);
413: Object bean = getBean(pri, this beanname, false);
414: den.add(bean);
415: }
416: return deliver;
417: }
418:
419: private Object createBean(final PerRequestInfo pri,
420: final String beanname, CreationMarker marker) {
421: boolean success = false;
422: try {
423: RSACBeanInfo rbi = (RSACBeanInfo) rbimap.get(beanname);
424: if (rbi == null) {
425: throw new NoSuchBeanDefinitionException(beanname,
426: "Bean definition not found");
427: }
428: if (rbi.isabstract) {
429: throw new BeanInstantiationException(rbi.beanclass,
430: "Abstract bean " + rbi.beanname
431: + " cannot be instantiated");
432: }
433:
434: if (marker == null) {
435: marker = BEAN_IN_CREATION_OBJECT;
436: if (rbi.issingleton) {
437: pri.beans.set(beanname, marker);
438: }
439: }
440:
441: // implement fetch wrappers in such a way that doesn't slow normal
442: // creation.
443: if (rbi.fetchwrappers != null
444: && marker.wrapperindex < rbi.fetchwrappers.length) {
445: Object wrappero = rbi.fetchwrappers[marker.wrapperindex];
446: if (marker.wrapperindex == 0) {
447: marker = new CreationMarker(1);
448: if (rbi.issingleton) {
449: pri.beans.set(beanname, marker);
450: }
451: } else {
452: ++marker.wrapperindex;
453: }
454: RunnableInvoker wrapper = (RunnableInvoker) (wrappero instanceof RunnableInvoker ? wrappero
455: : getBean(pri, (String) wrappero, true));
456: final Object[] togo = new Object[1];
457: final CreationMarker nextmarker = marker;
458: wrapper.invokeRunnable(new Runnable() {
459: public void run() {
460: togo[0] = createBean(pri, beanname, nextmarker);
461: }
462:
463: });
464: return togo[0];
465: }
466: if (rbi.issingleton) {
467: ++pri.cbeans;
468: }
469:
470: Object newbean;
471: // NB - isn't this odd, and in fact generally undocumented - properties
472: // defined for factory-method beans are set on the PRODUCT, whereas those
473: // set on FactoryBeans are set on the FACTORY!!
474: if (rbi.factorybean != null) {
475:
476: Object factorybean = null;
477: try {
478: factorybean = getBean(pri, rbi.factorybean, false);
479: } catch (Exception e) {
480: throw UniversalRuntimeException
481: .accumulate(e,
482: "Error fetching factory bean "
483: + rbi.factorybean
484: + " to initialise bean "
485: + beanname);
486: }
487:
488: try {
489: newbean = reflectivecache.invokeMethod(factorybean,
490: rbi.factorymethod);
491: } catch (Exception e) {
492: throw UniversalRuntimeException.accumulate(e,
493: "Error fetching bean " + beanname
494: + " from factory method "
495: + rbi.factorymethod
496: + " of factory bean "
497: + rbi.factorybean);
498: }
499: if (newbean == null) {
500: throw new IllegalArgumentException(
501: "Error: null returned from factory method "
502: + rbi.factorymethod + " of bean "
503: + rbi.factorybean);
504: }
505: // rbi.beanclass = newbean.getClass();
506: } else {
507: // Locate the "dead" bean from the genuine Spring context, and clone it
508: // as quick as we can - bytecodes might do faster but in the meantime
509: // observe that a clone typically costs 1.6 reflective calls so in
510: // general this method will win over a reflective solution.
511: // NB - all Copiables simply copy dependencies manually for now, no
512: // cost.
513: // Copiable deadbean = (Copiable) livecontext.getBean(rbi.isfactorybean?
514: // "&" +beanname : beanname);
515: // All the same, the following line will cost us close to 1us - unless
516: // it invokes manual code!
517: if (rbi.constructorargvals == null) {
518: newbean = reflectivecache.construct(rbi.beanclass);
519: } else {
520: newbean = null;
521: }
522: }
523: if (rbi.hasDependencies()) {
524: // guard this block since if it is a factory-method bean it may be
525: // something
526: // extremely undesirable (like an inner class) that we should not even
527: // dream of reflecting over. If on the other hand the user has specified
528: // some dependencies they doubtless know what they are doing.
529: MethodAnalyser ma = smc.getAnalyser(newbean.getClass());
530: // Object clonebean = deadbean.copy();
531: // iterate over each LOCAL dependency of the bean with given name.
532: for (Iterator depit = rbi.dependencies(); depit
533: .hasNext();) {
534: String propertyname = (String) depit.next();
535:
536: try {
537: AccessMethod setter = ma
538: .getAccessMethod(propertyname);
539: if (setter == null) {
540: throw new IllegalArgumentException(
541: newbean.getClass()
542: + " has no writeable property named "
543: + propertyname);
544: }
545: Object beanref = rbi.beanref(propertyname);
546: Class targetclazz = setter.getAccessedType();
547: Object depbean = resolveDependent(beanref, pri,
548: targetclazz, setter.getDeclaredType());
549:
550: // Lose another 500ns here, until we bring on FastClass.
551: setter.setChildObject(newbean, depbean);
552: } catch (Exception e) {
553: throw UniversalRuntimeException.accumulate(e,
554: "Error setting dependency "
555: + propertyname + " of bean "
556: + beanname);
557: }
558: }
559: }
560: if (rbi.dependson != null) {
561: for (int i = 0; i < rbi.dependson.length; ++i) {
562: getBean(pri, rbi.dependson[i], false);
563: }
564: }
565: // process it FIRST since it will be the factory that is expecting the
566: // dependencies set!
567: newbean = processNewBean(pri, beanname, newbean);
568: // now the bean is initialised, attempt to call any init-method or
569: // InitBean.
570: if (rbi.initmethod != null) {
571: try {
572: reflectivecache.invokeMethod(newbean,
573: rbi.initmethod);
574: } catch (Exception e) {
575: throw UniversalRuntimeException.accumulate(e,
576: "Error invoking init method "
577: + rbi.initmethod + " on bean "
578: + beanname);
579: }
580: }
581: if (newbean instanceof InitializingBean) {
582: try {
583: ((InitializingBean) newbean).afterPropertiesSet();
584: } catch (Exception e) {
585: throw UniversalRuntimeException.accumulate(e);
586: }
587: }
588: if (rbi.destroymethod != null
589: || (newbean instanceof DisposableBean)) {
590: pri.todestroy.add(beanname);
591: }
592:
593: if (newbean instanceof FactoryBean) {
594: FactoryBean factorybean = (FactoryBean) newbean;
595: try {
596: newbean = factorybean.getObject();
597: } catch (Exception e) {
598: throw UniversalRuntimeException.accumulate(e);
599: }
600: }
601: // enter the bean into the req-specific map.
602: if (rbi.issingleton) {
603: pri.beans.set(beanname, newbean);
604: }
605: success = true;
606: return newbean;
607: } finally {
608: if (marker.wrapperindex > 0) {
609: --marker.wrapperindex;
610: if (marker.wrapperindex == 0 && !success) {
611: pri.beans.remove(beanname);
612: }
613: }
614: }
615:
616: }
617:
618: private Object resolveDependent(Object beanref, PerRequestInfo pri,
619: Class accessedType, Class declaredType) {
620: Object depbean = null;
621: if (beanref instanceof String) {
622: String depbeanname = (String) beanref;
623: depbean = fetchDependent(pri, depbeanname, accessedType);
624: BeanUtil.censorNullBean(depbeanname, depbean);
625: } else if (beanref instanceof ValueHolder) {
626: String value = ((ValueHolder) beanref).value;
627: if (smc.saxleafparser.isLeafType(accessedType)) {
628: depbean = smc.saxleafparser.parse(accessedType, value);
629: } else {
630: // exception def copied from the beast BeanWrapperImpl!
631: throw new TypeMismatchException(
632: new PropertyChangeEvent(
633: //newbean, propertyname,
634: null, null, null, value), accessedType,
635: null);
636: }
637: } else {
638: // Really need generalised conversion of vector values here.
639: // The code to do this is actually WITHIN the grotty
640: // BeanWrapperImpl
641: // itself in a protected method with 5 arguments!!
642: // This is a sort of 50% solution. It will deal with all 1-d array
643: // types and collections, and values of parseable types.
644: depbean = assembleVectorProperty(pri, (StringList) beanref,
645: declaredType);
646: }
647: return depbean;
648: }
649:
650: private Object fetchDependent(final PerRequestInfo pri,
651: final String beanname, Class targetclazz) {
652:
653: if (ObjectFactory.class.isAssignableFrom(targetclazz)) {
654: return new ObjectFactory() {
655: public Object getObject() {
656: return getBean(pri, beanname, false);
657: }
658: };
659: } else if (org.springframework.beans.factory.ObjectFactory.class
660: .isAssignableFrom(targetclazz)) {
661: return new org.springframework.beans.factory.ObjectFactory() {
662: public Object getObject() throws BeansException {
663: return getBean(pri, beanname, false);
664: }
665: };
666: } else
667: return getBean(pri, beanname, false);
668: }
669:
670: private Object processNewBean(PerRequestInfo pri, String beanname,
671: Object newbean) {
672: pri.tlabpp.postProcessBeforeInitialization(newbean, beanname);
673: for (int i = 0; i < pri.postprocessors.size(); ++i) {
674: BeanPostProcessor beanpp = (BeanPostProcessor) pri.postprocessors
675: .get(i);
676: try {
677: newbean = beanpp.postProcessBeforeInitialization(
678: newbean, beanname);
679: // TODO: Timing of this next line is incorrect - should occur after
680: // initialisation in caller.
681: // beanpp.postProcessAfterInitialization(newbean, beanname);
682: } catch (Exception e) {
683: Logger.log.log(Level.ERROR,
684: "Exception processing bean "
685: + newbean.getClass().getName(), e);
686: }
687: }
688: if (newbean instanceof BeanFactoryAware) {
689: ((BeanFactoryAware) newbean).setBeanFactory(pri.blfactory);
690: }
691: if (newbean instanceof BeanNameAware) {
692: ((BeanNameAware) newbean).setBeanName(beanname);
693: }
694: if (newbean instanceof ApplicationContextAware) {
695: ((ApplicationContextAware) newbean)
696: .setApplicationContext(parentcontext);
697: }
698: return newbean;
699: }
700:
701: /**
702: * This method gets a BeanLocator which is good just for the current request
703: * scope. The ThreadLocal barrier has already been breached in the returned
704: * object, and evaluation will proceed quickly.
705: */
706: public WriteableBeanLocator getBeanLocator() {
707: assertIsStarted();
708: PerRequestInfo pri = getPerRequest();
709: return pri.requestwbl;
710: }
711:
712: /**
713: * Scope of this BeanLocator is the same as previous, but it will NOT
714: * auto-create beans that are not present.
715: */
716: public WriteableBeanLocator getDeadBeanLocator() {
717: assertIsStarted();
718: PerRequestInfo pri = getPerRequest();
719: return pri.beans;
720: }
721:
722: }
|