1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.myfaces.webapp.filter;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.InputStream;
24
25 import javax.servlet.Filter;
26 import javax.servlet.FilterChain;
27 import javax.servlet.FilterConfig;
28 import javax.servlet.RequestDispatcher;
29 import javax.servlet.ServletContext;
30 import javax.servlet.ServletException;
31 import javax.servlet.ServletRequest;
32 import javax.servlet.ServletResponse;
33 import javax.servlet.http.HttpServletRequest;
34 import javax.xml.parsers.SAXParser;
35 import javax.xml.parsers.SAXParserFactory;
36
37
38 /**
39 *
40 * Due to the manner in which the JSP / servlet lifecycle
41 * functions, it is not currently possible to specify default
42 * welcome files for a web application and map them to the
43 * MyFacesServlet. Normally they will be mapped to the
44 * default servlet for the JSP container. To offset this
45 * shortcoming, we utilize a servlet Filter which examines
46 * the URI of all incoming requests.
47 *
48 * @author Robert J. Lebowitz (latest modification by $Author: skitching $)
49 * @author Anton Koinov
50 * @since February 18th, 2003
51 * @version $Revision: 673833 $ $Date: 2008-07-03 16:58:05 -0500 (Thu, 03 Jul 2008) $
52 */
53 public class WelcomeFileFilter
54 implements Filter
55 {
56 //~ Instance fields --------------------------------------------------------
57
58 private FilterConfig _config;
59 private ServletContext _context;
60 private String[] _welcomeFiles = new String[0];
61
62 //~ Methods ----------------------------------------------------------------
63
64 /**
65 * @see javax.servlet.Filter#destroy()
66 */
67 public void destroy()
68 {
69 _config = null;
70 _context = null;
71 _welcomeFiles = null;
72 }
73
74 /**
75 *
76 * If the URI indicates a context, or a subdirectory within a particular
77 * context, but does not specify a filename, the request is redirected to
78 * one of the default welcome files, assuming they are provided in the web.xml file.
79 * If no welcome files are specified, or if none of the welcome files
80 * actually exists, then the request is redirected to a file named "index.jsp" for
81 * that context or subdirectory with the current context. If the index.jsp file
82 * does not exist, the servlet will return a File Not Found Error 404 message.
83 *
84 * A well configured servlet should provide a means of handling this type of
85 * error, along with a link to an appropriate help page.
86 *
87 * A URI is thought to represent a context and/or subdirectory(s) if
88 * it lacks a suffix following the pattern <b>.suffix</b>.
89 *
90 */
91 public void doFilter(
92 ServletRequest request, ServletResponse response, FilterChain chain)
93 throws IOException, ServletException
94 {
95 if (_config == null)
96 {
97 return;
98 }
99
100 HttpServletRequest httpRequest = (HttpServletRequest) request;
101 String uri = httpRequest.getRequestURI();
102
103 // if the uri does not contain a suffix, we consider
104 // it to represent a directory / context, not a file.
105 // file has suffix. No need to search for welcome file
106 if (uri.lastIndexOf('.') > uri.lastIndexOf('/'))
107 {
108 chain.doFilter(request, response);
109
110 return;
111 }
112
113 String contextPath = httpRequest.getContextPath();
114 String welcomeFile = null;
115 StringBuffer sb = new StringBuffer(uri);
116
117 if (!uri.endsWith("/"))
118 {
119 sb.append('/');
120 }
121
122 String baseURI = sb.delete(
123 0,
124 contextPath.length()).toString();
125
126 // REVISIT: we probably can check for existence once at startup
127 // and know the exact welcome file by now. Of course, that
128 // would not work if the files change at runtime, but does it matter?
129 for (int i = 0; i < _welcomeFiles.length; i++)
130 {
131 sb.setLength(0);
132 sb.append(baseURI).append(_welcomeFiles[i]);
133
134 File file = new File(_context.getRealPath(sb.toString()));
135
136 // context.log("Welcome File: " + file.getAbsolutePath());
137 if (file.exists())
138 {
139 // REVISIT: This will force all "welcome" JSPs through MyFaces.
140 // Shouldn't we allow the user to enter *.jsf and check for *.jsp for existence, instead?
141 if (_welcomeFiles[i].endsWith(".jsp"))
142 {
143 // alter the name of the file we are requesting to
144 // force it through the MyFacesServlet
145 sb.replace(
146 sb.lastIndexOf(".jsp"),
147 sb.length(),
148 ".jsf");
149 welcomeFile = sb.toString();
150 }
151
152 // we have discovered a filename;
153 // stop the loop
154 break;
155 }
156 }
157
158 if (welcomeFile == null)
159 {
160 sb.setLength(0);
161 sb.append(baseURI);
162 sb.append("index.jsf");
163 welcomeFile = sb.toString();
164 }
165
166 RequestDispatcher rd = httpRequest.getRequestDispatcher(welcomeFile);
167 rd.forward(request, response);
168
169 return;
170 }
171
172 /**
173 * During the init method, we have to get any predefined welcome files
174 * for the current ServletContext.
175 * @param config The filter configuration data
176 * @throws ServletException
177 */
178 public void init(FilterConfig config)
179 throws ServletException
180 {
181 if (config == null)
182 {
183 return;
184 }
185
186 this._config = config;
187 this._context = config.getServletContext();
188
189 try
190 {
191 SAXParserFactory factory = SAXParserFactory.newInstance();
192 factory.setValidating(false);
193 factory.setNamespaceAware(false);
194
195 SAXParser parser = factory.newSAXParser();
196 WelcomeFileHandler handler = new WelcomeFileHandler();
197 InputStream is =
198 _context.getResourceAsStream("WEB-INF/web.xml");
199
200 if (is == null)
201 {
202 _context.log("Unable to get inputstream for web.xml");
203 }
204
205 parser.parse(is, handler);
206 _welcomeFiles = handler.getWelcomeFiles();
207 _context.log("Number of welcome files: " + _welcomeFiles.length);
208 }
209 catch (Exception ex)
210 {
211 throw new ServletException(ex);
212 }
213 }
214 }