From fa7b247dc460eb76b588befbe4ee3aa5a49a4f5d Mon Sep 17 00:00:00 2001 From: Andy Taylor Date: Wed, 5 Jul 2017 16:34:18 +0100 Subject: [PATCH] ARTEMIS-1270 Management Console - Hawtio Solution Add Artemis Plugin --- artemis-hawtio/artemis-plugin/README.md | 3 + artemis-hawtio/artemis-plugin/pom.xml | 263 +++++++ .../hawtio/plugin/PluginContextListener.java | 71 ++ .../src/main/resources/WEB-INF/web.xml | 57 ++ .../src/main/resources/log4j.properties | 23 + .../src/main/webapp/plugin/doc/help.md | 19 + .../webapp/plugin/html/artemisLayout.html | 42 ++ .../webapp/plugin/html/brokerDiagram.html | 313 +++++++++ .../main/webapp/plugin/html/browseQueue.html | 156 ++++ .../webapp/plugin/html/createAddress.html | 44 ++ .../main/webapp/plugin/html/createQueue.html | 77 ++ .../webapp/plugin/html/deleteAddress.html | 48 ++ .../main/webapp/plugin/html/deleteQueue.html | 62 ++ .../main/webapp/plugin/html/preferences.html | 69 ++ .../main/webapp/plugin/html/sendMessage.html | 135 ++++ .../src/main/webapp/plugin/js/address.js | 119 ++++ .../main/webapp/plugin/js/artemisHelpers.js | 126 ++++ .../main/webapp/plugin/js/artemisPlugin.js | 246 +++++++ .../main/webapp/plugin/js/artemisService.js | 44 ++ .../main/webapp/plugin/js/brokerDiagram.js | 665 ++++++++++++++++++ .../src/main/webapp/plugin/js/browse.js | 499 +++++++++++++ .../main/webapp/plugin/js/jmsHeaderSchema.js | 62 ++ .../src/main/webapp/plugin/js/preferences.js | 54 ++ .../src/main/webapp/plugin/js/queue.js | 152 ++++ .../src/main/webapp/plugin/js/send.js | 211 ++++++ .../src/main/webapp/plugin/js/tree.js | 76 ++ .../main/webapp/plugin/lib/artemis-console.js | 82 +++ artemis-hawtio/pom.xml | 1 + 28 files changed, 3719 insertions(+) create mode 100644 artemis-hawtio/artemis-plugin/README.md create mode 100644 artemis-hawtio/artemis-plugin/pom.xml create mode 100644 artemis-hawtio/artemis-plugin/src/main/java/org/apache/activemq/hawtio/plugin/PluginContextListener.java create mode 100644 artemis-hawtio/artemis-plugin/src/main/resources/WEB-INF/web.xml create mode 100644 artemis-hawtio/artemis-plugin/src/main/resources/log4j.properties create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/doc/help.md create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/artemisLayout.html create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/brokerDiagram.html create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/browseQueue.html create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/createAddress.html create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/createQueue.html create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/deleteAddress.html create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/deleteQueue.html create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/preferences.html create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/sendMessage.html create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/address.js create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisHelpers.js create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisPlugin.js create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisService.js create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/brokerDiagram.js create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/browse.js create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/jmsHeaderSchema.js create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/preferences.js create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/queue.js create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/send.js create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/tree.js create mode 100644 artemis-hawtio/artemis-plugin/src/main/webapp/plugin/lib/artemis-console.js diff --git a/artemis-hawtio/artemis-plugin/README.md b/artemis-hawtio/artemis-plugin/README.md new file mode 100644 index 0000000000..dbf6e45436 --- /dev/null +++ b/artemis-hawtio/artemis-plugin/README.md @@ -0,0 +1,3 @@ +# artemis-hawtio + +Is a HawtIO plugin that allows the viewing and manipulation of topic/queues and other JMS resources. diff --git a/artemis-hawtio/artemis-plugin/pom.xml b/artemis-hawtio/artemis-plugin/pom.xml new file mode 100644 index 0000000000..234a054ceb --- /dev/null +++ b/artemis-hawtio/artemis-plugin/pom.xml @@ -0,0 +1,263 @@ + + + + + 4.0.0 + + + org.apache.activemq + artemis-hawtio-pom + 2.2.0-SNAPSHOT + + + artemis-plugin + ActiveMQ Artemis HawtIO Plugin + + + war + + + ${project.basedir}/../.. + + + + /artemis-plugin + + + ${project.artifactId} + + + + + + + javax.servlet, + *;resolution:=optional + + + ${project.artifactId}-${project.version} + ${basedir}/target/${webapp-dir} + ${basedir}/src/main/webapp/lib + ${webapp-outdir}/app/app.js + + + + + + + + io.hawt + hawtio-plugin-mbean + + + + + javax.servlet + servlet-api + provided + + + + + org.slf4j + slf4j-api + provided + + + org.slf4j + slf4j-log4j12 + provided + + + log4j + log4j + provided + + + + + + + + + + + src/main/resources + true + + **/*.xml + + + + + + + + + + maven-antrun-plugin + ${maven-antrun-plugin-version} + + + + + generate-sources + generate-sources + + run + + + + Building plugin javascript file list + + + + + + + + + Files: ${plugin-scripts} + + + + true + + + + + + + maven-resources-plugin + ${maven-resources-plugin-version} + + + + copy-resources + generate-sources + + resources + + + + + + + + org.apache.felix + maven-bundle-plugin + ${maven-bundle-plugin-version} + + + bundle-manifest + process-classes + + manifest + + + + + ${webapp-outdir}/META-INF + + jar + bundle + war + + + ${plugin-context} + ${plugin-context} + + WEB-INF/lib + *;scope=compile|runtime + true + + ${fuse.osgi.export} + ${fuse.osgi.import} + ${fuse.osgi.dynamic} + ${fuse.osgi.private.pkg} + + .,WEB-INF/classes + + ${project.description} + ${project.groupId}.${project.artifactId} + HawtIO + ${project.version} + + + + + + + org.apache.maven.plugins + maven-war-plugin + ${war-plugin-version} + + @{artifactId}@-@{baseVersion}@@{dashClassifier?}@.@{extension}@ + **/classes/OSGI-INF/** + false + + ${webapp-outdir}/META-INF/MANIFEST.MF + + + + true + src/main/resources + + **/*.* + + + log4j.properties + + + + + + + + + + diff --git a/artemis-hawtio/artemis-plugin/src/main/java/org/apache/activemq/hawtio/plugin/PluginContextListener.java b/artemis-hawtio/artemis-plugin/src/main/java/org/apache/activemq/hawtio/plugin/PluginContextListener.java new file mode 100644 index 0000000000..75fa7064b7 --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/java/org/apache/activemq/hawtio/plugin/PluginContextListener.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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.apache.activemq.hawtio.plugin; + +import io.hawt.web.plugin.HawtioPlugin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +/** + * The Plugin Context Listener used to load in the plugin + **/ +public class PluginContextListener implements ServletContextListener { + + private static final Logger LOG = LoggerFactory.getLogger(PluginContextListener.class); + + HawtioPlugin plugin = null; + + @Override + public void contextInitialized(ServletContextEvent servletContextEvent) { + + ServletContext context = servletContextEvent.getServletContext(); + + plugin = new HawtioPlugin(); + plugin.setContext((String)context.getInitParameter("plugin-context")); + plugin.setName(context.getInitParameter("plugin-name")); + plugin.setScripts(context.getInitParameter("plugin-scripts")); + plugin.setDomain(null); + + try { + plugin.init(); + } catch (Exception e) { + throw createServletException(e); + } + + LOG.info("Initialized {} plugin", plugin.getName()); + } + + @Override + public void contextDestroyed(ServletContextEvent servletContextEvent) { + try { + plugin.destroy(); + } catch (Exception e) { + throw createServletException(e); + } + + LOG.info("Destroyed {} plugin", plugin.getName()); + } + + protected RuntimeException createServletException(Exception e) { + return new RuntimeException(e); + } + +} \ No newline at end of file diff --git a/artemis-hawtio/artemis-plugin/src/main/resources/WEB-INF/web.xml b/artemis-hawtio/artemis-plugin/src/main/resources/WEB-INF/web.xml new file mode 100644 index 0000000000..b6c454e5d6 --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/resources/WEB-INF/web.xml @@ -0,0 +1,57 @@ + + + + + An Artemis Plugin + An Artemis plugin + + + Plugin's path on the server + plugin-context + ${plugin-context} + + + + Plugin's path on the server + plugin-name + ${project.artifactId} + + + + Plugin's path on the server + plugin-domain + ${plugin-domain} + + + + Plugin's path on the server + plugin-scripts + ${plugin-scripts} + + + + org.apache.activemq.hawtio.plugin.PluginContextListener + + + + + diff --git a/artemis-hawtio/artemis-plugin/src/main/resources/log4j.properties b/artemis-hawtio/artemis-plugin/src/main/resources/log4j.properties new file mode 100644 index 0000000000..52537ea702 --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/resources/log4j.properties @@ -0,0 +1,23 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You 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 +## +## http://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. +## --------------------------------------------------------------------------- + +log4j.rootLogger=INFO, console + +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%-5p | %t | %m%n + diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/doc/help.md b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/doc/help.md new file mode 100644 index 0000000000..e875acd8bc --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/doc/help.md @@ -0,0 +1,19 @@ +### Artemis + +Click [Artemis](#/jmx/attributes?tab=artemis) in the top navigation bar to see the Artemis specific plugin. (The Artemis tab won't appear if there is no broker in this JVM). The Artemis plugin works very much the same as the JMX plugin however with a focus on interacting with an Artemis broker. + +The tree view on the left-hand side shows the top level JMX tree of each broker instance running in the JVM. Expanding the tree will show the various MBeans registered by Artemis that you can inspect via the **Attributes** tab. + +#### Creating a new Address + +To create a new address simply click on the broker or the address folder in the jmx tree and click on the create tab. + +Once you have created an address you should be able to **Send** to it by clicking on it in the jmx tree and clicking on the send tab. + +#### Creating a new Queue + +To create a new queue click on the address you want to bind the queue to and click on the create tab. + +Once you have created a queue you should be able to **Send** a message to it or **Browse** it or view the **Attributes** or **Charts**. Simply click on the queue in th ejmx tree and click on the appropriate tab. + +You can also see a graphical view of all brokers, addresses, queues and their consumers using the **Diagram** tab. diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/artemisLayout.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/artemisLayout.html new file mode 100644 index 0000000000..eb254c971d --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/artemisLayout.html @@ -0,0 +1,42 @@ + + + +
+
+
+
+
+ +
+
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/brokerDiagram.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/brokerDiagram.html new file mode 100644 index 0000000000..9d0fd05ea4 --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/brokerDiagram.html @@ -0,0 +1,313 @@ + + + + +
+ +
+
+ +
+ + +
+ +
+ + View   + + + + +
+
+
+ + +
+
+
+
+ +
+
+
+
+
+
+
+
+
{{property.key}}:
+
+
+
+
+
+ +
+ +
+ + diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/browseQueue.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/browseQueue.html new file mode 100644 index 0000000000..650972c22c --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/browseQueue.html @@ -0,0 +1,156 @@ + +
+
+
+ +
+
+
+
+ + + + + + +
+
+
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+ + + + + + + +
+
+
+ +
+ +
+ +
+
Displaying body as
+
+
+ +
+
+ +
+
+

