Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts.tiles2;

import javax.servlet.ServletException;

import org.apache.struts.Globals;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.RequestProcessor;
import org.apache.struts.config.ModuleConfig;

/**
* WebLogic (at least v6 and v7) attempts to serialize the TilesRequestProcessor
* when re-deploying the Webapp in development mode. The TilesRequestProcessor
* is not serializable, and loses the Tiles definitions. This results in
* NullPointerException and/or NotSerializableException when using the app after
* automatic redeploy.
* <p>
* This bug report proposes a workaround for this problem, in the hope it will
* help others and maybe motivate an actual fix.
* </p>
* <p>
* The attached class extends the Struts Action servlet and fixes the problem by
* reloading the Tiles definitions when they have disappeared.
* </p>
* <p>
* For background discussion see
* <a href="https://issues.apache.org/jira/browse/STR-1937">STR-1937</a>.
* </p>
*
* @since 1.2.1
*/
public class RedeployableActionServlet extends ActionServlet {
private static final long serialVersionUID = -3681534284719373420L;

/**
* The request processor for Tiles definitions.
*/
private TilesRequestProcessor tileProcessor;

protected synchronized RequestProcessor getRequestProcessor(
final ModuleConfig config) throws ServletException {

if (tileProcessor != null) {
final TilesRequestProcessor processor =
(TilesRequestProcessor) super.getRequestProcessor(config);
return processor;
}

// reset the request processor
final String requestProcessorKey = Globals.REQUEST_PROCESSOR_KEY
+ config.getPrefix();
getServletContext().removeAttribute(requestProcessorKey);

// create a new request processor instance
final TilesRequestProcessor processor =
(TilesRequestProcessor) super.getRequestProcessor(config);

tileProcessor = processor;

return processor;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.struts.tiles2;

import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
Expand All @@ -43,21 +41,22 @@
import org.slf4j.LoggerFactory;

/**
* <p><strong>RequestProcessor</strong> contains the processing logic that
* the Struts controller servlet performs as it receives each servlet request
* from the container.</p>
* <p>This processor subclasses the Struts RequestProcessor in order to intercept calls to forward
* or include. When such calls are done, the Tiles processor checks if the specified URI
* is a definition name. If true, the definition is retrieved and included. If
* false, the original URI is included or a forward is performed.
* <p>
* Actually, catching is done by overloading the following methods:
* <strong>RequestProcessor</strong> contains the processing logic that the
* Struts controller servlet performs as it receives each servlet request from
* the container.
* <p>This processor subclasses the Struts RequestProcessor in order to
* intercept calls to forward or include. When such calls are done, the Tiles
* processor checks if the specified URI is a definition name. If {@code true},
* the definition is retrieved and included. If {@code false}, the original URI
* is included or a forward is performed.</p>
* <p>Actually, catching is done by overloading the following methods:
* <ul>
* <li>{@link #processForwardConfig(HttpServletRequest,HttpServletResponse,ForwardConfig)}</li>
* <li>{@link #internalModuleRelativeForward(String, HttpServletRequest , HttpServletResponse)}</li>
* <li>{@link #internalModuleRelativeInclude(String, HttpServletRequest , HttpServletResponse)}</li>
* </ul>
* </p>
*
* @since Struts 1.1
*/
public class TilesRequestProcessor extends RequestProcessor {
Expand All @@ -69,16 +68,12 @@ public class TilesRequestProcessor extends RequestProcessor {
private transient final Logger log =
LoggerFactory.getLogger(TilesRequestProcessor.class);

/**
* The used servlet context.
*/
protected ServletContext servletContext;

/**
* Initialize this request processor instance.
*
* @param servlet The ActionServlet we are associated with.
* @param servlet The ActionServlet we are associated with.
* @param moduleConfig The ModuleConfig we are associated with.
*
* @throws ServletException If an error occurs during initialization.
*/
public void init(ActionServlet servlet, ModuleConfig moduleConfig)
Expand All @@ -88,21 +83,22 @@ public void init(ActionServlet servlet, ModuleConfig moduleConfig)
}

/**
* Process a Tile definition name.
* This method tries to process the parameter <code>definitionName</code>
* as a definition name.
* It returns <code>true</code> if a definition has been processed, or
* <code>false</code> otherwise.
* Process a Tile definition name. This method tries to process the
* parameter {@code definitionName} as a definition name. It returns
* {@code true} if a definition has been processed, or {@code false}
* otherwise.
*
* @param definitionName Definition name to insert.
* @param req Current page request.
* @param res Current page response.
* @throws IOException If something goes wrong during writing the
* definition.
* @param req Current page request.
* @param res Current page response.
*
* @return {@code true} if the method has processed uri as a definition
* name, [@code false} otherwise.
*
* @throws IOException If something goes wrong during writing the
* definition.
* @throws ServletException If something goes wrong during the evaluation
* of the definition
* @return <code>true</code> if the method has processed uri as a
* definition name, <code>false</code> otherwise.
* of the definition
*/
protected boolean processTilesDefinition(
String definitionName,
Expand Down Expand Up @@ -139,16 +135,17 @@ protected boolean processTilesDefinition(
}

/**
* Do a forward using request dispatcher.
* Uri is a valid uri. If response has already been commited, do an include
* instead.
* @param uri Uri or Definition name to forward.
* @param request Current page request.
* Do a forward using request dispatcher. Uri is a valid uri. If response
* has already been commited, do an include instead.
*
* @param uri Uri or Definition name to forward.
* @param request Current page request.
* @param response Current page response.
* @throws IOException If something goes wrong during writing the
* definition.
*
* @throws IOException If something goes wrong during writing the
* definition.
* @throws ServletException If something goes wrong during the evaluation
* of the definition
* of the definition
*/
protected void doForward(
String uri,
Expand All @@ -165,18 +162,19 @@ protected void doForward(
}

/**
* Overloaded method from Struts' RequestProcessor.
* Forward or redirect to the specified destination by the specified
* mechanism.
* This method catches the Struts' actionForward call. It checks if the
* Overloaded method from Struts' RequestProcessor. Forward or redirect to
* the specified destination by the specified mechanism.
* <p>This method catches the Struts' actionForward call. It checks if the
* actionForward is done on a Tiles definition name. If true, process the
* definition and insert it. If false, call the original parent's method.
* @param request The servlet request we are processing.
* definition and insert it. If false, call the original parent's
* method.</p>
*
* @param request The servlet request we are processing.
* @param response The servlet response we are creating.
* @param forward The ActionForward controlling where we go next.
* @param forward The ActionForward controlling where we go next.
*
* @exception IOException if an input/output error occurs.
* @exception ServletException if a servlet exception occurs.
* @throws IOException if an input/output error occurs.
* @throws ServletException if a servlet exception occurs.
*/
protected void processForwardConfig(
HttpServletRequest request,
Expand Down Expand Up @@ -205,21 +203,23 @@ protected void processForwardConfig(
}

/**
* Catch the call to a module relative forward.
* If the specified uri is a tiles definition name, insert it.
* Otherwise, parent processing is called.
* Do a module relative forward to specified uri using request dispatcher.
* Uri is relative to the current module. The real uri is computed by
* prefixing the module name.
* <strong>This method is used internally and is not part of the public
* API. It is advised to not use it in subclasses.</strong>
* @param uri Module-relative URI to forward to.
* @param request Current page request.
* Catch the call to a module relative forward. If the specified uri is a
* tiles definition name, insert it. Otherwise, parent processing is
* called. Do a module relative forward to specified uri using request
* dispatcher. Uri is relative to the current module. The real uri is
* computed by prefixing the module name.
* <p><strong>This method is used internally and is not part of the public
* API. It is advised to not use it in subclasses.</strong></p>
*
* @param uri Module-relative URI to forward to.
* @param request Current page request.
* @param response Current page response.
* @throws IOException If something goes wrong during writing the
* definition.
*
* @throws IOException If something goes wrong during writing the
* definition.
* @throws ServletException If something goes wrong during the evaluation
* of the definition
* of the definition
*
* @since Struts 1.1
*/
protected void internalModuleRelativeForward(
Expand All @@ -239,15 +239,18 @@ protected void internalModuleRelativeForward(
* Do a module relative include to specified uri using request dispatcher.
* Uri is relative to the current module. The real uri is computed by
* prefixing the module name.
* <strong>This method is used internally and is not part of the public
* API. It is advised to not use it in subclasses.</strong>
* @param uri Module-relative URI to forward to.
* @param request Current page request.
* <p><strong>This method is used internally and is not part of the public
* API. It is advised to not use it in subclasses.</strong></p>
*
* @param uri Module-relative URI to forward to.
* @param request Current page request.
* @param response Current page response.
* @throws IOException If something goes wrong during writing the
* definition.
*
* @throws IOException If something goes wrong during writing the
* definition.
* @throws ServletException If something goes wrong during the evaluation
* of the definition
* of the definition
*
* @since Struts 1.1
*/
protected void internalModuleRelativeInclude(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.struts.tiles2.actions;

import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

/**
* This standard <strong>Action</strong> is for compatibility with
* {@code struts-tiles}. The configuration is now reloaded automatically.
*/
public class ReloadDefinitionsAction extends Action {
private static final long serialVersionUID = -7402180335252956248L;

/**
* Process the specified HTTP request, and create the corresponding HTTP
* response (or forward to another web component that will create it), with
* provision for handling exceptions thrown by the business logic.
*
* @param mapping The ActionMapping used to select this instance
* @param form The optional ActionForm bean for this request (if any)
* @param request The HTTP request we are processing
* @param response The HTTP response we are creating
*
* @return The forward object.
*
* @throws Exception if the application business logic throws an exception
*
* @since Struts 1.1
*/
public ActionForward execute(final ActionMapping mapping,
final ActionForm form, final HttpServletRequest request,
final HttpServletResponse response) throws Exception {

response.setContentType("text/plain");

final PrintWriter writer = response.getWriter();

writer.println("OK");

writer.flush();
writer.close();

return null;
}
}