Permalink
Browse files

changed how validateable plugin scans for components to avoid a dupli…

…cate scan and improve performance
  • Loading branch information...
1 parent 4123e5d commit c20d0e7578f1f3e20ef20fdd1334859995481dad @graemerocher graemerocher committed Jul 20, 2009
@@ -18,19 +18,23 @@
import grails.util.BuildSettingsHolder;
import grails.util.Metadata;
import org.apache.commons.io.FilenameUtils;
+import org.codehaus.groovy.grails.plugins.GrailsPluginManager;
+import org.codehaus.groovy.grails.plugins.PluginManagerHolder;
import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.beans.factory.xml.XmlReaderContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ComponentScanBeanDefinitionParser;
import org.springframework.core.io.Resource;
-import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.AntPathMatcher;
import org.w3c.dom.Element;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Set;
/**
@@ -43,6 +47,19 @@
public class ClosureClassIgnoringComponentScanBeanDefinitionParser extends ComponentScanBeanDefinitionParser{
@Override
+ protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {
+ final ClassPathBeanDefinitionScanner scanner = super.createScanner(readerContext, useDefaultFilters);
+ GrailsPluginManager pluginManager = PluginManagerHolder.getPluginManager();
+ if(pluginManager!=null) {
+ List<TypeFilter> typeFilters = pluginManager.getTypeFilters();
+ for (TypeFilter typeFilter : typeFilters) {
+ scanner.addIncludeFilter(typeFilter);
+ }
+ }
+ return scanner;
+ }
+
+ @Override
protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
final ClassPathBeanDefinitionScanner scanner = super.configureScanner(parserContext, element);
final PathMatchingResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(parserContext.getReaderContext().getResourceLoader()) {
@@ -93,21 +110,4 @@ public boolean match(String pattern, String path) {
scanner.setResourceLoader(resourceResolver);
return scanner;
}
-
- class DelegatingResourceLoader implements ResourceLoader{
- private ResourceLoader delegate;
-
- DelegatingResourceLoader(ResourceLoader loader) {
- this.delegate = loader;
- }
-
- public Resource getResource(String location) {
- System.out.println("location = " + location);
- return delegate.getResource(location);
- }
-
- public ClassLoader getClassLoader() {
- return delegate.getClassLoader();
- }
- }
}
@@ -6,13 +6,14 @@
import grails.util.BuildScope;
import grails.util.GrailsNameUtils;
import groovy.lang.ExpandoMetaClass;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
import org.codehaus.groovy.grails.commons.ArtefactHandler;
+import org.codehaus.groovy.grails.commons.GrailsApplication;
import org.codehaus.groovy.grails.commons.spring.RuntimeSpringConfiguration;
import org.codehaus.groovy.grails.plugins.exceptions.PluginException;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.Resource;
+import org.springframework.core.type.filter.TypeFilter;
import java.util.*;
@@ -45,6 +46,13 @@ public AbstractGrailsPluginManager(GrailsApplication application) {
this.application = application;
}
+ public List<TypeFilter> getTypeFilters() {
+ List<TypeFilter> list = new ArrayList<TypeFilter>();
+ for (GrailsPlugin grailsPlugin : pluginList) {
+ list.addAll(grailsPlugin.getTypeFilters());
+ }
+ return Collections.unmodifiableList(list);
+ }
public GrailsPlugin[] getAllPlugins() {
return pluginList.toArray(new GrailsPlugin[pluginList.size()]);
}
@@ -42,6 +42,7 @@
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.type.filter.TypeFilter;
import java.io.File;
import java.io.IOException;
@@ -95,6 +96,7 @@
private Map pluginScopes;
private Map pluginEnvs;
private List<String> pluginExcludes = new ArrayList<String>();
+ private Collection<? extends TypeFilter> typeFilters = new ArrayList<TypeFilter>();
public DefaultGrailsPlugin(Class pluginClass, Resource resource, GrailsApplication application) {
@@ -149,8 +151,15 @@ private void initialisePlugin(Class pluginClass) {
evaluatePluginStatus();
evaluatePluginScopes();
evaluatePluginExcludes();
+ evaluateTypeFilters();
+ }
+ private void evaluateTypeFilters() {
+ Object result = GrailsClassUtils.getPropertyOrStaticPropertyOrFieldValue(this.plugin, TYPE_FILTERS);
+ if(result instanceof List) {
+ this.typeFilters = (List<TypeFilter>) result;
+ }
}
private void evaluatePluginExcludes() {
@@ -1017,4 +1026,8 @@ public void doArtefactConfiguration() {
return this.pluginExcludes;
}
+ public Collection<? extends TypeFilter> getTypeFilters() {
+ return this.typeFilters;
+ }
+
}
@@ -24,9 +24,11 @@
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.type.filter.TypeFilter;
import java.util.List;
import java.util.Map;
+import java.util.Collection;
/**
* <p>Plugin interface that adds Spring {@link org.springframework.beans.factory.config.BeanDefinition}s
@@ -159,6 +161,10 @@
*/
String PLUGIN_EXCLUDES = "pluginExcludes";
+ /**
+ * The field that reperesents the list of type filters a plugin provides
+ */
+ String TYPE_FILTERS = "typeFilters";
/**
* <p>This method is called to allow the plugin to add {@link org.springframework.beans.factory.config.BeanDefinition}s
@@ -396,4 +402,11 @@
* @see #isBasePlugin()
*/
void setBasePlugin(boolean isBase);
+
+ /**
+ * Plugin can provide a list of Spring TypeFilters so that annotated components can
+ * be scanned into the ApplicationContext
+ * @return A collection of TypeFilter instance
+ */
+ Collection<? extends TypeFilter> getTypeFilters();
}
@@ -21,12 +21,14 @@
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.Resource;
+import org.springframework.core.type.filter.TypeFilter;
import org.springframework.web.context.ServletContextAware;
import java.io.File;
import java.io.Writer;
import java.util.Collection;
import java.util.Map;
+import java.util.List;
/**
* <p>A class that handles the loading and management of plug-ins in the Grails system.
@@ -255,4 +257,10 @@ void doRuntimeConfiguration(
* @param aClass The class
*/
void informOfClassChange(Class aClass);
+
+ /**
+ * Get all of the TypeFilter definitions defined by the plugins
+ * @return A list of TypeFilter definitions
+ */
+ List<TypeFilter> getTypeFilters();
}
@@ -1,13 +1,28 @@
+/*
+ * Copyright 2004-2005 the original author or authors.
+ *
+ * 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 org.codehaus.groovy.grails.plugins
import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU
import grails.util.GrailsUtil
+import org.codehaus.groovy.grails.plugins.DomainClassPluginSupport
import org.codehaus.groovy.grails.support.SoftThreadLocalMap
import org.codehaus.groovy.grails.validation.ConstrainedPropertyBuilder
import org.codehaus.groovy.grails.validation.Validateable
-import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry
-import org.springframework.context.annotation.ClassPathBeanDefinitionScanner
+import org.springframework.context.ApplicationContext
import org.springframework.core.type.filter.AnnotationTypeFilter
import org.springframework.validation.BeanPropertyBindingResult
import org.springframework.validation.Errors
@@ -16,9 +31,11 @@ public class ValidationGrailsPlugin {
def version = GrailsUtil.getGrailsVersion()
def dependsOn = [:]
def loadAfter = ['hibernate', 'controllers']
+ def typeFilters = [new AnnotationTypeFilter(Validateable)]
+
static final PROPERTY_INSTANCE_MAP = new SoftThreadLocalMap()
- def doWithDynamicMethods = {ctx ->
+ def doWithDynamicMethods = { ApplicationContext ctx ->
// list of validateable classes
def validateables = []
@@ -27,31 +44,14 @@ public class ValidationGrailsPlugin {
validateables << it
}
- // grab all of the classes annotated with @Validateable
- def simpleRegistry = new SimpleBeanDefinitionRegistry();
- try {
- def scanner = new ClassPathBeanDefinitionScanner(simpleRegistry, false)
- scanner.setIncludeAnnotationConfig(false)
- scanner.addIncludeFilter(new AnnotationTypeFilter(Validateable))
- def packagesToScan = application.config?.grails?.validateable?.packages
- if(!packagesToScan) {
- packagesToScan = ['']
- }
- scanner.scan(packagesToScan as String[])
- }
- catch (e) {
- // Workaround for http://jira.springframework.org/browse/SPR-5120
- log.warn "WARNING: Cannot scan for @Validateable due to container classloader issues. This feature has been disabled for this environment. Message: ${e.message}"
- };
-
- simpleRegistry.beanDefinitionNames?.each {beanDefinitionName ->
- def beanDefinition = simpleRegistry.getBeanDefinition(beanDefinitionName)
- def beanClass = application.classLoader.loadClass(beanDefinition.beanClassName)
- validateables << beanClass
+ for(entry in ctx.getBeansWithAnnotation(Validateable)) {
+ Class validateable = entry?.value?.class
+ if(validateable)
+ validateables << validateable
}
// make all of these classes 'validateable'
- validateables.each {validateableClass ->
+ for(validateableClass in validateables) {
log.debug "Making Class Validateable: ${validateableClass.name}"
addValidationMethods(application, validateableClass, ctx)
}

0 comments on commit c20d0e7

Please sign in to comment.