blob: 0a0a7599a5f24113a601a019f4c07bb92c30a8a0 [file] [log] [blame]
/*
* 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.
*/
import {Component, OnInit, ViewChild} from '@angular/core';
import {ResourceService} from '../resource/resource.service';
import {Resource} from '../resource/resource';
import {ProviderConfig} from './provider-config';
import {Descriptor} from './descriptor';
import {Service} from '../resource/service';
import {parseString} from 'xml2js';
import 'brace/theme/monokai';
import 'brace/mode/xml';
import {ProviderConfigSelectorComponent} from '../provider-config-selector/provider-config-selector.component';
import {ResourceTypesService} from '../resourcetypes/resourcetypes.service';
import {HttpErrorResponse} from '@angular/common/http';
@Component({
selector: 'app-resource-detail',
templateUrl: './resource-detail.component.html',
styleUrls: ['./resource-detail.component.css']
})
export class ResourceDetailComponent implements OnInit {
// Static "empty" Resource used for clearing the display between resource selections
private static emptyResource: Resource = new Resource();
private static emptyDescriptor: Descriptor = new Descriptor();
title: string;
resourceType: string;
resource: Resource;
resourceContent: string;
providers: Array<ProviderConfig>;
readOnlyProviderConfig: boolean;
changedProviders: Array<ProviderConfig>;
descriptor: Descriptor;
@ViewChild('choosePC')
chooseProviderConfigModal: ProviderConfigSelectorComponent;
referencedProviderConfigError = false;
constructor(private resourceService: ResourceService, private resourceTypesService: ResourceTypesService) {
}
ngOnInit() {
this.resourceService.selectedResourceType$.subscribe(type => this.setResourceType(type));
this.resourceService.selectedResource$.subscribe(value => this.setResource(value));
}
setResourceType(resType: string) {
// Clear the current resource details
if (this.resource) {
this.resource.name = '';
} // This clears the details title when the type context changes
this.resource = ResourceDetailComponent.emptyResource;
this.providers = null;
this.descriptor = ResourceDetailComponent.emptyDescriptor;
this.resourceContent = ''; // Clear the content area
this.resourceType = resType;
}
setResource(res: Resource) {
this.referencedProviderConfigError = false;
this.resource = res;
this.providers = [];
this.changedProviders = null;
this.descriptor = ResourceDetailComponent.emptyDescriptor;
if (res) {
this.resourceService.getResource(this.resourceType, res)
.then(content => this.setResourceContent(res, content))
.catch((error: HttpErrorResponse) => {
console.debug('Error accessing content for ' + res.name + ' : ' + error);
});
}
}
setResourceContent(res: Resource, content: string) {
switch (this.resourceType) {
case 'Provider Configurations': {
this.setProviderConfigContent(res, content);
break;
}
case 'Descriptors': {
this.setDescriptorContent(res, content);
break;
}
}
}
setProviderConfigContent(res: Resource, content: string) {
this.resourceContent = content;
if (this.resourceContent) {
try {
let contentObj;
if (res.name.endsWith('json')) {
// Parse the JSON representation
contentObj = JSON.parse(this.resourceContent);
this.providers = contentObj['providers'];
this.readOnlyProviderConfig = contentObj['readOnly'];
} else if (res.name.endsWith('yaml') || res.name.endsWith('yml')) {
// Parse the YAML representation
let yaml = require('js-yaml');
contentObj = yaml.safeLoad(this.resourceContent);
this.providers = contentObj['providers'];
this.readOnlyProviderConfig = contentObj['readOnly'];
} else if (res.name.endsWith('xml')) {
// Parse the XML representation
parseString(this.resourceContent,
(error, result) => {
if (error) {
console.log('Error parsing ' + res.name + ' error: ' + error);
} else {
// Parsing the XML is a bit less straight-forward
let tempProviders = new Array<ProviderConfig>();
result['gateway'].provider.forEach(entry => {
let providerConfig: ProviderConfig = new ProviderConfig();
providerConfig.role = entry.role[0];
providerConfig.name = entry.name[0];
providerConfig.enabled = entry.enabled[0];
// There may not be params
if (entry.param) {
let params = new Map<string, string>();
for (let i = 0; i < entry.param.length; i++) {
let param = entry.param[i];
params[param.name[0]] = param.value[0];
}
providerConfig.params = params;
}
tempProviders.push(providerConfig);
});
this.providers = tempProviders;
this.readOnlyProviderConfig = result['gateway'].readOnly;
}
});
}
} catch (e) {
console.error('ResourceDetailComponent --> setProviderConfigContent() --> Error parsing ' + res.name + ' content: ' + e);
this.providers = null; // Clear detail display
}
}
}
setDescriptorContent(res: Resource, content: string) {
this.resourceContent = content;
if (this.resourceContent) {
try {
let contentObj;
if (res.name.endsWith('json')) {
contentObj = JSON.parse(this.resourceContent);
} else if (res.name.endsWith('yaml') || res.name.endsWith('yml')) {
let yaml = require('js-yaml');
contentObj = yaml.load(this.resourceContent);
}
let tempDesc = new Descriptor();
if (contentObj) {
tempDesc.discoveryType = contentObj['discovery-type'];
tempDesc.discoveryAddress = contentObj['discovery-address'];
tempDesc.discoveryUser = contentObj['discovery-user'];
tempDesc.discoveryPassAlias = contentObj['discovery-pwd-alias'];
tempDesc.discoveryCluster = contentObj['cluster'];
tempDesc.providerConfig = contentObj['provider-config-ref'];
tempDesc.readOnly = contentObj['read-only'];
tempDesc.services = contentObj['services'];
}
this.descriptor = tempDesc;
} catch (e) {
console.error('ResourceDetailComponent.setDescriptorContent: Error parsing ' + res.name + ' content: ' + e);
}
}
}
persistChanges() {
switch (this.resourceType) {
case 'Provider Configurations' : {
this.persistProviderConfiguration();
break;
}
case 'Descriptors': {
this.persistDescriptor();
}
}
}
persistProviderConfiguration() {
let content;
let ext = this.resource.name.split('.').pop();
switch (ext) {
case 'json': {
content = this.resourceService.serializeProviderConfiguration(this.providers, 'json');
break;
}
case 'yaml':
case 'yml': {
content = this.resourceService.serializeProviderConfiguration(this.providers, 'yaml');
break;
}
case 'xml': {
// We're not going to bother serializing XML. Rather, delete the original XML resource, and replace it
// with JSON
console.debug('Replacing XML provider configuration ' + this.resource.name + ' with JSON...');
// Generate the JSON representation of the updated provider configuration
content = this.resourceService.serializeProviderConfiguration(this.providers, 'json');
let replacementResource = new Resource();
replacementResource.name = this.resource.name.slice(0, -4) + '.json';
replacementResource.href = this.resource.href;
// Delete the XML resource
this.resourceService.deleteResource(this.resource.href + '?force=true')
.then(() => {
// Save the updated content
this.resourceService.saveResource(replacementResource, content).then(() => {
// Update the list of provider configuration to ensure that the XML one is replaced with the JSON one
this.resourceTypesService.selectResourceType(this.resourceType);
// Update the detail view
this.resourceService.selectedResource(replacementResource);
})
.catch(err => {
console.error('Error persisting ' + replacementResource.name + ' : ' + err);
});
});
break;
}
}
// For the non-XML provider configuration cases, simply save the changes
if (ext !== 'xml') {
// Save the updated content
this.resourceService.saveResource(this.resource, content)
.then(() => {
// Refresh the presentation
this.resourceService.selectedResource(this.resource);
})
.catch(err => {
console.error('Error persisting ' + this.resource.name + ' : ' + err);
});
}
}
persistDescriptor() {
let content;
let ext = this.resource.name.split('.').pop();
switch (ext) {
case 'json': {
content = this.resourceService.serializeDescriptor(this.descriptor, 'json');
break;
}
case 'yaml':
case 'yml': {
content = this.resourceService.serializeDescriptor(this.descriptor, 'yaml');
break;
}
}
// Save the updated content
this.resourceService.saveResource(this.resource, content)
.then(() => {
// Refresh the presentation
this.resourceService.selectedResource(this.resource);
})
.catch(err => {
console.error('Error persisting ' + this.resource.name + ' : ' + err);
});
}
discardChanges() {
this.resourceService.selectedResource(this.resource);
}
deleteResource() {
let resourceName = this.resource.name;
this.resourceService.deleteResource(this.resource.href)
.then(() => {
console.debug('Deleted ' + resourceName);
// This refreshes the list of resources
this.resourceTypesService.selectResourceType(this.resourceType);
})
.catch((err: HttpErrorResponse) => {
if (err.status === 304) { // Not Modified
console.log(resourceName + ' cannot be deleted while there are descriptors actively referencing it.');
this.referencedProviderConfigError = true;
} else {
console.error('Error deleting ' + resourceName + ' : ' + err.message);
}
});
}
onRemoveProvider(name: string) {
for (let i = 0; i < this.providers.length; i++) {
if (this.providers[i].name === name) {
this.providers.splice(i, 1);
break;
}
}
this.changedProviders = this.providers;
}
onProviderEnabled(provider: ProviderConfig) {
provider.enabled = this.isProviderEnabled(provider) ? 'false' : 'true';
this.changedProviders = this.providers;
}
onRemoveProviderParam(pc: ProviderConfig, paramName: string) {
if (pc.params.hasOwnProperty(paramName)) {
delete pc.params[paramName];
}
this.changedProviders = this.providers;
}
onRemoveDescriptorService(serviceName: string) {
for (let i = 0; i < this.descriptor.services.length; i++) {
if (this.descriptor.services[i].name === serviceName) {
this.descriptor.services.splice(i, 1);
this.descriptor.setDirty();
break;
}
}
}
onRemoveDescriptorServiceParam(serviceName: string, paramName: string) {
let done = false;
for (let i = 0; i < this.descriptor.services.length; i++) {
if (this.descriptor.services[i].name === serviceName) {
let service = this.descriptor.services[i];
if (service.params.hasOwnProperty(paramName)) {
delete service.params[paramName];
this.descriptor.setDirty();
done = true;
break;
}
}
if (done) { // Stop checking services if it has already been handled
break;
}
}
}
onRemoveDescriptorServiceURL(serviceName: string, serviceUrl: string) {
let done = false;
for (let i = 0; i < this.descriptor.services.length; i++) {
if (this.descriptor.services[i].name === serviceName) {
let service = this.descriptor.services[i];
for (let j = 0; j < service.urls.length; j++) {
if (service.urls[j] === serviceUrl) {
service.urls.splice(j, 1);
this.descriptor.setDirty();
done = true;
break;
}
}
}
if (done) { // Stop checking services if it has already been handled
break;
}
}
}
toggleShowProvider(provider: ProviderConfig) {
this[this.resource.name + provider.name + 'Show'] = !this.isShowProvider(provider);
}
isShowProvider(provider: ProviderConfig): boolean {
return this[this.resource.name + provider.name + 'Show'];
}
toggleShowProviderParams(provider: ProviderConfig) {
this[this.resource.name + provider.name + 'ShowParams'] = !this.isShowProviderParams(provider);
}
showProviderParams(provider: ProviderConfig) {
this[this.resource.name + provider.name + 'ShowParams'] = true;
}
isShowProviderParams(provider: ProviderConfig): boolean {
return this[this.resource.name + provider.name + 'ShowParams'];
}
toggleShowServices() {
this[this.resource.name + 'ShowServices'] = !this.isShowServices();
}
showServices() {
this[this.resource.name + 'ShowServices'] = true;
}
isShowServices(): boolean {
return this[this.resource.name + 'ShowServices'];
}
toggleShowServiceDiscovery() {
this[this.resource.name + 'ShowDiscovery'] = !this.isShowServiceDiscovery();
}
isShowServiceDiscovery(): boolean {
return this[this.resource.name + 'ShowDiscovery'];
}
toggleShowServiceParams(service: Service) {
this[this.resource.name + service.name + 'ShowParams'] = !this.isShowServiceParams(service);
}
showServiceParams(service: Service) {
this[this.resource.name + service.name + 'ShowParams'] = true;
}
isShowServiceParams(service: Service): boolean {
return this[this.resource.name + service.name + 'ShowParams'];
}
toggleShowServiceURLs(service: Service) {
this[this.resource.name + service.name + 'ShowURLs'] = !this.isShowServiceURLs(service);
}
showServiceURLs(service: Service) {
this[this.resource.name + service.name + 'ShowURLs'] = true;
}
isShowServiceURLs(service: Service): boolean {
return this[this.resource.name + service.name + 'ShowURLs'];
}
setProviderParamEditFlag(provider: ProviderConfig, paramName: string, value: boolean) {
this[provider.name + paramName + 'EditMode'] = value;
this.changedProviders = this.providers;
}
getProviderParamEditFlag(provider: ProviderConfig, paramName: string): boolean {
return this[provider.name + paramName + 'EditMode'];
}
setServiceVersionEditFlag(service: Service, value: boolean) {
this[service.name + 'EditMode'] = value;
this.descriptor.setDirty();
}
getServiceVersionEditFlag(service: Service): boolean {
return this[service.name + 'EditMode'];
}
setServiceParamEditFlag(service: Service, paramName: string, value: boolean) {
this[service.name + paramName + 'EditMode'] = value;
this.descriptor.setDirty();
}
getServiceParamEditFlag(service: Service, paramName: string): boolean {
return this[service.name + paramName + 'EditMode'];
}
setServiceURLEditFlag(service: Service, index: number, value: boolean) {
this[service.name + index + 'EditMode'] = value;
this.descriptor.setDirty();
}
getServiceURLEditFlag(service: Service, index: number): boolean {
return this[service.name + index + 'EditMode'];
}
isAddingServiceParam(service: Service): boolean {
return this['addParam' + service.name];
}
setAddingServiceParam(service: Service, value: boolean) {
this['addParam' + service.name] = value;
}
isAddingServiceURL(service: Service): boolean {
return this['addURL' + service.name];
}
setAddingServiceURL(service: Service, value: boolean) {
this['addURL' + service.name] = value;
}
isAddingProviderParam(provider: ProviderConfig): boolean {
return this['addParam' + provider.name];
}
setAddingProviderParam(provider: ProviderConfig, value: boolean) {
this['addParam' + provider.name] = value;
}
addProvider(name: string, role: string) {
let p = new ProviderConfig();
p.name = name;
p.role = role;
this.providers.push(p);
this.changedProviders = this.providers;
}
addProviderParam(provider: ProviderConfig, name: string, value: string) {
if (!provider.params) {
provider.params = new Map<string, string>();
}
provider.params[name] = value;
this.changedProviders = this.providers;
}
getProviderParamNames(provider: ProviderConfig): string[] {
if (!provider.params) {
provider.params = new Map<string, string>();
}
return Object.keys(provider.params);
}
isProviderEnabled(pc: ProviderConfig): boolean {
let result = false;
if (pc) {
if (typeof (pc.enabled) === 'string') {
let lowered = pc.enabled.toLowerCase().trim();
result = (lowered === 'true');
} else if (typeof (pc.enabled) === 'boolean') {
result = pc.enabled;
}
}
return result;
}
// This method is required to maintain focus on descriptor service URLs when they're being edited.
trackByServiceURLIndex(index: any, item: any) {
return index;
}
hasSelectedResource(): boolean {
return Boolean(this.resource) && Boolean(this.resource.name);
}
getTitleSubject(): string {
switch (this.resourceType) {
case 'Topologies': {
return 'Topology';
}
case 'Provider Configurations':
case 'Descriptors': {
return this.resourceType.substring(0, this.resourceType.length - 1);
}
default: {
return 'Resource';
}
}
}
showEditOptions(): boolean {
if (this.resourceType === 'Descriptors' && this.descriptor.readOnly) {
return !Boolean(this.descriptor.readOnly);
}
if (this.resourceType === 'Provider Configurations' && this.readOnlyProviderConfig) {
return !this.readOnlyProviderConfig;
}
return true;
}
}