diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java index 4e4fc95c59..e6fe7f58af 100644 --- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java +++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java @@ -772,6 +772,24 @@ public interface ActiveMQServerControl { @Operation(desc = "Closes all the connections for sessions with the given user name", impact = MBeanOperationInfo.INFO) boolean closeConnectionsForUser(@Parameter(desc = "a user name", name = "userName") String address) throws Exception; + /** + * Closes the connection with the given id. + */ + @Operation(desc = "Closes all the connection with the id", impact = MBeanOperationInfo.INFO) + boolean closeConnectionWithID(@Parameter(desc = "The connection ID", name = "ID") String ID) throws Exception; + + /** + * Closes the session with the given id. + */ + @Operation(desc = "Closes the session with the id", impact = MBeanOperationInfo.INFO) + boolean closeSessionWithID(String connectionID, String ID) throws Exception; + + /** + * Closes the consumer with the given id. + */ + @Operation(desc = "Closes the consumer with the id", impact = MBeanOperationInfo.INFO) + boolean closeConsumerWithID(String sessionID, String ID) throws Exception; + /** * Lists all the IDs of the connections connected to this server. */ diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/connections.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/connections.html index c844ab86eb..9b3b231b80 100644 --- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/connections.html +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/connections.html @@ -42,10 +42,29 @@ + +
+
+ +     +
+
- +
+
+

You are about to close the selected connection: {{gridOptions.selectedItems[0].connectionID}} +

+

Are you sure you want to continue.

+
+
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/consumers.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/consumers.html index 296c54dc7e..32589260f2 100644 --- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/consumers.html +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/consumers.html @@ -44,9 +44,30 @@ + +
+
+ +     +
+
+
+
+

You are about to close the selected consumer: {{gridOptions.selectedItems[0].id}} +

+

Are you sure you want to continue.

+
+
+
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/sessions.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/sessions.html index f81fd7ea9d..0e03bc4d78 100644 --- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/sessions.html +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/sessions.html @@ -43,11 +43,32 @@ +
+
+ +     +
+
- +
+
+

You are about to close the selected session: {{gridOptions.selectedItems[0].id}} +

+

Are you sure you want to continue.

+
+
- \ No newline at end of file + + + + diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/connections.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/connections.js index c362f361e5..170af8a42e 100644 --- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/connections.js +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/connections.js @@ -108,7 +108,22 @@ var ARTEMIS = (function(ARTEMIS) { artemisConnection.connection = connection.entity; $location.path("artemis/sessions"); }; - + $scope.closeConnection = function () { + var connectionID = $scope.gridOptions.selectedItems[0].connectionID + ARTEMIS.log.info("closing connection: " + connectionID); + if (workspace.selection) { + var mbean = getBrokerMBean(jolokia); + if (mbean) { + jolokia.request({ type: 'exec', + mbean: mbean, + operation: 'closeConnectionWithID(java.lang.String)', + arguments: [connectionID] }, + onSuccess($scope.loadTable(), { error: function (response) { + Core.defaultJolokiaErrorHandler("Could not close connection: " + response); + }})); + } + } + }; /** * Below here is utility. * @@ -128,7 +143,6 @@ var ARTEMIS = (function(ARTEMIS) { directions: ["asc"] }; var refreshed = false; - $scope.gridOptions = { selectedItems: [], data: 'objects', @@ -177,6 +191,7 @@ var ARTEMIS = (function(ARTEMIS) { Core.notification("error", "Could not retrieve " + objectType + " list from Artemis."); } function populateTable(response) { + $scope.gridOptions.selectedItems.length = 0; var data = JSON.parse(response.value); $scope.objects = []; angular.forEach(data["data"], function (value, idx) { diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/consumers.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/consumers.js index 8a22fb933e..25e206a1bc 100644 --- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/consumers.js +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/consumers.js @@ -134,6 +134,23 @@ var ARTEMIS = (function(ARTEMIS) { artemisSession.session = null; + $scope.closeConsumer = function () { + var consumerID = $scope.gridOptions.selectedItems[0].id; + var sessionID = $scope.gridOptions.selectedItems[0].session; + ARTEMIS.log.info("closing session: " + sessionID); + if (workspace.selection) { + var mbean = getBrokerMBean(jolokia); + if (mbean) { + jolokia.request({ type: 'exec', + mbean: mbean, + operation: 'closeConsumerWithID(java.lang.String, java.lang.String)', + arguments: [sessionID, consumerID] }, + onSuccess($scope.loadTable(), { error: function (response) { + Core.defaultJolokiaErrorHandler("Could not close consumer: " + response); + }})); + } + } + }; /** * Below here is utility. * @@ -202,6 +219,7 @@ var ARTEMIS = (function(ARTEMIS) { Core.notification("error", "Could not retrieve " + objectType + " list from Artemis."); } function populateTable(response) { + $scope.gridOptions.selectedItems.length = 0; var data = JSON.parse(response.value); $scope.objects = []; angular.forEach(data["data"], function (value, idx) { diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/sessions.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/sessions.js index bf63298b53..ce661a10f1 100644 --- a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/sessions.js +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/sessions.js @@ -127,7 +127,23 @@ var ARTEMIS = (function(ARTEMIS) { artemisSession.connection = null; artemisConsumer.consumer = null; artemisProducer.producer = null; - + $scope.closeSession = function () { + var sessionID = $scope.gridOptions.selectedItems[0].id; + var connectionID = $scope.gridOptions.selectedItems[0].connectionID; + ARTEMIS.log.info("closing session: " + sessionID); + if (workspace.selection) { + var mbean = getBrokerMBean(jolokia); + if (mbean) { + jolokia.request({ type: 'exec', + mbean: mbean, + operation: 'closeSessionWithID(java.lang.String, java.lang.String)', + arguments: [connectionID, sessionID] }, + onSuccess($scope.loadTable(), { error: function (response) { + Core.defaultJolokiaErrorHandler("Could not close session: " + response); + }})); + } + } + }; /** * Below here is utility. * @@ -196,6 +212,7 @@ var ARTEMIS = (function(ARTEMIS) { Core.notification("error", "Could not retrieve " + objectType + " list from Artemis."); } function populateTable(response) { + $scope.gridOptions.selectedItems.length = 0; var data = JSON.parse(response.value); $scope.objects = []; angular.forEach(data["data"], function (value, idx) { diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java index a3773f8145..f2aec1c412 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java @@ -1533,6 +1533,70 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active return closed; } + @Override + public boolean closeConnectionWithID(final String ID) { + checkStarted(); + + clearIO(); + try { + for (RemotingConnection connection : remotingService.getConnections()) { + if (connection.getID().toString().equals(ID)) { + remotingService.removeConnection(connection.getID()); + connection.fail(ActiveMQMessageBundle.BUNDLE.connectionWithIDClosedByManagement(ID)); + return true; + } + } + } finally { + blockOnIO(); + } + return false; + } + + @Override + public boolean closeSessionWithID(final String connectionID, final String ID) throws Exception { + checkStarted(); + + clearIO(); + try { + List sessions = server.getSessions(connectionID); + for (ServerSession session : sessions) { + if (session.getName().equals(ID.toString())) { + session.close(true); + return true; + } + } + + } finally { + blockOnIO(); + } + return false; + } + + @Override + public boolean closeConsumerWithID(final String sessionID, final String ID) throws Exception { + checkStarted(); + + clearIO(); + try { + Set sessions = server.getSessions(); + for (ServerSession session : sessions) { + if (session.getName().equals(sessionID.toString())) { + Set serverConsumers = session.getServerConsumers(); + for (ServerConsumer serverConsumer : serverConsumers) { + if (serverConsumer.sequentialID() == Long.valueOf(ID)) { + serverConsumer.close(true); + return true; + } + } + } + } + + } finally { + blockOnIO(); + } + return false; + } + @Override public String[] listConnectionIDs() { checkStarted(); diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQMessageBundle.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQMessageBundle.java index 6d571a847c..bd0e8cfa1a 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQMessageBundle.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQMessageBundle.java @@ -386,6 +386,9 @@ public interface ActiveMQMessageBundle { @Message(id = 119119, value = "Disk Capacity is Low, cannot produce more messages.") ActiveMQIOErrorException diskBeyondLimit(); + @Message(id = 119120, value = "connection with ID {0} closed by management", format = Message.Format.MESSAGE_FORMAT) + ActiveMQInternalErrorException connectionWithIDClosedByManagement(String ID); + @Message(id = 119200, value = "Maximum Consumer Limit Reached on Queue:(address={0},queue={1})", format = Message.Format.MESSAGE_FORMAT) ActiveMQQueueMaxConsumerLimitReached maxConsumerLimitReachedForQueue(SimpleString address, SimpleString queueName); diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java index 587cab4b15..9408fdb324 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java @@ -97,6 +97,21 @@ public class ActiveMQServerControlUsingCoreTest extends ActiveMQServerControlTes return (Boolean) proxy.invokeOperation("closeConnectionsForUser", userName); } + @Override + public boolean closeConnectionWithID(String ID) throws Exception { + return (Boolean) proxy.invokeOperation("closeConnectionWithID", ID); + } + + @Override + public boolean closeSessionWithID(String connectionID, String ID) throws Exception { + return (Boolean) proxy.invokeOperation("closeSessionWithID", connectionID, ID); + } + + @Override + public boolean closeConsumerWithID(String sessionID, String ID) throws Exception { + return (Boolean) proxy.invokeOperation("closeConsumerWithID", sessionID, ID); + } + @Override public boolean commitPreparedTransaction(final String transactionAsBase64) throws Exception { return (Boolean) proxy.invokeOperation("commitPreparedTransaction", transactionAsBase64);