001: /*
002: * Created on 27-Feb-2006
003: */
004: package uk.org.ponder.rsf.view.support;
005:
006: import java.util.ArrayList;
007: import java.util.Collection;
008: import java.util.HashMap;
009: import java.util.List;
010: import java.util.Map;
011:
012: import org.springframework.beans.BeansException;
013: import org.springframework.context.ApplicationContext;
014: import org.springframework.context.ApplicationContextAware;
015:
016: import uk.org.ponder.reflect.ReflectiveCache;
017: import uk.org.ponder.rsac.RSACBeanLocator;
018: import uk.org.ponder.rsf.view.ComponentProducer;
019: import uk.org.ponder.rsf.view.ComponentProducerWrapper;
020: import uk.org.ponder.rsf.view.ViewComponentProducer;
021:
022: /**
023: * Manages a set of beans representing view producers. The slightly unusual
024: * approach adopted for request-scope producers is recommended by all sorts of
025: * considerations of user convenience - we would like implementors of request
026: * scope view producers to i) simply implement normal request-scope beans ii)
027: * not have any of them instantiated except for the ones required for a request,
028: * and iii) signal their capabilities through the selection of interfaces they
029: * implement. <br>
030: * All of these considerations militate against the use of some kind of AOP
031: * technique, which would become quite cumbersome, and also tedious to make
032: * efficient. <br>
033: * Instead, this class internally maintains a hash of application-scope "blank"
034: * producers that are dispensed to users (the framework) - these will answer to
035: * all application-scope and other static queries per contract - however, when
036: * the users want to invoke the production method, they must first make a call
037: * to wrapProducer - for an application scope producer, this simply returns the
038: * original bean. <br>
039: * This bean ALSO scours the application context similarly for application
040: * scope ViewProducers in the straightforward way.
041: *
042: * @author Antranig Basman (amb26@ponder.org.uk)
043: *
044: */
045:
046: public class AutoComponentProducerManager implements
047: ComponentProducerWrapper, ApplicationContextAware {
048:
049: private RSACBeanLocator rsacbl;
050: private ReflectiveCache reflectivecache;
051:
052: public void setRSACBeanLocator(RSACBeanLocator rsacbl) {
053: this .rsacbl = rsacbl;
054: }
055:
056: public void setReflectiveCache(ReflectiveCache reflectivecache) {
057: this .reflectivecache = reflectivecache;
058: }
059:
060: public void init() {
061: String[] viewbeans = rsacbl
062: .beanNamesForClass(ComponentProducer.class);
063: for (int i = 0; i < viewbeans.length; ++i) {
064: String beanname = viewbeans[i];
065: Class clazz = rsacbl.getBeanClass(beanname);
066: // this strategy currently assumes uniqueness on bean classes - could be
067: // upgraded to something more subtle, but where would we get the context
068: // from?
069: ComponentProducer blank = (ComponentProducer) reflectivecache
070: .construct(clazz);
071: componentMap.put(blank, beanname);
072: if (blank instanceof ViewComponentProducer) {
073: advertised.add(blank);
074: }
075: }
076: }
077:
078: // this is a map of "blank" component objects to bean names.
079: private Map componentMap = new HashMap();
080:
081: private List advertised = new ArrayList();
082:
083: public void setApplicationContext(
084: ApplicationContext applicationContext)
085: throws BeansException {
086: String[] viewbeans = applicationContext.getBeanNamesForType(
087: ViewComponentProducer.class, false, false);
088: for (int i = 0; i < viewbeans.length; ++i) {
089: String beanname = viewbeans[i];
090: ViewComponentProducer producer = (ViewComponentProducer) applicationContext
091: .getBean(beanname);
092: advertised.add(producer);
093: }
094:
095: }
096:
097: /**
098: * For a request-scope "blank" producer, fetches and returns the corresponding
099: * request-scope bean. For any other producer, returns the argument unchanged.
100: */
101:
102: public ComponentProducer wrapProducer(ComponentProducer towrap) {
103: String beanname = (String) componentMap.get(towrap);
104: ComponentProducer togo = towrap;
105: if (beanname != null) {
106: togo = (ComponentProducer) rsacbl.getBeanLocator()
107: .locateBean(beanname);
108: }
109: return togo;
110: }
111:
112: /**
113: * Returns the list of "advertised" producers. These will be the ones of type
114: * ViewComponentProducer found at either application or request scope. This
115: * differs from the set which can be "translated" by wrapProducer, which is
116: * the set of ALL producers found at request scope.
117: *
118: * @return The producers available for this request cycle.
119: */
120: public Collection getProducers() {
121: return advertised;
122: }
123:
124: }
|