Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit d9dc8af6113bf7af149c398d0346ce8ed23b3d00 0 parents
Cloud Foundry Engineer authored
Showing with 11,106 additions and 0 deletions.
  1. +15 −0 .gitignore
  2. +7,136 −0 LICENSE
  3. +10 −0 NOTICE
  4. +21 −0 README
  5. +3 −0  auto-reconfiguration/.gitignore
  6. +239 −0 auto-reconfiguration/pom.xml
  7. +325 −0 ...econfiguration/src/main/java/org/cloudfoundry/reconfiguration/CloudAutoStagingBeanFactoryPostProcessor.java
  8. +19 −0 auto-reconfiguration/src/main/resources/META-INF/cloud/cloudfoundry-auto-reconfiguration-context.xml
  9. +180 −0 ...ion/src/test/java/org/cloudfoundry/reconfiguration/CloudFactoryAutoStagingBeanFactoryPostProcessorTest.java
  10. +17 −0 auto-reconfiguration/src/test/resources/META-INF/persistence.xml
  11. +5 −0 auto-reconfiguration/src/test/resources/org/cloudfoundry/reconfiguration/hibernate.test.properties
  12. +1 −0  auto-reconfiguration/src/test/resources/org/cloudfoundry/reconfiguration/test-autostaging-corrupt.properties
  13. 0  auto-reconfiguration/src/test/resources/org/cloudfoundry/reconfiguration/test-autostaging-empty.properties
  14. +1 −0  auto-reconfiguration/src/test/resources/org/cloudfoundry/reconfiguration/test-autostaging-off.properties
  15. +1 −0  auto-reconfiguration/src/test/resources/org/cloudfoundry/reconfiguration/test-autostaging-on.properties
  16. +32 −0 ...nfiguration/src/test/resources/org/cloudfoundry/reconfiguration/test-grails-embedded-props-good-context.xml
  17. +33 −0 ...onfiguration/src/test/resources/org/cloudfoundry/reconfiguration/test-grails-map-reference-good-context.xml
  18. +26 −0 .../src/test/resources/org/cloudfoundry/reconfiguration/test-grails-propertyFactory-reference-good-context.xml
  19. +28 −0 auto-reconfiguration/src/test/resources/org/cloudfoundry/reconfiguration/test-hibernate-good-context.xml
  20. +20 −0 auto-reconfiguration/src/test/resources/org/cloudfoundry/reconfiguration/test-jpa-good-context.xml
  21. +40 −0 ...onfiguration/src/test/resources/org/cloudfoundry/reconfiguration/test-jpa-typedStringValue-good-context.xml
  22. +3 −0  cloudfoundry-runtime/.gitignore
  23. +225 −0 cloudfoundry-runtime/pom.xml
  24. +55 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/AbstractServiceInfo.java
  25. +78 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/ApplicationInstanceInfo.java
  26. +175 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/CloudEnvironment.java
  27. +69 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/CloudEnvironmentPropertiesFactoryBean.java
  28. +21 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/CloudServiceException.java
  29. +16 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/MongoServiceInfo.java
  30. +36 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/MysqlServiceInfo.java
  31. +39 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/RabbitServiceInfo.java
  32. +16 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/RedisServiceInfo.java
  33. +49 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/AbstractCloudServiceFactory.java
  34. +97 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/AbstractServiceCreator.java
  35. +89 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/CloudServicesAutoPopulator.java
  36. +55 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/config/xml/CloudNamespaceHandler.java
  37. +68 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/config/xml/CloudServiceFactoryParser.java
  38. +28 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/document/CloudMongoFactoryBean.java
  39. +33 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/document/MongoServiceCreator.java
  40. +27 −0 ...oundry-runtime/src/main/java/org/cloudfoundry/runtime/service/keyvalue/CloudRedisConnectionFactoryBean.java
  41. +32 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/keyvalue/RedisServiceCreator.java
  42. +28 −0 ...ndry-runtime/src/main/java/org/cloudfoundry/runtime/service/messaging/CloudRabbitConnectionFactoryBean.java
  43. +32 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/messaging/RabbitServiceCreator.java
  44. +28 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/relational/CloudDataSourceFactory.java
  45. +74 −0 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/relational/MysqlServiceCreator.java
  46. +1 −0  cloudfoundry-runtime/src/main/resources/META-INF/spring.handlers
  47. +2 −0  cloudfoundry-runtime/src/main/resources/META-INF/spring.schemas
  48. +4 −0 cloudfoundry-runtime/src/main/resources/META-INF/spring.tooling
  49. BIN  cloudfoundry-runtime/src/main/resources/org/cloudfoundry/runtime/service/config/xml/cloudfoundry-spring.gif
  50. +149 −0 cloudfoundry-runtime/src/main/resources/org/cloudfoundry/runtime/service/config/xml/cloudfoundry-spring.xsd
  51. +41 −0 cloudfoundry-runtime/src/test/java/org/cloudfoundry/runtime/env/CloudEnvPropertiesFactoryBeanTest.java
  52. +119 −0 cloudfoundry-runtime/src/test/java/org/cloudfoundry/runtime/env/CloudEnvironmentTest.java
  53. +126 −0 cloudfoundry-runtime/src/test/java/org/cloudfoundry/runtime/service/CloudEnvironmentTestHelper.java
  54. +43 −0 cloudfoundry-runtime/src/test/java/org/cloudfoundry/runtime/service/document/CloudMongoFactoryTest.java
  55. +54 −0 ...ry-runtime/src/test/java/org/cloudfoundry/runtime/service/keyvalue/CloudRedisConnectionFactoryBeanTest.java
  56. +44 −0 ...-runtime/src/test/java/org/cloudfoundry/runtime/service/messaging/CloudRabbitConnectionFactoryBeanTest.java
  57. +47 −0 cloudfoundry-runtime/src/test/java/org/cloudfoundry/runtime/service/relational/CloudDataSourceFactoryTest.java
  58. +18 −0 cloudfoundry-runtime/src/test/resources/org/cloudfoundry/runtime/service/test-application-info.json
  59. +12 −0 cloudfoundry-runtime/src/test/resources/org/cloudfoundry/runtime/service/test-mongodb-info.json
  60. +13 −0 cloudfoundry-runtime/src/test/resources/org/cloudfoundry/runtime/service/test-mysql-info.json
  61. +12 −0 cloudfoundry-runtime/src/test/resources/org/cloudfoundry/runtime/service/test-rabbit-info.json
  62. +12 −0 cloudfoundry-runtime/src/test/resources/org/cloudfoundry/runtime/service/test-redis-info.json
  63. +28 −0 plugins/maven/B29Plugin.iml
  64. +397 −0 plugins/maven/B29Plugin.ipr
  65. +74 −0 plugins/maven/pom.xml
  66. +284 −0 plugins/maven/src/main/java/com/vmware/b20nine/B20NineMojo.java
  67. +34 −0 plugins/tomcat_startup_listener/pom.xml
  68. +56 −0 plugins/tomcat_startup_listener/src/main/java/com/vmware/appcloud/tomcat/AppCloudLifecycleListener.java
  69. +11 −0 plugins/tomcat_startup_listener/src/main/java/com/vmware/appcloud/tomcat/TomcatStartupListener.java
