001: /*
002: * Copyright (c) 2002-2006 by OpenSymphony
003: * All rights reserved.
004: */
005: package com.opensymphony.webwork.views.tiles;
006:
007: import com.opensymphony.webwork.ServletActionContext;
008: import com.opensymphony.webwork.dispatcher.ServletDispatcherResult;
009: import com.opensymphony.xwork.ActionInvocation;
010: import com.opensymphony.xwork.LocaleProvider;
011: import org.apache.commons.logging.Log;
012: import org.apache.commons.logging.LogFactory;
013: import org.apache.tiles.*;
014:
015: import javax.servlet.ServletContext;
016: import javax.servlet.ServletException;
017: import javax.servlet.http.HttpServletRequest;
018: import javax.servlet.http.HttpServletResponse;
019: import java.util.Locale;
020:
021: /**
022: * <!-- START SNIPPET: description -->
023: * Renders a view using struts-tiles.
024: * <!-- END SNIPPET: description -->
025: *
026: * <!-- START SNIPPET: webxml -->
027: * In your web.xml file, you need to add a servlet entry for TilesServlet to load the tiles definitions into the ServletContext.
028: *
029: * <servlet>
030: * <servlet-name>tiles</servlet-name>
031: * <servlet-class>org.apache.tiles.servlets.TilesServlet</servlet-class>
032: * <init-param>
033: * <param-name>definitions-config</param-name>
034: * <param-value>/WEB-INF/tiles-config.xml</param-value>
035: * </init-param>
036: * <load-on-startup>1</load-on-startup>
037: * </servlet>
038: * <!-- END SNIPPET: webxml -->
039: *
040: * <!-- START SNIPPET: xworkxml -->
041: * In xwork.xml, use type="tiles" on your <result>.
042: *
043: * <action name="editUser" class="userAction" method="edit">
044: * <result name="success" type="tiles">userForm</result>
045: * <result name="input" type="tiles">userList</result>
046: * </action>
047: * <!-- END SNIPPET: xworkxml -->
048: *
049: *
050: * <!-- START SNIPPET: packageconfig -->
051: *
052: * Making this result type the default for the current package.
053: *
054: * <result-types>
055: * <result-type name="tiles" class="com.opensymphony.webwork.views.tiles.TilesResult" default="true" />
056: * </result-types>
057: * <!-- END SNIPPET: packageconfig -->
058: *
059: * @author Matt Raible
060: * @author Rainer Hermanns
061: * @version $Id: TilesResult.java 2207 2006-02-17 19:06:03Z rainerh $
062: */
063: public class TilesResult extends ServletDispatcherResult {
064:
065: private static final Log log = LogFactory.getLog(TilesResult.class);
066:
067: protected ActionInvocation invocation;
068: private DefinitionsFactory definitionsFactory;
069:
070: /**
071: * Dispatches to the given location. Does its forward via a RequestDispatcher. If the
072: * dispatch fails a 404 error will be sent back in the http response.
073: *
074: * @param location the location to dispatch to.
075: * @param invocation the execution state of the action
076: * @throws Exception if an error occurs. If the dispatch fails the error will go back via the
077: * HTTP request.
078: */
079: public void doExecute(String location, ActionInvocation invocation)
080: throws Exception {
081: this .location = location;
082: this .invocation = invocation;
083:
084: HttpServletRequest request = ServletActionContext.getRequest();
085: HttpServletResponse response = ServletActionContext
086: .getResponse();
087: ServletContext servletContext = ServletActionContext
088: .getServletContext();
089:
090: this .definitionsFactory = (DefinitionsFactory) servletContext
091: .getAttribute(TilesUtilImpl.DEFINITIONS_FACTORY);
092:
093: // get component definition
094: ComponentDefinition definition = getComponentDefinition(
095: this .definitionsFactory, request);
096: if (definition == null) {
097: throw new ServletException(
098: "No Tiles definition found for name '" + location
099: + "'");
100: }
101:
102: // get current component context
103: ComponentContext context = getComponentContext(definition,
104: request);
105: ComponentContext.setContext(context, request);
106:
107: // execute component controller associated with definition, if any
108: Controller controller = getController(definition, request);
109: if (controller != null) {
110: if (log.isDebugEnabled()) {
111: log.debug("Executing Tiles controller [" + controller
112: + "]");
113: }
114: executeController(controller, context, request, response);
115: }
116:
117: // determine the path of the definition
118: String path = getDispatcherPath(definition, request);
119: if (path == null) {
120: throw new ServletException(
121: "Could not determine a path for Tiles definition '"
122: + definition.getName() + "'");
123: }
124:
125: super .doExecute(path, invocation);
126: }
127:
128: protected Locale deduceLocale(HttpServletRequest request) {
129: if (invocation.getAction() instanceof LocaleProvider) {
130: return ((LocaleProvider) invocation.getAction())
131: .getLocale();
132: } else {
133: return request.getLocale();
134: }
135: }
136:
137: /**
138: * Determine the Tiles component definition for the given Tiles
139: * definitions factory.
140: *
141: * @param factory the Tiles definitions factory
142: * @param request current HTTP request
143: * @return the component definition
144: */
145: protected ComponentDefinition getComponentDefinition(
146: DefinitionsFactory factory, HttpServletRequest request)
147: throws Exception {
148: ComponentDefinitions definitions = factory.readDefinitions();
149: return definitions.getDefinition(location,
150: deduceLocale(request));
151: }
152:
153: /**
154: * Determine the Tiles component context for the given Tiles definition.
155: *
156: * @param definition the Tiles definition to render
157: * @param request current HTTP request
158: * @return the component context
159: * @throws Exception if preparations failed
160: */
161: protected ComponentContext getComponentContext(
162: ComponentDefinition definition, HttpServletRequest request)
163: throws Exception {
164: ComponentContext context = ComponentContext.getContext(request);
165: if (context == null) {
166: context = new ComponentContext(definition.getAttributes());
167: ComponentContext.setContext(context, request);
168: } else {
169: context.addMissing(definition.getAttributes());
170: }
171: return context;
172: }
173:
174: /**
175: * Determine and initialize the Tiles component controller for the
176: * given Tiles definition, if any.
177: *
178: * @param definition the Tiles definition to render
179: * @param request current HTTP request
180: * @return the component controller to execute, or <code>null</code> if none
181: * @throws Exception if preparations failed
182: */
183: protected Controller getController(ComponentDefinition definition,
184: HttpServletRequest request) throws Exception {
185: return definition.getOrCreateController();
186: }
187:
188: /**
189: * Execute the given Tiles controller.
190: *
191: * @param controller the component controller to execute
192: * @param context the component context
193: * @param request current HTTP request
194: * @param response current HTTP response
195: * @throws Exception if controller execution failed
196: */
197: protected void executeController(Controller controller,
198: ComponentContext context, HttpServletRequest request,
199: HttpServletResponse response) throws Exception {
200: controller.execute(context, request, response,
201: ServletActionContext.getServletContext());
202: }
203:
204: /**
205: * Determine the dispatcher path for the given Tiles definition,
206: * i.e. the request dispatcher path of the layout page.
207: * @param definition the Tiles definition to render
208: * @param request current HTTP request
209: * @return the path of the layout page to render
210: * @throws Exception if preparations failed
211: */
212: protected String getDispatcherPath(ComponentDefinition definition,
213: HttpServletRequest request) throws Exception {
214: Object pathAttr = null;
215: return (pathAttr != null ? pathAttr.toString() : definition
216: .getPath());
217: }
218: }
|