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    
013    import org.picocontainer.ComponentAdapter;
014    import org.picocontainer.MutablePicoContainer;
015    import org.picocontainer.web.PicoServletContainerFilter;
016    
017    import com.opensymphony.xwork2.ObjectFactory;
018    import com.opensymphony.xwork2.config.ConfigurationException;
019    import com.opensymphony.xwork2.config.entities.InterceptorConfig;
020    import com.opensymphony.xwork2.interceptor.Interceptor;
021    
022    /**
023     * XWork2 ObjectFactory implementation to delegate action/component/bean lookups
024     * to PicoContainer.
025     * 
026     * @author Paul Hammant
027     * @author Mauro Talevi
028     */
029    @SuppressWarnings("serial")
030    public class PicoObjectFactory extends ObjectFactory {
031    
032        public static class ServletFilter extends PicoServletContainerFilter {
033            private static ThreadLocal<MutablePicoContainer> currentRequestContainer = new ThreadLocal<MutablePicoContainer>();
034            private static ThreadLocal<MutablePicoContainer> currentSessionContainer = new ThreadLocal<MutablePicoContainer>();
035            private static ThreadLocal<MutablePicoContainer> currentAppContainer = new ThreadLocal<MutablePicoContainer>();
036    
037            protected void setAppContainer(MutablePicoContainer container) {
038                currentAppContainer.set(container);
039            }
040            protected void setRequestContainer(MutablePicoContainer container) {
041                currentRequestContainer.set(container);
042            }
043            protected void setSessionContainer(MutablePicoContainer container) {
044                currentSessionContainer.set(container);
045            }
046    
047            protected static MutablePicoContainer getRequestContainerForThread() {
048                return currentRequestContainer.get();
049            }
050            protected static MutablePicoContainer getSessionContainerForThread() {
051                return currentSessionContainer.get();
052            }
053            protected static MutablePicoContainer getApplicationContainerForThread() {
054                return currentAppContainer.get();
055            }
056    
057        }
058    
059        @SuppressWarnings("unchecked")
060        public Class getClassInstance(String name) throws ClassNotFoundException {
061            Class clazz = super.getClassInstance(name);
062            registerAction(clazz);
063            return clazz;
064        }
065    
066        private void registerAction(Class<?> clazz) throws NoClassDefFoundError {
067    
068            synchronized (this) {
069    
070                MutablePicoContainer reqContainer = ServletFilter.getRequestContainerForThread();
071                if (reqContainer == null) {
072                    return;
073                }
074                ComponentAdapter<?> ca = reqContainer.getComponentAdapter(clazz);
075                if (ca == null) {
076                    try {
077                        reqContainer.addComponent(clazz);
078                    } catch (NoClassDefFoundError e) {
079                        if (e.getMessage().equals("org/apache/velocity/context/Context")) {
080                            // half expected. XWork seems to setup stuff that cannot
081                            // work
082                            // TODO if this is the case we should make configurable
083                            // the list of classes we "expect" not to find.  Odd!
084                        } else {
085                            throw e;
086                        }
087                    }
088                }
089            }
090        }
091    
092        @SuppressWarnings("unchecked")
093        public Object buildBean(Class clazz, Map extraContext) throws Exception {
094    
095            MutablePicoContainer requestContainer = ServletFilter.getRequestContainerForThread();
096            if (requestContainer == null) {
097                MutablePicoContainer appContainer = ServletFilter.getApplicationContainerForThread();
098                Object comp = appContainer.getComponent(clazz);
099                if (comp == null) {
100                    appContainer.addComponent(clazz);
101                    comp = appContainer.getComponent(clazz);
102                }
103                return comp;
104    
105            }
106            return requestContainer.getComponent(clazz);
107    
108        }
109    
110        @SuppressWarnings("unchecked")
111        public Interceptor buildInterceptor(InterceptorConfig config, Map params) throws ConfigurationException {
112            return super.buildInterceptor(config, params);
113        }
114    
115        public boolean isNoArgConstructorRequired() {
116            return false;
117        }
118    
119    }