-
Notifications
You must be signed in to change notification settings - Fork 89
/
SiteMeshFilter.java
150 lines (125 loc) · 6.09 KB
/
SiteMeshFilter.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package com.opensymphony.sitemesh.webapp;
import com.opensymphony.module.sitemesh.Config;
import com.opensymphony.module.sitemesh.Factory;
import com.opensymphony.sitemesh.Content;
import com.opensymphony.sitemesh.Decorator;
import com.opensymphony.sitemesh.DecoratorSelector;
import com.opensymphony.sitemesh.ContentProcessor;
import com.opensymphony.sitemesh.compatability.DecoratorMapper2DecoratorSelector;
import com.opensymphony.sitemesh.compatability.PageParser2ContentProcessor;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Core Filter for integrating SiteMesh into a Java web application.
*
* @author Joe Walnes
* @author Scott Farquhar
* @since SiteMesh 3
*/
public class SiteMeshFilter implements Filter {
private FilterConfig filterConfig;
private ContainerTweaks containerTweaks;
private static final String ALREADY_APPLIED_KEY = "com.opensymphony.sitemesh.APPLIED_ONCE";
public void init(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
containerTweaks = new ContainerTweaks();
}
public void destroy() {
filterConfig = null;
containerTweaks = null;
}
/**
* Main method of the Filter.
* <p>Checks if the Filter has been applied this request. If not, parses the page
* and applies {@link com.opensymphony.module.sitemesh.Decorator} (if found).
*/
public void doFilter(ServletRequest rq, ServletResponse rs, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) rq;
HttpServletResponse response = (HttpServletResponse) rs;
ServletContext servletContext = filterConfig.getServletContext();
SiteMeshWebAppContext webAppContext = new SiteMeshWebAppContext(request, response, servletContext);
ContentProcessor contentProcessor = initContentProcessor(webAppContext);
DecoratorSelector decoratorSelector = initDecoratorSelector(webAppContext);
if (filterAlreadyAppliedForRequest(request)) {
// Prior to Servlet 2.4 spec, it was unspecified whether the filter should be called again upon an include().
chain.doFilter(request, response);
return;
}
if (!contentProcessor.handles(webAppContext)) {
// Optimization: If the content doesn't need to be processed, bypass SiteMesh.
chain.doFilter(request, response);
return;
}
if (containerTweaks.shouldAutoCreateSession()) {
// Some containers (such as Tomcat 4) will not allow sessions to be created in the decorator.
// (i.e after the response has been committed).
request.getSession(true);
}
try {
Content content = obtainContent(contentProcessor, webAppContext, request, response, chain);
if (content == null) {
request.setAttribute(ALREADY_APPLIED_KEY, null);
return;
}
Decorator decorator = decoratorSelector.selectDecorator(content, webAppContext);
decorator.render(content, webAppContext);
} catch (IllegalStateException e) {
// Some containers (such as WebLogic) throw an IllegalStateException when an error page is served.
// It may be ok to ignore this. However, for safety it is propegated if possible.
if (!containerTweaks.shouldIgnoreIllegalStateExceptionOnErrorPage()) {
throw e;
}
} catch (RuntimeException e) {
if (containerTweaks.shouldLogUnhandledExceptions()) {
// Some containers (such as Tomcat 4) swallow RuntimeExceptions in filters.
servletContext.log("Unhandled exception occurred whilst decorating page", e);
}
throw e;
} catch (ServletException e) {
request.setAttribute(ALREADY_APPLIED_KEY, null);
throw e;
}
}
protected ContentProcessor initContentProcessor(SiteMeshWebAppContext webAppContext) {
// TODO: Remove heavy coupling on horrible SM2 Factory
Factory factory = Factory.getInstance(new Config(filterConfig));
factory.refresh();
return new PageParser2ContentProcessor(factory);
}
protected DecoratorSelector initDecoratorSelector(SiteMeshWebAppContext webAppContext) {
// TODO: Remove heavy coupling on horrible SM2 Factory
Factory factory = Factory.getInstance(new Config(filterConfig));
factory.refresh();
return new DecoratorMapper2DecoratorSelector(factory.getDecoratorMapper());
}
/**
* Continue in filter-chain, writing all content to buffer and parsing
* into returned {@link com.opensymphony.module.sitemesh.Page} object. If
* {@link com.opensymphony.module.sitemesh.Page} is not parseable, null is returned.
*/
private Content obtainContent(ContentProcessor contentProcessor, SiteMeshWebAppContext webAppContext,
HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
ContentBufferingResponse contentBufferingResponse = new ContentBufferingResponse(response, contentProcessor, webAppContext);
chain.doFilter(request, contentBufferingResponse);
// TODO: check if another servlet or filter put a page object in the request
// Content result = request.getAttribute(PAGE);
// if (result == null) {
// // parse the page
// result = pageResponse.getPage();
// }
webAppContext.setUsingStream(contentBufferingResponse.isUsingStream());
return contentBufferingResponse.getContent();
}
private boolean filterAlreadyAppliedForRequest(HttpServletRequest request) {
if (request.getAttribute(ALREADY_APPLIED_KEY) == Boolean.TRUE) {
return true;
} else {
request.setAttribute(ALREADY_APPLIED_KEY, Boolean.TRUE);
return false;
}
}
}