SGF-749 - Expose SDG's Function annotation configuration as part of the public API for extension purposes.
This commit is contained in:
@@ -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<Class<? extends Annotation>> functionExecutionAnnotationTypes;
|
||||
|
||||
|
||||
static {
|
||||
Set<Class<? extends Annotation>> annotationTypes = new HashSet<Class<? extends Annotation>>(5);
|
||||
|
||||
Set<Class<? extends Annotation>> 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<Class<? extends Annotation>> getFunctionExecutionAnnotationTypes() {
|
||||
public static Set<Class<? extends Annotation>> getFunctionExecutionAnnotationTypes() {
|
||||
return functionExecutionAnnotationTypes;
|
||||
}
|
||||
|
||||
static Set<String> getFunctionExecutionAnnotationTypeNames() {
|
||||
Set<String> functionExecutionTypeNames = new HashSet<String>(getFunctionExecutionAnnotationTypes().size());
|
||||
|
||||
for (Class<? extends Annotation> annotationType : getFunctionExecutionAnnotationTypes()) {
|
||||
functionExecutionTypeNames.add(annotationType.getName());
|
||||
}
|
||||
|
||||
return functionExecutionTypeNames;
|
||||
public static Set<String> getFunctionExecutionAnnotationTypeNames() {
|
||||
return getFunctionExecutionAnnotationTypes().stream().map(Class::getName).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
protected Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
public Collection<ScannedGenericBeanDefinition> 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<ScannedGenericBeanDefinition> result = new HashSet<ScannedGenericBeanDefinition>();
|
||||
Set<ScannedGenericBeanDefinition> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<String> 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<String> packages = new HashSet<String>();
|
||||
Set<String> 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<TypeFilter> 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<TypeFilter> getExcludeFilters() {
|
||||
return parseFilters("excludeFilters");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<TypeFilter> getIncludeFilters() {
|
||||
return parseFilters("includeFilters");
|
||||
}
|
||||
|
||||
private Set<TypeFilter> parseFilters(String attributeName) {
|
||||
|
||||
Set<TypeFilter> result = new HashSet<TypeFilter>();
|
||||
AnnotationAttributes[] filters = attributes.getAnnotationArray(attributeName);
|
||||
AnnotationAttributes[] filters = this.attributes.getAnnotationArray(attributeName);
|
||||
|
||||
Set<TypeFilter> 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<TypeFilter> typeFiltersFor(AnnotationAttributes filterAttributes) {
|
||||
List<TypeFilter> typeFilters = new ArrayList<TypeFilter>();
|
||||
|
||||
FilterType filterType = filterAttributes.getEnum("type");
|
||||
|
||||
List<TypeFilter> 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<Annotation> annoClass = (Class<Annotation>) 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<Annotation> annoClass = (Class<Annotation>) 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<String> getBasePackages();
|
||||
|
||||
|
||||
/**
|
||||
* Returns configured {@link TypeFilter}s
|
||||
* @return include filters
|
||||
*/
|
||||
Iterable<TypeFilter> getIncludeFilters();
|
||||
|
||||
|
||||
/**
|
||||
* Returns configured {@link TypeFilter}s
|
||||
* @return exclude filters
|
||||
*/
|
||||
Iterable<TypeFilter> getExcludeFilters();
|
||||
|
||||
|
||||
/**
|
||||
* Returns configured {@link TypeFilter}s
|
||||
* @return include filters
|
||||
*/
|
||||
Iterable<TypeFilter> 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();
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<TypeFilter> includeFilters;
|
||||
private Iterable<TypeFilter> 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<TypeFilter> includeFilters;
|
||||
private final Iterable<TypeFilter> 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<String> 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<TypeFilter> getIncludeFilters() {
|
||||
return includeFilters;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.gemfire.function.config.FunctionExecutionConfigurationSource#getExcludeFilters()
|
||||
*/
|
||||
@Override
|
||||
public Iterable<TypeFilter> getExcludeFilters() {
|
||||
return excludeFilters;
|
||||
return this.excludeFilters;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.gemfire.function.config.FunctionExecutionConfigurationSource#getIncludeFilters()
|
||||
*/
|
||||
@Override
|
||||
public Iterable<TypeFilter> getIncludeFilters() {
|
||||
return this.includeFilters;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Class<?>>() {
|
||||
@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<Object>) 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<Class<?>>() {
|
||||
@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<Object>) 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<Class<?>>() {
|
||||
@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<Object>) 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<Class<?>>() {
|
||||
@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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user