1 /* 2 * $Id$ 3 * 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 */ 21 22 package org.apache.struts.tiles2; 23 24 import java.io.IOException; 25 26 import org.apache.struts.action.ActionServlet; 27 import org.apache.struts.action.RequestProcessor; 28 import org.apache.struts.config.ForwardConfig; 29 import org.apache.struts.config.ModuleConfig; 30 import org.apache.tiles.TilesContainer; 31 import org.apache.tiles.TilesException; 32 import org.apache.tiles.access.TilesAccess; 33 import org.apache.tiles.request.ApplicationContext; 34 import org.apache.tiles.request.Request; 35 import org.apache.tiles.request.jakarta.servlet.ServletRequest; 36 import org.apache.tiles.request.jakarta.servlet.ServletUtil; 37 import org.slf4j.Logger; 38 import org.slf4j.LoggerFactory; 39 40 import jakarta.servlet.ServletContext; 41 import jakarta.servlet.ServletException; 42 import jakarta.servlet.http.HttpServletRequest; 43 import jakarta.servlet.http.HttpServletResponse; 44 45 /** 46 * <p><strong>RequestProcessor</strong> contains the processing logic that 47 * the Struts controller servlet performs as it receives each servlet request 48 * from the container.</p> 49 * <p>This processor subclasses the Struts RequestProcessor in order to intercept calls to forward 50 * or include. When such calls are done, the Tiles processor checks if the specified URI 51 * is a definition name. If true, the definition is retrieved and included. If 52 * false, the original URI is included or a forward is performed. 53 * <p> 54 * Actually, catching is done by overloading the following methods: 55 * <ul> 56 * <li>{@link #processForwardConfig(HttpServletRequest,HttpServletResponse,ForwardConfig)}</li> 57 * <li>{@link #internalModuleRelativeForward(String, HttpServletRequest , HttpServletResponse)}</li> 58 * <li>{@link #internalModuleRelativeInclude(String, HttpServletRequest , HttpServletResponse)}</li> 59 * </ul> 60 * </p> 61 * @since Struts 1.1 62 */ 63 public class TilesRequestProcessor extends RequestProcessor { 64 private static final long serialVersionUID = 6212184689866961850L; 65 66 /** 67 * The {@code Log} instance for this class. 68 */ 69 private transient final Logger log = 70 LoggerFactory.getLogger(TilesRequestProcessor.class); 71 72 /** 73 * The used servlet context. 74 */ 75 protected ServletContext servletContext; 76 77 /** 78 * Initialize this request processor instance. 79 * 80 * @param servlet The ActionServlet we are associated with. 81 * @param moduleConfig The ModuleConfig we are associated with. 82 * @throws ServletException If an error occurs during initialization. 83 */ 84 public void init(ActionServlet servlet, ModuleConfig moduleConfig) 85 throws ServletException { 86 87 super.init(servlet, moduleConfig); 88 } 89 90 /** 91 * Process a Tile definition name. 92 * This method tries to process the parameter <code>definitionName</code> 93 * as a definition name. 94 * It returns <code>true</code> if a definition has been processed, or 95 * <code>false</code> otherwise. 96 * 97 * @param definitionName Definition name to insert. 98 * @param req Current page request. 99 * @param res Current page response. 100 * @throws IOException If something goes wrong during writing the 101 * definition. 102 * @throws ServletException If something goes wrong during the evaluation 103 * of the definition 104 * @return <code>true</code> if the method has processed uri as a 105 * definition name, <code>false</code> otherwise. 106 */ 107 protected boolean processTilesDefinition( 108 String definitionName, 109 HttpServletRequest req, 110 HttpServletResponse res) 111 throws IOException, ServletException { 112 113 ApplicationContext applicationContext = ServletUtil 114 .getApplicationContext(getServletContext()); 115 Request request = new ServletRequest(applicationContext, 116 req, res); 117 TilesContainer container = TilesAccess.getContainer(applicationContext); 118 if (container == null) { 119 log.debug("Tiles container not found, so pass to next command."); 120 return false; 121 } 122 123 boolean retValue = false; 124 125 if (container.isValidDefinition(definitionName, request)) { 126 retValue = true; 127 try { 128 container.render(definitionName, request); 129 } catch (TilesException e) { 130 throw new ServletException("Cannot render definition '" 131 + definitionName + "'"); 132 } 133 } else { 134 // ignore not found 135 log.debug("Cannot find definition '{}'", definitionName); 136 } 137 138 return retValue; 139 } 140 141 /** 142 * Do a forward using request dispatcher. 143 * Uri is a valid uri. If response has already been commited, do an include 144 * instead. 145 * @param uri Uri or Definition name to forward. 146 * @param request Current page request. 147 * @param response Current page response. 148 * @throws IOException If something goes wrong during writing the 149 * definition. 150 * @throws ServletException If something goes wrong during the evaluation 151 * of the definition 152 */ 153 protected void doForward( 154 String uri, 155 HttpServletRequest request, 156 HttpServletResponse response) 157 throws IOException, ServletException { 158 159 if (response.isCommitted()) { 160 this.doInclude(uri, request, response); 161 162 } else { 163 super.doForward(uri, request, response); 164 } 165 } 166 167 /** 168 * Overloaded method from Struts' RequestProcessor. 169 * Forward or redirect to the specified destination by the specified 170 * mechanism. 171 * This method catches the Struts' actionForward call. It checks if the 172 * actionForward is done on a Tiles definition name. If true, process the 173 * definition and insert it. If false, call the original parent's method. 174 * @param request The servlet request we are processing. 175 * @param response The servlet response we are creating. 176 * @param forward The ActionForward controlling where we go next. 177 * 178 * @exception IOException if an input/output error occurs. 179 * @exception ServletException if a servlet exception occurs. 180 */ 181 protected void processForwardConfig( 182 HttpServletRequest request, 183 HttpServletResponse response, 184 ForwardConfig forward) 185 throws IOException, ServletException { 186 187 // Required by struts contract 188 if (forward == null) { 189 return; 190 } 191 192 log.debug("processForwardConfig({})", forward.getPath()); 193 194 // Try to process the definition. 195 if (processTilesDefinition(forward.getPath(), 196 request, response)) { 197 log.debug(" '{}' - processed as definition", forward.getPath()); 198 return; 199 } 200 201 log.debug(" '{}' - processed as uri", forward.getPath()); 202 203 // forward doesn't contain a definition, let parent do processing 204 super.processForwardConfig(request, response, forward); 205 } 206 207 /** 208 * Catch the call to a module relative forward. 209 * If the specified uri is a tiles definition name, insert it. 210 * Otherwise, parent processing is called. 211 * Do a module relative forward to specified uri using request dispatcher. 212 * Uri is relative to the current module. The real uri is computed by 213 * prefixing the module name. 214 * <strong>This method is used internally and is not part of the public 215 * API. It is advised to not use it in subclasses.</strong> 216 * @param uri Module-relative URI to forward to. 217 * @param request Current page request. 218 * @param response Current page response. 219 * @throws IOException If something goes wrong during writing the 220 * definition. 221 * @throws ServletException If something goes wrong during the evaluation 222 * of the definition 223 * @since Struts 1.1 224 */ 225 protected void internalModuleRelativeForward( 226 String uri, 227 HttpServletRequest request, 228 HttpServletResponse response) 229 throws IOException, ServletException { 230 231 if (processTilesDefinition(uri, request, response)) { 232 return; 233 } 234 235 super.internalModuleRelativeForward(uri, request, response); 236 } 237 238 /** 239 * Do a module relative include to specified uri using request dispatcher. 240 * Uri is relative to the current module. The real uri is computed by 241 * prefixing the module name. 242 * <strong>This method is used internally and is not part of the public 243 * API. It is advised to not use it in subclasses.</strong> 244 * @param uri Module-relative URI to forward to. 245 * @param request Current page request. 246 * @param response Current page response. 247 * @throws IOException If something goes wrong during writing the 248 * definition. 249 * @throws ServletException If something goes wrong during the evaluation 250 * of the definition 251 * @since Struts 1.1 252 */ 253 protected void internalModuleRelativeInclude( 254 String uri, 255 HttpServletRequest request, 256 HttpServletResponse response) 257 throws IOException, ServletException { 258 259 if (processTilesDefinition(uri, request, response)) { 260 return; 261 } 262 263 super.internalModuleRelativeInclude(uri, request, response); 264 } 265 }