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