SGF-408 - Provide support in the SDG XML namespace to load a pre-defined data set using GemFire Snapshot Service for development and testing purposes.
Initial implementation and unit tests.
This commit is contained in:
@@ -0,0 +1,497 @@
|
||||
/*
|
||||
* Copyright 2010-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;
|
||||
|
||||
import static com.gemstone.gemfire.cache.snapshot.SnapshotOptions.SnapshotFormat;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.gemstone.gemfire.cache.Cache;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.snapshot.CacheSnapshotService;
|
||||
import com.gemstone.gemfire.cache.snapshot.RegionSnapshotService;
|
||||
import com.gemstone.gemfire.cache.snapshot.SnapshotFilter;
|
||||
import com.gemstone.gemfire.cache.snapshot.SnapshotOptions;
|
||||
|
||||
/**
|
||||
* The SnapshotServiceFactoryBean class is a Spring FactoryBean used to configure and create an instance
|
||||
* of the appropriate GemFire Snapshot Service. A CacheSnapshotService is created if the Region is not specified,
|
||||
* otherwise a RegionSnapshotService is used based on the configured Region.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.beans.factory.DisposableBean
|
||||
* @see org.springframework.beans.factory.FactoryBean
|
||||
* @see org.springframework.beans.factory.InitializingBean
|
||||
* @see com.gemstone.gemfire.cache.snapshot.CacheSnapshotService
|
||||
* @see com.gemstone.gemfire.cache.snapshot.RegionSnapshotService
|
||||
* @since 1.7.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class SnapshotServiceFactoryBean<K, V> implements FactoryBean<SnapshotServiceFactoryBean.SnapshotServiceAdapter<K, V>>,
|
||||
InitializingBean, DisposableBean {
|
||||
|
||||
protected static final SnapshotMetadata[] EMPTY_ARRAY = new SnapshotMetadata[0];
|
||||
|
||||
private Cache cache;
|
||||
|
||||
private Region<K, V> region;
|
||||
|
||||
private SnapshotServiceAdapter<K, V> snapshotServiceAdapter;
|
||||
|
||||
private SnapshotMetadata<K, V>[] exports;
|
||||
private SnapshotMetadata<K, V>[] imports;
|
||||
|
||||
/**
|
||||
* Sets a reference to the GemFire Cache for which the snapshot will be taken.
|
||||
*
|
||||
* @param cache the GemFire Cache used to create an instance of CacheSnapshotService.
|
||||
* @throws IllegalArgumentException if the Cache reference is null.
|
||||
* @see com.gemstone.gemfire.cache.Cache
|
||||
* @see #getCache()
|
||||
*/
|
||||
public void setCache(Cache cache) {
|
||||
Assert.notNull(cache, "The GemFire Cache must not be null");
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the GemFire Cache for which the snapshot will be taken.
|
||||
*
|
||||
* @return the GemFire Cache used to create an instance of CacheSnapshotService.
|
||||
* @throws IllegalStateException if the Cache argument is null.
|
||||
* @see com.gemstone.gemfire.cache.Cache
|
||||
* @see #setCache(Cache)
|
||||
*/
|
||||
protected Cache getCache() {
|
||||
Assert.state(cache != null, "The GemFire Cache was not properly initialized");
|
||||
return cache;
|
||||
}
|
||||
|
||||
public void setExports(SnapshotMetadata<K, V>[] exports) {
|
||||
this.exports = exports;
|
||||
}
|
||||
|
||||
protected SnapshotMetadata<K, V>[] getExports() {
|
||||
return nullSafeArray(exports);
|
||||
}
|
||||
|
||||
public void setImports(SnapshotMetadata<K, V>[] imports) {
|
||||
this.imports = imports;
|
||||
}
|
||||
|
||||
protected SnapshotMetadata<K, V>[] getImports() {
|
||||
return nullSafeArray(imports);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a reference to the GemFire Region for which the snapshot will be taken.
|
||||
*
|
||||
* @param region the GemFire Region used to create an instance of the RegionSnapshotService.
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
* @see #getRegion()
|
||||
*/
|
||||
public void setRegion(Region<K, V> region) {
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the GemFire Region for which the snapshot will be taken.
|
||||
*
|
||||
* @return the GemFire Region used to create an instance of the RegionSnapshotService.
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
* @see #getRegion()
|
||||
*/
|
||||
protected Region<K, V> getRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the reference to the GemFire Snapshot Service created by this FactoryBean.
|
||||
*
|
||||
* @return the GemFire Snapshot Service created by this FactoryBean.
|
||||
* @throws Exception if the GemFire Snapshot Service failed to be created.
|
||||
* @see org.springframework.data.gemfire.SnapshotServiceFactoryBean.SnapshotServiceAdapter
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public SnapshotServiceAdapter<K, V> getObject() throws Exception {
|
||||
return snapshotServiceAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of Snapshot Service created by this FactoryBean.
|
||||
*
|
||||
* @return a Class object representing the type of Snapshot Service created by this FactoryBean.
|
||||
* @see org.springframework.data.gemfire.SnapshotServiceFactoryBean.SnapshotServiceAdapter
|
||||
* @see org.springframework.data.gemfire.SnapshotServiceFactoryBean.CacheSnapshotServiceAdapter
|
||||
* @see org.springframework.data.gemfire.SnapshotServiceFactoryBean.RegionSnapshotServiceAdapter
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return (snapshotServiceAdapter != null ? snapshotServiceAdapter.getClass() : SnapshotServiceAdapter.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines this this FactoryBean creates single GemFire Snapshot Service instances.
|
||||
*
|
||||
* @return true.
|
||||
*/
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and initializes the GemFire Snapshot Service used to take a snapshot of the configured Cache
|
||||
* or Region if initialized. In addition, this initialization method will perform the actual import.
|
||||
*
|
||||
* @throws Exception if the construction and initialization of the GemFire Snapshot Service fails.
|
||||
* @see org.springframework.data.gemfire.SnapshotServiceFactoryBean.SnapshotServiceAdapter#doImport(SnapshotMetadata[])
|
||||
* @see #getImports()
|
||||
* @see #create()
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
snapshotServiceAdapter = create();
|
||||
snapshotServiceAdapter.doImport(getImports());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an appropriate instance of the SnapshotServiceAdapter based on the FactoryBean configuration. If
|
||||
* a Region has not been specified, then a GemFire Snapshot Service for the Cache is constructed, otherwise
|
||||
* the GemFire Snapshot Service for the configured Region is used.
|
||||
*
|
||||
* @return a SnapshotServiceAdapter wrapping the appropriate GemFire Snapshot Service (either Cache or Region)
|
||||
* depending on the FactoryBean configuration.
|
||||
* @see #wrap(CacheSnapshotService)
|
||||
* @see #wrap(RegionSnapshotService)
|
||||
* @see #getRegion()
|
||||
*/
|
||||
protected SnapshotServiceAdapter create() {
|
||||
Region<K, V> region = getRegion();
|
||||
return (region != null ? wrap(region.getSnapshotService()) : wrap(getCache().getSnapshotService()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the GemFire CacheSnapshotService into an appropriate Adapter to ...
|
||||
*
|
||||
* @param cacheSnapshotService the GemFire CacheSnapshotService to wrap.
|
||||
* @return a SnapshotServiceAdapter wrapping the GemFire CacheSnapshotService.
|
||||
* @see org.springframework.data.gemfire.SnapshotServiceFactoryBean.SnapshotServiceAdapter
|
||||
* @see org.springframework.data.gemfire.SnapshotServiceFactoryBean.CacheSnapshotServiceAdapter
|
||||
* @see com.gemstone.gemfire.cache.snapshot.CacheSnapshotService
|
||||
*/
|
||||
protected SnapshotServiceAdapter<Object, Object> wrap(CacheSnapshotService cacheSnapshotService) {
|
||||
return new CacheSnapshotServiceAdapter(cacheSnapshotService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the GemFire RegionSnapshotService into an appropriate Adapter to ...
|
||||
*
|
||||
* @param regionSnapshotService the GemFire RegionSnapshotService to wrap.
|
||||
* @return a SnapshotServiceAdapter wrapping the GemFire RegionSnapshotService.
|
||||
* @see org.springframework.data.gemfire.SnapshotServiceFactoryBean.SnapshotServiceAdapter
|
||||
* @see org.springframework.data.gemfire.SnapshotServiceFactoryBean.RegionSnapshotServiceAdapter
|
||||
* @see com.gemstone.gemfire.cache.snapshot.RegionSnapshotService
|
||||
*/
|
||||
protected SnapshotServiceAdapter<K, V> wrap(RegionSnapshotService<K, V> regionSnapshotService) {
|
||||
return new RegionSnapshotServiceAdapter(regionSnapshotService);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
@SuppressWarnings("unchecked")
|
||||
protected SnapshotMetadata<K, V>[] nullSafeArray(SnapshotMetadata<K, V>[] configurations) {
|
||||
return (configurations != null ? configurations : EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an export of the GemFire Cache or Region if configured.
|
||||
*
|
||||
* @throws Exception if the Cache/Region data export operation fails.
|
||||
* @see org.springframework.data.gemfire.SnapshotServiceFactoryBean.SnapshotServiceAdapter#doExport(SnapshotMetadata[])
|
||||
* @see #getExports()
|
||||
* @see #getObject()
|
||||
*/
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
getObject().doExport(getExports());
|
||||
}
|
||||
|
||||
public interface SnapshotServiceAdapter<K, V> {
|
||||
|
||||
SnapshotOptions<K, V> createOptions();
|
||||
|
||||
void doExport(SnapshotMetadata<K, V>[] configurations);
|
||||
|
||||
void doImport(SnapshotMetadata<K, V>[] configurations);
|
||||
|
||||
void load(File directory, SnapshotFormat format);
|
||||
|
||||
void load(SnapshotFormat format, SnapshotOptions<K, V> options, File... snapshots);
|
||||
|
||||
void save(File location, SnapshotFormat format);
|
||||
|
||||
void save(File location, SnapshotFormat format, SnapshotOptions<K, V> options);
|
||||
|
||||
}
|
||||
|
||||
protected class CacheSnapshotServiceAdapter implements SnapshotServiceAdapter<Object, Object> {
|
||||
|
||||
private final CacheSnapshotService snapshotService;
|
||||
|
||||
public CacheSnapshotServiceAdapter(CacheSnapshotService snapshotService) {
|
||||
Assert.notNull(snapshotService, "The backing CacheSnapshotService must not be null");
|
||||
this.snapshotService = snapshotService;
|
||||
}
|
||||
|
||||
protected CacheSnapshotService getSnapshotService() {
|
||||
return snapshotService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SnapshotOptions<Object, Object> createOptions() {
|
||||
return getSnapshotService().createOptions();
|
||||
}
|
||||
|
||||
protected SnapshotOptions<Object, Object> createOptions(SnapshotFilter<Object, Object> filter) {
|
||||
return createOptions().setFilter(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doExport(SnapshotMetadata<Object, Object>[] configurations) {
|
||||
if (!ObjectUtils.isEmpty(configurations)) {
|
||||
for (SnapshotMetadata<Object, Object> configuration : configurations) {
|
||||
save(configuration.getLocation(), configuration.getFormat(),
|
||||
createOptions(configuration.getFilter()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doImport(SnapshotMetadata<Object, Object>[] configurations) {
|
||||
if (!ObjectUtils.isEmpty(configurations)) {
|
||||
for (SnapshotMetadata<Object, Object> configuration : configurations) {
|
||||
if (configuration.isDirectory()) {
|
||||
load(configuration.getLocation(), configuration.getFormat());
|
||||
}
|
||||
else {
|
||||
load(configuration.getFormat(), createOptions(configuration.getFilter()),
|
||||
configuration.getLocation());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(File directory, SnapshotFormat format) {
|
||||
try {
|
||||
getSnapshotService().load(directory, format);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new RuntimeException(String.format(
|
||||
"Failed to load snapshots from directory (%1$s) in format (%2$s)", directory, format), t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(SnapshotFormat format, SnapshotOptions<Object, Object> options,
|
||||
File... snapshots) {
|
||||
try {
|
||||
getSnapshotService().load(snapshots, format, options);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new RuntimeException(String.format(
|
||||
"Failed to load snapshots (%1$s) in format (%2$s) with options (%3$s)",
|
||||
Arrays.toString(snapshots), format, options), t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(File directory, SnapshotFormat format) {
|
||||
try {
|
||||
getSnapshotService().save(directory, format);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new RuntimeException(String.format(
|
||||
"Failed to save snapshots to directory (%1$s) using format (%2$s)", directory, format), t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(File directory, SnapshotFormat format,
|
||||
SnapshotOptions<Object, Object> options) {
|
||||
try {
|
||||
getSnapshotService().save(directory, format, options);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new RuntimeException(String.format(
|
||||
"Failed to save snapshots to directory (%1$s) using format (%2$s) with options (%3$s)",
|
||||
directory, format, options), t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected class RegionSnapshotServiceAdapter implements SnapshotServiceAdapter<K, V> {
|
||||
|
||||
private final RegionSnapshotService<K, V> snapshotService;
|
||||
|
||||
public RegionSnapshotServiceAdapter(RegionSnapshotService<K, V> snapshotService) {
|
||||
Assert.notNull(snapshotService, "The backing RegionSnapshotService must not be null");
|
||||
this.snapshotService = snapshotService;
|
||||
}
|
||||
|
||||
protected RegionSnapshotService<K, V> getSnapshotService() {
|
||||
return snapshotService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SnapshotOptions<K, V> createOptions() {
|
||||
return getSnapshotService().createOptions();
|
||||
}
|
||||
|
||||
protected SnapshotOptions<K, V> createOptions(SnapshotFilter<K, V> filter) {
|
||||
return createOptions().setFilter(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doExport(final SnapshotMetadata<K, V>[] configurations) {
|
||||
if (!ObjectUtils.isEmpty(configurations)) {
|
||||
for (SnapshotMetadata<K, V> configuration : configurations) {
|
||||
Assert.isTrue(configuration.isFile(), String.format("The export location (%1$s) must be a file",
|
||||
configuration.getLocation()));
|
||||
save(configuration.getLocation(), configuration.getFormat(), createOptions(configuration.getFilter()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doImport(final SnapshotMetadata<K, V>[] configurations) {
|
||||
if (!ObjectUtils.isEmpty(configurations)) {
|
||||
for (SnapshotMetadata<K, V> configuration : configurations) {
|
||||
Assert.isTrue(configuration.isFile(), String.format("The import location (%1$s) must be a file",
|
||||
configuration.getLocation()));
|
||||
load(configuration.getFormat(), createOptions(configuration.getFilter()), configuration.getLocation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(File snapshot, SnapshotFormat format) {
|
||||
try {
|
||||
getSnapshotService().load(snapshot, format);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new RuntimeException(String.format(
|
||||
"Failed to load snapshot from file (%1$s) in format (%2$s)", snapshot, format), t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(SnapshotFormat format, SnapshotOptions<K, V> options, File... snapshots) {
|
||||
try {
|
||||
for (File snapshot : snapshots) {
|
||||
getSnapshotService().load(snapshot, format, options);
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new RuntimeException(String.format(
|
||||
"Failed to load snapshots (%1$s) in format (%2$s) with options (%3$s)",
|
||||
Arrays.toString(snapshots), format, options), t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(File snapshot, SnapshotFormat format) {
|
||||
try {
|
||||
getSnapshotService().save(snapshot, format);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new RuntimeException(String.format(
|
||||
"Failed to save snapshots to directory (%1$s) using format (%2$s)", snapshot, format), t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(File snapshot, SnapshotFormat format, SnapshotOptions<K, V> options) {
|
||||
try {
|
||||
getSnapshotService().save(snapshot, format, options);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new RuntimeException(String.format(
|
||||
"Failed to save snapshots to directory (%1$s) using format (%2$s) with options (%3$s)",
|
||||
snapshot, format, options), t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class SnapshotMetadata<K, V> {
|
||||
|
||||
private final File location;
|
||||
|
||||
private final SnapshotFilter<K, V> filter;
|
||||
|
||||
private final SnapshotFormat format;
|
||||
|
||||
public SnapshotMetadata(File location, SnapshotFilter<K, V> filter, SnapshotFormat format) {
|
||||
Assert.isTrue(location != null && location.exists(), String.format(
|
||||
"The File location (%1$s) must exist", location));
|
||||
|
||||
this.location = location;
|
||||
this.filter = filter;
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public boolean isDirectory() {
|
||||
return getLocation().isDirectory();
|
||||
}
|
||||
|
||||
public boolean isFile() {
|
||||
return getLocation().isFile();
|
||||
}
|
||||
|
||||
public File getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public boolean isFilterPresent() {
|
||||
return (getFilter() != null);
|
||||
}
|
||||
|
||||
public SnapshotFilter<K, V> getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
public SnapshotFormat getFormat() {
|
||||
return (format != null ? format : SnapshotFormat.GEMFIRE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{ @type = %1$s, location = %2$s, filter = %2$s, format = %4$s }",
|
||||
getClass().getName(), getLocation().getAbsolutePath(), getFilter(), getFormat());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,5 +40,6 @@ class GemfireDataNamespaceHandler extends NamespaceHandlerSupport {
|
||||
registerBeanDefinitionParser("function-executions", new FunctionExecutionBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("datasource", new GemfireDataSourceParser());
|
||||
registerBeanDefinitionParser("json-region-autoproxy", new GemfireRegionAutoProxyParser());
|
||||
registerBeanDefinitionParser("snapshot-service", new SnapshotServiceParser());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,9 @@ abstract class ParsingUtils {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ParsingUtils.class);
|
||||
|
||||
protected static final String CACHE_PROPERTY_NAME = "cache";
|
||||
protected static final String CACHE_REF_ATTRIBUTE_NAME = "cache-ref";
|
||||
|
||||
static void setPropertyReference(Element element, BeanDefinitionBuilder builder, String attributeName,
|
||||
String propertyName) {
|
||||
|
||||
@@ -416,7 +419,7 @@ abstract class ParsingUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void parseCompressor(ParserContext parserContext, Element element,
|
||||
static void parseCompressor(ParserContext parserContext, Element element,
|
||||
BeanDefinitionBuilder regionAttributesBuilder) {
|
||||
|
||||
Element compressorElement = DomUtils.getChildElementByTagName(element, "compressor");
|
||||
@@ -427,8 +430,16 @@ abstract class ParsingUtils {
|
||||
}
|
||||
}
|
||||
|
||||
static String resolveCacheReference(final String cacheRef) {
|
||||
return (StringUtils.hasText(cacheRef) ? cacheRef : GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME);
|
||||
static void setCacheReference(Element element, BeanDefinitionBuilder builder) {
|
||||
builder.addPropertyReference(CACHE_PROPERTY_NAME, resolveCacheReference(element));
|
||||
}
|
||||
|
||||
static String resolveCacheReference(Element element) {
|
||||
return resolveCacheReference(element.getAttribute(CACHE_REF_ATTRIBUTE_NAME));
|
||||
}
|
||||
|
||||
static String resolveCacheReference(String cacheReference) {
|
||||
return (StringUtils.hasText(cacheReference) ? cacheReference : GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2010-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.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.data.gemfire.SnapshotServiceFactoryBean;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Parser for <gfe-data:snapshot-service> bean definition elements in Spring XML config.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.beans.factory.config.BeanDefinition
|
||||
* @see org.springframework.beans.factory.support.BeanDefinitionBuilder
|
||||
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser
|
||||
* @see org.springframework.beans.factory.xml.ParserContext
|
||||
* @see org.springframework.data.gemfire.SnapshotServiceFactoryBean
|
||||
* @since 1.7.0
|
||||
*/
|
||||
class SnapshotServiceParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
@Override
|
||||
protected Class<?> getBeanClass(final Element element) {
|
||||
return SnapshotServiceFactoryBean.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
super.doParse(element, parserContext, builder);
|
||||
|
||||
ParsingUtils.setCacheReference(element, builder);
|
||||
ParsingUtils.setPropertyReference(element, builder, "region-ref", "region");
|
||||
builder.addPropertyValue("exports", parseExports(element, parserContext));
|
||||
builder.addPropertyValue("imports", parseImports(element, parserContext));
|
||||
}
|
||||
|
||||
private ManagedList<BeanDefinition> parseExports(Element element, ParserContext parserContext) {
|
||||
return parseSnapshots(element, parserContext, "export-snapshot");
|
||||
}
|
||||
|
||||
private ManagedList<BeanDefinition> parseImports(Element element, ParserContext parserContext) {
|
||||
return parseSnapshots(element, parserContext, "import-snapshot");
|
||||
}
|
||||
|
||||
private ManagedList<BeanDefinition> parseSnapshots(Element element, ParserContext parserContext,
|
||||
String childTagName) {
|
||||
|
||||
ManagedList<BeanDefinition> snapshotBeans = new ManagedList<BeanDefinition>();
|
||||
|
||||
for (Element childElement : DomUtils.getChildElementsByTagName(element, childTagName)) {
|
||||
snapshotBeans.add(parseSnapshotMetadata(childElement, parserContext));
|
||||
}
|
||||
|
||||
return snapshotBeans;
|
||||
}
|
||||
|
||||
private BeanDefinition parseSnapshotMetadata(Element snapshotMetadataElement, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder snapshotMetadataBuilder = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
SnapshotServiceFactoryBean.SnapshotMetadata.class);
|
||||
|
||||
ParsingUtils.setPropertyValue(snapshotMetadataElement, snapshotMetadataBuilder, "location");
|
||||
ParsingUtils.parseRefOrNestedBeanDeclaration(parserContext, snapshotMetadataElement, snapshotMetadataBuilder,
|
||||
"filter-ref");
|
||||
ParsingUtils.setPropertyValue(snapshotMetadataElement, snapshotMetadataBuilder, "format");
|
||||
|
||||
return snapshotMetadataBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -63,7 +63,6 @@
|
||||
Enables component scanning for annotated function execution interfaces.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="include-filter" type="context:filterType" minOccurs="0" maxOccurs="unbounded">
|
||||
@@ -175,4 +174,64 @@ native GemFire PdxInstance type. True, by default but will incur significant ove
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<!-- GemFire Cache & Region Snapshot Service support-->
|
||||
<xsd:element name="snapshot-service">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Access to GemFire's Snapshot Service for taking snapshots of GemFire Cache and Region data.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="import-snapshot" type="snapshotMetadataType" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Specifies meta-data for a snapshot import.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="export-snapshot" type="snapshotMetadataType" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Specifies meta-data for a snapshot export.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="cache-ref" type="xsd:string" use="optional" default="gemfireCache">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
(Optional) Name of the GemFire Cache bean from which to extract data and record a snapshot (by default 'gemfireCache').
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="region-ref" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
(Optional) Name of the GemFire Region bean from which to extract data and record a snapshot.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:complexType name="snapshotMetadataType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Declares an element type defining snapshot meta-data.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:sequence>
|
||||
<xsd:any namespace="##other" processContents="skip" minOccurs="0" maxOccurs="1">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Inner bean definition. The nested declaration serves as an alternative to bean references (using
|
||||
both in the same definition) is illegal.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:any>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="location" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="filter-ref" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="format" type="xsd:string" use="optional" default="GEMFIRE"/>
|
||||
</xsd:complexType>
|
||||
</xsd:schema>
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright 2010-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;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.hamcrest.CoreMatchers.sameInstance;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import com.gemstone.gemfire.cache.Cache;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.snapshot.CacheSnapshotService;
|
||||
import com.gemstone.gemfire.cache.snapshot.RegionSnapshotService;
|
||||
import com.gemstone.gemfire.cache.snapshot.SnapshotFilter;
|
||||
import com.gemstone.gemfire.cache.snapshot.SnapshotOptions;
|
||||
|
||||
/**
|
||||
* The SnapshotServiceFactoryBeanTest class is a test suite of test cases testing the contract and functionality
|
||||
* of the SnapshotServiceFactoryBean class.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Rule
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.data.gemfire.SnapshotServiceFactoryBean
|
||||
* @since 1.7.0
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public class SnapshotServiceFactoryBeanTest {
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
private SnapshotServiceFactoryBean<Object, Object> factoryBean = new SnapshotServiceFactoryBean<Object, Object>();
|
||||
|
||||
protected <K, V> SnapshotServiceFactoryBean.SnapshotMetadata<K, V> newSnapshotMetadata() {
|
||||
return newSnapshotMetadata(new File(System.getProperty("user.dir")));
|
||||
}
|
||||
|
||||
protected <K, V> SnapshotServiceFactoryBean.SnapshotMetadata<K, V> newSnapshotMetadata(File location) {
|
||||
return newSnapshotMetadata(location, null);
|
||||
}
|
||||
|
||||
protected <K, V> SnapshotServiceFactoryBean.SnapshotMetadata<K, V> newSnapshotMetadata(File location,
|
||||
SnapshotFilter<K, V> filter) {
|
||||
return newSnapshotMetadata(location, filter, SnapshotOptions.SnapshotFormat.GEMFIRE);
|
||||
}
|
||||
|
||||
protected <K, V> SnapshotServiceFactoryBean.SnapshotMetadata<K, V> newSnapshotMetadata(File location,
|
||||
SnapshotFilter<K, V> filter, SnapshotOptions.SnapshotFormat format) {
|
||||
return new SnapshotServiceFactoryBean.SnapshotMetadata<K, V>(location, filter, format);
|
||||
}
|
||||
|
||||
protected <K, V> SnapshotServiceFactoryBean.SnapshotMetadata<K, V>[] toArray(
|
||||
SnapshotServiceFactoryBean.SnapshotMetadata<K, V>... metadata) {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
factoryBean.setExports(null);
|
||||
factoryBean.setImports(null);
|
||||
factoryBean.setRegion(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setCacheToNull() {
|
||||
expectedException.expect(IllegalArgumentException.class);
|
||||
expectedException.expectCause(is(nullValue(Throwable.class)));
|
||||
expectedException.expectMessage("The GemFire Cache must not be null");
|
||||
factoryBean.setCache(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCacheWhenUninitialized() {
|
||||
expectedException.expect(IllegalStateException.class);
|
||||
expectedException.expectCause(is(nullValue(Throwable.class)));
|
||||
expectedException.expectMessage("The GemFire Cache was not properly initialized");
|
||||
factoryBean.getCache();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAndGetCacheSuccessfully() {
|
||||
Cache mockCache = mock(Cache.class, "MockCache");
|
||||
SnapshotServiceFactoryBean factoryBean = new SnapshotServiceFactoryBean();
|
||||
|
||||
factoryBean.setCache(mockCache);
|
||||
|
||||
assertThat(factoryBean.getCache(), is(sameInstance(mockCache)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAndGetExports() {
|
||||
SnapshotServiceFactoryBean.SnapshotMetadata[] actualExports = factoryBean.getExports();
|
||||
|
||||
assertThat(actualExports, is(notNullValue()));
|
||||
assertThat(actualExports.length, is(equalTo(0)));
|
||||
|
||||
SnapshotServiceFactoryBean.SnapshotMetadata[] expectedExports = toArray(newSnapshotMetadata());
|
||||
|
||||
factoryBean.setExports(expectedExports);
|
||||
actualExports = factoryBean.getExports();
|
||||
|
||||
assertThat(actualExports, is(sameInstance(expectedExports)));
|
||||
|
||||
factoryBean.setExports(null);
|
||||
actualExports = factoryBean.getExports();
|
||||
|
||||
assertThat(actualExports, is(not(sameInstance(expectedExports))));
|
||||
assertThat(actualExports, is(notNullValue()));
|
||||
assertThat(actualExports.length, is(equalTo(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAndGetImports() {
|
||||
SnapshotServiceFactoryBean.SnapshotMetadata[] actualImports = factoryBean.getImports();
|
||||
|
||||
assertThat(actualImports, is(notNullValue()));
|
||||
assertThat(actualImports.length, is(equalTo(0)));
|
||||
|
||||
SnapshotServiceFactoryBean.SnapshotMetadata[] expectedImports = toArray(newSnapshotMetadata());
|
||||
|
||||
factoryBean.setImports(expectedImports);
|
||||
actualImports = factoryBean.getImports();
|
||||
|
||||
assertThat(actualImports, is(sameInstance(expectedImports)));
|
||||
|
||||
factoryBean.setImports(null);
|
||||
actualImports = factoryBean.getImports();
|
||||
|
||||
assertThat(actualImports, is(not(sameInstance(expectedImports))));
|
||||
assertThat(actualImports, is(notNullValue()));
|
||||
assertThat(actualImports.length, is(equalTo(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAndGetRegionSuccessfully() {
|
||||
assertThat(factoryBean.getRegion(), is(nullValue()));
|
||||
|
||||
Region<Object, Object> mockRegion = mock(Region.class, "MockRegion");
|
||||
|
||||
factoryBean.setRegion(mockRegion);
|
||||
|
||||
assertThat(factoryBean.getRegion(), is(sameInstance(mockRegion)));
|
||||
|
||||
factoryBean.setRegion(null);
|
||||
|
||||
assertThat(factoryBean.getRegion(), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullSafeArrayWithNonNullArray() {
|
||||
SnapshotServiceFactoryBean.SnapshotMetadata[] expectedConfigurations =
|
||||
new SnapshotServiceFactoryBean.SnapshotMetadata[0];
|
||||
|
||||
assertThat(factoryBean.nullSafeArray(expectedConfigurations), is(sameInstance(expectedConfigurations)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullSafeArrayWithNullArray() {
|
||||
assertThat(factoryBean.nullSafeArray(null), is(equalTo(SnapshotServiceFactoryBean.EMPTY_ARRAY)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrapNullCacheSnapshotService() {
|
||||
expectedException.expect(IllegalArgumentException.class);
|
||||
expectedException.expectCause(is(nullValue(Throwable.class)));
|
||||
expectedException.expectMessage("The backing CacheSnapshotService must not be null");
|
||||
factoryBean.wrap((CacheSnapshotService) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrapNullRegionSnapshotService() {
|
||||
expectedException.expect(IllegalArgumentException.class);
|
||||
expectedException.expectCause(is(nullValue(Throwable.class)));
|
||||
expectedException.expectMessage("The backing RegionSnapshotService must not be null");
|
||||
factoryBean.wrap((RegionSnapshotService) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSingletonIsTrue() {
|
||||
assertThat(factoryBean.isSingleton(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createCacheSnapshotServiceAndImportOnInitialization() throws Exception {
|
||||
Cache mockCache = mock(Cache.class, "MockCache");
|
||||
CacheSnapshotService mockCacheSnapshotService = mock(CacheSnapshotService.class, "MockCacheSnapshotService");
|
||||
|
||||
when(mockCache.getSnapshotService()).thenReturn(mockCacheSnapshotService);
|
||||
|
||||
File userHomeDirectory = new File(System.getProperty("user.home"));
|
||||
|
||||
SnapshotServiceFactoryBean.SnapshotMetadata<Object, Object>[] expectedImports = toArray(
|
||||
newSnapshotMetadata(userHomeDirectory));
|
||||
|
||||
SnapshotServiceFactoryBean<Object, Object> factoryBean = new SnapshotServiceFactoryBean<Object, Object>();
|
||||
|
||||
factoryBean.setCache(mockCache);
|
||||
factoryBean.setImports(expectedImports);
|
||||
factoryBean.setRegion(null);
|
||||
|
||||
assertThat(factoryBean.getObject(), is(nullValue()));
|
||||
assertThat((Class<SnapshotServiceFactoryBean.SnapshotServiceAdapter>) factoryBean.getObjectType(),
|
||||
is(equalTo(SnapshotServiceFactoryBean.SnapshotServiceAdapter.class)));
|
||||
|
||||
factoryBean.afterPropertiesSet();
|
||||
|
||||
assertThat(factoryBean.getObject(), is(instanceOf(SnapshotServiceFactoryBean.CacheSnapshotServiceAdapter.class)));
|
||||
assertThat((Class<SnapshotServiceFactoryBean.CacheSnapshotServiceAdapter>) factoryBean.getObjectType(),
|
||||
is(equalTo(SnapshotServiceFactoryBean.CacheSnapshotServiceAdapter.class)));
|
||||
|
||||
verify(mockCache, times(1)).getSnapshotService();
|
||||
verify(mockCacheSnapshotService, times(1)).load(eq(userHomeDirectory), eq(SnapshotOptions.SnapshotFormat.GEMFIRE));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void createRegionSnapshotServiceAndImportOnInitialization() throws Exception {
|
||||
Cache mockCache = mock(Cache.class, "MockCache");
|
||||
Region mockRegion = mock(Region.class, "MockRegion");
|
||||
RegionSnapshotService mockRegionSnapshotService = mock(RegionSnapshotService.class, "MockRegionSnapshotService");
|
||||
SnapshotFilter mockFilter = mock(SnapshotFilter.class, "MockSnapshotFilter");
|
||||
SnapshotOptions mockSnapshotOptions = mock(SnapshotOptions.class, "MockSnapshotOptions");
|
||||
|
||||
when(mockCache.getSnapshotService()).thenThrow(new UnsupportedOperationException("operation not supported"));
|
||||
when(mockRegion.getSnapshotService()).thenReturn(mockRegionSnapshotService);
|
||||
when(mockRegionSnapshotService.createOptions()).thenReturn(mockSnapshotOptions);
|
||||
when(mockSnapshotOptions.setFilter(any(SnapshotFilter.class))).thenReturn(mockSnapshotOptions);
|
||||
|
||||
File snapshot = File.createTempFile("snapshot", "dat");
|
||||
|
||||
snapshot.deleteOnExit();
|
||||
|
||||
SnapshotServiceFactoryBean.SnapshotMetadata<Object, Object>[] expectedImports = toArray(
|
||||
newSnapshotMetadata(snapshot, mockFilter));
|
||||
|
||||
SnapshotServiceFactoryBean<Object, Object> factoryBean = new SnapshotServiceFactoryBean<Object, Object>();
|
||||
|
||||
factoryBean.setCache(mockCache);
|
||||
factoryBean.setImports(expectedImports);
|
||||
factoryBean.setRegion(mockRegion);
|
||||
|
||||
assertThat(factoryBean.getObject(), is(nullValue()));
|
||||
assertThat((Class<SnapshotServiceFactoryBean.SnapshotServiceAdapter>) factoryBean.getObjectType(),
|
||||
is(equalTo(SnapshotServiceFactoryBean.SnapshotServiceAdapter.class)));
|
||||
|
||||
factoryBean.afterPropertiesSet();
|
||||
|
||||
assertThat(factoryBean.getObject(),
|
||||
is(instanceOf(SnapshotServiceFactoryBean.RegionSnapshotServiceAdapter.class)));
|
||||
assertThat((Class<SnapshotServiceFactoryBean.RegionSnapshotServiceAdapter>) factoryBean.getObjectType(),
|
||||
is(equalTo(SnapshotServiceFactoryBean.RegionSnapshotServiceAdapter.class)));
|
||||
|
||||
verify(mockCache, never()).getSnapshotService();
|
||||
verify(mockRegion, times(1)).getSnapshotService();
|
||||
verify(mockRegionSnapshotService, times(1)).createOptions();
|
||||
verify(mockRegionSnapshotService, times(1)).load(eq(snapshot),
|
||||
eq(SnapshotOptions.SnapshotFormat.GEMFIRE), eq(mockSnapshotOptions));
|
||||
verify(mockSnapshotOptions, times(1)).setFilter(eq(mockFilter));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user