activemq-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From clebertsuco...@apache.org
Subject [1/6] activemq-artemis git commit: ARTEMIS-1270 Management Console - Hawtio Solution
Date Tue, 01 Aug 2017 20:18:06 GMT
Repository: activemq-artemis
Updated Branches:
  refs/heads/master 2b64ce4a3 -> bc2670a54


http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fa7b247d/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/brokerDiagram.js
----------------------------------------------------------------------
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 0000000..3faa093
--- /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 = '<a target="broker" ng-click="connectToBroker()">' + '<img title="Apache Artemis" src="img/icons/messagebroker.svg"> ' + brokerName + '</a>';
+               if (version && profile) {
+                  var brokerLink = Fabric.brokerConfigLink(workspace, jolokia, localStorage, version, profile, brokerName);
+                  if (brokerLink) {
+                     brokerHtml += ' <a title="configuration settings" target="brokerConfig" href="' + brokerLink + '"><i class="icon-tasks"></i></a>';
+                  }
+               }
+               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('<div fabric-container-link="' + selectedNode['container'] + '"></div>')($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('<a target="destination" title="' + destinationName + '" ng-click="connectToDestination()">' + destinationName + '</a>')($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 ? "<p></p>broker: " + brokerName + "</p>" : "";
+      }
+
+      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: "<p>client: " + (consumer.connectionID || "") + "</p> " + 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: "<p>Container: " + containerId + "</p> 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

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fa7b247d/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/browse.js
----------------------------------------------------------------------
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 0000000..9ced888
--- /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: '<div class="ngCellText"><a ng-click="openMessageDialog(row)">{{row.entity.messageID}}</a></div>',
+                // 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('<tr><td class="propertyName"><span class="green">Header</span> - ' + key + '</td><td class="property-value">' + value + '</td></tr>');
+          }
+
+          function appendProperty(key) {
+             var value = properties[key];
+             if (value === null) {
+                value = '';
+             }
+             buffer.push('<tr><td class="propertyName">' + key + '</td><td class="property-value">' + value + '</td></tr>');
+          }
+
+          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['<span class="green">' + key.replace('Properties', ' Property') + '</span> - ' + 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

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fa7b247d/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/jmsHeaderSchema.js
----------------------------------------------------------------------
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 0000000..89bbd9d
--- /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

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fa7b247d/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/preferences.js
----------------------------------------------------------------------
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 0000000..f66d7d9
--- /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

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fa7b247d/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/queue.js
----------------------------------------------------------------------
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 0000000..1cfb2de
--- /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

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fa7b247d/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/send.js
----------------------------------------------------------------------
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 0000000..1301387
--- /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

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fa7b247d/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/js/tree.js
----------------------------------------------------------------------
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 0000000..87c04f4
--- /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.
+ */
+/// <reference path="artemisPlugin.ts"/>
+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

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fa7b247d/artemis-hawtio/artemis-plugin/src/main/webapp/plugin/lib/artemis-console.js
----------------------------------------------------------------------
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 0000000..948127b
--- /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/"));
+}
+
+
+
+

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/fa7b247d/artemis-hawtio/pom.xml
----------------------------------------------------------------------
diff --git a/artemis-hawtio/pom.xml b/artemis-hawtio/pom.xml
index a12046d..7c60dd9 100644
--- a/artemis-hawtio/pom.xml
+++ b/artemis-hawtio/pom.xml
@@ -98,6 +98,7 @@
 
     <modules>
         <module>activemq-branding</module>
+        <module>artemis-plugin</module>
     </modules>
 
 </project>


Mime
View raw message