Minimizing class loading in parsers and using the parser context error handling capabilities rather than throwing Exceptions or using assertions. This facilitates proper tooling support (INT-114).

This commit is contained in:
Mark Fisher
2008-12-11 20:23:15 +00:00
parent 898762c2a3
commit 38edabe807
7 changed files with 63 additions and 50 deletions

View File

@@ -16,11 +16,9 @@
package org.springframework.integration.jms.config;
import javax.jms.Session;
import org.w3c.dom.Element;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
/**
@@ -28,7 +26,7 @@ import org.springframework.util.StringUtils;
*
* @author Mark Fisher
*/
public abstract class JmsAdapterParserUtils {
abstract class JmsAdapterParserUtils {
static final String JMS_TEMPLATE_ATTRIBUTE = "jms-template";
@@ -50,35 +48,48 @@ public abstract class JmsAdapterParserUtils {
static final String HEADER_MAPPER_PROPERTY = "headerMapper";
/*
* The following constants match those of javax.jms.Session.
* They are duplicated here to avoid a dependency in tooling.
*/
public static String determineConnectionFactoryBeanName(Element element) {
static final int SESSION_TRANSACTED = 0;
private static final int AUTO_ACKNOWLEDGE = 1;
private static final int CLIENT_ACKNOWLEDGE = 2;
private static final int DUPS_OK_ACKNOWLEDGE = 3;
static String determineConnectionFactoryBeanName(Element element, ParserContext parserContext) {
String connectionFactoryBeanName = "connectionFactory";
if (element.hasAttribute(CONNECTION_FACTORY_ATTRIBUTE)) {
connectionFactoryBeanName = element.getAttribute(CONNECTION_FACTORY_ATTRIBUTE);
if (!StringUtils.hasText(connectionFactoryBeanName)) {
throw new BeanCreationException(
"JMS adapter 'connection-factory' attribute must not be empty");
parserContext.getReaderContext().error(
"JMS adapter 'connection-factory' attribute must not be empty", element);
}
}
return connectionFactoryBeanName;
}
public static Integer parseAcknowledgeMode(Element element) {
static Integer parseAcknowledgeMode(Element element, ParserContext parserContext) {
String acknowledge = element.getAttribute("acknowledge");
if (StringUtils.hasText(acknowledge)) {
int acknowledgeMode = Session.AUTO_ACKNOWLEDGE;
int acknowledgeMode = AUTO_ACKNOWLEDGE;
if ("transacted".equals(acknowledge)) {
acknowledgeMode = Session.SESSION_TRANSACTED;
acknowledgeMode = SESSION_TRANSACTED;
}
else if ("dups-ok".equals(acknowledge)) {
acknowledgeMode = Session.DUPS_OK_ACKNOWLEDGE;
acknowledgeMode = DUPS_OK_ACKNOWLEDGE;
}
else if ("client".equals(acknowledge)) {
acknowledgeMode = Session.CLIENT_ACKNOWLEDGE;
acknowledgeMode = CLIENT_ACKNOWLEDGE;
}
else if (!"auto".equals(acknowledge)) {
throw new BeanCreationException("Invalid JMS 'acknowledge' setting: " +
"only \"auto\", \"client\", \"dups-ok\" and \"transacted\" supported.");
parserContext.getReaderContext().error("Invalid JMS 'acknowledge' setting: " +
"only \"auto\", \"client\", \"dups-ok\" and \"transacted\" supported.", element);
}
return acknowledgeMode;
}

View File

@@ -24,7 +24,6 @@ import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.jms.JmsDestinationPollingSource;
import org.springframework.util.StringUtils;
/**
@@ -44,7 +43,8 @@ public class JmsInboundChannelAdapterParser extends AbstractPollingInboundChanne
@Override
protected String parseSource(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(JmsDestinationPollingSource.class);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
"org.springframework.integration.jms.JmsDestinationPollingSource");
String jmsTemplate = element.getAttribute(JmsAdapterParserUtils.JMS_TEMPLATE_ATTRIBUTE);
String destination = element.getAttribute(JmsAdapterParserUtils.DESTINATION_ATTRIBUTE);
String destinationName = element.getAttribute(JmsAdapterParserUtils.DESTINATION_NAME_ATTRIBUTE);
@@ -62,7 +62,7 @@ public class JmsInboundChannelAdapterParser extends AbstractPollingInboundChanne
builder.addConstructorArgReference(jmsTemplate);
}
else if (StringUtils.hasText(destination) || StringUtils.hasText(destinationName)) {
builder.addConstructorArgReference(JmsAdapterParserUtils.determineConnectionFactoryBeanName(element));
builder.addConstructorArgReference(JmsAdapterParserUtils.determineConnectionFactoryBeanName(element, parserContext));
if (StringUtils.hasText(destination)) {
builder.addConstructorArgReference(destination);
}

View File

@@ -16,8 +16,6 @@
package org.springframework.integration.jms.config;
import javax.jms.Session;
import org.w3c.dom.Element;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@@ -25,10 +23,6 @@ import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.jms.ChannelPublishingJmsMessageListener;
import org.springframework.integration.jms.JmsMessageDrivenEndpoint;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
@@ -58,8 +52,8 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
@Override
protected Class<?> getBeanClass(Element element) {
return JmsMessageDrivenEndpoint.class;
protected String getBeanClassName(Element element) {
return "org.springframework.integration.jms.JmsMessageDrivenEndpoint";
}
@Override
@@ -84,30 +78,35 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
private String parseMessageListenerContainer(Element element, ParserContext parserContext) {
if (element.hasAttribute("container")) {
for (String containerAttribute : containerAttributes) {
Assert.isTrue(!element.hasAttribute(containerAttribute), "The '" + containerAttribute +
"' attribute should not be provided when specifying a 'container' reference.");
if (element.hasAttribute(containerAttribute)) {
parserContext.getReaderContext().error("The '" + containerAttribute +
"' attribute should not be provided when specifying a 'container' reference.", element);
}
}
return element.getAttribute("container");
}
// otherwise, we build a DefaultMessageListenerContainer instance
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(DefaultMessageListenerContainer.class);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
"org.springframework.jms.listener.DefaultMessageListenerContainer");
String destinationAttribute = this.expectReply ? "request-destination" : "destination";
String destinationNameAttribute = this.expectReply ? "request-destination-name" : "destination-name";
String destination = element.getAttribute(destinationAttribute);
String destinationName = element.getAttribute(destinationNameAttribute);
Assert.isTrue(StringUtils.hasText(destination) ^ StringUtils.hasText(destinationName),
"Exactly one of '" + destinationAttribute + "' or '" + destinationNameAttribute + "' is required.");
if (!(StringUtils.hasText(destination) ^ StringUtils.hasText(destinationName))) {
parserContext.getReaderContext().error(
"Exactly one of '" + destinationAttribute + "' or '" + destinationNameAttribute + "' is required.", element);
}
builder.addPropertyReference(JmsAdapterParserUtils.CONNECTION_FACTORY_PROPERTY,
JmsAdapterParserUtils.determineConnectionFactoryBeanName(element));
JmsAdapterParserUtils.determineConnectionFactoryBeanName(element, parserContext));
if (StringUtils.hasText(destination)) {
builder.addPropertyReference("destination", destination);
}
else {
builder.addPropertyValue("destinationName", destinationName);
}
Integer acknowledgeMode = JmsAdapterParserUtils.parseAcknowledgeMode(element);
Integer acknowledgeMode = JmsAdapterParserUtils.parseAcknowledgeMode(element, parserContext);
if (acknowledgeMode != null) {
if (acknowledgeMode.intValue() == Session.SESSION_TRANSACTED) {
if (acknowledgeMode.intValue() == JmsAdapterParserUtils.SESSION_TRANSACTED) {
builder.addPropertyValue("sessionTransacted", Boolean.TRUE);
}
else {
@@ -126,7 +125,8 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
}
private String parseMessageListener(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ChannelPublishingJmsMessageListener.class);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
"org.springframework.integration.jms.ChannelPublishingJmsMessageListener");
builder.addPropertyValue("expectReply", this.expectReply);
if (this.expectReply) {
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "request-channel");

View File

@@ -24,7 +24,6 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.jms.JmsSendingMessageHandler;
import org.springframework.util.StringUtils;
/**
@@ -36,7 +35,8 @@ public class JmsOutboundChannelAdapterParser extends AbstractOutboundChannelAdap
@Override
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(JmsSendingMessageHandler.class);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
"org.springframework.integration.jms.JmsSendingMessageHandler");
String jmsTemplate = element.getAttribute(JmsAdapterParserUtils.JMS_TEMPLATE_ATTRIBUTE);
String destination = element.getAttribute(JmsAdapterParserUtils.DESTINATION_ATTRIBUTE);
String destinationName = element.getAttribute(JmsAdapterParserUtils.DESTINATION_NAME_ATTRIBUTE);
@@ -52,7 +52,7 @@ public class JmsOutboundChannelAdapterParser extends AbstractOutboundChannelAdap
}
else if (StringUtils.hasText(destination) ^ StringUtils.hasText(destinationName)) {
builder.addPropertyReference(JmsAdapterParserUtils.CONNECTION_FACTORY_PROPERTY,
JmsAdapterParserUtils.determineConnectionFactoryBeanName(element));
JmsAdapterParserUtils.determineConnectionFactoryBeanName(element, parserContext));
if (StringUtils.hasText(destination)) {
builder.addPropertyReference(JmsAdapterParserUtils.DESTINATION_PROPERTY, destination);
}

View File

@@ -22,8 +22,6 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractConsumerEndpointParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.jms.JmsOutboundGateway;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
@@ -40,12 +38,15 @@ public class JmsOutboundGatewayParser extends AbstractConsumerEndpointParser {
@Override
protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(JmsOutboundGateway.class);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
"org.springframework.integration.jms.JmsOutboundGateway");
builder.addPropertyReference("connectionFactory", element.getAttribute("connection-factory"));
String requestDestination = element.getAttribute("request-destination");
String requestDestinationName = element.getAttribute("request-destination-name");
Assert.isTrue(StringUtils.hasText(requestDestination) ^ StringUtils.hasText(requestDestinationName),
"Exactly one of the 'request-destination' or 'request-destination-name' attributes is required.");
if (!(StringUtils.hasText(requestDestination) ^ StringUtils.hasText(requestDestinationName))) {
parserContext.getReaderContext().error(
"Exactly one of the 'request-destination' or 'request-destination-name' attributes is required.", element);
}
if (StringUtils.hasText(requestDestination)) {
builder.addPropertyReference("requestDestination", requestDestination);
}

View File

@@ -19,11 +19,11 @@ package org.springframework.integration.jms.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.channel.PollableChannel;
@@ -134,8 +134,9 @@ public class JmsInboundGatewayParserTests {
try {
new ClassPathXmlApplicationContext("jmsGatewayWithConnectionFactoryOnly.xml", this.getClass());
}
catch (RuntimeException e) {
assertEquals(IllegalArgumentException.class, e.getCause().getClass());
catch (BeanDefinitionStoreException e) {
assertTrue(e.getMessage().contains("request-destination"));
assertTrue(e.getMessage().contains("request-destination-name"));
throw e;
}
}
@@ -145,8 +146,8 @@ public class JmsInboundGatewayParserTests {
try {
new ClassPathXmlApplicationContext("jmsGatewayWithEmptyConnectionFactory.xml", this.getClass());
}
catch (RuntimeException e) {
assertEquals(BeanCreationException.class, e.getCause().getClass());
catch (BeanDefinitionStoreException e) {
assertTrue(e.getMessage().contains("connection-factory"));
throw e;
}
}

View File

@@ -18,11 +18,11 @@ package org.springframework.integration.jms.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.endpoint.EventDrivenConsumer;
@@ -80,8 +80,8 @@ public class JmsOutboundChannelAdapterParserTests {
try {
new ClassPathXmlApplicationContext("jmsOutboundWithEmptyConnectionFactory.xml", this.getClass());
}
catch (RuntimeException e) {
assertEquals(BeanCreationException.class, e.getCause().getClass());
catch (BeanDefinitionStoreException e) {
assertTrue(e.getMessage().contains("connection-factory"));
throw e;
}
}