001: /*
002: * Copyright 2002-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.web.servlet.view;
018:
019: import java.util.Map;
020:
021: import javax.servlet.RequestDispatcher;
022: import javax.servlet.ServletException;
023: import javax.servlet.http.HttpServletRequest;
024: import javax.servlet.http.HttpServletResponse;
025:
026: import org.springframework.web.util.WebUtils;
027:
028: /**
029: * Wrapper for a JSP or other resource within the same web application.
030: * Exposes model objects as request attributes and forwards the request to
031: * the specified resource URL using a RequestDispatcher.
032: *
033: * <p>A URL for this view is supposed to specify a resource within the web
034: * application, suitable for RequestDispatcher's <code>forward</code> or
035: * <code>include</code> method.
036: *
037: * <p>If operating within an already included request or within a response that
038: * has already been committed, this view will fall back to an include instead of
039: * a forward. This can be enforced by calling <code>response.flushBuffer()</code>
040: * (which will commit the response) before rendering the view.
041: *
042: * <p>Typical usage with InternalResourceViewResolver would look as follows,
043: * from the perspective of the DispatcherServlet context definition:
044: *
045: * <pre class="code"><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
046: * <property name="prefix" value="/WEB-INF/jsp/"/>
047: * <property name="suffix" value=".jsp"/>
048: * </bean></pre>
049: *
050: * Every view name returned from a handler will be translated to a JSP
051: * resource (for example: "myView" -> "/WEB-INF/jsp/myView.jsp"), using
052: * this view class by default.
053: *
054: * @author Rod Johnson
055: * @author Juergen Hoeller
056: * @author Rob Harrop
057: * @see javax.servlet.RequestDispatcher#forward
058: * @see javax.servlet.RequestDispatcher#include
059: * @see javax.servlet.ServletResponse#flushBuffer
060: * @see InternalResourceViewResolver
061: */
062: public class InternalResourceView extends AbstractUrlBasedView {
063:
064: private boolean alwaysInclude = false;
065:
066: /**
067: * Constructor for use as a bean.
068: * @see #setUrl
069: * @see #setAlwaysInclude
070: */
071: public InternalResourceView() {
072: }
073:
074: /**
075: * Create a new InternalResourceView with the given URL.
076: * @param url the URL to forward to
077: * @see #setAlwaysInclude
078: */
079: public InternalResourceView(String url) {
080: super (url);
081: }
082:
083: /**
084: * Create a new InternalResourceView with the given URL.
085: * @param url the URL to forward to
086: * @param alwaysInclude whether to always include the view rather than forward to it
087: */
088: public InternalResourceView(String url, boolean alwaysInclude) {
089: super (url);
090: this .alwaysInclude = alwaysInclude;
091: }
092:
093: /**
094: * Specify whether to always include the view rather than forward to it.
095: * <p>Default is "false". Switch this flag on to enforce the use of a
096: * Servlet include, even if a forward would be possible.
097: * @see javax.servlet.RequestDispatcher#forward
098: * @see javax.servlet.RequestDispatcher#include
099: * @see #useInclude(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
100: */
101: public void setAlwaysInclude(boolean alwaysInclude) {
102: this .alwaysInclude = alwaysInclude;
103: }
104:
105: /**
106: * Render the internal resource given the specified model.
107: * This includes setting the model as request attributes.
108: */
109: protected void renderMergedOutputModel(Map model,
110: HttpServletRequest request, HttpServletResponse response)
111: throws Exception {
112:
113: // Expose the model object as request attributes.
114: exposeModelAsRequestAttributes(model, request);
115:
116: // Expose helpers as request attributes, if any.
117: exposeHelpers(request);
118:
119: // Determine the path for the request dispatcher.
120: String dispatcherPath = prepareForRendering(request, response);
121:
122: // Forward to the resource (typically a JSP).
123: // Note: The JSP is supposed to determine the content type itself.
124: RequestDispatcher rd = request
125: .getRequestDispatcher(dispatcherPath);
126: if (rd == null) {
127: throw new ServletException(
128: "Could not get RequestDispatcher for ["
129: + getUrl()
130: + "]: check that this file exists within your WAR");
131: }
132:
133: // If already included or response already committed, perform include, else forward.
134: if (useInclude(request, response)) {
135: rd.include(request, response);
136: if (logger.isDebugEnabled()) {
137: logger.debug("Included resource [" + getUrl()
138: + "] in InternalResourceView '" + getBeanName()
139: + "'");
140: }
141: }
142:
143: else {
144: exposeForwardRequestAttributes(request);
145: rd.forward(request, response);
146: if (logger.isDebugEnabled()) {
147: logger.debug("Forwarded to resource [" + getUrl()
148: + "] in InternalResourceView '" + getBeanName()
149: + "'");
150: }
151: }
152: }
153:
154: /**
155: * Expose helpers unique to each rendering operation. This is necessary so that
156: * different rendering operations can't overwrite each other's contexts etc.
157: * <p>Called by {@link #renderMergedOutputModel(Map, HttpServletRequest, HttpServletResponse)}.
158: * The default implementation is empty. This method can be overridden to add
159: * custom helpers as request attributes.
160: * @param request current HTTP request
161: * @throws Exception if there's a fatal error while we're adding attributes
162: * @see #renderMergedOutputModel
163: * @see JstlView#exposeHelpers
164: * @see org.springframework.web.servlet.view.tiles.TilesJstlView#exposeHelpers
165: */
166: protected void exposeHelpers(HttpServletRequest request)
167: throws Exception {
168: }
169:
170: /**
171: * Prepare for rendering, and determine the request dispatcher path
172: * to forward to (or to include).
173: * <p>This implementation simply returns the configured URL.
174: * Subclasses can override this to determine a resource to render,
175: * typically interpreting the URL in a different manner.
176: * @param request current HTTP request
177: * @param response current HTTP response
178: * @return the request dispatcher path to use
179: * @throws Exception if preparations failed
180: * @see #getUrl
181: * @see org.springframework.web.servlet.view.tiles.TilesView#prepareForRendering
182: */
183: protected String prepareForRendering(HttpServletRequest request,
184: HttpServletResponse response) throws Exception {
185:
186: return getUrl();
187: }
188:
189: /**
190: * Determine whether to use RequestDispatcher's <code>include</code> or
191: * <code>forward</code> method.
192: * <p>Performs a check whether an include URI attribute is found in the request,
193: * indicating an include request, and whether the response has already been committed.
194: * In both cases, an include will be performed, as a forward is not possible anymore.
195: * @param request current HTTP request
196: * @param response current HTTP response
197: * @return <code>true</code> for include, <code>false</code> for forward
198: * @see javax.servlet.RequestDispatcher#forward
199: * @see javax.servlet.RequestDispatcher#include
200: * @see javax.servlet.ServletResponse#isCommitted
201: * @see org.springframework.web.util.WebUtils#isIncludeRequest
202: */
203: protected boolean useInclude(HttpServletRequest request,
204: HttpServletResponse response) {
205: return (this .alwaysInclude
206: || WebUtils.isIncludeRequest(request) || response
207: .isCommitted());
208: }
209:
210: /**
211: * Expose the current request URI and paths as {@link HttpServletRequest}
212: * attributes under the keys defined in the Servlet 2.4 specification,
213: * for Servlet 2.3- containers.
214: * <p>Does not override values if already present, to not conflict
215: * with Servlet 2.4+ containers.
216: * @see org.springframework.web.util.WebUtils#exposeForwardRequestAttributes
217: */
218: protected void exposeForwardRequestAttributes(
219: HttpServletRequest request) {
220: WebUtils.exposeForwardRequestAttributes(request);
221: }
222:
223: }
|