diff --git a/CHANGELOG.md b/CHANGELOG.md
index 582db1c..b76898a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,10 @@ on [Keep a CHANGELOG](http://keepachangelog.com/). This project adheres to
[Semantic Versioning](http://semver.org/).
## [Unreleased]
+## [3.6.0] - 2020-03-12
+
+### Added
+- Command _`sendmessage`_ that sends the contents of a text file as a text message to the DLQ
## [3.5.0] - 2019-06-20
diff --git a/README.md b/README.md
index 9237e97..21ecc05 100644
--- a/README.md
+++ b/README.md
@@ -118,6 +118,27 @@ Only messages that have the same JMSMessageId and different Consumer (_AMQ_ORIG_
`java -jar artemis-manager.jar browse @artemis.config -report created-at-name-total-report`
+## Send a Text Message to the DLQ
+
+* Sends a text message to the DLQ. The message must be contained in a text file, the path of which must be included in the command
+
+**Note: SendMessage uses JMS to connect to the Artemis broker.**
+
+`java -jar artemis-manager.jar sendmessage -messageFile path/to/some/text/file/containing/the/message.txt @artemis.config`
+
+**Warning. In order to have the correct permissions to run this command, you will need to update your
+broker.xml file in your Artemis configuration. This will disable your security**
+
+Add these 2 lines to broker.xml directly under the
+
+
+tag
+
+ false
+ true
+
+For an example, look at src/test/resources/artemis/broker.xml
+
## Chaining Commands
* Chaining commands
diff --git a/pom.xml b/pom.xml
index 9de91dc..1a514b6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -113,6 +113,11 @@
utilities-core
${utilities.version}
+
+ commons-io
+ commons-io
+
+
@@ -125,11 +130,6 @@
json-path-assert
test
-
- commons-io
- commons-io
- test
-
org.mockito
mockito-core
@@ -229,6 +229,7 @@
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false
+ ${basedir}/src/test/resources/artemis
diff --git a/src/main/java/uk/gov/justice/artemis/manager/connector/ArtemisConnector.java b/src/main/java/uk/gov/justice/artemis/manager/connector/ArtemisConnector.java
index e0aed8f..2daa084 100644
--- a/src/main/java/uk/gov/justice/artemis/manager/connector/ArtemisConnector.java
+++ b/src/main/java/uk/gov/justice/artemis/manager/connector/ArtemisConnector.java
@@ -35,4 +35,6 @@ void setParameters(final List jmxUrls,
final String jmsUrl,
final String jmsUsername,
final String jmsPassword) throws MalformedURLException;
-}
\ No newline at end of file
+
+ String sendTextMessage(final String destinationName, final String message);
+}
diff --git a/src/main/java/uk/gov/justice/artemis/manager/connector/CombinedJmsAndJmxArtemisConnector.java b/src/main/java/uk/gov/justice/artemis/manager/connector/CombinedJmsAndJmxArtemisConnector.java
index 7973f33..59a98e6 100644
--- a/src/main/java/uk/gov/justice/artemis/manager/connector/CombinedJmsAndJmxArtemisConnector.java
+++ b/src/main/java/uk/gov/justice/artemis/manager/connector/CombinedJmsAndJmxArtemisConnector.java
@@ -206,4 +206,17 @@ public Map topicMessageCount(final Collection topicNames)
.flatMap(m -> m.entrySet().stream())
.collect(groupingBy(Entry::getKey, summingLong(Entry::getValue)));
}
-}
\ No newline at end of file
+
+ @Override
+ public String sendTextMessage(final String destinationName, final String message) {
+
+ return jmxProcessor
+ .processQueueControl(
+ jmxServiceUrls,
+ jmxEnvironment,
+ objectNameBuilder,
+ destinationName,
+ jmxManagement.sendTextMessage(message))
+ .collect(toList()).toString();
+ }
+}
diff --git a/src/main/java/uk/gov/justice/artemis/manager/connector/JmxArtemisConnector.java b/src/main/java/uk/gov/justice/artemis/manager/connector/JmxArtemisConnector.java
index 8607092..6a308b3 100644
--- a/src/main/java/uk/gov/justice/artemis/manager/connector/JmxArtemisConnector.java
+++ b/src/main/java/uk/gov/justice/artemis/manager/connector/JmxArtemisConnector.java
@@ -147,4 +147,17 @@ public Map topicMessageCount(final Collection topicNames)
groupingBy(Entry::getKey,
summingLong(Entry::getValue)));
}
-}
\ No newline at end of file
+
+ @Override
+ public String sendTextMessage(final String destinationName, final String message) {
+
+ return jmxProcessor
+ .processQueueControl(
+ jmxServiceUrls,
+ jmxEnvironment,
+ objectNameBuilder,
+ destinationName,
+ jmxManagement.sendTextMessage(message))
+ .collect(toList()).toString();
+ }
+}
diff --git a/src/main/java/uk/gov/justice/artemis/manager/connector/filehandling/MessageFileException.java b/src/main/java/uk/gov/justice/artemis/manager/connector/filehandling/MessageFileException.java
new file mode 100644
index 0000000..47d61eb
--- /dev/null
+++ b/src/main/java/uk/gov/justice/artemis/manager/connector/filehandling/MessageFileException.java
@@ -0,0 +1,12 @@
+package uk.gov.justice.artemis.manager.connector.filehandling;
+
+public class MessageFileException extends RuntimeException {
+
+ public MessageFileException(final String message) {
+ super(message);
+ }
+
+ public MessageFileException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/main/java/uk/gov/justice/artemis/manager/connector/filehandling/TextMessageFileContentsReader.java b/src/main/java/uk/gov/justice/artemis/manager/connector/filehandling/TextMessageFileContentsReader.java
new file mode 100644
index 0000000..2c79cc9
--- /dev/null
+++ b/src/main/java/uk/gov/justice/artemis/manager/connector/filehandling/TextMessageFileContentsReader.java
@@ -0,0 +1,26 @@
+package uk.gov.justice.artemis.manager.connector.filehandling;
+
+import static java.lang.String.format;
+import static java.nio.charset.Charset.defaultCharset;
+import static org.apache.commons.io.FileUtils.getFile;
+import static org.apache.commons.io.FileUtils.readFileToString;
+
+import java.io.File;
+
+public class TextMessageFileContentsReader {
+
+ public String readContentsOf(final String pathToFile) {
+
+ try {
+ final File file = getFile(pathToFile);
+
+ if(! file.exists()) {
+ throw new MessageFileException(format("Failed to find file '%s'", file.getAbsolutePath()));
+ }
+
+ return readFileToString(file, defaultCharset());
+ } catch (final Exception e) {
+ throw new MessageFileException(format("Failed to read file '%s'", pathToFile), e);
+ }
+ }
+}
diff --git a/src/main/java/uk/gov/justice/artemis/manager/connector/jmx/JmxManagement.java b/src/main/java/uk/gov/justice/artemis/manager/connector/jmx/JmxManagement.java
index 616d534..4592553 100644
--- a/src/main/java/uk/gov/justice/artemis/manager/connector/jmx/JmxManagement.java
+++ b/src/main/java/uk/gov/justice/artemis/manager/connector/jmx/JmxManagement.java
@@ -98,4 +98,15 @@ public JmxManagementFunction reprocessAllMessages() {
return reprocessedMessageCount;
};
}
+
+ public JmxManagementFunction sendTextMessage(final String message) {
+ return queueControl -> {
+ try {
+ return queueControl.sendTextMessage(message);
+ } catch (final Exception exception) {
+ outputPrinter.writeException(exception);
+ return format("%s: %s", exception.getClass().getSimpleName(), exception.getMessage());
+ }
+ };
+ }
}
diff --git a/src/main/java/uk/gov/justice/framework/tools/command/AbstractArtemisCommand.java b/src/main/java/uk/gov/justice/framework/tools/command/AbstractArtemisCommand.java
index fdbbf58..1ef7422 100644
--- a/src/main/java/uk/gov/justice/framework/tools/command/AbstractArtemisCommand.java
+++ b/src/main/java/uk/gov/justice/framework/tools/command/AbstractArtemisCommand.java
@@ -16,7 +16,7 @@ abstract class AbstractArtemisCommand {
public static final String DEFAULT_BROKER_NAME = "default";
public static final String DEFAULT_JMS_URL = "tcp://localhost:61616?clientID=artemis-manager";
- final OutputPrinter outputPrinter = new ConsolePrinter();
+ OutputPrinter outputPrinter = new ConsolePrinter();
ArtemisConnector artemisConnector = new CombinedJmsAndJmxArtemisConnector();
@@ -41,6 +41,9 @@ abstract class AbstractArtemisCommand {
@Parameter(names = "-jmsPassword", description = "JMS Password (optional)")
String jmsPassword;
+ @Parameter(names = "-messageFile", description = "The text message file that should be sent when calling sendmessage. If not calling sendmessage this parameter is not required")
+ String textMessageFile;
+
@Parameter(names = "-help", help = true)
private boolean help;
@@ -53,4 +56,4 @@ public void setup() throws MalformedURLException {
this.jmsUsername,
this.jmsPassword);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/uk/gov/justice/framework/tools/command/SendMessage.java b/src/main/java/uk/gov/justice/framework/tools/command/SendMessage.java
new file mode 100644
index 0000000..64ab8d0
--- /dev/null
+++ b/src/main/java/uk/gov/justice/framework/tools/command/SendMessage.java
@@ -0,0 +1,39 @@
+package uk.gov.justice.framework.tools.command;
+
+
+import uk.gov.justice.artemis.manager.connector.filehandling.MessageFileException;
+import uk.gov.justice.artemis.manager.connector.filehandling.TextMessageFileContentsReader;
+import uk.gov.justice.framework.tools.common.command.ShellCommand;
+
+public class SendMessage extends AbstractArtemisCommand implements ShellCommand {
+
+ private final TextMessageFileContentsReader textMessageFileContentsReader;
+
+ public SendMessage() {
+ this(new TextMessageFileContentsReader());
+ }
+
+ public SendMessage(final TextMessageFileContentsReader textMessageFileContentsReader) {
+ this.textMessageFileContentsReader = textMessageFileContentsReader;
+ }
+
+ @Override
+ public void run(final String[] args) {
+
+ try {
+ super.setup();
+
+ if(textMessageFile == null || textMessageFile.isEmpty()) {
+ throw new MessageFileException("Cannot read message file. No file name set. Please use -messageFile parameter when calling this command");
+ }
+
+ final String message = textMessageFileContentsReader.readContentsOf(textMessageFile);
+
+ final String results = artemisConnector.sendTextMessage("DLQ", message);
+ outputPrinter.write(results);
+
+ } catch (final Exception exception) {
+ outputPrinter.writeStackTrace(exception);
+ }
+ }
+}
diff --git a/src/main/java/uk/gov/justice/framework/tools/common/command/Bootstrap.java b/src/main/java/uk/gov/justice/framework/tools/common/command/Bootstrap.java
index 50bde87..6c033f0 100644
--- a/src/main/java/uk/gov/justice/framework/tools/common/command/Bootstrap.java
+++ b/src/main/java/uk/gov/justice/framework/tools/common/command/Bootstrap.java
@@ -7,11 +7,10 @@
import java.util.Optional;
import java.util.Set;
+import com.beust.jcommander.JCommander;
import org.reflections.Reflections;
import org.slf4j.Logger;
-import com.beust.jcommander.JCommander;
-
public class Bootstrap {
private static final Logger LOGGER = getLogger(Bootstrap.class);
@@ -60,4 +59,4 @@ private void createInstanceAndAddToJCommander(final Class extends ShellCommand
LOGGER.error("Unable to create instance of {}", commandClass.getName());
}
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/uk/gov/justice/artemis/manager/ArtemisManagerIT.java b/src/test/java/uk/gov/justice/artemis/manager/ArtemisManagerIT.java
index 1ae7239..57e8623 100644
--- a/src/test/java/uk/gov/justice/artemis/manager/ArtemisManagerIT.java
+++ b/src/test/java/uk/gov/justice/artemis/manager/ArtemisManagerIT.java
@@ -1,5 +1,6 @@
package uk.gov.justice.artemis.manager;
+import static com.jayway.jsonassert.JsonAssert.with;
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
@@ -42,6 +43,7 @@ public class ArtemisManagerIT {
private static final String COMMAND_LINE_REMOVE = "env -u _JAVA_OPTIONS java -jar target/artemis-manager.jar remove -brokerName 0.0.0.0 -jmxUrl service:jmx:rmi:///jndi/rmi://localhost:3000/jmxrmi -jmsUrl tcp://localhost:61616?clientID=artemis-manager";
private static final String COMMAND_LINE_REMOVE_ALL_DUPLICATES = "env -u _JAVA_OPTIONS java -jar target/artemis-manager.jar removeallduplicates -brokerName 0.0.0.0 -jmxUrl service:jmx:rmi:///jndi/rmi://localhost:3000/jmxrmi -jmsUrl tcp://localhost:61616?clientID=artemis-manager";
private static final String COMMAND_LINE_DEDUPLICATE_TOPIC_MESSAGES = "env -u _JAVA_OPTIONS java -jar target/artemis-manager.jar deduplicatetopicmessages -brokerName 0.0.0.0 -jmxUrl service:jmx:rmi:///jndi/rmi://localhost:3000/jmxrmi -jmsUrl tcp://localhost:61616?clientID=artemis-manager";
+ private static final String COMMAND_LINE_SEND_TEXT_MESSAGE = "env -u _JAVA_OPTIONS java -jar target/artemis-manager.jar sendmessage -messageFile src/test/resources/messages/messageForSendingToArtemis.txt -brokerName 0.0.0.0 -jmxUrl service:jmx:rmi:///jndi/rmi://localhost:3000/jmxrmi -jmsUrl tcp://localhost:61616?clientID=artemis-manager";
@BeforeClass
public static void beforeClass() throws JMSException {
@@ -53,6 +55,26 @@ public static void afterClass() throws JMSException {
closeJmsConnection();
}
+ @Test
+ public void shouldSendTextMessage() throws Exception {
+
+ cleanQueue(DLQ);
+
+ final Output output = execute(COMMAND_LINE_SEND_TEXT_MESSAGE);
+
+ assertThat(output.errorOutput(), isEmptyString());
+
+ final Output browseOutput = execute(COMMAND_LINE_BROWSE);
+
+ assertThat(browseOutput.errorOutput(), isEmptyString());
+
+ final String messageText = browseOutput.standardOutput();
+ final String messageJson = messageText.replace("[", "").replace("]", "");
+
+ with(messageJson)
+ .assertThat("$.msgContent.message", is("All your base are belong to us"));
+ }
+
@Test
public void shouldBrowseMessagesInDLQ() throws Exception {
cleanQueue(DLQ);
diff --git a/src/test/java/uk/gov/justice/artemis/manager/connector/JmxArtemisConnectorIT.java b/src/test/java/uk/gov/justice/artemis/manager/connector/JmxArtemisConnectorIT.java
index 57606e5..6873c55 100644
--- a/src/test/java/uk/gov/justice/artemis/manager/connector/JmxArtemisConnectorIT.java
+++ b/src/test/java/uk/gov/justice/artemis/manager/connector/JmxArtemisConnectorIT.java
@@ -194,4 +194,4 @@ public void shouldReturnTopicsAndCounts() throws Exception {
throw e;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/uk/gov/justice/artemis/manager/connector/filehandling/TextMessageFileContentsReaderTest.java b/src/test/java/uk/gov/justice/artemis/manager/connector/filehandling/TextMessageFileContentsReaderTest.java
new file mode 100644
index 0000000..d408308
--- /dev/null
+++ b/src/test/java/uk/gov/justice/artemis/manager/connector/filehandling/TextMessageFileContentsReaderTest.java
@@ -0,0 +1,40 @@
+package uk.gov.justice.artemis.manager.connector.filehandling;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class TextMessageFileContentsReaderTest {
+
+ @InjectMocks
+ private TextMessageFileContentsReader textMessageFileContentsReader;
+
+ @Test
+ public void shouldReadContentsOfAMessageFileAsString() throws Exception {
+
+ final String pathToFile = "src/test/resources/messages/messageForSendingToArtemis.txt";
+
+ final String message = textMessageFileContentsReader.readContentsOf(pathToFile);
+
+ assertThat(message, is("{\n \"message\": \"All your base are belong to us\"\n}\n"));
+ }
+
+ @Test
+ public void shouldFailIfFileNotFound() throws Exception {
+
+ final String pathToFile = "this/file/does/not/exist.txt";
+
+ try {
+ textMessageFileContentsReader.readContentsOf(pathToFile);
+ fail();
+ } catch (final MessageFileException expected) {
+ assertThat(expected.getMessage(), is("Failed to read file 'this/file/does/not/exist.txt'"));
+ }
+ }
+}
diff --git a/src/test/java/uk/gov/justice/framework/tools/command/SendMessageTest.java b/src/test/java/uk/gov/justice/framework/tools/command/SendMessageTest.java
new file mode 100644
index 0000000..887eaee
--- /dev/null
+++ b/src/test/java/uk/gov/justice/framework/tools/command/SendMessageTest.java
@@ -0,0 +1,114 @@
+package uk.gov.justice.framework.tools.command;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import uk.gov.justice.artemis.manager.connector.ArtemisConnector;
+import uk.gov.justice.artemis.manager.connector.filehandling.MessageFileException;
+import uk.gov.justice.artemis.manager.connector.filehandling.TextMessageFileContentsReader;
+import uk.gov.justice.output.OutputPrinter;
+
+import java.net.MalformedURLException;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class SendMessageTest {
+
+ @Mock
+ private OutputPrinter outputPrinter;
+
+ @Mock
+ private ArtemisConnector artemisConnector;
+
+ private final TextMessageFileContentsReader textMessageFileContentsReader = mock(TextMessageFileContentsReader.class);
+
+ @InjectMocks
+ private SendMessage sendMessage = new SendMessage(textMessageFileContentsReader) {
+ @Override
+ public void setup() throws MalformedURLException {
+ }
+ };
+
+ @Captor
+ private ArgumentCaptor exceptionCaptor;
+
+ @Test
+ public void shouldSendReadContentsOfSuppliedFileAndSendAsTextMessage() throws Exception {
+
+ final String fileName = "some/messageFile.txt";
+ final String message = "a message";
+ final String results = "this message succeeded";
+
+ sendMessage.textMessageFile = fileName;
+
+ when(textMessageFileContentsReader.readContentsOf(fileName)).thenReturn(message);
+ when(artemisConnector.sendTextMessage("DLQ", message)).thenReturn(results);
+
+ sendMessage.run(new String[0]);
+
+ verify(outputPrinter).write(results);
+ }
+
+ @Test
+ public void shouldFailIfSuppliedFileNameIsNull() throws Exception {
+
+ sendMessage.textMessageFile = null;
+
+ sendMessage.run(new String[0]);
+
+ verify(outputPrinter).writeStackTrace(exceptionCaptor.capture());
+
+ final Exception exception = exceptionCaptor.getValue();
+
+ assertThat(exception, is(instanceOf(MessageFileException.class)));
+ assertThat(exception.getMessage(), is("Cannot read message file. No file name set. Please use -messageFile parameter when calling this command"));
+ }
+
+ @Test
+ public void shouldFailIfSuppliedFileNameIsEmpty() throws Exception {
+
+ sendMessage.textMessageFile = "";
+
+ sendMessage.run(new String[0]);
+
+ verify(outputPrinter).writeStackTrace(exceptionCaptor.capture());
+
+ final Exception exception = exceptionCaptor.getValue();
+
+ assertThat(exception, is(instanceOf(MessageFileException.class)));
+ assertThat(exception.getMessage(), is("Cannot read message file. No file name set. Please use -messageFile parameter when calling this command"));
+ }
+
+ @Test
+ public void shouldFailIfWriteExceptionIfSendingMessageFails() throws Exception {
+
+ final NullPointerException nullPointerException = new NullPointerException("Ooops");
+
+ final String fileName = "some/messageFile.txt";
+ final String message = "a message";
+
+ sendMessage.textMessageFile = fileName;
+
+ when(textMessageFileContentsReader.readContentsOf(fileName)).thenReturn(message);
+ when(artemisConnector.sendTextMessage("DLQ", message)).thenThrow(nullPointerException);
+
+ sendMessage.run(new String[0]);
+
+ verify(outputPrinter).writeStackTrace(exceptionCaptor.capture());
+
+ final Exception exception = exceptionCaptor.getValue();
+
+ assertThat(exception, is(nullPointerException));
+ }
+}
diff --git a/src/test/resources/artemis/broker.xml b/src/test/resources/artemis/broker.xml
new file mode 100644
index 0000000..8829de7
--- /dev/null
+++ b/src/test/resources/artemis/broker.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+ 0.0.0.0
+ true
+
+ NIO
+ ./data/paging
+ ./data/bindings
+ ./data/journal
+ ./data/large-messages
+ true
+ 2
+ -1
+
+
+
+
+
+
+
+
+
+
+
+ 5000
+
+ 90
+
+ 104857600
+
+
+ tcp://0.0.0.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE
+
+ tcp://0.0.0.0:5672?protocols=AMQP
+
+ tcp://0.0.0.0:61613?protocols=STOMP
+
+ tcp://0.0.0.0:5445?protocols=HORNETQ,STOMP
+
+ tcp://0.0.0.0:1883?protocols=MQTT
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ true
+
+
+
+ jms.queue.DLQ
+ jms.queue.ExpiryQueue
+ 0
+
+ -1
+ 10
+ PAGE
+
+
+
+
diff --git a/src/test/resources/messages/messageForSendingToArtemis.txt b/src/test/resources/messages/messageForSendingToArtemis.txt
new file mode 100644
index 0000000..b7fe9da
--- /dev/null
+++ b/src/test/resources/messages/messageForSendingToArtemis.txt
@@ -0,0 +1,3 @@
+{
+ "message": "All your base are belong to us"
+}