KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > opensymphony > webwork > dispatcher > FilterDispatcher


1 /*
2  * Copyright (c) 2002-2003 by OpenSymphony
3  * All rights reserved.
4  */

5 package com.opensymphony.webwork.dispatcher;
6
7 import com.opensymphony.util.ClassLoaderUtil;
8 import com.opensymphony.webwork.WebWorkStatics;
9 import com.opensymphony.webwork.config.Configuration;
10 import com.opensymphony.webwork.dispatcher.mapper.ActionMapper;
11 import com.opensymphony.webwork.dispatcher.mapper.ActionMapperFactory;
12 import com.opensymphony.webwork.dispatcher.mapper.ActionMapping;
13 import com.opensymphony.xwork.ActionContext;
14 import com.opensymphony.xwork.interceptor.component.ComponentConfiguration;
15 import com.opensymphony.xwork.interceptor.component.ComponentManager;
16 import com.opensymphony.xwork.interceptor.component.DefaultComponentManager;
17 import org.apache.commons.logging.Log;
18 import org.apache.commons.logging.LogFactory;
19
20 import javax.servlet.*;
21 import javax.servlet.http.HttpServletRequest JavaDoc;
22 import javax.servlet.http.HttpServletResponse JavaDoc;
23 import javax.servlet.http.HttpSession JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.io.OutputStream JavaDoc;
27 import java.net.URL JavaDoc;
28 import java.net.URLDecoder JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.StringTokenizer JavaDoc;
32
33 /**
34  * Master filter for WebWork that handles four distinct responsibilities:
35  * <ul>
36  * <li>Executing actions</li>
37  * <li>Cleaning up the {@link ActionContext} (see note)</li>
38  * <li>Serving static content</li>
39  * <li>Kicking off XWork's IoC for the request lifecycle</li>
40  * </ul>
41  * <p/>
42  * <p/>
43  * <b>IMPORTANT</b>: this filter must be mapped to all requests. Unless you know exactly
44  * what you are doing, always map to this URL pattern: /*
45  * <p/>
46  * <p/>
47  * <b>Executing actions</b>
48  * <p/>
49  * <p/>
50  * This filter executes actions by consulting the {@link ActionMapper} and determining
51  * if the requested URL should invoke an action. If the mapper indicates it should, <b>the
52  * rest of the filter chain is stopped</b> and the action is invoked. This is important, as
53  * it means that filters like the SiteMesh filter must be placed <b>before</b> this filter
54  * or they will not be able to decorate the output of actions.
55  * <p/>
56  * <p/>
57  * <b>Cleaning up the {@link ActionContext}</b>
58  * <p/>
59  * <p/>
60  * This filter will also automatically clean up the {@link ActionContext} for you, ensuring
61  * that no memory leaks take place. However, this can sometimes cause problems integrating
62  * with other products like SiteMesh. See {@link ActionContexCleanUp} for more information
63  * on how to deal with this.
64  * <p/>
65  * <p/>
66  * <b>Serving static content</b>
67  * <p/>
68  * <p/>
69  * This filter also serves common static content needed when using various parts of WebWork,
70  * such as JavaScript files, CSS files, etc. It works by looking for requests to /webwork/*,
71  * and then mapping the value after "/webwork/" to common packages in WebWork and, optionally,
72  * in your class path. By default, the following packages are automatically searched:
73  * <ul>
74  * <li>com.opensymphony.webwork.static</li>
75  * <li>template</li>
76  * </ul>
77  * <p/>
78  * <p/>
79  * This means that you can simply request /webwork/xhtml/styles.css and the XHTML UI theme's default
80  * stylesheet will be returned. Likewise, many of the AJAX UI components require various JavaScript files,
81  * which are found in the com.opensymphony.webwork.static package. If you wish to add additional packages
82  * to be searched, you can add a comma separated list in the filter init parameter named "packages".
83  * <b>Be careful</b>, however, to expose any packages that may have sensitive information, such as properties
84  * file with database access credentials.
85  * <p/>
86  * <p/>
87  * <b>Kicking off XWork's IoC for the request lifecycle</b>
88  * <p/>
89  * This filter also kicks off the XWork IoC request scope, provided that you are using XWork's IoC. All
90  * you have to do to get started with XWork's IoC is add a components.xml file to WEB-INF/classes and
91  * properly set up the {@link com.opensymphony.webwork.lifecycle.LifecycleListener} in web.xml. See the IoC
92  * docs for more information.
93  * <p/>
94  * <p/>
95  *
96  * @author Patrick Lightbody
97  * @see com.opensymphony.webwork.lifecycle.LifecycleListener
98  * @see ActionMapper
99  * @see ActionContexCleanUp
100  * @since 2.2
101  */

