001    /*******************************************************************************
002     * Copyright (c) PicoContainer Organization. All rights reserved.
003     * ---------------------------------------------------------------------------
004     * The software in this package is published under the terms of the BSD style
005     * license a copy of which has been included with this distribution in the
006     * LICENSE.txt file.
007     ******************************************************************************/
008    
009    package org.picocontainer.web.struts2;
010    
011    import java.util.Map;
012    import java.util.Collection;
013    import java.util.Iterator;
014    
015    import org.picocontainer.ComponentAdapter;
016    import org.picocontainer.MutablePicoContainer;
017    import org.picocontainer.injectors.AbstractInjector;
018    import org.picocontainer.web.PicoServletContainerFilter;
019    
020    import com.opensymphony.xwork2.ObjectFactory;
021    import com.opensymphony.xwork2.config.ConfigurationException;
022    import com.opensymphony.xwork2.config.entities.InterceptorConfig;
023    import com.opensymphony.xwork2.interceptor.Interceptor;
024    
025    /**
026     * XWork2 ObjectFactory implementation to delegate action/component/bean lookups
027     * to PicoContainer.
028     * 
029     * @author Paul Hammant
030     * @author Mauro Talevi
031     */
032    @SuppressWarnings("serial")
033    public class PicoObjectFactory extends ObjectFactory {
034    
035        private static ThreadLocal<MutablePicoContainer> currentRequestContainer = new ThreadLocal<MutablePicoContainer>();
036        private static ThreadLocal<MutablePicoContainer> currentSessionContainer = new ThreadLocal<MutablePicoContainer>();
037        private static ThreadLocal<MutablePicoContainer> currentAppContainer = new ThreadLocal<MutablePicoContainer>();
038    
039        public static class ServletFilter extends PicoServletContainerFilter {
040            protected void setAppContainer(MutablePicoContainer container) {
041                currentAppContainer.set(container);
042            }
043            protected void setRequestContainer(MutablePicoContainer container) {
044                currentRequestContainer.set(container);
045            }
046            protected void setSessionContainer(MutablePicoContainer container) {
047                currentSessionContainer.set(container);
048            }
049        }
050    
051        @SuppressWarnings("unchecked")
052        public Class getClassInstance(String name) throws ClassNotFoundException {
053            Class clazz = super.getClassInstance(name);
054            registerAction(clazz);
055            return clazz;
056        }
057    
058        private void registerAction(Class<?> clazz) throws NoClassDefFoundError {
059    
060            synchronized (this) {
061    
062                MutablePicoContainer reqContainer = currentRequestContainer.get();
063                if (reqContainer == null) {
064                    return;
065                }
066                ComponentAdapter<?> ca = reqContainer.getComponentAdapter(clazz);
067                if (ca == null) {
068                    try {
069                        reqContainer.addComponent(clazz);
070                    } catch (NoClassDefFoundError e) {
071                        if (e.getMessage().equals("org/apache/velocity/context/Context")) {
072                            // half expected. XWork seems to setup stuff that cannot
073                            // work
074                            // TODO if this is the case we should make configurable
075                            // the list of classes we "expect" not to find.  Odd!
076                        } else {
077                            throw e;
078                        }
079                    }
080                }
081            }
082        }
083    
084        @SuppressWarnings("unchecked")
085        public Object buildBean(Class clazz, Map extraContext) throws Exception {
086    
087            MutablePicoContainer requestContainer = currentRequestContainer.get();
088            if (requestContainer == null) {
089                MutablePicoContainer appContainer = currentAppContainer.get();
090                Object comp = appContainer.getComponent(clazz);
091                if (comp == null) {
092                    appContainer.addComponent(clazz);
093                    comp = appContainer.getComponent(clazz);
094                }
095                return comp;
096    
097            }
098    //        try {
099                return requestContainer.getComponent(clazz);
100    //        } catch (AbstractInjector.UnsatisfiableDependenciesException e) {
101    //            Collection<ComponentAdapter<?>> adapters = requestContainer.getComponentAdapters();
102    //            for (Iterator<ComponentAdapter<?>> componentAdapterIterator = adapters.iterator(); componentAdapterIterator.hasNext();) {
103    //                ComponentAdapter<?> adapter =  componentAdapterIterator.next();
104    //                System.out.println("--> " + adapter.getComponentKey());
105    //            }
106    //            throw e;
107    //        }
108    
109        }
110    
111        @SuppressWarnings("unchecked")
112        public Interceptor buildInterceptor(InterceptorConfig config, Map params) throws ConfigurationException {
113            return super.buildInterceptor(config, params);
114        }
115    
116        public boolean isNoArgConstructorRequired() {
117            return false;
118        }
119    
120    }