diff --git a/alfresco-transformer-base/src/main/java/org/alfresco/transformer/QueueTransformService.java b/alfresco-transformer-base/src/main/java/org/alfresco/transformer/QueueTransformService.java index cc4d546a..df39dc7e 100644 --- a/alfresco-transformer-base/src/main/java/org/alfresco/transformer/QueueTransformService.java +++ b/alfresco-transformer-base/src/main/java/org/alfresco/transformer/QueueTransformService.java @@ -45,12 +45,25 @@ public class QueueTransformService @JmsListener(destination = "${queue.engineRequestQueue}", concurrency = "${jms-listener.concurrency}") public void receive(final Message msg) { + if (msg == null) + { + logger.error("Received null message!"); + return; + } + final String correlationId = tryRetrieveCorrelationId(msg); Destination replyToDestinationQueue; try { replyToDestinationQueue = msg.getJMSReplyTo(); + if (replyToDestinationQueue == null) + { + logger.error( + "Cannot find 'replyTo' destination queue for message with correlationID {}. Stopping. ", + correlationId); + return; + } } catch (JMSException e) { @@ -58,27 +71,46 @@ public class QueueTransformService return; } - logger.info("New T-Request from queue with correlationId: {0}"); + logger.info("New T-Request from queue with correlationId: {0}", correlationId); - TransformReply reply = transformController.transform(convert(msg, correlationId, replyToDestinationQueue), null).getBody(); + + TransformRequest transformRequest = convert(msg, correlationId, replyToDestinationQueue); + if (transformRequest == null) + { + logger.error("Exception during T-Request deserialization! T-Reply with error has been " + + "sent to T-Router!"); + return; + } + + // Tries to convert and return the object. If it fails to convert, the method sends an error message and returns null. + TransformReply reply = transformController.transform( + transformRequest, null).getBody(); transformReplySender.send(replyToDestinationQueue, reply); } /** * Tries to convert the JMS {@link Message} to a {@link TransformRequest} - * If any errors occur standard error {@link TransformReply} are sent back + * If any errors occur standard error {@link TransformReply} are sent back to T-Router * * @param msg Message to be deserialized * @param correlationId CorrelationId of the message * @param destination Needed in case deserialization fails. Passed here so we don't retrieve it again. - * @return The converted {@link TransformRequest} instance + * @return The converted {@link TransformRequest} instance or null in case of errors */ private TransformRequest convert(final Message msg, final String correlationId, Destination destination) { try { - return (TransformRequest) transformMessageConverter.fromMessage(msg); + TransformRequest request = (TransformRequest) transformMessageConverter + .fromMessage(msg); + if (request == null) + { + logger.error("T-Request is null deserialization!"); + replyWithInternalSvErr(destination, + "JMS exception during T-Request deserialization: ", correlationId); + } + return request; } catch (MessageConversionException e) { diff --git a/alfresco-transformer-base/src/test/java/org/alfresco/transformer/QueueTransformServiceTest.java b/alfresco-transformer-base/src/test/java/org/alfresco/transformer/QueueTransformServiceTest.java new file mode 100644 index 00000000..4fb1ebc1 --- /dev/null +++ b/alfresco-transformer-base/src/test/java/org/alfresco/transformer/QueueTransformServiceTest.java @@ -0,0 +1,202 @@ +/* + * #%L + * Alfresco Enterprise Repository + * %% + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * %% + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + * #L% + */ + +package org.alfresco.transformer; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import org.alfresco.transform.client.model.TransformReply; +import org.alfresco.transform.client.model.TransformRequest; +import org.alfresco.transformer.messaging.TransformMessageConverter; +import org.alfresco.transformer.messaging.TransformReplySender; +import org.apache.activemq.command.ActiveMQObjectMessage; +import org.apache.activemq.command.ActiveMQQueue; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.jms.support.converter.MessageConversionException; + +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; + +public class QueueTransformServiceTest +{ + @Mock + private TransformController transformController; + @Mock + private TransformMessageConverter transformMessageConverter; + @Mock + private TransformReplySender transformReplySender; + + @InjectMocks + private QueueTransformService queueTransformService; + + @Before + public void setup() + { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testWhenReceiveNullMessageThenStopFlow() + { + queueTransformService.receive(null); + + verifyNoMoreInteractions(transformController); + verifyNoMoreInteractions(transformMessageConverter); + verifyNoMoreInteractions(transformReplySender); + } + + @Test + public void testWhenReceiveMessageWithNoReplyToQueueThenStopFlow() + { + queueTransformService.receive(new ActiveMQObjectMessage()); + + verifyNoMoreInteractions(transformController); + verifyNoMoreInteractions(transformMessageConverter); + verifyNoMoreInteractions(transformReplySender); + } + + @Test + public void testConvertMessageReturnsNullThenReplyWithInternalServerError() throws JMSException + { + ActiveMQObjectMessage msg = new ActiveMQObjectMessage(); + ActiveMQQueue destination = new ActiveMQQueue(); + msg.setJMSReplyTo(destination); + + TransformReply reply = TransformReply.builder() + .withStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()) + .withErrorDetails("JMS exception during T-Request deserialization: ").build(); + + doReturn(null).when(transformMessageConverter).fromMessage(msg); + + queueTransformService.receive(msg); + + verify(transformMessageConverter).fromMessage(msg); + verify(transformReplySender).send(destination, reply, null); + + verifyNoMoreInteractions(transformController); + } + + @Test + public void testConvertMessageThrowsMessageConversionExceptionThenReplyWithBadRequest() + throws JMSException + { + ActiveMQObjectMessage msg = new ActiveMQObjectMessage(); + ActiveMQQueue destination = new ActiveMQQueue(); + msg.setJMSReplyTo(destination); + + TransformReply reply = TransformReply.builder().withStatus(HttpStatus.BAD_REQUEST.value()) + .withErrorDetails("Message conversion exception during T-Request deserialization: ") + .build(); + + doThrow(MessageConversionException.class).when(transformMessageConverter).fromMessage(msg); + + queueTransformService.receive(msg); + + verify(transformMessageConverter).fromMessage(msg); + verify(transformReplySender).send(destination, reply, reply.getRequestId()); + + verifyNoMoreInteractions(transformController); + } + + @Test + public void testConvertMessageThrowsJMSExceptionThenReplyWithInternalServerError() + throws JMSException + { + ActiveMQObjectMessage msg = new ActiveMQObjectMessage(); + ActiveMQQueue destination = new ActiveMQQueue(); + msg.setJMSReplyTo(destination); + + TransformReply reply = TransformReply.builder().withStatus(HttpStatus.BAD_REQUEST.value()) + .withErrorDetails("JMS exception during T-Request deserialization: ").build(); + + doThrow(JMSException.class).when(transformMessageConverter).fromMessage(msg); + + queueTransformService.receive(msg); + + verify(transformMessageConverter).fromMessage(msg); + verify(transformReplySender).send(destination, reply, reply.getRequestId()); + + verifyNoMoreInteractions(transformController); + } + + @Test + public void testWhenReceiveValidTransformRequestThenReplyWithSuccess() throws JMSException + { + ActiveMQObjectMessage msg = new ActiveMQObjectMessage(); + ActiveMQQueue destination = new ActiveMQQueue(); + msg.setJMSReplyTo(destination); + + TransformRequest request = new TransformRequest(); + TransformReply reply = TransformReply.builder().withStatus(HttpStatus.CREATED.value()) + .build(); + + doReturn(request).when(transformMessageConverter).fromMessage(msg); + doReturn(new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()))) + .when(transformController).transform(request, null); + + queueTransformService.receive(msg); + + verify(transformMessageConverter).fromMessage(msg); + verify(transformController).transform(request, null); + verify(transformReplySender).send(destination, reply); + } + + @Test + public void testWhenJMSExceptionOnMessageIsThrownThenStopFlow() throws JMSException + { + Message msg = mock(Message.class); + + doThrow(JMSException.class).when(msg).getJMSReplyTo(); + + queueTransformService.receive(msg); + + verifyNoMoreInteractions(transformController); + verifyNoMoreInteractions(transformMessageConverter); + verifyNoMoreInteractions(transformReplySender); + } + + @Test + public void testWhenExceptionOnCorrelationIdIsThrownThenContinueFlowWithNullCorrelationId() + throws JMSException + { + Message msg = mock(Message.class); + Destination destination = mock(Destination.class); + + doThrow(JMSException.class).when(msg).getJMSCorrelationID(); + doReturn(destination).when(msg).getJMSReplyTo(); + + TransformRequest request = new TransformRequest(); + TransformReply reply = TransformReply.builder().withStatus(HttpStatus.CREATED.value()) + .build(); + + doReturn(request).when(transformMessageConverter).fromMessage(msg); + doReturn(new ResponseEntity<>(reply, HttpStatus.valueOf(reply.getStatus()))) + .when(transformController).transform(request, null); + + queueTransformService.receive(msg); + + verify(transformMessageConverter).fromMessage(msg); + verify(transformController).transform(request, null); + verify(transformReplySender).send(destination, reply); + } +}