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    package org.picocontainer.web.struts2;
009    
010    import org.picocontainer.web.PicoServletContainerListener;
011    import org.picocontainer.web.ThreadLocalLifecycleState;
012    import org.picocontainer.web.ScopedContainers;
013    import org.picocontainer.DefaultPicoContainer;
014    import org.picocontainer.MutablePicoContainer;
015    import org.picocontainer.PicoCompositionException;
016    import org.picocontainer.ComponentMonitor;
017    import org.picocontainer.monitors.NullComponentMonitor;
018    import org.picocontainer.lifecycle.NullLifecycleStrategy;
019    import org.picocontainer.behaviors.Caching;
020    import org.picocontainer.behaviors.Storing;
021    import org.picocontainer.behaviors.Guarding;
022    import com.opensymphony.xwork2.Action;
023    import com.opensymphony.xwork2.Result;
024    
025    import javax.servlet.ServletContextEvent;
026    
027    import ognl.OgnlRuntime;
028    
029    public class Struts2PicoServletContainerListener extends PicoServletContainerListener {
030    
031        public void contextInitialized(ServletContextEvent event) {
032            OgnlRuntime.setSecurityManager(null);
033            super.contextInitialized(event);
034        }
035    
036        protected ScopedContainers makeScopedContainers(boolean stateless) {
037    
038            //NullLifecycleStrategy ls = new NullLifecycleStrategy();
039    
040            DefaultPicoContainer appCtnr = new DefaultPicoContainer(new Guarding().wrap(new Caching()), makeLifecycleStrategy(), makeParentContainer(), makeAppComponentMonitor());
041            Storing sessStoring = new Storing();
042            DefaultPicoContainer sessCtnr = new DefaultPicoContainer(new Guarding().wrap(sessStoring), makeLifecycleStrategy(), appCtnr, makeSessionComponentMonitor());
043            Storing reqStoring = new Storing();
044            DefaultPicoContainer reqCtnr = new DefaultPicoContainer(new Guarding().wrap(addRequestBehaviors(reqStoring)), makeLifecycleStrategy(), sessCtnr, makeRequestComponentMonitor());
045            ThreadLocalLifecycleState sessionState = new ThreadLocalLifecycleState();
046            ThreadLocalLifecycleState requestState = new ThreadLocalLifecycleState();
047            sessCtnr.setLifecycleState(sessionState);
048            reqCtnr.setLifecycleState(requestState);
049    
050            return new ScopedContainers(appCtnr, sessCtnr, reqCtnr, sessStoring, reqStoring, sessionState, requestState);
051    
052        }
053    
054        /**
055         * Struts2 handles whole value objects in some configurations.
056         * This enables lazy instantiation of them    
057         */
058        @Override
059        protected ComponentMonitor makeRequestComponentMonitor() {
060            return new StrutsActionInstantiatingComponentMonitor();
061        }
062    
063        public static class StrutsActionInstantiatingComponentMonitor extends NullComponentMonitor {
064            public Object noComponentFound(MutablePicoContainer mutablePicoContainer, Object o) {
065                return noComponent(mutablePicoContainer, o);
066            }
067    
068            private Object noComponent(MutablePicoContainer mutablePicoContainer, Object o) {
069                if (o instanceof Class) {
070                    Class clazz = (Class) o;
071                    if (Action.class.isAssignableFrom(clazz) || Result.class.isAssignableFrom(clazz)) {
072                        try {
073                            mutablePicoContainer.addComponent(clazz);
074                        } catch (NoClassDefFoundError e) {
075                            if (e.getMessage().equals("org/apache/velocity/context/Context")) {
076                                // half expected. XWork seems to setup stuff that cannot
077                                // work
078                                // TODO if this is the case we should make configurable
079                                // the list of classes we "expect" not to find.  Odd!
080                            } else {
081                                throw e;
082                            }
083                        }
084    
085                        return null;
086                    }
087                    try {
088                        if (clazz.getConstructor(new Class[0]) != null) {
089                            return clazz.newInstance();
090                        }
091                    } catch (InstantiationException e) {
092                        throw new PicoCompositionException("can't instantiate " + o);
093                    } catch (IllegalAccessException e) {
094                        throw new PicoCompositionException("illegal access " + o);
095                    } catch (NoSuchMethodException e) {
096                    }
097                }
098                return super.noComponentFound(mutablePicoContainer, o);
099            }
100        }
101    }