001    /*****************************************************************************
002     * Copyright (C) NanoContainer Organization. All rights reserved.            *
003     * ------------------------------------------------------------------------- *
004     * The software in this package is published under the terms of the BSD      *
005     * style license a copy of which has been included with this distribution in *
006     * the LICENSE.txt file.                                                     *
007     *                                                                           *
008     *****************************************************************************/
009    package org.nanocontainer.nanowar.struts;
010    
011    import javax.servlet.http.HttpServletRequest;
012    
013    import org.apache.struts.action.Action;
014    import org.apache.struts.action.ActionMapping;
015    import org.apache.struts.action.ActionServlet;
016    import org.nanocontainer.nanowar.ActionsContainerFactory;
017    import org.picocontainer.MutablePicoContainer;
018    import org.picocontainer.PicoInitializationException;
019    import org.picocontainer.PicoIntrospectionException;
020    
021    /**
022     * Uses PicoContainer to produce Actions and inject dependencies into them. 
023     * If you have your own <code>RequestProcessor</code> implementation, you can use an
024     * <code>ActionFactory</code> in your <code>RequestProcessor.processActionCreate</code> 
025     * method to Picofy your Actions.
026     * 
027     * @author Stephen Molitor
028     * @author Mauro Talevi
029     */
030    public class ActionFactory {
031        
032         private ActionsContainerFactory actionsContainerFactory = new ActionsContainerFactory();
033    
034        /**
035         * Gets the <code>Action</code> specified by the mapping type from a PicoContainer. 
036         * The action will be instantiated if necessary, and its
037         * dependencies will be injected. The action will be instantiated via a
038         * special PicoContainer that just contains actions. If this container
039         * already exists in the request attribute, this method will use it. If no
040         * such container exists, this method will create a new Pico container and
041         * place it in the request. The parent container will either be the request
042         * container, or if that container can not be found the session container,
043         * or if that container can not be found, the application container. If no
044         * parent container can be found, a <code>PicoInitializationException</code>
045         * will be thrown. The action path specified in the mapping is used as
046         * the component key for the action.
047         * 
048         * @param request the Http servlet request.
049         * @param mapping the Struts mapping object, whose type property tells us what
050         *        Action class is required.
051         * @param servlet the Struts <code>ActionServlet</code>.  
052         * @return the <code>Action</code> instance.
053         * @throws PicoIntrospectionException  if the mapping type does not specify a valid action.
054         * @throws PicoInitializationException if no request, session, or application scoped Pico container
055         *                                     can be found.
056         */
057        public Action getAction(HttpServletRequest request, ActionMapping mapping, ActionServlet servlet)
058                throws PicoIntrospectionException, PicoInitializationException {
059    
060            MutablePicoContainer actionsContainer = actionsContainerFactory.getActionsContainer(request);
061            Object actionKey = mapping.getPath();
062            Class actionType = actionsContainerFactory.getActionClass(mapping.getType());
063    
064            Action action = (Action) actionsContainer.getComponentInstance(actionKey);
065            if (action == null) {
066                actionsContainer.registerComponentImplementation(actionKey, actionType);
067                action = (Action) actionsContainer.getComponentInstance(actionKey);
068            }
069    
070            action.setServlet(servlet);
071            return action;
072        }
073    
074    }