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.webwork;
009    
010    import java.util.HashMap;
011    import java.util.Map;
012    
013    import org.picocontainer.MutablePicoContainer;
014    import org.picocontainer.PicoCompositionException;
015    import org.picocontainer.web.PicoServletContainerFilter;
016    
017    import webwork.action.Action;
018    import webwork.action.factory.ActionFactory;
019    
020    /**
021     * Replacement for the standard WebWork JavaActionFactory that uses a
022     * PicoContainer to resolve all of the dependencies an Action may have.
023     * 
024     * @author Joe Walnes
025     * @author Mauro Talevi
026     */
027    public final class PicoActionFactory extends ActionFactory {
028    
029        @SuppressWarnings("serial")
030        public static class ServletFilter extends PicoServletContainerFilter {
031            private static ThreadLocal<MutablePicoContainer> currentRequestContainer = new ThreadLocal<MutablePicoContainer>();
032            private static ThreadLocal<MutablePicoContainer> currentSessionContainer = new ThreadLocal<MutablePicoContainer>();
033            private static ThreadLocal<MutablePicoContainer> currentAppContainer = new ThreadLocal<MutablePicoContainer>();
034    
035            protected void setAppContainer(MutablePicoContainer container) {
036                currentAppContainer.set(container);
037            }
038    
039            protected void setRequestContainer(MutablePicoContainer container) {
040                currentRequestContainer.set(container);
041            }
042    
043            protected void setSessionContainer(MutablePicoContainer container) {
044                currentSessionContainer.set(container);
045            }
046    
047            protected static MutablePicoContainer getRequestContainerForThread() {
048                return currentRequestContainer.get();
049            }
050    
051            protected static MutablePicoContainer getSessionContainerForThread() {
052                return currentSessionContainer.get();
053            }
054    
055            protected static MutablePicoContainer getApplicationContainerForThread() {
056                return currentAppContainer.get();
057            }
058    
059        }
060    
061        private final Map<String, Class<?>> classCache = new HashMap<String, Class<?>>();
062    
063        public Action getActionImpl(String className) {
064            try {
065                Class<?> actionClass = getActionClass(className);
066                Action action = null;
067                try {
068                    action = instantiateAction(actionClass);
069                } catch (Exception e) {
070                    // swallow these exceptions and return null action
071                }
072                return action;
073            } catch (PicoCompositionException e) {
074                return null;
075            }
076        }
077    
078        protected Action instantiateAction(Class<?> actionClass) {
079            MutablePicoContainer actionsContainer = ServletFilter.getRequestContainerForThread();
080            Action action = (Action) actionsContainer.getComponent(actionClass);
081    
082            if (action == null) {
083                // The action wasn't registered. Attempt to instantiate it.
084                actionsContainer.addComponent(actionClass);
085                action = (Action) actionsContainer.getComponent(actionClass);
086            }
087            return action;
088        }
089    
090        public Class<?> getActionClass(String className) throws PicoCompositionException {
091            try {
092                return loadClass(className);
093            } catch (ClassNotFoundException e) {
094                throw new PicoCompositionException("Action class '" + className + "' not found", e);
095            }
096        }
097    
098        protected Class<?> loadClass(String className) throws ClassNotFoundException {
099            if (classCache.containsKey(className)) {
100                return (Class<?>) classCache.get(className);
101            } else {
102                Class<?> result = Thread.currentThread().getContextClassLoader().loadClass(className);
103                classCache.put(className, result);
104                return result;
105            }
106        }
107    
108    }