Index: stripes/src/net/sourceforge/stripes/tag/DefaultTagErrorRendererFactory.java =================================================================== --- stripes/src/net/sourceforge/stripes/tag/DefaultTagErrorRendererFactory.java (revision 1000) +++ stripes/src/net/sourceforge/stripes/tag/DefaultTagErrorRendererFactory.java (revision ) @@ -53,7 +53,7 @@ this.rendererClass = configuration.getBootstrapPropertyResolver(). getClassProperty(RENDERER_CLASS_KEY, TagErrorRenderer.class); - + if (this.rendererClass == null) this.rendererClass = DefaultTagErrorRenderer.class; } @@ -86,4 +86,8 @@ { this.configuration = configuration; } + + public void terminate(Configuration configuration) { + //Nothing to clean up here -} + } +} Index: stripes/src/net/sourceforge/stripes/controller/AnnotatedClassActionResolver.java =================================================================== --- stripes/src/net/sourceforge/stripes/controller/AnnotatedClassActionResolver.java (revision 1412) +++ stripes/src/net/sourceforge/stripes/controller/AnnotatedClassActionResolver.java (revision ) @@ -59,7 +59,7 @@ * Configuration key used to lookup a comma-separated list of package names. The * packages (and their sub-packages) will be scanned for implementations of * ActionBean. - * @since Stripes 1.5 + * @since Stripes 1.5 */ public static final String PACKAGES = "ActionResolver.Packages"; @@ -348,7 +348,7 @@ * Calls {@link ActionBean#setContext(ActionBeanContext)} with the given {@code context} only if * necessary. Subclasses should use this method instead of setting the context directly because * it can be somewhat tricky to determine when it needs to be done. - * + * * @param bean The bean whose context may need to be set. * @param context The context to pass to the bean if necessary. */ @@ -408,12 +408,12 @@ * the request, then return its value. This attribute is used to handle internal forwards, when * request parameters are merged and cannot reliably determine the desired event name. *
- * + * ** If that doesn't work, the value of a 'special' request parameter ({@link StripesConstants#URL_KEY_EVENT_NAME}) * is checked to see if contains a single value matching an event name. *
- * + * ** Failing that, search for a parameter in the request whose name matches one of the named * events handled by the ActionBean. For example, if the ActionBean can handle events foo and @@ -422,13 +422,13 @@ * matching names, the result of this method cannot be guaranteed and a * {@link StripesRuntimeException} will be thrown. *
- * + * ** Finally, if the event name cannot be determined through the parameter names and there is * extra path information beyond the URL binding of the ActionBean, it is checked to see if it * matches an event name. *
- * + * * @param bean the ActionBean type bound to the request * @param context the ActionBeanContect for the current request * @return String the name of the event submitted, or null if none can be found @@ -445,7 +445,7 @@ * Checks a special request attribute to get the event name. This attribute * may be set when the presence of the original request parameters on a * forwarded request makes it difficult to determine which event to fire. - * + * * @param bean the ActionBean type bound to the request * @param context the ActionBeanContect for the current request * @return the name of the event submitted, or null if none can be found @@ -641,4 +641,8 @@ public Collection* Individual property binding is delegated to the other interface method, bind(ActionBean, * String, Object), in order to allow for easy extension of this class. *
- * + * * @param bean the ActionBean whose properties are to be validated and bound * @param context the ActionBeanContext of the current request * @param validate true indicates that validation should be run, false indicates that only type @@ -241,12 +241,12 @@ * expression is available through the {@code getExpression()} and the ActionBean is available * through the {@code getBean()} method on the evaluation. * - * + * ** By default checks to ensure that the expression is not attempting to bind into the * ActionBeanContext for security reasons. *
- * + * * @param eval the expression evaluation to check for binding permission * @return true if binding can/should proceed, false to veto binding */ @@ -255,7 +255,7 @@ .isBindingAllowed(eval); if (!allowed) { String param = eval.getExpression().getSource(); - log.warn("Binding denied for parameter [", param, "]"); + log.warn("Binding denied for parameter [", param, "]. Use @Validate to allow binding in conjunction with @StrictBinding."); } return allowed; } @@ -264,7 +264,7 @@ * Invoked whenever an exception is thrown when attempting to bind a property to an ActionBean. * By default logs some information about the occurrence, but could be overridden to do more * intelligent things based on the application. - * + * * @param bean the ActionBean that was the subject of binding * @param name the ParameterName object for the parameter being bound * @param values the list of values being bound, potentially null if the error occurred when @@ -290,7 +290,7 @@ * Uses a hidden field to determine what (if any) fields were present in the form but did not get * submitted to the server. For each such field the value is "softly" set to null on the * ActionBean. This is not uncommon for checkboxes, and also for multi-selects. - * + * * @param bean the ActionBean being bound to * @param context the current ActionBeanContext */ @@ -316,7 +316,7 @@ * hidden field containing a set of field names. This is encrypted to stop the user from * monkeying with it. This method retrieves the list of field names, decrypts it and splits it * out into a Collection of field names. - * + * * @param bean the current ActionBean * @return a non-null (though possibly empty) list of field names */ @@ -349,7 +349,7 @@ * Internal helper method to bind one or more values to a single property on an ActionBean. If * the target type is an array of Collection, then all values are bound. If the target type is a * scalar type then the first value in the List of values is bound. - * + * * @param bean the ActionBean instance to which the property is being bound * @param propertyEvaluation the property evaluation to be used to set the property * @param valueOrValues a List containing one or more values @@ -389,7 +389,7 @@ * or intervening objects in a nested property are null, nothing is done. If the property is * non-null, it will be set to null. Unless the property is a collection, in which case it will * be clear()'d. - * + * * @param bean the ActionBean to which properties are being bound * @param property the name of the property being bound * @param type the declared type of the property on the ActionBean @@ -424,7 +424,7 @@ /** * Attempt to set the named property on the target bean. If the binding fails for any reason * (property does not exist, type conversion not possible etc.) an exception will be thrown. - * + * * @param bean the ActionBean on to which the property is to be bound * @param propertyName the name of the property to be bound (simple or complex) * @param propertyValue the value of the target property @@ -534,13 +534,13 @@ * having one or more values, and where each value is a non-empty String after it has had white * space trimmed from each end. *- * + * *
* For any fields that fail validation, creates a ScopedLocaliableError that uses the stripped * name of the field to find localized info (e.g. foo.bar instead of foo[1].bar). The error is * bound to the actual field on the form though, e.g. foo[1].bar. *
- * + * * @param name the name of the parameter verbatim from the request * @param strippedName the name of the parameter with any indexing removed from it * @param values the String[] of values that was submitted in the request @@ -580,7 +580,7 @@ /** * Performs several basic validations on the String value supplied in the HttpServletRequest, * based on information provided in annotations on the ActionBean. - * + * * @param propertyName the name of the property being validated (used for constructing errors) * @param values the String[] of values from the request being validated * @param validationInfo the ValidationMetadata for the property being validated @@ -626,7 +626,7 @@ * Performs basic post-conversion validations on the properties of the ActionBean after they * have been converted to their rich type by the type conversion system. Validates single * properties in isolation from other properties. - * + * * @param bean the ActionBean that is undergoing validation and binding * @param convertedValues a map of ParameterName to all converted values for each field * @param errors the validation errors object to put errors in to @@ -681,7 +681,7 @@ * {@literal @}Validate annotation. The expression is evaluated once for each value converted. * See {@link net.sourceforge.stripes.validation.expression.ExpressionValidator} for details * on how this is implemented. - * + * * @param bean the ActionBean who's property is being validated * @param name the name of the property being validated * @param values the non-null post-conversion values for the property @@ -705,14 +705,14 @@ * no default converter, then a Constructor will be looked for on the target type which takes a * single String parameter. If such a Constructor exists it will be invoked. * - * + * ** Only parameter values that are non-null and do not equal the empty String will be converted * and returned. So an input array with one entry equaling the empty string, [""], will result * in an empty List being returned. Similarly, if a length three array is passed in with * one item equaling the empty String, a List of length two will be returned. *
- * + * * @param bean the ActionBean on which the property to convert exists * @param propertyName the name of the property being converted * @param values a String array of values to attempt conversion of @@ -838,7 +838,7 @@ /** * An inner class that represents a "row" of form properties that all have the same index - * so that we can validate all those properties together. + * so that we can validate all those properties together. */ protected static class Row extends HashMap* An implementation of {@link ObjectFactory} that simply calls {@link Class#newInstance()} to * obtain a new instance. *
- * + * * @author Ben Gunter * @since Stripes 1.5.1 */ @@ -60,7 +60,7 @@ /** * Wrap the given constructor. - * + * * @param factory The object factory whose * {@link ObjectFactory#newInstance(Constructor, Object...)} method will be * called when invoking the constructor. @@ -119,7 +119,7 @@ * will apply are determined by the value of the {@link TargetTypes} annotation on the class. If * there is no such annotation, then the post-processor will process all instances created by * the object factory. - * + * * @param postProcessor The post-processor to use. */ public synchronized void addPostProcessor(ObjectPostProcessor postProcessor) { @@ -169,7 +169,7 @@ /** * Calls {@link Class#newInstance()} and returns the newly created object. - * + * * @param clazz The class to instantiate. * @return The new object */ @@ -191,7 +191,7 @@ /** * Attempts to determine an implementing class for the interface provided and instantiate it * using a default constructor. - * + * * @param interfaceType an interface (or abstract class) to make an instance of * @return an instance of the interface type supplied * @throws InstantiationException if no implementation type has been configured @@ -221,7 +221,7 @@ /** * Looks up the default implementing type for the supplied interface. This is done based on a * static map of known common interface types and implementing classes. - * + * * @param iface an interface for which an implementing class is needed * @return a Class object representing the implementing type, or null if one is not found */ @@ -233,7 +233,7 @@ * Register a class as the default implementation of an interface. The implementation class will * be returned from future calls to {@link #getImplementingClass(Class)} when the argument is * {@code iface}. - * + * * @param iface The interface class * @param impl The implementation class */ @@ -247,7 +247,7 @@ /** * Create a new instance of {@code clazz} by looking up the specified constructor and passing it * and its parameters to {@link #newInstance(Constructor, Object...)}. - * + * * @param clazz The class to instantiate. * @param constructorArgTypes The type parameters of the constructor to be invoked. (See * {@link Class#getConstructor(Class...)}.) @@ -275,7 +275,7 @@ /** * Calls {@link Constructor#newInstance(Object...)} with the given parameters, passes the new * object to {@link #postProcess(Object)} and returns it. - * + * * @param constructor The constructor to invoke. * @param params The parameters to pass to the constructor. */ @@ -297,7 +297,7 @@ /** * Get a {@link ConstructorWrapper} that wraps the constructor for the given class that accepts * parameters of the given types. - * + * * @param clazz The class to look up the constructor in. * @param parameterTypes The parameter types that the constructor accepts. */ @@ -318,7 +318,7 @@ * {@link #newInstance(Class, Class[], Object[])}. Subclasses that do not need to change the way * objects are instantiated but do need to do something to the objects before returning them may * override this method to achieve that. - * + * * @param object A newly created object. * @return The given object, unchanged. */ @@ -334,4 +334,8 @@ return object; } + + public void terminate(Configuration configuration) { + //Nothing to clean up here -} + } +} Index: stripes/src/net/sourceforge/stripes/localization/DefaultLocalePicker.java =================================================================== --- stripes/src/net/sourceforge/stripes/localization/DefaultLocalePicker.java (revision 739) +++ stripes/src/net/sourceforge/stripes/localization/DefaultLocalePicker.java (revision ) @@ -197,4 +197,8 @@ public String pickCharacterEncoding(HttpServletRequest request, Locale locale) { return this.encodings.get(locale); } + + public void terminate(Configuration configuration) { + //Nothing to clean up here -} + } +} Index: stripes/src/net/sourceforge/stripes/config/DefaultConfiguration.java =================================================================== --- stripes/src/net/sourceforge/stripes/config/DefaultConfiguration.java (revision 1153) +++ stripes/src/net/sourceforge/stripes/config/DefaultConfiguration.java (revision ) @@ -14,18 +14,6 @@ */ package net.sourceforge.stripes.config; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.servlet.ServletContext; - import net.sourceforge.stripes.controller.ActionBeanContextFactory; import net.sourceforge.stripes.controller.ActionBeanPropertyBinder; import net.sourceforge.stripes.controller.ActionResolver; @@ -61,6 +49,17 @@ import net.sourceforge.stripes.validation.TypeConverterFactory; import net.sourceforge.stripes.validation.ValidationMetadataProvider; +import javax.servlet.ServletContext; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + /** *Centralized location for defaults for all Configuration properties. This implementation does * not lookup configuration information anywhere! It returns hard-coded defaults that will result @@ -68,9 +67,9 @@ * *
Despite it's name the DefaultConfiguration is not in fact the default Configuration * implementation in Stripes! Instead it is the retainer of default configuration values. The - * Configuration implementation that is used when no alternative is configured is the - * {@link RuntimeConfiguration}, which is a direct subclass of DefaultConfiguration, and when no - * further configuration properties are supplied behaves identically to the DefaultConfiguration.
+ * Configuration implementation that is used when no alternative is configured is the {@link + * RuntimeConfiguration}, which is a direct subclass of DefaultConfiguration, and when no further + * configuration properties are supplied behaves identically to the DefaultConfiguration. * *The DefaultConfiguration is designed to be easily extended as needed. The init() method
* ensures that components are initialized in the correct order (taking dependencies into account),
@@ -97,7 +96,7 @@
private FormatterFactory formatterFactory;
private TagErrorRendererFactory tagErrorRendererFactory;
private PopulationStrategy populationStrategy;
- private Map Default ExceptionHandler implementation that makes it easy for users to extend and
* add custom handling for different types of exception. When extending this class methods
@@ -184,7 +183,7 @@
* In production, most applications will provide their own handler for
* {@link SourcePageNotFoundException} by extending this class and overriding this method.
*
- *
+ *
* @param exception The exception that needs to be handled
* @param request The servlet request
* @param response The servlet response
@@ -326,7 +325,7 @@
* from the HTTP Referer header. If it is unable to do so, it returns null. Subclasses may
* override this method to return whatever they wish. The return value must be relative to the
* application context root.
- *
+ *
* @param request The request that generated the exception
* @return The context-relative path from which the request was submitted
*/
@@ -437,4 +436,8 @@
return throwable;
}
+
+ public void terminate(Configuration configuration) {
+ //Nothing to clean up here
-}
+ }
+}
Index: stripes/src/net/sourceforge/stripes/config/Configuration.java
===================================================================
--- stripes/src/net/sourceforge/stripes/config/Configuration.java (revision 1000)
+++ stripes/src/net/sourceforge/stripes/config/Configuration.java (revision )
@@ -51,7 +51,7 @@
/**
* Supplies the Configuration with a BootstrapPropertyResolver. This method is guaranteed to
* be invoked prior to the init method.
- *
+ *
* @param resolver a BootStrapPropertyResolver which can be used to find any values required
* by the Configuration in order to initialize
*/
@@ -65,6 +65,14 @@
void init();
/**
+ * Called by the DispatcherServlet after the application server perform a clean shutdown.
+ * In a terminate method would be possible to commit several data uncommitted
+ * Components are not expected to fail with a exception. Instead the should handle
+ * any failure on their own
+ */
+ void terminate();
+
+ /**
* Implementations should implement this method to simply return a reference to the
* BootstrapPropertyResolver passed to the Configuration at initialization time.
*
@@ -89,7 +97,7 @@
/**
* Returns an instance of {@link ObjectFactory} that is used throughout Stripes to instantiate
* classes.
- *
+ *
* @return an instance of {@link ObjectFactory}.
*/
ObjectFactory getObjectFactory();
@@ -206,7 +214,7 @@
* Returns an instance of {@link ValidationMetadataProvider} that can be used by Stripes to
* determine what validations need to be applied during
* {@link LifecycleStage#BindingAndValidation}.
- *
+ *
* @return an instance of {@link ValidationMetadataProvider}
*/
ValidationMetadataProvider getValidationMetadataProvider();
Index: tests/src/net/sourceforge/stripes/config/DefaultConfigurationTest.java
===================================================================
--- tests/src/net/sourceforge/stripes/config/DefaultConfigurationTest.java (revision )
+++ tests/src/net/sourceforge/stripes/config/DefaultConfigurationTest.java (revision )
@@ -0,0 +1,111 @@
+package net.sourceforge.stripes.config;
+
+import net.sourceforge.stripes.action.Resolution;
+import net.sourceforge.stripes.controller.ExecutionContext;
+import net.sourceforge.stripes.controller.Interceptor;
+import net.sourceforge.stripes.controller.LifecycleStage;
+import org.testng.Assert;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+public class DefaultConfigurationTest {
+ private DefaultConfiguration defaultConfiguration;
+
+ @BeforeTest
+ public void setup() {
+ defaultConfiguration = new DefaultConfiguration();
+ }
+
+ @Test(groups = "fast")
+ public void testTryTerminate() {
+ final StringBuilder called = new StringBuilder();
+ defaultConfiguration.tryTerminate(new ConfigurableComponent() {
+ public void init(final Configuration configuration) throws Exception {
+ }
+
+ public void terminate(final Configuration configuration) {
+ called.append("called");
+ }
+ });
+ Assert.assertEquals(called.toString(), "called", "expected to call the terminate method");
+ }
+
+ @Test(groups = "fast")
+ public void testTryTerminateIgnoresNullValues() {
+ defaultConfiguration.tryTerminate(null);
+ }
+
+ @Test(groups = "fast")
+ public void testTryTerminateIgnoresNonConfigurableComponentInstances() {
+ defaultConfiguration.tryTerminate("I am not a ConfigurableComponent");
+ }
+
+ @Test(groups = "fast")
+ public void testTryTerminateHandlesRuntimeExceptions() {
+ defaultConfiguration.tryTerminate(new ConfigurableComponent() {
+ public void init(final Configuration configuration) throws Exception {
+ }
+
+ public void terminate(final Configuration configuration) {
+ throw new RuntimeException("Something went terribly wrong");
+ }
+ });
+ }
+
+ @Test(groups = "fast")
+ public void testTerminateInterceptor() {
+ Map