Merge branch 'cf-post-processor'
This commit is contained in:
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
#Wed Jun 29 17:49:51 EDT 2016
|
||||
#Tue May 02 16:25:04 CDT 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package org.springframework.cloud.cloudfoundry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
import org.springframework.cloud.AbstractCloudConnector;
|
||||
import org.springframework.cloud.CloudException;
|
||||
@@ -17,7 +17,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
/**
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public class CloudFoundryConnector extends AbstractCloudConnector<Map<String,Object>> {
|
||||
|
||||
@@ -25,10 +25,13 @@ public class CloudFoundryConnector extends AbstractCloudConnector<Map<String,Obj
|
||||
private EnvironmentAccessor environment = new EnvironmentAccessor();
|
||||
|
||||
private ApplicationInstanceInfoCreator applicationInstanceInfoCreator = new ApplicationInstanceInfoCreator();
|
||||
|
||||
|
||||
private Iterable<ServiceDataPostProcessor> serviceDataPostProcessors;
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public CloudFoundryConnector() {
|
||||
super((Class) CloudFoundryServiceInfoCreator.class);
|
||||
scanServiceDataPostProcessors();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,20 +67,25 @@ public class CloudFoundryConnector extends AbstractCloudConnector<Map<String,Obj
|
||||
@SuppressWarnings("unchecked")
|
||||
protected List<Map<String,Object>> getServicesData() {
|
||||
String servicesString = environment.getEnvValue("VCAP_SERVICES");
|
||||
Map<String, List<Map<String,Object>>> rawServices = new HashMap<String, List<Map<String,Object>>>();
|
||||
CloudFoundryRawServiceData rawServices = new CloudFoundryRawServiceData();
|
||||
|
||||
if (servicesString != null && servicesString.length() > 0) {
|
||||
try {
|
||||
rawServices = objectMapper.readValue(servicesString, Map.class);
|
||||
rawServices = objectMapper.readValue(servicesString, CloudFoundryRawServiceData.class);
|
||||
} catch (Exception e) {
|
||||
throw new CloudException(e);
|
||||
}
|
||||
}
|
||||
|
||||
List<Map<String,Object>> flatServices = new ArrayList<Map<String,Object>>();
|
||||
for (ServiceDataPostProcessor postProcessor : serviceDataPostProcessors) {
|
||||
rawServices = postProcessor.process(rawServices);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -86,6 +94,10 @@ public class CloudFoundryConnector extends AbstractCloudConnector<Map<String,Obj
|
||||
protected FallbackServiceInfoCreator<BaseServiceInfo,Map<String,Object>> getFallbackServiceInfoCreator() {
|
||||
return new CloudFoundryFallbackServiceInfoCreator();
|
||||
}
|
||||
|
||||
private void scanServiceDataPostProcessors() {
|
||||
serviceDataPostProcessors = ServiceLoader.load(ServiceDataPostProcessor.class);
|
||||
}
|
||||
}
|
||||
|
||||
class CloudFoundryFallbackServiceInfoCreator extends FallbackServiceInfoCreator<BaseServiceInfo,Map<String,Object>> {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.springframework.cloud.cloudfoundry;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A {@link CloudFoundryRawServiceData} object represents the data read from the {@literal VCAP_SERVICES}
|
||||
* environment variable and transformed from JSON text to a collection of objects.
|
||||
*
|
||||
* The root of the data structure is a {@link List}. Each element of the list represents one service from
|
||||
* the JSON.
|
||||
*/
|
||||
public class CloudFoundryRawServiceData extends HashMap<String, List<Map<String,Object>>> {
|
||||
public CloudFoundryRawServiceData() {
|
||||
super();
|
||||
}
|
||||
|
||||
public CloudFoundryRawServiceData(Map<? extends String, ? extends List<Map<String, Object>>> map) {
|
||||
super(map);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.springframework.cloud.cloudfoundry;
|
||||
|
||||
/**
|
||||
* An extension point that allows service data to be processed after it is read from {@literal VCAP_SERVICES}.
|
||||
*/
|
||||
public interface ServiceDataPostProcessor {
|
||||
/**
|
||||
* Process raw service data as read from {@literal VCAP_SERVICES}.
|
||||
*
|
||||
* This method will be called after the {@literal VCAP_SERVICES} environment variable has been read from
|
||||
* the environment and transformed from JSON text into a {@link CloudFoundryRawServiceData} data structure.
|
||||
*
|
||||
* If the {@literal VCAP_SERVICES} environment variable for an application contains the following:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* "VCAP_SERVICES": {
|
||||
* "mysql": [
|
||||
* {
|
||||
* "label": "mysql",
|
||||
* "name": "mysql-db",
|
||||
* "plan": "100mb",
|
||||
* "tags": [ "mysql", "relational" ],
|
||||
* "credentials": {
|
||||
* "jdbcUrl": "jdbc:mysql://mysql-broker:3306/db?user=username\u0026password=password",
|
||||
* "uri": "mysql://username:password@mysql-broker:3306/db?reconnect=true",
|
||||
* }
|
||||
* }
|
||||
* ],
|
||||
* "rabbitmq": [
|
||||
* {
|
||||
* "label": "rabbitmq",
|
||||
* "name": "rabbit-queue",
|
||||
* "plan": "standard",
|
||||
* "tags": [ "rabbitmq", "messaging" ],
|
||||
* "credentials": {
|
||||
* "http_api_uri": "http://username:password@rabbitmq-broker:12345/api",
|
||||
* "uri": "amqp://username:password@rabbitmq-broker/vhost",
|
||||
* }
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Then the {@link CloudFoundryRawServiceData} data structure would contain the equivalent of this:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* {
|
||||
* "mysql": [
|
||||
* {
|
||||
* "label": "mysql",
|
||||
* "name": "mysql-db",
|
||||
* "plan": "100mb",
|
||||
* "tags": [ "mysql", "relational" ],
|
||||
* "credentials": {
|
||||
* "jdbcUrl": "jdbc:mysql://mysql-broker:3306/db?user=username\u0026password=password",
|
||||
* "uri": "mysql://username:password@mysql-broker:3306/db?reconnect=true",
|
||||
* }
|
||||
* }
|
||||
* ]
|
||||
* "rabbitmq": [
|
||||
* {
|
||||
* "label": "rabbitmq",
|
||||
* "name": "rabbit-queue",
|
||||
* "plan": "standard",
|
||||
* "tags": [ "rabbitmq", "messaging" ],
|
||||
* "credentials": {
|
||||
* "http_api_uri": "http://username:password@rabbitmq-broker:12345/api",
|
||||
* "uri": "amqp://username:password@rabbitmq-broker/vhost",
|
||||
* }
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param serviceData the service data parsed from {@literal VCAP_SERVICES}
|
||||
* @return the provided {@literal serviceData} with modifications
|
||||
*/
|
||||
CloudFoundryRawServiceData process(CloudFoundryRawServiceData serviceData);
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
package org.springframework.cloud.cloudfoundry;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -12,6 +14,7 @@ import java.util.List;
|
||||
import org.junit.Test;
|
||||
import org.springframework.cloud.CloudException;
|
||||
import org.springframework.cloud.service.ServiceInfo;
|
||||
import org.springframework.cloud.service.common.MysqlServiceInfo;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -95,4 +98,15 @@ public class CloudFoundryConnectorApplicationTest extends AbstractCloudFoundryCo
|
||||
assertEquals(1, serviceInfos.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serviceInfosWithPostProcessedCredentials() {
|
||||
when(mockEnvironment.getEnvValue("VCAP_SERVICES")).
|
||||
thenReturn(getServicesPayload(readTestDataFile("test-credentials-post-processed.json")));
|
||||
List<ServiceInfo> serviceInfos = testCloudConnector.getServiceInfos();
|
||||
assertNotNull(serviceInfos);
|
||||
assertEquals(1, serviceInfos.size());
|
||||
assertThat(serviceInfos.get(0), instanceOf(MysqlServiceInfo.class));
|
||||
assertEquals(((MysqlServiceInfo) serviceInfos.get(0)).getUri(), "MYSQL://USERNAME:PASSWORD@DB.EXAMPLE.COM/DB");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.springframework.cloud.cloudfoundry;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class StubServiceDataPostProcessor implements ServiceDataPostProcessor {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public CloudFoundryRawServiceData process(CloudFoundryRawServiceData serviceData) {
|
||||
for (List<Map<String, Object>> service : serviceData.values()) {
|
||||
Map<String, Object> serviceMap = service.get(0);
|
||||
String name = (String) serviceMap.get("name");
|
||||
if (name.equals("uppercase")) {
|
||||
Map<String, Object> credentials = (Map<String, Object>) serviceMap.get("credentials");
|
||||
for (Map.Entry<String, Object> entry : credentials.entrySet()) {
|
||||
String upperCaseValue = ((String) entry.getValue()).toUpperCase();
|
||||
credentials.put(entry.getKey(), upperCaseValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return serviceData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.cloud.cloudfoundry.StubServiceDataPostProcessor
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "uppercase",
|
||||
"label": "mysql",
|
||||
"tags": ["mysql"],
|
||||
"credentials": {
|
||||
"uri": "mysql://username:password@db.example.com/db"
|
||||
}
|
||||
}
|
||||
@@ -90,14 +90,14 @@ public class CloudTestUtil {
|
||||
public StubServiceInfo(String id, String host, int port, String username, String password) {
|
||||
super(id, "stub", host, port, username, password, null);
|
||||
}
|
||||
|
||||
// To test the scenario, where the name attribute of a property is explicitly specified
|
||||
|
||||
// To test the scenario, where the name attribute of a property is explicitly specified
|
||||
@ServiceProperty(name="bar")
|
||||
public String getFoo() {
|
||||
return "foo";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class StubCompositeServiceInfo implements CompositeServiceInfo {
|
||||
private String id;
|
||||
private List<ServiceInfo> constituents;
|
||||
|
||||
Reference in New Issue
Block a user