ChannelsEndpoint to show all the binding properties

- Set the default destination name when it is not explicitly set
 - The producer/consumer properties would also be shown via BindingProperties
  - Handle JSON serialization when the value is of type Expression

This resolves #406 #426
This commit is contained in:
Ilayaperumal Gopinathan
2016-03-07 13:52:58 +05:30
committed by Marius Bogoevici
parent 853e340a35
commit f390feb42b
6 changed files with 79 additions and 41 deletions

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2016 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.stream.binder;
import java.io.IOException;
import org.springframework.expression.Expression;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
/**
* JSON serializer for Expression value.
*
* @author Ilayaperumal Gopinathan
*/
public class ExpressionSerializer extends JsonSerializer<Expression> {
public ExpressionSerializer() {
}
@Override
public void serialize(Expression expression, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
if (expression != null) {
jsonGenerator.writeString(expression.getExpressionString());
}
}
}

View File

@@ -18,6 +18,8 @@ package org.springframework.cloud.stream.binder;
import org.springframework.expression.Expression;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
/**
* Common producer properties.
*
@@ -25,12 +27,14 @@ import org.springframework.expression.Expression;
*/
public class ProducerProperties {
@JsonSerialize(using = ExpressionSerializer.class)
private Expression partitionKeyExpression = null;
private Class<?> partitionKeyExtractorClass = null;
private Class<?> partitionSelectorClass = null;
@JsonSerialize(using = ExpressionSerializer.class)
private Expression partitionSelectorExpression = null;
private int partitionCount = 1;

View File

@@ -32,7 +32,7 @@ import org.springframework.cloud.stream.binder.Binding;
public final class DynamicDestinationsBindable extends BindableAdapter {
/**
* Map containing dynamic destination names and their bindings.
* Map containing channel names and their bindings.
*/
private Map<String, Binding> outputBindings = new HashMap<>();

View File

@@ -18,13 +18,13 @@ package org.springframework.cloud.stream.config;
import javax.validation.constraints.AssertTrue;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import org.springframework.cloud.stream.binder.ConsumerProperties;
import org.springframework.cloud.stream.binder.ProducerProperties;
import org.springframework.validation.annotation.Validated;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
/**
* Contains the properties of a binding.
* @author Marius Bogoevici
@@ -56,7 +56,6 @@ public class BindingProperties {
private String binder;
private ConsumerProperties consumer = null;
private ProducerProperties producer = null;

View File

@@ -21,9 +21,7 @@ import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
@@ -36,7 +34,9 @@ import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.convert.ConversionService;
import org.springframework.integration.support.utils.IntegrationUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
/**
* @author Dave Syer
@@ -189,7 +189,6 @@ public class ChannelBindingServiceProperties implements ApplicationContextAware,
return consumerProperties;
}
public ProducerProperties getProducerProperties(String outputChannelName) {
Assert.notNull(outputChannelName, "The output channel name cannot be null");
ProducerProperties producerProperties = getBindingProperties(outputChannelName).getProducer();
@@ -200,8 +199,13 @@ public class ChannelBindingServiceProperties implements ApplicationContextAware,
}
public BindingProperties getBindingProperties(String channelName) {
BindingProperties bindingProperties = bindings.containsKey(channelName) ?
bindings.get(channelName) : new BindingProperties();
BindingProperties bindingProperties = new BindingProperties();
if (this.bindings.containsKey(channelName)) {
BeanUtils.copyProperties(this.bindings.get(channelName), bindingProperties);
}
if (bindingProperties.getDestination() == null) {
bindingProperties.setDestination(channelName);
}
return bindingProperties;
}
@@ -210,10 +214,6 @@ public class ChannelBindingServiceProperties implements ApplicationContextAware,
}
public String getBindingDestination(String channelName) {
BindingProperties bindingProperties = getBindingProperties(channelName);
if (bindingProperties != null && StringUtils.hasText(bindingProperties.getDestination())) {
return bindingProperties.getDestination();
}
return channelName;
return getBindingProperties(channelName).getDestination();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-2016 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.
@@ -20,49 +20,49 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.cloud.stream.binding.Bindable;
import org.springframework.cloud.stream.config.BindingProperties;
import org.springframework.cloud.stream.config.ChannelBindingServiceProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
import org.springframework.cloud.stream.binding.Bindable;
import org.springframework.cloud.stream.config.BindingProperties;
import org.springframework.cloud.stream.config.ChannelBindingServiceProperties;
/**
* An {@link Endpoint} that has the binding information on all the {@link Bindable} message channels.
*
* @author Dave Syer
* @author Ilayaperumal Gopinathan
*/
public class ChannelsEndpoint extends AbstractEndpoint<Map<String,Object>> {
public class ChannelsEndpoint extends AbstractEndpoint<Map<String, Object>> {
private List<Bindable> adapters;
private ChannelBindingServiceProperties properties;
public ChannelsEndpoint(List<Bindable> adapters,
ChannelBindingServiceProperties properties) {
public ChannelsEndpoint(List<Bindable> adapters, ChannelBindingServiceProperties properties) {
super("channels");
this.adapters = adapters;
this.properties = properties;
}
@Override
public Map<String,Object> invoke() {
public Map<String, Object> invoke() {
ChannelsMetaData map = new ChannelsMetaData();
Map<String, BindingProperties> inputs = map.getInputs();
Map<String, BindingProperties> outputs = map.getOutputs();
for (Bindable factory : this.adapters) {
Map<String, BindingProperties> bindings = this.properties.getBindings();
for (String name : factory.getInputs()) {
inputs.put(name, bindings.containsKey(name) ? bindings.get(name)
: new BindingProperties());
inputs.put(name, this.properties.getBindingProperties(name));
}
for (String name : factory.getOutputs()) {
outputs.put(name, bindings.containsKey(name) ? bindings.get(name)
: new BindingProperties());
outputs.put(name, this.properties.getBindingProperties(name));
}
}
return new ObjectMapper().convertValue(map, new TypeReference<Map<String,Object>>() {
return new ObjectMapper().convertValue(map, new TypeReference<Map<String, Object>>() {
});
}
@@ -77,17 +77,9 @@ public class ChannelsEndpoint extends AbstractEndpoint<Map<String,Object>> {
return this.inputs;
}
public void setInputs(Map<String, BindingProperties> inputs) {
this.inputs = inputs;
}
public Map<String, BindingProperties> getOutputs() {
return this.outputs;
}
public void setOutputs(Map<String, BindingProperties> outputs) {
this.outputs = outputs;
}
}
}