Additional refactoring to the PdxDiskStoreAwareBeanFactoryPostProcessor class based on code review by David Turnaski in PR #31 for JIRA issue SGF-197.

This commit is contained in:
John Blum
2013-10-31 15:08:12 -07:00
parent 20f24aa3b0
commit 415f23216f
2 changed files with 53 additions and 214 deletions

View File

@@ -17,15 +17,10 @@
package org.springframework.data.gemfire.config;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.data.gemfire.DiskStoreFactoryBean;
import org.springframework.data.gemfire.RegionLookupFactoryBean;
import org.springframework.data.gemfire.util.ArrayUtils;
import org.springframework.data.gemfire.wan.AsyncEventQueueFactoryBean;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -34,26 +29,21 @@ import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.asyncqueue.AsyncEventQueue;
/**
* The PdxDiskStoreAwareBeanFactoryPostProcessor class is a BeanFactoryPostProcessor that modifies all Region bean
* definitions in the Spring BeanFactory to form a dependency on the Cache's PDX Disk Store bean. A persistent Region
* may contain PDX typed data, in which case, the PDX type meta-data stored to disk needs to be loaded before the Region
* having PDX data is loaded from disk.
* The PdxDiskStoreAwareBeanFactoryPostProcessor class is a BeanFactoryPostProcessor that modifies all Async Event Queue,
* Region and Disk Store beans in the Spring container to form a dependency on the Cache's PDX Disk Store bean.
* A persistent Region may contain PDX typed data, in which case, the PDX type meta-data stored to disk needs to be
* loaded before the Region having PDX data is loaded from disk.
* <p/>
* @author John Blum
* @see org.springframework.beans.factory.config.BeanDefinition
* @see org.springframework.beans.factory.config.BeanFactoryPostProcessor
* @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory
* @see com.gemstone.gemfire.cache.DiskStore
* @see com.gemstone.gemfire.cache.Region
* @see com.gemstone.gemfire.cache.asyncqueue.AsyncEventQueue
* @since 1.3.3
*/
@SuppressWarnings("unused")
public class PdxDiskStoreAwareBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
protected static final String DATA_POLICY_PROPERTY = "dataPolicy";
protected static final String DATA_POLICY_NAME_PROPERTY = "dataPolicyName";
protected static final String PERSISTENT_KEYWORD = "PERSISTENT";
protected static final String PERSISTENT_PROPERTY = "persistent";
protected static final String SHORTCUT_PROPERTY = "shortcut";
protected static final String[] EMPTY_STRING_ARRAY = new String[0];
private final String pdxDiskStoreName;
@@ -69,170 +59,48 @@ public class PdxDiskStoreAwareBeanFactoryPostProcessor implements BeanFactoryPos
@Override
public void postProcessBeanFactory(final ConfigurableListableBeanFactory beanFactory) throws BeansException {
Assert.state(!beanFactory.isConfigurationFrozen(),
"The BeanFactory configuration meta-data is frozen and cannot be modified further!");
//postProcessPdxDiskStoreDependencies(beanFactory);
postProcessPdxDiskStoreDependencies(beanFactory, AsyncEventQueue.class, DiskStore.class, Region.class);
//postProcessPdxDiskStoreDependencies(beanFactory, AsyncEventQueueFactoryBean.class, DiskStoreFactoryBean.class,
// RegionLookupFactoryBean.class);
}
private void postProcessPdxDiskStoreDependencies(final ConfigurableListableBeanFactory beanFactory, final Class<?>... beanTypes) {
/**
* Post processes all beans in the Spring container, application context that may potentially have a dependency,
* or requirement on the PDX-based Disk Store being present before the bean itself can be processed and created.
* For instance, Regions that might contained PDX-based Key types require the PDX type meta-data to be loaded
* before the Region's data (Keys) are accessed.
* <p/>
* @param beanFactory the BeanFactory used to evaluate beans in context for PDX Disk Store dependencies.
* @param beanTypes an array of Class types indicating the type of beans to evaluate.
* @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#getBeanNamesForType(Class)
*/
private void postProcessPdxDiskStoreDependencies(final ConfigurableListableBeanFactory beanFactory,
final Class<?>... beanTypes) {
for (Class<?> beanType : beanTypes) {
for (String beanName : beanFactory.getBeanNamesForType(beanType)) {
if (!beanName.equalsIgnoreCase(getPdxDiskStoreName())) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
if (isDiskStore(beanDefinition) || (isPersistent(beanDefinition)
&& !hasDiskStoreReference(beanFactory, beanDefinition))) {
addPdxDiskStoreDependency(beanDefinition);
}
}
}
}
}
// TODO remove
private void postProcessPdxDiskStoreDependencies(final ConfigurableListableBeanFactory beanFactory) {
for (String beanName : beanFactory.getBeanDefinitionNames()) {
// NOTE do not add the PDX Disk Store bean dependency to itself!
if (!beanName.equalsIgnoreCase(getPdxDiskStoreName())) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
// NOTE an optimization to only inspect Region bean definitions for persistent Regions (NOTE, the
// persistent Region might also define a Disk Store, or would depend on the DEFAULT Disk Store,
// which may depend on PDX type meta-data).
// NOTE add the dependency to the Disk Store bean definition in case the Disk Store bean is defined
// before the Region that uses it!
// TODO what else depends on a PDX Disk Store besides Regions?
if (isDiskStore(beanDefinition) || isPersistentAsyncEventQueue(beanDefinition)
|| isPersistentRegion(beanDefinition)) {
// NOTE for simplicity sake, we add a bean dependency to any bean definition for a bean
// (Async Event Queue, Region, Disk Store or otherwise) that may potentially require
// the PDX Disk Store to exist.
// NOTE this logic could be optimized to include Disk Store, persistent Async Event Queues
// and persistent Regions (either by way of 'persistent' attribute, Data Policy
// or [Client]RegionShortcut) that also does not have an explicit Disk Store reference.
addPdxDiskStoreDependency(beanDefinition);
}
}
}
}
private boolean isDiskStore(final BeanDefinition beanDefinition) {
return (beanDefinition instanceof AbstractBeanDefinition
&& isDiskStore((AbstractBeanDefinition) beanDefinition));
}
private boolean isDiskStore(final AbstractBeanDefinition beanDefinition) {
return (beanDefinition.hasBeanClass()
&& (DiskStoreFactoryBean.class.isAssignableFrom(beanDefinition.getBeanClass()))
|| DiskStore.class.isAssignableFrom(beanDefinition.getBeanClass()));
}
// TODO remove
private boolean isPersistentAsyncEventQueue(final BeanDefinition beanDefinition) {
return (beanDefinition instanceof AbstractBeanDefinition
&& isPersistentAsyncEventQueue((AbstractBeanDefinition) beanDefinition));
}
// TODO remove
private boolean isPersistentAsyncEventQueue(final AbstractBeanDefinition beanDefinition) {
return (isAsyncEventQueue(beanDefinition) && isPersistent(beanDefinition));
}
// TODO remove
private boolean isAsyncEventQueue(final AbstractBeanDefinition beanDefinition) {
return (beanDefinition.hasBeanClass()
&& AsyncEventQueueFactoryBean.class.isAssignableFrom(beanDefinition.getBeanClass()));
}
// TODO remove
private boolean isPersistentRegion(final BeanDefinition beanDefinition) {
return (beanDefinition instanceof AbstractBeanDefinition
&& isPersistentRegion((AbstractBeanDefinition) beanDefinition));
}
// TODO remove
private boolean isPersistentRegion(final AbstractBeanDefinition beanDefinition) {
return (isRegion(beanDefinition) && isPersistent(beanDefinition));
}
// TODO remove
// NOTE Class.isAssignableFrom is not null-safe, hence the AbstractBeanDefinition.hasBeanClass call!
private boolean isRegion(final AbstractBeanDefinition beanDefinition) {
return (beanDefinition.hasBeanClass()
&& RegionLookupFactoryBean.class.isAssignableFrom(beanDefinition.getBeanClass()));
}
private boolean hasDiskStoreReference(final ConfigurableListableBeanFactory beanFactory,
final BeanDefinition beanDefinition) {
String diskStoreName = getPropertyValue(beanDefinition, "diskStoreName");
return (StringUtils.hasText(diskStoreName) && beanFactory.containsBeanDefinition(diskStoreName));
}
// TODO will property placeholders be a problem or will the PropertyPlaceholderConfigurer BeanFactoryPostProcessor
// execute before this BeanFactoryPostProcessor???
private boolean isPersistent(final BeanDefinition beanDefinition) {
boolean persistent = getPropertyValue(beanDefinition, DATA_POLICY_PROPERTY, DATA_POLICY_NAME_PROPERTY)
.contains(PERSISTENT_KEYWORD);
persistent |= Boolean.parseBoolean(getPropertyValue(beanDefinition, PERSISTENT_PROPERTY));
persistent |= getPropertyValue(beanDefinition, SHORTCUT_PROPERTY).contains(PERSISTENT_KEYWORD);
return persistent;
}
/**
* Gets the value of a potentially multi-named property on a BeanDefinition returning the first non-null value.
* Adds the PDX Disk Store bean name as a dependency at the beginning of the list of dependencies declared
* by the Bean.
* <p/>
* @param beanDefinition the BeanDefinition of the Bean with the property identified by name(s).
* @param propertyNames a String array containing all the possible names of the property.
* @return the first non-null value of the property, which might have multi-names (aliases).
* @see #getPropertyValue(org.springframework.beans.factory.config.BeanDefinition, String)
*/
private String getPropertyValue(final BeanDefinition beanDefinition, final String... propertyNames) {
String propertyValue = null;
for (String propertyName : propertyNames) {
propertyValue = getPropertyValue(beanDefinition, propertyName);
if (!isNull(propertyValue)) {
break;
}
}
return String.valueOf(propertyValue);
}
/**
* Gets the value of the property identified by name from the Bean's BeanDefinition.
* <p/>
* @param beanDefinition the BeanDefinition containing the configuration meta-data and values of the properties
* for the Bean.
* @param propertyName a String identifying the property by name.
* @return a String value of the named property for the Bean.
* @see #getPropertyValue(org.springframework.beans.factory.config.BeanDefinition, String...)
*/
private String getPropertyValue(final BeanDefinition beanDefinition, final String propertyName) {
PropertyValue propertyValue = beanDefinition.getPropertyValues().getPropertyValue(propertyName);
return String.valueOf(propertyValue != null ? propertyValue.getValue() : null);
}
/**
* Determines whether the specified String value is null. The String value is null if it is a null references
* or is equal to the "null" String irrespective of case or whitespace.
* <p/>
* @param value the String to evaluate for null value.
* @return a boolean indicating whether the String value is null.
*/
private boolean isNull(final String value) {
return (value == null || "null".equalsIgnoreCase(value.trim()));
}
/**
* Adds the PDX Disk Store dependency to the beginning of the list of dependencies declared by the Bean.
* <p/>
* @param beanDefinition the BeanDefinition to add the dependency to the PDX Disk Store on.
* @param beanDefinition the BeanDefinition to add the PDX Disk Store dependency to.
* @see #getDependsOn(org.springframework.beans.factory.config.BeanDefinition)
* @see org.springframework.beans.factory.config.BeanDefinition#setDependsOn(String[])
*/
private void addPdxDiskStoreDependency(final BeanDefinition beanDefinition) {
String[] newDependsOn = (String[]) ArrayUtils.insert(getDependsOn(beanDefinition), 0, getPdxDiskStoreName());
beanDefinition.setDependsOn(newDependsOn);
}
@@ -243,6 +111,7 @@ public class PdxDiskStoreAwareBeanFactoryPostProcessor implements BeanFactoryPos
* @param beanDefinition the BeanDefinition of the Bean containing the dependencies.
* @return an array of Bean names that this Bean depends on, or an empty String array if the dependencies
* are undefined.
* @see #addPdxDiskStoreDependency(org.springframework.beans.factory.config.BeanDefinition)
* @see org.springframework.beans.factory.config.BeanDefinition#getDependsOn()
*/
private String[] getDependsOn(final BeanDefinition beanDefinition) {