GRAILS-1019: Allowing expressions to be used with the 'disabled' attribute for g...
[grails.git] / src / web / org / codehaus / groovy / grails / web / sitemesh / GrailsPageFilter.java
blob0f5b0229f05831aec061163ed237d6a3b8b94895
1 /*
2 * Copyright 2004-2005 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.codehaus.groovy.grails.web.sitemesh;
18 import com.opensymphony.module.sitemesh.Decorator;
19 import com.opensymphony.module.sitemesh.DecoratorMapper;
20 import com.opensymphony.module.sitemesh.Page;
21 import com.opensymphony.module.sitemesh.util.Container;
22 import com.opensymphony.module.sitemesh.filter.PageFilter;
23 import com.opensymphony.module.sitemesh.filter.PageResponseWrapper;
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes;
27 import org.codehaus.groovy.grails.commons.ConfigurationHolder;
28 import org.springframework.web.util.UrlPathHelper;
30 import javax.servlet.*;
31 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpServletResponse;
33 import java.io.IOException;
34 import java.io.PrintWriter;
36 /**
37 * Extends the default page filter to overide the apply decorator behaviour
38 * if the page is a GSP
40 * @author Graeme Rocher
41 * @since Apr 19, 2006
43 public class GrailsPageFilter extends PageFilter {
45 private static final Log LOG = LogFactory.getLog( GrailsPageFilter.class );
46 private static final String HTML_EXT = ".html";
47 private static final String UTF_8_ENCODING = "UTF-8";
48 private static final String CONFIG_OPTION_GSP_ENCODING = "grails.views.gsp.encoding";
51 public void init(FilterConfig filterConfig) {
52 super.init(filterConfig);
53 this.filterConfig = filterConfig;
54 FactoryHolder.setFactory(this.factory);
57 public void destroy() {
58 super.destroy();
59 FactoryHolder.setFactory(null);
62 * TODO: This method has been copied from the parent to fix a bug in sitemesh 2.3. When sitemesh 2.4 is release this method and the two private methods below can removed
64 * Main method of the Filter.
66 * <p>Checks if the Filter has been applied this request. If not, parses the page
67 * and applies {@link com.opensymphony.module.sitemesh.Decorator} (if found).
69 public void doFilter(ServletRequest rq, ServletResponse rs, FilterChain chain)
70 throws IOException, ServletException {
72 HttpServletRequest request = (HttpServletRequest) rq;
74 if (rq.getAttribute(FILTER_APPLIED) != null || factory.isPathExcluded(extractRequestPath(request))) {
75 // ensure that filter is only applied once per request
76 chain.doFilter(rq, rs);
78 else {
79 request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
81 factory.refresh();
82 DecoratorMapper decoratorMapper = factory.getDecoratorMapper();
83 HttpServletResponse response = (HttpServletResponse) rs;
85 // parse data into Page object (or continue as normal if Page not parseable)
86 Page page = parsePage(request, response, chain);
88 if (page != null) {
89 page.setRequest(request);
91 Decorator decorator = decoratorMapper.getDecorator(request, page);
92 if (decorator != null && decorator.getPage() != null) {
93 applyDecorator(page, decorator, request, response);
94 return;
96 // if we got here, an exception occured or the decorator was null,
97 // what we don't want is an exception printed to the user, so
98 // we write the original page
99 writeOriginal(request, response, page);
105 * Continue in filter-chain, writing all content to buffer and parsing
106 * into returned {@link com.opensymphony.module.sitemesh.Page} object. If
107 * {@link com.opensymphony.module.sitemesh.Page} is not parseable, null is returned.
109 protected Page parsePage(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
110 try {
111 PageResponseWrapper pageResponse = new PageResponseWrapper(response, factory);
112 UrlPathHelper urlHelper = new UrlPathHelper();
113 String requestURI = urlHelper.getOriginatingRequestUri(request);
114 // static content?
115 if(requestURI.endsWith(HTML_EXT)) {
116 String encoding = (String)ConfigurationHolder.getFlatConfig().get(CONFIG_OPTION_GSP_ENCODING);
117 if(encoding == null) encoding = UTF_8_ENCODING;
118 pageResponse.setContentType("text/html;charset="+encoding);
123 chain.doFilter(request, pageResponse);
124 // check if another servlet or filter put a page object to the request
125 Page result = (Page)request.getAttribute(PAGE);
126 if (result == null) {
127 // parse the page
128 result = pageResponse.getPage();
130 request.setAttribute(USING_STREAM, pageResponse.isUsingStream() ? Boolean.TRUE : Boolean.FALSE); // JDK 1.3 friendly
131 return result;
133 catch (IllegalStateException e) {
134 // weblogic throws an IllegalStateException when an error page is served.
135 // it's ok to ignore this, however for all other containers it should be thrown
136 // properly.
137 if (Container.get() != Container.WEBLOGIC) throw e;
138 return null;
142 private String extractRequestPath(HttpServletRequest request) {
143 String servletPath = request.getServletPath();
144 String pathInfo = request.getPathInfo();
145 String query = request.getQueryString();
146 return (servletPath == null ? "" : servletPath)
147 + (pathInfo == null ? "" : pathInfo)
148 + (query == null ? "" : ("?" + query));
151 /** Write the original page data to the response. */
152 private void writeOriginal(HttpServletRequest request, HttpServletResponse response, Page page) throws IOException {
153 response.setContentLength(page.getContentLength());
154 if (request.getAttribute(USING_STREAM).equals(Boolean.TRUE))
156 PrintWriter writer = new PrintWriter(response.getOutputStream());
157 page.writePage(writer);
158 //flush writer to underlying outputStream
159 writer.flush();
160 response.getOutputStream().flush();
162 else
164 page.writePage(response.getWriter());
165 response.getWriter().flush();
170 /* (non-Javadoc)
171 * @see com.opensymphony.module.sitemesh.filter.PageFilter#applyDecorator(com.opensymphony.module.sitemesh.Page, com.opensymphony.module.sitemesh.Decorator, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
173 protected void applyDecorator(Page page, Decorator decorator, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
174 final String uriPath = decorator.getURIPath();
175 if(uriPath != null && uriPath.endsWith(".gsp")) {
176 request.setAttribute(PAGE, page);
178 detectContentTypeFromPage(page, response);
180 RequestDispatcher rd = request.getRequestDispatcher(decorator.getURIPath());
181 if(!response.isCommitted()) {
182 if(LOG.isDebugEnabled()) {
183 LOG.debug("Rendering layout using forward: " + decorator.getURIPath());
185 rd.forward(request, response);
187 else {
188 if(LOG.isDebugEnabled()) {
189 LOG.debug("Rendering layout using include: " + decorator.getURIPath());
191 request.setAttribute(GrailsApplicationAttributes.GSP_TO_RENDER,decorator.getURIPath());
192 rd.include(request,response);
193 request.removeAttribute(GrailsApplicationAttributes.GSP_TO_RENDER);
196 // set the headers specified as decorator init params
197 while (decorator.getInitParameterNames().hasNext()) {
198 String initParam = (String) decorator.getInitParameterNames().next();
199 if (initParam.startsWith("header.")) {
200 response.setHeader(initParam.substring(initParam.indexOf('.')), decorator.getInitParameter(initParam));
203 request.removeAttribute(PAGE);
205 else {
207 super.applyDecorator(page, decorator, request, response);
212 private void detectContentTypeFromPage(Page page, HttpServletResponse response) {
213 String contentType = page.getProperty("meta.http-equiv.Content-Type");
214 if(contentType != null && "text/html".equals(response.getContentType())) {
215 response.setContentType(contentType);