001: /* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
002: * This code is licensed under the GPL 2.0 license, availible at the root
003: * application directory.
004: */
005: package org.vfny.geoserver.config.web.tiles;
006:
007: import org.apache.struts.action.ActionMapping;
008: import org.apache.struts.config.ForwardConfig;
009: import org.apache.struts.tiles.ComponentContext;
010: import org.apache.struts.tiles.ComponentDefinition;
011: import org.apache.struts.tiles.Controller;
012: import org.apache.struts.tiles.DefinitionsFactoryException;
013: import org.apache.struts.tiles.DefinitionsUtil;
014: import org.apache.struts.tiles.NoSuchDefinitionException;
015: import org.apache.struts.upload.MultipartRequestWrapper;
016: import org.springframework.web.context.support.WebApplicationContextUtils;
017: import org.springframework.web.struts.DelegatingActionProxy;
018: import org.springframework.web.struts.DelegatingActionUtils;
019: import org.springframework.web.struts.DelegatingRequestProcessor;
020: import org.springframework.web.struts.DelegatingTilesRequestProcessor;
021: import java.io.IOException;
022: import java.net.URI;
023: import java.net.URISyntaxException;
024: import java.net.URL;
025: import javax.servlet.RequestDispatcher;
026: import javax.servlet.ServletException;
027: import javax.servlet.http.HttpServletRequest;
028: import javax.servlet.http.HttpServletResponse;
029:
030: /**
031: * Subclass of Struts' TilesRequestProcessor that looks up Spring-managed
032: * Struts 1.1 Actions defined in ContextLoaderPlugIn's WebApplicationContext.
033: *
034: * <p>Behaves like
035: * {@link DelegatingRequestProcessor DelegatingRequestProcessor},
036: * but also provides the Tiles functionality of the original TilesRequestProcessor.
037: * As there's just a single central class to customize in Struts, we have to provide
038: * another subclass here, covering both the Tiles and the Spring delegation aspect.
039: *
040: * <p>The default implementation delegates to the DelegatingActionUtils
041: * class as fas as possible, to reuse as much code as possible despite
042: * the need to provide two RequestProcessor subclasses. If you need to
043: * subclass yet another RequestProcessor, take this class as a template,
044: * delegating to DelegatingActionUtils just like it.
045: *
046: * @author Juergen Hoeller
047: * @since 1.0.2
048: * @see DelegatingRequestProcessor
049: * @see DelegatingActionProxy
050: * @see DelegatingActionUtils
051: */
052: public class MultipleDelegatingTilesRequestProcessor extends
053: DelegatingTilesRequestProcessor {
054: /**
055: * Overloaded method from Struts' RequestProcessor.
056: * Forward or redirect to the specified destination by the specified
057: * mechanism.
058: * This method catches the Struts' actionForward call. It checks if the
059: * actionForward is done on a Tiles definition name. If true, process the
060: * definition and insert it. If false, call the original parent's method.
061: * @param request The servlet request we are processing.
062: * @param response The servlet response we are creating.
063: * @param forward The ActionForward controlling where we go next.
064: *
065: * @exception IOException if an input/output error occurs.
066: * @exception ServletException if a servlet exception occurs.
067: */
068: protected void processForwardConfig(HttpServletRequest request,
069: HttpServletResponse response, ForwardConfig forward)
070: throws IOException, ServletException {
071: // Required by struts contract
072: if (forward == null) {
073: return;
074: }
075:
076: if (log.isDebugEnabled()) {
077: log.debug("processForwardConfig(" + forward.getPath()
078: + ", " + forward.getContextRelative() + ")");
079: }
080:
081: // Try to process the definition.
082: if (processTilesDefinition(forward.getPath(), /*forward.getContextRelative()*/
083: false, request, response)) {
084: if (log.isDebugEnabled()) {
085: log.debug(" '" + forward.getPath()
086: + "' - processed as definition");
087: }
088:
089: return;
090: }
091:
092: if (log.isDebugEnabled()) {
093: log.debug(" '" + forward.getPath()
094: + "' - processed as uri");
095: }
096:
097: // forward doesn't contain a definition, let parent do processing
098: super .processForwardConfig(request, response, forward);
099: }
100:
101: /**
102: * Process a Tile definition name.
103: * This method tries to process the parameter <code>definitionName</code> as a definition name.
104: * It returns <code>true</code> if a definition has been processed, or <code>false</code> otherwise.
105: * Parameter <code>contextRelative</code> is not used in this implementation.
106: *
107: * @param definitionName Definition name to insert.
108: * @param contextRelative Is the definition marked contextRelative ?
109: * @param request Current page request.
110: * @param response Current page response.
111: * @return <code>true</code> if the method has processed uri as a definition name, <code>false</code> otherwise.
112: */
113: protected boolean processTilesDefinition(String definitionName,
114: boolean contextRelative, HttpServletRequest request,
115: HttpServletResponse response) throws IOException,
116: ServletException {
117: // Do we do a forward (original behavior) or an include ?
118: boolean doInclude = false;
119:
120: // Controller associated to a definition, if any
121: Controller controller = null;
122:
123: // Computed uri to include
124: String uri = null;
125:
126: ComponentContext tileContext = null;
127:
128: try {
129: // Get current tile context if any.
130: // If context exist, we will do an include
131: tileContext = ComponentContext.getContext(request);
132: doInclude = (tileContext != null);
133:
134: ComponentDefinition definition = null;
135:
136: // Process tiles definition names only if a definition factory exist,
137: // and definition is found.
138: if (definitionsFactory != null) {
139: // Get definition of tiles/component corresponding to uri.
140: try {
141: definition = definitionsFactory.getDefinition(
142: definitionName, request,
143: getServletContext());
144: } catch (NoSuchDefinitionException ex) {
145: // Ignore not found
146: log.debug("NoSuchDefinitionException "
147: + ex.getMessage());
148: }
149:
150: if (definition != null) { // We have a definition.
151: // We use it to complete missing attribute in context.
152: // We also get uri, controller.
153: uri = definition.getPath();
154: controller = definition.getOrCreateController();
155:
156: if (tileContext == null) {
157: tileContext = new ComponentContext(definition
158: .getAttributes());
159: ComponentContext.setContext(tileContext,
160: request);
161: } else {
162: tileContext.addMissing(definition
163: .getAttributes());
164: }
165: }
166: }
167:
168: // Process definition set in Action, if any.
169: definition = DefinitionsUtil.getActionDefinition(request);
170:
171: if (definition != null) { // We have a definition.
172: // We use it to complete missing attribute in context.
173: // We also overload uri and controller if set in definition.
174:
175: if (definition.getPath() != null) {
176: uri = definition.getPath();
177: }
178:
179: if (definition.getOrCreateController() != null) {
180: controller = definition.getOrCreateController();
181: }
182:
183: if (tileContext == null) {
184: tileContext = new ComponentContext(definition
185: .getAttributes());
186: ComponentContext.setContext(tileContext, request);
187: } else {
188: tileContext.addMissing(definition.getAttributes());
189: }
190: }
191: } catch (java.lang.InstantiationException ex) {
192: log.error("Can't create associated controller", ex);
193:
194: throw new ServletException(
195: "Can't create associated controller", ex);
196: } catch (DefinitionsFactoryException ex) {
197: throw new ServletException(ex);
198: }
199:
200: // Have we found a definition ?
201: if (uri == null) {
202: return false;
203: }
204:
205: // Execute controller associated to definition, if any.
206: if (controller != null) {
207: try {
208: controller.execute(tileContext, request, response,
209: getServletContext());
210: } catch (Exception e) {
211: throw new ServletException(e);
212: }
213: }
214:
215: // If request comes from a previous Tile, do an include.
216: // This allows to insert an action in a Tile.
217: if (log.isDebugEnabled()) {
218: log.debug("uri=" + uri + " doInclude=" + doInclude);
219: }
220:
221: if (doInclude) {
222: doInclude(uri, request, response);
223: } else {
224: doForward(uri, request, response); // original behavior
225: }
226:
227: return true;
228: }
229:
230: /**
231: * <p>Process a forward requested by this mapping (if any). Return
232: * <code>true</code> if standard processing should continue, or
233: * <code>false</code> if we have already handled this request.</p>
234: *
235: * @param request The servlet request we are processing
236: * @param response The servlet response we are creating
237: * @param mapping The ActionMapping we are using
238: */
239: protected boolean processForward(HttpServletRequest request,
240: HttpServletResponse response, ActionMapping mapping)
241: throws IOException, ServletException {
242: // Are we going to processing this request?
243: String forward = mapping.getForward();
244:
245: if (forward == null) {
246: return (true);
247: }
248:
249: internalModuleRelativeForward(forward, request, response);
250:
251: return (false);
252: }
253:
254: /**
255: * <p>Process an include requested by this mapping (if any). Return
256: * <code>true</code> if standard processing should continue, or
257: * <code>false</code> if we have already handled this request.</p>
258: *
259: * @param request The servlet request we are processing
260: * @param response The servlet response we are creating
261: * @param mapping The ActionMapping we are using
262: */
263: protected boolean processInclude(HttpServletRequest request,
264: HttpServletResponse response, ActionMapping mapping)
265: throws IOException, ServletException {
266: // Are we going to processing this request?
267: String include = mapping.getInclude();
268:
269: if (include == null) {
270: return (true);
271: }
272:
273: internalModuleRelativeInclude(include, request, response);
274:
275: return (false);
276: }
277:
278: /**
279: * <p>Do a module relative forward to specified URI using request dispatcher.
280: * URI is relative to the current module. The real URI is compute by prefixing
281: * the module name.</p>
282: * <p>This method is used internally and is not part of the public API. It is
283: * advised to not use it in subclasses. </p>
284: *
285: * @param uri Module-relative URI to forward to
286: * @param request Current page request
287: * @param response Current page response
288: *
289: * @since Struts 1.1
290: */
291: protected void internalModuleRelativeForward(String uri,
292: HttpServletRequest request, HttpServletResponse response)
293: throws IOException, ServletException {
294: // Construct a request dispatcher for the specified path
295: uri = moduleConfig.getPrefix() + uri;
296:
297: // Delegate the processing of this request
298: // :FIXME: - exception handling?
299: if (log.isDebugEnabled()) {
300: log.debug(" Delegating via forward to '" + uri + "'");
301: }
302:
303: doForward(uri, request, response);
304: }
305:
306: /**
307: * <p>Do a module relative include to specified URI using request dispatcher.
308: * URI is relative to the current module. The real URI is compute by prefixing
309: * the module name.</p>
310: * <p>This method is used internally and is not part of the public API. It is
311: * advised to not use it in subclasses.</p>
312: *
313: * @param uri Module-relative URI to include
314: * @param request Current page request
315: * @param response Current page response
316: *
317: * @since Struts 1.1
318: */
319: protected void internalModuleRelativeInclude(String uri,
320: HttpServletRequest request, HttpServletResponse response)
321: throws IOException, ServletException {
322: // Construct a request dispatcher for the specified path
323: uri = moduleConfig.getPrefix() + uri;
324:
325: // Delegate the processing of this request
326: // FIXME - exception handling?
327: if (log.isDebugEnabled()) {
328: log.debug(" Delegating via include to '" + uri + "'");
329: }
330:
331: doInclude(uri, request, response);
332: }
333:
334: /**
335: * <p>Do a forward to specified URI using a <code>RequestDispatcher</code>.
336: * This method is used by all internal method needing to do a forward.</p>
337: *
338: * @param uri Context-relative URI to forward to
339: * @param request Current page request
340: * @param response Current page response
341: * @since Struts 1.1
342: */
343: protected void doForward(String uri, HttpServletRequest request,
344: HttpServletResponse response) throws IOException,
345: ServletException {
346: // Unwrap the multipart request, if there is one.
347: if (request instanceof MultipartRequestWrapper) {
348: request = ((MultipartRequestWrapper) request).getRequest();
349: }
350:
351: RequestDispatcher rd = getServletContext()
352: .getRequestDispatcher(uri);
353:
354: if (rd == null) {
355: URL resource = WebApplicationContextUtils
356: .getWebApplicationContext(getServletContext())
357: .getResource(uri).getURL();
358: response.sendRedirect(resource.toString());
359: response.sendError(
360: HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
361: getInternal().getMessage("requestDispatcher", uri));
362:
363: return;
364: }
365:
366: rd.forward(request, response);
367: }
368:
369: /**
370: * <p>Do an include of specified URI using a <code>RequestDispatcher</code>.
371: * This method is used by all internal method needing to do an include.</p>
372: *
373: * @param uri Context-relative URI to include
374: * @param request Current page request
375: * @param response Current page response
376: * @since Struts 1.1
377: */
378: protected void doInclude(String uri, HttpServletRequest request,
379: HttpServletResponse response) throws IOException,
380: ServletException {
381: // Unwrap the multipart request, if there is one.
382: if (request instanceof MultipartRequestWrapper) {
383: request = ((MultipartRequestWrapper) request).getRequest();
384: }
385:
386: RequestDispatcher rd = getServletContext()
387: .getRequestDispatcher(uri);
388:
389: if (rd == null) {
390: response.sendError(
391: HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
392: getInternal().getMessage("requestDispatcher", uri));
393:
394: return;
395: }
396:
397: rd.include(request, response);
398: }
399: }
|