This is an automated email from the ASF dual-hosted git repository.
lmccay pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git
The following commit(s) were added to refs/heads/master by this push:
new 1bdbdee KNOX-2056 - Adding Service Definitions management into Admin
UI (#169)
1bdbdee is described below
commit 1bdbdee67be13cc3b83605350536ffc246fb722e
Author: Sandor Molnar <[email protected]>
AuthorDate: Tue Oct 29 15:02:59 2019 +0100
KNOX-2056 - Adding Service Definitions management into Admin UI (#169)
* KNOX-2056 - Adding Service Definitions management into Admin UI
* KNOX-2056 - TopologyResource should not overwrite any topology stored in
TopologyService
---
gateway-admin-ui/admin-ui/app/app.component.ts | 4 +-
gateway-admin-ui/admin-ui/app/app.module.ts | 8 +-
.../resource-detail/resource-detail.component.html | 7 +-
.../admin-ui/app/resource/resource.component.html | 11 +-
.../admin-ui/app/resource/resource.component.ts | 28 +++-
.../admin-ui/app/resource/resource.service.ts | 43 ++++--
gateway-admin-ui/admin-ui/app/resource/resource.ts | 1 +
.../app/resourcetypes/resourcetypes.service.ts | 2 +-
.../rewrite.rule.ts} | 8 +-
.../rewrite.rules.ts} | 9 +-
.../resource.ts => service-definition/service.ts} | 8 +-
.../servicedefinition-detail.component.ts | 144 +++++++++++++++++++++
.../servicedefinition.service.ts | 142 ++++++++++++++++++++
.../servicedefinition.ts} | 11 +-
gateway-admin-ui/package-lock.json | 16 ++-
gateway-admin-ui/package.json | 2 +
.../org/apache/knox/gateway/GatewayMessages.java | 9 ++
.../impl/DefaultServiceDefinitionRegistry.java | 6 +-
.../ServiceDefinitionCollectionMarshaller.java | 36 ++++--
.../service/admin/ServiceDefinitionsResource.java | 59 ++++++---
.../gateway/service/admin/TopologiesResource.java | 16 ++-
21 files changed, 494 insertions(+), 76 deletions(-)
diff --git a/gateway-admin-ui/admin-ui/app/app.component.ts
b/gateway-admin-ui/admin-ui/app/app.component.ts
index 195c7e4..63fd7e7 100644
--- a/gateway-admin-ui/admin-ui/app/app.component.ts
+++ b/gateway-admin-ui/admin-ui/app/app.component.ts
@@ -16,6 +16,7 @@
*/
import {Component} from '@angular/core';
import {TopologyService} from './topology.service';
+import {ServiceDefinitionService} from
'./service-definition/servicedefinition.service';
import {ResourceTypesService} from './resourcetypes/resourcetypes.service';
@Component({
@@ -35,11 +36,12 @@ import {ResourceTypesService} from
'./resourcetypes/resourcetypes.service';
</div>
</div>
`,
- providers: [TopologyService, ResourceTypesService]
+ providers: [TopologyService, ServiceDefinitionService,
ResourceTypesService]
})
export class AppComponent {
constructor(private topologyService: TopologyService,
+ private serviceDefinitionService: ServiceDefinitionService,
private resourcetypesService: ResourceTypesService) {
}
}
diff --git a/gateway-admin-ui/admin-ui/app/app.module.ts
b/gateway-admin-ui/admin-ui/app/app.module.ts
index 2521e9f..c33cf20 100644
--- a/gateway-admin-ui/admin-ui/app/app.module.ts
+++ b/gateway-admin-ui/admin-ui/app/app.module.ts
@@ -15,6 +15,7 @@
* limitations under the License.
*/
import {NgModule} from '@angular/core';
+import {DataTableModule} from 'angular2-datatable';
import {BrowserModule} from '@angular/platform-browser';
import {HttpClientModule, HttpClientXsrfModule} from '@angular/common/http';
import {FormsModule} from '@angular/forms';
@@ -23,6 +24,8 @@ import {APP_BASE_HREF} from '@angular/common';
import {AppComponent} from './app.component';
import {TopologyService} from './topology.service';
+import {ServiceDefinitionService} from
'./service-definition/servicedefinition.service';
+import {ServiceDefinitionDetailComponent} from
'./service-definition/servicedefinition-detail.component';
import {GatewayVersionService} from './gateway-version.service';
import {GatewayVersionComponent} from './gateway-version.component';
import {TopologyComponent} from './topology.component';
@@ -51,11 +54,13 @@ import {ProviderConfigWizardComponent} from
'./provider-config-wizard/provider-c
FormsModule,
CustomFormsModule,
BsModalModule,
- AceEditorModule
+ AceEditorModule,
+ DataTableModule
],
declarations: [AppComponent,
TopologyComponent,
TopologyDetailComponent,
+ ServiceDefinitionDetailComponent,
GatewayVersionComponent,
XmlPipe,
JsonPrettyPipe,
@@ -70,6 +75,7 @@ import {ProviderConfigWizardComponent} from
'./provider-config-wizard/provider-c
ProviderConfigWizardComponent
],
providers: [TopologyService,
+ ServiceDefinitionService,
GatewayVersionService,
ResourceComponent,
ResourceTypesService,
diff --git
a/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.html
b/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.html
index f6bb824..ab554c9 100644
---
a/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.html
+++
b/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.html
@@ -1,4 +1,4 @@
-<div *ngIf="resourceType && resourceType !== 'Topologies'" class="panel
panel-default">
+<div *ngIf="resourceType && resourceType !== 'Topologies' && resourceType !==
'Service Definitions'" class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
{{ getTitleSubject() }} Detail <span *ngIf="hasSelectedResource()"
@@ -551,3 +551,8 @@
<div *ngIf="resourceType === 'Topologies'">
<app-topology-detail></app-topology-detail>
</div>
+
+<!-- Service Definition Details -->
+<div *ngIf="resourceType === 'Service Definitions'">
+ <app-servicedefinition-detail></app-servicedefinition-detail>
+</div>
\ No newline at end of file
diff --git a/gateway-admin-ui/admin-ui/app/resource/resource.component.html
b/gateway-admin-ui/admin-ui/app/resource/resource.component.html
index d106b87..c586ce2 100644
--- a/gateway-admin-ui/admin-ui/app/resource/resource.component.html
+++ b/gateway-admin-ui/admin-ui/app/resource/resource.component.html
@@ -1,6 +1,6 @@
<div>
<div class="table-responsive" style="width:100%; overflow: auto;
overflow-y: scroll">
- <table class="table table-hover">
+ <table class="table table-hover" [mfData]="resources"
#mf="mfDataTable" [mfRowsOnPage]="10">
<thead>
<tr>
<th>
@@ -23,7 +23,7 @@
</tr>
</thead>
<tbody>
- <tr *ngFor="let resource of resources"
+ <tr *ngFor="let resource of mf.data"
[class.selected]="resource === selectedResource"
[class.active]="isSelectedResource(resource)"
(click)="onSelect(resource)"
@@ -32,6 +32,13 @@
<td *ngIf="resourceType === 'Topologies'">{{resource.timestamp
| date:'medium'}}</td>
</tr>
</tbody>
+ <tfoot>
+ <tr>
+ <td colspan="4">
+ <mfBootstrapPaginator
[rowsOnPageSet]="[5,10,15]"></mfBootstrapPaginator>
+ </td>
+ </tr>
+ </tfoot>
</table>
</div>
<div>
diff --git a/gateway-admin-ui/admin-ui/app/resource/resource.component.ts
b/gateway-admin-ui/admin-ui/app/resource/resource.component.ts
index 803b76a..ff682a9 100644
--- a/gateway-admin-ui/admin-ui/app/resource/resource.component.ts
+++ b/gateway-admin-ui/admin-ui/app/resource/resource.component.ts
@@ -20,6 +20,8 @@ import {ResourceService} from './resource.service';
import {Resource} from './resource';
import {TopologyService} from '../topology.service';
import {Topology} from '../topology';
+import {ServiceDefinitionService} from
'../service-definition/servicedefinition.service';
+import {ServiceDefinition} from '../service-definition/servicedefinition';
import {HttpErrorResponse} from '@angular/common/http';
@Component({
@@ -35,7 +37,8 @@ export class ResourceComponent implements OnInit {
constructor(private resourceTypesService: ResourceTypesService,
private resourceService: ResourceService,
- private topologyService: TopologyService) {
+ private topologyService: TopologyService,
+ private serviceDefinitionService: ServiceDefinitionService) {
}
ngOnInit() {
@@ -55,7 +58,11 @@ export class ResourceComponent implements OnInit {
let debugMsg = 'ResourceComponent --> Found ' +
resources.length + ' ' + resType + ' resources\n';
for (let res of resources) {
- debugMsg += ' ' + res.name + '\n';
+ if (res.service) {
+ debugMsg += ' ' + res.service['role'] + ' (' +
res.service['version'] + ')' + '\n';
+ } else {
+ debugMsg += ' ' + res.name + '\n';
+ }
}
console.debug(debugMsg);
})
@@ -73,6 +80,13 @@ export class ResourceComponent implements OnInit {
topology.name = resource.name;
topology.href = resource.href;
this.topologyService.selectedTopology(topology);
+ } else if (this.resourceType === 'Service Definitions') {
+ let serviceDefinition = new ServiceDefinition();
+ serviceDefinition.name = resource.name;
+ serviceDefinition.service = resource.service['name'];
+ serviceDefinition.role = resource.service['role'];
+ serviceDefinition.version = resource.service['version'];
+
this.serviceDefinitionService.selectedServiceDefinition(serviceDefinition);
} else {
// Otherwise, notify the resource service
this.resourceService.selectedResource(resource);
@@ -80,7 +94,14 @@ export class ResourceComponent implements OnInit {
}
isSelectedResource(res: Resource): boolean {
- return (res && this.selectedResource) ? (res.name ===
this.selectedResource.name) : false;
+ return (res && this.selectedResource) ? (res.service &&
this.selectedResource.service ? this.isSelectedServiceDefinition(res)
+ : (res.name === this.selectedResource.name)) : false;
+ }
+
+ isSelectedServiceDefinition(res: Resource): boolean {
+ return res.service['name'] === this.selectedResource.service['name']
+ && res.service['role'] === this.selectedResource.service['role']
+ && res.service['version'] ===
this.selectedResource.service['version'];
}
getResourceTypeSingularDisplayName(resType: string): string {
@@ -89,6 +110,7 @@ export class ResourceComponent implements OnInit {
return 'Topology';
}
case 'Provider Configurations':
+ case 'Service Definitions':
case 'Descriptors': {
return resType.substring(0, resType.length - 1);
}
diff --git a/gateway-admin-ui/admin-ui/app/resource/resource.service.ts
b/gateway-admin-ui/admin-ui/app/resource/resource.service.ts
index a8fcc28..4f88bc5 100644
--- a/gateway-admin-ui/admin-ui/app/resource/resource.service.ts
+++ b/gateway-admin-ui/admin-ui/app/resource/resource.service.ts
@@ -31,6 +31,7 @@ export class ResourceService {
descriptorsUrl = this.apiUrl + 'descriptors';
topologiesUrl = this.apiUrl + 'topologies';
serviceDiscoveriesUrl = this.apiUrl + 'servicediscoveries';
+ serviceDefinitionsUrl = this.apiUrl + 'servicedefinitions';
selectedResourceTypeSource = new Subject<string>();
selectedResourceType$ = this.selectedResourceTypeSource.asObservable();
@@ -44,7 +45,6 @@ export class ResourceService {
changedProviderConfigurationSource = new Subject<Array<ProviderConfig>>();
changedProviderConfiguration$ =
this.changedProviderConfigurationSource.asObservable();
-
constructor(private http: HttpClient) {
this.initSupportedDiscoveryTypes();
}
@@ -78,6 +78,9 @@ export class ResourceService {
case 'Descriptors': {
return this.getDescriptorResources();
}
+ case 'Service Definitions': {
+ return this.getServiceDefinitionResources();
+ }
case 'Topologies': {
return this.getTopologyResources();
}
@@ -129,11 +132,32 @@ export class ResourceService {
});
}
+ getServiceDefinitionResources(): Promise<Resource[]> {
+ let headers = this.addJsonHeaders(new HttpHeaders());
+ return this.http.get(this.serviceDefinitionsUrl + '?serviceOnly=true',
{headers: headers})
+ .toPromise()
+ .then(response => response['serviceDefinitions'].serviceDefinition
as Resource[])
+ .catch((err: HttpErrorResponse) => {
+ console.debug('ResourceService -->
getServiceDefinitionResources() --> error: HTTP ' + err.status + ' ' +
err.message);
+ if (err.status === 401) {
+ window.location.assign(document.location.pathname);
+ } else {
+ return this.handleError(err);
+ }
+ });
+ }
+
getResource(resType: string, res: Resource): Promise<string> {
if (res) {
+ let href = res.href;
+ if (resType === 'Service Definitions') {
+ href = this.serviceDefinitionsUrl + '/' + res.service['name']
+ '/' + res.service['role'] + '/' + res.service['version']
+ + '?serviceOnly=true';
+ }
let headers = new HttpHeaders();
- headers = (resType === 'Topologies') ? this.addXmlHeaders(headers)
: this.addHeaders(headers, res.name);
- return this.http.get(res.href, {headers: headers, responseType:
'text'})
+ headers = (resType === 'Topologies' || resType === 'Service
Definitions') ? this.addXmlHeaders(headers)
+ : this.addHeaders(headers, res.name);
+ return this.http.get(href, {headers: headers, responseType:
'text'})
.toPromise()
.then(response => {
console.debug('ResourceService --> Loading resource ' +
res.name + ' :\n' + response);
@@ -343,12 +367,15 @@ export class ResourceService {
}
public getResourceDisplayName(res: Resource): string {
- if (res && res.name) {
- let index = res.name.lastIndexOf('.');
- return index > 0 ? res.name.substring(0, index) : res.name;
- } else {
- return null;
+ if (res) {
+ if (res.service) {
+ return res.service['role'] + ' (' + res.service['version'] +
')';
+ } else if (res.name) {
+ let index = res.name.lastIndexOf('.');
+ return index > 0 ? res.name.substring(0, index) : res.name;
+ }
}
+ return null;
}
private handleError(error: any): Promise<any> {
diff --git a/gateway-admin-ui/admin-ui/app/resource/resource.ts
b/gateway-admin-ui/admin-ui/app/resource/resource.ts
index cb5ba6f..1cdc2e8 100644
--- a/gateway-admin-ui/admin-ui/app/resource/resource.ts
+++ b/gateway-admin-ui/admin-ui/app/resource/resource.ts
@@ -21,4 +21,5 @@ export class Resource {
uri: string;
href: string;
content: string;
+ service: string;
}
diff --git
a/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.service.ts
b/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.service.ts
index 71382c8..cc2dc4f 100644
--- a/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.service.ts
+++ b/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.service.ts
@@ -20,7 +20,7 @@ import {Subject} from 'rxjs/Subject';
@Injectable()
export class ResourceTypesService {
- resourceTypes = ['Provider Configurations', 'Descriptors', 'Topologies'];
+ resourceTypes = ['Provider Configurations', 'Descriptors', 'Topologies',
'Service Definitions'];
selectedResourceTypeSource = new Subject<string>();
public selectedResourceType$ =
this.selectedResourceTypeSource.asObservable();
diff --git a/gateway-admin-ui/admin-ui/app/resource/resource.ts
b/gateway-admin-ui/admin-ui/app/service-definition/rewrite.rule.ts
similarity index 88%
copy from gateway-admin-ui/admin-ui/app/resource/resource.ts
copy to gateway-admin-ui/admin-ui/app/service-definition/rewrite.rule.ts
index cb5ba6f..2f1e701 100644
--- a/gateway-admin-ui/admin-ui/app/resource/resource.ts
+++ b/gateway-admin-ui/admin-ui/app/service-definition/rewrite.rule.ts
@@ -15,10 +15,8 @@
* limitations under the License.
*/
-export class Resource {
- timestamp: number;
+export class RewriteRule {
+ dir: string;
name: string;
- uri: string;
- href: string;
- content: string;
+ pattern: string;
}
diff --git a/gateway-admin-ui/admin-ui/app/resource/resource.ts
b/gateway-admin-ui/admin-ui/app/service-definition/rewrite.rules.ts
similarity index 86%
copy from gateway-admin-ui/admin-ui/app/resource/resource.ts
copy to gateway-admin-ui/admin-ui/app/service-definition/rewrite.rules.ts
index cb5ba6f..d662981 100644
--- a/gateway-admin-ui/admin-ui/app/resource/resource.ts
+++ b/gateway-admin-ui/admin-ui/app/service-definition/rewrite.rules.ts
@@ -14,11 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import {RewriteRule} from './rewrite.rule';
-export class Resource {
- timestamp: number;
- name: string;
- uri: string;
- href: string;
- content: string;
+export class RewriteRules {
+ rules: RewriteRule[];
}
diff --git a/gateway-admin-ui/admin-ui/app/resource/resource.ts
b/gateway-admin-ui/admin-ui/app/service-definition/service.ts
similarity index 88%
copy from gateway-admin-ui/admin-ui/app/resource/resource.ts
copy to gateway-admin-ui/admin-ui/app/service-definition/service.ts
index cb5ba6f..6820ac3 100644
--- a/gateway-admin-ui/admin-ui/app/resource/resource.ts
+++ b/gateway-admin-ui/admin-ui/app/service-definition/service.ts
@@ -15,10 +15,8 @@
* limitations under the License.
*/
-export class Resource {
- timestamp: number;
+export class Service {
name: string;
- uri: string;
- href: string;
- content: string;
+ role: string;
+ version: string;
}
diff --git
a/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition-detail.component.ts
b/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition-detail.component.ts
new file mode 100644
index 0000000..02e4461
--- /dev/null
+++
b/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition-detail.component.ts
@@ -0,0 +1,144 @@
+/*
+ * 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 {BsModalComponent} from 'ng2-bs3-modal/ng2-bs3-modal';
+import {ServiceDefinition} from './servicedefinition';
+import {ServiceDefinitionService} from './servicedefinition.service';
+import {ResourceTypesService} from '../resourcetypes/resourcetypes.service';
+
+import 'brace/theme/monokai';
+import 'brace/mode/xml';
+
+@Component({
+ selector: 'app-servicedefinition-detail',
+ template: `
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h4 class="panel-title">{{title}} <span
class="pull-right">{{titleSuffix}}</span></h4>
+ </div>
+ <div *ngIf="serviceDefinitionContent" class="panel-body">
+ <ace-editor
+ [(text)]="serviceDefinitionContent"
+ [mode]="'xml'"
+ [options]="options"
+ [theme]="theme"
+ style="min-height: 430px; width:100%; overflow: auto;"
+ (textChanged)="onChange($event)">
+ </ace-editor>
+ <div class="panel-footer">
+ <button id="deleteServiceDefinition"
(click)="deleteServiceDefConfirmModal.open('sm')"
+ class="btn btn-default btn-sm"
type="submit">
+ <span class="glyphicon glyphicon-trash"
aria-hidden="true"></span>
+ </button>
+ <button id="updateServiceDefinition"
(click)="updateServiceDefConfirmModal.open('sm')"
+ class="btn btn-default btn-sm pull-right"
type="submit">
+ <span class="glyphicon glyphicon-floppy-disk"
aria-hidden="true"></span>
+ </button>
+ </div>
+ </div>
+ </div>
+ <bs-modal (onClose)="updateServiceDefinition()"
#updateServiceDefConfirmModal>
+ <bs-modal-header [showDismiss]="true">
+ <h4 class="modal-title">Updating Service Definition
{{titleSuffix}}</h4>
+ </bs-modal-header>
+ <bs-modal-body>
+ Are you sure you want to update this service definition?
+ </bs-modal-body>
+ <bs-modal-footer>
+ <button type="button" class="btn btn-default btn-sm"
data-dismiss="updateServiceDefConfirmModal"
+ (click)="updateServiceDefConfirmModal.dismiss()">Cancel
+ </button>
+ <button type="button" class="btn btn-primary btn-sm"
(click)="updateServiceDefConfirmModal.close()">Ok</button>
+ </bs-modal-footer>
+ </bs-modal>
+ <bs-modal (onClose)="deleteServiceDefinition()"
#deleteServiceDefConfirmModal>
+ <bs-modal-header [showDismiss]="true">
+ <h4 class="modal-title">Deleting Service Definition
{{titleSuffix}}</h4>
+ </bs-modal-header>
+ <bs-modal-body>
+ Are you sure you want to delete this service definition?
+ </bs-modal-body>
+ <bs-modal-footer>
+ <button type="button" class="btn btn-default btn-sm"
data-dismiss="deleteServiceDefConfirmModal"
+ (click)="deleteServiceDefConfirmModal.dismiss()">Cancel
+ </button>
+ <button type="button" class="btn btn-primary btn-sm"
(click)="deleteServiceDefConfirmModal.close()">Ok</button>
+ </bs-modal-footer>
+ </bs-modal>
+ `
+})
+
+export class ServiceDefinitionDetailComponent implements OnInit {
+ serviceDefinition: ServiceDefinition;
+ title = 'Service Definition Detail';
+ titleSuffix: string;
+ serviceDefinitionContent: string;
+ changedServiceDefinitionContent: string;
+ theme: String = 'monokai';
+ options: any = {useWorker: false, printMargin: false};
+
+ @ViewChild('editor') editor;
+
+ @ViewChild('deleteServiceDefConfirmModal')
+ deleteServiceDefConfirmModal: BsModalComponent;
+
+ constructor(private serviceDefinitionService: ServiceDefinitionService,
private resourceTypesService: ResourceTypesService) {
+ }
+
+ ngOnInit(): void {
+
this.serviceDefinitionService.selectedServiceDefinition$.subscribe(value =>
this.populateContent(value));
+ }
+
+ setTitleSuffix(value: string) {
+ this.titleSuffix = value;
+ }
+
+ onChange(code: any) {
+ this.changedServiceDefinitionContent = code;
+ }
+
+ populateContent(serviceDefinition: ServiceDefinition) {
+ if (serviceDefinition) {
+ this.serviceDefinition = serviceDefinition;
+ this.setTitleSuffix(serviceDefinition.role + ' (' +
serviceDefinition.version + ')');
+
this.serviceDefinitionService.getServiceDefinitionXml(serviceDefinition)
+ .then(content => this.serviceDefinitionContent = content);
+ }
+ }
+
+ updateServiceDefinition() {
+
this.serviceDefinitionService.updateServiceDefinition(this.changedServiceDefinitionContent
? this.changedServiceDefinitionContent
+ :
this.serviceDefinitionContent)
+ .then(() => {
+ // This refreshes the list of service definitions
+ this.resourceTypesService.selectResourceType('Service
Definitions');
+ });
+ }
+
+ deleteServiceDefinition() {
+
this.serviceDefinitionService.deleteServiceDefinition(this.serviceDefinition)
+ .then(() => {
+ // This refreshes the list of service definitions
+ this.resourceTypesService.selectResourceType('Service
Definitions');
+ // This refreshes the service definition content panel to the
first one in the list
+ this.serviceDefinitionService.getServiceDefinitions()
+ .then(serviceDefinitions => {
+
this.serviceDefinitionService.selectedServiceDefinition(serviceDefinitions[0]);
+ });
+ });
+ }
+}
diff --git
a/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition.service.ts
b/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition.service.ts
new file mode 100644
index 0000000..75e6b6c
--- /dev/null
+++
b/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition.service.ts
@@ -0,0 +1,142 @@
+/*
+ * 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 {Injectable} from '@angular/core';
+import {HttpClient, HttpErrorResponse, HttpHeaders} from
'@angular/common/http';
+import {RestURLBuilder} from 'rest-url-builder';
+
+import 'rxjs/add/operator/toPromise';
+import {Subject} from 'rxjs/Subject';
+
+import {ServiceDefinition} from './servicedefinition';
+
+ @Injectable()
+export class ServiceDefinitionService {
+ apiUrl = window.location.pathname.replace(new RegExp('admin-ui/.*'),
'api/v1/');
+ serviceDefinitionsBaseUrl = this.apiUrl + 'servicedefinitions';
+ serviceDefinitionUrlTemplate = this.serviceDefinitionsBaseUrl +
'/:service/:role/:version';
+ selectedServiceDefinitionSource = new Subject<ServiceDefinition>();
+ selectedServiceDefinition$ =
this.selectedServiceDefinitionSource.asObservable();
+ urlBuilder = new RestURLBuilder();
+
+ constructor(private http: HttpClient) {
+ }
+
+ getServiceDefinitions(): Promise<ServiceDefinition[]> {
+ let headers = new HttpHeaders();
+ headers = this.addXmlHeaders(headers);
+ return this.http.get(this.serviceDefinitionsBaseUrl, { headers:
headers})
+ .toPromise()
+ .then(response => response['serviceDefinitions'].serviceDefinition
as ServiceDefinition[])
+ .catch((err: HttpErrorResponse) => {
+ console.debug('ServiceDefinitionService -->
getServiceDefinitions() --> ' + this.serviceDefinitionsBaseUrl
+ + '\n error: ' + err.message);
+ if (err.status === 401) {
+ window.location.assign(document.location.pathname);
+ } else {
+ return this.handleError(err);
+ }
+ });
+ }
+
+ getServiceDefinitionXml(serviceDefinition: ServiceDefinition) {
+ let headers = new HttpHeaders();
+ headers = this.addXmlHeaders(headers);
+ let urlBuilder =
this.urlBuilder.buildRestURL(this.serviceDefinitionUrlTemplate);
+ urlBuilder.setNamedParameter('service', serviceDefinition.service);
+ urlBuilder.setNamedParameter('role', serviceDefinition.role);
+ urlBuilder.setNamedParameter('version', serviceDefinition.version);
+ return this.http.get(urlBuilder.get(), {headers: headers,
responseType: 'text'})
+ .toPromise()
+ .then(response => response)
+ .catch((err: HttpErrorResponse) => {
+ console.debug('ServiceDefinitionService -->
getServiceDefinitionXml() --> ' + urlBuilder.get()
+ + '\n error: ' + err.message);
+ if (err.status === 401) {
+ window.location.assign(document.location.pathname);
+ } else {
+ return this.handleError(err);
+ }
+ });
+ }
+
+ updateServiceDefinition(xml: string): Promise<string> {
+ let xheaders = new HttpHeaders();
+ xheaders = this.addXmlHeaders(xheaders);
+ let serviceDefintionXml = xml.replace('<serviceDefinitions>',
'').replace('</serviceDefinitions>', '');
+ return this.http.put(this.serviceDefinitionsBaseUrl,
serviceDefintionXml, {headers: xheaders, responseType: 'text'})
+ .toPromise()
+ .then(response => response)
+ .catch((err: HttpErrorResponse) => {
+ console.debug('ServiceDefinitionService -->
updateServiceDefinition() --> ' + this.serviceDefinitionsBaseUrl
+ + '\n error: ' + err.status + ' ' +
err.message);
+ if (err.status === 401) {
+ window.location.assign(document.location.pathname);
+ } else {
+ return this.handleError(err);
+ }
+ });
+ }
+
+ deleteServiceDefinition(serviceDefinition: ServiceDefinition):
Promise<string> {
+ let xheaders = new HttpHeaders();
+ xheaders = this.addXmlHeaders(xheaders);
+ let urlBuilder =
this.urlBuilder.buildRestURL(this.serviceDefinitionUrlTemplate);
+ urlBuilder.setNamedParameter('service', serviceDefinition.service);
+ urlBuilder.setNamedParameter('role', serviceDefinition.role);
+ urlBuilder.setNamedParameter('version', serviceDefinition.version);
+ return this.http.delete(urlBuilder.get(), {headers: xheaders,
responseType: 'text'})
+ .toPromise()
+ .then(response => response)
+ .catch((err: HttpErrorResponse) => {
+ console.debug('ServiceDefinitionService -->
deleteServiceDefinition() --> ' + urlBuilder.get()
+ + '\n error: ' + err.status + ' ' +
err.message);
+ if (err.status === 401) {
+ window.location.assign(document.location.pathname);
+ } else {
+ return this.handleError(err);
+ }
+ });
+ }
+
+ selectedServiceDefinition(value: ServiceDefinition) {
+ this.selectedServiceDefinitionSource.next(value);
+ }
+
+ addJsonHeaders(headers: HttpHeaders): HttpHeaders {
+ return this.addCsrfHeaders(headers.append('Accept', 'application/json')
+ .append('Content-Type', 'application/json'));
+ }
+
+ addXmlHeaders(headers: HttpHeaders): HttpHeaders {
+ return this.addCsrfHeaders(headers.append('Accept', 'application/xml')
+ .append('Content-Type', 'application/xml'));
+ }
+
+ addCsrfHeaders(headers: HttpHeaders): HttpHeaders {
+ return this.addXHRHeaders(headers.append('X-XSRF-Header', 'admin-ui'));
+ }
+
+ addXHRHeaders(headers: HttpHeaders): HttpHeaders {
+ return headers.append('X-Requested-With', 'XMLHttpRequest');
+ }
+
+ private handleError(error: any): Promise<any> {
+ console.error('An error occurred', error); // for demo purposes only
+ return Promise.reject(error.message || error);
+ }
+
+}
diff --git a/gateway-admin-ui/admin-ui/app/resource/resource.ts
b/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition.ts
similarity index 82%
copy from gateway-admin-ui/admin-ui/app/resource/resource.ts
copy to gateway-admin-ui/admin-ui/app/service-definition/servicedefinition.ts
index cb5ba6f..8a71e6a 100644
--- a/gateway-admin-ui/admin-ui/app/resource/resource.ts
+++ b/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition.ts
@@ -14,11 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import {RewriteRules} from './rewrite.rules';
+import {Service} from './service';
-export class Resource {
- timestamp: number;
+export class ServiceDefinition {
name: string;
- uri: string;
- href: string;
- content: string;
+ service: string;
+ role: string;
+ version: string;
}
diff --git a/gateway-admin-ui/package-lock.json
b/gateway-admin-ui/package-lock.json
index 15a67b8..584b8a7 100644
--- a/gateway-admin-ui/package-lock.json
+++ b/gateway-admin-ui/package-lock.json
@@ -379,6 +379,14 @@
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
"dev": true
},
+ "angular2-datatable": {
+ "version": "0.6.0",
+ "resolved":
"https://registry.npmjs.org/angular2-datatable/-/angular2-datatable-0.6.0.tgz",
+ "integrity": "sha1-ygCPdAh/DLh9pXCe0vLR0GF3JjI=",
+ "requires": {
+ "lodash": "^4.0.0"
+ }
+ },
"ansi-html": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
@@ -4683,8 +4691,7 @@
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
- "integrity":
"sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
- "dev": true
+ "integrity":
"sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
},
"lodash.assign": {
"version": "4.2.0",
@@ -6967,6 +6974,11 @@
"integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
"dev": true
},
+ "rest-url-builder": {
+ "version": "1.0.6",
+ "resolved":
"https://registry.npmjs.org/rest-url-builder/-/rest-url-builder-1.0.6.tgz",
+ "integrity": "sha1-TmYdivTydMX/Li/EnfKjcS65NiI="
+ },
"ret": {
"version": "0.1.15",
"resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
diff --git a/gateway-admin-ui/package.json b/gateway-admin-ui/package.json
index ab9e5ea..ee6309f 100644
--- a/gateway-admin-ui/package.json
+++ b/gateway-admin-ui/package.json
@@ -18,6 +18,7 @@
"@angular/platform-browser": "^5.2.0",
"@angular/platform-browser-dynamic": "^5.2.0",
"@angular/router": "^5.2.0",
+ "angular2-datatable": "^0.6.0",
"bootstrap": "^3.4.1",
"core-js": "^2.6.4",
"jquery": ">=3.0.0",
@@ -26,6 +27,7 @@
"ng2-bs3-modal": "^0.13.0",
"ng2-validation": "^4.2.0",
"popper.js": "^1.14.7",
+ "rest-url-builder": "^1.0.6",
"rxjs": "^5.5.2",
"ts-helpers": "^1.1.1",
"zone.js": "^0.8.29"
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java
b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java
index 430ecc2..0a3781f 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java
@@ -670,4 +670,13 @@ public interface GatewayMessages {
@Message(level = MessageLevel.INFO, text = "Redeploying topology {0} due to
service definition change {1} / {2} / {3}")
void redeployingTopologyOnServiceDefinitionChange(String topologyName,
String serviceName, String role, String version);
+
+ @Message(level = MessageLevel.INFO, text = "Saved service definition {0} /
{1} / {2}")
+ void savedServiceDefinitionChange(String serviceName, String role, String
version);
+
+ @Message(level = MessageLevel.INFO, text = "Updated service definition {0} /
{1} / {2}")
+ void updatedServiceDefinitionChange(String serviceName, String role, String
version);
+
+ @Message(level = MessageLevel.INFO, text = "Deleted service definition {0} /
{1} / {2}")
+ void deletedServiceDefinitionChange(String serviceName, String role, String
version);
}
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/services/registry/impl/DefaultServiceDefinitionRegistry.java
b/gateway-server/src/main/java/org/apache/knox/gateway/services/registry/impl/DefaultServiceDefinitionRegistry.java
index 4c93fd8..41030c2 100644
---
a/gateway-server/src/main/java/org/apache/knox/gateway/services/registry/impl/DefaultServiceDefinitionRegistry.java
+++
b/gateway-server/src/main/java/org/apache/knox/gateway/services/registry/impl/DefaultServiceDefinitionRegistry.java
@@ -33,6 +33,7 @@ import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -148,7 +149,7 @@ public class DefaultServiceDefinitionRegistry implements
ServiceDefinitionRegist
public Set<ServiceDefinitionPair> getServiceDefinitions() {
readLock.lock();
try {
- return serviceDefinitions;
+ return Collections.unmodifiableSet(serviceDefinitions);
} finally {
readLock.unlock();
}
@@ -157,11 +158,13 @@ public class DefaultServiceDefinitionRegistry implements
ServiceDefinitionRegist
@Override
public void saveServiceDefinition(ServiceDefinitionPair serviceDefinition)
throws ServiceDefinitionRegistryException {
saveOrUpdateServiceDefinition(serviceDefinition, false);
+ LOG.savedServiceDefinitionChange(serviceDefinition.getService().getName(),
serviceDefinition.getService().getRole(),
serviceDefinition.getService().getVersion());
}
@Override
public void saveOrUpdateServiceDefinition(ServiceDefinitionPair
serviceDefinition) throws ServiceDefinitionRegistryException {
saveOrUpdateServiceDefinition(serviceDefinition, true);
+
LOG.updatedServiceDefinitionChange(serviceDefinition.getService().getName(),
serviceDefinition.getService().getRole(),
serviceDefinition.getService().getVersion());
}
public void saveOrUpdateServiceDefinition(ServiceDefinitionPair
serviceDefinition, boolean allowUpdate) throws
ServiceDefinitionRegistryException {
@@ -228,6 +231,7 @@ public class DefaultServiceDefinitionRegistry implements
ServiceDefinitionRegist
writeLock.unlock();
}
notifyListeners(name, role, version);
+ LOG.deletedServiceDefinitionChange(name, role, version);
} else {
throw new ServiceDefinitionRegistryException("There is no service
definition with the given attributes: " + name + "," + role + "," + version);
}
diff --git
a/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/ServiceDefinitionCollectionMarshaller.java
b/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/ServiceDefinitionCollectionMarshaller.java
index 95f4307..2bc8477 100644
---
a/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/ServiceDefinitionCollectionMarshaller.java
+++
b/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/ServiceDefinitionCollectionMarshaller.java
@@ -21,6 +21,8 @@ import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
@@ -28,17 +30,19 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
-import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import
org.apache.knox.gateway.service.admin.ServiceDefinitionsResource.ServiceDefinitionsWrapper;
+import org.eclipse.persistence.jaxb.JAXBContextFactory;
+import org.eclipse.persistence.jaxb.JAXBContextProperties;
@Provider
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public class ServiceDefinitionCollectionMarshaller implements
MessageBodyWriter<ServiceDefinitionsResource.ServiceDefinitionsWrapper> {
- private static Marshaller marshaller;
+ private static Marshaller xmlMarshaller;
+ private static Marshaller jsonMarshaller;
@Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[]
annotations, MediaType mediaType) {
@@ -54,17 +58,33 @@ public class ServiceDefinitionCollectionMarshaller
implements MessageBodyWriter<
public void writeTo(ServiceDefinitionsWrapper instance, Class<?> type, Type
genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
throws IOException, WebApplicationException {
try {
- getMarshaller().marshal(instance, entityStream);
+ getMarshaller(mediaType).marshal(instance, entityStream);
} catch (JAXBException e) {
throw new IOException(e);
}
}
- private synchronized Marshaller getMarshaller() throws JAXBException {
- if (marshaller == null) {
- marshaller =
JAXBContext.newInstance(ServiceDefinitionsWrapper.class).createMarshaller();
- marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+ private Marshaller getMarshaller(MediaType mediaType) throws JAXBException {
+ return
MediaType.APPLICATION_JSON_TYPE.getSubtype().equals(mediaType.getSubtype()) ?
getJsonMarshaller() : getXmlMarshaller();
+ }
+
+ private synchronized Marshaller getXmlMarshaller() throws JAXBException {
+ if (xmlMarshaller == null) {
+ final Map<String, Object> properties = new HashMap<>(1);
+ properties.put(JAXBContextProperties.MEDIA_TYPE,
MediaType.APPLICATION_XML);
+ xmlMarshaller = JAXBContextFactory.createContext(new Class[] {
ServiceDefinitionsWrapper.class }, properties).createMarshaller();
+ xmlMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+ }
+ return xmlMarshaller;
+ }
+
+ private synchronized Marshaller getJsonMarshaller() throws JAXBException {
+ if (jsonMarshaller == null) {
+ final Map<String, Object> properties = new HashMap<>(1);
+ properties.put(JAXBContextProperties.MEDIA_TYPE,
MediaType.APPLICATION_JSON);
+ jsonMarshaller = JAXBContextFactory.createContext(new Class[] {
ServiceDefinitionsWrapper.class }, properties).createMarshaller();
+ jsonMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
}
- return marshaller;
+ return jsonMarshaller;
}
}
diff --git
a/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/ServiceDefinitionsResource.java
b/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/ServiceDefinitionsResource.java
index 25385ca..c765baa 100644
---
a/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/ServiceDefinitionsResource.java
+++
b/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/ServiceDefinitionsResource.java
@@ -25,8 +25,8 @@ import static javax.ws.rs.core.Response.serverError;
import java.net.URI;
import java.net.URISyntaxException;
-import java.util.HashSet;
import java.util.Set;
+import java.util.TreeSet;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -34,12 +34,14 @@ import javax.inject.Singleton;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.xml.bind.annotation.XmlAccessType;
@@ -48,6 +50,7 @@ import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import org.apache.knox.gateway.service.definition.ServiceDefinitionPair;
+import
org.apache.knox.gateway.service.definition.ServiceDefinitionPairComparator;
import org.apache.knox.gateway.services.GatewayServices;
import org.apache.knox.gateway.services.ServiceType;
import org.apache.knox.gateway.services.registry.ServiceDefinitionRegistry;
@@ -69,68 +72,71 @@ public class ServiceDefinitionsResource {
@GET
@Produces({ APPLICATION_JSON, APPLICATION_XML })
@Path("servicedefinitions")
- public ServiceDefinitionsWrapper getServiceDefinitions() {
- return getServiceDefinitions((Predicate<? super ServiceDefinitionPair>)
null);
+ public ServiceDefinitionsWrapper
getServiceDefinitions(@QueryParam("serviceOnly") @DefaultValue("false") boolean
serviceOnly) {
+ return getServiceDefinitions((Predicate<? super ServiceDefinitionPair>)
null, serviceOnly);
}
@GET
@Produces({ APPLICATION_JSON, APPLICATION_XML })
@Path("servicedefinitions/{name}")
- public ServiceDefinitionsWrapper getServiceDefinition(@PathParam("name")
String name) {
- return getServiceDefinitions(serviceDefinitionPair ->
serviceDefinitionPair.getService().getName().equalsIgnoreCase(name));
+ public ServiceDefinitionsWrapper getServiceDefinition(@PathParam("name")
String name, @QueryParam("serviceOnly") @DefaultValue("false") boolean
serviceOnly) {
+ return getServiceDefinitions(serviceDefinitionPair ->
serviceDefinitionPair.getService().getName().equalsIgnoreCase(name),
serviceOnly);
}
@GET
@Produces({ APPLICATION_JSON, APPLICATION_XML })
@Path("servicedefinitions/{name}/{role}")
- public ServiceDefinitionsWrapper getServiceDefinition(@PathParam("name")
String name, @PathParam("role") String role) {
+ public ServiceDefinitionsWrapper getServiceDefinition(@PathParam("name")
String name, @PathParam("role") String role,
+ @QueryParam("serviceOnly") @DefaultValue("false") boolean serviceOnly) {
return getServiceDefinitions(
- serviceDefinitionPair ->
serviceDefinitionPair.getService().getName().equalsIgnoreCase(name) &&
serviceDefinitionPair.getService().getRole().equalsIgnoreCase(role));
+ serviceDefinitionPair ->
serviceDefinitionPair.getService().getName().equalsIgnoreCase(name) &&
serviceDefinitionPair.getService().getRole().equalsIgnoreCase(role),
+ serviceOnly);
}
@GET
@Produces({ APPLICATION_JSON, APPLICATION_XML })
@Path("servicedefinitions/{name}/{role}/{version}")
- public ServiceDefinitionsWrapper getServiceDefinition(@PathParam("name")
String name, @PathParam("role") String role, @PathParam("version") String
version) {
+ public ServiceDefinitionsWrapper getServiceDefinition(@PathParam("name")
String name, @PathParam("role") String role, @PathParam("version") String
version,
+ @QueryParam("serviceOnly") @DefaultValue("false") boolean serviceOnly) {
return getServiceDefinitions(serviceDefinitionPair ->
serviceDefinitionPair.getService().getName().equalsIgnoreCase(name)
- && serviceDefinitionPair.getService().getRole().equalsIgnoreCase(role)
&& serviceDefinitionPair.getService().getVersion().equalsIgnoreCase(version));
+ && serviceDefinitionPair.getService().getRole().equalsIgnoreCase(role)
&& serviceDefinitionPair.getService().getVersion().equalsIgnoreCase(version),
serviceOnly);
}
@POST
@Consumes({ APPLICATION_XML })
- @Produces({ APPLICATION_JSON })
+ @Produces({ APPLICATION_JSON, APPLICATION_XML })
@Path("servicedefinitions")
public Response saveServiceDefinition(ServiceDefinitionPair
serviceDefinition) {
try {
getServiceDefinitionRegistry().saveServiceDefinition(serviceDefinition);
return created(toUri(serviceDefinition)).build();
} catch (URISyntaxException | ServiceDefinitionRegistryException e) {
- return serverError().entity("{ \"" + ERROR_CODE_CREATION + "\": \"" +
e.getMessage() + "\" }").build();
+ return serverError().entity("{ \"" + ERROR_CODE_CREATION + "\": \"" +
e.getMessage() + "\" }").build();
}
}
@PUT
@Consumes({ APPLICATION_XML })
- @Produces({ APPLICATION_JSON })
+ @Produces({ APPLICATION_JSON, APPLICATION_XML })
@Path("servicedefinitions")
public Response saveOrUpdateServiceDefinition(ServiceDefinitionPair
serviceDefinition) {
try {
getServiceDefinitionRegistry().saveOrUpdateServiceDefinition(serviceDefinition);
return created(toUri(serviceDefinition)).build();
} catch (URISyntaxException | ServiceDefinitionRegistryException e) {
- return serverError().entity("{ \"" + ERROR_CODE_CREATION_OR_UPDATE +
"\": \"" + e.getMessage() + "\" }").build();
+ return serverError().entity("{ \"" + ERROR_CODE_CREATION_OR_UPDATE +
"\": \"" + e.getMessage() + "\" }").build();
}
}
@DELETE
- @Produces({ APPLICATION_JSON })
+ @Produces({ APPLICATION_JSON, APPLICATION_XML })
@Path("servicedefinitions/{name}/{role}/{version}")
public Response deleteServiceDefinition(@PathParam("name") String name,
@PathParam("role") String role, @PathParam("version") String version) {
try {
getServiceDefinitionRegistry().deleteServiceDefinition(name, role,
version);
return ok().location(toUri(name, role, version)).build();
} catch (URISyntaxException | ServiceDefinitionRegistryException e) {
- return serverError().entity("{ \"" + ERROR_CODE_DELETION + "\": \"" +
e.getMessage() + "\" }").build();
+ return serverError().entity("{ \"" + ERROR_CODE_DELETION + "\": \"" +
e.getMessage() + "\" }").build();
}
}
@@ -142,13 +148,24 @@ public class ServiceDefinitionsResource {
return new URI("api/v1/servicedefinitions/" + name + "/" + role + "/" +
version);
}
- private ServiceDefinitionsWrapper getServiceDefinitions(Predicate<? super
ServiceDefinitionPair> predicate) {
+ private ServiceDefinitionsWrapper getServiceDefinitions(Predicate<? super
ServiceDefinitionPair> predicate, boolean serviceOnly) {
+ final Set<ServiceDefinitionPair> serviceDefinitions =
getServiceDefinitions(predicate);
+
final ServiceDefinitionsWrapper serviceDefinitionsWrapper = new
ServiceDefinitionsWrapper();
- final Set<ServiceDefinitionPair> serviceDefinitions =
getServiceDefinitionRegistry().getServiceDefinitions();
- serviceDefinitionsWrapper.setServiceDefinitions(predicate == null ?
serviceDefinitions :
serviceDefinitions.stream().filter(predicate).collect(Collectors.toSet()));
+ if (serviceOnly) {
+ serviceDefinitions.stream()
+ .forEach(serviceDefinition ->
serviceDefinitionsWrapper.getServiceDefinitions().add(new
ServiceDefinitionPair(serviceDefinition.getService(), null)));
+ } else {
+ serviceDefinitionsWrapper.setServiceDefinitions(serviceDefinitions);
+ }
return serviceDefinitionsWrapper;
}
+ private Set<ServiceDefinitionPair> getServiceDefinitions(Predicate<? super
ServiceDefinitionPair> predicate) {
+ final Set<ServiceDefinitionPair> serviceDefinitions =
getServiceDefinitionRegistry().getServiceDefinitions();
+ return predicate == null ? serviceDefinitions :
serviceDefinitions.stream().filter(predicate).collect(Collectors.toSet());
+ }
+
private ServiceDefinitionRegistry getServiceDefinitionRegistry() {
if (serviceDefinitionRegistry == null) {
final GatewayServices gatewayServices = (GatewayServices)
request.getServletContext().getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
@@ -157,12 +174,12 @@ public class ServiceDefinitionsResource {
return serviceDefinitionRegistry;
}
- @XmlAccessorType(XmlAccessType.FIELD)
+ @XmlAccessorType(XmlAccessType.NONE)
public static class ServiceDefinitionsWrapper {
- @XmlElement(name="serviceDefinition")
+ @XmlElement(name = "serviceDefinition")
@XmlElementWrapper(name = "serviceDefinitions")
- private Set<ServiceDefinitionPair> serviceDefinitions = new HashSet<>();
+ private Set<ServiceDefinitionPair> serviceDefinitions = new TreeSet<>(new
ServiceDefinitionPairComparator());
public Set<ServiceDefinitionPair> getServiceDefinitions() {
return serviceDefinitions;
diff --git
a/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/TopologiesResource.java
b/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/TopologiesResource.java
index 4251c48..2199da4 100644
---
a/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/TopologiesResource.java
+++
b/gateway-service-admin/src/main/java/org/apache/knox/gateway/service/admin/TopologiesResource.java
@@ -113,19 +113,23 @@ public class TopologiesResource {
(GatewayConfig)
request.getServletContext().getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
for (org.apache.knox.gateway.topology.Topology t : ts.getTopologies()) {
if (t.getName().equals(id)) {
+ // we need to convert first so that the original topology does not
get
+ // overwritten in TopologyService (i.e. URI does not change from
'file://...' to
+ // 'https://...'
+ final Topology convertedTopology = BeanConverter.getTopology(t);
try {
- t.setUri(new URI( buildURI(t, config, request) ));
+ convertedTopology.setUri(new URI( buildURI(t, config, request) ));
} catch (URISyntaxException se) {
- t.setUri(null);
+ convertedTopology.setUri(null);
}
// For any read-only override topology, mark it as generated to
discourage modification.
- List<String> ambariManagedTopos =
config.getReadOnlyOverrideTopologyNames();
- if (ambariManagedTopos.contains(t.getName())) {
- t.setGenerated(true);
+ final List<String> ambariManagedTopos =
config.getReadOnlyOverrideTopologyNames();
+ if (ambariManagedTopos.contains(convertedTopology.getName())) {
+ convertedTopology.setGenerated(true);
}
- return BeanConverter.getTopology(t);
+ return convertedTopology;
}
}
}