Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.springframework.amqp.rabbit.listener.DirectMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
Expand All @@ -39,6 +40,7 @@
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Gary Russell
* @author Artem Bilan
*
* @since 2.1
*/
Expand Down Expand Up @@ -103,7 +105,7 @@ protected void doParse(Element element, ParserContext parserContext, BeanDefinit
builder.addConstructorArgReference(listenerContainerRef);
}
else {
BeanDefinition listenerContainerBeanDef = this.buildListenerContainer(element, parserContext);
BeanDefinition listenerContainerBeanDef = buildListenerContainer(element, parserContext);
builder.addConstructorArgValue(listenerContainerBeanDef);
}
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "message-converter");
Expand All @@ -117,11 +119,12 @@ protected void doParse(Element element, ParserContext parserContext, BeanDefinit
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "error-channel");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-startup");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "phase");
this.configureChannels(element, parserContext, builder);
configureChannels(element, parserContext, builder);
AbstractBeanDefinition adapterBeanDefinition = builder.getRawBeanDefinition();
adapterBeanDefinition.setResource(parserContext.getReaderContext().getResource());
adapterBeanDefinition.setSource(IntegrationNamespaceUtils.createElementDescription(element));
}

protected abstract void configureChannels(Element element, ParserContext parserContext, BeanDefinitionBuilder builder);

