Skip to content
Browse files

made the parser lenient for unrecognized calls to support other varia…

…nts of the DSL; added support for a 'cache' element (so 'domain' is now effectively an alias for that); added support for defining the cache DSL in Config.groovy under the 'grails.cache.config' key and configuring the Ehcache manager from that;
  • Loading branch information...
1 parent c4d677e commit 7653a4e4ed47844837238241ae44be35705174f8 Burt Beckwith committed
View
32 CacheEhcacheGrailsPlugin.groovy
@@ -12,6 +12,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import grails.plugin.cache.ehcache.EhcacheConfigBuilder
import grails.plugin.cache.ehcache.GrailsEhcacheCacheManager
import grails.plugin.cache.web.filter.ehcache.EhcachePageFragmentCachingFilter
@@ -19,6 +20,7 @@ import org.codehaus.groovy.grails.commons.GrailsApplication
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean
+import org.springframework.core.io.ByteArrayResource
class CacheEhcacheGrailsPlugin {
@@ -45,18 +47,30 @@ class CacheEhcacheGrailsPlugin {
return
}
- def cacheConfig = application.config.grails.cache.ehcache
- String ehcacheXmlLocation
- if (cacheConfig.ehcacheXmlLocation instanceof CharSequence) {
- ehcacheXmlLocation = cacheConfig.ehcacheXmlLocation
- log.info "Using Ehcache configuration file $ehcacheXmlLocation"
+ def cacheConfig = application.config.grails.cache
+ def ehcacheConfig = cacheConfig.ehcache
+ def ehcacheConfigLocation
+ if (cacheConfig.config instanceof Closure) {
+ // parse the config into XML and let Ehcache configure itself from that
+ EhcacheConfigBuilder builder = new EhcacheConfigBuilder()
+ builder.parse cacheConfig.config
+ String xml = builder.toXml()
+ log.debug "Ehcache generated XML:\n$xml"
+ ehcacheConfigLocation = new ByteArrayResource(xml.bytes)
+ }
+ else if (ehcacheConfig.ehcacheXmlLocation instanceof CharSequence) {
+ // use the specified location
+ ehcacheConfigLocation = ehcacheConfig.ehcacheXmlLocation
+ log.info "Using Ehcache configuration file $ehcacheConfigLocation"
}
else {
+ // no config and no specified location, so look for ehcache.xml in the classpath,
+ // and fall back to ehcache-failsafe.xml in the Ehcache jar as a last resort
def ctx = springConfig.unrefreshedApplicationContext
def defaults = ['classpath:ehcache.xml', 'classpath:ehcache-failsafe.xml']
- ehcacheXmlLocation = defaults.find { ctx.getResource(it).exists() }
- if (ehcacheXmlLocation) {
- log.info "No Ehcache configuration file specified, using $ehcacheXmlLocation"
+ ehcacheConfigLocation = defaults.find { ctx.getResource(it).exists() }
+ if (ehcacheConfigLocation) {
+ log.info "No Ehcache configuration file specified, using $ehcacheConfigLocation"
}
else {
log.error "No Ehcache configuration file specified and default file not found"
@@ -64,7 +78,7 @@ class CacheEhcacheGrailsPlugin {
}
ehcacheCacheManager(EhCacheManagerFactoryBean) {
- configLocation = ehcacheXmlLocation
+ configLocation = ehcacheConfigLocation
}
cacheManager(GrailsEhcacheCacheManager) {
View
12 grails-app/conf/Config.groovy
@@ -3,4 +3,16 @@ log4j = {
'org.springframework',
'org.hibernate',
'net.sf.ehcache.hibernate'
+ debug 'grails.plugin.cache'
+}
+
+// for unit tests
+grails.cache.config = {
+ cache {
+ name 'mycache'
+ eternal false
+ overflowToDisk true
+ maxElementsInMemory 10000
+ maxElementsOnDisk 10000000
+ }
}
View
56 src/groovy/grails/plugin/cache/ehcache/EhcacheConfigBuilder.groovy
@@ -72,6 +72,7 @@ class EhcacheConfigBuilder extends BuilderSupport {
private Map<String, Object> _current
private String _diskStore = TEMP_DIR
private List<Map<String, Object>> _cacheManagerPeerProviderFactories = []
+ private int _unrecognizedElementDepth = 0
private final Logger _log = LoggerFactory.getLogger(getClass())
@@ -107,8 +108,24 @@ class EhcacheConfigBuilder extends BuilderSupport {
private static final String TEMP_DIR = 'java.io.tmpdir'
+ /**
+ * Convenience method to parse a config closure.
+ * @param c the closure
+ */
+ void parse(Closure c) {
+ c.delegate = this
+ c.resolveStrategy = Closure.DELEGATE_FIRST
+ c()
+ }
+
@Override
protected createNode(name) {
+ if (_unrecognizedElementDepth) {
+ _unrecognizedElementDepth++
+ _log.warn "ignoring node $name contained in unrecognized parent node"
+ return
+ }
+
_log.trace "createNode $name"
switch (name) {
@@ -137,6 +154,7 @@ class EhcacheConfigBuilder extends BuilderSupport {
case 'domainCollection':
case 'collection':
+ case 'cache':
case 'domain':
_current = [:]
_caches << _current
@@ -180,11 +198,18 @@ class EhcacheConfigBuilder extends BuilderSupport {
return name
}
- throw new IllegalArgumentException("Cannot create empty node with name '$name'")
+ _unrecognizedElementDepth++
+ _log.warn "Cannot create empty node with name '$name'"
}
@Override
protected createNode(name, value) {
+ if (_unrecognizedElementDepth) {
+ _unrecognizedElementDepth++
+ _log.warn "ignoring node $name with value $value contained in unrecognized parent node"
+ return
+ }
+
_log.trace "createNode $name, value: $value"
String level = _stack[-1]
@@ -257,12 +282,13 @@ class EhcacheConfigBuilder extends BuilderSupport {
break
case 'domain':
+ case 'cache':
case 'domainCollection':
- if (('name' == name || 'domain' == name) && value instanceof Class) {
+ if (('name' == name || 'cache' == name || 'domain' == name) && value instanceof Class) {
value = value.name
}
- if ('name' == name || 'domain' == name || name in CACHE_PARAM_NAMES) {
+ if ('name' == name || 'cache' == name || 'domain' == name || name in CACHE_PARAM_NAMES) {
_current[name] = value
return name
}
@@ -327,18 +353,30 @@ class EhcacheConfigBuilder extends BuilderSupport {
return name
}
- throw new IllegalArgumentException("Cannot create node with name '$name' and value '$value' for parent '$level'")
+ _unrecognizedElementDepth++
+ _log.warn "Cannot create node with name '$name' and value '$value' for parent '$level'"
}
@Override
protected createNode(name, Map attributes) {
+ if (_unrecognizedElementDepth) {
+ _unrecognizedElementDepth++
+ _log.warn "ignoring node $name with attributes $attributes contained in unrecognized parent node"
+ return
+ }
+
_log.trace "createNode $name + attributes: $attributes"
}
@Override
protected createNode(name, Map attributes, value) {
+ if (_unrecognizedElementDepth) {
+ _unrecognizedElementDepth++
+ _log.warn "ignoring node $name with value $value and attributes $attributes contained in unrecognized parent node"
+ return
+ }
+
_log.trace "createNode $name + value: $value attributes: $attributes"
- throw new UnsupportedOperationException()
}
@Override
@@ -350,7 +388,13 @@ class EhcacheConfigBuilder extends BuilderSupport {
@Override
protected void nodeCompleted(parent, node) {
_log.trace "nodeCompleted $parent $node"
- _stack.pop()
+
+ if (_unrecognizedElementDepth) {
+ _unrecognizedElementDepth--
+ }
+ else {
+ _stack.pop()
+ }
}
String toXml() {
View
71 test/unit/grails/plugin/cache/ehcache/EhcacheConfigBuilderTests.groovy
@@ -132,6 +132,28 @@ class EhcacheConfigBuilderTests extends GrailsUnitTestCase {
assertAttribute 'LRU', 'memoryStoreEvictionPolicy', defaultCache
}
+ void testCache() {
+
+ parse {
+ cache {
+ name 'mycache'
+ eternal false
+ overflowToDisk true
+ maxElementsInMemory 10000
+ maxElementsOnDisk 10000000
+ }
+ }
+
+ def caches = root.cache
+ assertEquals 1, caches.size()
+ def cache = caches[0]
+ assertAttribute 'mycache', 'name', cache
+ assertAttribute 'false', 'eternal', cache
+ assertAttribute 'true', 'overflowToDisk', cache
+ assertAttribute '10000', 'maxElementsInMemory', cache
+ assertAttribute '10000000', 'maxElementsOnDisk', cache
+ }
+
void testDomain() {
parse {
@@ -404,14 +426,59 @@ class EhcacheConfigBuilderTests extends GrailsUnitTestCase {
assertAttribute ',', 'propertySeparator', factory
}
+ void testFromConfigGroovy() {
+
+ ConfigObject config = new ConfigSlurper(Environment.current.name).parse(
+ new GroovyClassLoader(getClass().classLoader).loadClass('Config'))
+ def cacheConfig = config.grails.cache.config
+ assertTrue cacheConfig instanceof Closure
+
+ parse cacheConfig
+
+ def caches = root.cache
+ assertEquals 1, caches.size()
+ def cache = caches[0]
+ assertAttribute 'mycache', 'name', cache
+ assertAttribute 'false', 'eternal', cache
+ assertAttribute 'true', 'overflowToDisk', cache
+ assertAttribute '10000', 'maxElementsInMemory', cache
+ assertAttribute '10000000', 'maxElementsOnDisk', cache
+ }
+
+ void testLenient() {
+
+ parse {
+ domain {
+ name 'com.foo.Thing'
+ eternal false
+ overflowToDisk true
+ maxElementsInMemory 10000
+ maxElementsOnDisk 10000000
+ type 'com.foo.BarCache'
+ someOtherProperty 42
+ nested {
+ bar 123
+ }
+ }
+ }
+
+ def caches = root.cache
+ assertEquals 1, caches.size()
+ def cache = caches[0]
+ assertAttribute 'com.foo.Thing', 'name', cache
+ assertAttribute 'false', 'eternal', cache
+ assertAttribute 'true', 'overflowToDisk', cache
+ assertAttribute '10000', 'maxElementsInMemory', cache
+ assertAttribute '10000000', 'maxElementsOnDisk', cache
+ }
+
private void assertAttribute(String expected, String name, node = root) {
assertEquals expected, node."@$name".text()
}
private void parse(Closure config) {
builder = new EhcacheConfigBuilder()
- config.delegate = builder
- config()
+ builder.parse config
xml = builder.toXml()
root = new XmlSlurper().parseText(xml)
}

0 comments on commit 7653a4e

Please sign in to comment.
Something went wrong with that request. Please try again.