From 659c11a2feb7a99d7b320fb01aa7c003a46785b4 Mon Sep 17 00:00:00 2001 From: John Blum Date: Wed, 23 May 2018 13:37:24 -0700 Subject: [PATCH] SGF-749 - Expose SDG's Function annotation configuration as part of the public API for extension purposes. --- ...tFunctionExecutionConfigurationSource.java | 45 +++--- ...nFunctionExecutionConfigurationSource.java | 137 ++++++++++-------- ...ctionExecutionBeanDefinitionRegistrar.java | 66 ++++++--- .../FunctionExecutionConfigurationSource.java | 53 +++---- ...erBasedExecutionBeanDefinitionBuilder.java | 37 ++--- ...erBasedExecutionBeanDefinitionBuilder.java | 30 ++-- ...lFunctionExecutionConfigurationSource.java | 58 ++++---- ...sedExecutionBeanDefinitionBuilderTest.java | 92 ++++++------ 8 files changed, 292 insertions(+), 226 deletions(-) diff --git a/src/main/java/org/springframework/data/gemfire/function/config/AbstractFunctionExecutionConfigurationSource.java b/src/main/java/org/springframework/data/gemfire/function/config/AbstractFunctionExecutionConfigurationSource.java index 9c30f5a3..e9dec581 100644 --- a/src/main/java/org/springframework/data/gemfire/function/config/AbstractFunctionExecutionConfigurationSource.java +++ b/src/main/java/org/springframework/data/gemfire/function/config/AbstractFunctionExecutionConfigurationSource.java @@ -1,11 +1,11 @@ /* * Copyright 2002-2013 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. @@ -17,9 +17,10 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Set; +import java.util.stream.Collectors; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.context.annotation.ScannedGenericBeanDefinition; @@ -33,16 +34,17 @@ import org.springframework.data.gemfire.function.annotation.OnServers; /** * Annotation based configuration source for function executions - * + * * @author David Turanski * */ -abstract class AbstractFunctionExecutionConfigurationSource implements FunctionExecutionConfigurationSource { +public abstract class AbstractFunctionExecutionConfigurationSource implements FunctionExecutionConfigurationSource { private static Set> functionExecutionAnnotationTypes; - + static { - Set> annotationTypes = new HashSet>(5); + + Set> annotationTypes = new HashSet<>(5); annotationTypes.add(OnRegion.class); annotationTypes.add(OnServer.class); @@ -53,25 +55,20 @@ abstract class AbstractFunctionExecutionConfigurationSource implements FunctionE functionExecutionAnnotationTypes = Collections.unmodifiableSet(annotationTypes); } - protected Log logger = LogFactory.getLog(getClass()); - - static Set> getFunctionExecutionAnnotationTypes() { + public static Set> getFunctionExecutionAnnotationTypes() { return functionExecutionAnnotationTypes; } - static Set getFunctionExecutionAnnotationTypeNames() { - Set functionExecutionTypeNames = new HashSet(getFunctionExecutionAnnotationTypes().size()); - - for (Class annotationType : getFunctionExecutionAnnotationTypes()) { - functionExecutionTypeNames.add(annotationType.getName()); - } - - return functionExecutionTypeNames; + public static Set getFunctionExecutionAnnotationTypeNames() { + return getFunctionExecutionAnnotationTypes().stream().map(Class::getName).collect(Collectors.toSet()); } + protected Logger logger = LoggerFactory.getLogger(getClass()); + public Collection getCandidates(ResourceLoader loader) { - ClassPathScanningCandidateComponentProvider scanner = new FunctionExecutionComponentProvider( - getIncludeFilters(), getFunctionExecutionAnnotationTypes()); + + ClassPathScanningCandidateComponentProvider scanner = + new FunctionExecutionComponentProvider(getIncludeFilters(), getFunctionExecutionAnnotationTypes()); scanner.setResourceLoader(loader); @@ -79,9 +76,10 @@ abstract class AbstractFunctionExecutionConfigurationSource implements FunctionE scanner.addExcludeFilter(filter); } - Set result = new HashSet(); + Set result = new HashSet<>(); for (String basePackage : getBasePackages()) { + if (logger.isDebugEnabled()) { logger.debug("scanning package " + basePackage); } @@ -95,5 +93,4 @@ abstract class AbstractFunctionExecutionConfigurationSource implements FunctionE return result; } - } diff --git a/src/main/java/org/springframework/data/gemfire/function/config/AnnotationFunctionExecutionConfigurationSource.java b/src/main/java/org/springframework/data/gemfire/function/config/AnnotationFunctionExecutionConfigurationSource.java index a75d002c..77651351 100644 --- a/src/main/java/org/springframework/data/gemfire/function/config/AnnotationFunctionExecutionConfigurationSource.java +++ b/src/main/java/org/springframework/data/gemfire/function/config/AnnotationFunctionExecutionConfigurationSource.java @@ -1,17 +1,20 @@ /* * Copyright 2002-2013 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.springframework.data.gemfire.function.config; +import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray; +import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException; + import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Arrays; @@ -27,91 +30,107 @@ import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.core.type.filter.AssignableTypeFilter; import org.springframework.core.type.filter.TypeFilter; +import org.springframework.data.gemfire.util.ArrayUtils; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; /** - * Annotation based configuration source for function executions - * - * @author David Turanski + * Annotation based configuration source for function executions. * + * @author David Turanski + * @author John Blum */ -class AnnotationFunctionExecutionConfigurationSource extends AbstractFunctionExecutionConfigurationSource { - +public class AnnotationFunctionExecutionConfigurationSource extends AbstractFunctionExecutionConfigurationSource { + private static final String BASE_PACKAGES = "basePackages"; private static final String BASE_PACKAGE_CLASSES = "basePackageClasses"; - + private static final String VALUE = "value"; + private final AnnotationMetadata metadata; private final AnnotationAttributes attributes; - - + + /** * Creates a new {@link AnnotationFunctionExecutionConfigurationSource} from the given {@link AnnotationMetadata} and * annotation. - * + * * @param metadata must not be {@literal null}. */ - AnnotationFunctionExecutionConfigurationSource(AnnotationMetadata metadata) { + public AnnotationFunctionExecutionConfigurationSource(AnnotationMetadata metadata) { - Assert.notNull(metadata); + Assert.notNull(metadata, "AnnotationMetadata must not be null"); + + this.attributes = AnnotationAttributes.fromMap( + metadata.getAnnotationAttributes(EnableGemfireFunctionExecutions.class.getName())); - this.attributes = new AnnotationAttributes(metadata.getAnnotationAttributes(EnableGemfireFunctionExecutions.class.getName())); this.metadata = metadata; - } - - /* (non-Javadoc) * @see org.springframework.data.gemfire.function.config.FunctionExecutionConfigurationSource#getSource() */ @Override public Object getSource() { - // TODO Auto-generated method stub return this.metadata; - } + } /* (non-Javadoc) * @see org.springframework.data.gemfire.function.config.FunctionExecutionConfigurationSource#getBasePackages() */ @Override public Iterable getBasePackages() { - String[] value = attributes.getStringArray("value"); - String[] basePackages = attributes.getStringArray(BASE_PACKAGES); - Class[] basePackageClasses = attributes.getClassArray(BASE_PACKAGE_CLASSES); + + String[] value = this.attributes.getStringArray(VALUE); + String[] basePackages = this.attributes.getStringArray(BASE_PACKAGES); + + Class[] basePackageClasses = this.attributes.getClassArray(BASE_PACKAGE_CLASSES); // Default configuration - return package of annotated class - if (value.length == 0 && basePackages.length == 0 && basePackageClasses.length == 0) { - String className = metadata.getClassName(); + if (areAllEmpty(value, basePackages, basePackageClasses)) { + + String className = this.metadata.getClassName(); + return Collections.singleton(className.substring(0, className.lastIndexOf('.'))); } - Set packages = new HashSet(); + Set packages = new HashSet<>(); + packages.addAll(Arrays.asList(value)); packages.addAll(Arrays.asList(basePackages)); - for (Class typeName : basePackageClasses) { - packages.add(ClassUtils.getPackageName(typeName)); - } + Arrays.stream(nullSafeArray(basePackageClasses, Class.class)) + .map(ClassUtils::getPackageName) + .forEach(packages::add); return packages; } - - @Override - public Iterable getIncludeFilters() { - return parseFilters("includeFilters"); + private boolean areAllEmpty(Object[]... arrays) { + + for (Object[] array : arrays) { + if (!ArrayUtils.isEmpty(array)) { + return false; + } + } + + return true; } - - @Override + + @Override public Iterable getExcludeFilters() { return parseFilters("excludeFilters"); } + @Override + public Iterable getIncludeFilters() { + return parseFilters("includeFilters"); + } + private Set parseFilters(String attributeName) { - Set result = new HashSet(); - AnnotationAttributes[] filters = attributes.getAnnotationArray(attributeName); + AnnotationAttributes[] filters = this.attributes.getAnnotationArray(attributeName); + + Set result = new HashSet<>(); for (AnnotationAttributes filter : filters) { result.addAll(typeFiltersFor(filter)); @@ -119,39 +138,41 @@ class AnnotationFunctionExecutionConfigurationSource extends AbstractFunctionExe return result; } - + /** * Copy of {@code ComponentScanAnnotationParser#typeFiltersFor}. - * + * * @param filterAttributes * @return */ private List typeFiltersFor(AnnotationAttributes filterAttributes) { - List typeFilters = new ArrayList(); + FilterType filterType = filterAttributes.getEnum("type"); + List typeFilters = new ArrayList<>(); + for (Class filterClass : filterAttributes.getClassArray("value")) { switch (filterType) { - case ANNOTATION: - Assert.isAssignable(Annotation.class, filterClass, "An error occured when processing a @ComponentScan " - + "ANNOTATION type filter: "); - @SuppressWarnings("unchecked") - Class annoClass = (Class) filterClass; - typeFilters.add(new AnnotationTypeFilter(annoClass)); - break; - case ASSIGNABLE_TYPE: - typeFilters.add(new AssignableTypeFilter(filterClass)); - break; - case CUSTOM: - Assert.isAssignable(TypeFilter.class, filterClass, "An error occured when processing a @ComponentScan " - + "CUSTOM type filter: "); - typeFilters.add(BeanUtils.instantiateClass(filterClass, TypeFilter.class)); - break; - default: - throw new IllegalArgumentException("unknown filter type " + filterType); + case ANNOTATION: + Assert.isAssignable(Annotation.class, filterClass, + "An error occured when processing a @ComponentScan ANNOTATION type filter: "); + @SuppressWarnings("unchecked") + Class annoClass = (Class) filterClass; + typeFilters.add(new AnnotationTypeFilter(annoClass)); + break; + case ASSIGNABLE_TYPE: + typeFilters.add(new AssignableTypeFilter(filterClass)); + break; + case CUSTOM: + Assert.isAssignable(TypeFilter.class, filterClass, + "An error occured when processing a @ComponentScan CUSTOM type filter: "); + typeFilters.add(BeanUtils.instantiateClass(filterClass, TypeFilter.class)); + break; + default: + throw newIllegalArgumentException("Unknown filter type [*s]", filterType); } } + return typeFilters; } - } diff --git a/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionBeanDefinitionRegistrar.java b/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionBeanDefinitionRegistrar.java index a4b3d6f0..225bf898 100644 --- a/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionBeanDefinitionRegistrar.java +++ b/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionBeanDefinitionRegistrar.java @@ -1,11 +1,11 @@ /* * Copyright 2002-2013 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. @@ -16,35 +16,68 @@ import java.util.Set; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.xml.ParserContext; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.context.annotation.ScannedGenericBeanDefinition; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.data.gemfire.function.annotation.OnMember; +import org.springframework.data.gemfire.function.annotation.OnMembers; +import org.springframework.data.gemfire.function.annotation.OnRegion; +import org.springframework.data.gemfire.function.annotation.OnServer; +import org.springframework.data.gemfire.function.annotation.OnServers; import org.springframework.util.Assert; import org.springframework.util.StringUtils; +import org.w3c.dom.Element; /** - * {@link ImportBeanDefinitionRegistrar} for {code} @EnableGemfireFunctionExecutions {code} - * Scans for interfaces annotated with one of {code} @OnRegion, @OnServer, @OnServers, @OnMember, @OnMembers {code} - * @author David Turanski + * {@link ImportBeanDefinitionRegistrar} for {@link EnableGemfireFunctionExecutions}, which scans for interfaces + * annotated with one of {@link OnRegion}, {@link OnServer}, {@link OnServers}, {@link OnMember}, {@link OnMembers}. * + * @author David Turanski + * @author John Blum + * @see org.springframework.beans.factory.support.BeanDefinitionRegistry + * @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar + * @see org.springframework.context.annotation.ScannedGenericBeanDefinition */ -class FunctionExecutionBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { - - /* (non-Javadoc) - * @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar#registerBeanDefinitions(org.springframework.core.type.AnnotationMetadata, org.springframework.beans.factory.support.BeanDefinitionRegistry) +public class FunctionExecutionBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { + + /* + * (non-Javadoc) + * @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar + * #registerBeanDefinitions(org.springframework.core.type.AnnotationMetadata, org.springframework.beans.factory.support.BeanDefinitionRegistry) */ @Override public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) { - AbstractFunctionExecutionConfigurationSource configurationSource = new AnnotationFunctionExecutionConfigurationSource( - annotationMetadata); + + AbstractFunctionExecutionConfigurationSource configurationSource = + newAnnotationBasedFunctionExecutionConfigurationSource(annotationMetadata); registerBeanDefinitions(configurationSource, registry); - } - - /* - * This registers bean definitions from any function execution configuration source + + protected AbstractFunctionExecutionConfigurationSource newAnnotationBasedFunctionExecutionConfigurationSource( + AnnotationMetadata annotationMetadata) { + + return new AnnotationFunctionExecutionConfigurationSource(annotationMetadata); + } + + protected void registerBeanDefinitions(Element element, ParserContext parserContext) { + + AbstractFunctionExecutionConfigurationSource configurationSource = + newXmlBasedFunctionExecutionConfigurationSource(element, parserContext); + + registerBeanDefinitions(configurationSource, parserContext.getRegistry()); + } + + protected AbstractFunctionExecutionConfigurationSource newXmlBasedFunctionExecutionConfigurationSource( + Element element, ParserContext parserContext) { + + return new XmlFunctionExecutionConfigurationSource(element, parserContext); + } + + /** + * Registers bean definitions from any {@link FunctionExecutionConfigurationSource}. */ void registerBeanDefinitions(AbstractFunctionExecutionConfigurationSource functionExecutionConfigurationSource, BeanDefinitionRegistry registry) { @@ -89,5 +122,4 @@ class FunctionExecutionBeanDefinitionRegistrar implements ImportBeanDefinitionRe return functionExecutionAnnotation; } - } diff --git a/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionConfigurationSource.java b/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionConfigurationSource.java index b88f25a5..e090aca8 100644 --- a/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionConfigurationSource.java +++ b/src/main/java/org/springframework/data/gemfire/function/config/FunctionExecutionConfigurationSource.java @@ -1,53 +1,56 @@ /* * Copyright 2002-2013 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.springframework.data.gemfire.function.config; +import java.lang.annotation.Annotation; + import org.springframework.core.type.filter.TypeFilter; /** - * Interface for function execution configuration sources (e.g., annotation or XML configuration) to configure - * classpath scanning of annotated interfaces to implement proxies that invoke Gemfire functions - * - * @author David Turanski + * Interface for Function Execution configuration sources (e.g. {@link Annotation} or XML configuration) + * to configure classpath scanning of annotated interfaces to implement proxies that invoke Functions. * + * @author David Turanski + * @author John Blum */ -interface FunctionExecutionConfigurationSource { - /** - * Returns the actual source object that the configuration originated from. Will be used by the tooling to give visual - * feedback on where the repository instances actually come from. - * - * @return must not be {@literal null}. - */ - Object getSource(); +public interface FunctionExecutionConfigurationSource { /** * Returns the base packages the repository interfaces shall be found under. - * + * * @return must not be {@literal null}. */ Iterable getBasePackages(); - - - /** - * Returns configured {@link TypeFilter}s - * @return include filters - */ - Iterable getIncludeFilters(); - + /** * Returns configured {@link TypeFilter}s * @return exclude filters */ Iterable getExcludeFilters(); - + + /** + * Returns configured {@link TypeFilter}s + * @return include filters + */ + Iterable getIncludeFilters(); + + /** + * Returns the actual source object that the configuration originated from. Will be used by the tooling to give visual + * feedback on where the repository instances actually come from. + * + * @return must not be {@literal null}. + */ + Object getSource(); + } diff --git a/src/main/java/org/springframework/data/gemfire/function/config/MemberBasedExecutionBeanDefinitionBuilder.java b/src/main/java/org/springframework/data/gemfire/function/config/MemberBasedExecutionBeanDefinitionBuilder.java index 620d265d..4978202a 100644 --- a/src/main/java/org/springframework/data/gemfire/function/config/MemberBasedExecutionBeanDefinitionBuilder.java +++ b/src/main/java/org/springframework/data/gemfire/function/config/MemberBasedExecutionBeanDefinitionBuilder.java @@ -1,11 +1,11 @@ /* * Copyright 2002-2013 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. @@ -14,41 +14,43 @@ package org.springframework.data.gemfire.function.config; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.data.gemfire.function.annotation.OnMember; +import org.springframework.data.gemfire.function.annotation.OnMembers; import org.springframework.data.gemfire.function.execution.GemfireFunctionProxyFactoryBean; import org.springframework.util.StringUtils; /** - * A base class for OnMember and OnMembers function execution bean definition builders. - * - * @author David Turanski + * Base class for {@link OnMember} and {@link OnMembers} Function execution + * {@link BeanDefinitionBuilder BeanDefinitionBuilders}. * + * @author David Turanski + * @author John Blum + * @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder */ - abstract class MemberBasedExecutionBeanDefinitionBuilder extends AbstractFunctionExecutionBeanDefinitionBuilder { +abstract class MemberBasedExecutionBeanDefinitionBuilder extends AbstractFunctionExecutionBeanDefinitionBuilder { /** * @param configuration */ - public MemberBasedExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) { + MemberBasedExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) { super(configuration); } - - /* (non-Javadoc) * @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder#getGemfireFunctionOperationsBeanDefinitionBuilder(org.springframework.beans.factory.support.BeanDefinitionRegistry) */ @Override protected BeanDefinitionBuilder getGemfireFunctionOperationsBeanDefinitionBuilder(BeanDefinitionRegistry registry) { - - BeanDefinitionBuilder functionTemplateBuilder = BeanDefinitionBuilder.genericBeanDefinition(getGemfireOperationsClass()); - - String groups = (String)configuration.getAttribute("groups"); - - + + BeanDefinitionBuilder functionTemplateBuilder = + BeanDefinitionBuilder.genericBeanDefinition(getGemfireOperationsClass()); + + String groups = (String) this.configuration.getAttribute("groups"); + if (StringUtils.hasText(groups)) { functionTemplateBuilder.addConstructorArgValue(StringUtils.commaDelimitedListToStringArray(groups)); } - + return functionTemplateBuilder; } @@ -62,4 +64,5 @@ import org.springframework.util.StringUtils; } protected abstract Class getGemfireOperationsClass(); + } diff --git a/src/main/java/org/springframework/data/gemfire/function/config/ServerBasedExecutionBeanDefinitionBuilder.java b/src/main/java/org/springframework/data/gemfire/function/config/ServerBasedExecutionBeanDefinitionBuilder.java index 05e35990..60973e23 100644 --- a/src/main/java/org/springframework/data/gemfire/function/config/ServerBasedExecutionBeanDefinitionBuilder.java +++ b/src/main/java/org/springframework/data/gemfire/function/config/ServerBasedExecutionBeanDefinitionBuilder.java @@ -15,19 +15,22 @@ package org.springframework.data.gemfire.function.config; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.data.gemfire.config.xml.GemfireConstants; +import org.springframework.data.gemfire.function.annotation.OnServer; +import org.springframework.data.gemfire.function.annotation.OnServers; import org.springframework.data.gemfire.function.execution.GemfireFunctionProxyFactoryBean; import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** - * @author David Turanski + * Base class for {@link OnServer} and {@link OnServers} Function execution + * {@link BeanDefinitionBuilder BeanDefinitionBuilders}. * + * @author David Turanski + * @author John Blum + * @see org.springframework.data.gemfire.function.config.AbstractFunctionExecutionBeanDefinitionBuilder */ abstract class ServerBasedExecutionBeanDefinitionBuilder extends AbstractFunctionExecutionBeanDefinitionBuilder { - /** - * @param configuration - */ ServerBasedExecutionBeanDefinitionBuilder(FunctionExecutionConfiguration configuration) { super(configuration); } @@ -38,18 +41,19 @@ abstract class ServerBasedExecutionBeanDefinitionBuilder extends AbstractFunctio */ @Override protected BeanDefinitionBuilder getGemfireFunctionOperationsBeanDefinitionBuilder(BeanDefinitionRegistry registry) { - BeanDefinitionBuilder functionTemplateBuilder = BeanDefinitionBuilder.genericBeanDefinition( - getGemfireFunctionOperationsClass()); - String cache = (String) configuration.getAttribute("cache"); - String pool = (String) configuration.getAttribute("pool"); + BeanDefinitionBuilder functionTemplateBuilder = + BeanDefinitionBuilder.genericBeanDefinition(getGemfireFunctionOperationsClass()); - Assert.state(!(StringUtils.hasText(cache) && StringUtils.hasText(pool)), String.format( - "invalid configuration for interface %s; cannot specify both 'pool' and 'cache'", - configuration.getFunctionExecutionInterface().getName())); + String cache = (String) this.configuration.getAttribute("cache"); + String pool = (String) this.configuration.getAttribute("pool"); - functionTemplateBuilder.addConstructorArgReference(StringUtils.hasText(pool) ? pool - : (StringUtils.hasText(cache) ? cache : GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME)); + Assert.state(!(StringUtils.hasText(cache) && StringUtils.hasText(pool)), + String.format("Invalid configuration for interface [%s]; cannot specify both 'pool' and 'cache'", + this.configuration.getFunctionExecutionInterface().getName())); + + functionTemplateBuilder.addConstructorArgReference(StringUtils.hasText(pool) + ? pool : (StringUtils.hasText(cache) ? cache : GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME)); return functionTemplateBuilder; } diff --git a/src/main/java/org/springframework/data/gemfire/function/config/XmlFunctionExecutionConfigurationSource.java b/src/main/java/org/springframework/data/gemfire/function/config/XmlFunctionExecutionConfigurationSource.java index 7ce9d526..962fdb3d 100644 --- a/src/main/java/org/springframework/data/gemfire/function/config/XmlFunctionExecutionConfigurationSource.java +++ b/src/main/java/org/springframework/data/gemfire/function/config/XmlFunctionExecutionConfigurationSource.java @@ -1,15 +1,16 @@ /* * Copyright 2002-2013 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.springframework.data.gemfire.function.config; import java.util.Arrays; @@ -23,23 +24,29 @@ import org.w3c.dom.Element; /** * @author David Turanski - * + * @author John Blum */ -class XmlFunctionExecutionConfigurationSource extends AbstractFunctionExecutionConfigurationSource { - private static final String BASE_PACKAGE = "base-package"; - private Element element; - private ParserContext context; - private Iterable includeFilters; - private Iterable excludeFilters; +public class XmlFunctionExecutionConfigurationSource extends AbstractFunctionExecutionConfigurationSource { - XmlFunctionExecutionConfigurationSource(Element element, ParserContext context) { - Assert.notNull(element); - Assert.notNull(context); + private static final String BASE_PACKAGE = "base-package"; + + private final Element element; + + private final Iterable includeFilters; + private final Iterable excludeFilters; + + private final ParserContext parserContext; + + public XmlFunctionExecutionConfigurationSource(Element element, ParserContext parserContext) { + + Assert.notNull(element, "Element must not be null"); + Assert.notNull(parserContext, "ParserContext must not be null"); this.element = element; - this.context = context; + this.parserContext = parserContext; + + TypeFilterParser parser = new TypeFilterParser(parserContext.getReaderContext()); - TypeFilterParser parser = new TypeFilterParser(context.getReaderContext()); this.includeFilters = parser.parseTypeFilters(element, Type.INCLUDE); this.excludeFilters = parser.parseTypeFilters(element, Type.EXCLUDE); } @@ -49,7 +56,7 @@ class XmlFunctionExecutionConfigurationSource extends AbstractFunctionExecutionC */ @Override public Object getSource() { - return context.extractSource(element); + return this.parserContext.extractSource(element); } /* (non-Javadoc) @@ -57,25 +64,26 @@ class XmlFunctionExecutionConfigurationSource extends AbstractFunctionExecutionC */ @Override public Iterable getBasePackages() { + String attribute = element.getAttribute(BASE_PACKAGE); + return Arrays.asList(StringUtils.delimitedListToStringArray(attribute, ",", " ")); } - - /* (non-Javadoc) - * @see org.springframework.data.gemfire.function.config.FunctionExecutionConfigurationSource#getIncludeFilters() - */ - @Override - public Iterable getIncludeFilters() { - return includeFilters; - } /* (non-Javadoc) * @see org.springframework.data.gemfire.function.config.FunctionExecutionConfigurationSource#getExcludeFilters() */ @Override public Iterable getExcludeFilters() { - return excludeFilters; + return this.excludeFilters; } + /* (non-Javadoc) + * @see org.springframework.data.gemfire.function.config.FunctionExecutionConfigurationSource#getIncludeFilters() + */ + @Override + public Iterable getIncludeFilters() { + return this.includeFilters; + } } diff --git a/src/test/java/org/springframework/data/gemfire/function/config/ServerBasedExecutionBeanDefinitionBuilderTest.java b/src/test/java/org/springframework/data/gemfire/function/config/ServerBasedExecutionBeanDefinitionBuilderTest.java index b7c11291..04668ae4 100644 --- a/src/test/java/org/springframework/data/gemfire/function/config/ServerBasedExecutionBeanDefinitionBuilderTest.java +++ b/src/test/java/org/springframework/data/gemfire/function/config/ServerBasedExecutionBeanDefinitionBuilderTest.java @@ -31,8 +31,6 @@ import static org.mockito.Mockito.when; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -56,22 +54,22 @@ public class ServerBasedExecutionBeanDefinitionBuilderTest { @Test @SuppressWarnings("unchecked") public void getGemfireFunctionOperationsBeanDefinitionBuilder() { + FunctionExecutionConfiguration mockFunctionExecutionConfiguration = mock(FunctionExecutionConfiguration.class, "MockFunctionExecutionConfiguration"); when(mockFunctionExecutionConfiguration.getAttribute(eq("cache"))).thenReturn(null); when(mockFunctionExecutionConfiguration.getAttribute(eq("pool"))).thenReturn(" "); - when(mockFunctionExecutionConfiguration.getFunctionExecutionInterface()).thenAnswer(new Answer>() { - @Override public Class answer(final InvocationOnMock invocation) throws Throwable { - return Object.class; - } - }); + when(mockFunctionExecutionConfiguration.getFunctionExecutionInterface()).thenAnswer(invocation -> Object.class); - ServerBasedExecutionBeanDefinitionBuilder builder = new ServerBasedExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) { - @Override protected Class getGemfireFunctionOperationsClass() { - return Object.class; - } - }; + ServerBasedExecutionBeanDefinitionBuilder builder = + new ServerBasedExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) { + + @Override + protected Class getGemfireFunctionOperationsClass() { + return Object.class; + } + }; BeanDefinitionBuilder beanDefinitionBuilder = builder.getGemfireFunctionOperationsBeanDefinitionBuilder(null); @@ -80,7 +78,7 @@ public class ServerBasedExecutionBeanDefinitionBuilderTest { AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition(); assertThat(beanDefinition, is(notNullValue())); - assertThat((Class) beanDefinition.getBeanClass(), is(equalTo(Object.class))); + assertThat(beanDefinition.getBeanClass(), is(equalTo(Object.class))); assertThat(String.valueOf(beanDefinition.getConstructorArgumentValues() .getArgumentValue(0, RuntimeBeanReference.class).getValue()), containsString(GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME)); @@ -93,22 +91,22 @@ public class ServerBasedExecutionBeanDefinitionBuilderTest { @Test @SuppressWarnings("unchecked") public void getGemfireFunctionOperationsBeanDefinitionBuilderWithCache() { + FunctionExecutionConfiguration mockFunctionExecutionConfiguration = mock(FunctionExecutionConfiguration.class, "MockFunctionExecutionConfiguration"); when(mockFunctionExecutionConfiguration.getAttribute(eq("cache"))).thenReturn("TestCache"); when(mockFunctionExecutionConfiguration.getAttribute(eq("pool"))).thenReturn(" "); - when(mockFunctionExecutionConfiguration.getFunctionExecutionInterface()).thenAnswer(new Answer>() { - @Override public Class answer(final InvocationOnMock invocation) throws Throwable { - return Object.class; - } - }); + when(mockFunctionExecutionConfiguration.getFunctionExecutionInterface()).thenAnswer(invocation -> Object.class); - ServerBasedExecutionBeanDefinitionBuilder builder = new ServerBasedExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) { - @Override protected Class getGemfireFunctionOperationsClass() { - return Object.class; - } - }; + ServerBasedExecutionBeanDefinitionBuilder builder = + new ServerBasedExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) { + + @Override + protected Class getGemfireFunctionOperationsClass() { + return Object.class; + } + }; BeanDefinitionBuilder beanDefinitionBuilder = builder.getGemfireFunctionOperationsBeanDefinitionBuilder(null); @@ -117,7 +115,7 @@ public class ServerBasedExecutionBeanDefinitionBuilderTest { AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition(); assertThat(beanDefinition, is(notNullValue())); - assertThat((Class) beanDefinition.getBeanClass(), is(equalTo(Object.class))); + assertThat(beanDefinition.getBeanClass(), is(equalTo(Object.class))); assertThat(String.valueOf(beanDefinition.getConstructorArgumentValues() .getArgumentValue(0, RuntimeBeanReference.class).getValue()), containsString("TestCache")); @@ -129,22 +127,22 @@ public class ServerBasedExecutionBeanDefinitionBuilderTest { @Test @SuppressWarnings("unchecked") public void getGemfireFunctionOperationsBeanDefinitionBuilderWithPool() { + FunctionExecutionConfiguration mockFunctionExecutionConfiguration = mock(FunctionExecutionConfiguration.class, "MockFunctionExecutionConfiguration"); when(mockFunctionExecutionConfiguration.getAttribute(eq("cache"))).thenReturn(null); when(mockFunctionExecutionConfiguration.getAttribute(eq("pool"))).thenReturn("TestPool"); - when(mockFunctionExecutionConfiguration.getFunctionExecutionInterface()).thenAnswer(new Answer>() { - @Override public Class answer(final InvocationOnMock invocation) throws Throwable { - return Object.class; - } - }); + when(mockFunctionExecutionConfiguration.getFunctionExecutionInterface()).thenAnswer(invocation -> Object.class); - ServerBasedExecutionBeanDefinitionBuilder builder = new ServerBasedExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) { - @Override protected Class getGemfireFunctionOperationsClass() { - return Object.class; - } - }; + ServerBasedExecutionBeanDefinitionBuilder builder = + new ServerBasedExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) { + + @Override + protected Class getGemfireFunctionOperationsClass() { + return Object.class; + } + }; BeanDefinitionBuilder beanDefinitionBuilder = builder.getGemfireFunctionOperationsBeanDefinitionBuilder(null); @@ -153,7 +151,7 @@ public class ServerBasedExecutionBeanDefinitionBuilderTest { AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition(); assertThat(beanDefinition, is(notNullValue())); - assertThat((Class) beanDefinition.getBeanClass(), is(equalTo(Object.class))); + assertThat(beanDefinition.getBeanClass(), is(equalTo(Object.class))); assertThat(String.valueOf(beanDefinition.getConstructorArgumentValues() .getArgumentValue(0, RuntimeBeanReference.class).getValue()), containsString("TestPool")); @@ -165,32 +163,32 @@ public class ServerBasedExecutionBeanDefinitionBuilderTest { @Test @SuppressWarnings("unchecked") public void getGemfireFunctionOperationsBeanDefinitionBuilderWithCacheAndPool() { + FunctionExecutionConfiguration mockFunctionExecutionConfiguration = mock(FunctionExecutionConfiguration.class, "MockFunctionExecutionConfiguration"); when(mockFunctionExecutionConfiguration.getAttribute(eq("cache"))).thenReturn("TestCache"); when(mockFunctionExecutionConfiguration.getAttribute(eq("pool"))).thenReturn("TestPool"); - when(mockFunctionExecutionConfiguration.getFunctionExecutionInterface()).thenAnswer(new Answer>() { - @Override public Class answer(final InvocationOnMock invocation) throws Throwable { - return Object.class; - } - }); + when(mockFunctionExecutionConfiguration.getFunctionExecutionInterface()).thenAnswer(invocation -> Object.class); - ServerBasedExecutionBeanDefinitionBuilder builder = new ServerBasedExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) { - @Override protected Class getGemfireFunctionOperationsClass() { - return Object.class; - } - }; + ServerBasedExecutionBeanDefinitionBuilder builder = + new ServerBasedExecutionBeanDefinitionBuilder(mockFunctionExecutionConfiguration) { + + @Override + protected Class getGemfireFunctionOperationsClass() { + return Object.class; + } + }; expectedException.expect(IllegalStateException.class); expectedException.expectCause(is(nullValue(Throwable.class))); - expectedException.expectMessage(is(equalTo("invalid configuration for interface java.lang.Object;" + expectedException.expectMessage(is(equalTo("Invalid configuration for interface [java.lang.Object];" + " cannot specify both 'pool' and 'cache'"))); + builder.getGemfireFunctionOperationsBeanDefinitionBuilder(null); verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("cache")); verify(mockFunctionExecutionConfiguration, times(1)).getAttribute(eq("pool")); verify(mockFunctionExecutionConfiguration, times(1)).getFunctionExecutionInterface(); } - }