From 1847eaa194eaaa7ac5639a5ea30e1631aa68fab4 Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Thu, 15 Aug 2013 14:28:18 -0400 Subject: [PATCH] INT-3110 Fix JMX Control Bus With SF 3.2.3 Spring 3.2.3 registers MBean operations with parameter names instead of the JVM default p1, p2 etc based on parameter position in the method signature. Since the OperationInvokingMessageHandler matched the supplied arguments using the p1, p2 etc names, this prevented the control bus from finding the target method. Fall back to the old naming scheme based on parameter position if a matching parameter is not found. Add a test using a Map payload to supply the named arguments (p1, p2). Add an ignored test that tests using named arguments (key, channelName). Test with 3.1.4; remove Ignore and test with 3.2.3. TODO: remove the Ignore annotation when SF 3.2.3 is the minimum. --- .../jmx/OperationInvokingMessageHandler.java | 11 +++- .../OperationInvokingMessageHandlerTests.java | 13 ++-- .../jmx/config/DynamicRouterTests.java | 60 +++++++++++++++---- 3 files changed, 68 insertions(+), 16 deletions(-) diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/OperationInvokingMessageHandler.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/OperationInvokingMessageHandler.java index 5a47131102..7b2232c304 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/OperationInvokingMessageHandler.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/OperationInvokingMessageHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2013 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. @@ -58,6 +58,7 @@ import org.springframework.util.ObjectUtils; * * @author Mark Fisher * @author Oleg Zhurakousky + * @author Gary Russell * @since 2.0 */ public class OperationInvokingMessageHandler extends AbstractReplyProducingMessageHandler implements InitializingBean { @@ -127,6 +128,14 @@ public class OperationInvokingMessageHandler extends AbstractReplyProducingMessa String signature[] = new String[paramInfoArray.length]; for (MBeanParameterInfo paramInfo : paramInfoArray) { Object value = paramsFromMessage.get(paramInfo.getName()); + if (value == null) { + /* + * With Spring 3.2.3 and greater, the parameter names are + * registered instead of the JVM's default p1, p2 etc. + * Fall back to that naming style if not found. + */ + value = paramsFromMessage.get("p" + (index + 1)); + } if (value != null && value.getClass().getName().equals(paramInfo.getType())) { values[index] = value; signature[index] = paramInfo.getType(); diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/OperationInvokingMessageHandlerTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/OperationInvokingMessageHandlerTests.java index efcbbbd0a0..0b37d8b0ff 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/OperationInvokingMessageHandlerTests.java +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/OperationInvokingMessageHandlerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2013 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. @@ -33,11 +33,14 @@ import org.junit.Test; import org.springframework.integration.Message; import org.springframework.integration.MessagingException; import org.springframework.integration.channel.QueueChannel; +import org.springframework.integration.jmx.config.DynamicRouterTests; import org.springframework.integration.support.MessageBuilder; import org.springframework.jmx.support.MBeanServerFactoryBean; import org.springframework.jmx.support.ObjectNameManager; /** + * See DynamicRouterTests for additional tests where the MBean is registered by the Spring exporter. + * @see DynamicRouterTests * @author Mark Fisher * @author Oleg Zhurakousky * @since 2.0 @@ -82,7 +85,7 @@ public class OperationInvokingMessageHandlerTests { assertNotNull(reply); assertEquals("foobar", reply.getPayload()); } - + @Test public void invocationWithPayloadNoReturnValue() throws Exception { QueueChannel outputChannel = new QueueChannel(); @@ -95,7 +98,7 @@ public class OperationInvokingMessageHandlerTests { Message message = MessageBuilder.withPayload("foo").build(); handler.handleMessage(message); } - + @Test(expected=MessagingException.class) public void invocationWithMapPayloadNotEnoughParameters() throws Exception { QueueChannel outputChannel = new QueueChannel(); @@ -136,7 +139,7 @@ public class OperationInvokingMessageHandlerTests { String x(String s1, String s2); String x(String s, Integer i); - + void y(String s); } @@ -150,7 +153,7 @@ public class OperationInvokingMessageHandlerTests { public String x(String s, Integer i) { return s + i; } - + public void y(String s){} } diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/DynamicRouterTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/DynamicRouterTests.java index 4df7c4ece6..ac565a96c0 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/DynamicRouterTests.java +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/DynamicRouterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2013 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. @@ -18,19 +18,26 @@ package org.springframework.integration.jmx.config; import static org.junit.Assert.assertEquals; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.integration.MessageChannel; import org.springframework.integration.channel.QueueChannel; import org.springframework.integration.message.GenericMessage; import org.springframework.integration.support.MessageBuilder; +import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author Oleg Zhurakousky + * @author Gary Russell * */ @ContextConfiguration @@ -40,35 +47,68 @@ public class DynamicRouterTests { @Autowired @Qualifier("controlChannel") private MessageChannel controlChannel; - + @Autowired @Qualifier("routingChannel") private MessageChannel routingChannel; - + @Autowired @Qualifier("processAChannel") private QueueChannel processAChannel; - + @Autowired @Qualifier("processBChannel") private QueueChannel processBChannel; - + @Autowired @Qualifier("processCChannel") private QueueChannel processCChannel; - @Test + @Test @DirtiesContext public void testRouteChange() throws Exception { routingChannel.send(new GenericMessage("123")); - assertEquals("123", processAChannel.receive().getPayload()); + assertEquals("123", processAChannel.receive(0).getPayload()); routingChannel.send(MessageBuilder.withPayload(123).build()); - assertEquals(123, processBChannel.receive().getPayload()); + assertEquals(123, processBChannel.receive(0).getPayload()); controlChannel.send(MessageBuilder.withPayload(new String[]{"java.lang.String", "processCChannel"}).build()); - + routingChannel.send(new GenericMessage("123")); - assertEquals("123", processCChannel.receive().getPayload()); + assertEquals("123", processCChannel.receive(0).getPayload()); + } + + @Test @DirtiesContext + public void testRouteChangeMap() throws Exception { + routingChannel.send(new GenericMessage("123")); + assertEquals("123", processAChannel.receive(0).getPayload()); + routingChannel.send(MessageBuilder.withPayload(123).build()); + assertEquals(123, processBChannel.receive(0).getPayload()); + Map args = new HashMap(); + args.put("p1", "java.lang.String"); + args.put("p2", "processCChannel"); + + controlChannel.send(MessageBuilder.withPayload(args).build()); + + routingChannel.send(new GenericMessage("123")); + assertEquals("123", processCChannel.receive(0).getPayload()); + } + + @Test @DirtiesContext + @Ignore // Requires Spring 3.2.3 TODO: Remove when minimum SF is >= 3.2.3 + public void testRouteChangeMapNamedArgs() throws Exception { + routingChannel.send(new GenericMessage("123")); + assertEquals("123", processAChannel.receive(0).getPayload()); + routingChannel.send(MessageBuilder.withPayload(123).build()); + assertEquals(123, processBChannel.receive(0).getPayload()); + Map args = new HashMap(); + args.put("key", "java.lang.String"); + args.put("channelName", "processCChannel"); + + controlChannel.send(MessageBuilder.withPayload(args).build()); + + routingChannel.send(new GenericMessage("123")); + assertEquals("123", processCChannel.receive(0).getPayload()); } }