diff --git a/src/main/java/org/springframework/data/gemfire/DiskStoreFactoryBean.java b/src/main/java/org/springframework/data/gemfire/DiskStoreFactoryBean.java index 6a32a95b..6fd0b6b2 100644 --- a/src/main/java/org/springframework/data/gemfire/DiskStoreFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/DiskStoreFactoryBean.java @@ -40,7 +40,7 @@ import com.gemstone.gemfire.cache.GemFireCache; * @see org.springframework.beans.factory.InitializingBean */ @SuppressWarnings("unused") -public class DiskStoreFactoryBean implements FactoryBean, InitializingBean, BeanNameAware { +public class DiskStoreFactoryBean implements BeanNameAware , FactoryBean, InitializingBean { private Boolean allowForceCompaction; private Boolean autoCompact; @@ -66,7 +66,7 @@ public class DiskStoreFactoryBean implements FactoryBean, Initializin @Override public Class getObjectType() { - return DiskStore.class; + return (diskStore != null ? diskStore.getClass() : DiskStore.class); } @Override @@ -84,33 +84,34 @@ public class DiskStoreFactoryBean implements FactoryBean, Initializin if (allowForceCompaction != null) { diskStoreFactory.setAllowForceCompaction(allowForceCompaction); } + if (autoCompact != null) { + diskStoreFactory.setAutoCompact(autoCompact); + } if (compactionThreshold != null) { diskStoreFactory.setCompactionThreshold(compactionThreshold); } - if (autoCompact != null) { - diskStoreFactory.setAutoCompact(autoCompact); + if (maxOplogSize != null) { + diskStoreFactory.setMaxOplogSize(maxOplogSize); } if (queueSize != null) { diskStoreFactory.setQueueSize(queueSize); } - if (writeBufferSize != null) { - diskStoreFactory.setWriteBufferSize(writeBufferSize); - } if (timeInterval != null) { diskStoreFactory.setTimeInterval(timeInterval); } - if (maxOplogSize != null) { - diskStoreFactory.setMaxOplogSize(maxOplogSize); + if (writeBufferSize != null) { + diskStoreFactory.setWriteBufferSize(writeBufferSize); } if (!CollectionUtils.isEmpty(diskDirs)) { File[] diskDirFiles = new File[diskDirs.size()]; int[] diskDirSizes = new int[diskDirs.size()]; - for (int i = 0; i < diskDirs.size(); i++) { - DiskDir diskDir = diskDirs.get(i); - diskDirFiles[i] = new File(diskDir.location); - diskDirSizes[i] = diskDir.maxSize == null ? DiskStoreFactory.DEFAULT_DISK_DIR_SIZE : diskDir.maxSize; + for (int index = 0; index < diskDirs.size(); index++) { + DiskDir diskDir = diskDirs.get(index); + diskDirFiles[index] = new File(diskDir.location); + diskDirSizes[index] = (diskDir.maxSize != null ? diskDir.maxSize + : DiskStoreFactory.DEFAULT_DISK_DIR_SIZE); } diskStoreFactory.setDiskDirsAndSizes(diskDirFiles, diskDirSizes); @@ -118,7 +119,7 @@ public class DiskStoreFactoryBean implements FactoryBean, Initializin diskStore = diskStoreFactory.create(getName()); - Assert.notNull(diskStore, String.format("The DiskStore with name '%1$s' failed to be created successfully.", + Assert.notNull(diskStore, String.format("DiskStore with name '%1$s' failed to be created successfully.", diskStore.getName())); } @@ -178,15 +179,14 @@ public class DiskStoreFactoryBean implements FactoryBean, Initializin final Integer maxSize; final String location; - public DiskDir(String location, int maxSize) { - this.location = location; - this.maxSize = maxSize; - } - public DiskDir(String location) { this.location = location; this.maxSize = null; } + public DiskDir(String location, int maxSize) { + this.location = location; + this.maxSize = maxSize; + } } } diff --git a/src/main/java/org/springframework/data/gemfire/config/DiskStoreBeanPostProcessor.java b/src/main/java/org/springframework/data/gemfire/config/DiskStoreBeanPostProcessor.java new file mode 100644 index 00000000..55d4acca --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/config/DiskStoreBeanPostProcessor.java @@ -0,0 +1,104 @@ +/* + * 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.io.File; +import java.lang.reflect.Field; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.data.gemfire.DiskStoreFactoryBean.DiskDir; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; + +/** + * The DiskStoreBeanPostProcessor class post processes any GemFire Disk Store DiskDir Spring beans defined + * in the application context to ensure that the Disk Store directory location (disk-dir) actually exists + * before creating the Disk Store. + * + * @author John Blum + * @see org.springframework.beans.factory.config.BeanPostProcessor + * @see org.springframework.data.gemfire.DiskStoreFactoryBean.DiskDir + * @since 1.5.0 + */ +@SuppressWarnings("unused") +public class DiskStoreBeanPostProcessor implements BeanPostProcessor { + + protected final Log log = LogFactory.getLog(getClass()); + + @Override + public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException { + if (log.isDebugEnabled()) { + log.debug(String.format("Post Processing Bean (%1$s) of Type (%2$s) with Name (%3$s)...%n", bean, + ObjectUtils.nullSafeClassName(bean), beanName)); + } + + if (bean instanceof DiskDir) { + createIfNotExists((DiskDir) bean); + } + + return bean; + } + + private void createIfNotExists(final DiskDir diskDirectory) { + String location = readField(diskDirectory, "location"); + + File diskDirectoryFile = new File(location); + + Assert.isTrue(diskDirectoryFile.isDirectory() || diskDirectoryFile.mkdirs(), + String.format("Failed to create Disk Directory (%1$s)%n!", location)); + + if (log.isInfoEnabled()) { + log.info(String.format("The Disk Directory either exists or was created @ Location (%1$s).%n", location)); + } + } + + @SuppressWarnings("unchecked") + private T readField(final Object obj, final String fieldName) { + try { + Class type = obj.getClass(); + Field field; + + do { + field = type.getDeclaredField(fieldName); + type = type.getSuperclass(); // traverse up the object class hierarchy + } + while (field == null && !Object.class.equals(type)); + + if (field == null) { + throw new NoSuchFieldException(String.format("Field (%1$s) does not exist on Object of type (%2$s)!", + fieldName, ObjectUtils.nullSafeClassName(obj))); + } + + field.setAccessible(true); + + return (T) field.get(obj); + } + catch (Exception e) { + throw new RuntimeException(String.format("Failed to read field (%1$s) on Object of type (%2$s)!", + fieldName, ObjectUtils.nullSafeClassName(obj)), e); + } + } + + @Override + public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException { + return bean; + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/config/DiskStoreParser.java b/src/main/java/org/springframework/data/gemfire/config/DiskStoreParser.java index 383c7bd9..1b9a94a5 100644 --- a/src/main/java/org/springframework/data/gemfire/config/DiskStoreParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/DiskStoreParser.java @@ -16,9 +16,12 @@ package org.springframework.data.gemfire.config; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; @@ -33,9 +36,28 @@ import org.w3c.dom.Element; * * @author David Turanski * @author John Blum + * @see org.springframework.beans.factory.support.AbstractBeanDefinition + * @see org.springframework.beans.factory.support.BeanDefinitionBuilder + * @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser + * @see org.springframework.data.gemfire.DiskStoreFactoryBean + * @see org.w3c.dom.Element */ public class DiskStoreParser extends AbstractSingleBeanDefinitionParser { + private static final AtomicBoolean registered = new AtomicBoolean(false); + + private static void registerDiskStoreBeanPostProcessor(final ParserContext parserContext) { + if (registered.compareAndSet(false, true)) { + AbstractBeanDefinition diskStoreBeanPostProcessor = BeanDefinitionBuilder + .genericBeanDefinition(DiskStoreBeanPostProcessor.class) + .setRole(BeanDefinition.ROLE_INFRASTRUCTURE) + .getBeanDefinition(); + + BeanDefinitionReaderUtils.registerWithGeneratedName(diskStoreBeanPostProcessor, + parserContext.getRegistry()); + } + } + @Override protected Class getBeanClass(Element element) { return DiskStoreFactoryBean.class; @@ -45,6 +67,8 @@ public class DiskStoreParser extends AbstractSingleBeanDefinitionParser { protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { super.doParse(element, parserContext, builder); + registerDiskStoreBeanPostProcessor(parserContext); + builder.setLazyInit(false); ParsingUtils.setPropertyReference(element, builder, "cache-ref", "cache"); diff --git a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.5.xsd b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.5.xsd index 0984d689..dfa7dc1d 100644 --- a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.5.xsd +++ b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.5.xsd @@ -1687,6 +1687,13 @@ The maximum size (in megabytes) of data stored in each directory. Default value + + + + + - - - - - - - - - - - - - - - - + +Sets the maximum size in megabytes a single oplog (operation log) is allowed to be. When an oplog is created this +amount of file space will be immediately reserved. + ]]> + + + + + + + + + + diff --git a/src/test/java/org/springframework/data/gemfire/config/DiskStoreBeanPostProcessorTest.java b/src/test/java/org/springframework/data/gemfire/config/DiskStoreBeanPostProcessorTest.java new file mode 100644 index 00000000..79571134 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/config/DiskStoreBeanPostProcessorTest.java @@ -0,0 +1,68 @@ +/* + * 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 static org.junit.Assert.assertTrue; + +import java.io.File; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.data.gemfire.test.GemfireTestApplicationContextInitializer; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.util.FileSystemUtils; + +/** + * The DiskStoreBeanPostProcessorTest class is a test suite of test cases testing the contract and functionality of + * the DiskStoreBeanPostProcessor class. + * + * @author John Blum + * @see org.junit.Test + * @see org.junit.runner.RunWith + * @see org.springframework.data.gemfire.config.DiskStoreBeanPostProcessor + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner + * @since 1.5.0 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(initializers = GemfireTestApplicationContextInitializer.class) +public class DiskStoreBeanPostProcessorTest { + + @BeforeClass + public static void testSuiteSetup() { + assertTrue("Failed to created directory './gemfire/disk-stores/local/ds2'!", + new File("./gemfire/disk-stores/local/ds2").mkdirs()); + } + + @AfterClass + public static void testSuiteTearDown() { + assertTrue("Failed to delete directory './gemfire'!", FileSystemUtils.deleteRecursively(new File("./gemfire"))); + assertTrue("Failed to delete directory './gfe'!", FileSystemUtils.deleteRecursively(new File("./gfe"))); + } + + @Test + public void testDiskStoreDirectoryLocationsExist() { + assertTrue(new File("./gemfire/disk-stores/ds1").isDirectory()); + assertTrue(new File("./gemfire/disk-stores/local/ds2").isDirectory()); + assertTrue(new File("./gemfire/disk-stores/remote/ds2").isDirectory()); + assertTrue(new File("./gfe/ds/local/store3").isDirectory()); + } + +} diff --git a/src/test/resources/org/springframework/data/gemfire/config/DiskStoreBeanPostProcessorTest-context.xml b/src/test/resources/org/springframework/data/gemfire/config/DiskStoreBeanPostProcessorTest-context.xml new file mode 100644 index 00000000..a5495500 --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/config/DiskStoreBeanPostProcessorTest-context.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + +