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.velocity;
009    
010    import org.apache.velocity.Template;
011    import org.apache.velocity.VelocityContext;
012    import org.apache.velocity.context.Context;
013    import org.apache.velocity.tools.view.servlet.VelocityViewServlet;
014    import org.picocontainer.PicoContainer;
015    import org.picocontainer.MutablePicoContainer;
016    import org.picocontainer.containers.EmptyPicoContainer;
017    import org.picocontainer.web.PicoServletContainerFilter;
018    
019    import webwork.action.ServletActionContext;
020    import webwork.util.ServletValueStack;
021    import webwork.view.velocity.WebWorkUtil;
022    
023    /**
024     * velocity integration servlet. integrates container hieararchy into velocity
025     * context as well webwork specific objects. This servlet is not derived from
026     * standart webwork velocity servlet because it inherits from obsolete velocity
027     * servlet ( which does not allow resource loading from webapp ). acc
028     * configuration is done like original velocity servlet does
029     * 
030     * @author Konstantin Pribluda
031     */
032    @SuppressWarnings("serial")
033    public final class WebWorkVelocityServlet extends VelocityViewServlet {
034    
035        public static class ServletFilter extends PicoServletContainerFilter {
036            private static ThreadLocal<MutablePicoContainer> currentRequestContainer = new ThreadLocal<MutablePicoContainer>();
037            private static ThreadLocal<MutablePicoContainer> currentSessionContainer = new ThreadLocal<MutablePicoContainer>();
038            private static ThreadLocal<MutablePicoContainer> currentAppContainer = new ThreadLocal<MutablePicoContainer>();
039    
040            protected void setAppContainer(MutablePicoContainer container) {
041                currentAppContainer.set(container);
042            }
043            protected void setRequestContainer(MutablePicoContainer container) {
044                currentRequestContainer.set(container);
045            }
046            protected void setSessionContainer(MutablePicoContainer container) {
047                currentSessionContainer.set(container);
048            }
049    
050            protected static MutablePicoContainer getRequestContainerForThread() {
051                return currentRequestContainer.get();
052            }
053            protected static MutablePicoContainer getSessionContainerForThread() {
054                return currentSessionContainer.get();
055            }
056            protected static MutablePicoContainer getApplicationContainerForThread() {
057                return currentAppContainer.get();
058            }
059        }
060    
061        static final String WEBWORK_UTIL = "webwork";
062        // those have to be removed once dependency problem is solved.
063        // will bomb anyway.
064        static final String REQUEST = "req";
065        static final String RESPONSE = "res";
066    
067        static final EmptyPicoContainer emptyContainer = new EmptyPicoContainer();
068    
069        protected Context createContext(javax.servlet.http.HttpServletRequest request,
070                javax.servlet.http.HttpServletResponse response) {
071            Context ctx = new NanocontainerVelocityContext(ServletFilter.getRequestContainerForThread(),
072                    ServletValueStack.getStack(request));
073            ctx.put(REQUEST, request);
074            ctx.put(RESPONSE, response);
075            return ctx;
076        }
077    
078        /**
079         * Get the template to show.
080         */
081        protected Template handleRequest(javax.servlet.http.HttpServletRequest aRequest,
082                javax.servlet.http.HttpServletResponse aResponse, Context ctx) throws java.lang.Exception {
083            // Bind standard WebWork utility into context
084    
085            ServletActionContext.setContext(aRequest, aResponse, getServletContext(), null);
086            ctx.put(WEBWORK_UTIL, new WebWorkUtil(ctx));
087    
088            String servletPath = (String) aRequest.getAttribute("javax.servlet.include.servlet_path");
089            if (servletPath == null)
090                servletPath = aRequest.getServletPath();
091            return getTemplate(servletPath);
092        }
093    
094        static final class NanocontainerVelocityContext extends VelocityContext {
095            final PicoContainer container;
096            final ServletValueStack stack;
097    
098            NanocontainerVelocityContext(PicoContainer container, ServletValueStack stack) {
099                this.container = container != null ? container : emptyContainer;
100                this.stack = stack;
101            }
102    
103            public boolean internalContainsKey(java.lang.Object key) {
104                boolean contains = super.internalContainsKey(key);
105                if (contains)
106                    return contains;
107    
108                contains = stack.test(key.toString());
109                if (contains)
110                    return contains;
111    
112                return container.getComponentAdapter(key) != null;
113            }
114    
115            public Object internalGet(String key) {
116                if (super.internalContainsKey(key))
117                    return super.internalGet(key);
118    
119                if (stack.test(key))
120                    return stack.findValue(key);
121    
122                return container.getComponent(key);
123            }
124        }
125    }