forked from cloudfoundry/java-buildpack-auto-reconfiguration
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Split CloudAutoStagingBeanFactoryPostProcessor into multiple classes (without changing any functionality) - Replace a single MongoDbFactory with one connecting to a mongo cloud service bound to the current application Change-Id: I22f4a9970471f4d0ddf896fd97eedb1fdc8da66b
- Loading branch information
Jennifer Hickey
committed
Sep 13, 2011
1 parent
d75dffc
commit 8f5a207
Showing
13 changed files
with
786 additions
and
339 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
334 changes: 12 additions & 322 deletions
334
.../main/java/org/cloudfoundry/reconfiguration/CloudAutoStagingBeanFactoryPostProcessor.java
Large diffs are not rendered by default.
Oops, something went wrong.
27 changes: 27 additions & 0 deletions
27
.../auto-reconfiguration-core/src/main/java/org/cloudfoundry/reconfiguration/Configurer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
* Copyright (c) 2009-2011 VMware, Inc. | ||
*/ | ||
package org.cloudfoundry.reconfiguration; | ||
|
||
import org.springframework.beans.factory.support.DefaultListableBeanFactory; | ||
|
||
/** | ||
* | ||
* A {@link Configurer} reconfigures certain beans in a specified | ||
* {@link DefaultListableBeanFactory} | ||
* | ||
* @author Jennifer Hickey | ||
* | ||
*/ | ||
public interface Configurer { | ||
|
||
/** | ||
* Reconfigures beans in the specified {@link DefaultListableBeanFactory} | ||
* | ||
* @param beanFactory | ||
* The {@link DefaultListableBeanFactory} containing beans which | ||
* may need to be configured | ||
* @return true if any beans were reconfigured | ||
*/ | ||
boolean configure(DefaultListableBeanFactory beanFactory); | ||
} |
221 changes: 221 additions & 0 deletions
221
...reconfiguration-core/src/main/java/org/cloudfoundry/reconfiguration/PropertyReplacer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
/* | ||
* Copyright (c) 2009-2011 VMware, Inc. | ||
*/ | ||
package org.cloudfoundry.reconfiguration; | ||
|
||
import java.io.IOException; | ||
import java.io.StringReader; | ||
import java.util.Map; | ||
import java.util.Properties; | ||
|
||
import org.springframework.beans.MutablePropertyValues; | ||
import org.springframework.beans.PropertyValue; | ||
import org.springframework.beans.PropertyValues; | ||
import org.springframework.beans.factory.BeanFactory; | ||
import org.springframework.beans.factory.config.BeanDefinition; | ||
import org.springframework.beans.factory.config.BeanDefinitionHolder; | ||
import org.springframework.beans.factory.config.BeanReference; | ||
import org.springframework.beans.factory.config.PropertiesFactoryBean; | ||
import org.springframework.beans.factory.config.TypedStringValue; | ||
import org.springframework.beans.factory.support.DefaultListableBeanFactory; | ||
import org.springframework.beans.factory.support.ManagedList; | ||
import org.springframework.beans.factory.support.ManagedProperties; | ||
import org.springframework.core.io.support.PropertiesLoaderUtils; | ||
|
||
/** | ||
* Replaces a bean property with value type {@link ManagedProperties} with a | ||
* specified set of {@link ManagedProperties} | ||
* | ||
* @author Ramnivas Laddad | ||
* @author Xin Li | ||
* @author Jennifer Hickey | ||
* | ||
*/ | ||
public class PropertyReplacer { | ||
|
||
/** | ||
* Replaces a bean property with value type {@link ManagedProperties} with a | ||
* specified set of {@link ManagedProperties} | ||
* | ||
* @param beanFactory | ||
* The {@link DefaultListableBeanFactory} containing the beans to | ||
* evaluate for property replacements | ||
* @param beanClassName | ||
* The class of bean containing the property to be replaced | ||
* @param replacementPropertiesName | ||
* The name of the Properties bean containing values to use in | ||
* replacement | ||
* @param propertyKey | ||
* The name of the property whose value is to be replaced with replacement properties | ||
*/ | ||
public void replaceProperty(DefaultListableBeanFactory beanFactory, String beanClassName, | ||
String replacementPropertiesName, String propertyKey) { | ||
Class<?> beanClass = loadClass(beanClassName); | ||
if (beanClass == null) { | ||
return; | ||
} | ||
try { | ||
// TODO: Required in Grails case and need to reexamine | ||
beanFactory.getBeanDefinition(replacementPropertiesName); | ||
} catch (Exception ex) { | ||
return; | ||
} | ||
String[] beanNames = beanFactory.getBeanNamesForType(beanClass); | ||
for (String beanName : beanNames) { | ||
BeanDefinition beanDefinition = getBeanDefinition(beanFactory, beanName); | ||
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues(); | ||
PropertyValue originalProperties = propertyValues.getPropertyValue(propertyKey); | ||
|
||
Properties originalPropertyValue = null; | ||
if (originalProperties != null) { | ||
Object value = originalProperties.getValue(); | ||
if (value instanceof Properties) { | ||
originalPropertyValue = (Properties) originalProperties.getValue(); | ||
} else if (value instanceof BeanDefinitionHolder) { | ||
originalPropertyValue = extractProperties((BeanDefinitionHolder) value); | ||
} else if (value instanceof BeanReference) { | ||
originalPropertyValue = extractProperties((BeanReference) value, beanFactory); | ||
} else if (value instanceof TypedStringValue) { | ||
originalPropertyValue = extractProperties((TypedStringValue) value); | ||
} else { | ||
throw new IllegalStateException("Unable to process property " + originalProperties.getName() | ||
+ " of " + value.getClass() + " type"); | ||
} | ||
} else { | ||
originalPropertyValue = new ManagedProperties(); | ||
} | ||
|
||
ManagedProperties replacementProperties = loadReplacementPropertyValues(beanFactory, | ||
replacementPropertiesName); | ||
replacementProperties.setMergeEnabled(true); | ||
replacementProperties = (ManagedProperties) replacementProperties.merge(originalPropertyValue); | ||
propertyValues.addPropertyValue(new PropertyValue(propertyKey, replacementProperties)); | ||
} | ||
} | ||
|
||
private Properties extractProperties(BeanDefinitionHolder beanDefinitionHolder) { | ||
try { | ||
BeanDefinition valBeanDefinition = beanDefinitionHolder.getBeanDefinition(); | ||
return getMapWrappingBeanProperties(valBeanDefinition); | ||
} catch (Exception e) { | ||
throw new IllegalStateException("Error processing property replacement for a BeanDefinitionHolder", e); | ||
} | ||
} | ||
|
||
private Properties extractProperties(BeanReference beanReference, DefaultListableBeanFactory beanFactory) { | ||
try { | ||
BeanDefinition beanDefinition = getBeanDefinition(beanFactory, beanReference.getBeanName()); | ||
return getMapWrappingBeanProperties(beanDefinition); | ||
} catch (Exception e) { | ||
throw new IllegalStateException("Error processing property replacement for a BeanDefinitionHolder", e); | ||
} | ||
} | ||
|
||
private Properties extractProperties(TypedStringValue typeStringValue) { | ||
Object value = typeStringValue.getValue(); | ||
if (value instanceof Properties) { | ||
return (Properties) value; | ||
} else if (value instanceof String) { | ||
Properties props = new Properties(); | ||
try { | ||
props.load(new StringReader((String) value)); | ||
return props; | ||
} catch (IOException e) { | ||
throw new IllegalStateException("Error processing property replacement for a TypedStringValue", e); | ||
} | ||
} else { | ||
throw new IllegalStateException( | ||
"Error processing property replacement for a TypedStringValue of value type " + value.getClass()); | ||
} | ||
} | ||
|
||
private ManagedProperties loadReplacementPropertyValues(DefaultListableBeanFactory beanFactory, | ||
String replacementPropertiesName) { | ||
BeanDefinition replacementPropertiesBeanDef = beanFactory.getBeanDefinition(replacementPropertiesName); | ||
return (ManagedProperties) replacementPropertiesBeanDef.getPropertyValues().getPropertyValue("properties") | ||
.getValue(); | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
private Properties getMapWrappingBeanProperties(BeanDefinition beanDefinition) { | ||
if (beanDefinition.getBeanClassName().equals(PropertiesFactoryBean.class.getName())) { | ||
try { | ||
PropertyValues propertyValues = beanDefinition.getPropertyValues(); | ||
if (propertyValues.contains("location")) { | ||
return loadPropertiesForLocation(propertyValues.getPropertyValue("location")); | ||
} else if (propertyValues.contains("locations")) { | ||
return loadPropertiesForLocations(propertyValues.getPropertyValue("locations")); | ||
} else if (propertyValues.contains("properties")) { | ||
Object value = propertyValues.getPropertyValue("properties").getValue(); | ||
if (value instanceof BeanDefinitionHolder) { | ||
return extractProperties((BeanDefinitionHolder) value); | ||
} else { | ||
return mapToProperties((Map<String, String>) value); | ||
} | ||
} else { | ||
throw new IllegalArgumentException( | ||
"Unable to process PropertiesFactoryBean; doesn't contain either 'locations' or 'properties' property"); | ||
} | ||
} catch (IOException ex) { | ||
throw new IllegalArgumentException("Unable to process PropertiesFactoryBean", ex); | ||
} | ||
} else { | ||
Map<String, String> sourceMap = (Map<String, String>) beanDefinition.getPropertyValues() | ||
.getPropertyValue("sourceMap").getValue(); | ||
return mapToProperties(sourceMap); | ||
} | ||
} | ||
|
||
private Properties loadPropertiesForLocation(PropertyValue locationPV) throws IOException { | ||
Object locationValue = locationPV.getValue(); | ||
return loadPropertiesForLocation(locationValue); | ||
} | ||
|
||
private Properties loadPropertiesForLocation(Object location) throws IOException { | ||
if (location instanceof String) { | ||
return PropertiesLoaderUtils.loadAllProperties((String) location); | ||
} else if (location instanceof TypedStringValue) { | ||
return PropertiesLoaderUtils.loadAllProperties(((TypedStringValue) location).getValue()); | ||
} else { | ||
throw new IllegalArgumentException("Unable to process 'location' value of type " + location.getClass()); | ||
} | ||
} | ||
|
||
private Properties loadPropertiesForLocations(PropertyValue locationPV) throws IOException { | ||
Object locationsValue = locationPV.getValue(); | ||
if (locationsValue instanceof ManagedList) { | ||
Properties props = new Properties(); | ||
for (Object location : (ManagedList) locationsValue) { | ||
props.putAll(loadPropertiesForLocation(location)); | ||
} | ||
return props; | ||
} else { | ||
throw new IllegalArgumentException("Unable to process 'locations' value of PropertyValue " | ||
+ locationsValue.getClass()); | ||
} | ||
} | ||
|
||
private Properties mapToProperties(Map<String, String> map) { | ||
Properties properties = new Properties(); | ||
for (Map.Entry<String, String> entry : map.entrySet()) { | ||
properties.put(entry.getKey(), entry.getValue()); | ||
} | ||
return properties; | ||
} | ||
|
||
private Class<?> loadClass(String name) { | ||
try { | ||
return Class.forName(name); | ||
} catch (Throwable ex) { | ||
return null; | ||
} | ||
} | ||
|
||
private BeanDefinition getBeanDefinition(DefaultListableBeanFactory beanFactory, String beanName) { | ||
if (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) { | ||
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()); | ||
} | ||
return beanFactory.getBeanDefinition(beanName); | ||
|
||
} | ||
} |
87 changes: 87 additions & 0 deletions
87
...on-core/src/main/java/org/cloudfoundry/reconfiguration/data/document/MongoConfigurer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package org.cloudfoundry.reconfiguration.data.document; | ||
|
||
import java.util.Map; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
|
||
import org.cloudfoundry.reconfiguration.Configurer; | ||
import org.cloudfoundry.runtime.env.CloudEnvironment; | ||
import org.cloudfoundry.runtime.env.CloudServiceException; | ||
import org.cloudfoundry.runtime.service.document.MongoServiceCreator; | ||
import org.springframework.beans.factory.support.DefaultListableBeanFactory; | ||
|
||
/** | ||
* Implementation of {@link Configurer} that replaces a single | ||
* {@link MongoDbFactory} with one connecting to a mongo cloud service bound to | ||
* the current application. | ||
* | ||
* @author Jennifer Hickey | ||
* | ||
*/ | ||
public class MongoConfigurer implements Configurer { | ||
|
||
private final Logger logger = Logger.getLogger(MongoConfigurer.class.getName()); | ||
|
||
static final String CF_MONGO_DB_FACTORY_NAME = "__cloudFoundryMongoDbFactory"; | ||
|
||
private static final String MONGO_DB_FACTORY_CLASS_NAME = "org.springframework.data.mongodb.MongoDbFactory"; | ||
|
||
private CloudEnvironment cloudEnvironment; | ||
|
||
private MongoServiceCreator serviceCreator; | ||
|
||
public MongoConfigurer(CloudEnvironment cloudEnvironment) { | ||
this.cloudEnvironment = cloudEnvironment; | ||
this.serviceCreator = new MongoServiceCreator(cloudEnvironment); | ||
} | ||
|
||
@Override | ||
public boolean configure(DefaultListableBeanFactory beanFactory) { | ||
Class<?> mongoDbFactoryClass = loadClass(MONGO_DB_FACTORY_CLASS_NAME); | ||
if (mongoDbFactoryClass == null) { | ||
logger.log(Level.INFO, "No MongoDbFactory class found."); | ||
return false; | ||
} | ||
String[] mongoDbFactoryBeanNames = beanFactory.getBeanNamesForType(mongoDbFactoryClass); | ||
if (mongoDbFactoryBeanNames.length == 0) { | ||
logger.log(Level.INFO, "No MongoDbFactory found in application context"); | ||
return false; | ||
} else if (mongoDbFactoryBeanNames.length > 1) { | ||
logger.log(Level.INFO, "More than 1 (" + mongoDbFactoryBeanNames.length | ||
+ ") MongoDbFactory beans found in application context. Skipping autostaging."); | ||
return false; | ||
} | ||
for (Map<String, Object> service : cloudEnvironment.getServices()) { | ||
String label = (String) service.get("label"); | ||
if (label == null) { | ||
continue; | ||
} | ||
if (label.startsWith("mongodb")) { | ||
try { | ||
beanFactory.registerSingleton(CF_MONGO_DB_FACTORY_NAME, | ||
serviceCreator.createSingletonService().service); | ||
beanFactory.removeBeanDefinition(mongoDbFactoryBeanNames[0]); | ||
beanFactory.registerAlias(CF_MONGO_DB_FACTORY_NAME, mongoDbFactoryBeanNames[0]); | ||
return true; | ||
} catch (CloudServiceException ex) { | ||
logger.log(Level.INFO, "Multiple mongo services found. Skipping autostaging", ex); | ||
return false; | ||
} | ||
} | ||
} | ||
logger.log(Level.INFO, "No mongo service found. Skipping autostaging"); | ||
return false; | ||
} | ||
|
||
private Class<?> loadClass(String name) { | ||
try { | ||
return Class.forName(name); | ||
} catch (Throwable ex) { | ||
return null; | ||
} | ||
} | ||
|
||
public void setServiceCreator(MongoServiceCreator serviceCreator) { | ||
this.serviceCreator = serviceCreator; | ||
} | ||
} |
Oops, something went wrong.