clean up Javadocs to make Java 8 happy
This commit is contained in:
@@ -22,320 +22,346 @@ import org.springframework.cloud.service.ServiceInfo.ServiceProperty;
|
||||
|
||||
/**
|
||||
* The main user-level API access to application and services for the app in which this instance is embedded in.
|
||||
*
|
||||
* The class connects application and the underlying cloud. Besides passing along information about the application
|
||||
* instance, it allows simple access for using services. It uses {@link ServiceInfo}s obtained using the
|
||||
*
|
||||
* The class connects application and the underlying cloud. Besides passing along information about the application
|
||||
* instance, it allows simple access for using services. It uses {@link ServiceInfo}s obtained using the
|
||||
* underlying {@link CloudConnector} and allows translating those to service connector such as a {@link DataSource}.
|
||||
*
|
||||
*
|
||||
* It also passes along information obtained through {@link CloudConnector} to let application take control on how
|
||||
* to use bound services.
|
||||
*
|
||||
* <p>NOTE: Users or cloud providers shouldn't need to instantiate an instance of this class
|
||||
* (constructor has package-access only for unit-testing purpose). Instead, they can obtain an appropriate
|
||||
* instance through {@link CloudFactory}</p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* NOTE: Users or cloud providers shouldn't need to instantiate an instance of this class (constructor has package-access only for
|
||||
* unit-testing purpose). Instead, they can obtain an appropriate instance through {@link CloudFactory}
|
||||
* </p>
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
*/
|
||||
public class Cloud {
|
||||
private CloudConnector cloudConnector;
|
||||
private ServiceConnectorCreatorRegistry serviceConnectorCreatorRegistry = new ServiceConnectorCreatorRegistry();
|
||||
|
||||
/**
|
||||
* Package-access constructor.
|
||||
*
|
||||
* @param cloudConnector the underlying connector
|
||||
* @param serviceConnectorCreators service connector creators
|
||||
*/
|
||||
Cloud(CloudConnector cloudConnector, List<ServiceConnectorCreator<?, ? extends ServiceInfo>> serviceConnectorCreators) {
|
||||
this.cloudConnector = cloudConnector;
|
||||
|
||||
for (ServiceConnectorCreator<?, ? extends ServiceInfo> serviceCreator: serviceConnectorCreators) {
|
||||
registerServiceConnectorCreator(serviceCreator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CloudConnector#getApplicationInstanceInfo()
|
||||
*
|
||||
* @return information about the application instance
|
||||
*/
|
||||
public ApplicationInstanceInfo getApplicationInstanceInfo() {
|
||||
return cloudConnector.getApplicationInstanceInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link ServiceInfo} for the given service id
|
||||
*
|
||||
* @param serviceId service id
|
||||
* @return info for the serviceId
|
||||
*/
|
||||
public ServiceInfo getServiceInfo(String serviceId) {
|
||||
for (ServiceInfo serviceInfo : getServiceInfos()) {
|
||||
if (serviceInfo.getId().equals(serviceId)) {
|
||||
return serviceInfo;
|
||||
}
|
||||
}
|
||||
throw new CloudException("No service with id " + serviceId + " found");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CloudConnector#getServiceInfos()
|
||||
* @return information about all services bound to the application
|
||||
*/
|
||||
public List<ServiceInfo> getServiceInfos() {
|
||||
return cloudConnector.getServiceInfos();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link ServiceInfo}s for the bound services that could be mapped to the given service connector type.
|
||||
*
|
||||
* <p>
|
||||
* For example, if the connector type is {@link DataSource}, then the method will return
|
||||
* all {@link ServiceInfo} objects matching bound relational database services.
|
||||
* <p>
|
||||
*
|
||||
* @param serviceConnectorType service connector type.
|
||||
* Passing null returns all {@link ServiceInfo}s (matching that of {@link Cloud#getServiceInfos()}
|
||||
* @return information about services bound to the application that could be transformed into the given connector type
|
||||
*/
|
||||
public <T> List<ServiceInfo> getServiceInfos(Class<T> serviceConnectorType) {
|
||||
List<ServiceInfo> allServiceInfos = getServiceInfos();
|
||||
List<ServiceInfo> matchingServiceInfos = new ArrayList<ServiceInfo>();
|
||||
|
||||
for (ServiceInfo serviceInfo: allServiceInfos) {
|
||||
if (serviceConnectorCreatorRegistry.canCreate(serviceConnectorType, serviceInfo)) {
|
||||
matchingServiceInfos.add(serviceInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return matchingServiceInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a service connector for the given service id, the connector type, configured with the given config
|
||||
*
|
||||
* @param serviceId the service id
|
||||
* @param serviceConnectorType The expected class of service connector such as, DataSource.class.
|
||||
* @param serviceConnectorConfig service connector configuration (such as pooling parameters).
|
||||
*
|
||||
*/
|
||||
public <SC> SC getServiceConnector(String serviceId, Class<SC> serviceConnectorType, ServiceConnectorConfig serviceConnectorConfig) {
|
||||
ServiceInfo serviceInfo = getServiceInfo(serviceId);
|
||||
|
||||
return getServiceConnector(serviceInfo, serviceConnectorType, serviceConnectorConfig);
|
||||
}
|
||||
private CloudConnector cloudConnector;
|
||||
private ServiceConnectorCreatorRegistry serviceConnectorCreatorRegistry = new ServiceConnectorCreatorRegistry();
|
||||
|
||||
/**
|
||||
* Get the singleton service connector for the given connector type, configured with the given config
|
||||
*
|
||||
* @param serviceConnectorType The expected class of service connector such as, DataSource.class.
|
||||
* @param serviceConnectorConfig service connector configuration (such as pooling parameters).
|
||||
*
|
||||
*/
|
||||
public <SC> SC getSingletonServiceConnector(Class<SC> serviceConnectorType, ServiceConnectorConfig serviceConnectorConfig) {
|
||||
List<ServiceInfo> matchingServiceInfos = getServiceInfos(serviceConnectorType);
|
||||
|
||||
if (matchingServiceInfos.size() != 1) {
|
||||
throw new CloudException("No unique service matching " + serviceConnectorType + " found. Expected 1, found " + matchingServiceInfos.size());
|
||||
}
|
||||
|
||||
ServiceInfo matchingServiceInfo = matchingServiceInfos.get(0);
|
||||
|
||||
return getServiceConnector(matchingServiceInfo, serviceConnectorType, serviceConnectorConfig);
|
||||
}
|
||||
/**
|
||||
* Package-access constructor.
|
||||
*
|
||||
* @param cloudConnector
|
||||
* the underlying connector
|
||||
* @param serviceConnectorCreators
|
||||
* service connector creators
|
||||
*/
|
||||
Cloud(CloudConnector cloudConnector, List<ServiceConnectorCreator<?, ? extends ServiceInfo>> serviceConnectorCreators) {
|
||||
this.cloudConnector = cloudConnector;
|
||||
|
||||
/**
|
||||
* Register a new service connector creator
|
||||
*
|
||||
* @param serviceConnectorCreator
|
||||
*/
|
||||
public void registerServiceConnectorCreator(ServiceConnectorCreator<?, ? extends ServiceInfo> serviceConnectorCreator) {
|
||||
serviceConnectorCreatorRegistry.registerCreator(serviceConnectorCreator);
|
||||
}
|
||||
for (ServiceConnectorCreator<?, ? extends ServiceInfo> serviceCreator : serviceConnectorCreators) {
|
||||
registerServiceConnectorCreator(serviceCreator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get properties for app and services.
|
||||
*
|
||||
*
|
||||
*
|
||||
* <p>Application properties always include <code>cloud.application.app-id</code>
|
||||
* and <code>cloud.application.instance-id</code> with values bound to application id and
|
||||
* instance id. The rest of the properties are cloud-provider specific, but take the
|
||||
* <code>cloud.application.<property-name></code> form.
|
||||
* <code><pre>
|
||||
* cloud.application.app-id = helloworld
|
||||
* cloud.application.instance-id = instance-0-0fab098f
|
||||
* cloud.application.<property-name> = <property-value>
|
||||
* </pre></code>
|
||||
*
|
||||
* <p>Service specific properties are exposed for each bound service, with each key starting
|
||||
* in <code>cloud.services</code>. Like application properties, these too are cloud and service specific.
|
||||
* Each key for a specific service starts with <code>cloud.services.<service-id></code>
|
||||
* <code><pre>
|
||||
* cloud.services.customerDb.type = mysql-5.1
|
||||
* cloud.services.customerDb.plan = free
|
||||
* cloud.services.customerDb.connection.hostname = ...
|
||||
* cloud.services.customerDb.connection.port = ...
|
||||
* etc...
|
||||
* </pre></code>
|
||||
*
|
||||
* <p>If a there is only a single service of a given type, that service is
|
||||
* aliased to the service type. Keys for such properties start in <code>cloud.services.<service-type></code>.
|
||||
* For example, if there is only a single MySQL service bound to the application, the service properties will also be
|
||||
* exposed starting with '<code>cloud.services.mysql</code>' key:
|
||||
* <code><pre>
|
||||
* cloud.services.mysql.type = mysql-5.1
|
||||
* cloud.services.mysql.plan = free
|
||||
* cloud.services.mysql.connection.hostname = ...
|
||||
* cloud.services.mysql.connection.port = ...
|
||||
* etc...
|
||||
* </pre></code>
|
||||
*
|
||||
* @return the properties object
|
||||
*/
|
||||
public Properties getCloudProperties() {
|
||||
Map<String, List<ServiceInfo>> mappedServiceInfos = new HashMap<String, List<ServiceInfo>>();
|
||||
for (ServiceInfo serviceInfo : getServiceInfos()) {
|
||||
String key = getServiceLabel(serviceInfo);
|
||||
List<ServiceInfo> serviceInfosForLabel = mappedServiceInfos.get(key);
|
||||
if (serviceInfosForLabel == null) {
|
||||
serviceInfosForLabel = new ArrayList<ServiceInfo>();
|
||||
mappedServiceInfos.put(key, serviceInfosForLabel);
|
||||
}
|
||||
serviceInfosForLabel.add(serviceInfo);
|
||||
}
|
||||
|
||||
final String servicePropKeyLead = "cloud.services.";
|
||||
Properties cloudProperties = new Properties();
|
||||
for (Entry<String, List<ServiceInfo>> mappedServiceInfo : mappedServiceInfos.entrySet()) {
|
||||
List<ServiceInfo> serviceInfos = mappedServiceInfo.getValue();
|
||||
|
||||
for (ServiceInfo serviceInfo : serviceInfos) {
|
||||
String idBasedKey = servicePropKeyLead + serviceInfo.getId();
|
||||
cloudProperties.putAll(getServiceProperties(idBasedKey, serviceInfo));
|
||||
|
||||
// If there is only one service for a given label, put props with that label instead of just id
|
||||
if (serviceInfos.size() == 1) {
|
||||
String labelBasedKey = servicePropKeyLead + mappedServiceInfo.getKey();
|
||||
cloudProperties.putAll(getServiceProperties(labelBasedKey, serviceInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cloudProperties.putAll(getAppProperties());
|
||||
|
||||
return cloudProperties;
|
||||
}
|
||||
|
||||
private <SC> SC getServiceConnector(ServiceInfo serviceInfo, Class<SC> serviceConnectorType, ServiceConnectorConfig serviceConnectorConfig) {
|
||||
ServiceConnectorCreator<SC, ServiceInfo> serviceConnectorCreator = serviceConnectorCreatorRegistry.getServiceCreator(serviceConnectorType, serviceInfo);
|
||||
return serviceConnectorCreator.create(serviceInfo, serviceConnectorConfig);
|
||||
}
|
||||
|
||||
private Properties getAppProperties() {
|
||||
final String appPropLeadKey = "cloud.application.";
|
||||
|
||||
Properties appProperties = new Properties();
|
||||
appProperties.put(appPropLeadKey + "instance-id", getApplicationInstanceInfo().getInstanceId());
|
||||
appProperties.put(appPropLeadKey + "app-id", getApplicationInstanceInfo().getAppId());
|
||||
for (Map.Entry<String, Object> entry : getApplicationInstanceInfo().getProperties().entrySet()) {
|
||||
if (entry.getValue() != null) {
|
||||
appProperties.put(appPropLeadKey + entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @see CloudConnector#getApplicationInstanceInfo()
|
||||
*
|
||||
* @return information about the application instance
|
||||
*/
|
||||
public ApplicationInstanceInfo getApplicationInstanceInfo() {
|
||||
return cloudConnector.getApplicationInstanceInfo();
|
||||
}
|
||||
|
||||
return appProperties;
|
||||
}
|
||||
|
||||
private Properties getServiceProperties(String keyLead, ServiceInfo serviceInfo) {
|
||||
Properties cloudProperties = new Properties();
|
||||
|
||||
try {
|
||||
BeanInfo beanInfo = Introspector.getBeanInfo(serviceInfo.getClass());
|
||||
PropertyDescriptor[] propDescriptors = beanInfo.getPropertyDescriptors();
|
||||
for (PropertyDescriptor propDescriptor : propDescriptors) {
|
||||
ServiceProperty propAnnotation = propDescriptor.getReadMethod().getAnnotation(ServiceProperty.class);
|
||||
String key = keyLead;
|
||||
|
||||
if (propAnnotation != null) {
|
||||
if (!propAnnotation.category().isEmpty()) {
|
||||
key = key + "." + propAnnotation.category();
|
||||
}
|
||||
if (!propAnnotation.name().isEmpty()) {
|
||||
key = key + "." + propAnnotation.name();
|
||||
} else {
|
||||
key = key + "." + propDescriptor.getName().toLowerCase();
|
||||
}
|
||||
|
||||
Object value = propDescriptor.getReadMethod().invoke(serviceInfo);
|
||||
|
||||
if (value != null) {
|
||||
cloudProperties.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new CloudException(e);
|
||||
}
|
||||
|
||||
return cloudProperties;
|
||||
}
|
||||
|
||||
private static String getServiceLabel(ServiceInfo serviceInfo) {
|
||||
Class<? extends ServiceInfo> serviceInfoClass = serviceInfo.getClass();
|
||||
|
||||
ServiceLabel labelAnnotation = serviceInfoClass.getAnnotation(ServiceInfo.ServiceLabel.class);
|
||||
|
||||
if (labelAnnotation == null) {
|
||||
return null;
|
||||
} else {
|
||||
return labelAnnotation.value();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get {@link ServiceInfo} for the given service id
|
||||
*
|
||||
* @param serviceId
|
||||
* service id
|
||||
* @return info for the serviceId
|
||||
*/
|
||||
public ServiceInfo getServiceInfo(String serviceId) {
|
||||
for (ServiceInfo serviceInfo : getServiceInfos()) {
|
||||
if (serviceInfo.getId().equals(serviceId)) {
|
||||
return serviceInfo;
|
||||
}
|
||||
}
|
||||
throw new CloudException("No service with id " + serviceId + " found");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CloudConnector#getServiceInfos()
|
||||
* @return information about all services bound to the application
|
||||
*/
|
||||
public List<ServiceInfo> getServiceInfos() {
|
||||
return cloudConnector.getServiceInfos();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link ServiceInfo}s for the bound services that could be mapped to the given service connector type.
|
||||
*
|
||||
* <p>
|
||||
* For example, if the connector type is {@link DataSource}, then the method will return all {@link ServiceInfo} objects
|
||||
* matching bound relational database services.
|
||||
* <p>
|
||||
*
|
||||
* @param <T>
|
||||
* The class of the connector to find services for.
|
||||
* @param serviceConnectorType
|
||||
* service connector type.
|
||||
* Passing null returns all {@link ServiceInfo}s (matching that of {@link Cloud#getServiceInfos()}
|
||||
* @return information about services bound to the application that could be transformed into the given connector type
|
||||
*/
|
||||
public <T> List<ServiceInfo> getServiceInfos(Class<T> serviceConnectorType) {
|
||||
List<ServiceInfo> allServiceInfos = getServiceInfos();
|
||||
List<ServiceInfo> matchingServiceInfos = new ArrayList<ServiceInfo>();
|
||||
|
||||
for (ServiceInfo serviceInfo : allServiceInfos) {
|
||||
if (serviceConnectorCreatorRegistry.canCreate(serviceConnectorType, serviceInfo)) {
|
||||
matchingServiceInfos.add(serviceInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return matchingServiceInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a service connector for the given service id, the connector type, configured with the given config
|
||||
*
|
||||
*
|
||||
* @param <SC>
|
||||
* The class of the service connector to return.
|
||||
* @param serviceId
|
||||
* the service id
|
||||
* @param serviceConnectorType
|
||||
* The expected class of service connector such as, DataSource.class.
|
||||
* @param serviceConnectorConfig
|
||||
* service connector configuration (such as pooling parameters).
|
||||
* @return a service connector of the specified type with the given configuration applied
|
||||
*
|
||||
*/
|
||||
public <SC> SC getServiceConnector(String serviceId, Class<SC> serviceConnectorType,
|
||||
ServiceConnectorConfig serviceConnectorConfig) {
|
||||
ServiceInfo serviceInfo = getServiceInfo(serviceId);
|
||||
|
||||
return getServiceConnector(serviceInfo, serviceConnectorType, serviceConnectorConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the singleton service connector for the given connector type, configured with the given config
|
||||
*
|
||||
* @param <SC>
|
||||
* The class of the service connector to return.
|
||||
* @param serviceConnectorType
|
||||
* The expected class of service connector such as, DataSource.class.
|
||||
* @param serviceConnectorConfig
|
||||
* service connector configuration (such as pooling parameters).
|
||||
* @return the single service connector of the specified type with the given configuration applied
|
||||
*
|
||||
*/
|
||||
public <SC> SC getSingletonServiceConnector(Class<SC> serviceConnectorType, ServiceConnectorConfig serviceConnectorConfig) {
|
||||
List<ServiceInfo> matchingServiceInfos = getServiceInfos(serviceConnectorType);
|
||||
|
||||
if (matchingServiceInfos.size() != 1) {
|
||||
throw new CloudException("No unique service matching " + serviceConnectorType + " found. Expected 1, found "
|
||||
+ matchingServiceInfos.size());
|
||||
}
|
||||
|
||||
ServiceInfo matchingServiceInfo = matchingServiceInfos.get(0);
|
||||
|
||||
return getServiceConnector(matchingServiceInfo, serviceConnectorType, serviceConnectorConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new service connector creator
|
||||
*
|
||||
* @param serviceConnectorCreator the service connector to register
|
||||
*/
|
||||
public void registerServiceConnectorCreator(ServiceConnectorCreator<?, ? extends ServiceInfo> serviceConnectorCreator) {
|
||||
serviceConnectorCreatorRegistry.registerCreator(serviceConnectorCreator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get properties for app and services.
|
||||
*
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Application properties always include <code>cloud.application.app-id</code> and <code>cloud.application.instance-id</code>
|
||||
* with values bound to application id and instance id. The rest of the properties are cloud-provider specific, but take the
|
||||
* <code>cloud.application.<property-name></code> form. <pre>
|
||||
* cloud.application.app-id = helloworld
|
||||
* cloud.application.instance-id = instance-0-0fab098f
|
||||
* cloud.application.<property-name> = <property-value>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Service specific properties are exposed for each bound service, with each key starting in <code>cloud.services</code>. Like
|
||||
* application properties, these too are cloud and service specific. Each key for a specific service starts with
|
||||
* <code>cloud.services.<service-id></code> <pre>
|
||||
* cloud.services.customerDb.type = mysql-5.1
|
||||
* cloud.services.customerDb.plan = free
|
||||
* cloud.services.customerDb.connection.hostname = ...
|
||||
* cloud.services.customerDb.connection.port = ...
|
||||
* etc...
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* If a there is only a single service of a given type, that service is aliased to the service type. Keys for such properties
|
||||
* start in <code>cloud.services.<service-type></code>. For example, if there is only a single MySQL service bound to the
|
||||
* application, the service properties will also be exposed starting with '<code>cloud.services.mysql</code>' key: <pre>
|
||||
* cloud.services.mysql.type = mysql-5.1
|
||||
* cloud.services.mysql.plan = free
|
||||
* cloud.services.mysql.connection.hostname = ...
|
||||
* cloud.services.mysql.connection.port = ...
|
||||
* etc...
|
||||
* </pre>
|
||||
*
|
||||
* @return the properties object
|
||||
*/
|
||||
public Properties getCloudProperties() {
|
||||
Map<String, List<ServiceInfo>> mappedServiceInfos = new HashMap<String, List<ServiceInfo>>();
|
||||
for (ServiceInfo serviceInfo : getServiceInfos()) {
|
||||
String key = getServiceLabel(serviceInfo);
|
||||
List<ServiceInfo> serviceInfosForLabel = mappedServiceInfos.get(key);
|
||||
if (serviceInfosForLabel == null) {
|
||||
serviceInfosForLabel = new ArrayList<ServiceInfo>();
|
||||
mappedServiceInfos.put(key, serviceInfosForLabel);
|
||||
}
|
||||
serviceInfosForLabel.add(serviceInfo);
|
||||
}
|
||||
|
||||
final String servicePropKeyLead = "cloud.services.";
|
||||
Properties cloudProperties = new Properties();
|
||||
for (Entry<String, List<ServiceInfo>> mappedServiceInfo : mappedServiceInfos.entrySet()) {
|
||||
List<ServiceInfo> serviceInfos = mappedServiceInfo.getValue();
|
||||
|
||||
for (ServiceInfo serviceInfo : serviceInfos) {
|
||||
String idBasedKey = servicePropKeyLead + serviceInfo.getId();
|
||||
cloudProperties.putAll(getServiceProperties(idBasedKey, serviceInfo));
|
||||
|
||||
// If there is only one service for a given label, put props with that label instead of just id
|
||||
if (serviceInfos.size() == 1) {
|
||||
String labelBasedKey = servicePropKeyLead + mappedServiceInfo.getKey();
|
||||
cloudProperties.putAll(getServiceProperties(labelBasedKey, serviceInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cloudProperties.putAll(getAppProperties());
|
||||
|
||||
return cloudProperties;
|
||||
}
|
||||
|
||||
private <SC> SC getServiceConnector(ServiceInfo serviceInfo, Class<SC> serviceConnectorType,
|
||||
ServiceConnectorConfig serviceConnectorConfig) {
|
||||
ServiceConnectorCreator<SC, ServiceInfo> serviceConnectorCreator = serviceConnectorCreatorRegistry.getServiceCreator(
|
||||
serviceConnectorType, serviceInfo);
|
||||
return serviceConnectorCreator.create(serviceInfo, serviceConnectorConfig);
|
||||
}
|
||||
|
||||
private Properties getAppProperties() {
|
||||
final String appPropLeadKey = "cloud.application.";
|
||||
|
||||
Properties appProperties = new Properties();
|
||||
appProperties.put(appPropLeadKey + "instance-id", getApplicationInstanceInfo().getInstanceId());
|
||||
appProperties.put(appPropLeadKey + "app-id", getApplicationInstanceInfo().getAppId());
|
||||
for (Map.Entry<String, Object> entry : getApplicationInstanceInfo().getProperties().entrySet()) {
|
||||
if (entry.getValue() != null) {
|
||||
appProperties.put(appPropLeadKey + entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return appProperties;
|
||||
}
|
||||
|
||||
private Properties getServiceProperties(String keyLead, ServiceInfo serviceInfo) {
|
||||
Properties cloudProperties = new Properties();
|
||||
|
||||
try {
|
||||
BeanInfo beanInfo = Introspector.getBeanInfo(serviceInfo.getClass());
|
||||
PropertyDescriptor[] propDescriptors = beanInfo.getPropertyDescriptors();
|
||||
for (PropertyDescriptor propDescriptor : propDescriptors) {
|
||||
ServiceProperty propAnnotation = propDescriptor.getReadMethod().getAnnotation(ServiceProperty.class);
|
||||
String key = keyLead;
|
||||
|
||||
if (propAnnotation != null) {
|
||||
if (!propAnnotation.category().isEmpty()) {
|
||||
key = key + "." + propAnnotation.category();
|
||||
}
|
||||
if (!propAnnotation.name().isEmpty()) {
|
||||
key = key + "." + propAnnotation.name();
|
||||
} else {
|
||||
key = key + "." + propDescriptor.getName().toLowerCase();
|
||||
}
|
||||
|
||||
Object value = propDescriptor.getReadMethod().invoke(serviceInfo);
|
||||
|
||||
if (value != null) {
|
||||
cloudProperties.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new CloudException(e);
|
||||
}
|
||||
|
||||
return cloudProperties;
|
||||
}
|
||||
|
||||
private static String getServiceLabel(ServiceInfo serviceInfo) {
|
||||
Class<? extends ServiceInfo> serviceInfoClass = serviceInfo.getClass();
|
||||
|
||||
ServiceLabel labelAnnotation = serviceInfoClass.getAnnotation(ServiceInfo.ServiceLabel.class);
|
||||
|
||||
if (labelAnnotation == null) {
|
||||
return null;
|
||||
} else {
|
||||
return labelAnnotation.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ServiceConnectorCreatorRegistry {
|
||||
private static Logger logger = Logger.getLogger(Cloud.class.getName());
|
||||
private static Logger logger = Logger.getLogger(Cloud.class.getName());
|
||||
|
||||
private List<ServiceConnectorCreator<?, ? extends ServiceInfo>> serviceConnectorCreators = new ArrayList<ServiceConnectorCreator<?, ? extends ServiceInfo>>();
|
||||
|
||||
public void registerCreator(ServiceConnectorCreator<?, ? extends ServiceInfo> serviceConnectorCreator) {
|
||||
serviceConnectorCreators.add(serviceConnectorCreator);
|
||||
}
|
||||
|
||||
public <SC, SI extends ServiceInfo> ServiceConnectorCreator<SC, SI> getServiceCreator(Class<SC> serviceConnectorType, SI serviceInfo) {
|
||||
ServiceConnectorCreator<SC, SI> serviceConnectorCreator = getServiceCreatorOrNull(serviceConnectorType, serviceInfo);
|
||||
private List<ServiceConnectorCreator<?, ? extends ServiceInfo>> serviceConnectorCreators = new ArrayList<ServiceConnectorCreator<?, ? extends ServiceInfo>>();
|
||||
|
||||
if (serviceConnectorCreator != null) {
|
||||
return serviceConnectorCreator;
|
||||
} else {
|
||||
throw new CloudException("No suitable ServiceConnectorCreator found: "
|
||||
+ "service id=" + serviceInfo.getId() + ", "
|
||||
+ "service info type=" + serviceInfo.getClass().getName() + ", "
|
||||
+ "connector type=" + serviceConnectorType);
|
||||
}
|
||||
}
|
||||
|
||||
public <SC, SI extends ServiceInfo> boolean canCreate(Class<SC> serviceConnectorType, SI serviceInfo) {
|
||||
return getServiceCreatorOrNull(serviceConnectorType, serviceInfo) != null;
|
||||
}
|
||||
public void registerCreator(ServiceConnectorCreator<?, ? extends ServiceInfo> serviceConnectorCreator) {
|
||||
serviceConnectorCreators.add(serviceConnectorCreator);
|
||||
}
|
||||
|
||||
public boolean accept(ServiceConnectorCreator<?, ? extends ServiceInfo> creator, Class<?> serviceConnectorType, ServiceInfo serviceInfo) {
|
||||
boolean typeBasedAccept = serviceConnectorType == null ? true : serviceConnectorType.isAssignableFrom(creator.getServiceConnectorType());
|
||||
boolean infoBasedAccept = serviceInfo == null ? true : creator.getServiceInfoType().isAssignableFrom(serviceInfo.getClass());
|
||||
|
||||
return typeBasedAccept && infoBasedAccept;
|
||||
}
|
||||
public <SC, SI extends ServiceInfo> ServiceConnectorCreator<SC, SI> getServiceCreator(Class<SC> serviceConnectorType,
|
||||
SI serviceInfo) {
|
||||
ServiceConnectorCreator<SC, SI> serviceConnectorCreator = getServiceCreatorOrNull(serviceConnectorType, serviceInfo);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <SC, SI extends ServiceInfo> ServiceConnectorCreator<SC, SI> getServiceCreatorOrNull(Class<SC> serviceConnectorType, SI serviceInfo) {
|
||||
for (ServiceConnectorCreator<?, ? extends ServiceInfo> serviceConnectorCreator : serviceConnectorCreators) {
|
||||
logger.info("Trying connector creator type " + serviceConnectorCreator);
|
||||
if (accept(serviceConnectorCreator, serviceConnectorType, serviceInfo)) {
|
||||
return (ServiceConnectorCreator<SC, SI>) serviceConnectorCreator;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (serviceConnectorCreator != null) {
|
||||
return serviceConnectorCreator;
|
||||
} else {
|
||||
throw new CloudException("No suitable ServiceConnectorCreator found: "
|
||||
+ "service id=" + serviceInfo.getId() + ", "
|
||||
+ "service info type=" + serviceInfo.getClass().getName() + ", "
|
||||
+ "connector type=" + serviceConnectorType);
|
||||
}
|
||||
}
|
||||
|
||||
public <SC, SI extends ServiceInfo> boolean canCreate(Class<SC> serviceConnectorType, SI serviceInfo) {
|
||||
return getServiceCreatorOrNull(serviceConnectorType, serviceInfo) != null;
|
||||
}
|
||||
|
||||
public boolean accept(ServiceConnectorCreator<?, ? extends ServiceInfo> creator, Class<?> serviceConnectorType,
|
||||
ServiceInfo serviceInfo) {
|
||||
boolean typeBasedAccept = serviceConnectorType == null ? true : serviceConnectorType.isAssignableFrom(creator
|
||||
.getServiceConnectorType());
|
||||
boolean infoBasedAccept = serviceInfo == null ? true : creator.getServiceInfoType()
|
||||
.isAssignableFrom(serviceInfo.getClass());
|
||||
|
||||
return typeBasedAccept && infoBasedAccept;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <SC, SI extends ServiceInfo> ServiceConnectorCreator<SC, SI> getServiceCreatorOrNull(Class<SC> serviceConnectorType,
|
||||
SI serviceInfo) {
|
||||
for (ServiceConnectorCreator<?, ? extends ServiceInfo> serviceConnectorCreator : serviceConnectorCreators) {
|
||||
logger.info("Trying connector creator type " + serviceConnectorCreator);
|
||||
if (accept(serviceConnectorCreator, serviceConnectorType, serviceInfo)) {
|
||||
return (ServiceConnectorCreator<SC, SI>) serviceConnectorCreator;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,95 +10,96 @@ import org.springframework.cloud.util.ServiceLoaderWithExceptionControl;
|
||||
|
||||
/**
|
||||
* Factory for the cloud.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* The main entry point for user code. Typical code directly using this class (as opposed to using a dependency-injection
|
||||
* framework) will look like:
|
||||
* The main entry point for user code. Typical code directly using this class (as opposed to using a dependency-injection framework)
|
||||
* will look like:
|
||||
*
|
||||
* <pre>
|
||||
* CloudFactory cloudFactory = new CloudFactory();
|
||||
* Cloud cloud = cloudFoundry.getCloud();
|
||||
* </pre>
|
||||
*
|
||||
* Creating object of this class is somewhat expensive (due to scanning of various files to load connectors),
|
||||
* so consider caching such an object if you create it manually. If you use a dependency-injection framework such as
|
||||
* Spring, simply creating a bean for either CloudFactory or using this class as a factory-bean for {@link Cloud} will
|
||||
* suffice.
|
||||
*
|
||||
*
|
||||
* Creating object of this class is somewhat expensive (due to scanning of various files to load connectors), so consider caching
|
||||
* such an object if you create it manually. If you use a dependency-injection framework such as Spring, simply creating a bean for
|
||||
* either CloudFactory or using this class as a factory-bean for {@link Cloud} will suffice.
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
*/
|
||||
public class CloudFactory {
|
||||
private List<CloudConnector> cloudConnectors = new ArrayList<CloudConnector>();
|
||||
private List<ServiceConnectorCreator<?, ? extends ServiceInfo>> serviceCreators = new ArrayList<ServiceConnectorCreator<?, ? extends ServiceInfo>>();
|
||||
private List<CloudConnector> cloudConnectors = new ArrayList<CloudConnector>();
|
||||
private List<ServiceConnectorCreator<?, ? extends ServiceInfo>> serviceCreators = new ArrayList<ServiceConnectorCreator<?, ? extends ServiceInfo>>();
|
||||
|
||||
public CloudFactory() {
|
||||
scanCloudConnectors();
|
||||
scanServiceConnectorCreators();
|
||||
}
|
||||
public CloudFactory() {
|
||||
scanCloudConnectors();
|
||||
scanServiceConnectorCreators();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return a cloud suitable for the current environment
|
||||
* @throws CloudException if no suitable cloud found
|
||||
*/
|
||||
public Cloud getCloud() {
|
||||
CloudConnector suitableCloudConnector = null;
|
||||
for (CloudConnector cloudConnector : cloudConnectors) {
|
||||
if (cloudConnector.isInMatchingCloud()) {
|
||||
suitableCloudConnector = cloudConnector;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @return a cloud suitable for the current environment
|
||||
* @throws CloudException
|
||||
* if no suitable cloud found
|
||||
*/
|
||||
public Cloud getCloud() {
|
||||
CloudConnector suitableCloudConnector = null;
|
||||
for (CloudConnector cloudConnector : cloudConnectors) {
|
||||
if (cloudConnector.isInMatchingCloud()) {
|
||||
suitableCloudConnector = cloudConnector;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (suitableCloudConnector == null) {
|
||||
throw new CloudException("No suitable cloud connector found");
|
||||
}
|
||||
if (suitableCloudConnector == null) {
|
||||
throw new CloudException("No suitable cloud connector found");
|
||||
}
|
||||
|
||||
return new Cloud(suitableCloudConnector, serviceCreators);
|
||||
}
|
||||
return new Cloud(suitableCloudConnector, serviceCreators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a cloud connector.
|
||||
*
|
||||
* <p>
|
||||
* CloudConnector developers should prefer the declarative mechanism described in README.MD
|
||||
* instead of calling this method.
|
||||
* <p>
|
||||
*
|
||||
* @param cloudConnector
|
||||
*/
|
||||
public void registerCloudConnector(CloudConnector cloudConnector) {
|
||||
cloudConnectors.add(cloudConnector);
|
||||
}
|
||||
|
||||
/* package access for testing */
|
||||
List<CloudConnector> getCloudConnectors() {
|
||||
return cloudConnectors;
|
||||
}
|
||||
/**
|
||||
* Register a cloud connector.
|
||||
*
|
||||
* <p>
|
||||
* CloudConnector developers should prefer the declarative mechanism described in README.MD instead of calling this method.
|
||||
* </p>
|
||||
*
|
||||
* @param cloudConnector
|
||||
* the cloud connector to register for discovery
|
||||
*/
|
||||
public void registerCloudConnector(CloudConnector cloudConnector) {
|
||||
cloudConnectors.add(cloudConnector);
|
||||
}
|
||||
|
||||
/* package access for testing */
|
||||
List<ServiceConnectorCreator<?, ? extends ServiceInfo>> getServiceCreators() {
|
||||
return serviceCreators;
|
||||
}
|
||||
/* package access for testing */
|
||||
List<CloudConnector> getCloudConnectors() {
|
||||
return cloudConnectors;
|
||||
}
|
||||
|
||||
private void registerServiceCreator(ServiceConnectorCreator<?, ? extends ServiceInfo> serviceConnectorCreator) {
|
||||
serviceCreators.add(serviceConnectorCreator);
|
||||
}
|
||||
/* package access for testing */
|
||||
List<ServiceConnectorCreator<?, ? extends ServiceInfo>> getServiceCreators() {
|
||||
return serviceCreators;
|
||||
}
|
||||
|
||||
private void scanCloudConnectors() {
|
||||
Iterable<CloudConnector> loader = ServiceLoader.load(CloudConnector.class);
|
||||
for (CloudConnector cloudConnector: loader) {
|
||||
registerCloudConnector(cloudConnector);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private void scanServiceConnectorCreators() {
|
||||
Iterable<ServiceConnectorCreator> loader = ServiceLoaderWithExceptionControl.load(ServiceConnectorCreator.class);
|
||||
for (ServiceConnectorCreator serviceConnectorCreator: loader) {
|
||||
if (serviceConnectorCreator != null) {
|
||||
registerServiceCreator(serviceConnectorCreator);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void registerServiceCreator(ServiceConnectorCreator<?, ? extends ServiceInfo> serviceConnectorCreator) {
|
||||
serviceCreators.add(serviceConnectorCreator);
|
||||
}
|
||||
|
||||
private void scanCloudConnectors() {
|
||||
Iterable<CloudConnector> loader = ServiceLoader.load(CloudConnector.class);
|
||||
for (CloudConnector cloudConnector : loader) {
|
||||
registerCloudConnector(cloudConnector);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private void scanServiceConnectorCreators() {
|
||||
Iterable<ServiceConnectorCreator> loader = ServiceLoaderWithExceptionControl.load(ServiceConnectorCreator.class);
|
||||
for (ServiceConnectorCreator serviceConnectorCreator : loader) {
|
||||
if (serviceConnectorCreator != null) {
|
||||
registerServiceCreator(serviceConnectorCreator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,25 +3,28 @@ package org.springframework.cloud;
|
||||
import org.springframework.cloud.service.ServiceInfo;
|
||||
|
||||
/**
|
||||
* Fallback service info creator to deal with situations there is no {@link ServiceInfoCreator} that can
|
||||
* Fallback service info creator to deal with situations there is no {@link ServiceInfoCreator} that can
|
||||
* accept service data.
|
||||
*
|
||||
* A fallback mechanism is needed, for example, when a services is bound to an app, but there is no
|
||||
* {@link ServiceInfoCreator} implemented to handle it or the {@link ServiceInfoCreator} implementation
|
||||
* for it isn't placed properly to be picked up by scanning. By having a fallback mechanism, we can
|
||||
* extract as much info from the service data as possible (minimally, the service id) and issue a warning.
|
||||
*
|
||||
*
|
||||
* A fallback mechanism is needed, for example, when a services is bound to an app, but there is no {@link ServiceInfoCreator}
|
||||
* implemented to handle it or the {@link ServiceInfoCreator} implementation
|
||||
* for it isn't placed properly to be picked up by scanning. By having a fallback mechanism, we can
|
||||
* extract as much info from the service data as possible (minimally, the service id) and issue a warning.
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
* @param <SI>
|
||||
* the type of {@link ServiceInfo} that this fallback creator will return
|
||||
* @param <SD>
|
||||
* the type of service definition data that this creator will consume
|
||||
*/
|
||||
public abstract class FallbackServiceInfoCreator<SI extends ServiceInfo, SD> implements ServiceInfoCreator<SI, SD>{
|
||||
public abstract class FallbackServiceInfoCreator<SI extends ServiceInfo, SD> implements ServiceInfoCreator<SI, SD> {
|
||||
|
||||
/*
|
||||
* Override to ensure that it accepts all service data
|
||||
*/
|
||||
@Override
|
||||
public final boolean accept(SD serviceData) {
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
* Override to ensure that it accepts all service data
|
||||
*/
|
||||
@Override
|
||||
public final boolean accept(SD serviceData) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
package org.springframework.cloud.service;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
* @param <SC> service connector type
|
||||
* @param <SI> service info type
|
||||
* @param <SC>
|
||||
* service connector type
|
||||
* @param <SI>
|
||||
* service info type
|
||||
*/
|
||||
public interface ServiceConnectorCreator<SC, SI extends ServiceInfo> {
|
||||
/**
|
||||
* Create service for the given service info and configured with the given
|
||||
* configuration
|
||||
*
|
||||
* @param serviceInfo
|
||||
* @param serviceConnectorConfig
|
||||
* @return service connector
|
||||
*/
|
||||
SC create(SI serviceInfo, ServiceConnectorConfig serviceConnectorConfig);
|
||||
|
||||
Class<SC> getServiceConnectorType();
|
||||
/**
|
||||
* Create service for the given service info and configured with the given
|
||||
* configuration
|
||||
*
|
||||
* @param serviceInfo
|
||||
* the {@link ServiceInfo} object containing the information necessary to connect to the service
|
||||
* @param serviceConnectorConfig
|
||||
* configuration information to be applied to the connection
|
||||
* @return service connector
|
||||
*/
|
||||
SC create(SI serviceInfo, ServiceConnectorConfig serviceConnectorConfig);
|
||||
|
||||
Class<?> getServiceInfoType();
|
||||
Class<SC> getServiceConnectorType();
|
||||
|
||||
Class<?> getServiceInfoType();
|
||||
}
|
||||
|
||||
@@ -10,66 +10,66 @@ import org.springframework.cloud.service.ServiceConnectorCreator;
|
||||
|
||||
/**
|
||||
* A variation of {@link ServiceLoader} that ignores exception encountered when loading services.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* The {@link ServiceLoader} class throws an error when it encounters a service that it cannot load.
|
||||
* For {@link ServiceConnectorCreator}, this can be a common occurrence due to missing dependencies.
|
||||
* For example, if an app isn't using MongoDB, thus not declaring dependencies on relevant classes,
|
||||
* will cause {@link ServiceConnectorCreator} for MongoDB to fail. We don't want to abandon other service
|
||||
* connector creators in such cases.
|
||||
* The {@link ServiceLoader} class throws an error when it encounters a service that it cannot load. For
|
||||
* {@link ServiceConnectorCreator}, this can be a common occurrence due to missing dependencies. For example, if an app isn't using
|
||||
* MongoDB, thus not declaring dependencies on relevant classes, will cause {@link ServiceConnectorCreator} for MongoDB to fail. We
|
||||
* don't want to abandon other service connector creators in such cases.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
* @param <T>
|
||||
* the type of the service being loaded
|
||||
*/
|
||||
public class ServiceLoaderWithExceptionControl<T> implements Iterable<T> {
|
||||
private Iterable<T> underlying;
|
||||
|
||||
private static Logger logger = Logger.getLogger(ServiceLoaderWithExceptionControl.class.getName());
|
||||
private Iterable<T> underlying;
|
||||
|
||||
public static <T> Iterable<T> load(Class<T> serviceType) {
|
||||
ServiceLoader<T> loader = ServiceLoader.load(serviceType);
|
||||
return new ServiceLoaderWithExceptionControl<T>(loader);
|
||||
}
|
||||
private static Logger logger = Logger.getLogger(ServiceLoaderWithExceptionControl.class.getName());
|
||||
|
||||
private ServiceLoaderWithExceptionControl(Iterable<T> underlying) {
|
||||
this.underlying = underlying;
|
||||
}
|
||||
public static <T> Iterable<T> load(Class<T> serviceType) {
|
||||
ServiceLoader<T> loader = ServiceLoader.load(serviceType);
|
||||
return new ServiceLoaderWithExceptionControl<T>(loader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return new ServiceLoaderIterator(underlying.iterator());
|
||||
}
|
||||
|
||||
private class ServiceLoaderIterator implements Iterator<T> {
|
||||
private Iterator<T> underlying;
|
||||
|
||||
public ServiceLoaderIterator(Iterator<T> underlying) {
|
||||
this.underlying = underlying;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return underlying.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
try {
|
||||
return underlying.next();
|
||||
} catch (ServiceConfigurationError e) {
|
||||
logger.log(Level.CONFIG, "Failed to load " + e);
|
||||
if (hasNext()) {
|
||||
return next();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
underlying.remove();
|
||||
}
|
||||
}
|
||||
private ServiceLoaderWithExceptionControl(Iterable<T> underlying) {
|
||||
this.underlying = underlying;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return new ServiceLoaderIterator(underlying.iterator());
|
||||
}
|
||||
|
||||
private class ServiceLoaderIterator implements Iterator<T> {
|
||||
private Iterator<T> underlying;
|
||||
|
||||
public ServiceLoaderIterator(Iterator<T> underlying) {
|
||||
this.underlying = underlying;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return underlying.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
try {
|
||||
return underlying.next();
|
||||
} catch (ServiceConfigurationError e) {
|
||||
logger.log(Level.CONFIG, "Failed to load " + e);
|
||||
if (hasNext()) {
|
||||
return next();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
underlying.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,9 @@ import java.net.URISyntaxException;
|
||||
import java.net.URLDecoder;
|
||||
|
||||
/**
|
||||
* Factory for standard Cloud Foundry URIs which all conform to the format:
|
||||
* <p/>
|
||||
* [jdbc:]scheme://[user:pass]@authority[:port]/path
|
||||
* Factory for standard Cloud Foundry URIs, which all conform to the format:
|
||||
* <p>
|
||||
* {@code [jdbc:]scheme://[user:pass]@authority[:port]/path}
|
||||
*/
|
||||
public class StandardUriInfoFactory implements UriInfoFactory {
|
||||
|
||||
|
||||
@@ -2,31 +2,40 @@ package org.springframework.cloud.util;
|
||||
|
||||
/**
|
||||
* An interface implemented in order to create {@link UriInfo}s.
|
||||
*
|
||||
*
|
||||
* If your {@link org.springframework.cloud.service.ServiceInfo} needs to deal with special URIs and you are extending
|
||||
* {@link org.springframework.cloud.service.UriBasedServiceInfo} then you can implement this factory interface in order
|
||||
* to return a custom factory from your ServiceInfo by overriding
|
||||
* {@link org.springframework.cloud.service.UriBasedServiceInfo#getUriInfoFactory()}.
|
||||
*
|
||||
*
|
||||
* @author Jens Deppe
|
||||
*/
|
||||
public interface UriInfoFactory {
|
||||
|
||||
/**
|
||||
* Create a {@link UriInfo} based on a URI string
|
||||
* @param uriString the URI string to parse
|
||||
*
|
||||
* @param uriString
|
||||
* the URI string to parse
|
||||
* @return a {@link UriInfo}
|
||||
*/
|
||||
public UriInfo createUri(String uriString);
|
||||
|
||||
/**
|
||||
* Create a {@link UriInfo} based on explicit components of the URI
|
||||
*
|
||||
* @param scheme
|
||||
* the URI scheme for this service
|
||||
* @param host
|
||||
* the host for this service
|
||||
* @param port
|
||||
* the port for this service
|
||||
* @param username
|
||||
* the authentication username for this service
|
||||
* @param password
|
||||
* the authentication password for this service
|
||||
* @param path
|
||||
* the path to this service resource on the server
|
||||
* @return a {@link UriInfo}
|
||||
*/
|
||||
public UriInfo createUri(String scheme, String host, int port, String username, String password, String path);
|
||||
|
||||
@@ -24,350 +24,400 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
|
||||
/**
|
||||
* JavaConfig base class for simplified access to the bound services.
|
||||
*
|
||||
*
|
||||
* Note that this class doesn't directly expose low-level methods such as getServiceInfo()
|
||||
* to keep focus on typical needs of a Spring application. But, since it exposes the cloud object itself,
|
||||
* to keep focus on typical needs of a Spring application. But, since it exposes the cloud object itself,
|
||||
* you can always call methods on it to get that kind of information.
|
||||
*
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
public abstract class AbstractCloudConfig implements BeanFactoryAware {
|
||||
|
||||
private static final String CLOUD_FACTORY_BEAN_NAME = "__cloud_factory__";
|
||||
|
||||
private CloudFactory cloudFactory;
|
||||
private static final String CLOUD_FACTORY_BEAN_NAME = "__cloud_factory__";
|
||||
|
||||
private Cloud cloud;
|
||||
private CloudFactory cloudFactory;
|
||||
|
||||
private ServiceConnectionFactory connectionFactory;
|
||||
private Cloud cloud;
|
||||
|
||||
/**
|
||||
* Get the cloud factory.
|
||||
*
|
||||
* Most applications will never need this method, but provided here to cover corner cases.
|
||||
*
|
||||
* @return cloud factory
|
||||
*/
|
||||
protected CloudFactory cloudFactory() {
|
||||
return cloudFactory;
|
||||
}
|
||||
private ServiceConnectionFactory connectionFactory;
|
||||
|
||||
/**
|
||||
* Get the underlying cloud object.
|
||||
*
|
||||
* @return the cloud object appropriate for the current environment
|
||||
*/
|
||||
@Bean
|
||||
public Cloud cloud() {
|
||||
return cloud;
|
||||
}
|
||||
|
||||
public ServiceConnectionFactory connectionFactory() {
|
||||
return connectionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object containing service and app properties
|
||||
*
|
||||
*/
|
||||
public Properties properties() {
|
||||
return cloud().getCloudProperties();
|
||||
}
|
||||
/**
|
||||
* Get the cloud factory.
|
||||
*
|
||||
* Most applications will never need this method, but provided here to cover corner cases.
|
||||
*
|
||||
* @return cloud factory
|
||||
*/
|
||||
protected CloudFactory cloudFactory() {
|
||||
return cloudFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Get the underlying cloud object.
|
||||
*
|
||||
* @return the cloud object appropriate for the current environment
|
||||
*/
|
||||
@Bean
|
||||
public Cloud cloud() {
|
||||
return cloud;
|
||||
}
|
||||
|
||||
public ServiceConnectionFactory connectionFactory() {
|
||||
return connectionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object containing service and app properties
|
||||
*
|
||||
* @return the properties of the discovered runtime environment
|
||||
*/
|
||||
public Properties properties() {
|
||||
return cloud().getCloudProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation note: This roundabout way of implementation is required to ensure that
|
||||
* a {@link CloudFactory} bean if created in some other configuration is available, we should use
|
||||
* that.
|
||||
*/
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
if (cloudFactory == null) {
|
||||
try {
|
||||
cloudFactory = beanFactory.getBean(CloudFactory.class);
|
||||
} catch (NoSuchBeanDefinitionException ex) {
|
||||
cloudFactory = new CloudFactory();
|
||||
((SingletonBeanRegistry)beanFactory).registerSingleton(CLOUD_FACTORY_BEAN_NAME, cloudFactory);
|
||||
}
|
||||
}
|
||||
this.cloud = cloudFactory.getCloud();
|
||||
this.connectionFactory = new ServiceConnectionFactory();
|
||||
}
|
||||
*/
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
if (cloudFactory == null) {
|
||||
try {
|
||||
cloudFactory = beanFactory.getBean(CloudFactory.class);
|
||||
} catch (NoSuchBeanDefinitionException ex) {
|
||||
cloudFactory = new CloudFactory();
|
||||
((SingletonBeanRegistry) beanFactory).registerSingleton(CLOUD_FACTORY_BEAN_NAME, cloudFactory);
|
||||
}
|
||||
}
|
||||
this.cloud = cloudFactory.getCloud();
|
||||
this.connectionFactory = new ServiceConnectionFactory();
|
||||
}
|
||||
|
||||
|
||||
public class ServiceConnectionFactory {
|
||||
// Relational database
|
||||
|
||||
/**
|
||||
* Get the {@link DataSource} object associated with the only relational database service bound to the app.
|
||||
*
|
||||
* This is equivalent to the <cloud:data-source/> element.
|
||||
*
|
||||
* @return data source
|
||||
* @throws CloudException if there are either 0 or more than 1 relational database services.
|
||||
*/
|
||||
public DataSource dataSource() {
|
||||
return dataSource((DataSourceConfig)null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link DataSource} object associated with the only relational database service bound to the app
|
||||
* configured as specified.
|
||||
*
|
||||
* This is equivalent to the <cloud:data-source> element with a nested <cloud:connection>
|
||||
* and/or <cloud:pool> elements.
|
||||
*
|
||||
* @param dataSourceConfig configuration for the data source created
|
||||
* @return data source
|
||||
* @throws CloudException if there are either 0 or more than 1 relational database services.
|
||||
*/
|
||||
public DataSource dataSource(DataSourceConfig dataSourceConfig) {
|
||||
return cloud.getSingletonServiceConnector(DataSource.class, dataSourceConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link DataSource} object for the specified relational database service.
|
||||
*
|
||||
* This is equivalent to the <cloud:data-source service-id="serviceId"/>
|
||||
*
|
||||
* @param serviceId the name of the service
|
||||
* @return data source
|
||||
* @throws CloudException if the specified service doesn't exist
|
||||
*/
|
||||
public DataSource dataSource(String serviceId) {
|
||||
return dataSource(serviceId, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link DataSource} object for the specified relational database service configured as specified.
|
||||
*
|
||||
* This is equivalent to the <cloud:data-source service-id="serviceId"/> element with a
|
||||
* nested <cloud:connection> and/or <cloud:pool> elements.
|
||||
*
|
||||
* @param serviceId the name of the service
|
||||
* @param dataSourceConfig configuration for the data source created
|
||||
* @return data source
|
||||
* @throws CloudException if the specified service doesn't exist
|
||||
*/
|
||||
public DataSource dataSource(String serviceId, DataSourceConfig dataSourceConfig) {
|
||||
return cloud.getServiceConnector(serviceId, DataSource.class, dataSourceConfig);
|
||||
}
|
||||
|
||||
// Mongodb
|
||||
/**
|
||||
* Get the {@link MongoDbFactory} object associated with the only MongoDB service bound to the app.
|
||||
*
|
||||
* This is equivalent to the <cloud:mongo-db-factory/> element.
|
||||
*
|
||||
* @return mongo db factory
|
||||
* @throws CloudException if there are either 0 or more than 1 mongodb services.
|
||||
*/
|
||||
public MongoDbFactory mongoDbFactory() {
|
||||
return mongoDbFactory((MongoDbFactoryConfig)null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link MongoDbFactory} object associated with the only MongoDB service bound to the app
|
||||
* configured as specified.
|
||||
*
|
||||
* This is equivalent to the <cloud:mongo-db-factory> element with a nested <cloud:mongo-options> element.
|
||||
*
|
||||
* @param mongoDbFactoryConfig configuration for the mondo db factory created
|
||||
* @return mongo db factory
|
||||
* @throws CloudException if there are either 0 or more than 1 mongodb services.
|
||||
*/
|
||||
public MongoDbFactory mongoDbFactory(MongoDbFactoryConfig mongoDbFactoryConfig) {
|
||||
return cloud.getSingletonServiceConnector(MongoDbFactory.class, mongoDbFactoryConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link MongoDbFactory} object for the specified MongoDB service.
|
||||
*
|
||||
* This is equivalent to the <cloud:mongo-db-factory service-id="serviceId"> element.
|
||||
*
|
||||
* @param serviceId the name of the service
|
||||
* @return mongo db factory
|
||||
* @throws CloudException if the specified service doesn't exist
|
||||
*/
|
||||
public MongoDbFactory mongoDbFactory(String serviceId) {
|
||||
return mongoDbFactory(serviceId, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link MongoDbFactory} object for the specified MongoDB service configured as specified.
|
||||
*
|
||||
* This is equivalent to the <cloud:mongo-db-factory service-id="serviceId"> element
|
||||
* with a nested <cloud:mongo-options> element.
|
||||
*
|
||||
* @param serviceId the name of the service
|
||||
* @param mongoDbFactoryConfig configuration for the mongo db factory created
|
||||
* @return mongo db factory
|
||||
* @throws CloudException if the specified service doesn't exist
|
||||
*/
|
||||
public MongoDbFactory mongoDbFactory(String serviceId, MongoDbFactoryConfig mongoDbFactoryConfig) {
|
||||
return cloud.getServiceConnector(serviceId, MongoDbFactory.class, mongoDbFactoryConfig);
|
||||
}
|
||||
|
||||
// RabbitMQ
|
||||
/**
|
||||
* Get the {@link ConnectionFactory} object associated with the only RabbitMQ service bound to the app.
|
||||
*
|
||||
* This is equivalent to the <cloud:rabbit-connection-factory> element.
|
||||
*
|
||||
* @return rabbit connection factory
|
||||
* @throws CloudException if there are either 0 or more than 1 RabbitMQ services.
|
||||
*/
|
||||
public ConnectionFactory rabbitConnectionFactory() {
|
||||
return rabbitConnectionFactory((RabbitConnectionFactoryConfig)null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ConnectionFactory} object associated with the only RabbitMQ service bound to the app
|
||||
* configured as specified.
|
||||
*
|
||||
* This is equivalent to the <cloud:rabbit-connection-factory> element
|
||||
* with a nested <cloud:rabbit-options> element.
|
||||
*
|
||||
* @param rabbitConnectionFactoryConfig configuration for the rabbit connection factory created
|
||||
* @return rabbit connection factory
|
||||
* @throws CloudException if there are either 0 or more than 1 RabbitMQ services.
|
||||
*/
|
||||
public ConnectionFactory rabbitConnectionFactory(RabbitConnectionFactoryConfig rabbitConnectionFactoryConfig) {
|
||||
return cloud.getSingletonServiceConnector(ConnectionFactory.class, rabbitConnectionFactoryConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ConnectionFactory} object for the specified RabbitMQ service.
|
||||
*
|
||||
* This is equivalent to the <cloud:rabbit-connection-factory service-id="serviceId"> element.
|
||||
*
|
||||
* @param serviceId the name of the service
|
||||
* @return rabbit connection factory
|
||||
* @throws CloudException if the specified service doesn't exist
|
||||
*/
|
||||
public ConnectionFactory rabbitConnectionFactory(String serviceId) {
|
||||
return rabbitConnectionFactory(serviceId, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ConnectionFactory} object for the specified RabbitMQ service configured as specified.
|
||||
*
|
||||
* This is equivalent to the <cloud:rabbit-connection-factory service-id="serviceId"> element
|
||||
* with a nested <cloud:rabbit-options> element.
|
||||
*
|
||||
* @param serviceId the name of the service
|
||||
* @param rabbitConnectionFactoryConfig configuration for the {@link ConnectionFactory} created
|
||||
* @return rabbit connection factory
|
||||
* @throws CloudException if the specified service doesn't exist
|
||||
*/
|
||||
public ConnectionFactory rabbitConnectionFactory(String serviceId, RabbitConnectionFactoryConfig rabbitConnectionFactoryConfig) {
|
||||
return cloud.getServiceConnector(serviceId, ConnectionFactory.class, rabbitConnectionFactoryConfig);
|
||||
}
|
||||
|
||||
// Redis
|
||||
/**
|
||||
* Get the {@link RedisConnectionFactory} object associated with the only Redis service bound to the app.
|
||||
*
|
||||
* This is equivalent to the <cloud:redis-connection-factory/> element
|
||||
*
|
||||
* @return redis connection factory
|
||||
* @throws CloudException if there are either 0 or more than 1 redis services.
|
||||
*/
|
||||
public RedisConnectionFactory redisConnectionFactory() {
|
||||
return redisConnectionFactory((PooledServiceConnectorConfig)null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link RedisConnectionFactory} object associated with the only Redis service bound to the app
|
||||
* configured as specified.
|
||||
*
|
||||
* This is equivalent to the <cloud:redis-connection-factory service-id="serviceId"> element
|
||||
* with a nested <cloud:pool> element.
|
||||
*
|
||||
* @param redisConnectionFactoryConfig configuration for the {@link RedisConnectionFactory} created
|
||||
* @return redis connection factory
|
||||
* @throws CloudException if there are either 0 or more than 1 redis services.
|
||||
*/
|
||||
public RedisConnectionFactory redisConnectionFactory(PooledServiceConnectorConfig redisConnectionFactoryConfig) {
|
||||
return cloud.getSingletonServiceConnector(RedisConnectionFactory.class, redisConnectionFactoryConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link RedisConnectionFactory} object for the specified Redis service.
|
||||
*
|
||||
* This is equivalent to the <cloud:redis-connection-factory service-id="serviceId"> element.
|
||||
*
|
||||
* @param serviceId the name of the service
|
||||
* @return redis connection factory
|
||||
* @throws CloudException if the specified service doesn't exist
|
||||
*/
|
||||
public RedisConnectionFactory redisConnectionFactory(String serviceId) {
|
||||
return redisConnectionFactory(serviceId, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link RedisConnectionFactory} object for the specified Redis service configured as specified.
|
||||
*
|
||||
* This is equivalent to the <cloud:redis-connection-factory service-id="serviceId"> element
|
||||
* with a nested <cloud:pool> element.
|
||||
*
|
||||
* @param serviceId the name of the service
|
||||
* @param redisConnectionFactoryConfig configuration for the {@link RedisConnectionFactory} created
|
||||
* @return redis connection factory
|
||||
* @throws CloudException if the specified service doesn't exist
|
||||
*/
|
||||
public RedisConnectionFactory redisConnectionFactory(String serviceId, PooledServiceConnectorConfig redisConnectionFactoryConfig) {
|
||||
return cloud.getServiceConnector(serviceId, RedisConnectionFactory.class, redisConnectionFactoryConfig);
|
||||
}
|
||||
|
||||
// Generic service
|
||||
/**
|
||||
* Get the service connector object associated with the only service bound to the app.
|
||||
*
|
||||
* This is equivalent to the <cloud:service/> element.
|
||||
*
|
||||
* @return service connector object
|
||||
* @throws CloudException if there are either 0 or more than 1 services.
|
||||
*/
|
||||
public Object service() {
|
||||
return service(Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the service connector object of the specified type if there is only one such candidate service
|
||||
*
|
||||
* This is equivalent to the <cloud:service connector-type="T.class"/> element.
|
||||
*
|
||||
* @return service connector object
|
||||
* @throws CloudException if there are either 0 or more than 1 candidate services.
|
||||
*/
|
||||
public <T> T service(Class<T> serviceConnectorType) {
|
||||
return cloud.getSingletonServiceConnector(serviceConnectorType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the service connector object for the specified service.
|
||||
*
|
||||
* This is equivalent to the <cloud:service service-id="serviceId"/> element.
|
||||
*
|
||||
* @return service connector object
|
||||
* @throws CloudException if the specified service doesn't exist
|
||||
*/
|
||||
public Object service(String serviceId) {
|
||||
return service(serviceId, Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the service connector object of the specified type and service id
|
||||
*
|
||||
* This is equivalent to the <cloud:service service-id="serviceId" connector-type="T.class"/> element.
|
||||
*
|
||||
* @return service connector object
|
||||
* @throws CloudException if the specified service doesn't exist
|
||||
*/
|
||||
public <T> T service(String serviceId, Class<T> serviceConnectorType) {
|
||||
return cloud.getServiceConnector(serviceId, serviceConnectorType, null);
|
||||
}
|
||||
}
|
||||
public class ServiceConnectionFactory {
|
||||
// Relational database
|
||||
|
||||
/**
|
||||
* Get the {@link DataSource} object associated with the only relational database service bound to the app.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:data-source/>} element.
|
||||
*
|
||||
* @return data source
|
||||
* @throws CloudException
|
||||
* if there are either 0 or more than 1 relational database services.
|
||||
*/
|
||||
public DataSource dataSource() {
|
||||
return dataSource((DataSourceConfig) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link DataSource} object associated with the only relational database service bound to the app
|
||||
* configured as specified.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:data-source>} element with nested {@code <cloud:connection>} and/or
|
||||
* {@code <cloud:pool>} elements.
|
||||
*
|
||||
* @param dataSourceConfig
|
||||
* configuration for the data source created
|
||||
* @return data source
|
||||
* @throws CloudException
|
||||
* if there are either 0 or more than 1 relational database services.
|
||||
*/
|
||||
public DataSource dataSource(DataSourceConfig dataSourceConfig) {
|
||||
return cloud.getSingletonServiceConnector(DataSource.class, dataSourceConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link DataSource} object for the specified relational database service.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:data-source service-id="serviceId"/>}
|
||||
*
|
||||
* @param serviceId
|
||||
* the name of the service
|
||||
* @return data source
|
||||
* @throws CloudException
|
||||
* if the specified service doesn't exist
|
||||
*/
|
||||
public DataSource dataSource(String serviceId) {
|
||||
return dataSource(serviceId, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link DataSource} object for the specified relational database service configured as specified.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:data-source service-id="serviceId"/>} element with
|
||||
* nested {@code <cloud:connection>} and/or {@code <cloud:pool>} elements.
|
||||
*
|
||||
* @param serviceId
|
||||
* the name of the service
|
||||
* @param dataSourceConfig
|
||||
* configuration for the data source created
|
||||
* @return data source
|
||||
* @throws CloudException
|
||||
* if the specified service doesn't exist
|
||||
*/
|
||||
public DataSource dataSource(String serviceId, DataSourceConfig dataSourceConfig) {
|
||||
return cloud.getServiceConnector(serviceId, DataSource.class, dataSourceConfig);
|
||||
}
|
||||
|
||||
// Mongodb
|
||||
/**
|
||||
* Get the {@link MongoDbFactory} object associated with the only MongoDB service bound to the app.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:mongo-db-factory/>} element.
|
||||
*
|
||||
* @return mongo db factory
|
||||
* @throws CloudException
|
||||
* if there are either 0 or more than 1 mongodb services.
|
||||
*/
|
||||
public MongoDbFactory mongoDbFactory() {
|
||||
return mongoDbFactory((MongoDbFactoryConfig) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link MongoDbFactory} object associated with the only MongoDB service bound to the app
|
||||
* configured as specified.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:mongo-db-factory>} element with a nested {@code <cloud:mongo-options>} element.
|
||||
*
|
||||
* @param mongoDbFactoryConfig
|
||||
* configuration for the mondo db factory created
|
||||
* @return mongo db factory
|
||||
* @throws CloudException
|
||||
* if there are either 0 or more than 1 mongodb services.
|
||||
*/
|
||||
public MongoDbFactory mongoDbFactory(MongoDbFactoryConfig mongoDbFactoryConfig) {
|
||||
return cloud.getSingletonServiceConnector(MongoDbFactory.class, mongoDbFactoryConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link MongoDbFactory} object for the specified MongoDB service.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:mongo-db-factory service-id="serviceId">} element.
|
||||
*
|
||||
* @param serviceId
|
||||
* the name of the service
|
||||
* @return mongo db factory
|
||||
* @throws CloudException
|
||||
* if the specified service doesn't exist
|
||||
*/
|
||||
public MongoDbFactory mongoDbFactory(String serviceId) {
|
||||
return mongoDbFactory(serviceId, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link MongoDbFactory} object for the specified MongoDB service configured as specified.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:mongo-db-factory service-id="serviceId">} element
|
||||
* with a nested {@code <cloud:mongo-options>} element.
|
||||
*
|
||||
* @param serviceId
|
||||
* the name of the service
|
||||
* @param mongoDbFactoryConfig
|
||||
* configuration for the mongo db factory created
|
||||
* @return mongo db factory
|
||||
* @throws CloudException
|
||||
* if the specified service doesn't exist
|
||||
*/
|
||||
public MongoDbFactory mongoDbFactory(String serviceId, MongoDbFactoryConfig mongoDbFactoryConfig) {
|
||||
return cloud.getServiceConnector(serviceId, MongoDbFactory.class, mongoDbFactoryConfig);
|
||||
}
|
||||
|
||||
// RabbitMQ
|
||||
/**
|
||||
* Get the {@link ConnectionFactory} object associated with the only RabbitMQ service bound to the app.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:rabbit-connection-factory>} element.
|
||||
*
|
||||
* @return rabbit connection factory
|
||||
* @throws CloudException
|
||||
* if there are either 0 or more than 1 RabbitMQ services.
|
||||
*/
|
||||
public ConnectionFactory rabbitConnectionFactory() {
|
||||
return rabbitConnectionFactory((RabbitConnectionFactoryConfig) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ConnectionFactory} object associated with the only RabbitMQ service bound to the app
|
||||
* configured as specified.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:rabbit-connection-factory>} element
|
||||
* with a nested {@code <cloud:rabbit-options>} element.
|
||||
*
|
||||
* @param rabbitConnectionFactoryConfig
|
||||
* configuration for the rabbit connection factory created
|
||||
* @return rabbit connection factory
|
||||
* @throws CloudException
|
||||
* if there are either 0 or more than 1 RabbitMQ services.
|
||||
*/
|
||||
public ConnectionFactory rabbitConnectionFactory(RabbitConnectionFactoryConfig rabbitConnectionFactoryConfig) {
|
||||
return cloud.getSingletonServiceConnector(ConnectionFactory.class, rabbitConnectionFactoryConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ConnectionFactory} object for the specified RabbitMQ service.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:rabbit-connection-factory service-id="serviceId">} element.
|
||||
*
|
||||
* @param serviceId
|
||||
* the name of the service
|
||||
* @return rabbit connection factory
|
||||
* @throws CloudException
|
||||
* if the specified service doesn't exist
|
||||
*/
|
||||
public ConnectionFactory rabbitConnectionFactory(String serviceId) {
|
||||
return rabbitConnectionFactory(serviceId, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ConnectionFactory} object for the specified RabbitMQ service configured as specified.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:rabbit-connection-factory service-id="serviceId">} element
|
||||
* with a nested {@code <cloud:rabbit-options>} element.
|
||||
*
|
||||
* @param serviceId
|
||||
* the name of the service
|
||||
* @param rabbitConnectionFactoryConfig
|
||||
* configuration for the {@link ConnectionFactory} created
|
||||
* @return rabbit connection factory
|
||||
* @throws CloudException
|
||||
* if the specified service doesn't exist
|
||||
*/
|
||||
public ConnectionFactory rabbitConnectionFactory(String serviceId,
|
||||
RabbitConnectionFactoryConfig rabbitConnectionFactoryConfig) {
|
||||
return cloud.getServiceConnector(serviceId, ConnectionFactory.class, rabbitConnectionFactoryConfig);
|
||||
}
|
||||
|
||||
// Redis
|
||||
/**
|
||||
* Get the {@link RedisConnectionFactory} object associated with the only Redis service bound to the app.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:redis-connection-factory/>} element
|
||||
*
|
||||
* @return redis connection factory
|
||||
* @throws CloudException
|
||||
* if there are either 0 or more than 1 redis services.
|
||||
*/
|
||||
public RedisConnectionFactory redisConnectionFactory() {
|
||||
return redisConnectionFactory((PooledServiceConnectorConfig) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link RedisConnectionFactory} object associated with the only Redis service bound to the app
|
||||
* configured as specified.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:redis-connection-factory service-id="serviceId">} element
|
||||
* with a nested {@code <cloud:pool>} element.
|
||||
*
|
||||
* @param redisConnectionFactoryConfig
|
||||
* configuration for the {@link RedisConnectionFactory} created
|
||||
* @return redis connection factory
|
||||
* @throws CloudException
|
||||
* if there are either 0 or more than 1 redis services.
|
||||
*/
|
||||
public RedisConnectionFactory redisConnectionFactory(PooledServiceConnectorConfig redisConnectionFactoryConfig) {
|
||||
return cloud.getSingletonServiceConnector(RedisConnectionFactory.class, redisConnectionFactoryConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link RedisConnectionFactory} object for the specified Redis service.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:redis-connection-factory service-id="serviceId">} element.
|
||||
*
|
||||
* @param serviceId
|
||||
* the name of the service
|
||||
* @return redis connection factory
|
||||
* @throws CloudException
|
||||
* if the specified service doesn't exist
|
||||
*/
|
||||
public RedisConnectionFactory redisConnectionFactory(String serviceId) {
|
||||
return redisConnectionFactory(serviceId, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link RedisConnectionFactory} object for the specified Redis service configured as specified.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:redis-connection-factory service-id="serviceId">} element
|
||||
* with a nested {@code <cloud:pool>} element.
|
||||
*
|
||||
* @param serviceId
|
||||
* the name of the service
|
||||
* @param redisConnectionFactoryConfig
|
||||
* configuration for the {@link RedisConnectionFactory} created
|
||||
* @return redis connection factory
|
||||
* @throws CloudException
|
||||
* if the specified service doesn't exist
|
||||
*/
|
||||
public RedisConnectionFactory redisConnectionFactory(String serviceId,
|
||||
PooledServiceConnectorConfig redisConnectionFactoryConfig) {
|
||||
return cloud.getServiceConnector(serviceId, RedisConnectionFactory.class, redisConnectionFactoryConfig);
|
||||
}
|
||||
|
||||
// Generic service
|
||||
/**
|
||||
* Get the service connector object associated with the only service bound to the app.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:service/>} element.
|
||||
*
|
||||
* @return service connector object
|
||||
* @throws CloudException
|
||||
* if there are either 0 or more than 1 services.
|
||||
*/
|
||||
public Object service() {
|
||||
return service(Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the service connector object of the specified type if there is only one such candidate service
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:service connector-type="T.class"/>} element.
|
||||
*
|
||||
* @param <T>
|
||||
* the type of the service connector to be returned
|
||||
* @param serviceConnectorType
|
||||
* the class of the service connector to be returned
|
||||
* @return service connector object
|
||||
* @throws CloudException
|
||||
* if there are either 0 or more than 1 candidate services.
|
||||
*/
|
||||
public <T> T service(Class<T> serviceConnectorType) {
|
||||
return cloud.getSingletonServiceConnector(serviceConnectorType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the service connector object for the specified service.
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:service service-id="serviceId"/>} element.
|
||||
*
|
||||
* @param serviceId
|
||||
* the service ID of the service to be returned
|
||||
* @return service connector object
|
||||
* @throws CloudException
|
||||
* if the specified service doesn't exist
|
||||
*/
|
||||
public Object service(String serviceId) {
|
||||
return service(serviceId, Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the service connector object of the specified type and service ID
|
||||
*
|
||||
* This is equivalent to the {@code <cloud:service service-id="serviceId" connector-type="T.class"/>} element.
|
||||
*
|
||||
* @param serviceId
|
||||
* the service ID of the service to be returned
|
||||
* @param <T>
|
||||
* the type of the service connector to be returned
|
||||
* @param serviceConnectorType
|
||||
* the class of the service connector to be returned
|
||||
* @return service connector object
|
||||
* @throws CloudException
|
||||
* if the specified service doesn't exist
|
||||
*/
|
||||
public <T> T service(String serviceId, Class<T> serviceConnectorType) {
|
||||
return cloud.getServiceConnector(serviceId, serviceConnectorType, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* Parser for the <cloud:data-source> namespace element
|
||||
* Parser for the {@code <cloud:data-source>} namespace element
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
* @author Thomas Risberg
|
||||
@@ -38,7 +38,7 @@ public class CloudDataSourceFactoryParser extends AbstractPoolingCloudServiceFac
|
||||
cloudPoolConfiguration = parsePoolElement((Element) child, parserContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BeanDefinitionBuilder dataSourceConfigBeanBuilder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition("org.springframework.cloud.service.relational.DataSourceConfig");
|
||||
dataSourceConfigBeanBuilder.addConstructorArgValue(cloudPoolConfiguration);
|
||||
|
||||
@@ -12,7 +12,7 @@ import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* Parser for the <cloud:mongo-db-factory> namespace element
|
||||
* Parser for the {@code <cloud:mongo-db-factory>} namespace element
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Ramnivas Laddad
|
||||
@@ -31,7 +31,7 @@ public class CloudMongoDbFactoryParser extends AbstractNestedElementCloudService
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
super.doParse(element, parserContext, builder);
|
||||
|
||||
|
||||
Map<String, String> attributeMap = new HashMap<String, String>();
|
||||
parseWriteConcern(element, attributeMap);
|
||||
parseMongoOptionsElement(element, parserContext, attributeMap);
|
||||
@@ -40,9 +40,9 @@ public class CloudMongoDbFactoryParser extends AbstractNestedElementCloudService
|
||||
BeanDefinitionBuilder.genericBeanDefinition("org.springframework.cloud.service.document.MongoDbFactoryConfig");
|
||||
for (String key : new String[]{WRITE_CONCERN, CONNECTIONS_PER_HOST, MAX_WAIT_TIME}) {
|
||||
String value = attributeMap.get(key);
|
||||
cloudMongoConfigurationBeanBuilder.addConstructorArgValue(value);
|
||||
cloudMongoConfigurationBeanBuilder.addConstructorArgValue(value);
|
||||
}
|
||||
|
||||
|
||||
builder.addConstructorArgValue(cloudMongoConfigurationBeanBuilder.getBeanDefinition());
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public class CloudMongoDbFactoryParser extends AbstractNestedElementCloudService
|
||||
|
||||
private void parseMongoOptionsElement(Element element, ParserContext parserContext, Map<String, String> attributeMap) {
|
||||
NodeList childNodes = element.getChildNodes();
|
||||
|
||||
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
Node child = childNodes.item(i);
|
||||
if (isElement(child, parserContext, ELEMENT_MONGO_OPTIONS)) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* Parser for the <cloud:rabbit-connection-factory> namespace element
|
||||
* Parser for the {@code <cloud:rabbit-connection-factory>} namespace element
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Ramnivas Laddad
|
||||
|
||||
@@ -9,8 +9,8 @@ import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* Parser for the <cloud:redis-connection-factory> namespace element
|
||||
*
|
||||
* Parser for the {@code <cloud:redis-connection-factory>} namespace element
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
*/
|
||||
@@ -33,11 +33,11 @@ public class CloudRedisConnectionFactoryParser extends AbstractPoolingCloudServi
|
||||
cloudPoolConfiguration = parsePoolElement((Element) child, parserContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BeanDefinitionBuilder redisConfigBeanBuilder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition("org.springframework.cloud.service.PooledServiceConnectorConfig");
|
||||
redisConfigBeanBuilder.addConstructorArgValue(cloudPoolConfiguration);
|
||||
|
||||
builder.addConstructorArgValue(redisConfigBeanBuilder.getBeanDefinition());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,8 @@ import org.w3c.dom.Element;
|
||||
|
||||
|
||||
/**
|
||||
* Support for the catch-all <cloud:service> namespace
|
||||
*
|
||||
* Support for the catch-all {@code <cloud:service>} namespace
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
*/
|
||||
@@ -26,7 +26,7 @@ public class GenericCloudServiceFactoryParser extends AbstractCloudServiceFactor
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
super.doParse(element, parserContext, builder);
|
||||
|
||||
|
||||
String connectorTypeName = element.getAttribute(CONNECTOR_TYPE);
|
||||
if (StringUtils.hasText(connectorTypeName)) {
|
||||
try {
|
||||
@@ -36,7 +36,7 @@ public class GenericCloudServiceFactoryParser extends AbstractCloudServiceFactor
|
||||
throw new CloudException("Failed to load " + connectorTypeName, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TBD: Support generic (map-based?) service config
|
||||
builder.addConstructorArgValue(null);
|
||||
}
|
||||
|
||||
@@ -13,111 +13,118 @@ import org.springframework.util.StringUtils;
|
||||
/**
|
||||
* 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.
|
||||
* 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 <S>
|
||||
* The service type
|
||||
*/
|
||||
public abstract class AbstractCloudServiceConnectorFactory<S> extends AbstractFactoryBean<S> implements CloudServiceConnectorFactory<S> {
|
||||
public abstract class AbstractCloudServiceConnectorFactory<S> extends AbstractFactoryBean<S> implements
|
||||
CloudServiceConnectorFactory<S> {
|
||||
|
||||
private static final String CLOUD_FACTORY_BEAN_NAME = "__cloud_factory__";
|
||||
private static final String CLOUD_FACTORY_BEAN_NAME = "__cloud_factory__";
|
||||
|
||||
private Cloud cloud;
|
||||
private Cloud cloud;
|
||||
|
||||
protected String serviceId;
|
||||
private Class<? extends S> serviceConnectorType;
|
||||
private ServiceConnectorConfig serviceConnectorConfiguration;
|
||||
|
||||
private S serviceInstance;
|
||||
protected String serviceId;
|
||||
private Class<? extends S> serviceConnectorType;
|
||||
private ServiceConnectorConfig serviceConnectorConfiguration;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param serviceId Optional service name property. If this property is null, a unique service of the expected type
|
||||
* (redis, for example) needs to be bound to the application.
|
||||
* @param serviceConnectorType
|
||||
* @param serviceConnectorConfiguration
|
||||
*/
|
||||
public AbstractCloudServiceConnectorFactory(String serviceId, Class<S> serviceConnectorType, ServiceConnectorConfig serviceConnectorConfiguration) {
|
||||
this.serviceId = serviceId;
|
||||
this.serviceConnectorType = serviceConnectorType;
|
||||
this.serviceConnectorConfiguration = serviceConnectorConfiguration;
|
||||
}
|
||||
private S serviceInstance;
|
||||
|
||||
public AbstractCloudServiceConnectorFactory(Class<S> serviceConnectorType, ServiceConnectorConfig serviceConnectorConfiguration) {
|
||||
this(null, serviceConnectorType, serviceConnectorConfiguration);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param serviceId
|
||||
* Optional service name property. If this property is null, a unique service of the expected type
|
||||
* (redis, for example) needs to be bound to the application.
|
||||
* @param serviceConnectorType
|
||||
* the class of the service connector that will be returned
|
||||
* @param serviceConnectorConfiguration
|
||||
* configuration to be applied to the service connector
|
||||
*/
|
||||
public AbstractCloudServiceConnectorFactory(String serviceId, Class<S> serviceConnectorType,
|
||||
ServiceConnectorConfig serviceConnectorConfiguration) {
|
||||
this.serviceId = serviceId;
|
||||
this.serviceConnectorType = serviceConnectorType;
|
||||
this.serviceConnectorConfiguration = serviceConnectorConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cloud, for internal testing purpose only.
|
||||
*
|
||||
* <p>
|
||||
* For normal usage, the {@link InitializingBean} approach will create (if needed) a {@link CloudFactory} and obtain a {@link Cloud} from it.
|
||||
*
|
||||
* @param cloud
|
||||
*/
|
||||
public void setCloud(Cloud cloud) {
|
||||
this.cloud = cloud;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
ConfigurableListableBeanFactory beanFactory = (ConfigurableListableBeanFactory) getBeanFactory();
|
||||
|
||||
if (cloud == null) {
|
||||
if(beanFactory.getBeansOfType(CloudFactory.class).isEmpty()) {
|
||||
beanFactory.registerSingleton(CLOUD_FACTORY_BEAN_NAME, new CloudFactory());
|
||||
}
|
||||
CloudFactory cloudFactory = beanFactory.getBeansOfType(CloudFactory.class).values().iterator().next();
|
||||
cloud = cloudFactory.getCloud();
|
||||
}
|
||||
if (!StringUtils.hasText(serviceId)) {
|
||||
List<? extends ServiceInfo> infos = cloud.getServiceInfos(serviceConnectorType);
|
||||
if (infos.size() != 1) {
|
||||
throw new CloudException("Expected 1 service matching " + serviceConnectorType.getName() + " type, but found " + infos.size());
|
||||
}
|
||||
serviceId = infos.get(0).getId();
|
||||
}
|
||||
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected S createInstance() throws Exception {
|
||||
return createService();
|
||||
}
|
||||
|
||||
public S createService() {
|
||||
if (serviceInstance == null && cloud != null) {
|
||||
serviceInstance = cloud.getServiceConnector(serviceId, serviceConnectorType, serviceConnectorConfiguration);
|
||||
}
|
||||
return serviceInstance;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
if (serviceConnectorType == null) {
|
||||
try {
|
||||
serviceConnectorType = (Class<? extends S>) createService().getClass();
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return serviceConnectorType;
|
||||
}
|
||||
public AbstractCloudServiceConnectorFactory(Class<S> serviceConnectorType, ServiceConnectorConfig serviceConnectorConfiguration) {
|
||||
this(null, serviceConnectorType, serviceConnectorConfiguration);
|
||||
}
|
||||
|
||||
public String getServiceId() {
|
||||
return serviceId;
|
||||
}
|
||||
/**
|
||||
* Set the cloud, for internal testing purpose only.
|
||||
*
|
||||
* <p>
|
||||
* For normal usage, the {@link InitializingBean} approach will create (if needed) a {@link CloudFactory} and obtain a
|
||||
* {@link Cloud} from it.
|
||||
*
|
||||
* @param cloud
|
||||
* the {@link Cloud} instance describing the discovered runtime environment
|
||||
*/
|
||||
public void setCloud(Cloud cloud) {
|
||||
this.cloud = cloud;
|
||||
}
|
||||
|
||||
public void setServiceConnectorType(Class<? extends S> serviceConnectorType) {
|
||||
if (serviceConnectorType != null) {
|
||||
this.serviceConnectorType = serviceConnectorType;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
ConfigurableListableBeanFactory beanFactory = (ConfigurableListableBeanFactory) getBeanFactory();
|
||||
|
||||
if (cloud == null) {
|
||||
if (beanFactory.getBeansOfType(CloudFactory.class).isEmpty()) {
|
||||
beanFactory.registerSingleton(CLOUD_FACTORY_BEAN_NAME, new CloudFactory());
|
||||
}
|
||||
CloudFactory cloudFactory = beanFactory.getBeansOfType(CloudFactory.class).values().iterator().next();
|
||||
cloud = cloudFactory.getCloud();
|
||||
}
|
||||
if (!StringUtils.hasText(serviceId)) {
|
||||
List<? extends ServiceInfo> infos = cloud.getServiceInfos(serviceConnectorType);
|
||||
if (infos.size() != 1) {
|
||||
throw new CloudException("Expected 1 service matching " + serviceConnectorType.getName() + " type, but found "
|
||||
+ infos.size());
|
||||
}
|
||||
serviceId = infos.get(0).getId();
|
||||
}
|
||||
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected S createInstance() throws Exception {
|
||||
return createService();
|
||||
}
|
||||
|
||||
public S createService() {
|
||||
if (serviceInstance == null && cloud != null) {
|
||||
serviceInstance = cloud.getServiceConnector(serviceId, serviceConnectorType, serviceConnectorConfiguration);
|
||||
}
|
||||
return serviceInstance;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
if (serviceConnectorType == null) {
|
||||
try {
|
||||
serviceConnectorType = (Class<? extends S>) createService().getClass();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return serviceConnectorType;
|
||||
}
|
||||
|
||||
public String getServiceId() {
|
||||
return serviceId;
|
||||
}
|
||||
|
||||
public void setServiceConnectorType(Class<? extends S> serviceConnectorType) {
|
||||
if (serviceConnectorType != null) {
|
||||
this.serviceConnectorType = serviceConnectorType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Configuration for pooling
|
||||
*
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
* @author Mark Fisher
|
||||
* @author Thomas Risberg
|
||||
@@ -20,7 +20,7 @@ public class PooledServiceConnectorConfig implements ServiceConnectorConfig {
|
||||
public PoolConfig getPoolConfig() {
|
||||
return poolConfig;
|
||||
}
|
||||
|
||||
|
||||
public static class PoolConfig {
|
||||
private int minPoolSize;
|
||||
private int maxPoolSize;
|
||||
@@ -31,54 +31,60 @@ public class PooledServiceConnectorConfig implements ServiceConnectorConfig {
|
||||
this.maxPoolSize = maxPoolSize;
|
||||
this.maxWaitTime = maxWaitTime;
|
||||
}
|
||||
|
||||
|
||||
public PoolConfig(int maxPoolSize, int maxWaitTime) {
|
||||
this(0, maxPoolSize, maxWaitTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public PoolConfig(String poolSize, int maxWaitTime) {
|
||||
determinePoolSizeRange(poolSize);
|
||||
this.maxWaitTime = maxWaitTime;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter corresponding to the DBCP initialSize property
|
||||
* @return property corresponding to DBCP {@code initialSize}
|
||||
*/
|
||||
public int getInitialSize() {
|
||||
return minPoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter corresponding to the DBCP minIdle property
|
||||
* @return property corresponding to DBCP {@code minIdle}
|
||||
*/
|
||||
public int getMinIdle() {
|
||||
return minPoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter corresponding to the DBCP maxActive property
|
||||
* @return property corresponding to DBCP {@code maxActive}
|
||||
*/
|
||||
public int getMaxActive() {
|
||||
return maxPoolSize;
|
||||
}
|
||||
|
||||
// For commons-pool2
|
||||
/**
|
||||
* @return property corresponding to commons-pool {@code maxTotal}
|
||||
*/
|
||||
public int getMaxTotal() {
|
||||
return maxPoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter corresponding to the DBCP maxWait property
|
||||
* @return property corresponding to DBCP {@code maxWait}
|
||||
*/
|
||||
public int getMaxWait() {
|
||||
return maxWaitTime;
|
||||
}
|
||||
|
||||
// For commons-pool2
|
||||
// For commons-pool2
|
||||
/**
|
||||
* @return property corresponding to commons-pool {@code maxWaitMillis}
|
||||
*/
|
||||
public int getMaxWaitMillis() {
|
||||
return maxWaitTime;
|
||||
}
|
||||
|
||||
|
||||
private void determinePoolSizeRange(String poolSize) {
|
||||
if (StringUtils.hasText(poolSize)) {
|
||||
try {
|
||||
|
||||
@@ -12,7 +12,7 @@ public class MongoDbFactoryConfig implements ServiceConnectorConfig {
|
||||
private String writeConcern;
|
||||
private Integer connectionsPerHost;
|
||||
private Integer maxWaitTime;
|
||||
|
||||
|
||||
public MongoDbFactoryConfig(String writeConcern, Integer connectionsPerHost, Integer maxWaitTime) {
|
||||
this.writeConcern = writeConcern;
|
||||
this.connectionsPerHost = connectionsPerHost;
|
||||
@@ -24,14 +24,14 @@ public class MongoDbFactoryConfig implements ServiceConnectorConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter corresponding to the MongoOptions connectionsPerHost field
|
||||
* @return property corresponding to MongoOptions {@code connectionsPerHost}
|
||||
*/
|
||||
public Integer getConnectionsPerHost() {
|
||||
return connectionsPerHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter corresponding to the MongoOptions maxWaitTime field
|
||||
* @return property corresponding to the MongoOptions {@code maxWaitTime}
|
||||
*/
|
||||
public Integer getMaxWaitTime () {
|
||||
return maxWaitTime ;
|
||||
|
||||
@@ -8,10 +8,10 @@ import org.springframework.cloud.service.ServiceConnectorConfig;
|
||||
import org.springframework.cloud.service.common.RelationalServiceInfo;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
* @param <SI>
|
||||
* @param <SI> the {@link RelationalServiceInfo} type for the underlying database service
|
||||
*/
|
||||
public class BasicDbcpPooledDataSourceCreator<SI extends RelationalServiceInfo> extends DbcpLikePooledDataSourceCreator<SI> {
|
||||
|
||||
|
||||
@@ -15,10 +15,10 @@ import org.springframework.cloud.service.common.RelationalServiceInfo;
|
||||
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
* @param <SI>
|
||||
* @param <SI> the {@link RelationalServiceInfo} for the backing database service
|
||||
*/
|
||||
public abstract class DataSourceCreator<SI extends RelationalServiceInfo> extends AbstractServiceConnectorCreator<DataSource, SI> {
|
||||
|
||||
@@ -34,20 +34,20 @@ public abstract class DataSourceCreator<SI extends RelationalServiceInfo> extend
|
||||
this.driverSystemPropKey = driverSystemPropKey;
|
||||
this.driverClasses = driverClasses;
|
||||
this.validationQuery = validationQuery;
|
||||
|
||||
|
||||
if (pooledDataSourceCreators.size() == 0) {
|
||||
pooledDataSourceCreators.add(new BasicDbcpPooledDataSourceCreator<SI>());
|
||||
pooledDataSourceCreators.add(new TomcatDbcpPooledDataSourceCreator<SI>());
|
||||
pooledDataSourceCreators.add(new TomcatHighPerformancePooledDataSourceCreator<SI>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DataSource create(SI serviceInfo, ServiceConnectorConfig serviceConnectorConfig) {
|
||||
try {
|
||||
for (PooledDataSourceCreator<SI> delegate: pooledDataSourceCreators) {
|
||||
DataSource ds = delegate.create(serviceInfo, serviceConnectorConfig, getDriverClassName(serviceInfo), validationQuery);
|
||||
|
||||
|
||||
if (ds != null) {
|
||||
return ds;
|
||||
}
|
||||
@@ -61,10 +61,10 @@ public abstract class DataSourceCreator<SI extends RelationalServiceInfo> extend
|
||||
+ serviceInfo.getId() + " service", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getDriverClassName(SI serviceInfo) {
|
||||
String userSpecifiedDriver = System.getProperty(driverSystemPropKey);
|
||||
|
||||
|
||||
if (userSpecifiedDriver != null && !userSpecifiedDriver.isEmpty()) {
|
||||
return userSpecifiedDriver;
|
||||
} else {
|
||||
|
||||
@@ -12,13 +12,13 @@ import org.springframework.cloud.service.common.RelationalServiceInfo;
|
||||
|
||||
/**
|
||||
* Common implementation that assumes DBCP connection pool properties.
|
||||
*
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
* @param <SI>
|
||||
* @param <SI> the {@link RelationalServiceInfo} type for the underlying database service
|
||||
*/
|
||||
public abstract class DbcpLikePooledDataSourceCreator<SI extends RelationalServiceInfo> implements PooledDataSourceCreator<SI> {
|
||||
|
||||
|
||||
protected static Logger logger = Logger.getLogger(PooledDataSourceCreator.class.getName());
|
||||
|
||||
private DataSourceConfigurer configurer = new DataSourceConfigurer();
|
||||
@@ -33,9 +33,9 @@ public abstract class DbcpLikePooledDataSourceCreator<SI extends RelationalServi
|
||||
target.setPropertyValue("validationQuery", validationQuery);
|
||||
target.setPropertyValue("testOnBorrow", true);
|
||||
}
|
||||
|
||||
|
||||
if (serviceConnectorConfig == null) {
|
||||
// choose sensible values so that we set max connection pool size to what
|
||||
// choose sensible values so that we set max connection pool size to what
|
||||
// free tier services on Cloud Foundry and Heroku allow
|
||||
serviceConnectorConfig = new DataSourceConfig(new PoolConfig(4, 30000), null);
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@ import org.springframework.cloud.service.common.RelationalServiceInfo;
|
||||
|
||||
/**
|
||||
* DataSource creator that produces a pooled connection
|
||||
*
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
* @param <SI>
|
||||
* @param <SI> the {@link RelationalServiceInfo} type for the underlying database service
|
||||
*/
|
||||
public interface PooledDataSourceCreator<SI extends RelationalServiceInfo> {
|
||||
public abstract DataSource create(RelationalServiceInfo serviceInfo, ServiceConnectorConfig serviceConnectorConfig,
|
||||
|
||||
@@ -8,10 +8,10 @@ import org.springframework.cloud.service.ServiceConnectorConfig;
|
||||
import org.springframework.cloud.service.common.RelationalServiceInfo;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
* @param <SI>
|
||||
* @param <SI> the {@link RelationalServiceInfo} type for the underlying database service
|
||||
*/
|
||||
public class TomcatDbcpPooledDataSourceCreator<SI extends RelationalServiceInfo> extends DbcpLikePooledDataSourceCreator<SI> {
|
||||
|
||||
|
||||
@@ -8,12 +8,10 @@ import org.springframework.cloud.service.ServiceConnectorConfig;
|
||||
import org.springframework.cloud.service.common.RelationalServiceInfo;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ramnivas Laddad
|
||||
*
|
||||
* @param <SI>
|
||||
* @author Ramnivas Laddad
|
||||
*/
|
||||
public class TomcatHighPerformancePooledDataSourceCreator<SI extends RelationalServiceInfo>
|
||||
public class TomcatHighPerformancePooledDataSourceCreator<SI extends RelationalServiceInfo>
|
||||
extends DbcpLikePooledDataSourceCreator<SI> {
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user