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