org.apache.struts.action.Action Maven / Gradle / Ivy
/*
* $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.action;
import java.io.Serializable;
import java.util.Locale;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.apache.struts.Globals;
import org.apache.struts.config.ModuleConfig;
import org.apache.struts.util.MessageResources;
import org.apache.struts.util.ModuleUtils;
import org.apache.struts.util.RequestUtils;
import org.apache.struts.util.TokenProcessor;
/**
* An Action is an adapter between the contents of an
* incoming HTTP request and the corresponding business logic that should be
* executed to process this request. The controller (RequestProcessor) will
* select an appropriate Action for each request, create an instance (if
* necessary), and call the execute
method.
*
* Actions must be programmed in a thread-safe manner, because the
* controller will share the same instance for multiple simultaneous requests.
* This means you should design with the following items in mind:
*
*
*
* - Instance and static variables MUST NOT be used to store information
* related to the state of a particular request. They MAY be used to share
* global resources across requests for the same action.
*
* - Access to other resources (JavaBeans, session variables, etc.) MUST be
* synchronized if those resources require protection. (Generally, however,
* resource classes should be designed to provide their own protection where
* necessary.
*
*
*
* When an Action
instance is first created, the controller
* will call setServlet
with a non-null argument to identify the
* servlet instance to which this Action is attached. When the servlet is to
* be shut down (or restarted), the setServlet
method will be
* called with a null
argument, which can be used to clean up any
* allocated resources in use by this Action.
*
* @version $Rev$ $Date: 2005-08-26 21:58:39 -0400 (Fri, 26 Aug 2005)
* $
*/
public class Action implements Serializable {
private static final long serialVersionUID = 7282855522164012543L;
/**
* An instance of {@code TokenProcessor} to use for token
* functionality.
*/
private static TokenProcessor token = TokenProcessor.getInstance();
/**
* The action execution was a failure. Show an error view, possibly asking
* the user to retry entering data.
*
* @since Struts 1.4
*/
public static final String ERROR = "error";
/**
* The action execution require more input in order to succeed. This
* result is typically used if a form handling action has been executed
* so as to provide defaults for a form. The form associated with the
* handler should be shown to the end user.
*
* This result is also used if the given input params are invalid,
* meaning the user should try providing input again.
*
* @since Struts 1.4
*/
public static final String INPUT = "input";
/**
* The action could not execute, since the user most was not logged in.
* The login view should be shown.
*
* @since Struts 1.4
*/
public static final String LOGIN = "login";
/**
* The action execution was successful. Show result view to the end user.
*
* @since Struts 1.4
*/
public static final String SUCCESS = "success";
// NOTE: We can make the tken variable protected and remove Action's
// token methods or leave it private and allow the token methods to
// delegate their calls.
// ----------------------------------------------------- Instance Variables
/**
*
The servlet to which we are attached.
*/
protected transient ActionServlet servlet = null;
// ------------------------------------------------------------- Properties
/**
* Return the servlet instance to which we are attached.
*
* @return The servlet instance to which we are attached.
*/
public ActionServlet getServlet() {
return (this.servlet);
}
/**
* Set the servlet instance to which we are attached (if
* servlet
is non-null), or release any allocated resources
* (if servlet
is null).
*
* @param servlet The new controller servlet, if any
*/
public void setServlet(ActionServlet servlet) {
this.servlet = servlet;
// :FIXME: Is this suppose to release resources?
}
// --------------------------------------------------------- Public Methods
/**
* Process the specified non-HTTP request, and create the corresponding
* non-HTTP response (or forward to another web component that will create
* it), with provision for handling exceptions thrown by the business
* logic. Return an {@link ActionForward} instance describing where and
* how control should be forwarded, or null
if the response
* has already been completed.
*
* The default implementation attempts to forward to the HTTP version
* of this method.
*
* @param mapping The ActionMapping used to select this instance
* @param form The optional ActionForm bean for this request (if any)
* @param request The non-HTTP request we are processing
* @param response The non-HTTP response we are creating
* @return The forward to which control should be transferred, or
* null
if the response has been completed.
* @throws Exception if the application business logic throws an
* exception.
* @since Struts 1.1
*/
public ActionForward execute(ActionMapping mapping, ActionForm form,
ServletRequest request, ServletResponse response)
throws Exception {
try {
return execute(mapping, form, (HttpServletRequest) request,
(HttpServletResponse) response);
} catch (ClassCastException e) {
return null;
}
}
/**
* 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. Return an {@link ActionForward} instance describing where and
* how control should be forwarded, or null
if the response
* has already been completed.
*
* @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 to which control should be transferred, or
* null
if the response has been completed.
* @throws Exception if the application business logic throws an
* exception
* @since Struts 1.1
*/
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
return null;
}
// ---------------------------------------------------- Protected Methods
/**
* Adds the specified messages keys into the appropriate request attribute
* for use by the <html:messages> tag (if messages="true" is set),
* if any messages are required. Initialize the attribute if it has not
* already been. Otherwise, ensure that the request attribute is not set.
*
* @param request The servlet request we are processing
* @param messages Messages object
* @since Struts 1.2.1
*/
protected void addMessages(HttpServletRequest request,
ActionMessages messages) {
if (messages == null) {
// bad programmer! *slap*
return;
}
// get any existing messages from the request, or make a new one
ActionMessages requestMessages =
(ActionMessages) request.getAttribute(Globals.MESSAGE_KEY);
if (requestMessages == null) {
requestMessages = new ActionMessages();
}
// add incoming messages
requestMessages.add(messages);
// if still empty, just wipe it out from the request
if (requestMessages.isEmpty()) {
request.removeAttribute(Globals.MESSAGE_KEY);
return;
}
// Save the messages
request.setAttribute(Globals.MESSAGE_KEY, requestMessages);
}
/**
* Adds the specified errors keys into the appropriate request attribute
* for use by the <html:errors> tag, if any messages are required.
* Initialize the attribute if it has not already been. Otherwise, ensure
* that the request attribute is not set.
*
* @param request The servlet request we are processing
* @param errors Errors object
* @since Struts 1.2.1
*/
protected void addErrors(HttpServletRequest request, ActionMessages errors) {
if (errors == null) {
// bad programmer! *slap*
return;
}
// get any existing errors from the request, or make a new one
ActionMessages requestErrors =
(ActionMessages) request.getAttribute(Globals.ERROR_KEY);
if (requestErrors == null) {
requestErrors = new ActionMessages();
}
// add incoming errors
requestErrors.add(errors);
// if still empty, just wipe it out from the request
if (requestErrors.isEmpty()) {
request.removeAttribute(Globals.ERROR_KEY);
return;
}
// Save the errors
request.setAttribute(Globals.ERROR_KEY, requestErrors);
}
/**
* Generate a new transaction token, to be used for enforcing a single
* request for a particular transaction.
*
* @param request The request we are processing
* @return The new transaction token.
*/
protected String generateToken(HttpServletRequest request) {
return token.generateToken(request);
}
/**
* Retrieves any existing errors placed in the request by previous
* actions. This method could be called instead of creating a new
* ActionMessages()
at the beginning of an Action
.
* This will prevent saveErrors() from wiping out any existing Errors
*
* @param request The servlet request we are processing
* @return the Errors that already exist in the request, or a new
* ActionMessages object if empty.
* @since Struts 1.2.1
*/
protected ActionMessages getErrors(HttpServletRequest request) {
ActionMessages errors =
(ActionMessages) request.getAttribute(Globals.ERROR_KEY);
if (errors == null) {
errors = new ActionMessages();
}
return errors;
}
/**
* Return the user's currently selected Locale.
*
* @param request The request we are processing
* @return The user's currently selected Locale.
*/
protected Locale getLocale(HttpServletRequest request) {
return RequestUtils.getUserLocale(request, null);
}
/**
* Retrieves any existing messages placed in the request by previous
* actions. This method could be called instead of creating a new
* ActionMessages()
at the beginning of an Action
This
* will prevent saveMessages() from wiping out any existing Messages
*
* @param request The servlet request we are processing
* @return the Messages that already exist in the request, or a new
* ActionMessages object if empty.
* @since Struts 1.2.1
*/
protected ActionMessages getMessages(HttpServletRequest request) {
ActionMessages messages =
(ActionMessages) request.getAttribute(Globals.MESSAGE_KEY);
if (messages == null) {
messages = new ActionMessages();
}
return messages;
}
/**
* Return the default message resources for the current module.
*
* @param request The servlet request we are processing
* @return The default message resources for the current module.
* @since Struts 1.1
*/
protected MessageResources getResources(HttpServletRequest request) {
return ((MessageResources) request.getAttribute(Globals.MESSAGES_KEY));
}
/**
* Return the specified message resources for the current module.
*
* @param request The servlet request we are processing
* @param key The key specified in the message-resources element for
* the requested bundle.
* @return The specified message resource for the current module.
* @since Struts 1.1
*/
protected MessageResources getResources(HttpServletRequest request,
String key) {
// Identify the current module
ServletContext context = getServlet().getServletContext();
ModuleConfig moduleConfig =
ModuleUtils.getInstance().getModuleConfig(request, context);
// Return the requested message resources instance
return (MessageResources) context.getAttribute(key
+ moduleConfig.getPrefix());
}
/**
* Returns true
if the current form's cancel button was
* pressed. This method will check if the Globals.CANCEL_KEY
* request attribute has been set, which normally occurs if the cancel
* button generated by CancelTag was pressed by the user
* in the current request. If true
, validation performed by
* an ActionForm's validate()
method will
* have been skipped by the controller servlet.
*
* Since Action 1.3.0, the mapping for a cancellable Action must also have
* the new "cancellable" property set to true. If "cancellable" is not set, and
* the magic Cancel token is found in the request, the standard Composable
* Request Processor will throw an InvalidCancelException.
*
* @param request The servlet request we are processing
* @return true
if the cancel button was pressed;
* false
otherwise.
*/
protected boolean isCancelled(HttpServletRequest request) {
return (request.getAttribute(Globals.CANCEL_KEY) != null);
}
/**
* Return true
if there is a transaction token stored in
* the user's current session, and the value submitted as a request
* parameter with this action matches it. Returns false
under
* any of the following circumstances:
*
*
*
* - No session associated with this request
*
* - No transaction token saved in the session
*
* - No transaction token included as a request parameter
*
* - The included transaction token value does not match the transaction
* token in the user's session
*
*
*
* @param request The servlet request we are processing
* @return true
if there is a transaction token and it is
* valid; false
otherwise.
*/
protected boolean isTokenValid(HttpServletRequest request) {
return token.isTokenValid(request, false);
}
/**
* Return true
if there is a transaction token stored in
* the user's current session, and the value submitted as a request
* parameter with this action matches it. Returns false
under
* any of the following circumstances:
*
*
*
* - No session associated with this request
- No transaction
* token saved in the session
*
* - No transaction token included as a request parameter
*
* - The included transaction token value does not match the transaction
* token in the user's session
*
*
*
* @param request The servlet request we are processing
* @param reset Should we reset the token after checking it?
* @return true
if there is a transaction token and it is
* valid; false
otherwise.
*/
protected boolean isTokenValid(HttpServletRequest request, boolean reset) {
return token.isTokenValid(request, reset);
}
/**
* Reset the saved transaction token in the user's session. This
* indicates that transactional token checking will not be needed on the
* next request that is submitted.
*
* @param request The servlet request we are processing
*/
protected void resetToken(HttpServletRequest request) {
token.resetToken(request);
}
/**
* Save the specified error messages keys into the appropriate request
* attribute for use by the <html:errors> tag, if any messages are
* required. Otherwise, ensure that the request attribute is not
* created.
*
* @param request The servlet request we are processing
* @param errors Error messages object
* @since Struts 1.2
*/
protected void saveErrors(HttpServletRequest request, ActionMessages errors) {
// Remove any error messages attribute if none are required
if ((errors == null) || errors.isEmpty()) {
request.removeAttribute(Globals.ERROR_KEY);
return;
}
// Save the error messages we need
request.setAttribute(Globals.ERROR_KEY, errors);
}
/**
* Save the specified messages keys into the appropriate request
* attribute for use by the <html:messages> tag (if messages="true"
* is set), if any messages are required. Otherwise, ensure that the
* request attribute is not created.
*
* @param request The servlet request we are processing.
* @param messages The messages to save. null
or empty
* messages removes any existing ActionMessages in the
* request.
* @since Struts 1.1
*/
protected void saveMessages(HttpServletRequest request,
ActionMessages messages) {
// Remove any messages attribute if none are required
if ((messages == null) || messages.isEmpty()) {
request.removeAttribute(Globals.MESSAGE_KEY);
return;
}
// Save the messages we need
request.setAttribute(Globals.MESSAGE_KEY, messages);
}
/**
* Save the specified messages keys into the appropriate session
* attribute for use by the <html:messages> tag (if messages="true"
* is set), if any messages are required. Otherwise, ensure that the
* session attribute is not created.
*
* @param session The session to save the messages in.
* @param messages The messages to save. null
or empty
* messages removes any existing ActionMessages in the
* session.
* @since Struts 1.2
*/
protected void saveMessages(HttpSession session, ActionMessages messages) {
// Remove any messages attribute if none are required
if ((messages == null) || messages.isEmpty()) {
session.removeAttribute(Globals.MESSAGE_KEY);
return;
}
// Save the messages we need
session.setAttribute(Globals.MESSAGE_KEY, messages);
}
/**
* Save the specified error messages keys into the appropriate session
* attribute for use by the <html:messages> tag (if
* messages="false") or <html:errors>, if any error messages are
* required. Otherwise, ensure that the session attribute is empty.
*
* @param session The session to save the error messages in.
* @param errors The error messages to save. null
or empty
* messages removes any existing error ActionMessages in
* the session.
* @since Struts 1.3
*/
protected void saveErrors(HttpSession session, ActionMessages errors) {
// Remove the error attribute if none are required
if ((errors == null) || errors.isEmpty()) {
session.removeAttribute(Globals.ERROR_KEY);
return;
}
// Save the errors we need
session.setAttribute(Globals.ERROR_KEY, errors);
}
/**
* Save a new transaction token in the user's current session, creating
* a new session if necessary.
*
* @param request The servlet request we are processing
*/
protected void saveToken(HttpServletRequest request) {
token.saveToken(request);
}
/**
* Set the user's currently selected Locale
into their
* HttpSession
.
*
* @param request The request we are processing
* @param locale The user's selected Locale to be set, or null to select
* the server's default Locale
*/
protected void setLocale(HttpServletRequest request, Locale locale) {
HttpSession session = request.getSession();
if (locale == null) {
locale = Locale.getDefault();
}
session.setAttribute(Globals.LOCALE_KEY, locale);
}
}