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.mvc;
018:
019: import javax.servlet.RequestDispatcher;
020: import javax.servlet.ServletException;
021: import javax.servlet.http.HttpServletRequest;
022: import javax.servlet.http.HttpServletResponse;
023:
024: import org.springframework.beans.factory.BeanNameAware;
025: import org.springframework.web.servlet.ModelAndView;
026: import org.springframework.web.util.WebUtils;
027:
028: /**
029: * Spring Controller implementation that forwards to a named servlet,
030: * i.e. the "servlet-name" in web.xml rather than a URL path mapping.
031: * A target servlet doesn't even need a "servlet-mapping" in web.xml
032: * in the first place: A "servlet" declaration is sufficient.
033: *
034: * <p>Useful to invoke an existing servlet via Spring's dispatching infrastructure,
035: * for example to apply Spring HandlerInterceptors to its requests. This will work
036: * even in a Servlet 2.2 container that does not support Servlet filters.
037: *
038: * <p>In particular, the main intent of this controller is to allow for applying
039: * Spring's OpenSessionInViewInterceptor or OpenPersistenceManagerInViewInterceptor
040: * to servlets in a Servlet 2.2 container. The specified "servlet-name" will
041: * simply refer to a custom servlet definition in web.xml in such a scenario.
042: * You then need to map "/myservlet" (or whatever path you choose for your servlet)
043: * onto this controller, which will in turn forward to your servlet.
044: *
045: * <p>In a Servlet 2.3 container, when not using Spring's own web MVC framework,
046: * it is recommended to use classic servlet mapping in combination with a filter,
047: * for example Spring's OpenSessionInViewFilter or OpenPersistenceManagerInViewFilter.
048: *
049: * <p><b>Example:</b> web.xml, mapping all "/myservlet" requests to a Spring dispatcher.
050: * Also defines a custom "myServlet", but <i>without</i> servlet mapping.
051: *
052: * <pre>
053: * <servlet>
054: * <servlet-name>myServlet</servlet-name>
055: * <servlet-class>mypackage.TestServlet</servlet-class>
056: * </servlet>
057: *
058: * <servlet>
059: * <servlet-name>myDispatcher</servlet-name>
060: * <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
061: * </servlet>
062: *
063: * <servlet-mapping>
064: * <servlet-name>myDispatcher</servlet-name>
065: * <url-pattern>/myservlet</url-pattern>
066: * </servlet-mapping></pre>
067: *
068: * <b>Example:</b> myDispatcher-servlet.xml, in turn forwarding "/myservlet" to your
069: * servlet (identified by servlet name). All such requests will go through the
070: * configured HandlerInterceptor chain (e.g. an OpenSessionInViewInterceptor).
071: * From the servlet point of view, everything will work as usual.
072: *
073: * <pre>
074: * <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
075: * <property name="interceptors">
076: * <list>
077: * <ref bean="openSessionInViewInterceptor"/>
078: * </list>
079: * </property>
080: * <property name="mappings">
081: * <props>
082: * <prop key="/myservlet">myServletForwardingController</prop>
083: * </props>
084: * </property>
085: * </bean>
086: *
087: * <bean id="myServletForwardingController" class="org.springframework.web.servlet.mvc.ServletForwardingController">
088: * <property name="servletName"><value>myServlet</value></property>
089: * </bean></pre>
090: *
091: * @author Juergen Hoeller
092: * @since 1.1.1
093: * @see ServletWrappingController
094: * @see org.springframework.orm.hibernate.support.OpenSessionInViewInterceptor
095: * @see org.springframework.orm.hibernate.support.OpenSessionInViewFilter
096: * @see org.springframework.orm.jdo.support.OpenPersistenceManagerInViewInterceptor
097: * @see org.springframework.orm.jdo.support.OpenPersistenceManagerInViewFilter
098: */
099: public class ServletForwardingController extends AbstractController
100: implements BeanNameAware {
101:
102: private String servletName;
103:
104: private String beanName;
105:
106: /**
107: * Set the name of the servlet to forward to,
108: * i.e. the "servlet-name" of the target servlet in web.xml.
109: * <p>Default is the bean name of this controller.
110: */
111: public void setServletName(String servletName) {
112: this .servletName = servletName;
113: }
114:
115: public void setBeanName(String name) {
116: this .beanName = name;
117: if (this .servletName == null) {
118: this .servletName = name;
119: }
120: }
121:
122: protected ModelAndView handleRequestInternal(
123: HttpServletRequest request, HttpServletResponse response)
124: throws Exception {
125:
126: RequestDispatcher rd = getServletContext().getNamedDispatcher(
127: this .servletName);
128: if (rd == null) {
129: throw new ServletException("No servlet with name '"
130: + this .servletName + "' defined in web.xml");
131: }
132: // If already included, include again, else forward.
133: if (useInclude(request, response)) {
134: rd.include(request, response);
135: if (logger.isDebugEnabled()) {
136: logger.debug("Included servlet [" + this .servletName
137: + "] in ServletForwardingController '"
138: + this .beanName + "'");
139: }
140: } else {
141: rd.forward(request, response);
142: if (logger.isDebugEnabled()) {
143: logger.debug("Forwarded to servlet ["
144: + this .servletName
145: + "] in ServletForwardingController '"
146: + this .beanName + "'");
147: }
148: }
149: return null;
150: }
151:
152: /**
153: * Determine whether to use RequestDispatcher's <code>include</code> or
154: * <code>forward</code> method.
155: * <p>Performs a check whether an include URI attribute is found in the request,
156: * indicating an include request, and whether the response has already been committed.
157: * In both cases, an include will be performed, as a forward is not possible anymore.
158: * @param request current HTTP request
159: * @param response current HTTP response
160: * @return <code>true</code> for include, <code>false</code> for forward
161: * @see javax.servlet.RequestDispatcher#forward
162: * @see javax.servlet.RequestDispatcher#include
163: * @see javax.servlet.ServletResponse#isCommitted
164: * @see org.springframework.web.util.WebUtils#isIncludeRequest
165: */
166: protected boolean useInclude(HttpServletRequest request,
167: HttpServletResponse response) {
168: return (WebUtils.isIncludeRequest(request) || response
169: .isCommitted());
170: }
171:
172: }
|