From d62a85400f190eb40a2535c7ffb343c7d08b245b Mon Sep 17 00:00:00 2001 From: Lari Hotari Date: Wed, 7 Jan 2015 12:35:16 +0200 Subject: [PATCH 1/2] GRAILS-11897 add support for preserving ShutdownOperation --- .../grails/lifecycle/ShutdownOperations.java | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/grails-core/src/main/groovy/org/codehaus/groovy/grails/lifecycle/ShutdownOperations.java b/grails-core/src/main/groovy/org/codehaus/groovy/grails/lifecycle/ShutdownOperations.java index 97c1ba43584..bf7d6381c6f 100644 --- a/grails-core/src/main/groovy/org/codehaus/groovy/grails/lifecycle/ShutdownOperations.java +++ b/grails-core/src/main/groovy/org/codehaus/groovy/grails/lifecycle/ShutdownOperations.java @@ -16,14 +16,12 @@ package org.codehaus.groovy.grails.lifecycle; import grails.util.Holders; - -import java.util.Collection; -import java.util.concurrent.ConcurrentLinkedQueue; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.codehaus.groovy.grails.commons.ClassPropertyFetcher; import org.codehaus.groovy.grails.commons.cfg.ConfigurationHelper; +import java.util.Collection; +import java.util.LinkedHashSet; /** * Operations that should be executed on shutdown. @@ -32,10 +30,10 @@ * @since 2.0 */ public class ShutdownOperations { - private static final Log LOG = LogFactory.getLog(ShutdownOperations.class); - private static final Collection shutdownOperations = new ConcurrentLinkedQueue(); + private static final Collection shutdownOperations = new LinkedHashSet(); + private static final Collection preservedShutdownOperations = new LinkedHashSet(); public static final Runnable DEFAULT_SHUTDOWN_OPERATION = new Runnable() { public void run() { @@ -47,14 +45,13 @@ public void run() { }; static { - // default operations - shutdownOperations.add(DEFAULT_SHUTDOWN_OPERATION); + resetOperations(); } /** * Runs the shutdown operations */ - public static void runOperations() { + public static synchronized void runOperations() { try { for (Runnable shutdownOperation : shutdownOperations) { try { @@ -65,15 +62,37 @@ public static void runOperations() { } } finally { shutdownOperations.clear(); - shutdownOperations.add(DEFAULT_SHUTDOWN_OPERATION); + shutdownOperations.addAll(preservedShutdownOperations); } } + /** + * Adds a shutdown operation which will be run once for the next shutdown + * @param runnable The runnable operation + */ + public static synchronized void addOperation(Runnable runnable) { + addOperation(runnable, false); + } + /** * Adds a shutdown operation * @param runnable The runnable operation + * @param preserveForNextShutdown should preserve the operation for subsequent shutdowns, useful in tests */ - public static void addOperation(Runnable runnable) { + public static synchronized void addOperation(Runnable runnable, boolean preserveForNextShutdown) { shutdownOperations.add(runnable); + if(preserveForNextShutdown) { + preservedShutdownOperations.add(runnable); + } + } + + /** + * Clears all shutdown operations without running them. Also clears operations that are kept after running operations. + */ + public static synchronized void resetOperations() { + shutdownOperations.clear(); + preservedShutdownOperations.clear(); + // default operations + addOperation(DEFAULT_SHUTDOWN_OPERATION, true); } } From c0b1fedf59737ac1f2163006bd977dcaea31ff06 Mon Sep 17 00:00:00 2001 From: Lari Hotari Date: Wed, 7 Jan 2015 13:28:37 +0200 Subject: [PATCH 2/2] GRAILS-11898 GRAILS-11897 fix resetting ThreadLocal fields in ShutdownOperations --- .../grails/validation/DeferredBindingActions.java | 4 ++-- .../grails/validation/ConstraintEvalUtils.groovy | 2 +- .../ConvertersConfigurationHolder.java | 2 +- .../grails/plugins/DomainClassGrailsPlugin.groovy | 14 ++++++-------- .../src/main/groovy/grails/test/MockUtils.groovy | 6 +++++- .../grails/plugins/ValidationGrailsPlugin.groovy | 6 +++--- .../grails/web/servlet/WrappedResponseHolder.java | 6 +++--- 7 files changed, 21 insertions(+), 19 deletions(-) diff --git a/grails-core/src/main/groovy/grails/validation/DeferredBindingActions.java b/grails-core/src/main/groovy/grails/validation/DeferredBindingActions.java index 66681aaff20..db225f65555 100644 --- a/grails-core/src/main/groovy/grails/validation/DeferredBindingActions.java +++ b/grails-core/src/main/groovy/grails/validation/DeferredBindingActions.java @@ -36,9 +36,9 @@ public class DeferredBindingActions { static { ShutdownOperations.addOperation(new Runnable() { public void run() { - deferredBindingActions.remove(); + deferredBindingActions = new ThreadLocal>(); } - }); + }, true); } public static void addBindingAction(Runnable runnable) { diff --git a/grails-core/src/main/groovy/org/codehaus/groovy/grails/validation/ConstraintEvalUtils.groovy b/grails-core/src/main/groovy/org/codehaus/groovy/grails/validation/ConstraintEvalUtils.groovy index 88ff9560132..c46b2da4016 100644 --- a/grails-core/src/main/groovy/org/codehaus/groovy/grails/validation/ConstraintEvalUtils.groovy +++ b/grails-core/src/main/groovy/org/codehaus/groovy/grails/validation/ConstraintEvalUtils.groovy @@ -30,7 +30,7 @@ class ConstraintEvalUtils { static { ShutdownOperations.addOperation({ clearDefaultConstraints() - } as Runnable) + } as Runnable, true) } private static defaultConstraintsMap diff --git a/grails-plugin-converters/src/main/groovy/org/codehaus/groovy/grails/web/converters/configuration/ConvertersConfigurationHolder.java b/grails-plugin-converters/src/main/groovy/org/codehaus/groovy/grails/web/converters/configuration/ConvertersConfigurationHolder.java index 55888ef454c..e81f3443efc 100644 --- a/grails-plugin-converters/src/main/groovy/org/codehaus/groovy/grails/web/converters/configuration/ConvertersConfigurationHolder.java +++ b/grails-plugin-converters/src/main/groovy/org/codehaus/groovy/grails/web/converters/configuration/ConvertersConfigurationHolder.java @@ -42,7 +42,7 @@ public class ConvertersConfigurationHolder { public void run() { clear(); } - }); + }, true); } private static ConvertersConfigurationHolder INSTANCE = new ConvertersConfigurationHolder(); diff --git a/grails-plugin-domain-class/src/main/groovy/org/codehaus/groovy/grails/plugins/DomainClassGrailsPlugin.groovy b/grails-plugin-domain-class/src/main/groovy/org/codehaus/groovy/grails/plugins/DomainClassGrailsPlugin.groovy index 79419b76aea..ee4f1e2c70a 100644 --- a/grails-plugin-domain-class/src/main/groovy/org/codehaus/groovy/grails/plugins/DomainClassGrailsPlugin.groovy +++ b/grails-plugin-domain-class/src/main/groovy/org/codehaus/groovy/grails/plugins/DomainClassGrailsPlugin.groovy @@ -18,16 +18,11 @@ package org.codehaus.groovy.grails.plugins import grails.artefact.Enhanced import grails.util.GrailsUtil import grails.validation.ValidationErrors - -import org.codehaus.groovy.grails.commons.ComponentCapableDomainClass -import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler -import org.codehaus.groovy.grails.commons.GrailsApplication -import org.codehaus.groovy.grails.commons.GrailsClassUtils -import org.codehaus.groovy.grails.commons.GrailsDomainClass -import org.codehaus.groovy.grails.commons.GrailsDomainConfigurationUtil +import org.codehaus.groovy.grails.commons.* import org.codehaus.groovy.grails.domain.GormApiSupport import org.codehaus.groovy.grails.domain.GrailsDomainClassCleaner import org.codehaus.groovy.grails.domain.GrailsDomainClassMappingContext +import org.codehaus.groovy.grails.lifecycle.ShutdownOperations import org.codehaus.groovy.grails.support.SoftThreadLocalMap import org.codehaus.groovy.grails.validation.ConstraintEvalUtils import org.codehaus.groovy.grails.validation.ConstraintsEvaluator @@ -107,7 +102,10 @@ class DomainClassGrailsPlugin { ConstraintEvalUtils.getDefaultConstraints(config) } - static final PROPERTY_INSTANCE_MAP = new SoftThreadLocalMap() + static PROPERTY_INSTANCE_MAP = new SoftThreadLocalMap() + static { + ShutdownOperations.addOperation({-> PROPERTY_INSTANCE_MAP = new SoftThreadLocalMap() } as Runnable, true) + } def doWithDynamicMethods = { ApplicationContext ctx-> enhanceDomainClasses(application, ctx) diff --git a/grails-plugin-testing/src/main/groovy/grails/test/MockUtils.groovy b/grails-plugin-testing/src/main/groovy/grails/test/MockUtils.groovy index 7f32780a0e6..ee8328c8ca2 100755 --- a/grails-plugin-testing/src/main/groovy/grails/test/MockUtils.groovy +++ b/grails-plugin-testing/src/main/groovy/grails/test/MockUtils.groovy @@ -17,6 +17,7 @@ package grails.test import grails.validation.ValidationException import groovy.xml.StreamingMarkupBuilder +import org.codehaus.groovy.grails.lifecycle.ShutdownOperations import java.beans.Introspector import java.beans.PropertyDescriptor @@ -71,7 +72,10 @@ class MockUtils { static final COMPARATORS_RE = COMPARATORS.join("|") static final DYNAMIC_FINDER_RE = /(\w+?)(${COMPARATORS_RE})?((And|Or)(\w+?)(${COMPARATORS_RE})?)?/ - static final errorsObjects = new ThreadLocalMap() + static errorsObjects = new ThreadLocalMap() + static { + ShutdownOperations.addOperation({-> errorsObjects = new ThreadLocalMap() } as Runnable, true) + } static final Map IDS = [:] /** diff --git a/grails-plugin-validation/src/main/groovy/org/codehaus/groovy/grails/plugins/ValidationGrailsPlugin.groovy b/grails-plugin-validation/src/main/groovy/org/codehaus/groovy/grails/plugins/ValidationGrailsPlugin.groovy index f4238913b1f..5d4d60080a4 100644 --- a/grails-plugin-validation/src/main/groovy/org/codehaus/groovy/grails/plugins/ValidationGrailsPlugin.groovy +++ b/grails-plugin-validation/src/main/groovy/org/codehaus/groovy/grails/plugins/ValidationGrailsPlugin.groovy @@ -31,12 +31,12 @@ class ValidationGrailsPlugin { def version = GrailsUtil.getGrailsVersion() def loadAfter = ['hibernate', 'hibernate4', 'controllers'] - static final ThreadLocal PROPERTY_INSTANCE_MAP = new SoftThreadLocalMap() + static ThreadLocal PROPERTY_INSTANCE_MAP = new SoftThreadLocalMap() static { ShutdownOperations.addOperation({ - PROPERTY_INSTANCE_MAP.remove() - } as Runnable) + PROPERTY_INSTANCE_MAP = new SoftThreadLocalMap(); + } as Runnable, true) } def doWithDynamicMethods = { ApplicationContext ctx -> diff --git a/grails-web-common/src/main/groovy/org/codehaus/groovy/grails/web/servlet/WrappedResponseHolder.java b/grails-web-common/src/main/groovy/org/codehaus/groovy/grails/web/servlet/WrappedResponseHolder.java index eb2cae50500..d9213aa900e 100644 --- a/grails-web-common/src/main/groovy/org/codehaus/groovy/grails/web/servlet/WrappedResponseHolder.java +++ b/grails-web-common/src/main/groovy/org/codehaus/groovy/grails/web/servlet/WrappedResponseHolder.java @@ -30,11 +30,11 @@ public class WrappedResponseHolder { static { ShutdownOperations.addOperation(new Runnable() { public void run() { - wrappedResponseHolder.remove(); + wrappedResponseHolder = new ThreadLocal(); } - }); + }, true); } - private static final ThreadLocal wrappedResponseHolder = + private static ThreadLocal wrappedResponseHolder = new ThreadLocal(); /**