http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/4940e63d/console/stand-alone/plugin/js/qdrList.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrList.js 
b/console/stand-alone/plugin/js/qdrList.js
new file mode 100644
index 0000000..7352d82
--- /dev/null
+++ b/console/stand-alone/plugin/js/qdrList.js
@@ -0,0 +1,474 @@
+/*
+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 QDR
+ */
+var QDR = (function(QDR) {
+
+  /**
+   * @method ListController
+   * @param $scope
+   * @param QDRService
+   *
+   * Controller for the main interface
+   */
+       QDR.module.controller("QDR.ListController", ['$scope', '$location', 
'uiGridConstants', 'QDRService', 'QDRChartService', '$uibModal',
+               function ($scope, $location, uiGridConstants, QDRService, 
QDRChartService, $uibModal) {
+
+               //QDR.log.debug("started List controller");
+               if (!angular.isDefined(QDRService.schema))
+                       return;
+               $scope.selectedAction = localStorage['QDRSelectedAction'];
+               $scope.selectedNode = localStorage['QDRSelectedNode'];
+               $scope.selectedNodeId = localStorage['QDRSelectedNodeId'];
+               $scope.selectedRecordName = 
localStorage['QDRSelectedRecordName'];
+
+               var excludedEntities = ["management", "org.amqp.management", 
"operationalEntity", "entity", "configurationEntity", "dummy", "console"];
+               var aggregateEntities = ["router.address"];
+
+               $scope.entities = [];
+               for (var entity in QDRService.schema.entityTypes) {
+                       if (excludedEntities.indexOf(entity) == -1) {
+                               $scope.entities.push( {
+                                       title: 
angular.isDefined(QDRService.schema.entityTypes[entity].description) ? 
QDRService.schema.entityTypes[entity].description : '',
+                                       humanName: QDRService.humanify(entity),
+                                       name: entity}
+                                );
+                       }
+               }
+               if (!angular.isDefined($scope.selectedAction)) {
+                       $scope.selectedAction = $scope.entities[0].name;
+                       //QDR.log.debug("defaulted selectedAction to " + 
$scope.selectedAction);
+               }
+
+               $scope.nodes = QDRService.nodeList().sort(function (a, b) { 
return a.name.toLowerCase() > b.name.toLowerCase()});
+               if (!angular.isDefined($scope.selectedNode)) {
+                       //QDR.log.debug("selectedNode was " + 
$scope.selectedNode);
+                       if ($scope.nodes.length > 0) {
+                               $scope.selectedNode = $scope.nodes[0].name;
+                               $scope.selectedNodeId = $scope.nodes[0].id;
+                               //QDR.log.debug("forcing selectedNode to " + 
$scope.selectedNode);
+                       }
+               }
+
+               $scope.isActionActive = function(name) {
+                       //QDR.log.debug("isActionActive(" + name + ")  
selectedAction is " + $scope.selectedAction);
+                       return $scope.selectedAction === name;
+               };
+               $scope.isNodeSelected = function (id) {
+                       return $scope.selectedNodeId === id;
+               };
+
+               $scope.selectNode = function(node) {
+                       //QDR.log.debug("setting selectedNode to " + node.name);
+                       $scope.selectedNode = node.name;
+                       $scope.selectedNodeId = node.id;
+                       //QDR.log.debug("location is " + $location.url());
+                       $location.search('n', node.name);
+               };
+               $scope.selectAction = function(action) {
+                       $scope.selectedAction = action;
+                       $location.search('a', action);
+                       //QDR.log.debug("selectAction called with " + action + 
"  location is now " + $location.url());
+               };
+
+               $scope.$watch('selectedAction', function(newValue, oldValue) {
+                       if (newValue !== oldValue) {
+                               localStorage['QDRSelectedAction'] = 
$scope.selectedAction;
+                               //QDR.log.debug("saving selectedAction as " + 
$scope.selectedAction + " newValue is " + newValue);
+                       }
+               })
+               $scope.$watch('selectedNode', function(newValue, oldValue) {
+                   if (newValue !== oldValue) {
+                               localStorage['QDRSelectedNode'] = 
$scope.selectedNode;
+                               localStorage['QDRSelectedNodeId'] = 
$scope.selectedNodeId;
+                               //QDR.log.debug("saving selectedNode as " + 
$scope.selectedNode + " newValue is " + newValue);
+                       }
+               })
+               $scope.$watch('selectedRecordName', function(newValue, 
oldValue) {
+                       if (newValue != oldValue) {
+                               localStorage['QDRSelectedRecordName'] = 
$scope.selectedRecordName;
+                               //QDR.log.debug("saving selectedRecordName as " 
+ $scope.selectedRecordName);
+                       }
+               })
+
+               $scope.tableRows = [];
+               var selectedRowIndex = 0;
+               var updateTableData = function (entity) {
+                       var gotNodeInfo = function (nodeName, dotentity, 
response) {
+                               //QDR.log.debug("got results for  " + nodeName);
+                               //console.dump(response);
+
+                               var records = response.results;
+                               var aggregates = response.aggregates;
+                               var attributeNames = response.attributeNames;
+                               var nameIndex = attributeNames.indexOf("name");
+                               var ent = QDRService.schema.entityTypes[entity];
+                               var tableRows = [];
+                               for (var i=0; i<records.length; ++i) {
+                                       var record = records[i];
+                                       var aggregate = aggregates ? 
aggregates[i] : undefined;
+                                       var row = {};
+                                       var rowName;
+                                       if (nameIndex > -1) {
+                                               rowName = record[nameIndex];
+                                       } else {
+                                               QDR.log.error("response 
attributeNames did not contain a name field");
+                                               
console.dump(response.attributeNames);
+                                               return;
+                                       }
+                                       if (rowName == 
$scope.selectedRecordName)
+                                               selectedRowIndex = i;
+                                       for (var j=0; j<attributeNames.length; 
++j) {
+                                               var col = attributeNames[j];
+                                               row[col] = {value: record[j], 
type: undefined, graph: false, title: '', aggregate: '', aggregateTip: ''};
+                                               if (ent) {
+                                                       var att = 
ent.attributes[col];
+                                                       if (att) {
+                                                               row[col].type = 
att.type;
+                                                               row[col].graph 
= att.graph;
+                                                               row[col].title 
= att.description;
+
+                                                               if (aggregate) {
+                                                                       if 
(att.graph) {
+                                                                               
row[col].aggregate = att.graph ? aggregate[j].sum : '';
+                                                                               
var tip = [];
+                                                                               
aggregate[j].detail.forEach( function (line) {
+                                                                               
        tip.push(line);
+                                                                               
})
+                                                                               
row[col].aggregateTip = angular.toJson(tip);
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       tableRows.push(row);
+                               }
+                               setTimeout(selectRow, 0, tableRows);
+                       }
+
+                       // if this entity should show an aggregate column, send 
the request to get the info for this entity from all the nedes
+                       if (aggregateEntities.indexOf(entity) > -1) {
+                               var nodeInfo = QDRService.topology.nodeInfo();
+                               
QDRService.getMultipleNodeInfo(Object.keys(nodeInfo), entity, [], gotNodeInfo, 
$scope.selectedNodeId);
+                       } else {
+                               QDRService.getNodeInfo($scope.selectedNodeId, 
'.' + entity, [], gotNodeInfo);
+                       }
+               };
+
+               // tableRows are the records that were returned, this populates 
the left hand table on the page
+               var selectRow = function (tableRows) {
+                       $scope.tableRows = tableRows;
+                       // must apply scope here to update the tableRows before 
selecting the row
+                       $scope.$apply();
+            
$scope.gridApi.selection.selectRow($scope.tableRows[selectedRowIndex]);
+                       fixTooltips();
+               }
+
+               $scope.getTableHeight = function() {
+              return {height: ($scope.tableRows.length * 30) + "px"};
+           };
+           var titleFromAlt = function (alt) {
+                       if (alt && alt.length) {
+                               var data = angular.fromJson(alt);
+                               var table = "<table class='tiptable'><tbody>";
+                               data.forEach (function (row) {
+                                       table += "<tr>";
+                                       table += "<td>" + row.node + "</td><td 
align='right'>" + QDRService.pretty(row.val) + "</td>";
+                                       table += "</tr>"
+                               })
+                               table += "</tbody></table>"
+                               return table;
+                       }
+                       return '';
+           }
+               var fixTooltips = function () {
+                       if ($('.hastip').length == 0) {
+                               setTimeout(fixTooltips, 100);
+                               return;
+                       }
+                       $('.hastip').each( function (i, tip) {
+                               var tipset = tip.getAttribute('tipset')
+                               if (!tipset) {
+                                       $(tip).tipsy({html: true, className: 
'subTip', opacity: 1, title: function () {
+                                               return 
titleFromAlt(this.getAttribute('alt'))
+                                       } });
+                                       tip.setAttribute('tipset', true)
+                               } else {
+                                       var title = 
titleFromAlt(tip.getAttribute('alt'))
+                                       tip.setAttribute('original-title', 
title)
+                               }
+/*
+                               $(tip).tipsy({html: true, className: 'subTip', 
opacity: 1, title: function () {
+                                       var alt = this.getAttribute('alt');
+                                       if (alt && alt.length) {
+                                               var data = 
angular.fromJson(alt);
+                                               var table = "<table 
class='tiptable'><tbody>";
+                                               data.forEach (function (row) {
+                                                       table += "<tr>";
+                                                       table += "<td>" + 
row.node + "</td><td align='right'>" + QDRService.pretty(row.val) + "</td>";
+                                                       table += "</tr>"
+                                               })
+                                               table += "</tbody></table>"
+                                               return table;
+                                       }
+                                       return '';
+                               } });
+                               */
+                       })
+               }
+               $scope.selectedEntity = undefined;
+               for (var i=0; i<$scope.entities.length; ++i) {
+                       if ($scope.selectedAction === $scope.entities[i].name) {
+                               $scope.selectedEntity = $scope.entities[i].name;
+                               break;
+                       }
+               }
+               if (!angular.isDefined($scope.selectedEntity)) {
+                       $scope.selectedAction = $scope.entities[0].name;
+                       $scope.selectedEntity = $scope.entities[0].name;
+               }
+               var savedCharts = 
angular.fromJson(localStorage['QDRListCharts']);
+               var getCurrentSavedCharts = function () {
+                       if (angular.isDefined(savedCharts)) {
+                               if 
(angular.isDefined(savedCharts[$scope.selectedEntity])) {
+                                       //graphFields = 
savedCharts[$scope.selectedEntity];
+                               }
+                       } else {
+                               savedCharts = {};
+                       }
+               }
+               getCurrentSavedCharts();
+
+               //QDR.log.debug("using entity of " + $scope.selectedEntity);
+               var stop = undefined;
+
+               // The left-hand table that lists the names
+               var gridCols = [
+                       { field: 'name',
+                         displayName: '',
+                         cellTemplate: '<div class="ngCellText"><span 
ng-cell-text>{{row.entity.name.value}}</span></div>'
+                       }
+               ];
+               // the table on the left of the page contains the name field 
for each record that was returned
+               $scope.gridDef = {
+                       data: 'tableRows',
+                       hideHeader: true,
+                       showHeader: false,
+                       enableHorizontalScrollbar: 
uiGridConstants.scrollbars.NEVER,
+                       enableVerticalScrollbar: 
uiGridConstants.scrollbars.NEVER,
+                       columnDefs: gridCols,
+                       enableColumnResize: true,
+                       multiSelect: false,
+                       enableRowHeaderSelection: false,
+                       noUnselect: true,
+                       enableSelectAll: false,
+                       enableRowSelection: true,
+                       onRegisterApi: function (gridApi) {
+                               $scope.gridApi = gridApi;
+                               
gridApi.selection.on.rowSelectionChanged($scope, function(row) {
+                                       if (row.isSelected)  {
+                                               selectedRowIndex = row.rowIndex;
+                                               $scope.selectedRecordName = 
row.entity.name.value;
+                                               var details = [];
+                                               // for each field in the new 
row, add a row in the details grid
+                                               for (var name in row.entity) {
+                                                       details.push( { 
attributeName: QDRService.humanify(name),
+                                                                               
        attributeValue: QDRService.pretty(row.entity[name].value),
+                                                                               
        type: row.entity[name].type,
+                                                                               
        name: name,
+                                                                               
        rawValue: row.entity[name].value,
+                                                                               
        graph: row.entity[name].graph,
+                                                                               
        title: row.entity[name].title,
+                                                                               
        aggregateValue: QDRService.pretty(row.entity[name].aggregate),
+                                                                               
        aggregateTip: row.entity[name].aggregateTip})
+                                               }
+                                               setTimeout(updateDetails, 10, 
details);
+                                       }
+                               });
+                   }
+               };
+
+               $scope.detailFields = [];
+               updateDetails = function (details) {
+                       $scope.detailFields = details;
+                       $scope.$apply();
+               }
+
+               $scope.isFieldGraphed = function(rowEntity, aggregate) {
+                       var dot = !aggregate ? '.' : '';
+                       return 
QDRChartService.isAttrCharted($scope.selectedNodeId, dot + 
$scope.selectedEntity, $scope.selectedRecordName, rowEntity.name);
+               }
+
+               $scope.addToGraph = function(rowEntity) {
+                       var chart = 
QDRChartService.registerChart($scope.selectedNodeId, "." + 
$scope.selectedEntity, $scope.selectedRecordName, rowEntity.name, 1000);
+                       doDialog("template-from-script.html", chart);
+                       reset();
+               }
+
+               $scope.addAllToGraph = function(rowEntity) {
+                       var chart = 
QDRChartService.registerChart($scope.selectedNodeId,
+                                               $scope.selectedEntity,
+                                               $scope.selectedRecordName,
+                                               rowEntity.name,
+                                               1000,
+                                               false,
+                                               true);
+                       doDialog("template-from-script.html", chart);
+                       reset();
+               }
+
+               var detailCols = [
+                        {
+                                field: 'attributeName',
+                                cellTemplate: '<div 
title="{{row.entity.title}}" class="listAttrName">{{row.entity.name}}<i 
ng-if="row.entity.graph" ng-click="grid.appScope.addToGraph(row.entity)" 
ng-class="{\'active\': grid.appScope.isFieldGraphed(row.entity, false), 
\'icon-bar-chart\': row.entity.graph == true }"></i></div>',
+                                displayName: 'Attribute'
+                        },
+                        {
+                                field: 'attributeValue',
+                                displayName: 'Value'
+                        }
+               ];
+               if (aggregateEntities.indexOf($scope.selectedEntity) > -1) {
+                       detailCols.push(
+                        {
+                                width: '10%',
+                                field: 'aggregateValue',
+                                displayName: 'Aggregate',
+                                cellTemplate: '<div class="hastip" 
alt="{{row.entity.aggregateTip}}">{{row.entity.aggregateValue}}<i 
ng-if="row.entity.graph" ng-click="grid.appScope.addAllToGraph(row.entity)" 
ng-class="{\'active\': grid.appScope.isFieldGraphed(row.entity, true), 
\'icon-bar-chart\': row.entity.graph == true }"></i></div>',
+                                cellClass: 'aggregate'
+                        }
+                       )
+               }
+
+               // the table on the right of the page contains a row for each 
field in the selected record in the table on the left
+               $scope.details = {
+                       data: 'detailFields',
+                       columnDefs: detailCols,
+                       enableHorizontalScrollbar: 
uiGridConstants.scrollbars.NEVER,
+                       enableVerticalScrollbar: 
uiGridConstants.scrollbars.NEVER,
+                       enableColumnResize: true,
+                       multiSelect: false,
+                       enableRowHeaderSelection: false,
+                       noUnselect: true,
+                       enableSelectAll: false,
+                       enableRowSelection: true
+               };
+
+               updateTableData($scope.selectedEntity);
+               stop = setInterval(updateTableData, 5000, 
$scope.selectedEntity);
+               $scope.getDetailsTableHeight = function() {
+              return {height: ($scope.detailFields.length * 30) + "px"};
+           };
+
+               $scope.$on("$destroy", function( event ) {
+                       //QDR.log.debug("scope destroyed for qdrList");
+                       reset();
+                       if (angular.isDefined(stop)) {
+                               clearInterval(stop);
+                               stop = undefined;
+                       };
+               });
+
+               var reset = function () {
+                       if ($scope.context) {
+                               $scope.context.stop();
+                               $scope.context = null;
+                       }
+               };
+
+               function doDialog(template, chart) {
+
+                   var modalInstance = $uibModal.open({
+                     animation: true,
+                     templateUrl: template,
+                     controller: 'QDR.ListChartController',
+                     resolve: {
+                       chart: function () {
+                         return chart;
+                       }
+                     }
+                   });
+               };
+
+       }]);
+
+
+       QDR.module.controller('QDR.ListChartController', function ($scope, 
$uibModalInstance, $location, QDRChartService, chart) {
+
+           $scope.chart = chart;
+               $scope.dialogSvgChart = null;
+               $scope.updateTimer = null;
+               $scope.svgDivId = "dialogChart";    // the div id for the svg 
chart
+
+               $scope.showChartsPage = function () {
+                       cleanup();
+                   $uibModalInstance.close();
+                       $location.path("/charts");
+               };
+
+               $scope.addChartsPage = function () {
+                       QDRChartService.addDashboard($scope.chart);
+               };
+
+               $scope.delChartsPage = function () {
+                       QDRChartService.delDashboard($scope.chart);
+               };
+
+               $scope.isOnChartsPage = function () {
+                       return $scope.chart.dashboard;
+               }
+
+               var showChart = function () {
+                       // the chart divs are generated by angular and aren't 
available immediately
+                       var div = angular.element("#" + $scope.svgDivId);
+                       if (!div.width()) {
+                               setTimeout(showChart, 100);
+                               return;
+                       }
+                       dialogSvgChart = new 
QDRChartService.AreaChart($scope.chart, $location.$$path);
+                       $scope.dialogSvgChart = dialogSvgChart;
+                       updateDialogChart();
+               }
+               showChart();
+
+               var updateDialogChart = function () {
+                       if ($scope.dialogSvgChart)
+                               $scope.dialogSvgChart.tick($scope.svgDivId);
+                       $scope.updateTimer = setTimeout(updateDialogChart, 
1000);
+               }
+
+               var cleanup = function () {
+                       if ($scope.updateTimer) {
+                               clearTimeout($scope.updateTimer);
+                               $scope.updateTimer = null;
+                       }
+                       if (!$scope.chart.dashboard)
+                               QDRChartService.unRegisterChart(chart);     // 
remove the chart
+
+               }
+               $scope.ok = function () {
+                       cleanup();
+               $uibModalInstance.close();
+           };
+
+       });
+    return QDR;
+
+} (QDR || {}));

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/4940e63d/console/stand-alone/plugin/js/qdrOverview.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrOverview.js 
b/console/stand-alone/plugin/js/qdrOverview.js
new file mode 100644
index 0000000..d787a5e
--- /dev/null
+++ b/console/stand-alone/plugin/js/qdrOverview.js
@@ -0,0 +1,696 @@
+/*
+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 QDR
+ */
+/**
+ * @module QDR
+ */
+var QDR = (function (QDR) {
+
+  /**
+   * @method OverviewController
+   * @param $scope
+   * @param QDRService
+   * @param QDRChartServer
+   * dialogServer
+   * $location
+   *
+   * Controller that handles the QDR overview page
+   */
+       QDR.module.controller("QDR.OverviewController", ['$scope', 
'uiGridConstants', 'QDRService', function($scope, uiGridConstants, QDRService) {
+
+
+               if (!angular.isDefined(QDRService.schema))
+                   return;
+
+               var nodeIds = QDRService.nodeIdList();
+               var currentTimer;
+               var refreshInterval = 5000
+               var Folder = (function () {
+            function Folder(title) {
+                this.title = title;
+                               this.children = [];
+                               this.folder = true;
+            }
+            return Folder;
+        })();
+               var Leaf = (function () {
+            function Leaf(title) {
+                this.title = title;
+            }
+            return Leaf;
+        })();
+           $scope.modes = [
+               {title: 'Overview', name: 'Overview', right: false}
+               ];
+
+               $scope.templates =
+                   [ { name: 'Routers', url: 'routers.html'},
+                     { name: 'Router', url: 'router.html'},
+              { name: 'Addresses', url: 'addresses.html'},
+                     { name: 'Address', url: 'address.html'},
+              { name: 'Connections', url: 'connections.html'},
+                     { name: 'Connection', url: 'connection.html'},
+              { name: 'Logs', url: 'logs.html'},
+              { name: 'Log', url: 'log.html'} ];
+
+               $scope.getGridHeight = function (data) {
+              // add 1 for the header row
+              return {height: (($scope[data.data].length + 1) * 30) + "px"};
+               }
+               $scope.overview = new Folder("Overview");
+
+               $scope.allRouterFields = [];
+               var allRouterCols = [
+                        {
+                                field: 'routerId',
+                                displayName: 'Router'
+                        },
+                        {
+                                field: 'area',
+                                displayName: 'Area'
+                        },
+                        {
+                                field: 'mode',
+                                displayName: 'Mode'
+                        },
+                        {
+                                field: 'connections',
+                                displayName: 'External connections'
+                        },
+             {
+                 field: 'addrCount',
+                 displayName: 'Address count'
+             },
+             {
+                 field: 'linkCount',
+                 displayName: 'Link count'
+             }
+               ];
+               $scope.allRouters = {
+                       data: 'allRouterFields',
+                       columnDefs: allRouterCols,
+                       enableHorizontalScrollbar: 
uiGridConstants.scrollbars.NEVER,
+            enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
+                       enableColumnResize: true,
+                       multiSelect: false,
+                       enableRowHeaderSelection: false,
+                       noUnselect: true,
+                       enableSelectAll: false,
+                       enableRowSelection: true,
+                       onRegisterApi: function (gridApi) {
+                               
gridApi.selection.on.rowSelectionChanged($scope, function(row) {
+                                       if (row.isSelected) {
+                                               var nodeId = row.entity.nodeId;
+                                               
$("#overtree").fancytree("getTree").activateKey(nodeId);
+                                       }
+                               });
+                   }
+               };
+               // get info for all routers
+               var allRouterInfo = function () {
+                       nodeIds = QDRService.nodeIdList()
+                       var expected = Object.keys(nodeIds).length
+                       var received = 0;
+                       var allRouterFields = [];
+                       var gotNodeInfo = function (nodeName, entity, response) 
{
+                               var results = response.results;
+                               var name = QDRService.nameFromId(nodeName)
+                               var connections = 0;
+                               results.forEach( function (result) {
+                                       var role = 
QDRService.valFor(response.attributeNames, result, "role")
+                                       if (role != 'inter-router') {
+                                               ++connections
+                                       }
+                               })
+                               allRouterFields.push({routerId: name, 
connections: connections, nodeId: nodeName})
+                               ++received
+                               if (expected == received) {
+                                       allRouterFields.sort ( function (a,b) { 
return a.routerId < b.routerId ? -1 : a.routerId > b.routerId ? 1 : 0})
+                                       // now get each router's node info
+                                       QDRService.getMultipleNodeInfo(nodeIds, 
"router", [], function (nodeIds, entity, response) {
+                                               var results = 
response.aggregates
+                                               results.forEach ( function 
(result) {
+
+                                                       var routerId = 
QDRService.valFor(response.attributeNames, result, "routerId").sum
+                                                       allRouterFields.some( 
function (connField) {
+                                                               if (routerId 
=== connField.routerId) {
+                                                                       
response.attributeNames.forEach ( function (attrName) {
+                                                                               
connField[attrName] = QDRService.valFor(response.attributeNames, result, 
attrName).sum
+                                                                       })
+                                                                       return 
true
+                                                               }
+                                                               return false
+                                                       })
+                                               })
+                                               $scope.allRouterFields = 
allRouterFields
+                                               $scope.$apply()
+                                               if (currentTimer) {
+                                                       
clearTimeout(currentTimer)
+                                               }
+                                               currentTimer = 
setTimeout(allRouterInfo, refreshInterval);
+                                       }, nodeIds[0])
+                               }
+                       }
+                       nodeIds.forEach ( function (nodeId) {
+                               QDRService.getNodeInfo(nodeId, ".connection", 
["role"], gotNodeInfo)
+                       })
+
+               }
+
+               // get info for a single router
+               var routerInfo = function (node) {
+                       $scope.router = node
+                       $scope.routerFields = []
+                       var cols = [
+                                {
+                                        field: 'attribute',
+                                        displayName: 'Attribute',
+                                        width: '40%'
+                                },
+                                {
+                                        field: 'value',
+                                        displayName: 'Value',
+                                        width: '40%'
+                                }
+                       ]
+                       $scope.routerGrid = {
+                               data: 'routerFields',
+                               columnDefs: cols,
+                               enableHorizontalScrollbar: 
uiGridConstants.scrollbars.NEVER,
+                   enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
+                               enableColumnResize: true,
+                               multiSelect: false
+                       }
+
+                       $scope.allRouterFields.some( function (field) {
+                               if (field.routerId === node.title) {
+                                       Object.keys(field).forEach ( function 
(key) {
+                                               if (key !== '$$hashKey')
+                                                       
$scope.routerFields.push({attribute: key, value: field[key]})
+                                       })
+                                       return true
+                               }
+                       })
+
+                       $scope.$apply()
+                       if (currentTimer) {
+                               clearTimeout(currentTimer)
+                               currentTimer = null
+                       }
+               }
+
+               // get info for a all addresses
+               var allAddressInfo = function () {
+                       $scope.addressFields = []
+                       var addressCols = [
+                                {
+                                        field: 'address',
+                                        displayName: 'address'
+                                },
+                                {
+                                        field: 'class',
+                                        displayName: 'class'
+                                },
+                                {
+                                        field: 'phase',
+                                        displayName: 'phase',
+                                        cellClass: 'grid-align-value'
+                                },
+                                {
+                                        field: 'inproc',
+                                        displayName: 'in-proc'
+                                },
+                                {
+                                        field: 'local',
+                                        displayName: 'local',
+                                        cellClass: 'grid-align-value'
+                                },
+                                {
+                                        field: 'remote',
+                                        displayName: 'remote',
+                                        cellClass: 'grid-align-value'
+                                },
+                                {
+                                        field: 'in',
+                                        displayName: 'in',
+                                        cellClass: 'grid-align-value'
+                                },
+                                {
+                                        field: 'out',
+                                        displayName: 'out',
+                                        cellClass: 'grid-align-value'
+                                }
+                       ]
+                       $scope.selectedAddresses = []
+                       $scope.addressGrid = {
+                               data: 'addressFields',
+                               columnDefs: addressCols,
+                               enableColumnResize: true,
+                               enableHorizontalScrollbar: 
uiGridConstants.scrollbars.NEVER,
+                   enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
+                               multiSelect: false,
+                               enableRowHeaderSelection: false,
+                               noUnselect: true,
+                               enableSelectAll: false,
+                               enableRowSelection: true,
+                               onRegisterApi: function (gridApi) {
+                                       
gridApi.selection.on.rowSelectionChanged($scope, function(row) {
+                                               if (row.isSelected) {
+                                                       var key = 
row.entity.uid;
+                                                       
$("#overtree").fancytree("getTree").activateKey(key);
+                                               }
+                                       });
+                           }
+                       }
+
+                       var gotAllAddressFields = function ( addressFields ) {
+                               $scope.addressFields =  addressFields
+                               $scope.$apply()
+                               if (currentTimer) {
+                                       clearTimeout(currentTimer)
+                               }
+                               currentTimer = setTimeout(allAddressInfo, 
refreshInterval);
+                       }
+                       getAllAddressFields(gotAllAddressFields)
+               }
+
+               var getAllAddressFields = function (callback) {
+                       var addr_class = function (addr) {
+                               if (!addr) return "-"
+                       if (addr[0] == 'M')  return "mobile"
+                       if (addr[0] == 'R')  return "router"
+                       if (addr[0] == 'A')  return "area"
+                       if (addr[0] == 'L')  return "local"
+                       if (addr[0] == 'C')  return "link-incoming"
+                       if (addr[0] == 'D')  return "link-outgoing"
+                       return "unknown: " + addr[0]
+                       }
+
+                       var addr_text = function (addr) {
+                       if (!addr)
+                           return "-"
+                       if (addr[0] == 'M')
+                           return addr.substring(2)
+                       else
+                           return addr.substring(1)
+                       }
+
+                       var addr_phase = function (addr) {
+                       if (!addr)
+                           return "-"
+                       if (addr[0] == 'M')
+                           return addr[1]
+                       return ''
+                       }
+
+                       var identity_clean = function (identity) {
+                       if (!identity)
+                           return "-"
+                       var pos = identity.indexOf('/')
+                       if (pos >= 0)
+                           return identity.substring(pos + 1)
+                       return identity
+                       }
+
+                       var addressFields = []
+                       nodeIds = QDRService.nodeIdList()
+                       QDRService.getMultipleNodeInfo(nodeIds, 
"router.address", [], function (nodeIds, entity, response) {
+                               response.aggregates.forEach( function (result) {
+                                       var prettySum = function (field) {
+                                               var fieldIndex = 
response.attributeNames.indexOf(field)
+                                               if (fieldIndex < 0) {
+                                                       return "-"
+                                               }
+                                               var val = result[fieldIndex].sum
+                                               return QDRService.pretty(val)
+                                       }
+
+                                       var uid = 
QDRService.valFor(response.attributeNames, result, "identity").sum
+                                       var identity = identity_clean(uid)
+
+                                       addressFields.push({
+                                               address: addr_text(identity),
+                                               'class': addr_class(identity),
+                                               phase:   addr_phase(identity),
+                                               inproc:  prettySum("inProcess"),
+                                               local:   
prettySum("subscriberCount"),
+                                               remote:  
prettySum("remoteCount"),
+                                               'in':    
prettySum("deliveriesIngress"),
+                                               out:     
prettySum("deliveriesEgress"),
+                                               thru:    
prettySum("deliveriesTransit"),
+                                               toproc:  
prettySum("deliveriesToContainer"),
+                                               
fromproc:prettySum("deliveriesFromContainer"),
+                                               uid:     uid
+                                       })
+                               })
+                               callback(addressFields)
+                       }, nodeIds[0])
+               }
+
+
+               // get info for a all connections
+               var allConnectionInfo = function () {
+                       $scope.allConnectionFields = []
+                       var allConnectionCols = [
+                                {
+                                        field: 'host',
+                                        displayName: 'host'
+                                },
+                                {
+                                        field: 'container',
+                                        displayName: 'container'
+                                },
+                                {
+                                        field: 'role',
+                                        displayName: 'role'
+                                },
+                                {
+                                        field: 'dir',
+                                        displayName: 'dir'
+                                },
+                                {
+                                        field: 'security',
+                                        displayName: 'security'
+                                },
+                                {
+                                        field: 'authentication',
+                                        displayName: 'authentication'
+                                }
+                       ]
+                       $scope.allConnectionGrid = {
+                               data: 'allConnectionFields',
+                               columnDefs: allConnectionCols,
+                               enableHorizontalScrollbar: 
uiGridConstants.scrollbars.NEVER,
+                   enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
+                               enableColumnResize: true,
+                               multiSelect: false,
+                               enableRowHeaderSelection: false,
+                               noUnselect: true,
+                               enableSelectAll: false,
+                               enableRowSelection: true,
+                               onRegisterApi: function (gridApi) {
+                                       
gridApi.selection.on.rowSelectionChanged($scope, function(row) {
+                                               if (row.isSelected) {
+                                                       var host = 
row.entity.host;
+                                                       
$("#overtree").fancytree("getTree").activateKey(host);
+                                               }
+                                       });
+                           }
+                       }
+                       connections.children.forEach( function (connection) {
+                               
$scope.allConnectionFields.push(connection.fields)
+                       })
+                       $scope.$apply()
+                       if (currentTimer) {
+                               clearTimeout(currentTimer)
+                               currentTimer = null
+                       }
+               }
+
+               // get info for a single address
+               var addressInfo = function (address) {
+                       $scope.address = address
+                       $scope.addressFields = []
+                       var cols = [
+                                {
+                                        field: 'attribute',
+                                        displayName: 'Attribute',
+                                        width: '40%'
+                                },
+                                {
+                                        field: 'value',
+                                        displayName: 'Value',
+                                        width: '40%'
+                                }
+                       ]
+                       $scope.addressGrid = {
+                               data: 'addressFields',
+                               columnDefs: cols,
+                               enableColumnResize: true,
+                               enableHorizontalScrollbar: 
uiGridConstants.scrollbars.NEVER,
+                   enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
+                               multiSelect: false
+                       }
+
+                       var fields = Object.keys(address.data.fields)
+                       fields.forEach( function (field) {
+                               if (field != "title" && field != "uid")
+                                       $scope.addressFields.push({attribute: 
field, value: address.data.fields[field]})
+                       })
+
+                       $scope.$apply()
+                       if (currentTimer) {
+                               clearTimeout(currentTimer)
+                               currentTimer = null
+                       }
+               }
+
+               // get info for a single connection
+               var connectionInfo = function (connection) {
+                       $scope.connection = connection
+                       $scope.connectionFields = []
+                       var cols = [
+                                {
+                                        field: 'attribute',
+                                        displayName: 'Attribute',
+                                        width: '40%'
+                                },
+                                {
+                                        field: 'value',
+                                        displayName: 'Value',
+                                        width: '40%'
+                                }
+                       ]
+                       $scope.connectionGrid = {
+                               data: 'connectionFields',
+                               columnDefs: cols,
+                               enableColumnResize: true,
+                               enableHorizontalScrollbar: 
uiGridConstants.scrollbars.NEVER,
+                   enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
+                               multiSelect: false
+                       }
+
+                       var fields = Object.keys(connection.data.fields)
+                       fields.forEach( function (field) {
+                               $scope.connectionFields.push({attribute: field, 
value: connection.data.fields[field]})
+                       })
+
+                       $scope.$apply()
+                       if (currentTimer) {
+                               clearTimeout(currentTimer)
+                               currentTimer = null
+                       }
+               }
+
+               // get info for a all logs
+               var allLogInfo = function () {
+               }
+
+               // get info for a single log
+               var logInfo = function (node) {
+                       $scope.log = node
+               }
+
+               var activated = function (event, node) {
+                       //QDR.log.debug("node activated: " + node.data.title)
+                       node = node.node;
+                       var type = node.data.type;
+                       var template = $scope.templates.filter( function (tpl) {
+                               return tpl.name == type;
+                       })
+                       $scope.template = template[0];
+                       // Call the function associated with this type passing 
in the node that was selected
+                       // In dynatree I could save the function to call in the 
node, but not in FancyTree
+                       if (treeTypeMap[type])
+                               treeTypeMap[type](node);
+
+                       /*if (node.data.info)
+                               node.data.info(node)
+                       */
+                       $scope.$apply();
+               }
+        $scope.template = $scope.templates[0];
+
+               var routers = new Folder("Routers")
+               routers.type = "Routers"
+               //routers.info = allRouterInfo
+               routers.focus = true
+               routers.expanded = true
+               routers.key = "Routers"
+               $scope.overview.children.push(routers)
+               nodeIds.forEach( function (node) {
+                       var name = QDRService.nameFromId(node)
+                       var router = new Leaf(name)
+                       router.type = "Router"
+                       //router.info = routerInfo
+                       router.nodeId = node
+                       router.key = node
+                       routers.children.push(router)
+               })
+
+               var expected = nodeIds.length;
+               var addresses = new Folder("Addresses")
+               addresses.type = "Addresses"
+               //addresses.info = allAddressInfo
+               addresses.key = "Addresses"
+               $scope.overview.children.push(addresses)
+
+               var gotAddressFields = function (addressFields) {
+                       addressFields.sort ( function (a,b) { return a.address 
< b.address ? -1 : a.address > b.address ? 1 : 0})
+                       addressFields[0].title = addressFields[0].address
+                       for (var i=1; i<addressFields.length; ++i) {
+                               if (addressFields[i].address === 
addressFields[i-1].address) {
+                                       addressFields[i-1].title = 
addressFields[i-1].address + " (" + addressFields[i-1]['class'] + ")"
+                                       addressFields[i].title = 
addressFields[i].address + " (" + addressFields[i]['class'] + ")"
+                               } else
+                                       addressFields[i].title = 
addressFields[i].address
+                       }
+                       addressFields.forEach( function (address) {
+                               var a = new Leaf(address.title)
+                               //a.info = addressInfo
+                               a.key = address.uid
+                               a.fields = address
+                               a.type = "Address"
+                               addresses.children.push(a)
+                       } )
+               }
+               getAllAddressFields(gotAddressFields)
+
+
+               var connreceived = 0;
+               var connectionsObj = {}
+               var connections = new Folder("Connections")
+               connections.type = "Connections"
+               //connections.info = allConnectionInfo
+               connections.key = "Connections"
+               $scope.overview.children.push(connections)
+               nodeIds.forEach( function (nodeId) {
+
+                       QDRService.getNodeInfo(nodeId, ".connection", [], 
function (nodeName, entity, response) {
+                               response.results.forEach( function (result) {
+
+                                       var auth = "no_auth"
+                                       var sasl = 
QDRService.valFor(response.attributeNames, result, "sasl")
+                                       if 
(QDRService.valFor(response.attributeNames, result, "isAuthenticated")) {
+                                               auth = sasl
+                                               if (sasl === "ANONYMOUS")
+                                                       auth = "anonymous-user"
+                                               else {
+                                                       if (sasl === "GSSAPI")
+                                                               sasl = 
"Kerberos"
+                                                       if (sasl === "EXTERNAL")
+                                                               sasl = "x.509"
+                                                       auth = 
QDRService.valFor(response.attributeNames, result, "user") + "(" +
+                                                                       
QDRService.valFor(response.attributeNames, result, "sslCipher") + ")"
+                                                       }
+                                       }
+
+                                       var sec = "no-security"
+                                       if 
(QDRService.valFor(response.attributeNames, result, "isEncrypted")) {
+                                               if (sasl === "GSSAPI")
+                                                       sec = "Kerberos"
+                                               else
+                                                       sec = 
QDRService.valFor(response.attributeNames, result, "sslProto") + "(" +
+                                                                       
QDRService.valFor(response.attributeNames, result, "sslCipher") + ")"
+                                       }
+
+                                       var host = 
QDRService.valFor(response.attributeNames, result, "host")
+                                       connectionsObj[host] = {}
+                                       response.attributeNames.forEach( 
function (attribute, i) {
+                                               connectionsObj[host][attribute] 
= result[i]
+                                       })
+                                       connectionsObj[host].security = sec
+                                       connectionsObj[host].authentication = 
auth
+                               })
+                               ++connreceived;
+                               if (connreceived == expected) {
+                                       var allConnections = 
Object.keys(connectionsObj).sort()
+                                       allConnections.forEach(function 
(connection) {
+                                               var c = new Leaf(connection)
+                                               c.type = "Connection"
+                                               c.icon = "ui-icon "
+                                               c.icon += 
connectionsObj[connection].role === "inter-router" ? "ui-icon-refresh" : 
"ui-icon-transfer-e-w"
+                                               //c.info = connectionInfo
+                                               c.key = connection
+                                               c.fields = 
connectionsObj[connection]
+                                               c.tooltip = 
connectionsObj[connection].role === "inter-router" ? "inter-router connection" 
: "external connection"
+                                               connections.children.push(c)
+                                       })
+                               }
+                       })
+               })
+
+               var logsreceived = 0;
+               var logObj = {}
+               var logs = new Folder("Logs")
+               logs.type = "Logs"
+               //logs.info = allLogInfo
+               logs.key = "Logs"
+               //$scope.overview.children.push(logs)
+               nodeIds.forEach( function (nodeId) {
+                       QDRService.getNodeInfo(nodeId, ".log", ["name"], 
function (nodeName, entity, response) {
+                               response.results.forEach( function (result) {
+                                       logObj[result[0]] = 1    // use object 
to collapse duplicates
+                               })
+                               ++logsreceived;
+                               if (logsreceived == expected) {
+                                       var allLogs = Object.keys(logObj).sort()
+                                       allLogs.forEach(function (log) {
+                                               var l = new Leaf(log)
+                                               l.type = "Log"
+                                               //l.info = logInfo
+                                               l.key = log
+                                               logs.children.push(l)
+                                       })
+                                       //console.log("---------------")
+                                       //console.dump($scope.overview.children)
+                                       //console.log("---------------")
+                                       $("#overtree").fancytree({
+                                               activate: activated,
+                                               clickFolderMode: 1,
+                                               source: $scope.overview.children
+                                               })
+                                       allRouterInfo();
+                               }
+                       })
+               })
+
+        $scope.$on("$destroy", function( event ) {
+                       if (currentTimer) {
+                               clearTimeout(currentTimer)
+                               currentTimer = null;
+                       }
+        });
+               var treeTypeMap = {
+                       Routers:     allRouterInfo,
+                       Router:      routerInfo,
+                       Addresses:   allAddressInfo,
+                       Address:     addressInfo,
+                       Connections: allConnectionInfo,
+                       Connection:  connectionInfo
+               }
+
+    }]);
+
+  return QDR;
+
+}(QDR || {}));
+

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/4940e63d/console/stand-alone/plugin/js/qdrPlugin.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrPlugin.js 
b/console/stand-alone/plugin/js/qdrPlugin.js
new file mode 100644
index 0000000..3d14f72
--- /dev/null
+++ b/console/stand-alone/plugin/js/qdrPlugin.js
@@ -0,0 +1,197 @@
+/*
+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 QDR
+ * @main QDR
+ *
+ * The main entrypoint for the QDR module
+ *
+ */
+var QDR = (function(QDR) {
+
+  /**
+   * @property pluginName
+   * @type {string}
+   *
+   * The name of this plugin
+   */
+  QDR.pluginName = "QDR";
+
+  /**
+   * @property log
+   * @type {Logging.Logger}
+   *
+   * This plugin's logger instance
+   */
+  //HIO QDR.log = Logger.get(QDR.pluginName);
+  /**
+   * @property templatePath
+   * @type {string}
+   *
+   * The top level path to this plugin's partials
+   */
+  QDR.srcBase = "../dispatch/plugin/";
+  QDR.templatePath = QDR.srcBase + "html/";
+  QDR.cssPath = QDR.srcBase + "css/";
+
+  /**
+   * @property SETTINGS_KEY
+   * @type {string}
+   *
+   * The key used to fetch our settings from local storage
+   */
+  QDR.SETTINGS_KEY = 'QDRSettings';
+  QDR.LAST_LOCATION = "QDRLastLocation";
+
+  /**
+   * @property module
+   * @type {object}
+   *
+   * This plugin's angularjs module instance
+   */
+  QDR.module = angular.module(QDR.pluginName, ['ngAnimate', 'ngResource', 
'ngRoute', 'ui.grid', 'ui.grid.selection',
+    'ui.grid.autoResize', 'jsonFormatter', 'ui.bootstrap', 'ui.slider'/*, 
'minicolors' */]);
+
+  // set up the routing for this plugin
+  QDR.module.config(function($routeProvider) {
+    $routeProvider
+      .when('/', {
+        templateUrl: QDR.templatePath + 'qdrConnect.html'
+        })
+      .when('/overview', {
+          templateUrl: QDR.templatePath + 'qdrOverview.html'
+        })
+      .when('/topology', {
+          templateUrl: QDR.templatePath + 'qdrTopology.html'
+        })
+      .when('/list', {
+          templateUrl: QDR.templatePath + 'qdrList.html'
+        })
+      .when('/schema', {
+          templateUrl: QDR.templatePath + 'qdrSchema.html'
+        })
+      .when('/charts', {
+          templateUrl: QDR.templatePath + 'qdrCharts.html'
+        })
+      .when('/connect', {
+          templateUrl: QDR.templatePath + 'qdrConnect.html'
+        })
+  });
+
+  QDR.module.config(['$compileProvider', function ($compileProvider) {
+       var cur = $compileProvider.aHrefSanitizationWhitelist();
+    
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|blob):/);
+       cur = $compileProvider.aHrefSanitizationWhitelist();
+  }]);
+
+       QDR.module.config(function (JSONFormatterConfigProvider) {
+               // Enable the hover preview feature
+        JSONFormatterConfigProvider.hoverPreviewEnabled = true;
+       });
+
+       QDR.module.filter('to_trusted', ['$sce', function($sce){
+          return function(text) {
+              return $sce.trustAsHtml(text);
+          };
+    }]);
+
+       QDR.module.filter('humanify', function (QDRService) {
+               return function (input) {
+                       return QDRService.humanify(input);
+               };
+       });
+
+       QDR.logger = function ($log) {
+               var log = $log;
+
+               this.debug = function (msg) { msg = "QDR: " + msg; 
log.debug(msg)};
+               this.error = function (msg) {msg = "QDR: " + msg; 
log.error(msg)}
+               this.info = function (msg) {msg = "QDR: " + msg; log.info(msg)}
+               this.warn = function (msg) {msg = "QDR: " + msg; log.warn(msg)}
+
+               return this;
+       }
+    // one-time initialization happens in the run function
+    // of our module
+       QDR.module.run( ["$rootScope", "$location", "$log", "QDRService", 
"QDRChartService",  function ($rootScope, $location, $log, QDRService, 
QDRChartService) {
+               QDR.log = new QDR.logger($log);
+               QDR.log.debug("QDR.module.run()")
+
+               QDRService.initProton();
+               var settings = angular.fromJson(localStorage[QDR.SETTINGS_KEY]);
+               var lastLocation = localStorage[QDR.LAST_LOCATION];
+               if (!angular.isDefined(lastLocation))
+                       lastLocation = "/overview";
+
+               QDRService.addConnectAction(function() {
+                       QDRChartService.init(); // initialize charting service 
after we are connected
+               });
+               if (settings && settings.autostart) {
+                       QDRService.addConnectAction(function() {
+                               $location.path(lastLocation);
+                               $location.replace();
+                               $rootScope.$apply();
+                       });
+                       QDRService.connect(settings);
+        } else {
+                       setTimeout(function () {
+                   $location.url('/connect')
+                               $location.replace();
+                       }, 100)
+        }
+
+        $rootScope.$on('$routeChangeSuccess', function() {
+            localStorage[QDR.LAST_LOCATION] = $location.$$path;
+        });
+
+
+       }]);
+
+       QDR.module.controller ("QDR.MainController", ['$scope', '$location', 
function ($scope, $location) {
+               QDR.log.debug("started QDR.MainController with location.url: " 
+ $location.url());
+               QDR.log.debug("started QDR.MainController with 
window.location.pathname : " + window.location.pathname);
+               $scope.topLevelTabs = [];
+               $scope.topLevelTabs.push({
+                       id: "qdr",
+                       content: "Qpid Dispatch Router Console",
+                       title: "Dispatch Router Console",
+                       isValid: function() { return true; },
+                       href: function() { return "#connect"; },
+                       isActive: function() { return true; }
+               });
+       }])
+
+       QDR.module.controller ("QDR.Core", function ($scope, $rootScope) {
+               $scope.alerts = [];
+               $scope.closeAlert = function(index) {
+            $scope.alerts.splice(index, 1);
+        };
+               $scope.$on('newAlert', function(event, data) {
+                       $scope.alerts.push(data);
+                       $scope.$apply();
+               });
+               $scope.$on("clearAlerts", function () {
+                       $scope.alerts = [];
+                       $scope.$apply();
+               })
+
+       })
+
+  return QDR;
+}(QDR || {}));

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/4940e63d/console/stand-alone/plugin/js/qdrSchema.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrSchema.js 
b/console/stand-alone/plugin/js/qdrSchema.js
new file mode 100644
index 0000000..0e94351
--- /dev/null
+++ b/console/stand-alone/plugin/js/qdrSchema.js
@@ -0,0 +1,31 @@
+/*
+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 QDR
+ */
+var QDR = (function (QDR) {
+
+    QDR.module.controller("QDR.SchemaController", ['$scope', 'QDRService', 
function($scope, QDRService) {
+
+        $scope.schema = QDRService.schema;
+
+    }]);
+
+    return QDR;
+}(QDR || {}));

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/4940e63d/console/stand-alone/plugin/js/qdrService.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrService.js 
b/console/stand-alone/plugin/js/qdrService.js
new file mode 100644
index 0000000..47029d7
--- /dev/null
+++ b/console/stand-alone/plugin/js/qdrService.js
@@ -0,0 +1,742 @@
+/*
+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 QDR
+ */
+var QDR = (function(QDR) {
+
+  // The QDR service handles the connection to
+  // the server in the background
+  QDR.module.factory("QDRService", ['$rootScope', '$http', '$resource', 
'$location', function($rootScope, $http, $resource, $location) {
+    var self = {
+
+         rhea: require("rhea"),
+
+      timeout: 10,
+      connectActions: [],
+      disconnectActions: [],
+      updatedActions: {},
+      stop: undefined,  // update interval handle
+
+      addConnectAction: function(action) {
+        if (angular.isFunction(action)) {
+          self.connectActions.push(action);
+        }
+      },
+      addDisconnectAction: function(action) {
+        if (angular.isFunction(action)) {
+          self.disconnectActions.push(action);
+        }
+      },
+      addUpdatedAction: function(key, action) {
+        if (angular.isFunction(action)) {
+            self.updatedActions[key] = action;
+        }
+      },
+      delUpdatedAction: function(key) {
+        if (key in self.updatedActions)
+            delete self.updatedActions[key];
+      },
+
+      executeConnectActions: function() {
+        self.connectActions.forEach(function(action) {
+          //QDR.log.debug("executing connect action " + action);
+          action.apply();
+        });
+        self.connectActions = [];
+      },
+      executeDisconnectActions: function() {
+        self.disconnectActions.forEach(function(action) {
+          action.apply();
+        });
+        self.disconnectActions = [];
+      },
+      executeUpdatedActions: function() {
+        for (action in self.updatedActions) {
+            self.updatedActions[action].apply();
+        }
+      },
+
+      notifyTopologyDone: function() {
+        //QDR.log.debug("got Toplogy done notice");
+
+        if (!angular.isDefined(self.schema))
+            return;
+        else if (self.topology._gettingTopo)
+            return;
+        if (!self.gotTopology) {
+            QDR.log.debug("topology was just initialized");
+            self.gotTopology = true;
+            self.executeConnectActions();
+            $rootScope.$apply();
+        } else {
+            QDR.log.debug("topology model was just updated");
+            self.executeUpdatedActions();
+        }
+
+      },
+      /**
+       * @property options
+       * Holds a reference to the connection options when
+       * a connection is started
+       */
+      options: undefined,
+
+      /*
+       * @property message
+       * The proton message that is used to send commands
+       * and receive responses
+       */
+               sender: undefined,
+               receiver: undefined,
+               sendable: false,
+
+      schema: undefined,
+
+      toAddress: undefined,
+      connected: false,
+      gotTopology: false,
+      errorText: undefined,
+         connectionError: undefined,
+
+      isConnected: function() {
+        return self.gotTopology;
+      },
+
+    correlator: {
+        _objects: {},
+        _corremationID: 0,
+
+        corr: function () {
+            var id = ++this._corremationID + "";
+                       this._objects[id] = {resolver: null}
+            return id;
+        },
+        request: function() {
+            //QDR.log.debug("correlator:request");
+            return this;
+        },
+        then: function(id, resolver, error) {
+            //QDR.log.debug("registered then resolver for correlationID: " + 
id);
+                       if (error) {
+                   delete this._objects[id];
+                               return;
+                       }
+            this._objects[id].resolver = resolver;
+        },
+        // called by receiver's on('message') handler when a response arrives
+        resolve: function(context) {
+                       var correlationID = 
context.message.properties.correlation_id;
+            this._objects[correlationID].resolver(context.message.body);
+            delete this._objects[correlationID];
+        }
+    },
+    
+    onSubscription: function() {
+        self.getSchema();
+        self.topology.get();
+     },
+
+    startUpdating: function () {
+        QDR.log.info("startUpdating called")
+        self.stopUpdating();
+        self.topology.get();
+        self.stop = setInterval(function() {
+            self.topology.get();
+        }, 2000);
+    },
+    stopUpdating: function () {
+        if (angular.isDefined(self.stop)) {
+            QDR.log.info("stoptUpdating called")
+            clearInterval(self.stop);
+            self.stop = undefined;
+        }
+    },
+
+      initProton: function() {
+        //QDR.log.debug("*************QDR init proton called ************");
+      },
+      cleanUp: function() {
+      },
+      error: function(line) {
+        if (line.num) {
+          QDR.log.debug("error - num: ", line.num, " message: ", line.message);
+        } else {
+          QDR.log.debug("error - message: ", line.message);
+        }
+      },
+      disconnected: function(line) {
+        QDR.log.debug("Disconnected from QDR server");
+        self.executeDisconnectActions();
+      },
+
+      nameFromId: function (id) {
+               return id.split('/')[3];
+      },
+
+      humanify: function (s) {
+          var t = s.charAt(0).toUpperCase() + s.substr(1).replace(/[A-Z]/g, ' 
$&');
+          return t.replace(".", " ");
+      },
+         pretty: function(v) {
+       var formatComma = d3.format(",");
+               if (!isNaN(parseFloat(v)) && isFinite(v))
+                       return formatComma(v);
+               return v;
+         },
+
+      nodeNameList: function() {
+        var nl = [];
+        // if we are in the middel of updating the topology
+        // then use the last known node info
+        var ni = self.topology._nodeInfo;
+        if (self.topology._gettingTopo)
+            ni = self.topology._lastNodeInfo;
+               for (var id in ni) {
+            nl.push(self.nameFromId(id));
+        }
+        return nl.sort();
+      },
+
+      nodeIdList: function() {
+        var nl = [];
+        // if we are in the middel of updating the topology
+        // then use the last known node info
+        var ni = self.topology._nodeInfo;
+        if (self.topology._gettingTopo)
+            ni = self.topology._lastNodeInfo;
+               for (var id in ni) {
+            nl.push(id);
+        }
+        return nl.sort();
+      },
+
+      nodeList: function () {
+        var nl = [];
+        var ni = self.topology._nodeInfo;
+        if (self.topology._gettingTopo)
+            ni = self.topology._lastNodeInfo;
+               for (var id in ni) {
+            nl.push({name: self.nameFromId(id), id: id});
+        }
+        return nl;
+      },
+
+      // given an attribute name array, find the value at the same index in 
the values array
+      valFor: function (aAr, vAr, key) {
+          var idx = aAr.indexOf(key);
+          if ((idx > -1) && (idx < vAr.length)) {
+              return vAr[idx];
+          }
+          return null;
+      },
+
+      /*
+       * send the management messages that build up the topology
+       *
+       *
+       */
+      topology: {
+        _gettingTopo: false,
+        _nodeInfo: {},
+        _lastNodeInfo: {},
+        _expected: {},
+        _timerHandle: null,
+
+        nodeInfo: function () {
+            return this._gettingTopo ? this._lastNodeInfo : this._nodeInfo;
+        },
+
+        get: function () {
+            if (this._gettingTopo)
+                return;
+            if (!self.connected) {
+                               QDR.log.debug("topology get failed because 
!self.connected")
+                return;
+            }
+            this._lastNodeInfo = angular.copy(this._nodeInfo);
+            this._gettingTopo = true;
+
+            self.errorText = undefined;
+            this.cleanUp(this._nodeInfo);
+            this._nodeInfo = {};
+            this._expected = {};
+
+            // get the list of nodes to query.
+            // once this completes, we will get the info for each node returned
+            self.getRemoteNodeInfo( function (response) {
+                //QDR.log.debug("got remote node list of ");
+                //console.dump(response);
+                if( Object.prototype.toString.call( response ) === '[object 
Array]' ) {
+                    // we expect a response for each of these nodes
+                    self.topology.wait(self.timeout);
+                    for (var i=0; i<response.length; ++i) {
+                        self.makeMgmtCalls(response[i]);
+                    }
+                };
+            });
+        },
+
+        cleanUp: function (obj) {
+/*
+            for (var o in obj) {
+                QDR.log.debug("cleaning up");
+                console.dump(obj[o]);
+                if (isNaN(parseInt(o)))
+                    this.cleanUp(obj[o]);
+            }
+*/
+            if (obj)
+                delete obj;
+        },
+        wait: function (timeout) {
+            this.timerHandle = setTimeout(this.timedOut, timeout * 1000);
+         },
+        timedOut: function () {
+        // a node dropped out. this happens when the get-mgmt-nodex
+        // results contains more nodes than actually respond within
+        // the timeout. However, if the responses we get don't contain
+        // the missing node, assume we are done.
+            QDR.log.debug("timed out waiting for management responses");
+            // note: can't use 'this' in a timeout handler
+            self.topology.dump("state at timeout");
+            // check if _nodeInfo is consistent
+            if (self.topology.isConsistent()) {
+                //TODO: notify controllers which node was dropped
+                // so they can keep an event log
+                self.topology.ondone();
+                return;
+            }
+            self.topology.onerror(Error("Timed out waiting for management 
responses"));
+        },
+        isConsistent: function () {
+            // see if the responses we have so far reference any nodes
+            // for which we don't have a response
+            var gotKeys = {};
+            for (var id in this._nodeInfo) {
+                var onode = this._nodeInfo[id];
+                var conn = onode['.connection'];
+                // get list of node names in the connection data
+                if (conn) {
+                    var containerIndex = 
conn.attributeNames.indexOf('container');
+                    var connectionResults = conn.results;
+                    if (containerIndex >= 0)
+                        for (var j=0; j < connectionResults.length; ++j) {
+                            // inter-router connection to a valid dispatch 
connection name
+                            gotKeys[connectionResults[j][containerIndex]] = 
""; // just add the key
+                        }
+                }
+            }
+            // gotKeys now contains all the container names that we have 
received
+            // Are any of the keys that are still expected in the gotKeys list?
+            var keys = Object.keys(gotKeys);
+            for (var id in this._expected) {
+                var key = self.nameFromId(id);
+                if (key in keys)
+                    return false;
+            }
+            return true;
+        },
+            
+        addNodeInfo: function (id, entity, values) {
+            // save the results in the nodeInfo object
+            if (id) {
+                if (!(id in self.topology._nodeInfo)) {
+                    self.topology._nodeInfo[id] = {};
+                }
+                self.topology._nodeInfo[id][entity] = values;
+            }
+  
+            // remove the id / entity from _expected
+            if (id in self.topology._expected) {
+                var entities = self.topology._expected[id];
+                var idx = entities.indexOf(entity);
+                if (idx > -1) {
+                    entities.splice(idx, 1);
+                    if (entities.length == 0)
+                        delete self.topology._expected[id];
+                }
+            }
+            // see if the expected obj is empty
+            if (Object.getOwnPropertyNames(self.topology._expected).length == 
0)
+                self.topology.ondone();
+            self.topology.cleanUp(values);
+        },
+        expect: function (id, key) {
+            if (!key || !id)
+                return;
+            if (!(id in this._expected))
+                this._expected[id] = [];
+            if (this._expected[id].indexOf(key) == -1)
+                this._expected[id].push(key);
+        },
+/*
+The response looks like:
+{
+    ".router": {
+        "results": [
+            [4, "router/QDR.X", 1, "0", 3, 60, 60, 11, "QDR.X", 30, 
"interior", "org.apache.qpid.dispatch.router", 5, 12, "router/QDR.X"]
+        ],
+        "attributeNames": ["raIntervalFlux", "name", "helloInterval", "area", 
"helloMaxAge", "mobileAddrMaxAge", "remoteLsMaxAge", "addrCount", "routerId", 
"raInterval", "mode", "type", "nodeCount", "linkCount", "identity"]
+    },
+    ".connection": {
+        "results": [
+            ["QDR.B", "connection/0.0.0.0:20002", "operational", 
"0.0.0.0:20002", "inter-router", "connection/0.0.0.0:20002", "ANONYMOUS", 
"org.apache.qpid.dispatch.connection", "out"],
+            ["QDR.A", "connection/0.0.0.0:20001", "operational", 
"0.0.0.0:20001", "inter-router", "connection/0.0.0.0:20001", "ANONYMOUS", 
"org.apache.qpid.dispatch.connection", "out"],
+            ["b2de2f8c-ef4a-4415-9a23-000c2f86e85d", 
"connection/localhost:33669", "operational", "localhost:33669", "normal", 
"connection/localhost:33669", "ANONYMOUS", 
"org.apache.qpid.dispatch.connection", "in"]
+        ],
+        "attributeNames": ["container", "name", "state", "host", "role", 
"identity", "sasl", "type", "dir"]
+    },
+    ".router.node": {
+        "results": [
+            ["QDR.A", null],
+            ["QDR.B", null],
+            ["QDR.C", "QDR.A"],
+            ["QDR.D", "QDR.A"],
+            ["QDR.Y", "QDR.A"]
+        ],
+        "attributeNames": ["routerId", "nextHop"]
+    }
+}*/
+        ondone: function () {
+            clearTimeout(this.timerHandle);
+            this._gettingTopo = false;
+            //this.miniDump();
+            //this.dump();
+            self.notifyTopologyDone();
+
+         },
+         dump: function (prefix) {
+            if (prefix)
+                QDR.log.debug(prefix);
+            QDR.log.debug("---");
+            for (var key in this._nodeInfo) {
+                QDR.log.debug(key);
+                console.dump(this._nodeInfo[key]);
+                QDR.log.debug("---");
+            }
+            QDR.log.debug("was still expecting:");
+            console.dump(this._expected);
+        },
+         miniDump: function (prefix) {
+            if (prefix)
+                QDR.log.debug(prefix);
+            QDR.log.debug("---");
+            console.dump(Object.keys(this._nodeInfo));
+            QDR.log.debug("---");
+        },
+        onerror: function (err) {
+            this._gettingTopo = false;
+            QDR.log.debug("Err:" + err);
+            self.executeDisconnectActions();
+
+        }
+
+      },
+
+      getRemoteNodeInfo: function (callback) {
+               //QDR.log.debug("getRemoteNodeInfo called");
+        var ret;
+        // first get the list of remote node names
+               self.correlator.request(
+                ret = self.sendMgmtQuery('GET-MGMT-NODES')
+            ).then(ret.id, function(response) {
+                callback(response);
+                self.topology.cleanUp(response);
+            }, ret.error);
+      },
+
+      makeMgmtCalls: function (id) {
+            var keys = [".router", ".connection", ".container", 
".router.node", ".listener", ".router.link"];
+            $.each(keys, function (i, key) {
+                self.topology.expect(id, key);
+                self.getNodeInfo(id, key, [], self.topology.addNodeInfo);
+            });
+      },
+
+      getNodeInfo: function (nodeName, entity, attrs, callback) {
+        //QDR.log.debug("getNodeInfo called with nodeName: " + nodeName + " 
and entity " + entity);
+        var ret;
+        self.correlator.request(
+            ret = self.sendQuery(nodeName, entity, attrs)
+        ).then(ret.id, function(response) {
+            // TODO: file a bug against rhea - large numbers are coming back 
as Uint8Array
+                       response.results.forEach( function (result) {
+                               result.forEach( function (val, i) {
+                                       if (val instanceof Uint8Array) {
+                                               var ua2num = function(ua) {
+                               var n = 0;
+                               for (var i = 0; i<ua.length; i++) {
+                                   n *= 256;
+                                   n += ua[i];
+                               }
+                               return n;
+                           }
+                           result[i] = ua2num(val);
+                                       }
+                               })
+                       })
+            callback(nodeName, entity, response);
+            //self.topology.addNodeInfo(nodeName, entity, response);
+            //self.topology.cleanUp(response);
+        }, ret.error);
+      },
+
+               getMultipleNodeInfo: function (nodeNames, entity, attrs, 
callback, selectedNodeId) {
+                       var responses = {};
+                       var gotNodesResult = function (nodeName, dotentity, 
response) {
+                               responses[nodeName] = response;
+                               if (Object.keys(responses).length == 
nodeNames.length) {
+                                       aggregateNodeInfo(nodeNames, entity, 
responses, callback);
+                               }
+                       }
+
+                       var aggregateNodeInfo = function (nodeNames, entity, 
responses, callback) {
+                               //QDR.log.debug("got all results for  " + 
entity);
+                               // aggregate the responses
+                               var newResponse = {};
+                               var thisNode = responses[selectedNodeId];
+                               newResponse['attributeNames'] = 
thisNode.attributeNames;
+                               newResponse['results'] = thisNode.results;
+                               newResponse['aggregates'] = [];
+                               for (var i=0; i<thisNode.results.length; ++i) {
+                                       var result = thisNode.results[i];
+                                       var vals = [];
+                                       result.forEach( function (val) {
+                                               vals.push({sum: val, detail: 
[]})
+                                       })
+                                       newResponse.aggregates.push(vals);
+                               }
+                               var nameIndex = 
thisNode.attributeNames.indexOf("name");
+                               var ent = self.schema.entityTypes[entity];
+                               var ids = Object.keys(responses);
+                               ids.sort();
+                               ids.forEach( function (id) {
+                                       var response = responses[id];
+                                       var results = response.results;
+                                       results.forEach( function (result) {
+                                               // find the matching result in 
the aggregates
+                                               var found = 
newResponse.aggregates.some( function (aggregate, j) {
+                                                       if 
(aggregate[nameIndex].sum === result[nameIndex]) {
+                                                               // result and 
aggregate are now the same record, add the graphable values
+                                                               
newResponse.attributeNames.forEach( function (key, i) {
+                                                                       if 
(ent.attributes[key] && ent.attributes[key].graph) {
+                                                                               
if (id != selectedNodeId)
+                                                                               
        aggregate[i].sum += result[i];
+                                                                               
aggregate[i].detail.push({node: self.nameFromId(id)+':', val: result[i]})
+                                                                       }
+                                                               })
+                                                               return true; // 
stop looping
+                                                       }
+                                                       return false; // 
continute looking for the aggregate record
+                                               })
+                                               if (!found) {
+                                                       // this attribute was 
not found in the aggregates yet
+                                                       // because it was not 
in the selectedNodeId's results
+                                                       var vals = [];
+                                                       result.forEach( 
function (val) {
+                                                               vals.push({sum: 
val, detail: []})
+                                                       })
+                                                       
newResponse.aggregates.push(vals)
+                                               }
+                                       })
+                               })
+                               callback(nodeNames, entity, newResponse);
+                       }
+
+                       nodeNames.forEach( function (id) {
+                   self.getNodeInfo(id, '.'+entity, attrs, gotNodesResult);
+               })
+                       //TODO: implement a timeout in case not all requests 
complete
+               },
+
+      getSchema: function () {
+        //QDR.log.debug("getting schema");
+        var ret;
+        self.correlator.request(
+            ret = self.sendMgmtQuery('GET-SCHEMA')
+        ).then(ret.id, function(response) {
+            //QDR.log.debug("Got schema response");
+                       self.schema = response;
+            //self.schema = angular.copy(response);
+            //self.topology.cleanUp(response);
+            self.notifyTopologyDone();
+        }, ret.error);
+      },
+
+    sendQuery: function(toAddr, entity, attrs) {
+        var toAddrParts = toAddr.split('/');
+        if (toAddrParts.shift() != "amqp:") {
+            self.topology.error(Error("unexpected format for router address: " 
+ toAddr));
+            return;
+        }
+        var fullAddr =  self.toAddress + "/" + toAddrParts.join('/');
+
+               var body;
+        if (attrs)
+            body = {
+                    "attributeNames": attrs,
+            }
+        else
+            body = {
+                "attributeNames": [],
+            }
+
+               return self._send(body, fullAddr, "QUERY", 
"org.apache.qpid.dispatch" + entity);
+    },
+
+    sendMgmtQuery: function (operation) {
+               // TODO: file bug against dispatch - We should be able to just 
pass body: [], but that generates an 'invalid body'
+               return self._send([' '], self.toAddress + "/$management", 
operation);
+    },
+
+       _send: function (body, to, operation, entityType) {
+               var ret = {id: self.correlator.corr()};
+               if (!self.sender || !self.sendable) {
+                       ret.error = "no sender"
+                       return ret;
+               }
+               try {
+                       var application_properties = {
+                               operation:  operation,
+                type:       "org.amqp.management",
+                name:       "self"
+            };
+                       if (entityType)
+                application_properties.entityType = entityType;
+
+               self.sender.send({
+                       body: body,
+                       properties: {
+                           to:                     to,
+                        reply_to:               
self.receiver.remote.attach.source.address,
+                           correlation_id:         ret.id
+                       },
+                       application_properties: application_properties
+            })
+               }
+               catch (e) {
+                       error = "error sending: " + e;
+                       QDR.log.error(error)
+                       ret.error = error;
+               }
+               return ret;
+       },
+
+      disconnect: function() {
+        self.connection.close();
+      },
+
+      connect: function(options) {
+        self.options = options;
+        self.topologyInitialized = false;
+               if (!self.connected) {
+                       var okay = {connection: false, sender: false, receiver: 
false}
+            var port = options.port || 5673;
+            var baseAddress = options.address + ':' + port;
+                       var ws = self.rhea.websocket_connect(WebSocket);
+                       self.toAddress = "amqp://" + baseAddress;
+                       self.connectionError = undefined;
+
+                       var stop = function (context) {
+                               //self.stopUpdating();
+                               if (self.connected) {
+                                   $rootScope.$broadcast('newAlert', { type: 
'danger', msg: 'Connection to ' + baseAddress + " was lost. Retrying..." });
+                               }
+                               okay.sender = false;
+                               okay.receiver = false;
+                               okay.connected = false;
+                               self.connected = false;
+                               self.sender = null;
+                               self.receiver = null;
+                               self.sendable = false;
+                       }
+
+                       var maybeStart = function () {
+                               if (okay.connection && okay.sender && 
okay.receiver && self.sendable && !self.connected) {
+                                       QDR.log.info("okay to start")
+                                       self.connected = true;
+                                       self.connection = connection;
+                                       self.sender = sender;
+                                       self.receiver = receiver;
+                                       self.onSubscription();
+                                       $rootScope.$broadcast("clearAlerts");
+                               }
+                       }
+
+                       QDR.log.debug("****** calling rhea.connect ********")
+            var connection = self.rhea.connect({
+                    connection_details:ws('ws://' + baseAddress),
+                    reconnect:true,
+                    properties: {console_identifier: 'Dispatch console'}
+            });
+                       connection.on('connection_open', function (context) {
+                               QDR.log.debug("connection_opened")
+                               okay.connection = true;
+                               okay.receiver = false;
+                               okay.sender = false;
+                       })
+                       connection.on('disconnected', function (context) {
+                               QDR.log.warn("disconnected");
+                               stop();
+                               self.errorText = "Error: Connection failed."
+                               self.executeDisconnectActions();
+                               self.connectionError = true;
+                       })
+                       connection.on('connection_close', function (context) { 
QDR.log.warn("connection_close"); stop()})
+
+                       var sender = connection.open_sender("/$management");
+                       sender.on('sender_open', function (context) {
+                               QDR.log.debug("sender_opened")
+                               okay.sender = true
+                               maybeStart()
+                       })
+                       sender.on('sendable', function (context) {
+                               //QDR.log.debug("sendable")
+                               self.sendable = true;
+                               maybeStart();
+                       })
+
+                       var receiver = connection.open_receiver({source: 
{dynamic: true}});
+                       receiver.on('receiver_open', function (context) {
+                               QDR.log.debug("receiver_opened")
+                               okay.receiver = true;
+                               maybeStart()
+                       })
+                       receiver.on("message", function (context) {
+                               self.correlator.resolve(context);
+                       });
+
+               }
+      }
+    }
+      return self;
+  }]);
+
+  return QDR;
+}(QDR || {}));
+
+(function() {
+    console.dump = function(object) {
+        if (window.JSON && window.JSON.stringify)
+            console.log(JSON.stringify(object));
+        else
+            console.log(object);
+    };
+})();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/4940e63d/console/stand-alone/plugin/js/qdrSettings.js
----------------------------------------------------------------------
diff --git a/console/stand-alone/plugin/js/qdrSettings.js 
b/console/stand-alone/plugin/js/qdrSettings.js
new file mode 100644
index 0000000..950e1c5
--- /dev/null
+++ b/console/stand-alone/plugin/js/qdrSettings.js
@@ -0,0 +1,115 @@
+/*
+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 QDR
+ */
+var QDR = (function (QDR) {
+
+  /**
+   * @method SettingsController
+   * @param $scope
+   * @param QDRServer
+   *
+   * Controller that handles the QDR settings page
+   */
+  QDR.module.controller("QDR.SettingsController", ['$scope', 'QDRService', 
'$location', function($scope, QDRService, $location) {
+
+    $scope.connecting = false;
+    $scope.connectionError = false;
+    $scope.connectionErrorText = undefined;
+    $scope.forms = {};
+
+    $scope.formEntity = angular.fromJson(localStorage[QDR.SETTINGS_KEY]) || 
{address: '', port: '', username: '', password: '', autostart: false};
+    $scope.formConfig = {
+      properties: {
+        address: {
+          description: "Router address",
+          'type': 'java.lang.String',
+          required: true
+        },
+        port: {
+          description: 'Router port',
+          'type': 'Integer',
+          tooltip: 'Ports to connect to, by default 5672'
+        },
+        username: {
+          description: 'User Name',
+          'type': 'java.lang.String'
+        },
+        password: {
+          description: 'Password',
+          'type': 'password'
+        },
+        /*
+        useSSL: {
+          description: 'SSL',
+          'type': 'boolean'
+        },*/
+        autostart: {
+          description: 'Connect at startup',
+          'type': 'boolean',
+          tooltip: 'Whether or not the connection should be started as soon as 
you log into hawtio'
+        }
+      }
+    };
+
+    $scope.$watch('formEntity', function(newValue, oldValue) {
+      if (newValue !== oldValue) {
+        localStorage[QDR.SETTINGS_KEY] = angular.toJson(newValue);
+      }
+    }, true);
+
+    $scope.buttonText = function() {
+      if (QDRService.isConnected()) {
+        return "Reconnect";
+      } else {
+        return "Connect";
+      }
+    };
+
+    
+    $scope.connect = function() {
+      if ($scope.settings.$valid) {
+        $scope.connectionError = false;
+        $scope.connecting = true;
+        console.log("attempting to connect");
+        QDRService.addDisconnectAction(function() {
+          //QDR.log.debug("disconnect action called");
+          $scope.connecting = false;
+          $scope.connectionErrorText = QDRService.errorText;
+          $scope.connectionError = true;
+          $scope.$apply();
+        });
+        QDRService.addConnectAction(function() {
+          //QDR.log.debug("got connection notification");
+          $scope.connecting = false;
+          //console.log("we were on connect page. let's switch to topo now 
that we are connected");
+          //QDR.log.debug("location before the connect " + $location.path());
+          $location.path("/overview");
+          //QDR.log.debug("location after the connect " + $location.path());
+          $scope.$apply();
+        });
+        QDRService.connect($scope.formEntity);
+      }
+    };
+
+  }]);
+
+  return QDR;
+}(QDR || {}));


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to