You are about to delete + + +

+

This operation cannot be undone so please be careful.

+
+
+ +
+
+

Move + + to:

+

+ You cannot undo this operation.
+ Though after the move you can always move the + + back again. +

+
+
+ +
+ diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/createAddress.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/createAddress.html new file mode 100644 index 0000000000..0eb2d0af0f --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/createAddress.html @@ -0,0 +1,44 @@ + +
+
+ +
+ +
+
+ +
+ + +
+ +
+
+ +
+
+ +
+
+
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/createQueue.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/createQueue.html new file mode 100644 index 0000000000..1d294faa8b --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/createQueue.html @@ -0,0 +1,77 @@ + +
+ +
+ +
+ +
+
+ +
+ + +
+ +
+
+ + +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+
+ +
+
+
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/deleteAddress.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/deleteAddress.html new file mode 100644 index 0000000000..afa3172338 --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/deleteAddress.html @@ -0,0 +1,48 @@ + +
+
+ +
+
+ + Warning: these operations cannot be undone. Please be careful! +
+
+
+
+
+
+ + +
+
+
+ +
+
+

You are about to delete the {{name().unescapeHTML()}} address

+

This operation cannot be undone so please be careful.

+
+
+ + + +
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/deleteQueue.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/deleteQueue.html new file mode 100644 index 0000000000..9caa7c302f --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/deleteQueue.html @@ -0,0 +1,62 @@ + +
+
+ +
+
+ + Warning: these operations cannot be undone. Please be careful! +
+
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+ +
+
+

You are about to delete the {{name().unescapeHTML()}} queue

+

This operation cannot be undone so please be careful.

+
+
+ +
+
+

You are about to purge the {{name().unescapeHTML()}} queue

+

This operation cannot be undone so please be careful.

+
+
+ + +
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/preferences.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/preferences.html new file mode 100644 index 0000000000..10fb619a65 --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/preferences.html @@ -0,0 +1,69 @@ + +
+
+ +
+ + +
+ +
+
+
+ + +
+ +
+
+ +
+ + +
+ +
+
+ +
+ + +
+ +
+
+ +
+ + +
+ + Browsing byte messages should display the message body as +
+
+ +
+
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/sendMessage.html b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/sendMessage.html new file mode 100644 index 0000000000..002b558467 --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/html/sendMessage.html @@ -0,0 +1,135 @@ + +
+ +
+ +
+ + +
+ + No credentials set for endpoint! Please set your username and password in the Preferences page + + +
+
+
+ + +
+ + + +
+ +
+
    +
    +
  1. +
    + +
    +
    + +
    +
    + + +
    +
  2. +
    +
+
+ +
+
+
+ + + + +
+
+
+ +
+ +
+
+ + +
+
+
+ +
+ + No credentials set for endpoint! Please set your username and password in the Preferences page + + +
+ +

Choose which files to send from the profile configuration:

+ +
+ +
+ +
    +
  • + {{fileName}} +
  • +
