001    package com.mockrunner.mock.web;
002    
003    import java.io.IOException;
004    import java.util.ArrayList;
005    import java.util.Collections;
006    import java.util.Iterator;
007    import java.util.List;
008    
009    import javax.servlet.Filter;
010    import javax.servlet.FilterChain;
011    import javax.servlet.Servlet;
012    import javax.servlet.ServletException;
013    import javax.servlet.ServletRequest;
014    import javax.servlet.ServletResponse;
015    
016    import org.apache.commons.logging.Log;
017    import org.apache.commons.logging.LogFactory;
018    
019    import com.mockrunner.base.NestedApplicationException;
020    
021    /**
022     * Mock implementation of <code>FilterChain</code>.
023     */
024    public class MockFilterChain implements FilterChain
025    {
026        private final static Log log = LogFactory.getLog(MockFilterChain.class);
027        private List filters = new ArrayList();
028        private Servlet servlet;
029        private Iterator iterator;
030        private List requestList = new ArrayList();
031        private List responseList = new ArrayList();
032        
033        public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException
034        {
035            requestList.add(request);
036            responseList.add(response);
037            if(null == iterator)
038            {
039                iterator = filters.iterator();
040            }
041            if(iterator.hasNext())
042            {
043                Filter nextFilter = (Filter)iterator.next();
044                nextFilter.doFilter(request, response, this);
045            }
046            else
047            {
048                iterator = null;
049                if(null == servlet) return;
050                servlet.service(request, response);
051            }
052        }
053    
054        /**
055         * Adds a filter to the chain.
056         * @param filter the filter
057         */
058        public void addFilter(Filter filter) 
059        {
060            filters.add(filter);
061        }
062        
063        /**
064         * Adds a filter to the chain. The filter must implement
065         * <code>javax.servlet.Filter</code>.
066         * @param filterClass the filter class
067         * @throws IllegalArgumentException if the specified class does not implement
068         *         <code>javax.servlet.Filter</code>
069         */
070        public void addFilter(Class filterClass) 
071        {
072            if(!Filter.class.isAssignableFrom(filterClass))
073            {
074                throw new IllegalArgumentException("filterClass must be an instance of javax.servlet.Filter");
075            }
076            try
077            {
078                filters.add(filterClass.newInstance());
079            }
080            catch(Exception exc)
081            {
082                log.error(exc.getMessage(), exc);
083                throw new NestedApplicationException(exc);
084            }
085        }
086        
087        /**
088         * Sets the servlet that is called at the end of the chain.
089         * @param servlet the servlet
090         */
091        public void setServlet(Servlet servlet) 
092        {
093            this.servlet = servlet;
094        }
095    
096        /**
097         * Clears all filters and sets the current servlet to <code>null</code>.
098         */
099        public void release()
100        {
101            filters.clear();
102            setServlet(null);
103        }
104        
105        /**
106         * Returns the list of all request objects used to call
107         * {@link #doFilter} when iterating through the chain.
108         * @return the request list
109         */
110        public List getRequestList()
111        {
112            return Collections.unmodifiableList(requestList);
113        }
114        
115        /**
116         * Returns the list of all response objects used to call
117         * {@link #doFilter} when iterating through the chain.
118         * @return the response list
119         */
120        public List getResponseList()
121        {
122            return Collections.unmodifiableList(responseList);
123        }
124        
125        /**
126         * Returns the last request, usually the request that was
127         * used to call the final servlet. Returns <code>null</code>
128         * if no request is specified, e.g. if the chain wasn't called.
129         * Otherwise returns the last entry of the list returned by
130         * {@link #getRequestList}.
131         * @return the last request
132         */
133        public ServletRequest getLastRequest()
134        {
135            if(requestList.isEmpty()) return null;
136            return (ServletRequest)requestList.get(requestList.size() - 1);
137        }
138    
139        /**
140         * Returns the last response, usually the response that was
141         * used to call the final servlet. Returns <code>null</code>
142         * if no response is specified, e.g. if the chain wasn't called.
143         * Otherwise returns the last entry of the list returned by
144         * {@link #getResponseList}.
145         * @return the last response
146         */
147        public ServletResponse getLastResponse()
148        {
149            if(responseList.isEmpty()) return null;
150            return (ServletResponse)responseList.get(responseList.size() - 1);
151        }
152    }