102 public class FilterDispatcher implements Filter, WebWorkStatics {
103     private static final Log LOG = LogFactory.getLog(FilterDispatcher.class);
104
105     protected FilterConfig filterConfig;
106     protected String JavaDoc[] pathPrefixes;
107
108     public FilterConfig getFilterConfig() {
109         return filterConfig;
110     }
111
112     public void destroy() {
113     }
114
115     public void init(FilterConfig filterConfig) throws ServletException {
116         this.filterConfig = filterConfig;
117         String JavaDoc param = filterConfig.getInitParameter("packages");
118         String JavaDoc packages = "com.opensymphony.webwork.static template";
119         if (param != null) {
120             packages = param + " " + packages;
121         }
122         this.pathPrefixes = parse(packages);
123         DispatcherUtils.initialize(filterConfig.getServletContext());
124     }
125
126     protected String JavaDoc[] parse(String JavaDoc packages) {
127         if (packages == null) {
128             return null;
129         }
130         List JavaDoc pathPrefixes = new ArrayList JavaDoc();
131
132         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(packages, ", \n\t");
133         while (st.hasMoreTokens()) {
134             String JavaDoc pathPrefix = st.nextToken().replace('.', '/');
135             if (!pathPrefix.endsWith("/")) {
136                 pathPrefix += "/";
137             }
138             pathPrefixes.add(pathPrefix);
139         }
140
141         return (String JavaDoc[]) pathPrefixes.toArray(new String JavaDoc[pathPrefixes.size()]);
142     }
143
144
145     public void doFilter(ServletRequest JavaDoc req, ServletResponse JavaDoc res, FilterChain chain) throws IOException JavaDoc, ServletException {
146         HttpServletRequest JavaDoc request = (HttpServletRequest JavaDoc) req;
147         HttpServletResponse JavaDoc response = (HttpServletResponse JavaDoc) res;
148         ActionMapper mapper = ActionMapperFactory.getMapper();
149         ActionMapping mapping = mapper.getMapping(request);
150
151         try {
152             setupContainer(request);
153
154             if (mapping == null) {
155                 // there is no action in this request, should we look for a static resource?
156
if (request.getServletPath().startsWith("/webwork")) {
157                     String JavaDoc name = request.getServletPath().substring("/webwork".length());
158                     findStaticResource(name, response);
159                 } else {
160                     // this is a normal request, let it pass through
161
chain.doFilter(request, response);
162                 }
163             } else {
164                 DispatcherUtils du = DispatcherUtils.getInstance();
165                 du.prepare(request, response);
166
167                 try {
168                     request = du.wrapRequest(request, filterConfig.getServletContext());
169                 } catch (IOException JavaDoc e) {
170                     String JavaDoc message = "Could not wrap servlet request with MultipartRequestWrapper!";
171                     LOG.error(message, e);
172                     du.sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, new ServletException(message, e));
173                     return;
174                 }
175
176                 du.serviceAction(request, response, filterConfig.getServletContext(), mapping);
177             }
178         } finally {
179             ActionContexCleanUp.cleanUp(req);
180         }
181     }
182
183     protected void setupContainer(HttpServletRequest JavaDoc request) {
184         ComponentManager container = null;
185         HttpSession JavaDoc session = request.getSession(false);
186         ComponentManager fallback = null;
187         if (session != null) {
188             fallback = (ComponentManager) session.getAttribute(ComponentManager.COMPONENT_MANAGER_KEY);
189         }
190
191         ServletContext servletContext = getServletContext(session);
192         if (fallback == null) {
193             fallback = (ComponentManager) servletContext.getAttribute(ComponentManager.COMPONENT_MANAGER_KEY);
194         }
195
196         if (fallback != null) {
197             container = createComponentManager();
198             container.setFallback(fallback);
199         }
200
201         ComponentConfiguration config = (ComponentConfiguration) servletContext.getAttribute("ComponentConfiguration");
202         if (config != null) {
203             if (container == null) {
204                 container = createComponentManager();
205             }
206
207             config.configure(container, "request");
208             request.setAttribute(ComponentManager.COMPONENT_MANAGER_KEY, container);
209         }
210     }
211
212     /**
213      * Servlet 2.3 specifies that the servlet context can be retrieved from the session. Unfortunately, some
214      * versions of WebLogic can only retrieve the servlet context from the filter config. Hence, this method
215      * enables subclasses to retrieve the servlet context from other sources.
216      *
217      * @param session the HTTP session where, in Servlet 2.3, the servlet context can be retrieved
218      * @return the servlet context.
219      */