+
+
+ +
+ +
+
diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/address.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/address.js new file mode 100644 index 0000000000..cc0aef1a30 --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/address.js @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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. + */ +/** + * @module ARTEMIS + */ +var ARTEMIS = (function(ARTEMIS) { + + /** + * @method AddressController + * @param $scope + * @param ARTEMISService + * + * Controller for the Create interface + */ + ARTEMIS.AddressController = function ($scope, workspace, ARTEMISService, jolokia, localStorage) { + Core.initPreferenceScope($scope, localStorage, { + 'routingType': { + 'value': 0, + 'converter': parseInt, + 'formatter': parseInt + } + }); + var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis"; + $scope.workspace = workspace; + $scope.message = ""; + $scope.deleteDialog = false; + $scope.$watch('workspace.selection', function () { + workspace.moveIfViewInvalid(); + }); + function operationSuccess() { + $scope.addressName = ""; + $scope.workspace.operationCounter += 1; + Core.$apply($scope); + Core.notification("success", $scope.message); + $scope.workspace.loadTree(); + } + function deleteSuccess() { + // lets set the selection to the parent + workspace.removeAndSelectParentNode(); + $scope.workspace.operationCounter += 1; + Core.$apply($scope); + Core.notification("success", $scope.message); + $scope.workspace.loadTree(); + } + $scope.createAddress = function (name, routingType) { + var mbean = getBrokerMBean(jolokia); + if (mbean) { + if (routingType == 0) { + $scope.message = "Created Multicast Address " + name; + ARTEMIS.log.info($scope.message); + ARTEMISService.artemisConsole.createAddress(mbean, jolokia, name, "MULTICAST", onSuccess(operationSuccess)); + } + else if (routingType == 1) { + $scope.message = "Created Anycast Address " + name; + ARTEMIS.log.info($scope.message); + ARTEMISService.artemisConsole.createAddress(mbean, jolokia, name, "ANYCAST", onSuccess(operationSuccess)); + } + else { + $scope.message = "Created Anycast/Multicast Address " + name; + ARTEMIS.log.info($scope.message); + ARTEMISService.artemisConsole.createAddress(mbean, jolokia, name, "ANYCAST,MULTICAST", onSuccess(operationSuccess)); + } + } + }; + $scope.deleteAddress = function () { + var selection = workspace.selection; + var entries = selection.entries; + var mbean = getBrokerMBean(jolokia); + ARTEMIS.log.info(mbean); + if (mbean) { + if (selection && jolokia && entries) { + var domain = selection.domain; + var name = entries["name"]; + name = name.unescapeHTML(); + if (name.charAt(0) === '"' && name.charAt(name.length -1) === '"') + { + name = name.substr(1,name.length -2); + } + ARTEMIS.log.info(name); + var operation; + $scope.message = "Deleted address " + name; + ARTEMISService.artemisConsole.deleteAddress(mbean, jolokia, name, onSuccess(deleteSuccess)); + } + } + }; + $scope.name = function () { + var selection = workspace.selection; + if (selection) { + return selection.title; + } + return null; + }; + + function getBrokerMBean(jolokia) { + var mbean = null; + var selection = workspace.selection; + var folderNames = selection.folderNames; + mbean = "" + folderNames[0] + ":broker=" + folderNames[1]; + ARTEMIS.log.info("broker=" + mbean); + return mbean; + } + }; + + return ARTEMIS; +} (ARTEMIS || {})); \ No newline at end of file diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisHelpers.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisHelpers.js new file mode 100644 index 0000000000..210c52a4be --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisHelpers.js @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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. + */ +var ARTEMIS; +(function (ARTEMIS) { + ARTEMIS.log = Logger.get("ARTEMIS"); + ARTEMIS.jmxDomain = 'org.apache.ARTEMIS'; + function getSelectionQueuesFolder(workspace) { + function findQueuesFolder(node) { + if (node) { + if (node.title === "Queues" || node.title === "Queue") { + return node; + } + var parent = node.parent; + if (parent) { + return findQueuesFolder(parent); + } + } + return null; + } + var selection = workspace.selection; + if (selection) { + return findQueuesFolder(selection); + } + return null; + } + ARTEMIS.getSelectionQueuesFolder = getSelectionQueuesFolder; + function getSelectionTopicsFolder(workspace) { + function findTopicsFolder(node) { + var answer = null; + if (node) { + if (node.title === "Topics" || node.title === "Topic") { + answer = node; + } + if (answer === null) { + angular.forEach(node.children, function (child) { + if (child.title === "Topics" || child.title === "Topic") { + answer = child; + } + }); + } + } + return answer; + } + var selection = workspace.selection; + if (selection) { + return findTopicsFolder(selection); + } + return null; + } + ARTEMIS.getSelectionTopicsFolder = getSelectionTopicsFolder; + /** + * Sets $scope.row to currently selected JMS message. + * Used in: + * - ARTEMIS/js/browse.ts + * - camel/js/browseEndpoint.ts + * + * TODO: remove $scope argument and operate directly on other variables. but it's too much side effects here... + * + * @param message + * @param key unique key inside message that distinguishes between values + * @param $scope + */ + function selectCurrentMessage(message, key, $scope) { + // clicking on message's link would interfere with messages selected with checkboxes + $scope.gridOptions.selectAll(false); + var idx = Core.pathGet(message, ["rowIndex"]); + var jmsMessageID = Core.pathGet(message, ["entity", key]); + $scope.rowIndex = idx; + var selected = $scope.gridOptions.selectedItems; + selected.splice(0, selected.length); + if (idx >= 0 && idx < $scope.messages.length) { + $scope.row = $scope.messages.find(function (msg) { return msg[key] === jmsMessageID; }); + if ($scope.row) { + selected.push($scope.row); + } + } + else { + $scope.row = null; + } + } + ARTEMIS.selectCurrentMessage = selectCurrentMessage; + /** + * - Adds functions needed for message browsing with details + * - Adds a watch to deselect all rows after closing the slideout with message details + * TODO: export these functions too? + * + * @param $scope + */ + function decorate($scope) { + $scope.selectRowIndex = function (idx) { + $scope.rowIndex = idx; + var selected = $scope.gridOptions.selectedItems; + selected.splice(0, selected.length); + if (idx >= 0 && idx < $scope.messages.length) { + $scope.row = $scope.messages[idx]; + if ($scope.row) { + selected.push($scope.row); + } + } + else { + $scope.row = null; + } + }; + $scope.$watch("showMessageDetails", function () { + if (!$scope.showMessageDetails) { + $scope.row = null; + $scope.gridOptions.selectedItems.splice(0, $scope.gridOptions.selectedItems.length); + } + }); + } + ARTEMIS.decorate = decorate; +})(ARTEMIS || (ARTEMIS = {})); \ No newline at end of file diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisPlugin.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisPlugin.js new file mode 100644 index 0000000000..6f791698cc --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisPlugin.js @@ -0,0 +1,246 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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. + */ +/** + * @module ARTEMIS + * @main ARTEMIS + * + * The main entrypoint for the ARTEMIS module + * + */ +var ARTEMIS = (function(ARTEMIS) { + + /** + * @property pluginName + * @type {string} + * + * The name of this plugin + */ + ARTEMIS.pluginName = "ARTEMIS"; + + /** + * @property log + * @type {Logging.Logger} + * + * This plugin's logger instance + */ + ARTEMIS.log = Logger.get(ARTEMIS.pluginName); + + /** + * @property templatePath + * @type {string} + * + * The top level path to this plugin's partials + */ + ARTEMIS.templatePath = "../artemis-plugin/plugin/html/"; + + /** + * @property jmxDomain + * @type {string} + * + * The JMX domain this plugin mostly works with + */ + ARTEMIS.jmxDomain = "hawtio" + + /** + * @property mbeanType + * @type {string} + * + * The mbean type this plugin will work with + */ + ARTEMIS.mbeanType = "ARTEMISHandler"; + + /** + * @property mbean + * @type {string} + * + * The mbean's full object name + */ + ARTEMIS.mbean = ARTEMIS.jmxDomain + ":type=" + ARTEMIS.mbeanType; + + /** + * @property SETTINGS_KEY + * @type {string} + * + * The key used to fetch our settings from local storage + */ + ARTEMIS.SETTINGS_KEY = 'ARTEMISSettings'; + + /** + * @property module + * @type {object} + * + * This plugin's angularjs module instance + */ + ARTEMIS.module = angular.module(ARTEMIS.pluginName, ['bootstrap', 'ngResource', 'ui.bootstrap.dialog', 'hawtioCore', 'camel', 'hawtio-ui']); + + // set up the routing for this plugin, these are referenced by the subleveltabs added below + ARTEMIS.module.config(function($routeProvider) { + $routeProvider + .when('/artemis/createAddress', { + templateUrl: ARTEMIS.templatePath + 'createAddress.html' + }) + .when('/artemis/deleteAddress', { + templateUrl: ARTEMIS.templatePath + 'deleteAddress.html' + }) + .when('/artemis/deleteQueue', { + templateUrl: ARTEMIS.templatePath + 'deleteQueue.html' + }) + .when('/artemis/createQueue', { + templateUrl: ARTEMIS.templatePath + 'createQueue.html' + }) + .when('/artemis/browseQueue', { + templateUrl: ARTEMIS.templatePath + 'browseQueue.html' + }) + .when('/artemis/diagram', { + templateUrl: ARTEMIS.templatePath + 'brokerDiagram.html' + }) + .when('/artemis/sendMessage', { + templateUrl: ARTEMIS.templatePath + 'sendMessage.html' + }); + }); + + ARTEMIS.module.factory('artemisMessage', function () { + return { 'message': null }; + }); + + // one-time initialization happens in the run function + // of our module + ARTEMIS.module.run(function(workspace, viewRegistry, helpRegistry, preferencesRegistry, localStorage, jolokia, ARTEMISService, $rootScope) { + // let folks know we're actually running + ARTEMIS.log.info("plugin running " + jolokia); + + var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis"; + + ARTEMISService.initArtemis(); + + // tell hawtio that we have our own custom layout for + // our view + viewRegistry["artemis"] = ARTEMIS.templatePath + "artemisLayout.html"; + + helpRegistry.addUserDoc("artemis", "../artemis-plugin/plugin/doc/help.md", function () { + return workspace.treeContainsDomainAndProperties(artemisJmxDomain); + }); + + preferencesRegistry.addTab("Artemis", ARTEMIS.templatePath + "preferences.html", function () { + return workspace.treeContainsDomainAndProperties(artemisJmxDomain); + }); + + // Add a top level tab to hawtio's navigation bar + workspace.topLevelTabs.push({ + id: "artemis", + content: "Artemis", + title: "Artemis Broker", + isValid: function (workspace) { + return workspace.treeContainsDomainAndProperties(artemisJmxDomain); + }, + href: function () { + return "#/jmx/attributes?tab=artemis"; + }, + isActive: function () { + return workspace.isLinkActive("artemis"); + } + }); + + workspace.subLevelTabs.push({ + content: ' Create', + title: "Create a new address", + isValid: function (workspace) { + return isBroker(workspace, artemisJmxDomain) || isAddressFolder(workspace, artemisJmxDomain); + }, + href: function () { + return "#/artemis/createAddress"; + } + }); + + workspace.subLevelTabs.push({ + content: ' Delete', + title: "Delete an address", + isValid: function (workspace) { + return isAddress(workspace, artemisJmxDomain); + }, + href: function () { + return "#/artemis/deleteAddress"; + } + }); + + workspace.subLevelTabs.push({ + content: ' Create', + title: "Create a new queue", + isValid: function (workspace) { + return isAddress(workspace, artemisJmxDomain) + }, + href: function () { + return "#/artemis/createQueue" + } + }); + + workspace.subLevelTabs.push({ + content: ' Delete', + title: "Delete or purge this queue", + isValid: function (workspace) { + return isQueue(workspace, artemisJmxDomain) + }, + href: function () { + return "#/artemis/deleteQueue" + } + }); + + workspace.subLevelTabs.push({ + content: ' Browse', + title: "Browse the messages on the queue", + isValid: function (workspace) { return isQueue(workspace, artemisJmxDomain); }, + href: function () { return "#/artemis/browseQueue"; } + }); + + workspace.subLevelTabs.push({ + content: ' Send', + title: "Send a message to this address", + isValid: function (workspace) { return isAddress(workspace, artemisJmxDomain) || isQueue(workspace, artemisJmxDomain); }, + href: function () { return "#/artemis/sendMessage"; } + }); + + workspace.subLevelTabs.push({ + content: ' Diagram', + title: "View a diagram of the producers, destinations and consumers", + isValid: function (workspace) { return workspace.isTopTabActive("artemis") || workspace.selectionHasDomain(artemisJmxDomain); }, + href: function () { return "#/artemis/diagram"; } + }); +}); + + + function isBroker(workspace, domain) { + return workspace.hasDomainAndProperties(domain, {'broker': 'Broker'}, 3); + } + + function isAddressFolder(workspace, domain) { + return workspace.selectionHasDomainAndLastFolderName(domain, 'addresses'); + } + + function isAddress(workspace, domain) { + return workspace.hasDomainAndProperties(domain, {'component': 'addresses'}) && !workspace.hasDomainAndProperties(domain, {'subcomponent': 'queues'}); + } + + function isQueue(workspace, domain) { + return workspace.hasDomainAndProperties(domain, {'subcomponent': 'queues'}); + } + + return ARTEMIS; +}(ARTEMIS || {})); + +// Very important! Add our module to hawtioPluginLoader so it +// bootstraps our module +hawtioPluginLoader.addModule(ARTEMIS.pluginName); \ No newline at end of file diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisService.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisService.js new file mode 100644 index 0000000000..3d7aa559a0 --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/artemisService.js @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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. + */ +/** + * @module ARTEMIS + */ +var ARTEMIS = (function(ARTEMIS) { + + ARTEMIS.SERVER = 'Server Messages'; + + + // The ARTEMIS service handles the connection to + // the Artemis Jolokia server in the background + ARTEMIS.module.factory("ARTEMISService", function(jolokia, $rootScope) { + var self = { + artemisConsole: undefined, + + getVersion: function(jolokia) { + ARTEMIS.log.info("Connecting to ARTEMIS service: " + self.artemisConsole.getServerAttributes(jolokia)); + } , + initArtemis: function(broker) { + ARTEMIS.log.info("*************creating Artemis Console************"); + self.artemisConsole = new ArtemisConsole(); + } + }; + + return self; + }); + + return ARTEMIS; +}(ARTEMIS || {})); diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/brokerDiagram.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/brokerDiagram.js new file mode 100644 index 0000000000..3faa0939ac --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/brokerDiagram.js @@ -0,0 +1,665 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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. + */ +/** + * @module ARTEMIS + */ +var ARTEMIS = (function(ARTEMIS) { + ARTEMIS.BrokerDiagramController = function ($scope, $compile, $location, localStorage, ARTEMISService, jolokia, workspace, $routeParams) { + + Fabric.initScope($scope, $location, jolokia, workspace); + var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis"; + + $scope.selectedNode = null; + var defaultFlags = { + panel: true, + popup: false, + label: true, + group: false, + profile: false, + slave: false, + broker: true, + network: true, + container: false, + address: true, + queue: true, + consumer: true, + producer: true + }; + $scope.viewSettings = {}; + $scope.shapeSize = { + broker: 20, + queue: 14, + address: 14 + }; + var redrawGraph = Core.throttled(doRedrawGraph, 1000); + var graphBuilder = new ForceGraph.GraphBuilder(); + Core.bindModelToSearchParam($scope, $location, "searchFilter", "q", ""); + angular.forEach(defaultFlags, function (defaultValue, key) { + var modelName = "viewSettings." + key; + // bind model values to search params... + function currentValue() { + var answer = $location.search()[paramName] || defaultValue; + return answer === "false" ? false : answer; + } + + var paramName = key; + var value = currentValue(); + Core.pathSet($scope, modelName, value); + $scope.$watch(modelName, function () { + var current = Core.pathGet($scope, modelName); + var old = currentValue(); + if (current !== old) { + var defaultValue = defaultFlags[key]; + if (current !== defaultValue) { + if (!current) { + current = "false"; + } + $location.search(paramName, current); + } + else { + $location.search(paramName, null); + } + } + redrawGraph(); + }); + }); + $scope.connectToBroker = function () { + var selectedNode = $scope.selectedNode; + if (selectedNode) { + var container = selectedNode["brokerContainer"] || selectedNode; + connectToBroker(container, selectedNode["brokerName"]); + } + }; + function connectToBroker(container, brokerName, postfix) { + if (postfix === void 0) { + postfix = null; + } + + var view = "/jmx/attributes?tab=artemis"; + if (!postfix) { + if (brokerName) { + // lets default to the broker view + postfix = "nid=root-" + artemisJmxDomain + "-Broker-" + brokerName; + } + } + if (postfix) { + view += "&" + postfix; + } + var path = Core.url("/#" + view); + window.open(path, '_destination'); + window.focus(); + } + + $scope.connectToDestination = function () { + var selectedNode = $scope.selectedNode; + if (selectedNode) { + var container = selectedNode["brokerContainer"] || selectedNode; + var brokerName = selectedNode["brokerName"]; + var destinationType = selectedNode["destinationType"] || selectedNode["typeLabel"]; + var destinationName = selectedNode["destinationName"]; + var postfix = null; + if (brokerName && destinationType && destinationName) { + postfix = "nid=root-" + artemisJmxDomain + "-Broker-" + brokerName + "-" + destinationType + "-" + destinationName; + } + connectToBroker(container, brokerName, postfix); + } + }; + $scope.$on('$destroy', function (event) { + stopOldJolokia(); + }); + function stopOldJolokia() { + var oldJolokia = $scope.selectedNodeJolokia; + if (oldJolokia && oldJolokia !== jolokia) { + oldJolokia.stop(); + } + } + + $scope.$watch("selectedNode", function (newValue, oldValue) { + // lets cancel any previously registered thingy + if ($scope.unregisterFn) { + $scope.unregisterFn(); + $scope.unregisterFn = null; + } + var node = $scope.selectedNode; + if (node) { + var mbean = node.objectName; + var brokerContainer = node.brokerContainer || {}; + var nodeJolokia = node.jolokia || brokerContainer.jolokia || jolokia; + if (nodeJolokia !== $scope.selectedNodeJolokia) { + stopOldJolokia(); + $scope.selectedNodeJolokia = nodeJolokia; + if (nodeJolokia !== jolokia) { + var rate = Core.parseIntValue(localStorage['updateRate'] || "2000", "update rate"); + if (rate) { + nodeJolokia.start(rate); + } + } + } + var dummyResponse = {value: node.panelProperties || {}}; + if (mbean && nodeJolokia) { + ARTEMIS.log.debug("reading ", mbean, " on remote container"); + $scope.unregisterFn = Core.register(nodeJolokia, $scope, { + type: 'read', + mbean: mbean + }, onSuccess(renderNodeAttributes, { + error: function (response) { + // probably we've got a wrong mbean name? + // so lets render at least + renderNodeAttributes(dummyResponse); + Core.defaultJolokiaErrorHandler(response); + } + })); + } + else { + ARTEMIS.log.debug("no mbean or jolokia available, using dummy response"); + renderNodeAttributes(dummyResponse); + } + } + }); + function getDestinationTypeName(attributes) { + var prefix = attributes["DestinationTemporary"] ? "Temporary " : ""; + return prefix + (attributes["DestinationTopic"] ? "Topic" : "Queue"); + } + + var ignoreNodeAttributes = ["Broker", "BrokerId", "BrokerName", "Connection", "DestinationName", "DestinationQueue", "DestinationTemporary", "DestinationTopic",]; + var ignoreNodeAttributesByType = { + producer: ["Producer", "ProducerId"], + queue: ["Name", "MessageGroups", "MessageGroupType", "Subscriptions"], + topic: ["Name", "Subscriptions"], + broker: ["DataDirectory", "DurableTopicSubscriptions", "DynamicDestinationProducers", "InactiveDurableToppicSubscribers"] + }; + var brokerShowProperties = ["Version", "Started"]; + var onlyShowAttributesByType = { + broker: brokerShowProperties, + brokerSlave: brokerShowProperties + }; + + function renderNodeAttributes(response) { + var properties = []; + if (response) { + var value = response.value || {}; + $scope.selectedNodeAttributes = value; + var selectedNode = $scope.selectedNode || {}; + var brokerContainer = selectedNode['brokerContainer'] || {}; + var nodeType = selectedNode["type"]; + var brokerName = selectedNode["brokerName"]; + var containerId = selectedNode["container"] || brokerContainer["container"]; + var group = selectedNode["group"] || brokerContainer["group"]; + var jolokiaUrl = selectedNode["jolokiaUrl"] || brokerContainer["jolokiaUrl"]; + var profile = selectedNode["profile"] || brokerContainer["profile"]; + var version = selectedNode["version"] || brokerContainer["version"]; + var isBroker = nodeType && nodeType.startsWith("broker"); + var ignoreKeys = ignoreNodeAttributes.concat(ignoreNodeAttributesByType[nodeType] || []); + var onlyShowKeys = onlyShowAttributesByType[nodeType]; + angular.forEach(value, function (v, k) { + if (onlyShowKeys ? onlyShowKeys.indexOf(k) >= 0 : ignoreKeys.indexOf(k) < 0) { + var formattedValue = Core.humanizeValueHtml(v); + properties.push({key: Core.humanizeValue(k), value: formattedValue}); + } + }); + properties = properties.sortBy("key"); + var brokerProperty = null; + if (brokerName) { + var brokerHtml = '' + ' ' + brokerName + ''; + if (version && profile) { + var brokerLink = Fabric.brokerConfigLink(workspace, jolokia, localStorage, version, profile, brokerName); + if (brokerLink) { + brokerHtml += ' '; + } + } + var html = $compile(brokerHtml)($scope); + brokerProperty = {key: "Broker", value: html}; + if (!isBroker) { + properties.splice(0, 0, brokerProperty); + } + } + if (containerId) { + //var containerModel = "selectedNode" + (selectedNode['brokerContainer'] ? ".brokerContainer" : ""); + properties.splice(0, 0, { + key: "Container", + value: $compile('
')($scope) + }); + } + var destinationName = value["DestinationName"] || selectedNode["destinationName"]; + if (destinationName && (nodeType !== "queue" && nodeType !== "topic")) { + var destinationTypeName = getDestinationTypeName(value); + var html = createDestinationLink(destinationName, destinationTypeName); + properties.splice(0, 0, {key: destinationTypeName, value: html}); + } + var typeLabel = selectedNode["typeLabel"]; + var name = selectedNode["name"] || selectedNode["id"] || selectedNode['objectName']; + if (typeLabel) { + var html = name; + if (nodeType === "queue" || nodeType === "topic") { + html = createDestinationLink(name, nodeType); + } + var typeProperty = {key: typeLabel, value: html}; + if (isBroker && brokerProperty) { + typeProperty = brokerProperty; + } + properties.splice(0, 0, typeProperty); + } + } + $scope.selectedNodeProperties = properties; + Core.$apply($scope); + } + + /** + * Generates the HTML for a link to the destination + */ + function createDestinationLink(destinationName, destinationType) { + if (destinationType === void 0) { + destinationType = "queue"; + } + return $compile('' + destinationName + '')($scope); + } + + $scope.$watch("searchFilter", function (newValue, oldValue) { + redrawGraph(); + }); + // lets just use the current stuff from the workspace + $scope.$watch('workspace.tree', function () { + redrawGraph(); + }); + $scope.$on('jmxTreeUpdated', function () { + redrawGraph(); + }); + + function onBrokerData(response) { + if (response) { + var responseJson = angular.toJson(response.value); + if ($scope.responseJson === responseJson) { + return; + } + $scope.responseJson = responseJson; + $scope.brokers = response.value; + doRedrawGraph(); + } + } + + function redrawLocalBroker() { + var container = { + jolokia: jolokia + }; + var containerId = "local"; + $scope.activeContainers = { + containerId: container + }; + var brokers = []; + jolokia.search(artemisJmxDomain + ":broker=*", onSuccess(function (response) { + angular.forEach(response, function (objectName) { + var atts = ARTEMISService.artemisConsole.getServerAttributes(jolokia, objectName); + var val = atts.value; + var details = Core.parseMBean(objectName); + if (details) { + var properties = details['attributes']; + ARTEMIS.log.info("Got broker: " + objectName + " on container: " + containerId + " properties: " + angular.toJson(properties, true)); + if (properties) { + var master = true; + var brokerId = properties["broker"] || "unknown"; + var nodeId = val["NodeID"]; + var theBroker = { + brokerId: brokerId, + nodeId: nodeId + }; + brokers.push(theBroker); + if ($scope.viewSettings.broker) { + var broker = getOrAddBroker(master, brokerId, nodeId, containerId, container, properties); + } + } + } + }); + + redrawActiveContainers(brokers); + })); + } + + function redrawActiveContainers(brokers) { + // TODO delete any nodes from dead containers in containersToDelete + angular.forEach($scope.activeContainers, function (container, id) { + var containerJolokia = container.jolokia; + if (containerJolokia) { + onContainerJolokia(containerJolokia, container, id, brokers); + } + else { + Fabric.containerJolokia(jolokia, id, function (containerJolokia) { + return onContainerJolokia(containerJolokia, container, id, brokers); + }); + } + }); + $scope.graph = graphBuilder.buildGraph(); + Core.$apply($scope); + } + + function doRedrawGraph() { + graphBuilder = new ForceGraph.GraphBuilder(); + redrawLocalBroker(); + } + + function brokerNameMarkup(brokerName) { + return brokerName ? "

broker: " + brokerName + "

" : ""; + } + + function onContainerJolokia(containerJolokia, container, id, brokers) { + function createQueues(brokers) { + if ($scope.viewSettings.queue) { + containerJolokia.search(artemisJmxDomain + ":*,subcomponent=queues", onSuccess(function (response) { + angular.forEach(response, function (objectName) { + var details = Core.parseMBean(objectName); + if (details) { + var properties = details['attributes']; + if (properties) { + configureDestinationProperties(properties); + var brokerName = properties.broker; + var addressName = properties.address; + var typeName = "queue"; + var queueName = properties.queue; + var routingType = properties["routing-type"]; + var destination = getOrAddQueue(properties, typeName, routingType, queueName, addressName, brokerName); + } + } + }); + graphModelUpdated(); + createConsumersAndNetwork(brokers); + })); + } else { + createConsumersAndNetwork(brokers); + } + } + + function createAddresses(brokers) { + if ($scope.viewSettings.address) { + containerJolokia.search(artemisJmxDomain + ":*,component=addresses", onSuccess(function (response) { + angular.forEach(response, function (objectName) { + var details = Core.parseMBean(objectName); + if (details) { + var properties = details['attributes']; + if (properties) { + var brokerName = properties.broker; + var typeName = "address"; + var addressName = properties.address; + var destination = getOrAddAddress(properties, typeName, addressName, brokerName); + } + } + }); + createQueues(brokers); + graphModelUpdated(); + })); + } else { + createQueues(brokers); + } + } + + function createConsumersAndNetwork(brokers) { + angular.forEach(brokers, function (broker) { + mBean = artemisJmxDomain + ":broker=" + broker.brokerId; + // find consumers + if ($scope.viewSettings.consumer) { + ARTEMISService.artemisConsole.getConsumers(mBean, containerJolokia, onSuccess(function (properties) { + consumers = properties.value; + ARTEMIS.log.info(consumers); + angular.forEach(angular.fromJson(consumers), function (consumer) { + if (consumer) { + + configureDestinationProperties(consumer); + var consumerId = consumer.sessionID + "-" + consumer.consumerID; + if (consumerId) { + var queueName = consumer.queueName; + var consumerNode = getOrAddNode("consumer", consumerId, consumer, function () { + return { + typeLabel: "Consumer", + brokerContainer: container, + //objectName: "null", + jolokia: containerJolokia, + popup: { + title: "Consumer: " + consumerId, + content: "

client: " + (consumer.connectionID || "") + "

" + brokerNameMarkup(broker.brokerId) + } + }; + }); + addLinkIds("queue:\"" + queueName + "\"", consumerNode["id"], "consumer"); + } + } + }); + graphModelUpdated(); + })); + } + + + // find networks of brokers + if ($scope.viewSettings.network && $scope.viewSettings.broker) { + + ARTEMISService.artemisConsole.getRemoteBrokers(mBean, containerJolokia, onSuccess(function (properties) { + remoteBrokers = properties.value; + + ARTEMIS.log.info("remoteBrokers=" + angular.toJson(remoteBrokers)) + angular.forEach(angular.fromJson(remoteBrokers), function (remoteBroker) { + if (remoteBroker) { + ARTEMIS.log.info("remote=" + angular.toJson(remoteBroker)) + if (broker.nodeId != remoteBroker.nodeID) { + getOrAddBroker(true, "\"" + remoteBroker.live + "\"", remoteBroker.nodeID, "remote", null, properties); + addLinkIds("broker:" + broker.brokerId, "broker:" + "\"" + remoteBroker.live + "\"", "network"); + + var backup = remoteBroker.backup; + if (backup) { + getOrAddBroker(false, "\"" + backup + "\"", remoteBroker.nodeID, "remote", null, properties); + addLinkIds("broker:" + "\"" + remoteBroker.live + "\"", "broker:" + "\"" + backup + "\"", "network"); + } + } + else { + var backup = remoteBroker.backup; + if (backup) { + getOrAddBroker(false, "\"" + remoteBroker.backup + "\"", remoteBroker.nodeID, "remote", null, properties); + addLinkIds("broker:" + broker.brokerId, "broker:" + "\"" + remoteBroker.backup + "\"", "network"); + } + } + } + }); + graphModelUpdated(); + })); + } + }); + } + + if (containerJolokia) { + container.jolokia = containerJolokia; + function getOrAddQueue(properties, typeName, routingType, queueName, addressName, brokerName) { + var queue = getOrAddNode(typeName.toLowerCase(), queueName, properties, function () { + var objectName = ""; + if (addressName) { + objectName = artemisJmxDomain + ":broker=" + brokerName + ",component=addresses,address=" + addressName + ",subcomponent=queues,routing-type=" + routingType + ",queue=" + queueName; + + } + ARTEMIS.log.info(objectName); + var answer = { + typeLabel: typeName, + brokerContainer: container, + objectName: objectName, + jolokia: containerJolokia, + popup: { + title: "queue: " + queueName, + content: "address:" + addressName + } + }; + if (!addressName) { + containerJolokia.search(artemisJmxDomain + ":broker=" + brokerName + ",component=addresses,address=" + addressName + ",subcomponent=queues,routing-type=" + routingType + ",queue=" + queueName + ",*", onSuccess(function (response) { + if (response && response.length) { + answer.objectName = response[0]; + } + })); + } + return answer; + }); + if (queue && $scope.viewSettings.broker && addressName) { + addLinkIds("address:" + addressName, queue["id"], "queue"); + } + return queue; + } + + function getOrAddAddress(properties, typeName, destinationName, brokerName) { + var destination = getOrAddNode(typeName.toLowerCase(), destinationName, properties, function () { + var objectName = ""; + if (brokerName) { + objectName = artemisJmxDomain + ":broker=" + brokerName + ",component=addresses,address=" + destinationName; + } + var answer = { + typeLabel: typeName, + brokerContainer: container, + objectName: objectName, + jolokia: containerJolokia, + popup: { + title: typeName + ": " + destinationName, + content: brokerNameMarkup(brokerName) + } + }; + if (!brokerName) { + containerJolokia.search(artemisJmxDomain + ":broker=" + brokerName + ",component=addresses,address=" + destinationName + ",*", onSuccess(function (response) { + if (response && response.length) { + answer.objectName = response[0]; + } + })); + } + return answer; + }); + if (destination && $scope.viewSettings.broker && brokerName) { + addLinkIds(brokerNodeId(brokerName), destination["id"], "address"); + } + return destination; + } + + createAddresses(brokers); + } + } + + function graphModelUpdated() { + $scope.graph = graphBuilder.buildGraph(); + Core.$apply($scope); + } + + function getOrAddBroker(master, brokerId, nodeId, containerId, container, brokerStatus) { + var broker = null; + var brokerFlag = master ? $scope.viewSettings.broker : $scope.viewSettings.slave; + if (brokerFlag) { + broker = getOrAddNode("broker", brokerId, brokerStatus, function () { + return { + type: master ? "broker" : "brokerSlave", + typeLabel: master ? "Broker" : "Slave Broker", + popup: { + title: (master ? "Master" : "Slave") + " Broker: " + brokerId, + content: "

