CassandraBindingsPropertiesProcessor
Now tell me you don't love that implementation! Signed-off-by: Ben Hale <bhale@vmware.com>
This commit is contained in:
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.cnb.boot;
|
||||
|
||||
import org.springframework.cloud.cnb.Binding;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class CassandraCnbBindingProcessor implements CnbBindingProcessor {
|
||||
public static final String CASSANDRA_KIND = "cassandra";
|
||||
|
||||
@Override
|
||||
public boolean accept(Binding binding) {
|
||||
return binding.getKind().equals(CASSANDRA_KIND);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Binding binding, Map<String, Object> properties) {
|
||||
properties.put("spring.data.cassandra.username", binding.getSecret().get("username"));
|
||||
properties.put("spring.data.cassandra.password", binding.getSecret().get("password"));
|
||||
properties.put("spring.data.cassandra.contact-points", binding.getSecret().get("node_ips"));
|
||||
properties.put("spring.data.cassandra.port", binding.getSecret().get("port"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CnbBindingProcessorProperties getProperties() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.cnb.boot;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cloud.cnb.Binding;
|
||||
|
||||
public interface CnbBindingProcessor {
|
||||
|
||||
boolean accept(Binding binding);
|
||||
|
||||
void process(Binding binding, Map<String, Object> properties);
|
||||
|
||||
CnbBindingProcessorProperties getProperties();
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.cnb.boot;
|
||||
|
||||
/**
|
||||
* Properties describing a CfEnvProcessor, mainly used for better logging messages in {@link CnbBindingProcessor}.
|
||||
*
|
||||
* @author Mark Pollack
|
||||
*/
|
||||
public class CnbBindingProcessorProperties {
|
||||
|
||||
private String propertyPrefixes;
|
||||
|
||||
private String serviceName;
|
||||
|
||||
private CnbBindingProcessorProperties() {
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new CnbBindingProcessorProperties.Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* A string containing the values of property prefixes that will be set in the {@code process} method. Used
|
||||
* for logging purposes.
|
||||
* @return property prefix values set in the {@code process} method
|
||||
*/
|
||||
public String getPropertyPrefixes() {
|
||||
return propertyPrefixes;
|
||||
}
|
||||
|
||||
/**
|
||||
* A name that describes the service being processed, eg. 'Redis', 'MongoDB'. Used for logging purposes.
|
||||
* @return name that describes the service being processed
|
||||
*/
|
||||
public String getServiceName() {
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
|
||||
public static class Builder {
|
||||
private CnbBindingProcessorProperties processorProperties = new CnbBindingProcessorProperties();
|
||||
|
||||
// Todo: add kind & provider, make serviceName the binding name
|
||||
|
||||
public Builder propertyPrefixes(String propertyPrefixes) {
|
||||
this.processorProperties.propertyPrefixes = propertyPrefixes;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder serviceName(String serviceName) {
|
||||
this.processorProperties.serviceName = serviceName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CnbBindingProcessorProperties build() {
|
||||
return processorProperties;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.cnb.boot;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.context.config.ConfigFileApplicationListener;
|
||||
import org.springframework.boot.context.event.ApplicationPreparedEvent;
|
||||
import org.springframework.boot.env.EnvironmentPostProcessor;
|
||||
import org.springframework.cloud.cnb.core.CNBBindingsSingleton;
|
||||
import org.springframework.cloud.cnb.Binding;
|
||||
import org.springframework.cloud.cnb.Bindings;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.env.CommandLinePropertySource;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* An EnvironmentPostProcessor that iterates over {@link CnbBindingProcessor} implementations to contribute
|
||||
* Spring Boot properties for bound Cloud Foundry Services.
|
||||
*
|
||||
* Implementation of {@link CnbBindingProcessor }should be registered using the
|
||||
* {@code resources/META-INF/spring.factories} property file.
|
||||
*
|
||||
* @author Mark Pollack
|
||||
* @author David Turanski
|
||||
*/
|
||||
@Component
|
||||
public class CnbBindingsPostProcessor implements EnvironmentPostProcessor, Ordered, ApplicationListener<ApplicationEvent> {
|
||||
|
||||
private static DeferredLog DEFERRED_LOG = new DeferredLog();
|
||||
|
||||
private static int invocationCount;
|
||||
|
||||
// Before ConfigFileApplicationListener so values there can use these ones
|
||||
private int order = ConfigFileApplicationListener.DEFAULT_ORDER - 1;
|
||||
|
||||
public CnbBindingsPostProcessor() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return this.order;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessEnvironment(ConfigurableEnvironment environment,
|
||||
SpringApplication application) {
|
||||
|
||||
// TODO: allow users to disable processing of a given binding by name, kind, or processor
|
||||
|
||||
increaseInvocationCount();
|
||||
Bindings bindings = CNBBindingsSingleton.getCnbBindingsInstance();
|
||||
|
||||
if (bindings.hasBindings()) {
|
||||
List<Binding> allBindings = bindings.findAllBindings();
|
||||
|
||||
List<CnbBindingProcessor> cnbBindingProcessors = SpringFactoriesLoader
|
||||
.loadFactories(CnbBindingProcessor.class, getClass().getClassLoader());
|
||||
AnnotationAwareOrderComparator.sort(cnbBindingProcessors);
|
||||
|
||||
for (CnbBindingProcessor processor : cnbBindingProcessors) {
|
||||
List<Binding> cnbBindings = allBindings.stream()
|
||||
.filter(processor::accept)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
||||
if (cnbBindings.size() == 1) {
|
||||
Binding binding = cnbBindings.get(0);
|
||||
Map<String, Object> properties = new LinkedHashMap<>();
|
||||
|
||||
processor.process(binding, properties);
|
||||
|
||||
MutablePropertySources propertySources = environment.getPropertySources();
|
||||
|
||||
if (propertySources.contains(
|
||||
CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME)) {
|
||||
propertySources.addAfter(
|
||||
CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME,
|
||||
new MapPropertySource(processor.getClass().getSimpleName(), properties));
|
||||
} else {
|
||||
propertySources.addFirst(
|
||||
new MapPropertySource(processor.getClass().getSimpleName(), properties));
|
||||
}
|
||||
|
||||
if (invocationCount == 1) {
|
||||
DEFERRED_LOG.info(
|
||||
"Setting " + processor.getProperties().getPropertyPrefixes() +
|
||||
" properties from bound service ["
|
||||
+ binding.getName() + "] using " + processor.getClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (invocationCount == 1) {
|
||||
DEFERRED_LOG.debug(
|
||||
"Not setting properties, CNB Bindings not detected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
if (event instanceof ApplicationPreparedEvent) {
|
||||
DEFERRED_LOG
|
||||
.switchTo(CnbBindingsPostProcessor.class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* EnvironmentPostProcessors can end up getting called twice due to spring-cloud-commons
|
||||
* functionality
|
||||
*/
|
||||
protected void increaseInvocationCount() {
|
||||
synchronized (this) {
|
||||
invocationCount++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.cnb.boot;
|
||||
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Determine if the Connector Library is on the classpath
|
||||
* @author Mark Pollack
|
||||
*/
|
||||
public abstract class ConnectorLibraryDetector {
|
||||
|
||||
public static String MESSAGE = "Exiting the application since the Spring Cloud Connector library has been detected on the classpath. Please remove this dependency from your project and set the environment variable JBP_CONFIG_SPRING_AUTO_RECONFIGURATION '{enabled: false}' in the Cloud Foundry manifest.";
|
||||
|
||||
private static boolean usingConnectorLibrary;
|
||||
|
||||
static {
|
||||
ClassLoader classLoader = ConnectorLibraryDetector.class.getClassLoader();
|
||||
usingConnectorLibrary = ClassUtils.isPresent("org.springframework.cloud.Cloud", classLoader) ||
|
||||
ClassUtils.isPresent("org.cloudfoundry.reconfiguration.org.springframework.cloud.Cloud", classLoader);
|
||||
}
|
||||
|
||||
static boolean isUsingConnectorLibrary() {
|
||||
return usingConnectorLibrary;
|
||||
}
|
||||
|
||||
static void assertNoConnectorLibrary() {
|
||||
if (ConnectorLibraryDetector.isUsingConnectorLibrary()) {
|
||||
throw new IllegalStateException(ConnectorLibraryDetector.MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,269 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.cnb.boot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Deferred {@link Log} that can be used to store messages that shouldn't be written until
|
||||
* the logging system is fully initialized.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class DeferredLog implements Log {
|
||||
|
||||
private volatile Log destination;
|
||||
|
||||
private final List<Line> lines = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public boolean isTraceEnabled() {
|
||||
synchronized (this.lines) {
|
||||
return (this.destination != null) ? this.destination.isTraceEnabled() : true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled() {
|
||||
synchronized (this.lines) {
|
||||
return (this.destination != null) ? this.destination.isDebugEnabled() : true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInfoEnabled() {
|
||||
synchronized (this.lines) {
|
||||
return (this.destination != null) ? this.destination.isInfoEnabled() : true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWarnEnabled() {
|
||||
synchronized (this.lines) {
|
||||
return (this.destination != null) ? this.destination.isWarnEnabled() : true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isErrorEnabled() {
|
||||
synchronized (this.lines) {
|
||||
return (this.destination != null) ? this.destination.isErrorEnabled() : true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFatalEnabled() {
|
||||
synchronized (this.lines) {
|
||||
return (this.destination != null) ? this.destination.isFatalEnabled() : true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Object message) {
|
||||
log(LogLevel.TRACE, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Object message, Throwable t) {
|
||||
log(LogLevel.TRACE, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Object message) {
|
||||
log(LogLevel.DEBUG, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Object message, Throwable t) {
|
||||
log(LogLevel.DEBUG, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Object message) {
|
||||
log(LogLevel.INFO, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Object message, Throwable t) {
|
||||
log(LogLevel.INFO, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Object message) {
|
||||
log(LogLevel.WARN, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Object message, Throwable t) {
|
||||
log(LogLevel.WARN, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Object message) {
|
||||
log(LogLevel.ERROR, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Object message, Throwable t) {
|
||||
log(LogLevel.ERROR, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatal(Object message) {
|
||||
log(LogLevel.FATAL, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatal(Object message, Throwable t) {
|
||||
log(LogLevel.FATAL, message, t);
|
||||
}
|
||||
|
||||
private void log(LogLevel level, Object message, Throwable t) {
|
||||
synchronized (this.lines) {
|
||||
if (this.destination != null) {
|
||||
logTo(this.destination, level, message, t);
|
||||
}
|
||||
else {
|
||||
this.lines.add(new Line(level, message, t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch from deferred logging to immediate logging to the specified destination.
|
||||
* @param destination the new log destination
|
||||
* @since 2.1.0
|
||||
*/
|
||||
public void switchTo(Class<?> destination) {
|
||||
switchTo(LogFactory.getLog(destination));
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch from deferred logging to immediate logging to the specified destination.
|
||||
* @param destination the new log destination
|
||||
* @since 2.1.0
|
||||
*/
|
||||
public void switchTo(Log destination) {
|
||||
synchronized (this.lines) {
|
||||
replayTo(destination);
|
||||
this.destination = destination;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replay deferred logging to the specified destination.
|
||||
* @param destination the destination for the deferred log messages
|
||||
*/
|
||||
public void replayTo(Class<?> destination) {
|
||||
replayTo(LogFactory.getLog(destination));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replay deferred logging to the specified destination.
|
||||
* @param destination the destination for the deferred log messages
|
||||
*/
|
||||
public void replayTo(Log destination) {
|
||||
synchronized (this.lines) {
|
||||
for (Line line : this.lines) {
|
||||
logTo(destination, line.getLevel(), line.getMessage(),
|
||||
line.getThrowable());
|
||||
}
|
||||
this.lines.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replay from a source log to a destination log when the source is deferred.
|
||||
* @param source the source logger
|
||||
* @param destination the destination logger class
|
||||
* @return the destination
|
||||
*/
|
||||
public static Log replay(Log source, Class<?> destination) {
|
||||
return replay(source, LogFactory.getLog(destination));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replay from a source log to a destination log when the source is deferred.
|
||||
* @param source the source logger
|
||||
* @param destination the destination logger
|
||||
* @return the destination
|
||||
*/
|
||||
public static Log replay(Log source, Log destination) {
|
||||
if (source instanceof DeferredLog) {
|
||||
((DeferredLog) source).replayTo(destination);
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
|
||||
private static void logTo(Log log, LogLevel level, Object message,
|
||||
Throwable throwable) {
|
||||
switch (level) {
|
||||
case TRACE:
|
||||
log.trace(message, throwable);
|
||||
return;
|
||||
case DEBUG:
|
||||
log.debug(message, throwable);
|
||||
return;
|
||||
case INFO:
|
||||
log.info(message, throwable);
|
||||
return;
|
||||
case WARN:
|
||||
log.warn(message, throwable);
|
||||
return;
|
||||
case ERROR:
|
||||
log.error(message, throwable);
|
||||
return;
|
||||
case FATAL:
|
||||
log.fatal(message, throwable);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Line {
|
||||
|
||||
private final LogLevel level;
|
||||
|
||||
private final Object message;
|
||||
|
||||
private final Throwable throwable;
|
||||
|
||||
Line(LogLevel level, Object message, Throwable throwable) {
|
||||
this.level = level;
|
||||
this.message = message;
|
||||
this.throwable = throwable;
|
||||
}
|
||||
|
||||
public LogLevel getLevel() {
|
||||
return this.level;
|
||||
}
|
||||
|
||||
public Object getMessage() {
|
||||
return this.message;
|
||||
}
|
||||
|
||||
public Throwable getThrowable() {
|
||||
return this.throwable;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.cnb.boot;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.cloud.cnb.Binding;
|
||||
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class CassandraCnbBindingProcessorTests {
|
||||
|
||||
@Test
|
||||
public void acceptIfCassandraKind() {
|
||||
CassandraCnbBindingProcessor bindingProcessor = new CassandraCnbBindingProcessor();
|
||||
Map<String, String> bindingMetadata = new HashMap<String, String>();
|
||||
bindingMetadata.put("kind", "cassandra");
|
||||
Binding binding = new Binding(bindingMetadata, new HashMap<String, String>());
|
||||
assertThat(bindingProcessor.accept(binding)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectIfNotCassandraKind() {
|
||||
CassandraCnbBindingProcessor bindingProcessor = new CassandraCnbBindingProcessor();
|
||||
Map<String, String> bindingMetadata = new HashMap<String, String>();
|
||||
bindingMetadata.put("kind", "mysql");
|
||||
Binding binding = new Binding(bindingMetadata, new HashMap<String, String>());
|
||||
assertThat(bindingProcessor.accept(binding)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processDataSourcePropertiesTest() {
|
||||
CassandraCnbBindingProcessor bindingProcessor = new CassandraCnbBindingProcessor();
|
||||
Map<String, String> bindingMetadata = new HashMap<String, String>();
|
||||
bindingMetadata.put("kind", "cassandra");
|
||||
Map<String,String> bindingSecret = new HashMap<String,String>();
|
||||
bindingSecret.put("port", "9042");
|
||||
bindingSecret.put("node_ips", "10.0.4.35,10.0.4.36");
|
||||
bindingSecret.put("password", "some-password");
|
||||
bindingSecret.put("username", "some-username");
|
||||
Binding binding = new Binding(bindingMetadata, bindingSecret);
|
||||
Map<String,Object> properties = new HashMap<String,Object>();
|
||||
bindingProcessor.process(binding, properties);
|
||||
assertThat(properties.get("spring.data.cassandra.username")).isEqualTo("some-username");
|
||||
assertThat(properties.get("spring.data.cassandra.password")).isEqualTo("some-password");
|
||||
assertThat(properties.get("spring.data.cassandra.contact-points")).isEqualTo("10.0.4.35,10.0.4.36");
|
||||
assertThat(properties.get("spring.data.cassandra.port")).isEqualTo("9042");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.cnb.boot;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.Banner;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.cnb.boot.test.EnvMock;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class CnbBindingsPostProcessorTest {
|
||||
|
||||
@Test
|
||||
public void testPostProcessEnvironment(){
|
||||
Path resourceDirectory = Paths.get("src", "test", "resources", "test-bindings");
|
||||
String bindingsDir = resourceDirectory.toFile().getAbsolutePath();
|
||||
|
||||
new EnvMock(bindingsDir);
|
||||
|
||||
CnbBindingsPostProcessor environmentPostProcessor = new CnbBindingsPostProcessor();
|
||||
|
||||
environmentPostProcessor.postProcessEnvironment(getEnvironment(),
|
||||
null);
|
||||
assertThat(getEnvironment().getProperty("spring.datasource.url"))
|
||||
.isEqualTo("jdbc:mysql://10.0.4.35:3306/mysql_name?user=mysql_username&password=mysql_password");
|
||||
assertThat(
|
||||
getEnvironment().getProperty("spring.datasource.username"))
|
||||
.isEqualTo("mysql_username");
|
||||
assertThat(
|
||||
getEnvironment().getProperty("spring.datasource.password"))
|
||||
.isEqualTo("mysql_password");
|
||||
}
|
||||
|
||||
// TODO: test multiple services
|
||||
|
||||
@Test
|
||||
public void testNoBindingsPresent(){
|
||||
CnbBindingsPostProcessor environmentPostProcessor = new CnbBindingsPostProcessor();
|
||||
|
||||
// doen't fail
|
||||
environmentPostProcessor.postProcessEnvironment(getEnvironment(),
|
||||
null);
|
||||
}
|
||||
|
||||
public ConfigurableEnvironment getEnvironment() {
|
||||
return getEnvironment(null);
|
||||
}
|
||||
|
||||
public ConfigurableEnvironment getEnvironment(Map<String, Object> properties) {
|
||||
SpringApplicationBuilder builder = new SpringApplicationBuilder(TestApp.class)
|
||||
.web(WebApplicationType.NONE);
|
||||
if (!CollectionUtils.isEmpty(properties)) {
|
||||
builder.properties(properties);
|
||||
}
|
||||
builder.bannerMode(Banner.Mode.OFF);
|
||||
ConfigurableApplicationContext applicationContext = builder.run();
|
||||
ConfigurableEnvironment environment = applicationContext.getEnvironment();
|
||||
applicationContext.close();
|
||||
return environment;
|
||||
}
|
||||
|
||||
@SpringBootApplication
|
||||
static class TestApp {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.cnb.boot;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
/**
|
||||
* Tests for {@link DeferredLog}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class DeferredLogTests {
|
||||
|
||||
private DeferredLog deferredLog = new DeferredLog();
|
||||
|
||||
private Object message = "Message";
|
||||
|
||||
private Throwable throwable = new IllegalStateException();
|
||||
|
||||
private Log log = mock(Log.class);
|
||||
|
||||
@Test
|
||||
public void isTraceEnabled() {
|
||||
assertThat(this.deferredLog.isTraceEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isDebugEnabled() {
|
||||
assertThat(this.deferredLog.isDebugEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isInfoEnabled() {
|
||||
assertThat(this.deferredLog.isInfoEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isWarnEnabled() {
|
||||
assertThat(this.deferredLog.isWarnEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isErrorEnabled() {
|
||||
assertThat(this.deferredLog.isErrorEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isFatalEnabled() {
|
||||
assertThat(this.deferredLog.isFatalEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trace() {
|
||||
this.deferredLog.trace(this.message);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).trace(this.message, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void traceWithThrowable() {
|
||||
this.deferredLog.trace(this.message, this.throwable);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).trace(this.message, this.throwable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void debug() {
|
||||
this.deferredLog.debug(this.message);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).debug(this.message, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void debugWithThrowable() {
|
||||
this.deferredLog.debug(this.message, this.throwable);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).debug(this.message, this.throwable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void info() {
|
||||
this.deferredLog.info(this.message);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).info(this.message, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void infoWithThrowable() {
|
||||
this.deferredLog.info(this.message, this.throwable);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).info(this.message, this.throwable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void warn() {
|
||||
this.deferredLog.warn(this.message);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).warn(this.message, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void warnWithThrowable() {
|
||||
this.deferredLog.warn(this.message, this.throwable);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).warn(this.message, this.throwable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void error() {
|
||||
this.deferredLog.error(this.message);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).error(this.message, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void errorWithThrowable() {
|
||||
this.deferredLog.error(this.message, this.throwable);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).error(this.message, this.throwable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fatal() {
|
||||
this.deferredLog.fatal(this.message);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).fatal(this.message, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fatalWithThrowable() {
|
||||
this.deferredLog.fatal(this.message, this.throwable);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).fatal(this.message, this.throwable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearsOnReplayTo() {
|
||||
this.deferredLog.info("1");
|
||||
this.deferredLog.fatal("2");
|
||||
Log log2 = mock(Log.class);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
this.deferredLog.replayTo(log2);
|
||||
verify(this.log).info("1", null);
|
||||
verify(this.log).fatal("2", null);
|
||||
verifyNoMoreInteractions(this.log);
|
||||
verifyNoInteractions(log2);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void switchTo() {
|
||||
List<String> lines = (List<String>) ReflectionTestUtils.getField(this.deferredLog,
|
||||
"lines");
|
||||
assertThat(lines).isEmpty();
|
||||
|
||||
this.deferredLog.error(this.message, this.throwable);
|
||||
assertThat(lines).hasSize(1);
|
||||
|
||||
this.deferredLog.switchTo(this.log);
|
||||
assertThat(lines).isEmpty();
|
||||
|
||||
this.deferredLog.info("Message2");
|
||||
assertThat(lines).isEmpty();
|
||||
|
||||
verify(this.log).error(this.message, this.throwable);
|
||||
verify(this.log).info("Message2", null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,12 +50,12 @@ public final class BindingsEnvironmentPostProcessor implements EnvironmentPostPr
|
||||
*/
|
||||
public static final String BINDINGS_PROPERTY_SOURCE_NAME = "cnbBindings";
|
||||
|
||||
final List<BindingsPropertiesProcessor> processors;
|
||||
|
||||
private final Log log = LogFactory.getLog(getClass());
|
||||
|
||||
private final Bindings bindings;
|
||||
|
||||
private final List<BindingsPropertiesProcessor> processors;
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@code BindingsEnvironmentPostProcessor} using the {@link Bindings} available in the
|
||||
* environment and the {@link BindingsPropertiesProcessor}s registered with {@link SpringFactoriesLoader}.
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.bindings;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An implementation of {@link BindingsPropertiesProcessor} that detects {@link Binding}s of kind: {@value KIND}.
|
||||
*/
|
||||
public final class CassandraBindingsPropertiesProcessor implements BindingsPropertiesProcessor {
|
||||
|
||||
/**
|
||||
* The {@link Binding} kind that this processor is interested in: {@value}.
|
||||
**/
|
||||
public static final String KIND = "cassandra";
|
||||
|
||||
@Override
|
||||
public void process(@NonNull Bindings bindings, @NotNull Map<String, Object> properties) {
|
||||
bindings.filterBindings(KIND).forEach(binding -> {
|
||||
Map<String, String> secret = binding.getSecret();
|
||||
|
||||
properties.put("spring.data.cassandra.contact-points", secret.get("node_ips"));
|
||||
properties.put("spring.data.cassandra.password", secret.get("password"));
|
||||
properties.put("spring.data.cassandra.port", secret.get("port"));
|
||||
properties.put("spring.data.cassandra.username", secret.get("username"));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,2 +1,5 @@
|
||||
org.springframework.boot.env.EnvironmentPostProcessor=\
|
||||
org.springframework.cloud.bindings.BindingsEnvironmentPostProcessor
|
||||
# Included implementations
|
||||
org.springframework.cloud.bindings.BindingsPropertiesProcessor=\
|
||||
org.springframework.cloud.bindings.CassandraBindingsPropertiesProcessor
|
||||
|
||||
@@ -113,4 +113,11 @@ final class BindingsEnvironmentPostProcessorTest {
|
||||
assertThat(new BindingsEnvironmentPostProcessor(new Bindings()).getOrder())
|
||||
.isLessThan(ConfigFileApplicationListener.DEFAULT_ORDER);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("included implementations are registered")
|
||||
void includedImplementations() {
|
||||
assertThat(new BindingsEnvironmentPostProcessor().processors).hasSize(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
@@ -78,18 +76,13 @@ final class BindingsTests {
|
||||
|
||||
private final Bindings bindings = new Bindings(
|
||||
new Binding("test-name-1", Paths.get("src/test/resources/test-name-1"),
|
||||
metadata("test-kind-1", "test-provider-1"), Collections.emptyMap()),
|
||||
new FluentMap().withEntry("kind", "test-kind-1").withEntry("provider", "test-provider-1"),
|
||||
Collections.emptyMap()),
|
||||
new Binding("test-name-2", Paths.get("src/test/resources/test-name-2"),
|
||||
metadata("test-kind-2", "test-provider-2"), Collections.emptyMap())
|
||||
new FluentMap().withEntry("kind", "test-kind-2").withEntry("provider", "test-provider-2"),
|
||||
Collections.emptyMap())
|
||||
);
|
||||
|
||||
private Map<String, String> metadata(String kind, String provider) {
|
||||
Map<String, String> metadata = new HashMap<>(2);
|
||||
metadata.put("kind", kind);
|
||||
metadata.put("provider", provider);
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("returns content")
|
||||
void getBindings() {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.bindings;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.bindings.CassandraBindingsPropertiesProcessor.KIND;
|
||||
|
||||
@DisplayName("Cassandra BindingsPropertiesProcessor")
|
||||
final class CassandraBindingsPropertiesProcessorTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("contributes properties")
|
||||
void test() {
|
||||
HashMap<String, Object> properties = new HashMap<>();
|
||||
|
||||
new CassandraBindingsPropertiesProcessor().process(new Bindings(
|
||||
new Binding("test-name", Paths.get("test-path"),
|
||||
Collections.singletonMap("kind", KIND),
|
||||
new FluentMap()
|
||||
.withEntry("node_ips", "test-node-ips")
|
||||
.withEntry("password", "test-password")
|
||||
.withEntry("port", "test-port")
|
||||
.withEntry("username", "test-username")
|
||||
)
|
||||
), properties);
|
||||
|
||||
assertThat(properties)
|
||||
.containsEntry("spring.data.cassandra.contact-points", "test-node-ips")
|
||||
.containsEntry("spring.data.cassandra.password", "test-password")
|
||||
.containsEntry("spring.data.cassandra.port", "test-port")
|
||||
.containsEntry("spring.data.cassandra.username", "test-username");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,15 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.cnb.boot;
|
||||
|
||||
/**
|
||||
* Logging levels supported by a LoggingSystem.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public enum LogLevel {
|
||||
package org.springframework.cloud.bindings;
|
||||
|
||||
TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF
|
||||
import java.util.HashMap;
|
||||
|
||||
final class FluentMap extends HashMap<String, String> {
|
||||
|
||||
FluentMap withEntry(String key, String value) {
|
||||
put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user