private BeanDefinition buildListenerContainer(Element element, ParserContext parserContext) {
if (!element.hasAttribute("queue-names")) {
parserContext.getReaderContext().error("If no 'listener-container' reference is provided, " +
Expand Down Expand Up @@ -163,7 +166,7 @@ private BeanDefinition buildListenerContainer(Element element, ParserContext par

private void assertNoContainerAttributes(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
List<String> allContainerAttributes = new ArrayList<String>(Arrays.asList(CONTAINER_VALUE_ATTRIBUTES));
List<String> allContainerAttributes = new ArrayList<>(Arrays.asList(CONTAINER_VALUE_ATTRIBUTES));
allContainerAttributes.addAll(Arrays.asList(CONTAINER_REFERENCE_ATTRIBUTES));
for (String attributeName : allContainerAttributes) {
if (StringUtils.hasText(element.getAttribute(attributeName))) {
Expand All @@ -173,4 +176,7 @@ private void assertNoContainerAttributes(Element element, ParserContext parserCo
}
}

protected abstract void configureChannels(Element element, ParserContext parserContext,
BeanDefinitionBuilder builder);

}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public abstract class AbstractConsumerEndpointParser extends AbstractBeanDefinit
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
throws BeanDefinitionStoreException {

String id = element.getAttribute(ID_ATTRIBUTE);
if (!StringUtils.hasText(id)) {
id = element.getAttribute("name");
Expand Down Expand Up @@ -103,10 +104,12 @@ protected final AbstractBeanDefinition parseInternal(Element element, ParserCont
}

AbstractBeanDefinition handlerBeanDefinition = handlerBuilder.getBeanDefinition();
String inputChannelAttributeName = this.getInputChannelAttributeName();
handlerBeanDefinition.setResource(parserContext.getReaderContext().getResource());
String elementDescription = IntegrationNamespaceUtils.createElementDescription(element);
handlerBeanDefinition.setSource(elementDescription);
String inputChannelAttributeName = getInputChannelAttributeName();
boolean hasInputChannelAttribute = element.hasAttribute(inputChannelAttributeName);
if (parserContext.isNested()) {
String elementDescription = IntegrationNamespaceUtils.createElementDescription(element);
if (hasInputChannelAttribute) {
parserContext.getReaderContext().error("The '" + inputChannelAttributeName
+ "' attribute isn't allowed for a nested (e.g. inside a <chain/>) endpoint element: "
Expand All @@ -122,7 +125,6 @@ protected final AbstractBeanDefinition parseInternal(Element element, ParserCont
}
else {
if (!hasInputChannelAttribute) {
String elementDescription = IntegrationNamespaceUtils.createElementDescription(element);
parserContext.getReaderContext().error("The '" + inputChannelAttributeName
+ "' attribute is required for the top-level endpoint element: "
+ elementDescription + ".", element);
Expand All @@ -135,9 +137,11 @@ protected final AbstractBeanDefinition parseInternal(Element element, ParserCont
builder.addPropertyValue("adviceChain", adviceChain);
}

String handlerBeanName = BeanDefinitionReaderUtils.generateBeanName(handlerBeanDefinition, parserContext.getRegistry());
String handlerBeanName =
BeanDefinitionReaderUtils.generateBeanName(handlerBeanDefinition, parserContext.getRegistry());
String[] handlerAlias = IntegrationNamespaceUtils.generateAlias(element);
parserContext.registerBeanComponent(new BeanComponentDefinition(handlerBeanDefinition, handlerBeanName, handlerAlias));
parserContext.registerBeanComponent(
new BeanComponentDefinition(handlerBeanDefinition, handlerBeanName, handlerAlias));

builder.addPropertyReference("handler", handlerBeanName);

Expand All @@ -157,7 +161,7 @@ protected final AbstractBeanDefinition parseInternal(Element element, ParserCont
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, IntegrationNamespaceUtils.ROLE);

AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
String beanName = this.resolveId(element, beanDefinition, parserContext);
String beanName = resolveId(element, beanDefinition, parserContext);
parserContext.registerBeanComponent(new BeanComponentDefinition(beanDefinition, beanName));
return null;
}
Expand Down Expand Up @@ -187,12 +191,13 @@ private void registerChannelForCreation(ParserContext parserContext, String inpu

@SuppressWarnings("unchecked")
Collection<String> channelCandidateNames =
(Collection<String>) caValues.getArgumentValue(0, Collection.class).getValue(); // NOSONAR see comment above
(Collection<String>) caValues.getArgumentValue(0, Collection.class)
.getValue(); // NOSONAR see comment above
channelCandidateNames.add(inputChannelName); // NOSONAR
}
else {
parserContext.getReaderContext().error("Failed to locate '" +
IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME + "'",
IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME + "'",
parserContext.getRegistry());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.convert.ConversionService;
Expand Down Expand Up @@ -136,6 +138,32 @@ public String getComponentType() {
return null;
}

public String getBeanDescription() {
String description = null;
Object source = null;

if (this.beanFactory instanceof ConfigurableListableBeanFactory &&
((ConfigurableListableBeanFactory) this.beanFactory).containsBeanDefinition(this.beanName)) {
BeanDefinition beanDefinition =
((ConfigurableListableBeanFactory) this.beanFactory).getBeanDefinition(this.beanName);
description = beanDefinition.getResourceDescription();
source = beanDefinition.getSource();
}

StringBuilder sb = new StringBuilder("bean '")
.append(this.beanName).append("'");
if (!this.beanName.equals(getComponentName())) {
sb.append("for component '").append(getComponentName()).append("'");
}
if (description != null) {
sb.append("; defined in: '").append(description).append("'");
}
if (source != null) {
sb.append("; from source: '").append(source).append("'");
}
return sb.toString();
}

@Override
public void setBeanFactory(BeanFactory beanFactory) {
Assert.notNull(beanFactory, "'beanFactory' must not be null");
Expand Down Expand Up @@ -297,7 +325,7 @@ protected <T> T getIntegrationProperty(String key, Class<T> tClass) {

@Override
public String toString() {
return (this.beanName != null) ? this.beanName : super.toString();
return (this.beanName != null) ? getBeanDescription() : super.toString();
}

@SuppressWarnings("unchecked")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.SmartLifecycle;
import org.springframework.core.io.DescriptiveResource;
import org.springframework.core.type.MethodMetadata;
import org.springframework.integration.channel.AbstractMessageChannel;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.FixedSubscriberChannel;
Expand Down Expand Up @@ -426,16 +427,25 @@ private void registerComponent(Object component, String beanName) {
private void registerComponent(Object component, String beanName, String parentName,
BeanDefinitionCustomizer... customizers) {

BeanDefinition beanDefinition =
AbstractBeanDefinition beanDefinition =
BeanDefinitionBuilder.genericBeanDefinition((Class<Object>) component.getClass(), () -> component)
.applyCustomizers(customizers)
.getRawBeanDefinition();
.applyCustomizers(customizers)
.getRawBeanDefinition();

if (parentName != null && this.beanFactory.containsBeanDefinition(parentName)) {
AbstractBeanDefinition parentBeanDefinition =
(AbstractBeanDefinition) this.beanFactory.getBeanDefinition(parentName);
beanDefinition.setResource(parentBeanDefinition.getResource());
Object source = parentBeanDefinition.getSource();
if (source instanceof MethodMetadata) {
source = "bean method " + ((MethodMetadata) source).getMethodName();
}
beanDefinition.setSource(source);
this.beanFactory.registerDependentBean(parentName, beanName);
}

((BeanDefinitionRegistry) this.beanFactory).registerBeanDefinition(beanName, beanDefinition);

if (parentName != null) {
this.beanFactory.registerDependentBean(parentName, beanName);
}

this.beanFactory.getBean(beanName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,16 @@ interface IntegrationFlowRegistrationBuilder {
*/
IntegrationFlowRegistrationBuilder addBean(String name, Object bean);

/**
* Set the configuration source {@code Object} for this manual Integration flow definition.
* Can be any arbitrary object which could easily lead to a source code for the flow when
* a messaging exception happens at runtime.
* @param source the configuration source representation.
* @return the current builder instance
* @since 5.2
*/
IntegrationFlowRegistrationBuilder setSource(Object source);

/**
* Invoke this method to prefix bean names in the flow with the (required) flow id
* and a period. This is useful if you wish to register the same flow multiple times
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.type.MethodMetadata;
import org.springframework.integration.core.MessagingTemplate;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.support.context.NamedComponent;
Expand Down Expand Up @@ -105,7 +106,7 @@ else if (this.registry.containsKey(flowId)) {
"An existing IntegrationFlowRegistration must be destroyed before overriding.");
}

integrationFlow = (IntegrationFlow) registerBean(integrationFlow, flowId, null);
integrationFlow = registerFlowBean(integrationFlow, flowId, builder.source);
}
finally {
if (registerBeanLock != null) {
Expand All @@ -124,24 +125,38 @@ else if (this.registry.containsKey(flowId)) {
this.registry.put(flowId, builder.integrationFlowRegistration);
}

private IntegrationFlow registerFlowBean(IntegrationFlow flow, String flowId, @Nullable Object source) {
AbstractBeanDefinition beanDefinition =
BeanDefinitionBuilder.genericBeanDefinition(IntegrationFlow.class, () -> flow)
.getRawBeanDefinition();
beanDefinition.setSource(source);
this.beanDefinitionRegistry.registerBeanDefinition(flowId, beanDefinition);
return this.beanFactory.getBean(flowId, IntegrationFlow.class);
}

@SuppressWarnings("unchecked")
private Object registerBean(Object bean, @Nullable String beanNameArg, String parentName) {
private void registerBean(Object bean, @Nullable String beanNameArg, String parentName) {
String beanName = beanNameArg;
if (beanName == null) {
beanName = generateBeanName(bean, parentName);
}

BeanDefinition beanDefinition =
AbstractBeanDefinition beanDefinition =
BeanDefinitionBuilder.genericBeanDefinition((Class<Object>) bean.getClass(), () -> bean)
.getRawBeanDefinition();

this.beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);

if (parentName != null) {
AbstractBeanDefinition parentBeanDefinition =
(AbstractBeanDefinition) this.beanFactory.getBeanDefinition(parentName);
Object source = parentBeanDefinition.getSource();
if (source instanceof MethodMetadata) {
source = "bean method " + ((MethodMetadata) source).getMethodName();
}
beanDefinition.setSource(source);
this.beanFactory.registerDependentBean(parentName, beanName);
}

return this.beanFactory.getBean(beanName);
this.beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
this.beanFactory.getBean(beanName);
}

/**
Expand Down Expand Up @@ -247,6 +262,9 @@ public final class StandardIntegrationFlowRegistrationBuilder implements Integra

private boolean idAsPrefix;

@Nullable
private Object source;

StandardIntegrationFlowRegistrationBuilder(IntegrationFlow integrationFlow) {
this.integrationFlowRegistration = new StandardIntegrationFlowRegistration(integrationFlow);
this.integrationFlowRegistration.setBeanFactory(StandardIntegrationFlowContext.this.beanFactory);
Expand Down Expand Up @@ -306,6 +324,12 @@ public StandardIntegrationFlowRegistrationBuilder addBean(String name, Object be
return this;
}

@Override
public IntegrationFlowRegistrationBuilder setSource(Object source) {
this.source = source;
return this;
}

@Override
public IntegrationFlowRegistrationBuilder useFlowIdAsPrefix() {
this.idAsPrefix = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ public Object postProcess(Message<?> message, Object result) {
this.messagingTemplate.send(channel, message);
}
if (this.throwExceptionOnRejection) {
throw new MessageRejectedException(message, "MessageFilter '" + getBeanName() + "' rejected Message");
throw new MessageRejectedException(message, "message has been rejected in filter: " + this);
}
}
return result;
Expand Down
Loading