Container: " + containerId + "

Node ID: " + nodeId + } + }; + }); + if (!broker['objectName']) { + // lets try guess the mbean name + broker['objectName'] = artemisJmxDomain + ":broker=" + brokerId; + ARTEMIS.log.debug("Guessed broker mbean: " + broker['objectName']); + } + if (!broker['brokerContainer'] && container) { + broker['brokerContainer'] = container; + } + if (!broker['nodeID']) { + broker['nodeID'] = nodeId; + } + } + return broker; + } + + function getOrAddNode(typeName, id, properties, createFn) { + var node = null; + if (id) { + var nodeId = typeName + ":" + id; + node = graphBuilder.getNode(nodeId); + if (!node) { + var nodeValues = createFn(); + node = angular.copy(properties); + + angular.forEach(nodeValues, function (value, key) { + return node[key] = value; + }); + node['id'] = nodeId; + if (!node['type']) { + node['type'] = typeName; + } + if (!node['name']) { + node['name'] = id; + } + if (node) { + var size = $scope.shapeSize[typeName]; + if (size && !node['size']) { + node['size'] = size; + } + if (!node['summary']) { + node['summary'] = node['popup'] || ""; + } + if (!$scope.viewSettings.popup) { + delete node['popup']; + } + if (!$scope.viewSettings.label) { + delete node['name']; + } + // lets not add nodes which are defined as being disabled + var enabled = $scope.viewSettings[typeName]; + if (enabled || !angular.isDefined(enabled)) { + graphBuilder.addNode(node); + } + else { + } + } + } + } + return node; + } + + function addLink(object1, object2, linkType) { + if (object1 && object2) { + addLinkIds(object1.id, object2.id, linkType); + } + } + + function addLinkIds(id1, id2, linkType) { + ARTEMIS.log.info("adding " + id1 + " to " + id2 + " " + linkType) + if (id1 && id2) { + graphBuilder.addLink(id1, id2, linkType); + } + } + + function brokerNodeId(brokerId) { + return brokerId ? "broker:" + brokerId : null; + } + + /** + * Avoid the JMX type property clashing with the ForceGraph type property; used for associating css classes with nodes on the graph + * + * @param properties + */ + function renameTypeProperty(properties) { + properties.mbeanType = properties['type']; + delete properties['type']; + } + + function configureDestinationProperties(properties) { + renameTypeProperty(properties); + var destinationType = properties.destinationType || "Queue"; + var typeName = destinationType.toLowerCase(); + properties.isQueue = !typeName.startsWith("t"); + properties['destType'] = typeName; + } + }; + + return ARTEMIS; +} (ARTEMIS || {})); \ No newline at end of file diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/browse.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/browse.js new file mode 100644 index 0000000000..9ced888ec0 --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/browse.js @@ -0,0 +1,499 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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. + */ +/** + * @module ARTEMIS + */ +var ARTEMIS = (function(ARTEMIS) { + + ARTEMIS.BrowseQueueController = function ($scope, workspace, ARTEMISService, jolokia, localStorage, artemisMessage, $location, $timeout) { + $scope.searchText = ''; + $scope.allMessages = []; + $scope.messages = []; + $scope.headers = {}; + $scope.mode = 'text'; + $scope.deleteDialog = false; + $scope.moveDialog = false; + $scope.gridOptions = { + selectedItems: [], + data: 'messages', + displayFooter: false, + showFilter: false, + showColumnMenu: true, + enableColumnResize: true, + enableColumnReordering: true, + enableHighlighting: true, + filterOptions: { + filterText: '', + useExternalFilter: true + }, + selectWithCheckboxOnly: true, + showSelectionCheckbox: true, + maintainColumnRatios: false, + columnDefs: [ + { + field: 'messageID', + displayName: 'Message ID', + cellTemplate: '', + // for ng-grid + width: '10%' + }, + { + field: 'userID', + displayName: 'User ID', + width: '10%' + }, + { + field: 'type', + displayName: 'Type', + width: '10%' + }, + { + field: 'durable', + displayName: 'Durable', + width: '10%' + }, + { + field: 'priority', + displayName: 'Priority', + width: '7%' + }, + { + field: 'timestamp', + displayName: 'Timestamp', + width: '19%' + }, + { + field: 'expiration', + displayName: 'Expires', + width: '10%' + }, + { + field: 'redelivered', + displayName: 'Redelivered', + width: '10%' + } + ], + afterSelectionChange: afterSelectionChange + }; + $scope.showMessageDetails = false; + var ignoreColumns = ["PropertiesText", "BodyPreview", "text"]; + var flattenColumns = ["BooleanProperties", "ByteProperties", "ShortProperties", "IntProperties", "LongProperties", "FloatProperties", "DoubleProperties", "StringProperties"]; + $scope.$watch('workspace.selection', function () { + if (workspace.moveIfViewInvalid()) { + return; + } + // lets defer execution as we may not have the selection just yet + setTimeout(loadTable, 50); + }); + $scope.$watch('gridOptions.filterOptions.filterText', function (filterText) { + filterMessages(filterText); + }); + $scope.openMessageDialog = function (message) { + ARTEMIS.selectCurrentMessage(message, "messageID", $scope); + if ($scope.row) { + $scope.mode = CodeEditor.detectTextFormat($scope.row.Text); + $scope.showMessageDetails = true; + } + }; + $scope.refresh = loadTable; + ARTEMIS.decorate($scope); + $scope.moveMessages = function () { + var selection = workspace.selection; + var mbean = selection.objectName; + if (mbean && selection) { + var selectedItems = $scope.gridOptions.selectedItems; + $scope.message = "Moved " + Core.maybePlural(selectedItems.length, "message" + " to " + $scope.queueName); + var operation = "moveMessageTo(java.lang.String, java.lang.String)"; + angular.forEach(selectedItems, function (item, idx) { + var id = item.messageID; + if (id) { + var callback = (idx + 1 < selectedItems.length) ? intermediateResult : moveSuccess; + jolokia.execute(mbean, operation, id, $scope.queueName, onSuccess(callback)); + ARTEMISService.artemisConsole.moveMessage(mbean, jolokia, id, $scope.queueName, onSuccess(callback)); + } + }); + } + }; + $scope.resendMessage = function () { + var selection = workspace.selection; + var mbean = selection.objectName; + if (mbean && selection) { + var selectedItems = $scope.gridOptions.selectedItems; + //always assume a single message + artemisMessage.message = selectedItems[0]; + $location.path('artemis/sendMessage'); + } + }; + $scope.deleteMessages = function () { + var selection = workspace.selection; + var mbean = selection.objectName; + if (mbean && selection) { + var selectedItems = $scope.gridOptions.selectedItems; + $scope.message = "Deleted " + Core.maybePlural(selectedItems.length, "message"); + angular.forEach(selectedItems, function (item, idx) { + var id = item.messageID; + if (id) { + var callback = (idx + 1 < selectedItems.length) ? intermediateResult : operationSuccess; + ARTEMISService.artemisConsole.deleteMessage(mbean, jolokia, id, onSuccess(callback)); + } + }); + } + }; + $scope.retryMessages = function () { + var selection = workspace.selection; + var mbean = selection.objectName; + if (mbean && selection) { + var selectedItems = $scope.gridOptions.selectedItems; + $scope.message = "Retry " + Core.maybePlural(selectedItems.length, "message"); + var operation = "retryMessage(java.lang.String)"; + angular.forEach(selectedItems, function (item, idx) { + var id = item.messageID; + if (id) { + var callback = (idx + 1 < selectedItems.length) ? intermediateResult : operationSuccess; + jolokia.execute(mbean, operation, id, onSuccess(callback)); + ARTEMISService.artemisConsole.retryMessage(mbean, jolokia, id, onSuccess(callback)); + } + }); + } + }; + $scope.queueNames = function (completionText) { + var queuesFolder = ARTEMIS.getSelectionQueuesFolder(workspace); + if (queuesFolder) { + var selectedQueue = workspace.selection.key; + var otherQueues = queuesFolder.children.exclude(function (child) { + return child.key == selectedQueue; + }); + return (otherQueues) ? otherQueues.map(function (n) { + return n.title; + }) : []; + } + else { + return []; + } + }; + function populateTable(response) { + var data = response.value; + ARTEMIS.log.info("loading data:" + data); + + if (!angular.isArray(data)) { + $scope.allMessages = []; + angular.forEach(data, function (value, idx) { + $scope.allMessages.push(value); + }); + } + else { + $scope.allMessages = data; + } + angular.forEach($scope.allMessages, function (message) { + message.headerHtml = createHeaderHtml(message); + message.bodyText = createBodyText(message); + }); + filterMessages($scope.gridOptions.filterOptions.filterText); + Core.$apply($scope); + } + + /* + * For some reason using ng-repeat in the modal dialog doesn't work so lets + * just create the HTML in code :) + */ + function createBodyText(message) { + + ARTEMIS.log.info("loading message:" + message); + if (message.text) { + var body = message.text; + var lenTxt = "" + body.length; + message.textMode = "text (" + lenTxt + " chars)"; + return body; + } + else if (message.BodyPreview) { + var code = Core.parseIntValue(localStorage["ARTEMISBrowseBytesMessages"] || "1", "browse bytes messages"); + var body; + message.textMode = "bytes (turned off)"; + if (code != 99) { + var bytesArr = []; + var textArr = []; + message.BodyPreview.forEach(function (b) { + if (code === 1 || code === 2) { + // text + textArr.push(String.fromCharCode(b)); + } + if (code === 1 || code === 4) { + // hex and must be 2 digit so they space out evenly + var s = b.toString(16); + if (s.length === 1) { + s = "0" + s; + } + bytesArr.push(s); + } + else { + // just show as is without spacing out, as that is usually more used for hex than decimal + var s = b.toString(10); + bytesArr.push(s); + } + }); + var bytesData = bytesArr.join(" "); + var textData = textArr.join(""); + if (code === 1 || code === 2) { + // bytes and text + var len = message.BodyPreview.length; + var lenTxt = "" + textArr.length; + body = "bytes:\n" + bytesData + "\n\ntext:\n" + textData; + message.textMode = "bytes (" + len + " bytes) and text (" + lenTxt + " chars)"; + } + else { + // bytes only + var len = message.BodyPreview.length; + body = bytesData; + message.textMode = "bytes (" + len + " bytes)"; + } + } + return body; + } + else { + message.textMode = "unsupported"; + return "Unsupported message body type which cannot be displayed by hawtio"; + } + } + + /* + * For some reason using ng-repeat in the modal dialog doesn't work so lets + * just create the HTML in code :) + */ + function createHeaderHtml(message) { + var headers = createHeaders(message); + var properties = createProperties(message); + var headerKeys = Object.extended(headers).keys(); + + function sort(a, b) { + if (a > b) + return 1; + if (a < b) + return -1; + return 0; + } + + var propertiesKeys = Object.extended(properties).keys().sort(sort); + var jmsHeaders = headerKeys.filter(function (key) { + return key.startsWith("JMS"); + }).sort(sort); + var remaining = headerKeys.subtract(jmsHeaders, propertiesKeys).sort(sort); + var buffer = []; + + function appendHeader(key) { + var value = headers[key]; + if (value === null) { + value = ''; + } + buffer.push('Header - ' + key + '' + value + ''); + } + + function appendProperty(key) { + var value = properties[key]; + if (value === null) { + value = ''; + } + buffer.push('' + key + '' + value + ''); + } + + jmsHeaders.forEach(appendHeader); + remaining.forEach(appendHeader); + propertiesKeys.forEach(appendProperty); + return buffer.join("\n"); + } + + function createHeaders(row) { + var answer = {}; + angular.forEach(row, function (value, key) { + if (!ignoreColumns.any(key) && !flattenColumns.any(key)) { + answer[Core.escapeHtml(key)] = Core.escapeHtml(value); + } + }); + return answer; + } + + function createProperties(row) { + ARTEMIS.log.debug("properties: ", row); + var answer = {}; + angular.forEach(row, function (value, key) { + if (!ignoreColumns.any(key) && flattenColumns.any(key)) { + angular.forEach(value, function (v2, k2) { + answer['' + key.replace('Properties', ' Property') + ' - ' + Core.escapeHtml(k2)] = Core.escapeHtml(v2); + }); + } + }); + return answer; + } + + function loadTable() { + ARTEMIS.log.info("loading table") + var objName; + $scope.gridOptions.selectedItems.length = 0; + if (workspace.selection) { + objName = workspace.selection.objectName; + } + else { + // in case of refresh + var key = location.search()['nid']; + var node = workspace.keyToNodeMap[key]; + objName = node.objectName; + } + if (objName) { + $scope.dlq = false; + var queueName = jolokia.getAttribute(objName, "Name"); + + var artemisDLQ = localStorage['artemisDLQ'] || "DLQ"; + var artemisExpiryQueue = localStorage['artemisExpiryQueue'] || "ExpiryQueue"; + ARTEMIS.log.info("loading table" + artemisExpiryQueue); + if (queueName == artemisDLQ || queueName == artemisExpiryQueue) { + onDlq(true); + } + else { + onDlq(false); + } + ARTEMISService.artemisConsole.browse(objName, jolokia, onSuccess(populateTable)); + } + } + + function onDlq(response) { + ARTEMIS.log.info("onDLQ=" + response); + $scope.dlq = response; + Core.$apply($scope); + } + + function intermediateResult() { + } + + function operationSuccess() { + $scope.messageDialog = false; + deselectAll(); + Core.notification("success", $scope.message); + loadTable(); + setTimeout(loadTable, 50); + } + + function moveSuccess() { + operationSuccess(); + workspace.loadTree(); + } + + function filterMessages(filter) { + var searchConditions = buildSearchConditions(filter); + evalFilter(searchConditions); + } + + function evalFilter(searchConditions) { + if (!searchConditions || searchConditions.length === 0) { + $scope.messages = $scope.allMessages; + } + else { + ARTEMIS.log.debug("Filtering conditions:", searchConditions); + $scope.messages = $scope.allMessages.filter(function (message) { + ARTEMIS.log.debug("Message:", message); + var matched = true; + $.each(searchConditions, function (index, condition) { + if (!condition.column) { + matched = matched && evalMessage(message, condition.regex); + } + else { + matched = matched && (message[condition.column] && condition.regex.test(message[condition.column])) || (message.StringProperties && message.StringProperties[condition.column] && condition.regex.test(message.StringProperties[condition.column])); + } + }); + return matched; + }); + } + } + + function evalMessage(message, regex) { + var jmsHeaders = ['JMSDestination', 'JMSDeliveryMode', 'JMSExpiration', 'JMSPriority', 'JMSmessageID', 'JMSTimestamp', 'JMSCorrelationID', 'JMSReplyTo', 'JMSType', 'JMSRedelivered']; + for (var i = 0; i < jmsHeaders.length; i++) { + var header = jmsHeaders[i]; + if (message[header] && regex.test(message[header])) { + return true; + } + } + if (message.StringProperties) { + for (var property in message.StringProperties) { + if (regex.test(message.StringProperties[property])) { + return true; + } + } + } + if (message.bodyText && regex.test(message.bodyText)) { + return true; + } + return false; + } + + function getRegExp(str, modifiers) { + try { + return new RegExp(str, modifiers); + } + catch (err) { + return new RegExp(str.replace(/(\^|\$|\(|\)|<|>|\[|\]|\{|\}|\\|\||\.|\*|\+|\?)/g, '\\$1')); + } + } + + function buildSearchConditions(filterText) { + var searchConditions = []; + var qStr; + if (!(qStr = $.trim(filterText))) { + return; + } + var columnFilters = qStr.split(";"); + for (var i = 0; i < columnFilters.length; i++) { + var args = columnFilters[i].split(':'); + if (args.length > 1) { + var columnName = $.trim(args[0]); + var columnValue = $.trim(args[1]); + if (columnName && columnValue) { + searchConditions.push({ + column: columnName, + columnDisplay: columnName.replace(/\s+/g, '').toLowerCase(), + regex: getRegExp(columnValue, 'i') + }); + } + } + else { + var val = $.trim(args[0]); + if (val) { + searchConditions.push({ + column: '', + regex: getRegExp(val, 'i') + }); + } + } + } + return searchConditions; + } + + function afterSelectionChange(rowItem, checkAll) { + if (checkAll === void 0) { + // then row was clicked, not select-all checkbox + $scope.gridOptions['$gridScope'].allSelected = rowItem.config.selectedItems.length == $scope.messages.length; + } + else { + $scope.gridOptions['$gridScope'].allSelected = checkAll; + } + } + + function deselectAll() { + $scope.gridOptions['$gridScope'].allSelected = false; + } + } + + return ARTEMIS; + } (ARTEMIS || {})); \ No newline at end of file diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/jmsHeaderSchema.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/jmsHeaderSchema.js new file mode 100644 index 0000000000..89bbd9d27f --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/jmsHeaderSchema.js @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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. + */ +var ARTEMIS; +(function (ARTEMIS) { + ARTEMIS.jmsHeaderSchema = { + definitions: { + headers: { + properties: { + JMSCorrelationID: { + type: "java.lang.String" + }, + JMSDeliveryMode: { + "type": "string", + "enum": [ + "PERSISTENT", + "NON_PERSISTENT" + ] + }, + JMSDestination: { + type: "javax.jms.Destination" + }, + JMSExpiration: { + type: "long" + }, + JMSPriority: { + type: "int" + }, + JMSReplyTo: { + type: "javax.jms.Destination" + }, + JMSType: { + type: "java.lang.String" + }, + JMSXGroupId: { + type: "java.lang.String" + }, + _AMQ_SCHED_DELIVERY: { + type: "java.lang.String" + } + } + }, + "javax.jms.Destination": { + type: "java.lang.String" + } + } + }; +})(ARTEMIS || (ARTEMIS = {})); +//# sourceMappingURL=jmsHeaderSchema.js.map \ No newline at end of file diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/preferences.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/preferences.js new file mode 100644 index 0000000000..f66d7d9cc0 --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/preferences.js @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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. + */ +/** + * @module ARTEMIS + */ +var ARTEMIS = (function(ARTEMIS) { + + /** + * @method PreferencesController + * @param $scope + * + * Controller for the Preferences interface + */ + ARTEMIS.PreferencesController = function ($scope, localStorage, userDetails, $rootScope) { + Core.initPreferenceScope($scope, localStorage, { + 'artemisUserName': { + 'value': userDetails.username + }, + 'artemisPassword': { + 'value': userDetails.password + }, + 'artemisDLQ': { + 'value': "DLQ" + }, + 'artemisExpiryQueue': { + 'value': "ExpiryQueue" + }, + 'artemisBrowseBytesMessages': { + 'value': 1, + 'converter': parseInt, + 'formatter': function (value) { + return "" + value; + } + } + }); + }; + + return ARTEMIS; + +}(ARTEMIS || {})); \ No newline at end of file diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/queue.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/queue.js new file mode 100644 index 0000000000..1cfb2de551 --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/queue.js @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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. + */ +/** + * @module ARTEMIS + */ +var ARTEMIS = (function(ARTEMIS) { + + /** + * @method QueueController + * @param $scope + * @param ARTEMISService + * + * Controller for the Create interface + */ + ARTEMIS.QueueController = function ($scope, workspace, ARTEMISService, jolokia, localStorage) { + Core.initPreferenceScope($scope, localStorage, { + 'durable': { + 'value': true, + 'converter': Core.parseBooleanValue + }, + 'routingType': { + 'value': 0, + 'converter': parseInt, + 'formatter': parseInt + }, + 'maxConsumers': { + 'value': -1, + 'converter': parseInt, + 'formatter': parseInt + }, + 'purgeWhenNoConsumers': { + 'value': false, + 'converter': Core.parseBooleanValue + } + }); + var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis"; + $scope.workspace = workspace; + $scope.message = ""; + $scope.queueType = 'true'; + $scope.deleteDialog = false; + $scope.purgeDialog = false; + $scope.$watch('workspace.selection', function () { + workspace.moveIfViewInvalid(); + }); + function operationSuccess() { + $scope.queueName = ""; + $scope.workspace.operationCounter += 1; + Core.$apply($scope); + Core.notification("success", $scope.message); + $scope.workspace.loadTree(); + } + function deleteSuccess() { + // lets set the selection to the parent + workspace.removeAndSelectParentNode(); + $scope.workspace.operationCounter += 1; + Core.$apply($scope); + Core.notification("success", $scope.message); + $scope.workspace.loadTree(); + } + $scope.createQueue = function (queueName, routingType, durable, filter, maxConsumers, purgeWhenNoConsumers) { + var mbean = getBrokerMBean(jolokia); + if (mbean) { + var selection = workspace.selection; + var entries = selection.entries; + var address = entries["address"]; + if (address.charAt(0) === '"' && address.charAt(address.length -1) === '"') + { + address = address.substr(1,address.length -2); + } + $scope.message = "Created queue " + queueName + " durable=" + durable + " filter=" + filter + " on address " + address; + if (routingType == 0) { + ARTEMIS.log.info($scope.message); + ARTEMISService.artemisConsole.createQueue(mbean, jolokia, address, "MULTICAST", queueName, durable, filter, maxConsumers, purgeWhenNoConsumers, onSuccess(operationSuccess)); + ARTEMIS.log.info("executed"); + } else { + ARTEMIS.log.info($scope.message); + ARTEMISService.artemisConsole.createQueue(mbean, jolokia, address, "ANYCAST", queueName, durable, filter, maxConsumers, purgeWhenNoConsumers, onSuccess(operationSuccess)); + ARTEMIS.log.info("executed"); + } + } + }; + $scope.deleteDestination = function (isQueue) { + var selection = workspace.selection; + var entries = selection.entries; + var mbean = getBrokerMBean(jolokia); + ARTEMIS.log.info(mbean); + if (mbean) { + if (selection && jolokia && entries) { + var domain = selection.domain; + var name = entries["Destination"] || entries["destinationName"] || selection.title; + name = name.replace(/['"]+/g, ''); + ARTEMIS.log.info(name); + var operation; + if (isQueue) { + $scope.message = "Deleted queue " + name; + ARTEMISService.artemisConsole.deleteQueue(mbean, jolokia, name, onSuccess(deleteSuccess)); + } + else { + $scope.message = "Deleted topic " + name; + ARTEMISService.artemisConsole.deleteTopic(mbean, jolokia, name, onSuccess(deleteSuccess)); + } + } + } + }; + $scope.purgeDestination = function () { + var selection = workspace.selection; + var entries = selection.entries; + var mbean = getBrokerMBean(jolokia); + if (mbean) { + if (selection && jolokia && entries) { + var name = entries["Destination"] || entries["destinationName"] || selection.title; + name = name.unescapeHTML(); + var operation = "purge()"; + $scope.message = "Purged queue " + name; + ARTEMISService.artemisConsole.purgeQueue(mbean, jolokia, name, onSuccess(deleteSuccess)); + } + } + }; + $scope.name = function () { + var selection = workspace.selection; + if (selection) { + return selection.title; + } + return null; + }; + + function getBrokerMBean(jolokia) { + var mbean = null; + var selection = workspace.selection; + var folderNames = selection.folderNames; + mbean = "" + folderNames[0] + ":broker=" + folderNames[1]; + ARTEMIS.log.info("broker=" + mbean); + return mbean; + } + }; + + return ARTEMIS; +} (ARTEMIS || {})); \ No newline at end of file diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/send.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/send.js new file mode 100644 index 0000000000..1301387ba6 --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/send.js @@ -0,0 +1,211 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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. + */ +/** + * @module ARTEMIS + */ +var ARTEMIS; +(function (ARTEMIS) { + var DELIVERY_PERSISTENT = "2"; + ARTEMIS.SendMessageController = function($route, $scope, $element, $timeout, workspace, ARTEMISService, jolokia, localStorage, $location, artemisMessage) { + Core.initPreferenceScope($scope, localStorage, { + 'durable': { + 'value': true, + 'converter': Core.parseBooleanValue + } + }); + var log = Logger.get("ARTEMIS"); + $scope.noCredentials = false; + $scope.showChoose = false; + $scope.profileFileNames = []; + $scope.profileFileNameToProfileId = {}; + $scope.selectedFiles = {}; + $scope.container = {}; + $scope.message = "\n\n\n\n"; + $scope.headers = []; + // bind model values to search params... + Core.bindModelToSearchParam($scope, $location, "tab", "subtab", "compose"); + Core.bindModelToSearchParam($scope, $location, "searchText", "q", ""); + // only reload the page if certain search parameters change + Core.reloadWhenParametersChange($route, $scope, $location); + $scope.checkCredentials = function () { + ARTEMIS.log.info(localStorage['artemisUserName'] + " " + localStorage['artemisPassword']); + $scope.noCredentials = (Core.isBlank(localStorage['artemisUserName']) || Core.isBlank(localStorage['artemisPassword'])); + }; + if ($location.path().has('artemis')) { + $scope.localStorage = localStorage; + $scope.$watch('localStorage.artemisUserName', $scope.checkCredentials); + $scope.$watch('localStorage.artemisPassword', $scope.checkCredentials); + //prefill if it's a resent + if (artemisMessage.message !== null) { + $scope.message = artemisMessage.message.bodyText; + if (artemisMessage.message.PropertiesText !== null) { + for (var p in artemisMessage.message.StringProperties) { + $scope.headers.push({name: p, value: artemisMessage.message.StringProperties[p]}); + } + } + } + // always reset at the end + artemisMessage.message = null; + } + $scope.openPrefs = function () { + $location.search('pref', 'Artemis'); + $scope.$emit("hawtioOpenPrefs"); + }; + var LANGUAGE_FORMAT_PREFERENCE = "defaultLanguageFormat"; + var sourceFormat = workspace.getLocalStorage(LANGUAGE_FORMAT_PREFERENCE) || "javascript"; + // TODO Remove this if possible + $scope.codeMirror = undefined; + var options = { + mode: { + name: sourceFormat + }, + // Quick hack to get the codeMirror instance. + onChange: function (codeMirror) { + if (!$scope.codeMirror) { + $scope.codeMirror = codeMirror; + } + } + }; + $scope.codeMirrorOptions = CodeEditor.createEditorSettings(options); + $scope.addHeader = function () { + $scope.headers.push({name: "", value: ""}); + // lets set the focus to the last header + if ($element) { + $timeout(function () { + var lastHeader = $element.find("input.headerName").last(); + lastHeader.focus(); + }, 100); + } + }; + $scope.removeHeader = function (header) { + $scope.headers = $scope.headers.remove(header); + }; + $scope.defaultHeaderNames = function () { + var answer = []; + + function addHeaderSchema(schema) { + angular.forEach(schema.definitions.headers.properties, function (value, name) { + answer.push(name); + }); + } + + if (isJmsEndpoint()) { + addHeaderSchema(ARTEMIS.jmsHeaderSchema); + } + /*if (isARTEMISEndpoint()) { + addHeaderSchema(ARTEMIS.ARTEMISHeaderSchema); + }*/ + return answer; + }; + /* save the sourceFormat in preferences for later + * Note, this would be controller specific preferences and not the global, overriding, preferences */ + // TODO Use ng-selected="changeSourceFormat()" - Although it seemed to fire multiple times.. + $scope.$watch('codeMirrorOptions.mode.name', function (newValue, oldValue) { + workspace.setLocalStorage(LANGUAGE_FORMAT_PREFERENCE, newValue); + }); + var sendWorked = function () { + Core.notification("success", "Message sent!"); + }; + $scope.autoFormat = function () { + setTimeout(function () { + CodeEditor.autoFormatEditor($scope.codeMirror); + }, 50); + }; + $scope.sendMessage = function (durable) { + var body = $scope.message; + ARTEMIS.log.info(body); + doSendMessage(durable, body, sendWorked); + }; + function doSendMessage(durable, body, onSendCompleteFn) { + var selection = workspace.selection; + if (selection) { + var mbean = selection.objectName; + if (mbean) { + var headers = null; + if ($scope.headers.length) { + headers = {}; + angular.forEach($scope.headers, function (object) { + var key = object.name; + if (key) { + headers[key] = object.value; + } + }); + log.info("About to send headers: " + JSON.stringify(headers)); + } + var callback = onSuccess(onSendCompleteFn); + + ARTEMIS.log.info("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); + var user = localStorage["artemisUserName"]; + var pwd = localStorage["artemisPassword"]; + // AMQ is sending non persistent by default, so make sure we tell to sent persistent by default + if (!headers) { + headers = {}; + } + var type = 3; + ARTEMISService.artemisConsole.sendMessage(mbean, jolokia, headers, type, body, durable, user, pwd, callback, onSuccess(callback)); + + } + } + } + + $scope.fileSelection = function () { + var answer = []; + angular.forEach($scope.selectedFiles, function (value, key) { + if (value) { + answer.push(key); + } + }); + return answer; + }; + $scope.sendSelectedFiles = function () { + var filesToSend = $scope.fileSelection(); + var fileCount = filesToSend.length; + var version = $scope.container.versionId || "1.0"; + + function onSendFileCompleted(response) { + if (filesToSend.length) { + var fileName = filesToSend.pop(); + if (fileName) { + // lets load the file data... + var profile = $scope.profileFileNameToProfileId[fileName]; + if (profile) { + var body = Fabric.getConfigFile(jolokia, version, profile, fileName); + if (!body) { + log.warn("No body for message " + fileName); + body = ""; + } + doSendMessage(body, onSendFileCompleted); + } + } + } + else { + var text = Core.maybePlural(fileCount, "Message") + " sent!"; + Core.notification("success", text); + } + } + + // now lets start sending + onSendFileCompleted(null); + }; + + function isJmsEndpoint() { + // TODO check for the jms/activemq endpoint in ARTEMIS or if its an activemq endpoint + return true; + } + }; + return ARTEMIS; +} (ARTEMIS || {})); \ No newline at end of file diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/tree.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/tree.js new file mode 100644 index 0000000000..87c04f4b51 --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/tree.js @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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. + */ +/// +var ARTEMIS; +(function (ARTEMIS) { + ARTEMIS.module.controller("ARTEMIS.TreeHeaderController", ["$scope", function ($scope) { + $scope.expandAll = function () { + Tree.expandAll("#artemistree"); + }; + $scope.contractAll = function () { + Tree.contractAll("#artemistree"); + }; + }]); + ARTEMIS.module.controller("ARTEMIS.TreeController", ["$scope", "$location", "workspace", "localStorage", function ($scope, $location, workspace, localStorage) { + var artemisJmxDomain = localStorage['artemisJmxDomain'] || "org.apache.activemq.artemis"; + ARTEMIS.log.info("init tree " + artemisJmxDomain); + $scope.$on("$routeChangeSuccess", function (event, current, previous) { + // lets do this asynchronously to avoid Error: $digest already in progress + setTimeout(updateSelectionFromURL, 50); + }); + $scope.$watch('workspace.tree', function () { + reloadTree(); + }); + $scope.$on('jmxTreeUpdated', function () { + reloadTree(); + }); + function reloadTree() { + ARTEMIS.log.info("workspace tree has changed, lets reload the artemis tree"); + var children = []; + var tree = workspace.tree; + + ARTEMIS.log.info("tree="+tree); + if (tree) { + var domainName = artemisJmxDomain; + var folder = tree.get(domainName); + + ARTEMIS.log.info("folder="+folder); + if (folder) { + children = folder.children; + } + var treeElement = $("#artemistree"); + Jmx.enableTree($scope, $location, workspace, treeElement, children, true); + // lets do this asynchronously to avoid Error: $digest already in progress + setTimeout(updateSelectionFromURL, 50); + } + } + function updateSelectionFromURL() { + Jmx.updateTreeSelectionFromURLAndAutoSelect($location, $("#artemistree"), function (first) { + // use function to auto select the queue folder on the 1st broker + var jms = first.getChildren()[0]; + ARTEMIS.log.info("%%%%%%" + jms); + var queues = jms.getChildren()[0]; + if (queues && queues.data.title === 'Queue') { + first = queues; + first.expand(true); + return first; + } + return null; + }, true); + } + }]); +})(ARTEMIS || (ARTEMIS = {})); \ No newline at end of file diff --git a/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/lib/artemis-console.js b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/lib/artemis-console.js new file mode 100644 index 0000000000..948127b1c8 --- /dev/null +++ b/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/lib/artemis-console.js @@ -0,0 +1,82 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You 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 + + http://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. + Architecture + */ +function ArtemisConsole() { + + this.getServerAttributes = function (jolokia, mBean) { + var req1 = { type: "read", mbean: mBean}; + return jolokia.request(req1, {method: "post"}); + }; + + this.createAddress = function (mbean, jolokia, name, routingType, method) { + jolokia.execute(mbean, "createAddress(java.lang.String,java.lang.String)", name, routingType, method); + }; + + this.deleteAddress = function (mbean, jolokia, name, method) { + jolokia.execute(mbean, "deleteAddress(java.lang.String)", name, method); + }; + + this.createQueue = function (mbean, jolokia, address, routingType, name, durable, filter, maxConsumers, purgeWhenNoConsumers, method) { + jolokia.execute(mbean, "createQueue(java.lang.String,java.lang.String,java.lang.String,java.lang.String,boolean,int,boolean,boolean)", address, routingType, name, filter, durable, maxConsumers, purgeWhenNoConsumers, true, method); + }; + + this.deleteQueue = function (mbean, jolokia, name, method) { + jolokia.execute(mbean, "destroyQueue(java.lang.String)", name, method); + }; + + this.purgeQueue = function (mbean, jolokia, name, method) { + //todo + }; + + this.browse = function (mbean, jolokia, method) { + jolokia.request({ type: 'exec', mbean: mbean, operation: 'browse()' }, method); + }; + + this.deleteMessage = function (mbean, jolokia, id, method) { + ARTEMIS.log.info("executing on " + mbean); + jolokia.execute(mbean, "removeMessage(long)", id, method); + }; + + this.moveMessage = function (mbean, jolokia, id, queueName, method) { + jolokia.execute(mbean, "moveMessage(java.lang.String,java.lang.String)", id, queueName, method); + }; + + this.retryMessage = function (mbean, jolokia, id, method) { + jolokia.execute(mbean, "retryMessage(java.lang.String)", id, method); + }; + + this.sendMessage = function (mbean, jolokia, headers, type, body, durable, user, pwd, method) { + jolokia.execute(mbean, "sendMessage(java.util.Map, int, java.lang.String, boolean, java.lang.String, java.lang.String)", headers, type, body, durable, user, pwd, method); + }; + + this.getConsumers = function (mbean, jolokia, method) { + jolokia.request({ type: 'exec', mbean: mbean, operation: 'listAllConsumersAsJSON()' }, method); + }; + + this.getRemoteBrokers = function (mbean, jolokia, method) { + jolokia.request({ type: 'exec', mbean: mbean, operation: 'listNetworkTopology()' }, method); + }; +} + +function getServerAttributes() { + var console = new ArtemisConsole(); + return console.getVersion(new Jolokia("http://localhost:8161/jolokia/")); +} + + + + diff --git a/artemis-hawtio/pom.xml b/artemis-hawtio/pom.xml index a12046de43..7c60dd9d73 100644 --- a/artemis-hawtio/pom.xml +++ b/artemis-hawtio/pom.xml @@ -98,6 +98,7 @@ activemq-branding + artemis-plugin