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        private static ThreadLocal<MutablePicoContainer> currentRequestContainer = new ThreadLocal<MutablePicoContainer>();
030        private static ThreadLocal<MutablePicoContainer> currentSessionContainer = new ThreadLocal<MutablePicoContainer>();
031        private static ThreadLocal<MutablePicoContainer> currentAppContainer = new ThreadLocal<MutablePicoContainer>();
032    
033        @SuppressWarnings("serial")
034        public static class ServletFilter extends PicoServletContainerFilter {
035            protected void setAppContainer(MutablePicoContainer container) {
036                currentAppContainer.set(container);
037            }
038            protected void setRequestContainer(MutablePicoContainer container) {
039                currentRequestContainer.set(container);
040            }
041            protected void setSessionContainer(MutablePicoContainer container) {
042                currentSessionContainer.set(container);
043            }
044        }
045    
046        private final Map<String, Class<?>> classCache = new HashMap<String, Class<?>>();
047    
048        public Action getActionImpl(String className) {
049            try {
050                Class<?> actionClass = getActionClass(className);
051                Action action = null;
052                try {
053                    action = instantiateAction(actionClass);
054                } catch (Exception e) {
055                    // swallow these exceptions and return null action
056                }
057                return action;
058            } catch (PicoCompositionException e) {
059                return null;
060            }
061        }
062    
063        protected Action instantiateAction(Class<?> actionClass) {
064            MutablePicoContainer actionsContainer = currentRequestContainer.get();
065            Action action = (Action) actionsContainer.getComponent(actionClass);
066    
067            if (action == null) {
068                // The action wasn't registered. Attempt to instantiate it.
069                actionsContainer.addComponent(actionClass);
070                action = (Action) actionsContainer.getComponent(actionClass);
071            }
072            return action;
073        }
074    
075        public Class<?> getActionClass(String className) throws PicoCompositionException {
076            try {
077                return loadClass(className);
078            } catch (ClassNotFoundException e) {
079                throw new PicoCompositionException("Action class '" + className + "' not found", e);
080            }
081        }
082    
083        protected Class<?> loadClass(String className) throws ClassNotFoundException {
084            if (classCache.containsKey(className)) {
085                return (Class<?>) classCache.get(className);
086            } else {
087                Class<?> result = Thread.currentThread().getContextClassLoader().loadClass(className);
088                classCache.put(className, result);
089                return result;
090            }
091        }
092    
093    }