Added integration for JMS

fixes gh-1141
This commit is contained in:
Marcin Grzejszczak
2019-09-09 14:22:02 +02:00
parent 530fdee87f
commit c7b4f0125b
33 changed files with 1941 additions and 15 deletions

View File

@@ -30,12 +30,10 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
import org.springframework.stereotype.Component;
/**
* @author Marcin Grzejszczak
*/
@Component
public class CamelStubMessages implements MessageVerifier<Message> {
private static final Logger log = LoggerFactory.getLogger(CamelStubMessages.class);

View File

@@ -27,6 +27,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage;
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging;
import org.springframework.cloud.contract.verifier.messaging.jms.ContractVerifierJmsConfiguration;
import org.springframework.cloud.contract.verifier.messaging.noop.NoOpContractVerifierAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -38,9 +39,9 @@ import org.springframework.context.annotation.Import;
@Configuration
@ConditionalOnClass(Message.class)
@Import(CamelAutoConfiguration.class)
@ConditionalOnProperty(name = "stubrunner.camel.enabled", havingValue = "true",
matchIfMissing = true)
@AutoConfigureBefore(NoOpContractVerifierAutoConfiguration.class)
@ConditionalOnProperty(name = "stubrunner.camel.enabled", havingValue = "true", matchIfMissing = true)
@AutoConfigureBefore({ NoOpContractVerifierAutoConfiguration.class,
ContractVerifierJmsConfiguration.class })
public class ContractVerifierCamelConfiguration {
@Bean

View File

@@ -0,0 +1,123 @@
/*
* Copyright 2013-2019 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
*
* https://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.contract.verifier.messaging.jms;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.StreamMessage;
import javax.jms.TextMessage;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessage;
import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging;
import org.springframework.cloud.contract.verifier.messaging.noop.NoOpContractVerifierAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.core.JmsTemplate;
/**
* @author Marcin Grzejszczak
*/
@Configuration
@ConditionalOnClass(JmsTemplate.class)
@ConditionalOnProperty(name = "stubrunner.jms.enabled", havingValue = "true",
matchIfMissing = true)
@AutoConfigureBefore(NoOpContractVerifierAutoConfiguration.class)
public class ContractVerifierJmsConfiguration {
@Bean
@ConditionalOnMissingBean
MessageVerifier<Message> contractVerifierJmsMessageExchange(
ObjectProvider<JmsTemplate> jmsTemplateProvider) {
JmsTemplate jmsTemplate = jmsTemplateProvider.getIfAvailable(JmsTemplate::new);
return new JmsStubMessages(jmsTemplate);
}
@Bean
@ConditionalOnMissingBean
public ContractVerifierMessaging<Message> contractVerifierJmsMessaging(
MessageVerifier<Message> exchange) {
return new ContractVerifierJmsHelper(exchange);
}
}
class ContractVerifierJmsHelper extends ContractVerifierMessaging<Message> {
private static final Log log = LogFactory.getLog(ContractVerifierJmsHelper.class);
ContractVerifierJmsHelper(MessageVerifier<Message> exchange) {
super(exchange);
}
@Override
protected ContractVerifierMessage convert(Message message) {
try {
Map<String, Object> headers = headers(message);
return new ContractVerifierMessage(getPayload(message), headers);
}
catch (JMSException ex) {
log.warn("An exception occurred while trying to convert the JMS message", ex);
throw new IllegalStateException(ex);
}
}
private Map<String, Object> headers(Message message) throws JMSException {
Map<String, Object> headers = new HashMap<>();
if (message == null) {
return headers;
}
Enumeration enumeration = message.getPropertyNames();
while (enumeration.hasMoreElements()) {
Object element = enumeration.nextElement();
String asString = element.toString();
Object property = message.getObjectProperty(asString);
headers.put(asString, property);
}
return headers;
}
private Object getPayload(Message message) throws JMSException {
if (message == null) {
return null;
}
else if (message instanceof TextMessage) {
return ((TextMessage) message).getText();
}
else if (message instanceof StreamMessage) {
return ((StreamMessage) message).readObject();
}
else if (message instanceof ObjectMessage) {
return ((ObjectMessage) message).getObject();
}
return message.getBody(Object.class);
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright 2013-2019 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
*
* https://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.contract.verifier.messaging.jms;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.jms.BytesMessage;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import org.springframework.cloud.contract.verifier.messaging.MessageVerifier;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessagePostProcessor;
class JmsStubMessages implements MessageVerifier<Message> {
private final JmsTemplate jmsTemplate;
JmsStubMessages(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
@Override
public void send(Message message, String destination) {
jmsTemplate.convertAndSend(destination, message, new ReplyToProcessor());
}
@Override
public Message receive(String destination, long timeout, TimeUnit timeUnit) {
jmsTemplate.setReceiveTimeout(timeUnit.toMillis(timeout));
return jmsTemplate.receive(destination);
}
@Override
public Message receive(String destination) {
return receive(destination, 5, TimeUnit.SECONDS);
}
@Override
public void send(Object payload, Map headers, String destination) {
jmsTemplate.send(destination, session -> {
Message message = createMessage(session, payload);
setHeaders(message, headers);
return message;
});
}
private Message createMessage(Session session, Object payload) throws JMSException {
if (payload instanceof String) {
return session.createTextMessage((String) payload);
}
else if (payload instanceof byte[]) {
BytesMessage bytesMessage = session.createBytesMessage();
bytesMessage.writeBytes((byte[]) payload);
return bytesMessage;
}
else if (payload instanceof Serializable) {
return session.createObjectMessage((Serializable) payload);
}
return session.createMessage();
}
private void setHeaders(Message message, Map<String, Object> headers) {
for (Map.Entry<String, Object> entry : headers.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
try {
if (value instanceof String) {
message.setStringProperty(key, (String) value);
}
else if (value instanceof Boolean) {
message.setBooleanProperty(key, (Boolean) value);
}
else {
message.setObjectProperty(key, value);
}
}
catch (JMSException ex) {
throw new IllegalStateException(ex);
}
}
}
}
class ReplyToProcessor implements MessagePostProcessor {
@Override
public Message postProcessMessage(Message message) throws JMSException {
message.setStringProperty("requiresReply", "no");
return message;
}
}

View File

@@ -5,4 +5,5 @@ org.springframework.cloud.contract.verifier.messaging.integration.ContractVerifi
org.springframework.cloud.contract.verifier.messaging.amqp.ContractVerifierAmqpAutoConfiguration,\
org.springframework.cloud.contract.verifier.messaging.amqp.RabbitMockConnectionFactoryAutoConfiguration,\
org.springframework.cloud.contract.verifier.messaging.camel.ContractVerifierCamelConfiguration,\
org.springframework.cloud.contract.verifier.messaging.jms.ContractVerifierJmsConfiguration,\
org.springframework.cloud.contract.verifier.messaging.noop.NoOpContractVerifierAutoConfiguration