Add ChannelsEndpoint back for introspecting bindings
Bindable picks up 2 new methods to enumerate the binding names, and then it's a simple matter to list all the inputs and outputs and their properties. Fixes gh-149
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.stream.binding;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Marker interface for instances that can bind/unbind groups of inputs and outputs.
|
||||
*
|
||||
@@ -45,4 +47,14 @@ public interface Bindable {
|
||||
*/
|
||||
void unbindOutputs(ChannelBindingService adapter);
|
||||
|
||||
/**
|
||||
* Enumerates all the input binding names.
|
||||
*/
|
||||
Set<String> getInputs();
|
||||
|
||||
/**
|
||||
* Enumerates all the output binding names.
|
||||
*/
|
||||
Set<String> getOutputs();
|
||||
|
||||
}
|
||||
|
||||
@@ -19,12 +19,12 @@ package org.springframework.cloud.stream.binding;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
@@ -102,7 +102,17 @@ public class BindableProxyFactory implements MethodInterceptor, FactoryBean<Obje
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(beanFactory, "Bean factory cannot be empty");
|
||||
Assert.notNull(this.beanFactory, "Bean factory cannot be empty");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getInputs() {
|
||||
return this.inputs.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getOutputs() {
|
||||
return this.outputs.keySet();
|
||||
}
|
||||
|
||||
private void createChannels(Class<?> type) throws Exception {
|
||||
@@ -119,11 +129,11 @@ public class BindableProxyFactory implements MethodInterceptor, FactoryBean<Obje
|
||||
MessageChannel sharedChannel = locateSharedChannel(name);
|
||||
if (sharedChannel == null) {
|
||||
MessageChannel inputChannel = createMessageChannel(inputChannelType);
|
||||
inputs.put(name, new ChannelHolder(inputChannel, true));
|
||||
BindableProxyFactory.this.inputs.put(name, new ChannelHolder(inputChannel, true));
|
||||
}
|
||||
else {
|
||||
if (inputChannelType.isAssignableFrom(sharedChannel.getClass())) {
|
||||
inputs.put(name, new ChannelHolder(sharedChannel, false));
|
||||
BindableProxyFactory.this.inputs.put(name, new ChannelHolder(sharedChannel, false));
|
||||
}
|
||||
else {
|
||||
// handle the special case where the shared channel is of a different nature
|
||||
@@ -137,7 +147,7 @@ public class BindableProxyFactory implements MethodInterceptor, FactoryBean<Obje
|
||||
bridgeSubscribableToPollableChannel(
|
||||
(SubscribableChannel) sharedChannel, inputChannel);
|
||||
}
|
||||
inputs.put(name, new ChannelHolder(inputChannel, false));
|
||||
BindableProxyFactory.this.inputs.put(name, new ChannelHolder(inputChannel, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,11 +160,11 @@ public class BindableProxyFactory implements MethodInterceptor, FactoryBean<Obje
|
||||
MessageChannel sharedChannel = locateSharedChannel(name);
|
||||
if (sharedChannel == null) {
|
||||
MessageChannel outputChannel = createMessageChannel(messageChannelType);
|
||||
outputs.put(name, new ChannelHolder(outputChannel, true));
|
||||
BindableProxyFactory.this.outputs.put(name, new ChannelHolder(outputChannel, true));
|
||||
}
|
||||
else {
|
||||
if (messageChannelType.isAssignableFrom(sharedChannel.getClass())) {
|
||||
outputs.put(name, new ChannelHolder(sharedChannel, false));
|
||||
BindableProxyFactory.this.outputs.put(name, new ChannelHolder(sharedChannel, false));
|
||||
}
|
||||
else {
|
||||
// handle the special case where the shared channel is of a different nature
|
||||
@@ -169,7 +179,7 @@ public class BindableProxyFactory implements MethodInterceptor, FactoryBean<Obje
|
||||
(SubscribableChannel) outputChannel,
|
||||
sharedChannel);
|
||||
}
|
||||
outputs.put(name, new ChannelHolder(outputChannel, false));
|
||||
BindableProxyFactory.this.outputs.put(name, new ChannelHolder(outputChannel, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,11 +188,11 @@ public class BindableProxyFactory implements MethodInterceptor, FactoryBean<Obje
|
||||
}
|
||||
|
||||
private MessageChannel locateSharedChannel(String name) {
|
||||
return sharedChannelRegistry != null ? sharedChannelRegistry.get(getNamespacePrefixedChannelName(name)) : null;
|
||||
return this.sharedChannelRegistry != null ? this.sharedChannelRegistry.get(getNamespacePrefixedChannelName(name)) : null;
|
||||
}
|
||||
|
||||
private String getNamespacePrefixedChannelName(String name) {
|
||||
return channelNamespace + "." + name;
|
||||
return this.channelNamespace + "." + name;
|
||||
}
|
||||
|
||||
private void bridgeSubscribableToPollableChannel(SubscribableChannel sharedChannel,
|
||||
@@ -196,12 +206,12 @@ public class BindableProxyFactory implements MethodInterceptor, FactoryBean<Obje
|
||||
ConsumerEndpointFactoryBean consumerEndpointFactoryBean = new ConsumerEndpointFactoryBean();
|
||||
consumerEndpointFactoryBean.setInputChannel(pollableChannel);
|
||||
PollerMetadata pollerMetadata = new PollerMetadata();
|
||||
pollerMetadata.setTrigger(new PeriodicTrigger(pollableBridgeDefaultFrequency));
|
||||
pollerMetadata.setTrigger(new PeriodicTrigger(this.pollableBridgeDefaultFrequency));
|
||||
consumerEndpointFactoryBean.setPollerMetadata(pollerMetadata);
|
||||
consumerEndpointFactoryBean
|
||||
.setHandler(new MessageChannelBinderSupport.DirectHandler(
|
||||
subscribableChannel));
|
||||
consumerEndpointFactoryBean.setBeanFactory(beanFactory);
|
||||
consumerEndpointFactoryBean.setBeanFactory(this.beanFactory);
|
||||
try {
|
||||
consumerEndpointFactoryBean.afterPropertiesSet();
|
||||
} catch (Exception e) {
|
||||
@@ -243,7 +253,7 @@ public class BindableProxyFactory implements MethodInterceptor, FactoryBean<Obje
|
||||
public synchronized Object getObject() throws Exception {
|
||||
if (this.proxy == null) {
|
||||
createChannels(this.type);
|
||||
ProxyFactory factory = new ProxyFactory(type, this);
|
||||
ProxyFactory factory = new ProxyFactory(this.type, this);
|
||||
this.proxy = factory.getProxy();
|
||||
}
|
||||
return this.proxy;
|
||||
@@ -264,7 +274,7 @@ public class BindableProxyFactory implements MethodInterceptor, FactoryBean<Obje
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("Binding inputs for %s:%s", this.channelNamespace, this.type));
|
||||
}
|
||||
for (Map.Entry<String, ChannelHolder> channelHolderEntry : inputs.entrySet()) {
|
||||
for (Map.Entry<String, ChannelHolder> channelHolderEntry : this.inputs.entrySet()) {
|
||||
String inputChannelName = channelHolderEntry.getKey();
|
||||
ChannelHolder channelHolder = channelHolderEntry.getValue();
|
||||
channelBindingService.configureMessageConverters(channelHolder.getMessageChannel(), inputChannelName);
|
||||
@@ -282,7 +292,7 @@ public class BindableProxyFactory implements MethodInterceptor, FactoryBean<Obje
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("Binding outputs for %s:%s", this.channelNamespace, this.type));
|
||||
}
|
||||
for (Map.Entry<String, ChannelHolder> channelHolderEntry : outputs.entrySet()) {
|
||||
for (Map.Entry<String, ChannelHolder> channelHolderEntry : this.outputs.entrySet()) {
|
||||
ChannelHolder channelHolder = channelHolderEntry.getValue();
|
||||
String outputChannelName = channelHolderEntry.getKey();
|
||||
channelBindingService.configureMessageConverters(channelHolder.getMessageChannel(), outputChannelName);
|
||||
@@ -300,7 +310,7 @@ public class BindableProxyFactory implements MethodInterceptor, FactoryBean<Obje
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("Unbinding inputs for %s:%s", this.channelNamespace, this.type));
|
||||
}
|
||||
for (Map.Entry<String, ChannelHolder> channelHolderEntry : inputs.entrySet()) {
|
||||
for (Map.Entry<String, ChannelHolder> channelHolderEntry : this.inputs.entrySet()) {
|
||||
if (channelHolderEntry.getValue().isBindable()) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("Unbinding %s:%s:%s", this.channelNamespace, this.type, channelHolderEntry.getKey()));
|
||||
@@ -315,7 +325,7 @@ public class BindableProxyFactory implements MethodInterceptor, FactoryBean<Obje
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("Unbinding outputs for %s:%s", this.channelNamespace, this.type));
|
||||
}
|
||||
for (Map.Entry<String, ChannelHolder> channelHolderEntry : outputs.entrySet()) {
|
||||
for (Map.Entry<String, ChannelHolder> channelHolderEntry : this.outputs.entrySet()) {
|
||||
if (channelHolderEntry.getValue().isBindable()) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("Binding %s:%s:%s", this.channelNamespace, this.type, channelHolderEntry.getKey()));
|
||||
@@ -342,11 +352,11 @@ public class BindableProxyFactory implements MethodInterceptor, FactoryBean<Obje
|
||||
}
|
||||
|
||||
public MessageChannel getMessageChannel() {
|
||||
return messageChannel;
|
||||
return this.messageChannel;
|
||||
}
|
||||
|
||||
public boolean isBindable() {
|
||||
return bindable;
|
||||
return this.bindable;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,16 @@
|
||||
|
||||
package org.springframework.cloud.stream.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
|
||||
/**
|
||||
* Contains the properties of a binding.
|
||||
*
|
||||
* @author Marius Bogoevici
|
||||
* @author Ilayaperumal Gopinathan
|
||||
*/
|
||||
@JsonInclude(value = Include.NON_DEFAULT)
|
||||
public class BindingProperties {
|
||||
|
||||
private String destination;
|
||||
@@ -41,7 +45,7 @@ public class BindingProperties {
|
||||
private String contentType;
|
||||
|
||||
public String getDestination() {
|
||||
return destination;
|
||||
return this.destination;
|
||||
}
|
||||
|
||||
public void setDestination(String destination) {
|
||||
@@ -49,7 +53,7 @@ public class BindingProperties {
|
||||
}
|
||||
|
||||
public boolean isPartitioned() {
|
||||
return partitioned;
|
||||
return this.partitioned;
|
||||
}
|
||||
|
||||
public void setPartitioned(boolean partitioned) {
|
||||
@@ -57,7 +61,7 @@ public class BindingProperties {
|
||||
}
|
||||
|
||||
public int getPartitionCount() {
|
||||
return partitionCount;
|
||||
return this.partitionCount;
|
||||
}
|
||||
|
||||
public void setPartitionCount(int partitionCount) {
|
||||
@@ -65,7 +69,7 @@ public class BindingProperties {
|
||||
}
|
||||
|
||||
public String getPartitionKeyExpression() {
|
||||
return partitionKeyExpression;
|
||||
return this.partitionKeyExpression;
|
||||
}
|
||||
|
||||
public void setPartitionKeyExpression(String partitionKeyExpression) {
|
||||
@@ -73,7 +77,7 @@ public class BindingProperties {
|
||||
}
|
||||
|
||||
public String getPartitionKeyExtractorClass() {
|
||||
return partitionKeyExtractorClass;
|
||||
return this.partitionKeyExtractorClass;
|
||||
}
|
||||
|
||||
public void setPartitionKeyExtractorClass(String partitionKeyExtractorClass) {
|
||||
@@ -81,7 +85,7 @@ public class BindingProperties {
|
||||
}
|
||||
|
||||
public String getPartitionSelectorClass() {
|
||||
return partitionSelectorClass;
|
||||
return this.partitionSelectorClass;
|
||||
}
|
||||
|
||||
public void setPartitionSelectorClass(String partitionSelectorClass) {
|
||||
@@ -89,7 +93,7 @@ public class BindingProperties {
|
||||
}
|
||||
|
||||
public String getPartitionSelectorExpression() {
|
||||
return partitionSelectorExpression;
|
||||
return this.partitionSelectorExpression;
|
||||
}
|
||||
|
||||
public void setPartitionSelectorExpression(String partitionSelectorExpression) {
|
||||
|
||||
@@ -16,11 +16,15 @@
|
||||
|
||||
package org.springframework.cloud.stream.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.stream.binding.Bindable;
|
||||
import org.springframework.cloud.stream.binding.ChannelBindingService;
|
||||
import org.springframework.cloud.stream.endpoint.ChannelsEndpoint;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.scheduling.PollerMetadata;
|
||||
@@ -46,4 +50,10 @@ public class ChannelBindingAutoConfiguration {
|
||||
return this.poller.getPollerMetadata();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Autowired(required=false)
|
||||
public ChannelsEndpoint channelsEndpoint(List<Bindable> adapters, ChannelBindingServiceProperties properties) {
|
||||
return new ChannelsEndpoint(adapters, properties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2015 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.endpoint;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
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;
|
||||
import org.springframework.cloud.stream.endpoint.ChannelsEndpoint.ChannelsMetaData;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@RestController
|
||||
public class ChannelsEndpoint extends AbstractEndpoint<ChannelsMetaData> {
|
||||
|
||||
private List<Bindable> adapters;
|
||||
|
||||
private ChannelBindingServiceProperties properties;
|
||||
|
||||
public ChannelsEndpoint(List<Bindable> adapters,
|
||||
ChannelBindingServiceProperties properties) {
|
||||
super("channels");
|
||||
this.adapters = adapters;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelsMetaData 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());
|
||||
}
|
||||
for (String name : factory.getOutputs()) {
|
||||
outputs.put(name, bindings.containsKey(name) ? bindings.get(name)
|
||||
: new BindingProperties());
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@JsonInclude(value = Include.NON_DEFAULT)
|
||||
public static class ChannelsMetaData {
|
||||
private Map<String, BindingProperties> inputs = new LinkedHashMap<>();
|
||||
private Map<String, BindingProperties> outputs = new LinkedHashMap<>();
|
||||
|
||||
public Map<String, BindingProperties> getInputs() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user