Skip to content

Commit

Permalink
changed how validateable plugin scans for components to avoid a dupli…
Browse files Browse the repository at this point in the history
…cate scan and improve performance
  • Loading branch information
graemerocher committed Jul 20, 2009
1 parent 4123e5d commit c20d0e7
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand All @@ -42,6 +46,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);
Expand Down Expand Up @@ -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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.*;

Expand Down Expand Up @@ -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()]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -95,6 +96,7 @@ public class DefaultGrailsPlugin extends AbstractGrailsPlugin implements GrailsP
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) {
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -1017,4 +1026,8 @@ public List<String> getPluginExcludes() {
return this.pluginExcludes;
}

public Collection<? extends TypeFilter> getTypeFilters() {
return this.typeFilters;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -159,6 +161,10 @@ public interface GrailsPlugin extends ApplicationContextAware, Comparable {
*/
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
Expand Down Expand Up @@ -396,4 +402,11 @@ public interface GrailsPlugin extends ApplicationContextAware, Comparable {
* @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();
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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();
}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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 = []

Expand All @@ -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)
}
Expand Down

0 comments on commit c20d0e7

Please sign in to comment.