1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.struts2.jasper.servlet;
19
20 import com.opensymphony.xwork2.util.logging.Logger;
21 import com.opensymphony.xwork2.util.logging.LoggerFactory;
22 import org.apache.struts2.jasper.Constants;
23 import org.apache.struts2.jasper.EmbeddedServletOptions;
24 import org.apache.struts2.jasper.Options;
25 import org.apache.struts2.jasper.compiler.JspRuntimeContext;
26 import org.apache.struts2.jasper.compiler.Localizer;
27
28 import javax.servlet.ServletConfig;
29 import javax.servlet.ServletContext;
30 import javax.servlet.ServletException;
31 import javax.servlet.http.HttpServlet;
32 import javax.servlet.http.HttpServletRequest;
33 import javax.servlet.http.HttpServletResponse;
34 import java.io.IOException;
35 import java.lang.reflect.Constructor;
36 import java.util.Enumeration;
37
38 /***
39 * The JSP engine (a.k.a Jasper).
40 * <p/>
41 * The servlet container is responsible for providing a
42 * URLClassLoader for the web application context Jasper
43 * is being used in. Jasper will try get the Tomcat
44 * ServletContext attribute for its ServletContext class
45 * loader, if that fails, it uses the parent class loader.
46 * In either case, it must be a URLClassLoader.
47 *
48 * @author Anil K. Vijendran
49 * @author Harish Prabandham
50 * @author Remy Maucherat
51 * @author Kin-man Chung
52 * @author Glenn Nielsen
53 */
54 public class JspServlet extends HttpServlet {
55
56
57 private Logger log = LoggerFactory.getLogger(JspServlet.class);
58
59 private ServletContext context;
60 private ServletConfig config;
61 private Options options;
62 private JspRuntimeContext rctxt;
63
64
65
66
67
68 public void init(ServletConfig config) throws ServletException {
69
70 super.init(config);
71 this.config = config;
72 this.context = config.getServletContext();
73
74
75
76 String engineOptionsName =
77 config.getInitParameter("engineOptionsClass");
78 if (engineOptionsName != null) {
79
80 try {
81 ClassLoader loader = Thread.currentThread()
82 .getContextClassLoader();
83 Class engineOptionsClass = loader.loadClass(engineOptionsName);
84 Class[] ctorSig = {ServletConfig.class, ServletContext.class};
85 Constructor ctor = engineOptionsClass.getConstructor(ctorSig);
86 Object[] args = {config, context};
87 options = (Options) ctor.newInstance(args);
88 } catch (Throwable e) {
89
90 log.warn("Failed to load engineOptionsClass", e);
91
92 options = new EmbeddedServletOptions(config, context);
93 }
94 } else {
95
96 options = new EmbeddedServletOptions(config, context);
97 }
98 rctxt = new JspRuntimeContext(context, options);
99
100 if (log.isDebugEnabled()) {
101 log.debug(Localizer.getMessage("jsp.message.scratch.dir.is",
102 options.getScratchDir().toString()));
103 log.debug(Localizer.getMessage("jsp.message.dont.modify.servlets"));
104 }
105 }
106
107
108 /***
109 * Returns the number of JSPs for which JspServletWrappers exist, i.e.,
110 * the number of JSPs that have been loaded into the webapp with which
111 * this JspServlet is associated.
112 * <p/>
113 * <p>This info may be used for monitoring purposes.
114 *
115 * @return The number of JSPs that have been loaded into the webapp with
116 * which this JspServlet is associated
117 */
118 public int getJspCount() {
119 return this.rctxt.getJspCount();
120 }
121
122
123 /***
124 * Resets the JSP reload counter.
125 *
126 * @param count Value to which to reset the JSP reload counter
127 */
128 public void setJspReloadCount(int count) {
129 this.rctxt.setJspReloadCount(count);
130 }
131
132
133 /***
134 * Gets the number of JSPs that have been reloaded.
135 * <p/>
136 * <p>This info may be used for monitoring purposes.
137 *
138 * @return The number of JSPs (in the webapp with which this JspServlet is
139 * associated) that have been reloaded
140 */
141 public int getJspReloadCount() {
142 return this.rctxt.getJspReloadCount();
143 }
144
145
146 /***
147 * <p>Look for a <em>precompilation request</em> as described in
148 * Section 8.4.2 of the JSP 1.2 Specification. <strong>WARNING</strong> -
149 * we cannot use <code>request.getParameter()</code> for this, because
150 * that will trigger parsing all of the request parameters, and not give
151 * a servlet the opportunity to call
152 * <code>request.setCharacterEncoding()</code> first.</p>
153 *
154 * @param request The servlet requset we are processing
155 * @throws ServletException if an invalid parameter value for the
156 * <code>jsp_precompile</code> parameter name is specified
157 */
158 boolean preCompile(HttpServletRequest request) throws ServletException {
159
160 String queryString = request.getQueryString();
161 if (queryString == null) {
162 return (false);
163 }
164 int start = queryString.indexOf(Constants.PRECOMPILE);
165 if (start < 0) {
166 return (false);
167 }
168 queryString =
169 queryString.substring(start + Constants.PRECOMPILE.length());
170 if (queryString.length() == 0) {
171 return (true);
172 }
173 if (queryString.startsWith("&")) {
174 return (true);
175 }
176 if (!queryString.startsWith("=")) {
177 return (false);
178 }
179 int limit = queryString.length();
180 int ampersand = queryString.indexOf("&");
181 if (ampersand > 0) {
182 limit = ampersand;
183 }
184 String value = queryString.substring(1, limit);
185 if (value.equals("true")) {
186 return (true);
187 } else if (value.equals("false")) {
188
189
190
191
192
193 return (true);
194 } else {
195 throw new ServletException("Cannot have request parameter " +
196 Constants.PRECOMPILE + " set to " +
197 value);
198 }
199
200 }
201
202
203 public void service(HttpServletRequest request,
204 HttpServletResponse response)
205 throws ServletException, IOException {
206
207 String jspUri = null;
208
209 String jspFile = (String) request.getAttribute(Constants.JSP_FILE);
210 if (jspFile != null) {
211
212 jspUri = jspFile;
213 } else {
214
215
216
217
218 jspUri = (String) request.getAttribute(Constants.INC_SERVLET_PATH);
219 if (jspUri != null) {
220
221
222
223
224
225 String pathInfo = (String) request.getAttribute(
226 "javax.servlet.include.path_info");
227 if (pathInfo != null) {
228 jspUri += pathInfo;
229 }
230 } else {
231
232
233
234
235
236 jspUri = request.getServletPath();
237 String pathInfo = request.getPathInfo();
238 if (pathInfo != null) {
239 jspUri += pathInfo;
240 }
241 }
242 }
243
244 if (log.isDebugEnabled()) {
245 log.debug("JspEngine --> " + jspUri);
246 log.debug("\t ServletPath: " + request.getServletPath());
247 log.debug("\t PathInfo: " + request.getPathInfo());
248 log.debug("\t RealPath: " + context.getRealPath(jspUri));
249 log.debug("\t RequestURI: " + request.getRequestURI());
250 log.debug("\t QueryString: " + request.getQueryString());
251 log.debug("\t Request Params: ");
252 Enumeration e = request.getParameterNames();
253 while (e.hasMoreElements()) {
254 String name = (String) e.nextElement();
255 log.debug("\t\t " + name + " = "
256 + request.getParameter(name));
257 }
258 }
259
260 try {
261 boolean precompile = preCompile(request);
262 serviceJspFile(request, response, jspUri, null, precompile);
263 } catch (RuntimeException e) {
264 throw e;
265 } catch (ServletException e) {
266 throw e;
267 } catch (IOException e) {
268 throw e;
269 } catch (Throwable e) {
270 throw new ServletException(e);
271 }
272
273 }
274
275 public void destroy() {
276 if (log.isDebugEnabled()) {
277 log.debug("JspServlet.destroy()");
278 }
279
280 rctxt.destroy();
281 }
282
283
284
285
286 private void serviceJspFile(HttpServletRequest request,
287 HttpServletResponse response, String jspUri,
288 Throwable exception, boolean precompile)
289 throws ServletException, IOException {
290
291 JspServletWrapper wrapper =
292 (JspServletWrapper) rctxt.getWrapper(jspUri);
293 if (wrapper == null) {
294 synchronized (this) {
295 wrapper = (JspServletWrapper) rctxt.getWrapper(jspUri);
296 if (wrapper == null) {
297
298
299 if (null == context.getResource(jspUri)) {
300 String includeRequestUri = (String)
301 request.getAttribute("javax.servlet.include.request_uri");
302 if (includeRequestUri != null) {
303
304
305 throw new ServletException(Localizer.getMessage(
306 "jsp.error.file.not.found", jspUri));
307 } else {
308 try {
309 response.sendError(HttpServletResponse.SC_NOT_FOUND,
310 request.getRequestURI());
311 } catch (IllegalStateException ise) {
312 log.error(Localizer.getMessage("jsp.error.file.not.found",
313 jspUri));
314 }
315 }
316 return;
317 }
318 boolean isErrorPage = exception != null;
319 wrapper = new JspServletWrapper(config, options, jspUri,
320 isErrorPage, rctxt);
321 rctxt.addWrapper(jspUri, wrapper);
322 }
323 }
324 }
325
326 wrapper.service(request, response, precompile);
327
328 }
329
330 }