| /* |
| 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.NodeDialogController", function($scope, QDRService, $uibModalInstance, newname) { |
| var schema = QDRService.schema; |
| var myEntities = ['router', 'log', 'listener']; |
| var typeMap = { |
| integer: 'number', |
| string: 'text', |
| path: 'text', |
| boolean: 'boolean' |
| }; |
| var newLinks = $('path.temp').toArray(); // jquery array of new links for the added router |
| var nodeInfo = QDRService.topology.nodeInfo(); |
| var separatedEntities = []; // additional entities required if a link is reversed |
| var myPort = 0, |
| myAddr = '0.0.0.0'; // port and address for new router |
| $scope.entities = []; |
| |
| // find max port number that is used in all the listeners |
| var getMaxPort = function(nodeInfo) { |
| var maxPort = 5674; |
| for (var key in nodeInfo) { |
| var node = nodeInfo[key]; |
| var listeners = node['.listener']; |
| var attrs = listeners.attributeNames; |
| for (var i = 0; i < listeners.results.length; ++i) { |
| var res = listeners.results[i]; |
| var port = QDRService.valFor(attrs, res, 'port'); |
| if (parseInt(port, 10) > maxPort) |
| maxPort = parseInt(port, 10); |
| } |
| } |
| return maxPort; |
| } |
| var maxPort = getMaxPort(nodeInfo); |
| |
| // construct an object that contains all the info needed for a single tab's fields |
| var entity = function(actualName, tabName, humanName, ent, icon, link) { |
| var nameIndex = -1; // the index into attributes that the name field was placed |
| var index = 0; |
| var info = { |
| actualName: actualName, |
| tabName: tabName, |
| humanName: humanName, |
| description: ent.description, |
| icon: angular.isDefined(icon) ? icon : '', |
| references: ent.references, |
| link: link, |
| |
| attributes: $.map(ent.attributes, function(value, key) { |
| // skip identity and depricated fields |
| if (key == 'identity' || value.description.startsWith('Deprecated')) |
| return null; |
| var val = value['default']; |
| if (key == 'name') |
| nameIndex = index; |
| index++; |
| return { |
| name: key, |
| humanName: QDRService.humanify(key), |
| description: value.description, |
| type: typeMap[value.type], |
| rawtype: value.type, |
| input: typeof value.type == 'string' ? value.type == 'boolean' ? 'boolean' : 'input' : 'select', |
| selected: val ? val : undefined, |
| 'default': value['default'], |
| value: val, |
| required: value.required, |
| unique: value.unique |
| }; |
| }) |
| } |
| // move the 'name' attribute to the 1st position |
| if (nameIndex > -1) { |
| var tmp = info.attributes[0]; |
| info.attributes[0] = info.attributes[nameIndex]; |
| info.attributes[nameIndex] = tmp; |
| } |
| return info; |
| } |
| |
| // remove the annotation fields |
| var stripAnnotations = function(entityName, ent, annotations) { |
| if (ent.references) { |
| var newEnt = { |
| attributes: {} |
| }; |
| ent.references.forEach(function(annoKey) { |
| if (!annotations[annoKey]) |
| annotations[annoKey] = {}; |
| annotations[annoKey][entityName] = true; // create the key/consolidate duplicates |
| var keys = Object.keys(schema.annotations[annoKey].attributes); |
| for (var attrib in ent.attributes) { |
| if (keys.indexOf(attrib) == -1) { |
| newEnt.attributes[attrib] = ent.attributes[attrib]; |
| } |
| } |
| // add a field for the reference name |
| newEnt.attributes[annoKey] = { |
| type: 'string', |
| description: 'Name of the ' + annoKey + ' section.', |
| 'default': annoKey, |
| required: true |
| }; |
| }) |
| newEnt.references = ent.references; |
| newEnt.description = ent.description; |
| return newEnt; |
| } |
| return ent; |
| } |
| |
| var annotations = {}; |
| myEntities.forEach(function(entityName) { |
| var ent = schema.entityTypes[entityName]; |
| var hName = QDRService.humanify(entityName); |
| if (entityName == 'listener') |
| hName = "Listener for clients"; |
| var noAnnotations = stripAnnotations(entityName, ent, annotations); |
| var ediv = entity(entityName, entityName, hName, noAnnotations, undefined); |
| if (ediv.actualName == 'router') { |
| ediv.attributes.filter(function(attr) { |
| return attr.name == 'name' |
| })[0].value = newname; |
| // if we have any new links (connectors), then the router's mode should be interior |
| if (newLinks.length) { |
| var roleAttr = ediv.attributes.filter(function(attr) { |
| return attr.name == 'mode' |
| })[0]; |
| roleAttr.value = roleAttr.selected = "interior"; |
| } |
| } |
| if (ediv.actualName == 'container') { |
| ediv.attributes.filter(function(attr) { |
| return attr.name == 'containerName' |
| })[0].value = newname + "-container"; |
| } |
| if (ediv.actualName == 'listener') { |
| // find max port number that is used in all the listeners |
| ediv.attributes.filter(function(attr) { |
| return attr.name == 'port' |
| })[0].value = ++maxPort; |
| } |
| // special case for required log.module since it doesn't have a default |
| if (ediv.actualName == 'log') { |
| var moduleAttr = ediv.attributes.filter(function(attr) { |
| return attr.name == 'module' |
| })[0]; |
| moduleAttr.value = moduleAttr.selected = "DEFAULT"; |
| } |
| $scope.entities.push(ediv); |
| }) |
| |
| // add a tab for each annotation that was found |
| var annotationEnts = []; |
| for (var key in annotations) { |
| ent = angular.copy(schema.annotations[key]); |
| ent.attributes.name = { |
| type: "string", |
| unique: true, |
| description: "Unique name that is used to refer to this set of attributes." |
| } |
| var ediv = entity(key, key + 'tab', QDRService.humanify(key), ent, undefined); |
| ediv.attributes.filter(function(attr) { |
| return attr.name == 'name' |
| })[0].value = key; |
| $scope.entities.push(ediv); |
| annotationEnts.push(ediv); |
| } |
| |
| // add an additional listener tab if any links are reversed |
| ent = schema.entityTypes['listener']; |
| newLinks.some(function(link) { |
| if (link.__data__.right) { |
| var noAnnotations = stripAnnotations('listener', ent, annotations); |
| var ediv = entity("listener", "listener0", "Listener (internal)", noAnnotations, undefined); |
| ediv.attributes.filter(function(attr) { |
| return attr.name == 'port' |
| })[0].value = ++maxPort; |
| // connectors from other routers need to connect to this addr:port |
| myPort = maxPort; |
| myAddr = ediv.attributes.filter(function(attr) { |
| return attr.name == 'host' |
| })[0].value |
| |
| // override the role. 'normal' is the default, but we want inter-router |
| ediv.attributes.filter(function(attr) { |
| return attr.name == 'role' |
| })[0].selected = 'inter-router'; |
| separatedEntities.push(ediv); |
| return true; // stop looping |
| } |
| return false; // continue looping |
| }) |
| |
| // Add connector tabs for each new link on the topology graph |
| ent = schema.entityTypes['connector']; |
| newLinks.forEach(function(link, i) { |
| var noAnnotations = stripAnnotations('connector', ent, annotations); |
| var ediv = entity('connector', 'connector' + i, " " + link.__data__.source.name, noAnnotations, link.__data__.right, link) |
| |
| // override the connector role. 'normal' is the default, but we want inter-router |
| ediv.attributes.filter(function(attr) { |
| return attr.name == 'role' |
| })[0].selected = 'inter-router'; |
| |
| // find the addr:port of the inter-router listener to use |
| var listener = nodeInfo[link.__data__.source.key]['.listener']; |
| var attrs = listener.attributeNames; |
| for (var i = 0; i < listener.results.length; ++i) { |
| var res = listener.results[i]; |
| var role = QDRService.valFor(attrs, res, 'role'); |
| if (role == 'inter-router') { |
| ediv.attributes.filter(function(attr) { |
| return attr.name == 'host' |
| })[0].value = |
| QDRService.valFor(attrs, res, 'host') |
| ediv.attributes.filter(function(attr) { |
| return attr.name == 'port' |
| })[0].value = |
| QDRService.valFor(attrs, res, 'port') |
| break; |
| } |
| } |
| if (link.__data__.right) { |
| // connectors from other nodes need to connect to the new router's listener addr:port |
| ediv.attributes.filter(function(attr) { |
| return attr.name == 'port' |
| })[0].value = myPort; |
| ediv.attributes.filter(function(attr) { |
| return attr.name == 'host' |
| })[0].value = myAddr; |
| |
| separatedEntities.push(ediv) |
| } else |
| $scope.entities.push(ediv); |
| }) |
| Array.prototype.push.apply($scope.entities, separatedEntities); |
| |
| // update the description on all the annotation tabs |
| annotationEnts.forEach(function(ent) { |
| var shared = Object.keys(annotations[ent.actualName]); |
| ent.description += " These fields are shared by " + shared.join(" and ") + "."; |
| |
| }) |
| |
| $scope.testPattern = function(attr) { |
| if (attr.rawtype == 'path') |
| return /^(\/)?([^/\0]+(\/)?)+$/; |
| //return /^(.*\/)([^/]*)$/; |
| return /(.*?)/; |
| } |
| |
| $scope.attributeDescription = ''; |
| $scope.attributeType = ''; |
| $scope.attributeRequired = ''; |
| $scope.attributeUnique = ''; |
| $scope.active = 'router' |
| $scope.fieldsetDivs = "/fieldsetDivs.html" |
| $scope.setActive = function(tabName) { |
| $scope.active = tabName |
| } |
| $scope.isActive = function(tabName) { |
| return $scope.active === tabName |
| } |
| $scope.showDescription = function(attr, e) { |
| $scope.attributeDescription = attr.description; |
| var offset = jQuery(e.currentTarget).offset() |
| jQuery('.attr-description').offset({ |
| top: offset.top |
| }) |
| |
| $scope.attributeType = "Type: " + JSON.stringify(attr.rawtype); |
| $scope.attributeRequired = attr.required ? 'required' : ''; |
| $scope.attributeUnique = attr.unique ? 'Must be unique' : ''; |
| } |
| // handle the download button click |
| // copy the dialog's values to the original node |
| $scope.download = function() { |
| $uibModalInstance.close({ |
| entities: $scope.entities, |
| annotations: annotations |
| }); |
| } |
| $scope.cancel = function() { |
| $uibModalInstance.close() |
| }; |
| |
| $scope.selectAnnotationTab = function(tabName) { |
| var tabs = $("#tabs").tabs(); |
| tabs.tabs("select", tabName); |
| } |
| |
| var initTabs = function() { |
| var div = angular.element("#tabs"); |
| if (!div.width()) { |
| setTimeout(initTabs, 100); |
| return; |
| } |
| $("#tabs") |
| .tabs() |
| .addClass('ui-tabs-vertical ui-helper-clearfix'); |
| } |
| // start the update loop |
| initTabs(); |
| |
| }); |
| |
| QDR.module.controller("QDR.DownloadDialogController", function($scope, QDRService, $templateCache, $window, $uibModalInstance, results) { |
| var result = results.entities; |
| var annotations = results.annotations; |
| var annotationKeys = Object.keys(annotations); |
| var annotationSections = {}; |
| |
| // use the router's name as the file name if present |
| $scope.newRouterName = 'router'; |
| result.forEach(function(e) { |
| if (e.actualName == 'router') { |
| e.attributes.forEach(function(a) { |
| if (a.name == 'name') { |
| $scope.newRouterName = a.value; |
| } |
| }) |
| } |
| }) |
| $scope.newRouterName = $scope.newRouterName + ".conf"; |
| |
| var template = $templateCache.get('config-file-header.html'); |
| $scope.verbose = true; |
| $scope.$watch('verbose', function(newVal) { |
| if (newVal !== undefined) { |
| // recreate output using current verbose setting |
| getOutput(); |
| } |
| }) |
| |
| var getOutput = function() { |
| $scope.output = template + '\n'; |
| $scope.parts = []; |
| var commentChar = '#' |
| result.forEach(function(entity) { |
| // don't output a section for annotations, they get flattened into the entities |
| var section = ""; |
| if (entity.icon) { |
| section += "##\n## Add to " + entity.link.__data__.source.name + "'s configuration file\n##\n"; |
| } |
| section += "##\n## " + QDRService.humanify(entity.actualName) + " - " + entity.description + "\n##\n"; |
| section += entity.actualName + " {\n"; |
| entity.attributes.forEach(function(attribute) { |
| if (attribute.input == 'select') |
| attribute.value = attribute.selected; |
| |
| // treat values with all spaces and empty strings as undefined |
| attribute.value = String(attribute.value).trim(); |
| if (attribute.value === 'undefined' || attribute.value === '') |
| attribute.value = undefined; |
| |
| if ($scope.verbose) { |
| commentChar = attribute.required || attribute.value != attribute['default'] ? ' ' : '#'; |
| if (!attribute.value) { |
| commentChar = '#'; |
| attribute.value = ''; |
| } |
| section += commentChar + " " + attribute.name + ":" + Array(Math.max(20 - attribute.name.length, 1)).join(" ") + attribute.value + Array(Math.max(20 - ((attribute.value) + "").length, 1)).join(" ") + '# ' + attribute.description + "\n"; |
| } else { |
| if (attribute.value) { |
| if (attribute.value != attribute['default'] || attribute.required) |
| section += " " + attribute.name + ":" + Array(20 - attribute.name.length).join(" ") + attribute.value + "\n"; |
| |
| } |
| } |
| }) |
| section += "}\n\n"; |
| // if entity.icon is true, this is a connector intended for another router |
| if (entity.icon) |
| $scope.parts.push({ |
| output: section, |
| link: entity.link, |
| name: entity.link.__data__.source.name, |
| references: entity.references |
| }); |
| else |
| $scope.output += section; |
| |
| // if this section is actually an annotation |
| if (annotationKeys.indexOf(entity.actualName) > -1) { |
| annotationSections[entity.actualName] = section; |
| } |
| }) |
| // go back and add annotation sections to the parts |
| $scope.parts.forEach(function(part) { |
| for (var section in annotationSections) { |
| if (part.references.indexOf(section) > -1) { |
| part.output += annotationSections[section]; |
| } |
| } |
| }) |
| QDR.log.debug($scope.output); |
| } |
| |
| // handle the download button click |
| $scope.download = function() { |
| var output = $scope.output + "\n\n" |
| var blob = new Blob([output], { |
| type: 'text/plain;charset=utf-16' |
| }); |
| saveAs(blob, $scope.newRouterName); |
| } |
| |
| $scope.downloadPart = function(part) { |
| var linkName = part.link.__data__.source.name + 'additional.conf'; |
| var blob = new Blob([part.output], { |
| type: 'text/plain;charset=utf-16' |
| }); |
| saveAs(blob, linkName); |
| } |
| |
| $scope.done = function() { |
| $uibModalInstance.close(); |
| } |
| }); |
| |
| return QDR; |
| }(QDR || {})); |