All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sourceforge.stripes.action.ActionBeanContext Maven / Gradle / Ivy

/* Copyright 2005-2006 Tim Fennell
 *
 * Licensed 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 net.sourceforge.stripes.action;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

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

import net.sourceforge.stripes.controller.FlashScope;
import net.sourceforge.stripes.controller.StripesConstants;
import net.sourceforge.stripes.controller.StripesFilter;
import net.sourceforge.stripes.tag.ErrorsTag;
import net.sourceforge.stripes.util.CryptoUtil;
import net.sourceforge.stripes.util.Log;
import net.sourceforge.stripes.validation.ValidationError;
import net.sourceforge.stripes.validation.ValidationErrors;

/**
 * 

Encapsulates information about the current request. Also provides access to the underlying * Servlet API should you need to use it for any reason.

* *

Developers should generally consider subclassing ActionBeanContext to provide a facade * to contextual state for their application. Type safe getters and setter can be added to * the subclass and used by the application, thus hiding where the information is actually * stored. This approach is documented in more detail in the Stripes documentation on * State Management.

* * @author Tim Fennell */ public class ActionBeanContext { private HttpServletRequest request; private HttpServletResponse response; private ServletContext servletContext; private String eventName; private ValidationErrors validationErrors; /** * Retrieves the HttpServletRequest object that is associated with the current request. * @return HttpServletRequest the current request */ public HttpServletRequest getRequest() { return request; } /** * Used by the DispatcherServlet to set the HttpServletRequest for the current request * @param request the current request */ public void setRequest(HttpServletRequest request) { this.request = request; } /** * Retrieves the HttpServletResponse that is associated with the current request. * @return HttpServletResponse the current response */ public HttpServletResponse getResponse() { return response; } /** * Used by the DispatcherServlet to set the HttpServletResponse that is associated with * the current request. * @param response the current response */ public void setResponse(HttpServletResponse response) { this.response = response; } /** * Retrieves the ServletContext object that is associated with the context in which the * current request is being processed. * @return ServletContext the current ServletContext */ public ServletContext getServletContext() { return servletContext; } /** * Sets the ServletContext object that is associated with the context in which the * current request is being processed. * @param servletContext the current ServletContext */ public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } /** * Supplies the name of the event being handled. While a specific method is usually invoked on * an ActionBean, through the use of default handlers ambiguity can arise. This allows * ActionBeans to definitively know the name of the event that was fired. * * @return String the name of the event being handled */ public String getEventName() { return eventName; } /** * Used by the DispatcherServlet to set the name of the even being handled. * @param eventName the name of the event being handled */ public void setEventName(String eventName) { this.eventName = eventName; } /** * Returns the set of validation errors associated with the current form. Lazily * initialized the set of errors, and will never return null. * * @return a Collection of validation errors */ public ValidationErrors getValidationErrors() { if (this.validationErrors == null) { this.validationErrors = new ValidationErrors(); } return validationErrors; } /** * Replaces the current set of validation errors. * @param validationErrors a collect of validation errors */ public void setValidationErrors(ValidationErrors validationErrors) { this.validationErrors = validationErrors; } /** *

Returns the default set of non-error messages associated with the current request. * Guaranteed to always return a List, though the list may be empty. It is envisaged that * messages will normally be added to the request as follows:

* *
     *getContext().getMessages().add( ... );
     *
* *

To remove messages from the current request fetch the list of messages and invoke * remove() or clear(). Messages will be made available to JSPs during the current * request and in the subsequent request if a redirect is issued.

* * @return a List of Message objects associated with the current request, never null. * @see ActionBeanContext#getMessages(String) */ public List getMessages() { return getMessages(StripesConstants.REQ_ATTR_MESSAGES); } /** *

Returns the set of non-error messages associated with the current request under the * specified key. Can be used to manage multiple lists of messages, for different purposes. * Guaranteed to always return a List, though the list may be empty. It is envisaged that * messages will normally be added to the request as follows:

* *
     *getContext().getMessages(key).add( ... );
     *
* *

To remove messages from the current request fetch the list of messages and invoke * remove() or clear().

* *

Messages are stored in a {@link net.sourceforge.stripes.controller.FlashScope} for * the current request. This means that they are available in request scope using the * supplied key during both this request, and the subsequent request if it is the result * of a redirect.

* * @return a List of Message objects associated with the current request, never null. */ @SuppressWarnings("unchecked") public List getMessages(String key) { FlashScope scope = FlashScope.getCurrent(getRequest(), true); List messages = (List) scope.get(key); if (messages == null) { messages = new ArrayList(); scope.put(key, messages); } return messages; } /** * Gets the Locale that is being used to service the current request. This is *not* the value * that was submitted in the request, but the value picked by the configured LocalePicker * which takes into consideration the locales preferred in the request. * * @return Locale the locale being used for the current request * @see net.sourceforge.stripes.localization.LocalePicker */ public Locale getLocale() { return this.request.getLocale(); } /** *

Returns a resolution that can be used to return the user to the page from which they * submitted they current request. Most useful in situations where a user-correctable error * has occurred that was too difficult or expensive to check at validation time. In that case * an ActionBean can call setValidationErrors() and then return the resolution provided by * this method.

* * @return Resolution a resolution that will forward the user to the page they came from * @throws IllegalStateException if the information required to construct a source page * resolution cannot be found in the request. * @see #getSourcePage() */ public Resolution getSourcePageResolution() { String sourcePage = getSourcePage(); if (sourcePage == null) { return new ValidationErrorReportResolution(getValidationErrors()); } else { return new ForwardResolution(sourcePage); } } /** *

* Returns the context-relative path to the page from which the user submitted they current * request. *

* * @return Resolution a resolution that will forward the user to the page they came from * @throws IllegalStateException if the information required to construct a source page * resolution cannot be found in the request. * @see #getSourcePageResolution() */ public String getSourcePage() { String sourcePage = request.getParameter(StripesConstants.URL_KEY_SOURCE_PAGE); if (sourcePage != null) { sourcePage = CryptoUtil.decrypt(sourcePage); } return sourcePage; } /** * Returns a String with the name of the event for which the instance holds context, and * the set of validation errors, if any. */ @Override public String toString() { return getClass().getName() + "{" + "eventName='" + eventName + "'" + ", validationErrors=" + validationErrors + "}"; } } class ValidationErrorReportResolution implements Resolution { private static final Log log = Log.getInstance(ValidationErrorReportResolution.class); private ValidationErrors errors; protected ValidationErrorReportResolution(ValidationErrors errors) { this.errors = errors; } public void execute(HttpServletRequest request, HttpServletResponse response) throws Exception { // log an exception for the stack trace Exception exception = new IllegalStateException( "Here's how it is. Someone (quite possibly the Stripes Dispatcher) needed " + "to get the source page resolution. But no source page was supplied in the " + "request, and unless you override ActionBeanContext.getSourcePageResolution() " + "you're going to need that value. When you use a tag a hidden " + "field called '" + StripesConstants.URL_KEY_SOURCE_PAGE + "' is included. " + "If you write your own forms or links that could generate validation errors, " + "you must include a value for this parameter. This can be done by calling " + "request.getServletPath()."); log.error(exception); // start the HTML error report response.setContentType("text/html"); PrintWriter writer = response.getWriter(); writer.println(""); writer.println("Stripes validation error report"); writer.println(""); writer.println("

Stripes validation error report

"); writer.println(exception.getMessage()); writer.println("

Validation errors

"); sendErrors(request, response); writer.println("

"); } protected void sendErrors(HttpServletRequest request, HttpServletResponse response) throws Exception { // Output all errors in a standard format Locale locale = request.getLocale(); ResourceBundle bundle = null; try { bundle = StripesFilter.getConfiguration().getLocalizationBundleFactory() .getErrorMessageBundle(locale); } catch (MissingResourceException mre) { log.warn(getClass().getName(), " could not find the error messages resource bundle. ", "As a result default headers/footers etc. will be used. Check that ", "you have a StripesResources.properties in your classpath (unless ", "of course you have configured a different bundle)."); } // Fetch the header and footer String header = getResource(bundle, "header", ErrorsTag.DEFAULT_HEADER); String footer = getResource(bundle, "footer", ErrorsTag.DEFAULT_FOOTER); String openElement = getResource(bundle, "beforeError", "
  • "); String closeElement = getResource(bundle, "afterError", "
  • "); // Write out the error messages PrintWriter writer = response.getWriter(); writer.write(header); for (List list : errors.values()) { for (ValidationError fieldError : list) { writer.write(openElement); writer.write(fieldError.getMessage(locale)); writer.write(closeElement); } } writer.write(footer); } /** * Utility method that is used to lookup the resources used for the errors header, * footer, and the strings that go before and after each error. * * @param bundle the bundle to look up the resource from * @param name the name of the resource to lookup (prefixes will be added) * @param fallback a value to return if no resource can be found * @return the value to use for the named resource */ protected String getResource(ResourceBundle bundle, String name, String fallback) { if (bundle == null) { return fallback; } String resource; try { resource = bundle.getString("stripes.errors." + name); } catch (MissingResourceException mre) { resource = fallback; } return resource; } }




    © 2015 - 2025 Weber Informatics LLC | Privacy Policy