220     protected ServletContext getServletContext(HttpSession JavaDoc session) {
221         return filterConfig.getServletContext();
222     }
223
224     protected void tearDownContainer() {
225     }
226
227     protected void findStaticResource(String JavaDoc name, HttpServletResponse JavaDoc response) throws IOException JavaDoc {
228         if (!name.endsWith(".class")) {
229             for (int i = 0; i < pathPrefixes.length; i++) {
230                 InputStream JavaDoc is = findInputStream(name, pathPrefixes[i]);
231                 if (is != null) {
232                     try {
233                         copy(is, response.getOutputStream());
234                     } finally {
235                         is.close();
236                     }
237                     return;
238                 }
239             }
240         }
241
242         response.sendError(HttpServletResponse.SC_NOT_FOUND);
243     }
244
245     protected void copy(InputStream JavaDoc input, OutputStream JavaDoc output) throws IOException JavaDoc {
246         final byte[] buffer = new byte[4096];
247         int n;
248         while (-1 != (n = input.read(buffer))) {
249             output.write(buffer, 0, n);
250         }
251     }
252
253     protected InputStream JavaDoc findInputStream(String JavaDoc name, String JavaDoc packagePrefix) throws IOException JavaDoc {
254         String JavaDoc resourcePath;
255         if (packagePrefix.endsWith("/") && name.startsWith("/")) {
256             resourcePath = packagePrefix + name.substring(1);
257         } else {
258             resourcePath = packagePrefix + name;
259         }
260
261         String JavaDoc enc = (String JavaDoc) Configuration.get("webwork.i18n.encoding");
262         resourcePath = URLDecoder.decode(resourcePath, enc);
263
264         return ClassLoaderUtil.getResourceAsStream(resourcePath, getClass());
265     }
266
267     /**
268      * handle .. chars here and other URL hacks
269      */

270     protected boolean checkUrl(URL JavaDoc url, String JavaDoc rawResourcePath) {
271
272         // ignore folder resources - they provide streams too ! dunno why :)
273
if (url.getPath().endsWith("/")) {
274             return false;
275         }
276
277         // check for parent path access
278
// NOTE : most servlet containers shoudl resolve .. chars in the request url anyway
279
if (url.toExternalForm().indexOf(rawResourcePath) == -1) {
280             return false;
281         }
282
283         return true;
284     }
285
286     /**
287      * Returns a new <tt>DefaultComponentManager</tt> instance. This method is useful for developers
288      * wishing to subclass this class and provide a different implementation of <tt>DefaultComponentManager</tt>.
289      *
290      * @return a new <tt>DefaultComponentManager</tt> instance.
291      */

292     protected DefaultComponentManager createComponentManager() {
293         return new DefaultComponentManager();
294     }
295 }
296
Popular Tags