Support flattening of composite services

This commit is contained in:
Ramnivas Laddad
2014-08-22 11:47:47 -07:00
parent d005a06d24
commit 908ade4721
6 changed files with 141 additions and 1 deletions

View File

@@ -14,6 +14,7 @@ import java.util.logging.Logger;
import javax.activation.DataSource;
import org.springframework.cloud.app.ApplicationInstanceInfo;
import org.springframework.cloud.service.CompositeServiceInfo;
import org.springframework.cloud.service.ServiceConnectorConfig;
import org.springframework.cloud.service.ServiceConnectorCreator;
import org.springframework.cloud.service.ServiceInfo;
@@ -88,7 +89,7 @@ public class Cloud {
* @return information about all services bound to the application
*/
public List<ServiceInfo> getServiceInfos() {
return cloudConnector.getServiceInfos();
return flatten(cloudConnector.getServiceInfos());
}
/**
@@ -316,6 +317,24 @@ public class Cloud {
return labelAnnotation.value();
}
}
private static List<ServiceInfo> flatten(List<ServiceInfo> serviceInfos) {
List<ServiceInfo> flattened = new ArrayList<ServiceInfo>();
for (ServiceInfo serviceInfo : serviceInfos) {
if (serviceInfo instanceof CompositeServiceInfo) {
// recursively flatten any CompositeServiceInfos
CompositeServiceInfo compositeServiceInfo = (CompositeServiceInfo)serviceInfo;
flattened.addAll(flatten(compositeServiceInfo.getServiceInfos()));
} else {
flattened.add(serviceInfo);
}
}
return flattened;
}
}
class ServiceConnectorCreatorRegistry {

View File

@@ -0,0 +1,25 @@
package org.springframework.cloud.service;
import java.util.Arrays;
import java.util.List;
/**
* A generic implementation of {@link CompositeServiceInfo} that should suffice in many situations.
*
* @author Ramnivas Laddad
*
*/
public class BaseCompositeServiceInfo extends BaseServiceInfo implements CompositeServiceInfo {
private List<ServiceInfo> constituents;
public BaseCompositeServiceInfo(String id, ServiceInfo... constituents) {
super(id);
this.constituents = Arrays.asList(constituents);
}
@Override
public List<ServiceInfo> getServiceInfos() {
return constituents;
}
}

View File

@@ -0,0 +1,24 @@
package org.springframework.cloud.service;
import java.util.List;
import org.springframework.cloud.Cloud;
/**
* Interface to represent services constituted out of other services.
*
* <p>
* With services such as Pivotal HD, even though the app will be bound to one such service,
* from the application developer's point of view, it needs to access the constituent services.
* This interface expresses such a service, which the {@link Cloud} class flattens into
* its constituents. Then from the rest of the Spring Cloud infrastructure as well as application
* code, the effect is as if all the constituents were individually bound.
*
* @author Ramnivas Laddad
*
*/
public interface CompositeServiceInfo extends ServiceInfo {
List<ServiceInfo> getServiceInfos();
}

View File

@@ -104,4 +104,19 @@ class TestServiceData {
public String getTag() {
return tag;
}
}
class TestCompositeServiceData extends TestServiceData {
private TestServiceData[] constituents;
public TestCompositeServiceData(String id, String tag, TestServiceData... constituents) {
super(id, tag);
this.constituents = constituents;
}
public TestServiceData[] getConstituents() {
return constituents;
}
}

View File

@@ -14,6 +14,7 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.cloud.CloudTestUtil.StubApplicationInstanceInfo;
import org.springframework.cloud.CloudTestUtil.StubCloudConnector;
import org.springframework.cloud.CloudTestUtil.StubCompositeServiceInfo;
import org.springframework.cloud.CloudTestUtil.StubServiceInfo;
import org.springframework.cloud.service.BaseServiceInfo;
import org.springframework.cloud.service.ServiceConnectorConfig;
@@ -182,7 +183,41 @@ public class CloudTest {
testCloud.getServiceInfo("foo");
}
@Test
public void compositeServiceInfo() {
StubServiceInfo testServiceInfo1 = new StubServiceInfo("test-id-1", "test-host", 1000, "test-username", "test-password");
StubServiceInfo testServiceInfo2 = new StubServiceInfo("test-id-2", "test-host", 1000, "test-username", "test-password");
ServiceInfo testCompositeServiceInfo = new StubCompositeServiceInfo("test-composite",testServiceInfo1, testServiceInfo2);
StubCloudConnector stubCloudConnector = CloudTestUtil.getTestCloudConnector(testCompositeServiceInfo);
Cloud testCloud = new Cloud(stubCloudConnector, serviceConnectorCreators);
assertNotNull(testCloud.getServiceInfo("test-id-1"));
assertNotNull(testCloud.getServiceInfo("test-id-2"));
}
@Test
public void compositeServiceInfoRecursive() {
StubServiceInfo testServiceInfo1a = new StubServiceInfo("test-id-1a", "test-host", 1000, "test-username", "test-password");
StubServiceInfo testServiceInfo1b = new StubServiceInfo("test-id-1b", "test-host", 1000, "test-username", "test-password");
ServiceInfo testCompositeServiceInfo1 = new StubCompositeServiceInfo("test-composite-1",testServiceInfo1a, testServiceInfo1b);
StubServiceInfo testServiceInfo2a = new StubServiceInfo("test-id-2a", "test-host", 1000, "test-username", "test-password");
StubServiceInfo testServiceInfo2b = new StubServiceInfo("test-id-2b", "test-host", 1000, "test-username", "test-password");
ServiceInfo testCompositeServiceInfo2 = new StubCompositeServiceInfo("test-composite-2",testServiceInfo2a, testServiceInfo2b);
ServiceInfo testCompositeServiceInfo = new StubCompositeServiceInfo("test-composite",testCompositeServiceInfo1, testCompositeServiceInfo2);
StubCloudConnector stubCloudConnector = CloudTestUtil.getTestCloudConnector(testCompositeServiceInfo);
Cloud testCloud = new Cloud(stubCloudConnector, serviceConnectorCreators);
assertNotNull(testCloud.getServiceInfo("test-id-1a"));
assertNotNull(testCloud.getServiceInfo("test-id-1b"));
assertNotNull(testCloud.getServiceInfo("test-id-2a"));
assertNotNull(testCloud.getServiceInfo("test-id-2b"));
}
private void assertStubServiceProp(String leadKey, StubServiceInfo serviceInfo, Properties cloudProperties) {
CloudTestUtil.assertBasicProps(leadKey, serviceInfo, cloudProperties);

View File

@@ -3,6 +3,7 @@ package org.springframework.cloud;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -10,6 +11,7 @@ import java.util.Properties;
import org.springframework.cloud.CloudConnector;
import org.springframework.cloud.app.ApplicationInstanceInfo;
import org.springframework.cloud.service.CompositeServiceInfo;
import org.springframework.cloud.service.UriBasedServiceInfo;
import org.springframework.cloud.service.ServiceInfo;
import org.springframework.cloud.service.ServiceInfo.ServiceLabel;
@@ -96,6 +98,26 @@ public class CloudTestUtil {
}
}
public static class StubCompositeServiceInfo implements CompositeServiceInfo {
private String id;
private List<ServiceInfo> constituents;
public StubCompositeServiceInfo(String id, ServiceInfo... constituents) {
this.id = id;
this.constituents = Arrays.asList(constituents);
}
@Override
public String getId() {
return id;
}
@Override
public List<ServiceInfo> getServiceInfos() {
return constituents;
}
}
public static StubCloudConnector getTestCloudConnector(ApplicationInstanceInfo applicationInstanceInfo, ServiceInfo... serviceInfos) {
final StubCloudConnector stubCloudConnector = getTestCloudConnector(serviceInfos);
stubCloudConnector.setApplicationInstance(applicationInstanceInfo);