15 .gitignore
@@ -0,0 +1,15 @@
+*~
+.idea
+\#*\#
+.\#*
+target/
+build/
+eclipse-base.tar.gz
+eclipse/
+org.eclipse.releng.basebuilder/
+org.eclipse.releng.basebuilder.zip
+com.vmware.sts.server.appcloud.releng/springsource/
+/AppCloudClient/src/test/java/com/vmware/appcloud/client/credentials.properties
+.classpath
+.project
+.settings
7,136 LICENSE
7,136 additions, 0 deletions not shown
10 NOTICE
@@ -0,0 +1,10 @@
+Cloud Foundry 2011.04.12 beta
+Copyright (c) [2009-2011] VMware, Inc. All Rights Reserved.
+
+This product is licensed to you under the Apache License, Version 2.0 (the "License").
+You may not use this product except in compliance with the License.
+
+This product includes a number of subcomponents with
+separate copyright notices and license terms. Your use of these
+subcomponents is subject to the terms and conditions of the
+subcomponent's license, as noted in the LICENSE file.
21 README
@@ -0,0 +1,21 @@
+Copyright (c) 2009-2011 VMware, Inc.
+
+== What is Cloud Foundry?
+
+Cloud Foundry is an open platform-as-a-service (PaaS). The system supports
+multiple frameworks, multiple application infrastructure services and
+deployment to multiple clouds.
+
+== What is this component
+
+The vcap-java repo contains a java client library for Cloud Foundry.
+The library provides a set of classes that ultimately call the core
+Cloud Foundry REST API.
+
+== License
+
+Cloud Foundry uses the Apache 2 license. See LICENSE for details.
+
+== Installation Notes
+
+Complete installation notes are present in the README for vcap
3  auto-reconfiguration/.gitignore
@@ -0,0 +1,3 @@
+.springBeans
+.settings/
+*.log
239 auto-reconfiguration/pom.xml
@@ -0,0 +1,239 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.cloudfoundry</groupId>
+ <artifactId>auto-reconfiguration</artifactId>
+ <packaging>jar</packaging>
+ <name>auto-reconfiguration</name>
+ <version>0.6.0-BUILD-SNAPSHOT</version>
+ <properties>
+ <java.version>1.6</java.version>
+ <spring.version>2.5.6</spring.version>
+ <slf4j.version>1.5.6</slf4j.version>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.cloudfoundry</groupId>
+ <artifactId>cloudfoundry-runtime</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!-- Spring -->
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ <version>${spring.version}</version>
+ <exclusions>
+ <!-- Exclude Commons Logging in favor of SLF4j -->
+ <exclusion>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ </exclusion>
+ </exclusions>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>1.1.1</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-orm</artifactId>
+ <version>${spring.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- Test -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.8.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.8.5</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>mysql</groupId>
+ <artifactId>mysql-connector-java</artifactId>
+ <version>5.0.5</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>com.springsource.slf4j.api</artifactId>
+ <version>${slf4j.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>com.springsource.slf4j.org.apache.commons.logging</artifactId>
+ <version>${slf4j.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>com.springsource.slf4j.log4j</artifactId>
+ <version>${slf4j.version}</version>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.transaction</groupId>
+ <artifactId>com.springsource.javax.transaction</artifactId>
+ <version>1.1.0</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.persistence</groupId>
+ <artifactId>persistence-api</artifactId>
+ <version>1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-entitymanager</artifactId>
+ <version>3.4.0.GA</version>
+ <exclusions>
+ <exclusion>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ </exclusion>
+ </exclusions>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-annotations</artifactId>
+ <version>3.4.0.GA</version>
+ <exclusions>
+ <exclusion>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ </exclusion>
+ </exclusions>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-jdbc</artifactId>
+ <version>${spring.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+ <repositories>
+ <!-- For testing against latest Spring snapshots -->
+ <repository>
+ <id>org.springframework.maven.snapshot</id>
+ <name>Spring Maven Snapshot Repository</name>
+ <url>http://maven.springframework.org/snapshot</url>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </repository>
+ <!-- For developing against latest Spring milestones -->
+ <repository>
+ <id>org.springframework.maven.milestone</id>
+ <name>Spring Maven Milestone Repository</name>
+ <url>http://maven.springframework.org/milestone</url>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </repository>
+ <repository>
+ <id>spring-maven-snapshot</id>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ <name>Springframework Maven SNAPSHOT Repository</name>
+ <url>http://maven.springframework.org/snapshot</url>
+ </repository>
+ <repository>
+ <id>JBoss Repo</id>
+ <url>https://repository.jboss.org/nexus/content/repositories/releases</url>
+ <name>JBoss Repo</name>
+ </repository>
+ </repositories>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${java.version}</source>
+ <target>${java.version}</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>install</id>
+ <phase>install</phase>
+ <goals>
+ <goal>sources</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <junitArtifactName>junit:junit</junitArtifactName>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>1.4</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <artifactSet>
+ <excludes>
+ <exclude>org.slf4j:com.springsource.slf4j.log4j</exclude>
+ <exclude>org.apache.log4j:com.springsource.org.apache.log4j</exclude>
+ </excludes>
+ </artifactSet>
+ <filters>
+ <filter>
+ <artifact>org.cloudfoundry:cloudfoundry-runtime</artifact>
+ <excludes>
+ <exclude>META-INF/**</exclude>
+ <exclude>**/*.xsd</exclude>
+ <exclude>**/*.gif</exclude>
+ </excludes>
+ </filter>
+ </filters>
+ <relocations>
+ <relocation>
+ <pattern>org.cloudfoundry.runtime</pattern>
+ <shadedPattern>org.cloudfoundry.org.cloudfoundry.runtime</shadedPattern>
+ </relocation>
+ </relocations>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+</project>
325 ...nfiguration/src/main/java/org/cloudfoundry/reconfiguration/CloudAutoStagingBeanFactoryPostProcessor.java
@@ -0,0 +1,325 @@
+package org.cloudfoundry.reconfiguration;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.sql.DataSource;
+
+import org.cloudfoundry.runtime.env.CloudEnvironment;
+import org.cloudfoundry.runtime.env.CloudServiceException;
+import org.cloudfoundry.runtime.service.relational.MysqlServiceCreator;
+import org.springframework.beans.BeansException;
+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.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.BeanReference;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+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.ManagedProperties;
+import org.springframework.core.Ordered;
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PropertiesLoaderUtils;
+
+/**
+ * A bean factory post processor that auto-stage service-related beans.
+ * <p>
+ * Currently, this bean supports auto-staging of {@link DataSource} beans.
+ *
+ * @author Ramnivas Laddad
+ *
+ */
+public class CloudAutoStagingBeanFactoryPostProcessor implements BeanFactoryPostProcessor, Ordered {
+
+ Logger logger = Logger.getLogger(CloudAutoStagingBeanFactoryPostProcessor.class.getName());
+
+ private CloudEnvironment cloudEnvironment;
+
+ private static final String CLOUDFOUNDRY_PROPERTIES = "META-INF/cloudfoundry.properties";
+ private static final String APP_CLOUD_DATA_SOURCE_NAME = "__appCloudDataSource";
+ private static final String APP_CLOUD_JPA_REPLACEMENT_PROPERTIES = "__appCloudJpaReplacementProperties";
+ private static final String APP_CLOUD_HIBERNATE_REPLACEMENT_PROPERTIES = "__appCloudHibernateReplacementProperties";
+
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+ if (autoStagingOff()) {
+ return;
+ }
+
+ DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
+
+ // defaultListableBeanFactory.getBean(CloudEnvironment.class) will do,
+ // but we go through a mechanism that will work for spring-2.5.x as well
+ @SuppressWarnings("unchecked")
+ Map<String,CloudEnvironment> cloudEnvironmentBeans = defaultListableBeanFactory.getBeansOfType(CloudEnvironment.class);
+ if (cloudEnvironmentBeans.size() > 1) {
+ logger.log(Level.INFO, "Multiple (" + cloudEnvironmentBeans.size() + ") CloudEnvironmentBeans found; zero or 1 expected");
+ return;
+ } else if (cloudEnvironmentBeans.size() == 1) {
+ cloudEnvironment = cloudEnvironmentBeans.entrySet().iterator().next().getValue();
+ } else {
+ cloudEnvironment = new CloudEnvironment();
+ }
+
+ if(processDatasources(defaultListableBeanFactory)) {
+ processJpaFactories(defaultListableBeanFactory);
+ processHibernateFactories(defaultListableBeanFactory);
+ }
+ }
+
+ private boolean autoStagingOff() {
+ return autoStagingOff(CLOUDFOUNDRY_PROPERTIES);
+ }
+
+ /**
+ * WARNING: Experimental support to opt out of autostaging, useful if autostaging comes in your way.
+ *
+ * Turn off autostaging if we find a META-INF/cloudfoundry.properties on classpath and it
+ * contains autostaging=false. Applications can opt-out of autostaging by adding a property
+ * to src/main/resources/META-INF/cloudfoundry.properties (assuming Maven layout).
+ *
+ * @return return true to opt out of autostaging
+ */
+ boolean autoStagingOff(String propertyLocation) {
+ try {
+ Resource cloudfoundryConfig = new DefaultResourceLoader().getResource(propertyLocation);
+ if (!cloudfoundryConfig.exists()) {
+ logger.log(Level.INFO, "No 'META-INF/cloudfoundry.properties' found, autostaging is active");
+ return false;
+ }
+ Properties cloudfoundryProperties = PropertiesLoaderUtils.loadProperties(cloudfoundryConfig);
+ String autostagingStringValue = cloudfoundryProperties.getProperty("autostaging", "true");
+ boolean autostagingValue = Boolean.valueOf(autostagingStringValue);
+ if (!autostagingValue) {
+ logger.log(Level.INFO, "Application requested to skip autostaging");
+ }
+ return !autostagingValue;
+ } catch (Exception ex) {
+ // Turn off autostaging if anything goes wrong in our detection
+ return true;
+ }
+ }
+
+ // Let this be the last to process
+ @Override
+ public int getOrder() {
+ return LOWEST_PRECEDENCE;
+ }
+
+ private boolean processDatasources(DefaultListableBeanFactory defaultListableBeanFactory) {
+ String[] dataSourceBeanNames = getRealDataSources(defaultListableBeanFactory);
+ if (dataSourceBeanNames.length == 0) {
+ logger.log(Level.INFO, "No datasources found in application context");
+ return false;
+ } else if (dataSourceBeanNames.length > 1) {
+ logger.log(Level.INFO, "More than 1 (" + dataSourceBeanNames.length + ") real datasources found in application context. Skipping autostaging.");
+ return false;
+ }
+
+ DataSource theOnlyDataSource = null;
+ try {
+ MysqlServiceCreator mysqlCreationHelper = new MysqlServiceCreator(cloudEnvironment);
+ theOnlyDataSource = mysqlCreationHelper.createSingletonService().service;
+ } catch (CloudServiceException ex) {
+ logger.log(Level.INFO, "Multiple database services found. Skipping autostaging");
+ return false;
+ }
+ defaultListableBeanFactory.registerSingleton(APP_CLOUD_DATA_SOURCE_NAME, theOnlyDataSource);
+
+ for (String dataSourceBeanName : dataSourceBeanNames) {
+ if (dataSourceBeanName.equals(APP_CLOUD_DATA_SOURCE_NAME)) {
+ continue;
+ }
+ defaultListableBeanFactory.removeBeanDefinition(dataSourceBeanName);
+ defaultListableBeanFactory.registerAlias(APP_CLOUD_DATA_SOURCE_NAME, dataSourceBeanName);
+ }
+ return true;
+ }
+
+ private void processJpaFactories(DefaultListableBeanFactory beanFactory) {
+ processBeanProperties(beanFactory, "org.springframework.orm.jpa.AbstractEntityManagerFactoryBean",
+ APP_CLOUD_JPA_REPLACEMENT_PROPERTIES, "jpaProperties");
+ }
+
+ private void processHibernateFactories(DefaultListableBeanFactory beanFactory) {
+ processBeanProperties(beanFactory, "org.springframework.orm.hibernate3.AbstractSessionFactoryBean",
+ APP_CLOUD_HIBERNATE_REPLACEMENT_PROPERTIES, "hibernateProperties");
+ }
+
+ private void processBeanProperties(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();
+ }
+
+ private String[] getRealDataSources( DefaultListableBeanFactory beanFactory) {
+ String[] dataSourceBeanNames = beanFactory.getBeanNamesForType(DataSource.class);
+ Class<?> txAwareDSClass = loadClass("org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy");
+ if (txAwareDSClass == null) {
+ return dataSourceBeanNames;
+ }
+ // In Scala, could have been one line and not even need contains()!
+ String[] txAwareDSBeanNames = beanFactory.getBeanNamesForType(txAwareDSClass);
+ List<String> realDSBeanNames = new ArrayList<String>();
+ for (String dataSourceBeanName : dataSourceBeanNames) {
+ if (!contains(txAwareDSBeanNames, dataSourceBeanName)) {
+ // Skip singletons
+ try {
+ if (getBeanDefinition(beanFactory, dataSourceBeanName) != null) {
+ realDSBeanNames.add(dataSourceBeanName);
+ }
+ } catch (NoSuchBeanDefinitionException ex) {
+ // skip
+ }
+ }
+ }
+ return realDSBeanNames.toArray(new String[0]);
+ }
+
+ private <T> boolean contains(T[] array, T searchElement) {
+ for (T element : array) {
+ if (element.equals(searchElement)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ 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);
+
+ }
+
+ private Properties getMapWrappingBeanProperties(BeanDefinition beanDefinition) {
+ if (beanDefinition.getBeanClassName().equals(PropertiesFactoryBean.class.getName())) {
+ try {
+ PropertyValues propertyValues = beanDefinition.getPropertyValues();
+ if (propertyValues.contains("location")) {
+ String propertyLocation = (String) propertyValues.getPropertyValue("location").getValue();
+ return PropertiesLoaderUtils.loadAllProperties(propertyLocation);
+ } else if (propertyValues.contains("properties")) {
+ return mapToProperties((Map<String,String>)propertyValues.getPropertyValue("properties").getValue());
+ } 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 {
+ @SuppressWarnings("unchecked")
+ Map<String,String> sourceMap = (Map<String,String>) beanDefinition.getPropertyValues().getPropertyValue("sourceMap").getValue();
+ return mapToProperties(sourceMap);
+ }
+ }
+
+ 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;
+ }
+ }
+}
19 auto-reconfiguration/src/main/resources/META-INF/cloud/cloudfoundry-auto-reconfiguration-context.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">
+
+ <description>Replacement bean definitions for cloud deployment</description>
+
+ <util:properties id="__appCloudJpaReplacementProperties">
+ <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
+ </util:properties>
+
+ <util:properties id="__appCloudHibernateReplacementProperties">
+ <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
+ </util:properties>
+
+ <bean class="org.cloudfoundry.reconfiguration.CloudAutoStagingBeanFactoryPostProcessor"/>
+</beans>
180 .../src/test/java/org/cloudfoundry/reconfiguration/CloudFactoryAutoStagingBeanFactoryPostProcessorTest.java
@@ -0,0 +1,180 @@
+package org.cloudfoundry.reconfiguration;
+
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.sql.DataSource;
+
+import org.cloudfoundry.runtime.env.CloudEnvironment;
+import org.cloudfoundry.runtime.env.MysqlServiceInfo;
+import org.hibernate.SessionFactory;
+import org.hibernate.impl.SessionFactoryImpl;
+import org.hibernate.impl.SessionImpl;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.jdbc.datasource.AbstractDriverBasedDataSource;
+
+/**
+ * Unit-tests for {@link CloudAutoStagingBeanFactoryPostProcessor}.
+ * <p>
+ * This test uses a mock application context to introduce environment with services
+ * to avoid the need of actual working application and services. The assertions
+ * are made to check if the actual beans got replaced/not replaced with the mock beans.
+ *
+ * @author Ramnivas Laddad
+ *
+ */
+public class CloudFactoryAutoStagingBeanFactoryPostProcessorTest {
+ @Mock private MysqlServiceInfo mockMysqlServiceInfo1;
+ @Mock private MysqlServiceInfo mockMysqlServiceInfo2;
+ @Mock private CloudEnvironment mockEnvironment;
+
+ private CloudAutoStagingBeanFactoryPostProcessor testBFPP;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ testBFPP = new CloudAutoStagingBeanFactoryPostProcessor();
+ }
+
+ @Test
+ public void cloudDataSourceReplacesUserDataSourceIfOneServiceDetected() {
+ String serviceJdbcUrl = "jdbc:mysql://10.20.20.40:1234/mysql-1";
+ List<MysqlServiceInfo> serviceInfos = new ArrayList<MysqlServiceInfo>();
+ serviceInfos.add(mockMysqlServiceInfo1);
+ when(mockMysqlServiceInfo1.getUrl()).thenReturn(serviceJdbcUrl);
+ when(mockEnvironment.getServiceInfos(MysqlServiceInfo.class)).thenReturn(serviceInfos);
+
+ ApplicationContext context = getTestApplicationContext("test-jpa-good-context.xml");
+ AbstractDriverBasedDataSource replacedDataSource = (AbstractDriverBasedDataSource) context.getBean("myDs", DataSource.class);
+ Assert.assertEquals(serviceJdbcUrl, replacedDataSource.getUrl());
+ }
+
+ @Test
+ public void cloudDataSourceLeavesOriginalInPlaceIfMultipleServicesDetected() {
+ String serviceJdbcUrl1 = "jdbc:mysql://10.20.20.40:1234/mysql-1";
+ String serviceJdbcUrl2 = "jdbc:mysql://10.20.20.40:1234/mysql-2";
+ List<MysqlServiceInfo> serviceInfos = new ArrayList<MysqlServiceInfo>();
+ serviceInfos.add(mockMysqlServiceInfo1);
+ serviceInfos.add(mockMysqlServiceInfo2);
+ when(mockMysqlServiceInfo1.getUrl()).thenReturn(serviceJdbcUrl1);
+ when(mockMysqlServiceInfo2.getUrl()).thenReturn(serviceJdbcUrl2);
+ when(mockEnvironment.getServiceInfos(MysqlServiceInfo.class)).thenReturn(serviceInfos);
+
+ ApplicationContext context = getTestApplicationContext("test-jpa-good-context.xml");
+ AbstractDriverBasedDataSource replacedDataSource = (AbstractDriverBasedDataSource) context.getBean("myDs", DataSource.class);
+ Assert.assertEquals("jdbc:hsql:localdb", replacedDataSource.getUrl());
+ }
+
+ @Test
+ public void cloudDataSourceLeavesOriginalInPlaceIfNoServicesDetected() {
+ List<MysqlServiceInfo> serviceInfos = new ArrayList<MysqlServiceInfo>();
+ when(mockEnvironment.getServiceInfos(MysqlServiceInfo.class)).thenReturn(serviceInfos);
+
+ ApplicationContext context = getTestApplicationContext("test-jpa-good-context.xml");
+ AbstractDriverBasedDataSource replacedDataSource = (AbstractDriverBasedDataSource) context.getBean("myDs", DataSource.class);
+ Assert.assertEquals("jdbc:hsql:localdb", replacedDataSource.getUrl());
+ }
+
+ @Test
+ public void hibernateSessionFactoryDialectUpdated() {
+ assertApplicationContextProcessing("test-hibernate-good-context.xml");
+ }
+
+ @Test
+ public void entityManagerFactoryDialectUpdated() {
+ String serviceJdbcUrl = "jdbc:mysql://10.20.20.40:1234/mysql-1";
+ List<MysqlServiceInfo> serviceInfos = new ArrayList<MysqlServiceInfo>();
+ serviceInfos.add(mockMysqlServiceInfo1);
+ when(mockMysqlServiceInfo1.getUrl()).thenReturn(serviceJdbcUrl);
+ when(mockEnvironment.getServiceInfos(MysqlServiceInfo.class)).thenReturn(serviceInfos);
+
+ ApplicationContext context = getTestApplicationContext("test-jpa-good-context.xml");
+ EntityManagerFactory entityManagerFactory = (EntityManagerFactory) context.getBean("entityManagerFactory", EntityManagerFactory.class);
+ EntityManager entityManager = entityManagerFactory.createEntityManager();
+ SessionImpl entityManagerDelegate = (SessionImpl) entityManager.getDelegate();
+ SessionFactoryImpl underlyingSessionFactory = (SessionFactoryImpl) entityManagerDelegate.getSessionFactory();
+ Assert.assertEquals("org.hibernate.dialect.MySQLDialect", underlyingSessionFactory.getDialect().toString());
+ }
+
+ @Test
+ public void grailsLikeEmbeddedPropertyApplicationContextProcessed() {
+ assertApplicationContextProcessing("test-grails-embedded-props-good-context.xml");
+ }
+
+ @Test
+ public void grailsLikeReferencedMapApplicationContextProcessed() {
+ assertApplicationContextProcessing("test-grails-map-reference-good-context.xml");
+ }
+
+ @Test
+ public void grailsLikeReferencedPropertyFactoryApplicationContextProcessed() {
+ assertApplicationContextProcessing("test-grails-propertyFactory-reference-good-context.xml");
+ }
+
+ @Test
+ public void typeStringValuePropertyApplicationContextProcessed() {
+ assertApplicationContextProcessing("test-jpa-typedStringValue-good-context.xml");
+ }
+
+ @Test
+ public void autostagingOffWhenPropertyFileSpecifiedOff() {
+ Assert.assertTrue(testBFPP.autoStagingOff("org/cloudfoundry/reconfiguration/test-autostaging-off.properties"));
+ }
+
+ @Test
+ public void autostagingOnWhenPropertyFileSpecifiedOn() {
+ Assert.assertFalse(testBFPP.autoStagingOff("org/cloudfoundry/reconfiguration/test-autostaging-on.properties"));
+ }
+
+ @Test
+ public void autostagingOnWhenPropertyFileEmpty() {
+ Assert.assertFalse(testBFPP.autoStagingOff("org/cloudfoundry/reconfiguration/test-autostaging-empty.properties"));
+ }
+
+ @Test
+ public void autostagingOnWhenPropertyFileCorrupt() {
+ Assert.assertFalse(testBFPP.autoStagingOff("org/cloudfoundry/reconfiguration/test-autostaging-corrupt.properties"));
+ }
+
+ @Test
+ public void autostagingOnWhenPropertyFileDoesntExist() {
+ Assert.assertFalse(testBFPP.autoStagingOff("file-that-doesnt-exist"));
+ }
+
+ private void assertApplicationContextProcessing(String appContextFile) {
+ String serviceJdbcUrl = "jdbc:mysql://10.20.20.40:1234/mysql-1";
+ List<MysqlServiceInfo> serviceInfos = new ArrayList<MysqlServiceInfo>();
+ serviceInfos.add(mockMysqlServiceInfo1);
+ when(mockMysqlServiceInfo1.getUrl()).thenReturn(serviceJdbcUrl);
+ when(mockEnvironment.getServiceInfos(MysqlServiceInfo.class)).thenReturn(serviceInfos);
+
+ ApplicationContext context = getTestApplicationContext(appContextFile);
+ SessionFactoryImpl sessionFactory = (SessionFactoryImpl) context.getBean("sessionFactory", SessionFactory.class);
+
+ Assert.assertEquals("org.hibernate.dialect.MySQLDialect", sessionFactory.getDialect().toString());
+
+ }
+
+ private ApplicationContext getTestApplicationContext(String fileName) {
+ return new ClassPathXmlApplicationContext(new String[]{"org/cloudfoundry/reconfiguration/" + fileName,
+ "META-INF/cloud/cloudfoundry-auto-reconfiguration-context.xml"}) {
+ @Override
+ protected void prepareBeanFactory(
+ ConfigurableListableBeanFactory beanFactory) {
+ getBeanFactory().registerSingleton("test-cloudEnvironment", mockEnvironment);
+ super.prepareBeanFactory(beanFactory);
+ }
+ };
+ }
+}
17 auto-reconfiguration/src/test/resources/META-INF/persistence.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<persistence xmlns="http://java.sun.com/xml/ns/persistence"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ version="1.0"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
+<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
+ <provider>org.hibernate.ejb.HibernatePersistence</provider>
+ <properties>
+ <property name="hibernate.dialect" value="dialect.that.doesnt.exist.and.should.be.auto_replaced"/>
+ <property name="hibernate.hbm2ddl.auto" value="none"/>
+ <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
+ <property name="hibernate.connection.charSet" value="UTF-8"/>
+ <!-- To avoid connecting to database during testing -->
+ <property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
+ </properties>
+</persistence-unit>
+</persistence>
5 auto-reconfiguration/src/test/resources/org/cloudfoundry/reconfiguration/hibernate.test.properties
@@ -0,0 +1,5 @@
+hibernate.dialect=dialect.that.doesnt.exist.and.should.be.auto_replaced
+hibernate.show_sql=true
+hibernate.generate_statistics=false
+# To avoid connecting to database during testing -->
+hibernate.temp.use_jdbc_metadata_defaults=false
1  ...-reconfiguration/src/test/resources/org/cloudfoundry/reconfiguration/test-autostaging-corrupt.properties
@@ -0,0 +1 @@
+$$$$$%%%
0  auto-reconfiguration/src/test/resources/org/cloudfoundry/reconfiguration/test-autostaging-empty.properties
No changes.
1  auto-reconfiguration/src/test/resources/org/cloudfoundry/reconfiguration/test-autostaging-off.properties
@@ -0,0 +1 @@
+autostaging=false
1  auto-reconfiguration/src/test/resources/org/cloudfoundry/reconfiguration/test-autostaging-on.properties
@@ -0,0 +1 @@
+autostaging=true
32 ...guration/src/test/resources/org/cloudfoundry/reconfiguration/test-grails-embedded-props-good-context.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+
+ <bean name="myDs" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
+ <property name="url" value="jdbc:hsql:localdb" />
+ </bean>
+
+ <bean name="txAwareDXProxy" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
+ <property name="targetDataSource" ref="myDs"/>
+ </bean>
+
+ <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" lazy-init="true">
+ <property name="dataSource" ref="myDs"/>
+ <property name="hibernateProperties">
+ <util:map>
+ <entry key="hibernate.dialect" value="dialect.that.doesnt.exist.and.should.be.auto_replaced"/>
+ <entry key="hibernate.show_sql" value="true"/>
+ <entry key="hibernate.generate_statistics" value="false"/>
+ <!-- To avoid connecting to database during testing -->
+ <entry key="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
+ </util:map>
+ </property>
+ </bean>
+
+</beans>
+
33 ...iguration/src/test/resources/org/cloudfoundry/reconfiguration/test-grails-map-reference-good-context.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+
+ <bean name="myDs" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
+ <property name="url" value="jdbc:hsql:localdb" />
+ </bean>
+
+ <bean name="txAwareDXProxy" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
+ <property name="targetDataSource" ref="myDs"/>
+ </bean>
+
+ <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" lazy-init="true">
+ <property name="dataSource" ref="myDs"/>
+ <property name="hibernateProperties" ref="hibernateProperties"/>
+ </bean>
+
+
+ <util:map id="hibernateProperties">
+ <entry key="hibernate.dialect" value="dialect.that.doesnt.exist.and.should.be.auto_replaced"/>
+ <entry key="hibernate.show_sql" value="true"/>
+ <entry key="hibernate.generate_statistics" value="false"/>
+ <!-- To avoid connecting to database during testing -->
+ <entry key="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
+ </util:map>
+
+</beans>
+
26 ...c/test/resources/org/cloudfoundry/reconfiguration/test-grails-propertyFactory-reference-good-context.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+
+ <bean name="myDs" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
+ <property name="url" value="jdbc:hsql:localdb" />
+ </bean>
+
+ <bean name="txAwareDXProxy" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
+ <property name="targetDataSource" ref="myDs"/>
+ </bean>
+
+ <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" lazy-init="true">
+ <property name="dataSource" ref="myDs"/>
+ <property name="hibernateProperties" ref="hibernateProperties"/>
+ </bean>
+
+ <util:properties id="hibernateProperties" location="org/cloudfoundry/reconfiguration/hibernate.test.properties"/>
+
+</beans>
+
28 auto-reconfiguration/src/test/resources/org/cloudfoundry/reconfiguration/test-hibernate-good-context.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+
+ <bean name="myDs" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
+ <property name="url" value="jdbc:hsql:localdb" />
+ </bean>
+
+ <bean name="txAwareDXProxy" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
+ <property name="targetDataSource" ref="myDs"/>
+ </bean>
+
+ <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" lazy-init="true">
+ <property name="dataSource" ref="myDs"/>
+ <property name="hibernateProperties">
+ <props>
+ <prop key="hibernate.dialect">dialect.that.doesnt.exist.and.should.be.auto_replaced</prop>
+ <prop key="hibernate.show_sql">true</prop>
+ <prop key="hibernate.generate_statistics">false</prop>
+ <!-- To avoid connecting to database during testing -->
+ <prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
+ </props>
+ </property>
+ </bean>
+
+</beans>
20 auto-reconfiguration/src/test/resources/org/cloudfoundry/reconfiguration/test-jpa-good-context.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+
+ <bean name="myDs" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
+ <property name="url" value="jdbc:hsql:localdb" />
+ </bean>
+
+ <bean name="txAwareDXProxy" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
+ <property name="targetDataSource" ref="myDs"/>
+ </bean>
+
+ <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
+ lazy-init="true">
+ <property name="dataSource" ref="myDs"/>
+ </bean>
+
+</beans>
40 ...iguration/src/test/resources/org/cloudfoundry/reconfiguration/test-jpa-typedStringValue-good-context.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+
+ <!-- Travel app in webflow 2.3 version uses this style -->
+
+ <bean name="myDs" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
+ <property name="url" value="jdbc:hsql:localdb" />
+ </bean>
+
+ <bean name="txAwareDXProxy" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
+ <property name="targetDataSource" ref="myDs"/>
+ </bean>
+
+ <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
+ lazy-init="true">
+ <property name="dataSource" ref="myDs"/>
+ <property name="jpaProperties">
+ <value>
+ hibernate.dialect=dialect.that.doesnt.exist.and.should.be.auto_replaced
+ </value>
+ </property>
+ </bean>
+
+ <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" lazy-init="true">
+ <property name="dataSource" ref="myDs"/>
+ <property name="hibernateProperties">
+ <props>
+ <prop key="hibernate.dialect">dialect.that.doesnt.exist.and.should.be.auto_replaced</prop>
+ <prop key="hibernate.show_sql">true</prop>
+ <prop key="hibernate.generate_statistics">false</prop>
+ <!-- To avoid connecting to database during testing -->
+ <prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
+ </props>
+ </property>
+ </bean>
+
+</beans>
3  cloudfoundry-runtime/.gitignore
@@ -0,0 +1,3 @@
+.springBeans
+.settings/
+*.log
225 cloudfoundry-runtime/pom.xml
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.cloudfoundry</groupId>
+ <artifactId>cloudfoundry-runtime</artifactId>
+ <packaging>jar</packaging>
+ <name>Cloud Foundry Runtime for Java/Spring</name>
+ <version>0.6.0-BUILD-SNAPSHOT</version>
+ <properties>
+ <java.version>1.6</java.version>
+ <spring.version>3.0.5.RELEASE</spring.version>
+ <tomcat.version>6.0.29</tomcat.version>
+ <spring.amqp.version>1.0.0.BUILD-SNAPSHOT</spring.amqp.version>
+ </properties>
+ <dependencies>
+ <!-- Spring -->
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ <version>${spring.version}</version>
+ <exclusions>
+ <!-- Exclude Commons Logging in favor of SLF4j -->
+ <exclusion>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ </exclusion>
+ </exclusions>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-jdbc</artifactId>
+ <version>${spring.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-core-asl</artifactId>
+ <version>1.4.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ <version>1.4.1</version>
+ </dependency>
+
+ <!-- services -->
+ <dependency>
+ <groupId>mysql</groupId>
+ <artifactId>mysql-connector-java</artifactId>
+ <version>5.0.5</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.amqp</groupId>
+ <artifactId>spring-amqp</artifactId>
+ <version>${spring.amqp.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.amqp</groupId>
+ <artifactId>spring-rabbit</artifactId>
+ <version>${spring.amqp.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.data</groupId>
+ <artifactId>spring-data-redis</artifactId>
+ <version>1.0.0.BUILD-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.data</groupId>
+ <artifactId>spring-data-mongodb</artifactId>
+ <version>1.0.0.BUILD-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tomcat</groupId>
+ <artifactId>dbcp</artifactId>
+ <version>${tomcat.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-dbcp</groupId>
+ <artifactId>commons-dbcp</artifactId>
+ <version>1.3</version>
+ <scope>provided</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>commons-pool</groupId>
+ <artifactId>commons-pool</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>xerces</groupId>
+ <artifactId>xerces</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>xml-apis</groupId>
+ <artifactId>xml-apis</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <!-- Test -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.8.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.8.5</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-test</artifactId>
+ <version>${spring.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+ <repositories>
+ <!-- For testing against latest Spring snapshots -->
+ <repository>
+ <id>org.springframework.maven.snapshot</id>
+ <name>Spring Maven Snapshot Repository</name>
+ <url>http://maven.springframework.org/snapshot</url>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </repository>
+ <!-- For developing against latest Spring milestones -->
+ <repository>
+ <id>org.springframework.maven.milestone</id>
+ <name>Spring Maven Milestone Repository</name>
+ <url>http://maven.springframework.org/milestone</url>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </repository>
+ <repository>
+ <id>spring-maven-snapshot</id>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ <name>Springframework Maven SNAPSHOT Repository</name>
+ <url>http://maven.springframework.org/snapshot</url>
+ </repository>
+ </repositories>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${java.version}</source>
+ <target>${java.version}</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>install</id>
+ <phase>install</phase>
+ <goals>
+ <goal>sources</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <junitArtifactName>junit:junit</junitArtifactName>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>1.4</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <relocations>
+ <relocation>
+ <pattern>org.codehaus</pattern>
+ <shadedPattern>org.cloudfoundry.org.codehaus</shadedPattern>
+ </relocation>
+ </relocations>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
55 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/AbstractServiceInfo.java
@@ -0,0 +1,55 @@
+package org.cloudfoundry.runtime.env;
+
+import java.util.Map;
+
+/**
+ * Base information for all service types
+ *
+ * @author Ramnivas Laddad
+ *
+ */
+public abstract class AbstractServiceInfo {
+ private String serviceName;
+ private String plan;
+
+ private String host;
+ private int port;
+ private String password;
+
+ public AbstractServiceInfo(Map<String, Object> serviceInfo) {
+ serviceName = (String) serviceInfo.get("name");
+ plan = (String) serviceInfo.get("plan");
+
+ @SuppressWarnings("unchecked")
+ Map<String,Object> credentials = (Map<String, Object>) serviceInfo.get("credentials");
+ host = (String) credentials.get("hostname");
+ port = (Integer) credentials.get("port");
+
+ password = (String) credentials.get("password");
+ if (password == null) {
+ // For rabbitmq that uses 'pass'
+ password = (String) credentials.get("pass");
+ }
+ }
+
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ public String getPlan() {
+ return plan;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+}
78 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/ApplicationInstanceInfo.java
@@ -0,0 +1,78 @@
+package org.cloudfoundry.runtime.env;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * Examines VCAP_APPLICATION environment variable to provide application instance information.
+ * <p>
+ * This class expects the value for the environment variable in the following JSON form
+ * <pre>
+ * {
+ * "instance_id":"4057662a40caae017ac86fb3ab12f1a2",
+ * "instance_index":0,
+ * "name":"env",
+ * "uris":["env.vcap.me"],
+ * "users":["user@company.com"],
+ * "version":"8364547a15da0dd39aa8f62f0497ae1598bdd037",
+ * "start":"2011-04-02 11:39:11 -0700",
+ * "runtime":"ruby18",
+ * "state_timestamp":1301769551,
+ * "port":53160,
+ * "limits":{
+ * "fds":256,
+ * "mem":134217728,
+ * "disk":2147483648
+ * },
+ * "host":"127.0.0.1"
+ *}
+ *</code>
+ *
+ * @author Ramnivas Laddad
+ *
+ */
+public class ApplicationInstanceInfo {
+ private String name;
+ private int instanceIndex;
+ private List<String> uris;
+
+ private String host;
+ private int port;
+
+ @SuppressWarnings("unchecked")
+ public ApplicationInstanceInfo(Map<String, Object> info) {
+ name = (String) info.get("name");
+ instanceIndex = (Integer) info.get("instance_index");
+
+ uris = (List<String>) info.get("uris");
+
+ host = (String) info.get("host");
+ port = (Integer) info.get("port");
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getInstanceIndex() {
+ return instanceIndex;
+ }
+
+ public List<String> getUris() {
+ return uris;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+
+}
+
+
+
175 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/CloudEnvironment.java
@@ -0,0 +1,175 @@
+package org.cloudfoundry.runtime.env;
+
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.jackson.map.ObjectMapper;
+
+/**
+ * Simpler access to Cloud Foundry environment.
+ * <p>
+ * This class interprets environment variables and provide a simple
+ * access without needing JSON parsing.
+ * </p>
+ *
+ * @author Ramnivas Laddad
+ *
+ */
+public class CloudEnvironment {
+
+ private ObjectMapper objectMapper = new ObjectMapper();
+ private EnvironmentAccessor environment = new EnvironmentAccessor();
+
+ private static Map<Class<? extends AbstractServiceInfo>, String> serviceTypeToNameMap = new HashMap<Class<? extends AbstractServiceInfo>, String>();
+
+ static {
+ serviceTypeToNameMap.put(MysqlServiceInfo.class, "mysql-5.1");
+ serviceTypeToNameMap.put(RedisServiceInfo.class, "redis-2.2");
+ serviceTypeToNameMap.put(MongoServiceInfo.class, "mongodb-1.8");
+ serviceTypeToNameMap.put(RabbitServiceInfo.class, "rabbitmq-2.4");
+ }
+
+ /* package for testing purpose */
+ void setCloudEnvironment(EnvironmentAccessor environment) {
+ this.environment = environment;
+ }
+
+ public String getValue(String key) {
+ return environment.getValue(key);
+ }
+
+ @SuppressWarnings("unchecked")
+ public ApplicationInstanceInfo getInstanceInfo() {
+ String instanceInfoString = getValue("VCAP_APPLICATION");
+ if (instanceInfoString == null || instanceInfoString.trim().isEmpty()) {
+ return null;
+ }
+ try {
+ Map<String,Object> infoMap = objectMapper.readValue(instanceInfoString, Map.class);
+ return new ApplicationInstanceInfo(infoMap);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public String getCloudApiUri() {
+ ApplicationInstanceInfo instanceInfo = getInstanceInfo();
+ if (instanceInfo == null) {
+ throw new IllegalArgumentException("There is no cloud API urls in a non-cloud deployment");
+ }
+ List<String> uris = instanceInfo.getUris();
+ String defaultUri = uris.get(0);
+ return "api" + defaultUri.substring(defaultUri.indexOf("."));
+ }
+
+ /**
+ * Return object representation of the VCAP_SERIVCES environment variable
+ * <p>
+ * Returns a map whose key is the label (for example "redis-2.2") of the
+ * service and value is a list of services for that label. Each list element
+ * is a map with service attributes.
+ * </p>
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ private Map<String, List<Map<String,Object>>> getRawServices() {
+ String servicesString = getValue("VCAP_SERVICES");
+ if (servicesString == null || servicesString.length() == 0) {
+ return new HashMap<String, List<Map<String,Object>>>();
+ }
+ try {
+ return objectMapper.readValue(servicesString, Map.class);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public List<Map<String,Object>> getServices() {
+ Map<String, List<Map<String,Object>>> rawServices = getRawServices();
+
+ List<Map<String,Object>> flatServices = new ArrayList<Map<String,Object>>();
+ for (Map.Entry<String, List<Map<String,Object>>> entry : rawServices.entrySet()) {
+ flatServices.addAll(entry.getValue());
+ }
+ return flatServices;
+ }
+
+ private Map<String, Object> getServiceDataByName(String name) {
+ List<Map<String, Object>> services = getServices();
+
+ for (Map<String, Object> service : services) {
+ if (service.get("name").equals(name)) {
+ return service;
+ }
+ }
+ return null;
+ }
+
+ private List<Map<String, Object>> getServiceDataByServiceType(String type) {
+ List<Map<String, Object>> services = getServices();
+
+ List<Map<String, Object>> matchedServices = new ArrayList<Map<String,Object>>();
+
+ for (Map<String, Object> service : services) {
+ if (service.get("label").equals(type)) {
+ matchedServices.add(service);
+ }
+ }
+ return matchedServices;
+ }
+
+
+ public <T extends AbstractServiceInfo> T getServiceInfo(String name, Class<T> serviceInfoType) {
+ Map<String,Object> serviceInfoMap = getServiceDataByName(name);
+ String typeName = serviceTypeToNameMap.get(serviceInfoType);
+
+ if (serviceInfoMap.get("label").equals(typeName)) {
+ return getServiceInfo(serviceInfoMap, serviceInfoType);
+ }
+ return null;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public List<? extends AbstractServiceInfo> getServiceInfos() {
+ List serviceInfos = new ArrayList();
+ for (Map.Entry<Class<? extends AbstractServiceInfo>, String> serviceTypeToNameEntry : serviceTypeToNameMap.entrySet()) {
+ serviceInfos.addAll(getServiceInfos(serviceTypeToNameEntry.getKey()));
+ }
+ return serviceInfos;
+ }
+
+ public <T extends AbstractServiceInfo> List<T> getServiceInfos(Class<T> serviceInfoType) {
+ String typeName = serviceTypeToNameMap.get(serviceInfoType);
+ List<Map<String,Object>> serviceInfoMaps = getServiceDataByServiceType(typeName);
+
+ List<T> serviceInfos = new ArrayList<T>();
+ for (Map<String,Object> serviceInfoMap : serviceInfoMaps) {
+ serviceInfos.add(getServiceInfo(serviceInfoMap, serviceInfoType));
+ }
+ return serviceInfos;
+ }
+
+ private <T extends AbstractServiceInfo> T getServiceInfo(Map<String,Object> serviceInfoMap, Class<T> serviceInfoType) {
+ try {
+ Constructor<T> ctor = serviceInfoType.getConstructor(Map.class);
+ return ctor.newInstance(serviceInfoMap);
+ } catch (Exception e) {
+ throw new CloudServiceException("Failed to create service information for " + serviceInfoMap.get("name"), e);
+ }
+ }
+
+ /**
+ * Environment available to the deployed app.
+ *
+ * The main purpose of this class is to allow unit-testing of {@link CloudEnvironment}
+ *
+ */
+ public static class EnvironmentAccessor {
+ public String getValue(String key) {
+ return System.getenv(key);
+ }
+ }
+}
69 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/CloudEnvironmentPropertiesFactoryBean.java
@@ -0,0 +1,69 @@
+package org.cloudfoundry.runtime.env;
+
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.springframework.beans.factory.FactoryBean;
+
+/**
+ * FactoryBean exposing the current cloud service settings as properties,
+ * suitable for property placeholder processing.
+ *
+ * @author Costin Leau
+ */
+public class CloudEnvironmentPropertiesFactoryBean implements FactoryBean<Properties> {
+
+ private Properties properties;
+ private CloudEnvironment cloudEnv;
+
+ /**
+ * Sets the cloud environment (optional) for this factory bean.
+ *
+ * @param cloudEnv The cloudEnv to set.
+ */
+ public void setCloudEnv(CloudEnvironment cloudEnv) {
+ this.cloudEnv = cloudEnv;
+ }
+
+ @Override
+ public boolean isSingleton() {
+ return true;
+ }
+
+ @Override
+ public Class<Properties> getObjectType() {
+ return Properties.class;
+ }
+
+ @Override
+ public Properties getObject() throws Exception {
+ if (properties == null) {
+ properties = loadProperties();
+ }
+ return properties;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Properties loadProperties() {
+ Properties props = new Properties();
+ CloudEnvironment cloudEnv = (this.cloudEnv != null ? this.cloudEnv : new CloudEnvironment());
+ List<Map<String, Object>> services = cloudEnv.getServices();
+
+ for (Map<String, Object> map : services) {
+ String name = String.valueOf(map.get("name"));
+
+ Map<String, Object> ops = (Map<String, Object>) map.get("credentials");
+
+ if (ops != null) {
+ for (Map.Entry<String, Object> entry : ops.entrySet()) {
+ props.put(name + "." + entry.getKey(), String.valueOf(entry.getValue()));
+ }
+ }
+ }
+
+ return props;
+ }
+}
21 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/CloudServiceException.java
@@ -0,0 +1,21 @@
+package org.cloudfoundry.runtime.env;
+
+/**
+ * @author Ramnivas Laddad
+ */
+public class CloudServiceException extends RuntimeException {
+ private static final long serialVersionUID = -8609074700303153444L;
+
+ public CloudServiceException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public CloudServiceException(Throwable cause) {
+ super(cause);
+ }
+
+ public CloudServiceException(String message) {
+ super(message);
+ }
+
+}
16 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/MongoServiceInfo.java
@@ -0,0 +1,16 @@
+package org.cloudfoundry.runtime.env;
+
+import java.util.Map;
+
+
+/**
+ * Service info for Mongo.
+ *
+ * @author Ramnivas Laddad
+ *
+ */
+public class MongoServiceInfo extends AbstractServiceInfo {
+ public MongoServiceInfo(Map<String, Object> serviceInfo) {
+ super(serviceInfo);
+ }
+}
36 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/MysqlServiceInfo.java
@@ -0,0 +1,36 @@
+package org.cloudfoundry.runtime.env;
+
+import java.util.Map;
+
+
+/**
+ * Information to access Mysql service.
+ *
+ * @author Ramnivas Laddad
+ *
+ */
+public class MysqlServiceInfo extends AbstractServiceInfo {
+
+ private String database;
+
+ private String userName;
+
+ public MysqlServiceInfo(Map<String, Object> serviceInfo) {
+ super(serviceInfo);
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> credentials =
+ (Map<String, Object>) serviceInfo.get("credentials");
+ database = (String) credentials.get("name");
+
+ userName = (String) credentials.get("user");
+ }
+
+ public String getUrl() {
+ return "jdbc:mysql://" + getHost() + ":" + + getPort() + "/" + database;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+}
39 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/RabbitServiceInfo.java
@@ -0,0 +1,39 @@
+package org.cloudfoundry.runtime.env;
+
+import java.util.Map;
+
+
+/**
+ * Information to access RabbitMQ service.
+ *
+ * <p>
+ * This class expects the environment exposed with RabbitMQ service info to be
+ * in the following format:
+ *
+ * @author Ramnivas Laddad
+ *
+ */
+public class RabbitServiceInfo extends AbstractServiceInfo {
+
+ private String virtualHost;
+
+ private String userName;
+
+ public RabbitServiceInfo(Map<String, Object> serviceInfo) {
+ super(serviceInfo);
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> credentials =
+ (Map<String, Object>) serviceInfo.get("credentials");
+ userName = (String) credentials.get("user");
+ virtualHost = (String) credentials.get("vhost");
+ }
+
+ public String getVirtualHost() {
+ return virtualHost;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+}
16 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/env/RedisServiceInfo.java
@@ -0,0 +1,16 @@
+package org.cloudfoundry.runtime.env;
+
+import java.util.Map;
+
+
+/**
+ * Service info for Redis.
+ *
+ * @author Ramnivas Laddad
+ *
+ */
+public class RedisServiceInfo extends AbstractServiceInfo {
+ public RedisServiceInfo(Map<String, Object> serviceInfo) {
+ super(serviceInfo);
+ }
+}
49 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/AbstractCloudServiceFactory.java
@@ -0,0 +1,49 @@
+package org.cloudfoundry.runtime.service;
+
+import org.cloudfoundry.runtime.env.AbstractServiceInfo;
+import org.springframework.beans.factory.config.AbstractFactoryBean;
+
+/**
+ * Abstract base factory class.
+ * <p>
+ * This factory uses the service creator provided through the constructor to create services.
+ * If the service name is provided it creates a service object based on the service bound
+ * to that name. Otherwise, it creates a singleton service and fails if it doesn't
+ * find a unique service of the expected type.
+ *
+ * @author Ramnivas Laddad
+ *
+ * @param <S> The service type
+ * @param <SI> The service info type matching the service to be created
+ */
+public abstract class AbstractCloudServiceFactory<S, SI extends AbstractServiceInfo>
+ extends AbstractFactoryBean<S> {
+
+ private AbstractServiceCreator<S, SI> serviceCreator;
+
+ protected String serviceName;
+
+ public AbstractCloudServiceFactory(AbstractServiceCreator<S, SI> creationHelper) {
+ this.serviceCreator = creationHelper;
+ }
+
+ /**
+ * Optional service name property. If this property isn't set or set to null,
+ * unique service of the expected type (redis, for example) needs to be bound
+ * to the application.
+ *
+ * @param serviceName
+ */
+ public void setServiceName(String serviceName) {
+ this.serviceName = serviceName;
+ }
+
+ @Override
+ protected S createInstance() throws Exception {
+ if (serviceName != null) {
+ return serviceCreator.createService(serviceName);
+ } else {
+ return serviceCreator.createSingletonService().service;
+ }
+ }
+}
97 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/AbstractServiceCreator.java
@@ -0,0 +1,97 @@
+package org.cloudfoundry.runtime.service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.cloudfoundry.runtime.env.AbstractServiceInfo;
+import org.cloudfoundry.runtime.env.CloudEnvironment;
+import org.cloudfoundry.runtime.env.CloudServiceException;
+
+/**
+ * Base service creator
+ * <p>
+ * This class allows creating services based on
+ * <ul>
+ * <li>The singleton service of the matching type</li>
+ * <li>The service matching the given name</li>
+ * <li>All services matching of the matching type</li>
+ * </ul>
+ *
+ * @author Ramnivas Laddad
+ *
+ * @param <S> Service type to be create
+ * @param <SI> ServiceInfo type
+ */
+public abstract class AbstractServiceCreator<S, SI extends AbstractServiceInfo> {
+
+ private CloudEnvironment cloudEnvironment;
+ private Class<SI> serviceInfoClass;
+
+ public AbstractServiceCreator(CloudEnvironment cloudEnvironment, Class<SI> serviceInfoClass) {
+ this.cloudEnvironment = cloudEnvironment;
+ this.serviceInfoClass = serviceInfoClass;
+ }
+
+ /**
+ * Implementation of this method must create service based on the service info object passed.
+ *
+ * @param serviceInfo
+ * @return service
+ */
+ public abstract S createService(SI serviceInfo);
+
+ /**
+ * Create service based on the unique service of the required type.
+ *
+ * @return service object along with the name of the matching service
+ * @throws ServiceAccessException if unique service of the expected type isn't bound to the application
+ */
+ public ServiceNameTuple<S> createSingletonService() {
+ List<SI> serviceInfos = cloudEnvironment.getServiceInfos(serviceInfoClass);
+
+ if (serviceInfos.size() != 1) {
+ throw new CloudServiceException("Expected 1 service of " + serviceInfoClass + " type, but found " + serviceInfos.size());
+ }
+
+ SI singletonServiceInfo = serviceInfos.get(0);
+ return new ServiceNameTuple<S>(createService(singletonServiceInfo), singletonServiceInfo.getServiceName());
+ }
+
+ /**
+ * Create service object for the given name service bound to the application.
+ *
+ * @param serviceName
+ * @return service object
+ */
+ public S createService(String serviceName) {
+ SI serviceInfo = cloudEnvironment.getServiceInfo(serviceName, serviceInfoClass);
+ if (serviceInfo != null) {
+ return createService(serviceInfo);
+ }
+ return null;
+ }
+
+ /**
+ * Create service objects for all services of the matching type bound to the application.
+ *
+ * @return service objects along with the name of the matching services
+ */
+ public List<ServiceNameTuple<S>> createServices() {
+ List<SI> serviceInfos = cloudEnvironment.getServiceInfos(serviceInfoClass);
+ List<ServiceNameTuple<S>> services = new ArrayList<ServiceNameTuple<S>>();
+ for (SI serviceInfo : serviceInfos) {
+ services.add(new ServiceNameTuple<S>(createService(serviceInfo), serviceInfo.getServiceName()));
+ }
+ return services;
+ }
+
+ public static class ServiceNameTuple<S> {
+ public ServiceNameTuple(S service, String name) {
+ this.service = service;
+ this.name = name;
+ }
+
+ public S service;
+ public String name;
+ }
+}
89 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/CloudServicesAutoPopulator.java
@@ -0,0 +1,89 @@
+package org.cloudfoundry.runtime.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.cloudfoundry.runtime.env.CloudEnvironment;
+import org.cloudfoundry.runtime.env.CloudServiceException;
+import org.cloudfoundry.runtime.service.AbstractServiceCreator.ServiceNameTuple;
+import org.cloudfoundry.runtime.service.document.MongoServiceCreator;
+import org.cloudfoundry.runtime.service.keyvalue.RedisServiceCreator;
+import org.cloudfoundry.runtime.service.messaging.RabbitServiceCreator;
+import org.cloudfoundry.runtime.service.relational.MysqlServiceCreator;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+
+/**
+ * Bean factory post processor that adds a bean for each service bound to the application.
+ *
+ * <p>
+ * Each service populated by this bean has the same name as the service it is bound to.
+ * </p>
+ *
+ * Usage:
+ * <p>
+ * An application may add a bean of this type:
+ * <pre>
+ * &lt;bean class="org.cloudfoundry.runtime.service.CloudServicesAutoPopulator"/&gt;
+ * </pre>
+ * to have an easy access to all the services.
+ *
+ * If there is unique bean of a type, you can inject beans using the following
+ * code (shows Redis, but the same scheme works for all services):
+ * <pre>
+ * &#64;Autowired RedisConnectionFactory redisConnectionFactory;
+ * </pre>
+ *
+ * If there are more than one services of a type, you can use the @Qualifier
+ * as in the following code:
+ * <pre>
+ * &#64;Autowired &#64;Qualifier("service-name1") RedisConnectionFactory redisConnectionFactory;
+ * &#64;Autowired &#64;Qualifier("service-name2") RedisConnectionFactory redisConnectionFactory;
+ * </pre>
+ *
+ * You may, of course, use XML-based configuration.
+ *
+ * @author Ramnivas Laddad
+ *
+ */
+public class CloudServicesAutoPopulator implements BeanFactoryPostProcessor {
+
+ Logger logger = Logger.getLogger(CloudServicesAutoPopulator.class.getName());
+
+ @Override
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+ CloudEnvironment cloudEnvironment;
+
+ String[] envBeans = beanFactory.getBeanNamesForType(CloudEnvironment.class);
+ if (envBeans.length == 0) {
+ cloudEnvironment = new CloudEnvironment();
+ beanFactory.registerSingleton("cloud-environment", cloudEnvironment);
+ } else if (envBeans.length == 1){
+ cloudEnvironment = beanFactory.getBean(CloudEnvironment.class);
+ } else {
+ throw new CloudServiceException("CloudServicesAutoPopulator expects 0 or 1 bean of CloudEnvironment, found "
+ + envBeans.length);
+ }
+
+ List<AbstractServiceCreator> serviceCreators = new ArrayList<AbstractServiceCreator>();
+ serviceCreators.add(new MysqlServiceCreator(cloudEnvironment));
+ serviceCreators.add(new RedisServiceCreator(cloudEnvironment));
+ serviceCreators.add(new RabbitServiceCreator(cloudEnvironment));
+ serviceCreators.add(new MongoServiceCreator(cloudEnvironment));
+
+ logger.info("Auto-creating service beans");
+
+ for (AbstractServiceCreator serviceCreator : serviceCreators) {
+ List<ServiceNameTuple<Object>> serviceNamePairs = serviceCreator.createServices();
+ for (ServiceNameTuple<Object> serviceNamePair : serviceNamePairs) {
+ logger.info("Auto-creating service bean for " + serviceNamePair.name);
+ beanFactory.registerSingleton(serviceNamePair.name, serviceNamePair.service);
+ }
+ }
+
+ }
+
+}
55 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/config/xml/CloudNamespaceHandler.java
@@ -0,0 +1,55 @@
+package org.cloudfoundry.runtime.service.config.xml;
+
+import org.cloudfoundry.runtime.env.CloudEnvironmentPropertiesFactoryBean;
+import org.cloudfoundry.runtime.env.MongoServiceInfo;
+import org.cloudfoundry.runtime.env.MysqlServiceInfo;
+import org.cloudfoundry.runtime.env.RabbitServiceInfo;
+import org.cloudfoundry.runtime.env.RedisServiceInfo;
+import org.cloudfoundry.runtime.service.CloudServicesAutoPopulator;
+import org.cloudfoundry.runtime.service.document.CloudMongoFactoryBean;
+import org.cloudfoundry.runtime.service.keyvalue.CloudRedisConnectionFactoryBean;
+import org.cloudfoundry.runtime.service.messaging.CloudRabbitConnectionFactoryBean;
+import org.cloudfoundry.runtime.service.relational.CloudDataSourceFactory;
+import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
+import org.w3c.dom.Element;
+
+/**
+ * Handler for the 'cloud' namespace
+ *
+ * @author Mark Fisher
+ * @author Costin Leau
+ * @author Ramnivas Laddad
+ */
+public class CloudNamespaceHandler extends NamespaceHandlerSupport {
+
+ @Override
+ public void init() {
+ this.registerBeanDefinitionParser("rabbit-connection-factory",
+ new CloudServiceFactoryParser(CloudRabbitConnectionFactoryBean.class, RabbitServiceInfo.class));
+ this.registerBeanDefinitionParser("redis-connection-factory",
+ new CloudServiceFactoryParser(CloudRedisConnectionFactoryBean.class, RedisServiceInfo.class));
+ this.registerBeanDefinitionParser("mongo",
+ new CloudServiceFactoryParser(CloudMongoFactoryBean.class, MongoServiceInfo.class));
+ this.registerBeanDefinitionParser("data-source",
+ new CloudServiceFactoryParser(CloudDataSourceFactory.class, MysqlServiceInfo.class));
+
+ this.registerBeanDefinitionParser("service-properties", new AbstractSimpleBeanDefinitionParser() {
+ @Override
+ protected Class<?> getBeanClass(Element element) {
+ return CloudEnvironmentPropertiesFactoryBean.class;
+ }
+ });
+ this.registerBeanDefinitionParser("auto-populate", new AbstractSimpleBeanDefinitionParser() {
+ @Override
+ protected Class<?> getBeanClass(Element element) {
+ return CloudServicesAutoPopulator.class;
+ }
+
+ @Override
+ protected boolean shouldGenerateId() {
+ return true;
+ }
+ });
+ }
+}
68 ...foundry-runtime/src/main/java/org/cloudfoundry/runtime/service/config/xml/CloudServiceFactoryParser.java
@@ -0,0 +1,68 @@
+package org.cloudfoundry.runtime.service.config.xml;
+
+import java.util.List;
+
+import org.cloudfoundry.runtime.env.AbstractServiceInfo;
+import org.cloudfoundry.runtime.env.CloudEnvironment;
+import org.cloudfoundry.runtime.env.CloudServiceException;
+import org.springframework.beans.factory.BeanDefinitionStoreException;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
+
+/**
+ * @author Mark Fisher
+ */
+class CloudServiceFactoryParser extends AbstractSingleBeanDefinitionParser {
+
+ private final Class<?> beanClass;
+
+ private final Class<? extends AbstractServiceInfo> serviceInfoClass;
+
+ private final CloudEnvironment cloudEnvironment;
+
+
+ public CloudServiceFactoryParser(Class<?> beanClass, Class<? extends AbstractServiceInfo> serviceInfoClass) {
+ Assert.notNull(beanClass, "beanClass must not be null");
+ Assert.notNull(serviceInfoClass, "serviceInfoClass must not be null");
+ this.beanClass = beanClass;
+ this.serviceInfoClass = serviceInfoClass;
+ this.cloudEnvironment = new CloudEnvironment();
+ }
+
+
+ @Override
+ protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException {
+ String id = element.getAttribute(ID_ATTRIBUTE);
+ if (!StringUtils.hasText(id)) {
+ id = element.getAttribute("service-name");
+ }
+ if (!StringUtils.hasText(id)) {
+ List<? extends AbstractServiceInfo> serviceInfos = this.cloudEnvironment.getServiceInfos(this.serviceInfoClass);
+ if (serviceInfos.size() != 1) {
+ throw new CloudServiceException("No 'service-name' specified. Expected 1 service of " + serviceInfoClass + " type, but found " + serviceInfos.size());
+ }
+ id = serviceInfos.get(0).getServiceName();
+ }
+ return id;
+ }
+
+ @Override
+ protected final Class<?> getBeanClass(Element element) {
+ return this.beanClass;
+ }
+
+ @Override
+ protected final void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
+ builder.addConstructorArgValue(this.cloudEnvironment);
+ String serviceName = element.getAttribute("service-name");
+ if (StringUtils.hasText(serviceName)) {
+ builder.addPropertyValue("serviceName", serviceName);
+ }
+ }
+
+}
28 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/document/CloudMongoFactoryBean.java
@@ -0,0 +1,28 @@
+package org.cloudfoundry.runtime.service.document;
+
+import org.cloudfoundry.runtime.env.CloudEnvironment;
+import org.cloudfoundry.runtime.env.MongoServiceInfo;
+import org.cloudfoundry.runtime.service.AbstractCloudServiceFactory;
+
+import com.mongodb.Mongo;
+
+/**
+ * Spring factory bean for Mongo service.
+ *
+ * @author Ramnivas Laddad
+ *
+ */
+public class CloudMongoFactoryBean extends AbstractCloudServiceFactory<Mongo, MongoServiceInfo> {
+ public CloudMongoFactoryBean(CloudEnvironment cloudEnvironment) {
+ super(new MongoServiceCreator(cloudEnvironment));
+ }
+
+ public CloudMongoFactoryBean() {
+ super(new MongoServiceCreator(new CloudEnvironment()));
+ }
+
+ @Override
+ public Class<?> getObjectType() {
+ return Mongo.class;
+ }
+}
33 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/document/MongoServiceCreator.java
@@ -0,0 +1,33 @@
+package org.cloudfoundry.runtime.service.document;
+
+import java.net.UnknownHostException;
+
+import org.cloudfoundry.runtime.env.CloudEnvironment;
+import org.cloudfoundry.runtime.env.MongoServiceInfo;
+import org.cloudfoundry.runtime.env.CloudServiceException;
+import org.cloudfoundry.runtime.service.AbstractServiceCreator;
+
+import com.mongodb.Mongo;
+import com.mongodb.MongoException;
+
+/**
+ * Simplified access to creating MongoDB service objects.
+ *
+ * @author Ramnivas Laddad
+ *
+ */
+public class MongoServiceCreator extends AbstractServiceCreator<Mongo, MongoServiceInfo> {
+ public MongoServiceCreator(CloudEnvironment cloudEnvironment) {
+ super(cloudEnvironment, MongoServiceInfo.class);
+ }
+
+ public Mongo createService(MongoServiceInfo serviceInfo) {
+ try {
+ return new Mongo(serviceInfo.getHost(), serviceInfo.getPort());
+ } catch (UnknownHostException e) {
+ throw new CloudServiceException(e);
+ } catch (MongoException e) {
+ throw new CloudServiceException(e);
+ }
+ }
+}
27 ...dry-runtime/src/main/java/org/cloudfoundry/runtime/service/keyvalue/CloudRedisConnectionFactoryBean.java
@@ -0,0 +1,27 @@
+package org.cloudfoundry.runtime.service.keyvalue;
+
+import org.cloudfoundry.runtime.env.CloudEnvironment;
+import org.cloudfoundry.runtime.env.RedisServiceInfo;
+import org.cloudfoundry.runtime.service.AbstractCloudServiceFactory;
+import org.springframework.data.keyvalue.redis.connection.RedisConnectionFactory;
+
+/**
+ * Spring factory bean for Redis service.
+ *
+ * @author Ramnivas Laddad
+ *
+ */
+public class CloudRedisConnectionFactoryBean extends AbstractCloudServiceFactory<RedisConnectionFactory, RedisServiceInfo> {
+ public CloudRedisConnectionFactoryBean(CloudEnvironment cloudEnvironment) {
+ super(new RedisServiceCreator(cloudEnvironment));
+ }
+
+ public CloudRedisConnectionFactoryBean() {
+ super(new RedisServiceCreator(new CloudEnvironment()));
+ }
+
+ @Override
+ public Class<?> getObjectType() {
+ return RedisConnectionFactory.class;
+ }
+}
32 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/keyvalue/RedisServiceCreator.java
@@ -0,0 +1,32 @@
+package org.cloudfoundry.runtime.service.keyvalue;
+
+import org.cloudfoundry.runtime.env.CloudEnvironment;
+import org.cloudfoundry.runtime.env.RedisServiceInfo;
+import org.cloudfoundry.runtime.service.AbstractServiceCreator;
+import org.springframework.data.keyvalue.redis.connection.RedisConnectionFactory;
+import org.springframework.data.keyvalue.redis.connection.jedis.JedisConnectionFactory;
+
+/**
+ * Simplified access to creating Redis service objects.
+ *
+ * @author Ramnivas Laddad
+ *
+ */
+public class RedisServiceCreator
+ extends AbstractServiceCreator<RedisConnectionFactory, RedisServiceInfo> {
+
+ public RedisServiceCreator(CloudEnvironment cloudEnvironment) {
+ super(cloudEnvironment, RedisServiceInfo.class);
+ }
+
+ public RedisConnectionFactory createService(RedisServiceInfo serviceInfo) {
+ JedisConnectionFactory connectionFactory
+ = new JedisConnectionFactory();
+ connectionFactory.setHostName(serviceInfo.getHost());
+ connectionFactory.setPort(serviceInfo.getPort());
+ connectionFactory.setPassword(serviceInfo.getPassword());
+ connectionFactory.afterPropertiesSet();
+ return connectionFactory;
+ }
+
+}
28 ...y-runtime/src/main/java/org/cloudfoundry/runtime/service/messaging/CloudRabbitConnectionFactoryBean.java
@@ -0,0 +1,28 @@
+package org.cloudfoundry.runtime.service.messaging;
+
+import org.cloudfoundry.runtime.env.CloudEnvironment;
+import org.cloudfoundry.runtime.env.RabbitServiceInfo;
+import org.cloudfoundry.runtime.service.AbstractCloudServiceFactory;
+import org.springframework.amqp.rabbit.connection.ConnectionFactory;
+
+/**
+ * Spring factory bean for Rabbit service.
+ *
+ * @author Ramnivas Laddad
+ *
+ */
+public class CloudRabbitConnectionFactoryBean extends AbstractCloudServiceFactory<ConnectionFactory, RabbitServiceInfo> {
+
+ public CloudRabbitConnectionFactoryBean(CloudEnvironment cloudEnvironment) {
+ super(new RabbitServiceCreator(cloudEnvironment));
+ }
+
+ public CloudRabbitConnectionFactoryBean() {
+ super(new RabbitServiceCreator(new CloudEnvironment()));
+ }
+
+ @Override
+ public Class<?> getObjectType() {
+ return ConnectionFactory.class;
+ }
+}
32 cloudfoundry-runtime/src/main/java/org/cloudfoundry/runtime/service/messaging/RabbitServiceCreator.java
<
@@ -0,0 +1,32 @@
+package org.cloudfoundry.runtime.service.messaging;
+
+import org.cloudfoundry.runtime.env.CloudEnvironment;