Merge branch 'mkoller/chartviewer' into mkoller/contrib

Conflicts:
	org.eclipse.mdm.application/src/main/webapp/package.json

Signed-off-by: Matthias Koller <m.koller@peak-solution.de>
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..8f51d10
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,54 @@
+# Contributing to Eclipse MDM|BL
+
+Thanks for your interest in this project.
+
+## Project description
+
+* https://projects.eclipse.org/projects/technology.mdmbl
+
+## Developer resources
+
+Information regarding source code management, builds, coding standards, and
+more.
+
+* https://projects.eclipse.org/projects/technology.mdmbl/developer
+
+The project maintains the following source code repositories
+
+* https://git.eclipse.org/r/plugins/gitiles/mdmbl/org.eclipse.mdm.api.base
+* https://git.eclipse.org/r/plugins/gitiles/mdmbl/org.eclipse.mdm.api.default
+* https://git.eclipse.org/r/plugins/gitiles/mdmbl/org.eclipse.mdm.api.odsadapter
+* https://git.eclipse.org/r/plugins/gitiles/mdmbl/org.eclipse.mdm.mdfsorter
+* https://git.eclipse.org/r/plugins/gitiles/mdmbl/org.eclipse.mdm.nucleus
+* https://git.eclipse.org/r/plugins/gitiles/mdmbl/org.eclipse.mdm.openatfx.mdf
+
+This project uses Bugzilla to track ongoing development and issues.
+
+* Search for issues: https://bugs.eclipse.org/bugs/buglist.cgi?product=MDMBL
+* Create a new report:
+   https://bugs.eclipse.org/bugs/enter_bug.cgi?product=MDMBL
+
+Be sure to search for existing bugs before you create another one. Remember that
+contributions are always welcome!
+
+## Eclipse Contributor Agreement
+
+Before your contribution can be accepted by the project team contributors must
+electronically sign the Eclipse Contributor Agreement (ECA).
+
+* http://www.eclipse.org/legal/ECA.php
+
+Commits that are provided by non-committers must have a Signed-off-by field in
+the footer indicating that the author is aware of the terms by which the
+contribution has been provided to the project. The non-committer must
+additionally have an Eclipse Foundation account and must have a signed Eclipse
+Contributor Agreement (ECA) on file.
+
+For more information, please see the Eclipse Committer Handbook:
+https://www.eclipse.org/projects/handbook/#resources-commit
+
+## Contact
+
+Contact the project developers via the project's "dev" list.
+
+* https://dev.eclipse.org/mailman/listinfo/mdmbl-dev
diff --git a/NOTICE.txt b/NOTICE.txt
index 05b1024..56281c6 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -16,14 +16,15 @@
 For more information regarding authorship of content, please consult the listed
 source code repository logs.
 
-Copyright (c) 2016-2018 Gigatronik Ingolstadt GmbH
-Copyright (c) 2016-2019 Peak Solution GmbH
+Copyright (c) 2016-2019 Gigatronik Ingolstadt GmbH
+Copyright (c) 2016-2020 Peak Solution GmbH
 Copyright (c) 2017-2018 science + computing AG Tuebingen (ATOS SE)
 Copyright (c) 2017-2018 Canoo Engineering AG
 Copyright (c) 2017 Florian Schmitt
-Copyright (c) 2017-2019 Angelika Wittek
-Copyright (c) 2018 Elektronische Fahrwerksysteme GMBH
-Copyright (c) 2018-2019 Karakun AG
+Copyright (c) 2017-2020 Angelika Wittek
+Copyright (c) 2018-2019 Elektronische Fahrwerksysteme GMBH
+Copyright (c) 2018-2020 Karakun AG
+Copyright (c) 2018-2020 Alexander Nehmer
 
 ## Declared Project Licenses
 
@@ -37,7 +38,7 @@
 
 The project maintains the following source code repositories:
 
-org.eclipse.mdm.api.base.git	      - The openMDM(R) API.
+org.eclipse.mdm.api.base.git	    - The openMDM(R) API.
 org.eclipse.mdm.api.default.git	    - Extension of the openMDM(R) API containing default elements.
 org.eclipse.mdm.api.odsadapter.git	- ODS implementation of persistence adapter.
 org.eclipse.mdm.nucleus.git	        - Core building blocks for the openMDM Business Logic and Web Frontend.
@@ -67,9 +68,6 @@
 commons-text-1.6.jar (1.6)
     * License: Apache License, 2.0
 
-commons-math-2.2.jar (2.2)
-    * License: Apache License, 2.0
-
 gson-2.7.jar (2.7)
     * License: Apache License, 2.0
 
@@ -85,7 +83,7 @@
 hk2-locator-2.5.0-b05.jar(2.5.0-b05)
     * License: CDDL
 
-hk2-utils-2.5.0-b05.jar  (2.5.0-b05)
+hk2-utils-2.5.0-b05.jar (2.5.0-b05)
     * License: CDDL
 
 jackson-annotations-2.9.0.jar  (2.9.0)
@@ -151,6 +149,9 @@
 logback-core-1.2.3.jar(1.2.3)
     * License: Eclipse Public License 1.0
 
+mimepull-1.9.6.jar (1.9.4)
+    * License: CDDL
+
 openatfx-0.7.4.jar (0.7.4)
     * License: Apache-2.0
 
@@ -175,12 +176,18 @@
     * Project URL: https://github.com/qos-ch/slf4j
     * Source URL:  https://github.com/qos-ch/slf4j/releases/tag/v_1.7.25
 
+stax2-api-3.1.4.jar (3.1.4)
+    * License: BSD-2-Clause
+
 validation-api-1.1.0.Final.jar (1.1.0.Final)
   * License: Apache License, 2.0
 
 vavr-0.9.1-sources.jar (0.9.1)
   * License: Apache License, 2.0
 
+vavr-match-0.9.1.jar (0.9.1)
+  * License: Apache License, 2.0
+
 woodstox-core-asl-4.4.1.jar (4.4.1)
   * License: Apache License, 2.0
 
@@ -294,6 +301,18 @@
     * Project: https://valor-software.com/ngx-bootstrap
     * Source:  https://github.com/valor-software/ngx-bootstrap/tree/v3.1.2
 
+@ngx-translate/core@11.0.1
+    * License: MIT 
+    * Licence Path:   https://github.com/ngx-translate/core/blob/v11.0.1/LICENSE  
+    * Project URL:    http://www.ngx-translate.com/
+    * Source URL:     https://github.com/ngx-translate/core
+
+@ngx-translate/http-loader@4.0.0
+    * License: MIT 
+    * Licence Path:   https://github.com/ngx-translate/http-loader/blob/v4.0.0/LICENSE  
+    * Project URL:    http://www.ngx-translate.com/
+    * Source URL:     https://github.com/ngx-translate/http-loader/tree/v4.0.0
+
 primeicons:1.0.0
     * License: MIT
     * Licence Path: https://github.com/primefaces/primeicons/blob/1.0.0/LICENSE
@@ -306,7 +325,7 @@
     * Project: https://www.primefaces.org/primeng
     * Source:  https://github.com/primefaces/primeng/tree/7.0.1
 
-rxjs@5.1.0
+rxjs@6.3.3
     * License: Apache-2.0
     * Project: https://rxjs-dev.firebaseapp.com/
     * Source:  https://github.com/ReactiveX/rxjs/tree/6.3.3
@@ -316,6 +335,10 @@
     * Project: https://rxjs-dev.firebaseapp.com/
     * Source:  https://github.com/ReactiveX/rxjs/tree/6.3.3/compat
 
+tslib@1.9.0
+    * License: Apache-2.0
+    * Project: https://github.com/Microsoft/tslib
+    * Source:  https://github.com/Microsoft/tslib/tree/1.9.0
 
 zone.js@0.8.26
     * License: MIT
@@ -336,17 +359,12 @@
 * Source: https://www.omg.org/spec/NOT/1.1/PDF
 
 ods530.idl
-Permission of use:
-From Hans-Georg Swolana, Chairman of the Board ASAM e.V.,
- Prof. Dr. Marcus Rieker, Member of the Board ASAM e.V.
 Date: Hoehenkirchen, 06/01/2016
 "The ASAM Board of Directors releases the IDL files for use under the EPL to the Eclipse IWG openMDM.
 This is valid for all versions of ASAM ODS 5.3.x.
 This permission is valid under the conditions of Eclipse will not modify the file."
 
 AvalonEvent.idl, CorbaFileServer.idl
-Permission of use:
-From Dr. Ralph Noerenberg
 Date: 08/15/2016
 "Herewith, we release the generated Client-Source-Code generated from our CORBA IDLs, namely
 * CORBANotification Service (generated from „AvalonEvent.idl”)
diff --git a/build.gradle b/build.gradle
index 5e04e9f..d79ce1d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -146,15 +146,16 @@
 
 task distribute(type: Zip) {
 	archiveName = "openMDM_application-${version}.zip"
-	
+
 	from "${project.projectDir}/LICENSE.txt"
 	from "${project.projectDir}/NOTICE.txt"
+	from "${project.projectDir}/CONTRIBUTING.md"
 	from "${project.projectDir}/readme.md"
 	from "${project.projectDir}/release_notes.md"
-	
+
 	from "${project.projectDir}/doc/GettingStarted_mdmbl.pdf"
 	from "${project.projectDir}/doc/Installation Guide for the openMDM5 Application.pdf"
-	
+
 	from "${project.projectDir}/build/tmp/openmdm_application"
 	from "${project.projectDir}/build/libs/"
 }
@@ -172,13 +173,14 @@
 	from ("${project.projectDir}/src/main/webapp/") {
 		include('**/*')
 	}
-	
+
 
 	webXml = file('org.eclipse.mdm.application/src/main/webconfig/web.xml')
 	webInf  {from 'org.eclipse.mdm.application/src/main/webconfig/glassfish-web.xml'}
-	
+
 	metaInf { from 'NOTICE.txt' }
 	metaInf { from 'LICENSE.txt' }
+	metaInf { from 'CONTRIBUTING.md' }
 }
 
 war.finalizedBy(distribute)
diff --git a/org.eclipse.mdm.application/src/main/webapp/package.json b/org.eclipse.mdm.application/src/main/webapp/package.json
index 73751c4..08410e8 100644
--- a/org.eclipse.mdm.application/src/main/webapp/package.json
+++ b/org.eclipse.mdm.application/src/main/webapp/package.json
@@ -1,9 +1,9 @@
 {
   "name": "openMDM-Web",
-  "version": "1.0.0",
+  "version": "5.1.0M8",
   "description": "MDM web client",
   "repository": "http://git.eclipse.org/c/mdmbl/org.eclipse.mdm.nucleus.git",
-  "license": "EPL-1.0",
+  "license": "EPL-2.0",
   "scripts": {
     "ng": "ng",
     "start": "ng serve",
@@ -37,13 +37,13 @@
     "file-saver": "1.3.3",
     "font-awesome": "4.7.0",
     "hammerjs": "2.0.8",
-    "ng2-split-pane": "1.3.1",
     "ngx-bootstrap": "3.1.2",
     "primeflex": "^1.0.0",
     "primeicons": "1.0.0",
     "primeng": "7.0.1",
     "rxjs": "6.3.3",
     "rxjs-compat": "6.3.3",
+    "split.js": "1.5.11",
     "tslib": "1.9.0",
     "zone.js": "0.8.26"
   },
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/NOTICE.html b/org.eclipse.mdm.application/src/main/webapp/src/app/NOTICE.html
index 1142f69..1bf6a90 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/NOTICE.html
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/NOTICE.html
@@ -17,14 +17,15 @@
 For more information regarding authorship of content, please consult the listed
 source code repository logs.
 
-Copyright (c) 2016-2018 Gigatronik Ingolstadt GmbH
-Copyright (c) 2016-2019 Peak Solution GmbH
+Copyright (c) 2016-2019 Gigatronik Ingolstadt GmbH
+Copyright (c) 2016-2020 Peak Solution GmbH
 Copyright (c) 2017-2018 science + computing AG Tuebingen (ATOS SE)
 Copyright (c) 2017-2018 Canoo Engineering AG
 Copyright (c) 2017 Florian Schmitt
-Copyright (c) 2017-2019 Angelika Wittek
-Copyright (c) 2018 Elektronische Fahrwerksysteme GMBH
-Copyright (c) 2018-2019 Karakun AG
+Copyright (c) 2017-2020 Angelika Wittek
+Copyright (c) 2018-2019 Elektronische Fahrwerksysteme GMBH
+Copyright (c) 2018-2020 Karakun AG
+Copyright (c) 2018-2020 Alexander Nehmer
 
 ## Declared Project Licenses
 
@@ -153,6 +154,19 @@
     * Licence Path: https://github.com/valor-software/ngx-bootstrap/blob/v3.1.2/LICENSE
     * Project: https://valor-software.com/ngx-bootstrap
     * Source:  https://github.com/valor-software/ngx-bootstrap/tree/v3.1.2
+    
+@ngx-translate/core@11.0.1
+    * License: MIT 
+    * Licence Path:   https://github.com/ngx-translate/core/blob/v11.0.1/LICENSE  
+    * Project URL:    http://www.ngx-translate.com/
+    * Source URL:     https://github.com/ngx-translate/core
+
+@ngx-translate/http-loader@4.0.0
+    * License: MIT 
+    * Licence Path:   https://github.com/ngx-translate/http-loader/blob/v4.0.0/LICENSE  
+    * Project URL:    http://www.ngx-translate.com/
+    * Source URL:     https://github.com/ngx-translate/http-loader/tree/v4.0.0
+    
 
 primeicons:1.0.0
     * License: MIT
@@ -176,6 +190,10 @@
     * Project: https://rxjs-dev.firebaseapp.com/
     * Source:  https://github.com/ReactiveX/rxjs/tree/6.3.3/compat
 
+tslib@1.9.0
+    * License: Apache-2.0
+    * Project: https://github.com/Microsoft/tslib
+    * Source:  https://github.com/Microsoft/tslib/tree/1.9.0
 
 zone.js@0.8.26
     * License: MIT
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/authentication/authentication.module.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/authentication/authentication.module.ts
new file mode 100644
index 0000000..a3920c7
--- /dev/null
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/authentication/authentication.module.ts
@@ -0,0 +1,26 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+import { NgModule } from '@angular/core';
+import { AuthenticationService } from './authentication.service';
+import { AuthenticationStateService } from './authenticationstate.service';
+
+@NgModule({
+providers: [
+    AuthenticationStateService,
+    AuthenticationService
+]
+})
+export class AuthenticationModule {
+}
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/authentication/authentication.service.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/authentication/authentication.service.ts
new file mode 100644
index 0000000..c94221a
--- /dev/null
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/authentication/authentication.service.ts
@@ -0,0 +1,55 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { Router } from '@angular/router';
+import { AuthenticationStateService, User } from './authenticationstate.service';
+import { PropertyService } from '../core/property.service';
+
+@Injectable({
+    providedIn: 'root'
+  })
+export class AuthenticationService {
+  readonly loginURL: string;
+  readonly logoutURL: string;
+  readonly currentUserURL: string;
+
+  constructor(private http: HttpClient, private router: Router, private _prop: PropertyService,
+              private authService: AuthenticationStateService) {
+
+    this.currentUserURL = _prop.getUrl('mdm/user/current');
+
+      this.loadUser().subscribe(
+          user => this.authService.setLoginUser(user),
+          error => this.authService.unsetLoginUser());
+  }
+
+  private loadUser() {
+      return this.http.get<User>(this.currentUserURL);
+  }
+
+  isLoggedIn() {
+      return this.authService.isLoggedIn();
+  }
+
+  getLoginUser() {
+      return this.authService.getLoginUser();
+  }
+
+  hasRole(role: string) {
+    return this.authService.isUserInRole(role);
+  }
+
+}
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/authentication/authenticationstate.service.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/authentication/authenticationstate.service.ts
new file mode 100644
index 0000000..377ecbd
--- /dev/null
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/authentication/authenticationstate.service.ts
@@ -0,0 +1,64 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+import { Injectable } from '@angular/core';
+import { BehaviorSubject } from 'rxjs';
+import { map } from 'rxjs/operators';
+
+export class User {
+    username: string;
+    roles: string[];
+}
+
+@Injectable({
+    providedIn: 'root'
+  })
+export class AuthenticationStateService {
+    readonly currentUserKey = 'currentUser';
+
+    loginUser = new BehaviorSubject<User>(null);
+
+    getLoginUserValue() {
+        return this.loginUser.value;
+    }
+
+    isUserInRole(roles: string | string[]) {
+        if (typeof roles === 'string') {
+            roles = [ roles ];
+        }
+      return this.isLoggedIn() ? this.loginUser.value.roles.filter(x => roles.includes(x)).length > 0 : false;
+    }
+
+    getLoginUser() {
+        return this.loginUser.asObservable();
+    }
+
+    isLoggedIn() {
+        return this.loginUser.asObservable().pipe(map(user => user !== null));
+    }
+
+    setLoginUser(user: User) {
+        this.loginUser.next(user);
+        localStorage.setItem(this.currentUserKey, JSON.stringify(user));
+    }
+
+    unsetLoginUser() {
+        this.loginUser.next(null);
+        localStorage.removeItem(this.currentUserKey);
+    }
+
+    clearLoginState() {
+        this.unsetLoginUser();
+    }
+}
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/details/attribute-editor/attribute-editor.component.css b/org.eclipse.mdm.application/src/main/webapp/src/app/details/attribute-editor/attribute-editor.component.css
new file mode 100644
index 0000000..03e0f0c
--- /dev/null
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/details/attribute-editor/attribute-editor.component.css
@@ -0,0 +1,15 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+.attreditor {width: 80%;}
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/details/attribute-editor/attribute-editor.component.html b/org.eclipse.mdm.application/src/main/webapp/src/app/details/attribute-editor/attribute-editor.component.html
new file mode 100644
index 0000000..cc9347b
--- /dev/null
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/details/attribute-editor/attribute-editor.component.html
@@ -0,0 +1,22 @@
+<!--******************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ *******************************************************************************-->
+
+<input *ngIf="attribute != null && attribute.dataType === 'STRING'" pInputText type="text" [(ngModel)]="attribute.value[index]" class="attreditor">
+<input *ngIf="attribute != null && attribute.dataType === 'FLOAT'" pInputText type="number" [(ngModel)]="attribute.value[index]" class="attreditor">
+<input *ngIf="attribute != null && attribute.dataType === 'SHORT'" pInputText type="number" [(ngModel)]="attribute.value[index]" class="attreditor">
+<input *ngIf="attribute != null && attribute.dataType === 'LONG'" pInputText type="number" [(ngModel)]="attribute.value[index]" class="attreditor">
+<input *ngIf="attribute != null && attribute.dataType === 'LONGLONG'" pInputText type="number" [(ngModel)]="attribute.value[index]" class="attreditor">
+<input *ngIf="attribute != null && attribute.dataType === 'DOUBLE'" pInputText type="number" [(ngModel)]="attribute.value[index]" class="attreditor">
+<p-calendar *ngIf="attribute != null && attribute.dataType === 'DATE'" dataType="string" dateFormat="{{'details.mdm-detail-descriptive-data.input-dateformat' | translate}}" [(ngModel)]="attribute.value[index]" class="attreditor"></p-calendar>
+<input *ngIf="attribute != null && attribute.dataType === 'BOOLEAN'" pInputText type="checkbox" [(ngModel)]="attribute.value[index]" class="attreditorbool">
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/details/attribute-editor/attribute-editor.component.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/details/attribute-editor/attribute-editor.component.ts
new file mode 100644
index 0000000..e01811a
--- /dev/null
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/details/attribute-editor/attribute-editor.component.ts
@@ -0,0 +1,41 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
+
+import { DetailViewService } from '../detail-view.service';
+import { BasketService } from '../../basket/basket.service';
+import { Node, Attribute } from '../../navigator/node';
+import { MDMItem } from '../../core/mdm-item';
+import { TreeNode } from 'primeng/api';
+import { CalendarModule } from 'primeng/calendar';
+
+@Component({
+  selector: 'attribute-editor',
+  templateUrl: './attribute-editor.component.html',
+  styleUrls: ['./attribute-editor.component.css']
+})
+export class AttributeEditorComponent {
+
+  // attributes of display node
+  @Input() attribute: Attribute;
+
+  @Input() index: number;
+
+  constructor(
+    private detailViewService: DetailViewService,
+    private basketService: BasketService) { }
+
+}
+
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/details/context.service.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/details/context.service.ts
index 0cf0114..986201c 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/details/context.service.ts
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/details/context.service.ts
@@ -37,6 +37,21 @@
     this._contextUrl = _prop.getUrl('mdm/environments');
   }
 
+  putContext(node: Node, context: any) {
+    let url = this._contextUrl + '/' + node.sourceName;
+    url = url + '/' + node.type.toLowerCase() + 's/' + node.id + '/contexts';
+    let body = {
+      "data": [ context ]
+    };
+    return this.http.put(url, body).pipe(
+      map((res) => {
+        let data = res.json().data;
+        let context = this.mergeContextRoots([data[0].ordered, data[0].measured]);
+        return <{}>context;
+      }),
+      catchError(this.httpErrorHandler.handleError));
+  }
+
   getContext(node: Node) {
     let url = this._contextUrl + '/' + node.sourceName;
     url = url + '/' + node.type.toLowerCase() + 's/' + node.id + '/contexts';
@@ -90,7 +105,7 @@
       attr.dataType = ['', attr.dataType];
       attr.name = ['', attr.name];
       attr.unit = ['', attr.unit];
-      attr.value = ['', attr.unit];
+      attr.value = ['', attr.value];
     });
     return node;
   }
@@ -100,7 +115,7 @@
       attr.dataType = [attr.dataType, ''];
       attr.name = [attr.name, ''];
       attr.unit = [attr.unit, ''];
-      attr.value = [attr.unit, ''];
+      attr.value = [attr.value, ''];
     });
     return node;
   }
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail-descriptive-data.component.html b/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail-descriptive-data.component.html
index 05925ab..6a40d62 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail-descriptive-data.component.html
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail-descriptive-data.component.html
@@ -19,74 +19,90 @@
   </div>
 </div>
 
-<div *ngIf="contexts">
-<accordion *ngIf="isUUT()">
-  <accordion-group *ngFor="let template of contexts['UNITUNDERTEST']" #UUT>
-    <div accordion-heading class="thinheader">{{template.name}}
-      <span class="pull-right fa" [ngClass]="{'fa-chevron-down': UUT?.isOpen, 'fa-chevron-right': !UUT?.isOpen}"></span>
-    </div>
-    <table class="table table-hover">
-      <thead>
+<div *ngIf="contexts" class="mdm-details-attributes">
+
+  <button (click)="changeTreeEdit(true, false)" *ngIf="!isEditMode() && canEdit()" style="margin-bottom: 5px;">{{ 'details.mdm-detail-descriptive-data.btn-edit' | translate }}</button>
+  <button (click)="changeTreeEdit(false, false)" *ngIf="isEditMode()" style="margin-bottom: 5px;">{{ 'details.mdm-detail-descriptive-data.btn-cancel' | translate }}</button>
+  <button (click)="changeTreeEdit(false, true)" *ngIf="isEditMode()" style="margin-bottom: 5px;margin-left:10px;">{{ 'details.mdm-detail-descriptive-data.btn-save' | translate }}</button>
+
+  <ng-template ngFor let-tbltype [ngForOf]="getTableTypes()" let-i="tblidx">
+    <p-treeTable #ttref [value]="getTreeNodesFor(tbltype)" *ngIf="isTableType(tbltype)" styleClass="table-hover">
+      <ng-template pTemplate="header">
         <tr>
-          <th>{{ 'details.mdm-detail-descriptive-data.tblhdr-name' | translate }}</th>
+          <th>{{ 'details.mdm-detail-descriptive-data.tblhdr-name' | translate }} <span class="inlinebuttons"><button (click)="changeTreeNodeState(tbltype, true, ttref)">+</button><button (click)="changeTreeNodeState(tbltype, false, ttref)">-</button></span></th>
           <th>{{ 'details.mdm-detail-descriptive-data.tblhdr-ordered' | translate }}</th>
           <th>{{ 'details.mdm-detail-descriptive-data.tblhdr-measured' | translate }}</th>
         </tr>
-      </thead>
-      <tbody>
-        <tr *ngFor="let attr of template.attributes" [ngClass]="diff(attr.value[0], attr.value[1])">
-          <td>{{attr.name}}</td>
-          <td>{{attr.value[0]}}</td>
-          <td>{{attr.value[1]}}</td>
-        </tr>
-      </tbody>
-    </table>
-  </accordion-group>
-</accordion>
-<accordion *ngIf="isTS()">
-  <accordion-group *ngFor="let template of contexts['TESTSEQUENCE']" #TS>
-    <div accordion-heading class="thinheader">{{template.name}}
-      <span class="pull-right fa" [ngClass]="{'fa-chevron-down': TS?.isOpen, 'fa-chevron-right': !TS?.isOpen}"></span>
-    </div>
-    <table class="table table-hover">
-      <thead>
+      </ng-template>
+      <ng-template pTemplate="body" let-rowNode let-rowData="rowData">
         <tr>
-          <th>{{ 'details.mdm-detail-descriptive-data.tblhdr-name' | translate }}</th>
-          <th>{{ 'details.mdm-detail-descriptive-data.tblhdr-ordered' | translate }}</th>
-          <th>{{ 'details.mdm-detail-descriptive-data.tblhdr-measured' | translate }}</th>
+          <td class="{{rowData.header ? 'mdm-component-row' : 'mdm-attribute-row'}}">
+            <p-treeTableToggler [rowNode]="rowNode"></p-treeTableToggler>
+            <span pTooltip="{{rowData.attribute != null ? rowData.attribute.description : ''}}" tooltipPosition="bottom">{{rowData.name}}</span>
+          </td>
+          <td ttEditableColumn class="{{rowData.header ? 'mdm-component-row' : 'mdm-attribute-row'}}">
+            <p-treeTableCellEditor>
+              <ng-template pTemplate="input">
+                <span *ngIf="rowData.attribute != null && isEditMode()"><attribute-editor [attribute]="rowData.attribute" [index]="0"></attribute-editor></span>
+                <span *ngIf="rowData.attribute != null && !isEditMode()">{{rowData.attribute.value[0]}}</span>
+              </ng-template>
+              <ng-template pTemplate="output"><span *ngIf="rowData.attribute != null">{{rowData.attribute.value[0]}}</span></ng-template>
+            </p-treeTableCellEditor>
+            <span *ngIf="rowData.attribute != null && rowData.attribute.unit != null && rowData.attribute.unit.length > 0" class="inlinecontent">{{rowData.attribute.unit}}</span>
+          </td>
+          <td ttEditableColumn class="{{rowData.header ? 'mdm-component-row' : 'mdm-attribute-row'}}">
+            <p-treeTableCellEditor>
+              <ng-template pTemplate="input">
+                <span *ngIf="rowData.attribute != null && rowData.attribute.value.length == 2 && isEditMode()"><attribute-editor [attribute]="rowData.attribute" [index]="1"></attribute-editor></span>
+                <span *ngIf="rowData.attribute != null && rowData.attribute.value.length != 2 && !isEditMode()">{{rowData.attribute.value[1]}}</span>
+              </ng-template>
+              <ng-template pTemplate="output"><span *ngIf="rowData.attribute != null && rowData.attribute.value.length == 2">{{rowData.attribute.value[1]}}</span></ng-template>
+            </p-treeTableCellEditor>
+            <span *ngIf="rowData.attribute != null && rowData.attribute.unit != null && rowData.attribute.unit.length > 0" class="inlinecontent">{{rowData.attribute.unit}}</span>
+          </td>
         </tr>
-      </thead>
-      <tbody>
-        <tr *ngFor="let attr of template.attributes" [ngClass]="diff(attr.value[0], attr.value[1])">
-          <td>{{attr.name}}</td>
-          <td>{{attr.value[0]}}</td>
-          <td>{{attr.value[1]}}</td>
-        </tr>
-      </tbody>
-    </table>
-  </accordion-group>
-</accordion>
-<accordion *ngIf="isTE()">
-  <accordion-group *ngFor="let template of contexts['TESTEQUIPMENT']" #TE>
-    <div accordion-heading class="thinheader">{{template.name}}
-      <span class="pull-right fa" [ngClass]="{'fa-chevron-down': TE?.isOpen, 'fa-chevron-right': !TE?.isOpen}"></span>
-    </div>
-    <table class="table table-hover">
-      <thead>
-        <tr>
-          <th>{{ 'details.mdm-detail-descriptive-data.tblhdr-name' | translate }}</th>
-          <th>{{ 'details.mdm-detail-descriptive-data.tblhdr-ordered' | translate }}</th>
-          <th>{{ 'details.mdm-detail-descriptive-data.tblhdr-measured' | translate }}</th>
-        </tr>
-      </thead>
-      <tbody>
-        <tr *ngFor="let attr of template.attributes" [ngClass]="diff(attr.value[0], attr.value[1])">
-          <td>{{attr.name}}</td>
-          <td>{{attr.value[0]}}</td>
-          <td>{{attr.value[1]}}</td>
-        </tr>
-      </tbody>
-    </table>
-  </accordion-group>
-</accordion>
+      </ng-template>
+    </p-treeTable>
+  </ng-template>
+    <!--
+  <p-treeTable #ttts [value]="getTreeNodesFor('TESTSEQUENCE')" *ngIf="isTS()" styleClass="table-hover">
+    <ng-template pTemplate="header">
+      <tr>
+        <th>{{ 'details.mdm-detail-descriptive-data.tblhdr-name' | translate }} <span class="inlinebuttons"><button (click)="changeTreeNodeState('TESTSEQUENCE', true, ttts)">+</button><button (click)="changeTreeNodeState('TESTSEQUENCE', false, ttts)">-</button></span></th>
+        <th>{{ 'details.mdm-detail-descriptive-data.tblhdr-ordered' | translate }}</th>
+        <th>{{ 'details.mdm-detail-descriptive-data.tblhdr-measured' | translate }}</th>
+      </tr>
+    </ng-template>
+    <ng-template pTemplate="body" let-rowNode let-rowData="rowData">
+      <tr>
+        <td class="{{rowData.header ? 'mdm-component-row' : 'mdm-attribute-row'}}">
+          <p-treeTableToggler [rowNode]="rowNode"></p-treeTableToggler>
+          <span pTooltip="{{rowData.attribute != null ? rowData.attribute.description : ''}}" tooltipPosition="bottom">{{rowData.name}}</span>
+        </td>
+        <td class="{{rowData.header ? 'mdm-component-row' : 'mdm-attribute-row'}}">{{rowData.attribute != null ? rowData.attribute.value[0] : ''}} <span *ngIf="rowData.attribute != null && rowData.attribute.unit != null && rowData.attribute.unit.length > 0" class="inlinecontent">{{rowData.attribute.unit}}</span></td>
+        <td class="{{rowData.header ? 'mdm-component-row' : 'mdm-attribute-row'}}">{{rowData.attribute != null ? rowData.attribute.value[1] : ''}} <span *ngIf="rowData.attribute != null && rowData.attribute.unit != null && rowData.attribute.unit.length > 0" class="inlinecontent">{{rowData.attribute.unit}}</span></td>
+      </tr>
+    </ng-template>
+  </p-treeTable>
+  <p-treeTable #ttte [value]="getTreeNodesFor('TESTEQUIPMENT')" *ngIf="isTE()" styleClass="table-hover">
+    <ng-template pTemplate="header">
+      <tr>
+        <th>{{ 'details.mdm-detail-descriptive-data.tblhdr-name' | translate }} <span class="inlinebuttons"><button (click)="changeTreeNodeState('TESTEQUIPMENT', true, ttte)">+</button><button (click)="changeTreeNodeState('TESTEQUIPMENT', false, ttte)">-</button></span></th>
+        <th>{{ 'details.mdm-detail-descriptive-data.tblhdr-ordered' | translate }}</th>
+        <th>{{ 'details.mdm-detail-descriptive-data.tblhdr-measured' | translate }}</th>
+      </tr>
+    </ng-template>
+    <ng-template pTemplate="body" let-rowNode let-rowData="rowData">
+      <tr>
+        <td class="{{rowData.header ? 'mdm-component-row' : 'mdm-attribute-row'}}">
+          <p-treeTableToggler [rowNode]="rowNode"></p-treeTableToggler>
+          <span pTooltip="{{rowData.attribute != null ? rowData.attribute.description : ''}}" tooltipPosition="bottom">{{rowData.name}}</span>
+        </td>
+        <td class="{{rowData.header ? 'mdm-component-row' : 'mdm-attribute-row'}}">{{rowData.attribute != null ? rowData.attribute.value[0] : ''}} <span *ngIf="rowData.attribute != null && rowData.attribute.unit != null && rowData.attribute.unit.length > 0" class="inlinecontent">{{rowData.attribute.unit}}</span></td>
+        <td class="{{rowData.header ? 'mdm-component-row' : 'mdm-attribute-row'}}">{{rowData.attribute != null ? rowData.attribute.value[1] : ''}} <span *ngIf="rowData.attribute != null && rowData.attribute.unit != null && rowData.attribute.unit.length > 0" class="inlinecontent">{{rowData.attribute.unit}}</span></td>
+      </tr>
+    </ng-template>
+  </p-treeTable>
+      -->
+
 </div>
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail-descriptive-data.component.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail-descriptive-data.component.ts
index 936ef94..7a6c5f6 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail-descriptive-data.component.ts
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail-descriptive-data.component.ts
@@ -16,17 +16,24 @@
 import { Component, OnInit } from '@angular/core';
 import { ActivatedRoute } from '@angular/router';
 
+import { TreeNode } from 'primeng/api';
+
 import { LocalizationService } from '../localization/localization.service';
 
-import { ContextService } from './context.service';
+import { ContextService, ContextAttribute, MergedContextAttribute } from './context.service';
 import { Context, Sensor } from './context';
-import { Node } from '../navigator/node';
+import { Node, Attribute } from '../navigator/node';
 import { NavigatorService } from '../navigator/navigator.service';
 
 import { MDMNotificationService } from '../core/mdm-notification.service';
 
 import { TranslateService } from '@ngx-translate/core';
 import { TRANSLATE } from '../core/mdm-core.module';
+import { TreeTable } from 'primeng/primeng';
+import { Observable, BehaviorSubject } from 'rxjs';
+import { DatePipe } from '@angular/common';
+import { AuthenticationService } from '../authentication/authentication.service';
+import { isArray } from 'util';
 
 @Component({
   selector: 'mdm-detail-context',
@@ -36,9 +43,16 @@
 export class MDMDescriptiveDataComponent implements OnInit {
 
   readonly StatusLoading = TRANSLATE('details.mdm-detail-descriptive-data.status-loading');
+  readonly StatusSaving = TRANSLATE('details.mdm-detail-descriptive-data.status-saving');
   readonly StatusNoNodes = TRANSLATE('details.mdm-detail-descriptive-data.status-no-nodes-available');
   readonly StatusNoDescriptiveData = TRANSLATE('details.mdm-detail-descriptive-data.status-no-descriptive-data-available');
 
+  treeNodes: TreeNode[][];
+  bsTreeNodes: BehaviorSubject<TreeNode[][]> = new BehaviorSubject<TreeNode[][]>(undefined);
+
+  // this holds the type dependant original context data in case of cancelling the edit mode
+  tmpTreeNodes: Context;
+
   selectedNode: Node;
   context: String;
 
@@ -48,25 +62,36 @@
   status: string;
 
   msgsStatus: string;
+  editMode: boolean;
 
   constructor(private route: ActivatedRoute,
               private localService: LocalizationService,
               private _contextService: ContextService,
               private navigatorService: NavigatorService,
               private notificationService: MDMNotificationService,
-              private translateService: TranslateService) {}
+              private translateService: TranslateService,
+              private datePipe: DatePipe,
+              private authenticationService: AuthenticationService) {
+
+    this.bsTreeNodes.subscribe(value => {
+      this.treeNodes = value;
+    });
+  }
 
   ngOnInit() {
-   this.status = this.StatusLoading;
+    this.status = this.StatusLoading;
+    this.editMode = false;
 
     this.refreshDetailData(this.navigatorService.getSelectedNode());
 
+    // context tab changed from the toolbar navigation
     this.route.params
-        .subscribe(
-          params => this.setContext(params['context']),
+      .subscribe(
+        params => this.refreshContextData(params['context']),
           error => this.notificationService.notifyError(
             this.translateService.instant('details.mdm-detail-descriptive-data.err-cannot-load-scope'), error));
 
+    // node changed from the navigation tree
     this.navigatorService.selectedNodeChanged
         .subscribe(
           node => this.refreshDetailData(node),
@@ -78,11 +103,31 @@
     this.context = context;
   }
 
+  /**
+   * Listener method to change the context tab
+   * 
+   * @param contextType
+   */
+  refreshContextData(contextType: string) {
+    // revert before changing the context
+    this.undoEditChanges(undefined, this.editMode);
+    this.setContext(contextType);
+    this.editMode = false;
+  }
+
+  /**
+   * Listener method to change the node
+   * 
+   * @param node
+   */
   refreshDetailData(node: Node) {
     if (node != undefined) {
       this.selectedNode = node;
       this.status = this.StatusLoading;
-      if (node.type.toLowerCase() === 'measurement' || node.type.toLowerCase() === 'teststep') {
+      this.editMode = false;
+      this.contexts = undefined;
+      this.bsTreeNodes.next(undefined);
+      if (node.type.toLowerCase() === 'measurement' || node.type.toLowerCase() === 'teststep' || node.type.toLowerCase() === 'test') {
         this.loadContext(node);
       } else {
         this.status = this.StatusNoDescriptiveData;
@@ -92,14 +137,19 @@
     }
   }
 
+  /**
+   * Load the context data for the provided node
+   * 
+   * @param node
+   */
   private loadContext(node: Node) {
-    this.contexts = undefined;
     this._contextService.getContext(node).subscribe(
       contexts => {
           if (contexts.hasOwnProperty('UNITUNDERTEST')
               || contexts.hasOwnProperty('TESTEQUIPMENT')
               || contexts.hasOwnProperty('TESTSEQUENCE')) {
-                this.contexts =  <Context[]> contexts;
+                this.contexts = <Context[]>contexts;
+                this.bsTreeNodes.next(this.mapContexts(this.contexts));
               } else {
                 this.status = this.StatusNoDescriptiveData;
               }
@@ -130,4 +180,449 @@
   isTS() {
     return this.context.toLowerCase() === 'ts';
   }
+
+  getId(node: TreeNode) {
+    if (node && node.data) {
+      return 'node_' + node.data.source + '_' + node.data.type + '_' + node.data.id;
+    } else {
+      return '';
+    }
+  }
+
+  getNodeClass(item: Node) {
+    return 'icon ' + item.type.toLowerCase();
+  }
+
+  /**
+   * Get the tree nodes for the type
+   *
+   * @param type
+   */
+  getTreeNodesFor(type: string) {
+    for (let i in this.treeNodes) {
+      if (i == type) {
+        return this.treeNodes[i];
+      }
+    }
+    return [];
+  }
+
+  /**
+   * Change the tree state to expanded or collapsed
+   *
+   * @param type
+   * @param expand
+   */
+  changeTreeNodeState(type: string, expand: boolean, tt: TreeTable) {
+    for (var i in this.treeNodes) {
+      if (i == type) {
+        for (let j in this.treeNodes[i]) {
+          this.recursiveChangeNodes(this.treeNodes[i][j], expand);
+        }
+      }
+    }
+    // invoke table update when pressing the plus or minus buttons from the table header
+    tt.updateSerializedValue();
+    tt.tableService.onUIUpdate(tt.value);
+  }
+
+  /**
+   * Change the tree node state recursively
+   *
+   * @param node
+   * @param expand
+   */
+  recursiveChangeNodes(node: TreeNode, expand: boolean) {
+    node.expanded = expand;
+    if (node.children != undefined && node.children.length > 0) {
+      for (let i in node.children) {
+        this.recursiveChangeNodes(node.children[i], expand);
+      }
+    }
+  }
+
+  /**
+   * Get the nodes from the current context
+   *
+   * @param context
+   * @param parentId optional parent id which will get the child nodes
+   */
+  getNodes(context: Context, parentId: string) {
+    let list = [];
+    for (let j in context) {
+      let parentNodeId = context[j].relations != null && context[j].relations.length > 0 ? context[j].relations[0].parentId : null;
+      if (parentId == null && parentNodeId == null) {
+        list.push(context[j]);
+      } else if (parentId != null && parentNodeId != null && parentId == parentNodeId) {
+        list.push(context[j]);
+      }
+    }
+    return list;
+  }
+
+  /**
+   * Create a tree node based on the mdm entity
+   *
+   * @param node
+   * @param context
+   */
+  createTreeNode(node: Node, context: Context) {
+    return <TreeNode>{
+      label: node.name,
+      data: {
+        "name": node.name,
+        "attribute": null,
+        "header": true
+      },
+      children: this.createTreeChildren(node, context),
+      icon: this.getNodeClass(node),
+      expanded: true
+    };
+  }
+
+  /**
+   * Create the tree children nodes recursive based on the mdm attributes and subsequent mdm entities
+   *
+   * @param node the current node
+   * @param contexts the complete contexts
+   */
+  createTreeChildren(node: Node, context: Context) {
+    let list = [];
+
+    for (let i in node.attributes) {
+      let tmp = <TreeNode>{
+        data: {
+          "name": node.attributes[i].name,
+          "attribute": this.patchAttributeForDate(node.attributes[i] as any as MergedContextAttribute),
+          "header": false
+        },
+        expanded: true
+      };
+      list.push(tmp);
+    }
+    // call recursive child components with complete null checks
+    if (node.relations != null && node.relations.length > 0) {
+      for (let i in node.relations) {
+        if (node.relations[i].ids != null && node.relations[i].ids.length > 0) {
+          for (let j in node.relations[i].ids) {
+            let curTplId = node.relations[i].ids[j];
+            let nodes = this.getNodes(context, curTplId);
+            for (var k in nodes) {
+              let node = this.createTreeNode(nodes[k], context);
+              list.push(node);
+            }
+          }
+        }
+      }
+    }
+
+    return list;
+  }
+
+  /**
+   * Method to create a tree structure from the flat context entity and attribute map
+   *
+   * @param contexts
+   */
+  mapContexts(contexts: Context[]) {
+    let list = [];
+    let subList = [];
+
+    // generate all context component mappings
+    for (let i in contexts) {
+      let nodes = this.getNodes(contexts[i], null);
+      for (let j in nodes) {
+        let node = this.createTreeNode(nodes[j], contexts[i]);
+        subList.push(node);
+      }
+      list[i] = subList;
+      subList = [];
+    }
+
+    return list;
+  }
+
+  /**
+   * Convert the date for UI or backend
+   * 
+   * @param attribute
+   */
+  patchAttributeForDate(attribute: MergedContextAttribute) {
+    if (attribute.dataType != null && attribute.dataType.length > 0 && "DATE" === attribute.dataType
+      && attribute.value != null && attribute.value.length > 0) {
+      if (attribute.value[0] != null && attribute.value[0].length > 0)
+        attribute.value[0] = this.convertFixedDateStr(attribute.value[0], true);
+      if (attribute.value.length > 1 && attribute.value[1] != null && attribute.value[1].length > 0)
+        attribute.value[1] = this.convertFixedDateStr(attribute.value[1], true);
+    }
+    return attribute;
+  }
+  
+  /** *********************
+   * Edit functions start
+   ********************** */
+
+  convertFixedDateStr(dt: string, convertForUI: boolean) {
+    let newDt = dt;
+    let sourceFormat = "";
+    (this.translateService.get("details.mdm-detail-descriptive-data.input-dateformat") as Observable<string | any>).subscribe(val => sourceFormat = val);
+    sourceFormat = sourceFormat.replace("yy", "yyyy");
+
+    if (dt != null && dt.length > 0 && convertForUI && dt.indexOf('T') > -1) {
+      let tmpDt = this.parseISOString(dt);
+      newDt = this.datePipe.transform(tmpDt, sourceFormat.replace('mm', 'MM'));
+    } else if (dt != null && dt.length > 0 && !convertForUI && dt.indexOf('T') == -1) {
+      // re-convert date to server date
+      if (newDt.indexOf('-') == -1) {
+        // find dd, mm and yyyy and grab the according index positions
+        let startDay = sourceFormat.indexOf('d');
+        let endDay = sourceFormat.lastIndexOf('d');
+        let startMonth = sourceFormat.indexOf('m');
+        let endMonth = sourceFormat.lastIndexOf('m');
+        let startYear = sourceFormat.indexOf('y');
+        let endYear = sourceFormat.lastIndexOf('y');
+        // manually attach the time as toISOString() will not properly transform the winter/summer time
+        newDt = dt.substring(startYear, endYear + 1) + '-' + dt.substring(startMonth, endMonth + 1) + '-' + dt.substring(startDay, endDay + 1) + 'T00:00:00Z';
+        if (newDt.length != 20) {
+          newDt = "";
+        }
+      }
+    }
+    return newDt;
+  }
+
+  /**
+   * Fixed parsing for ISO date string
+   * 
+   * @param s
+   */
+  parseISOString(s: string) {
+    let b: any[] = s.split(/\D+/);
+    return new Date(Date.UTC(b[0], --b[1], b[2], b[3], b[4], b[5], b[6]));
+  }
+
+  /**
+   * Send the changed data to the backend
+   * 
+   * @param node
+   * @param type
+   */
+  private putContext(node: Node, type: string) {
+    if (type == null) {
+      return;
+    }
+
+    this.status = this.StatusSaving;
+    this.bsTreeNodes.next(undefined);
+
+    let data = { "ordered": {}, "measured": {} };
+
+    for (let i in this.contexts) {
+      // only the requested type
+      if (i == type) {
+        // workaround to initialize as map or we get a list in the backend
+        data["ordered"][i] = [];
+        data["ordered"][i] = this.getNodesWithUpdatedContent(this.contexts[i], type, true);
+        data["measured"][i] = [];
+        data["measured"][i] = this.getNodesWithUpdatedContent(this.contexts[i], type, false);
+      }
+    }
+
+    // clear for status display
+    this.contexts = undefined;
+
+    this._contextService.putContext(node, data).subscribe(
+      contexts => {
+        if (contexts.hasOwnProperty('UNITUNDERTEST')
+          || contexts.hasOwnProperty('TESTEQUIPMENT')
+          || contexts.hasOwnProperty('TESTSEQUENCE')) {
+          this.contexts = <Context[]>contexts;
+          this.bsTreeNodes.next(this.mapContexts(this.contexts));
+        } else {
+          this.status = this.StatusNoDescriptiveData;
+        }
+      },
+      error => this.notificationService.notifyError(
+        this.translateService.instant('details.mdm-detail-descriptive-data.err-cannot-load-context'), error)
+    );
+  }
+
+  /**
+   * Get the table types
+   */
+  getTableTypes() {
+    return ["UNITUNDERTEST", "TESTEQUIPMENT", "TESTSEQUENCE"];
+  }
+
+  /**
+   * Check if the provided type matches with the url path
+   * 
+   * @param type
+   */
+  isTableType(type: string) {
+    return "UNITUNDERTEST" === type && this.isUUT()
+      || "TESTEQUIPMENT" === type && this.isTE()
+      || "TESTSEQUENCE" === type && this.isTS();
+  }
+
+  /**
+   * Is edit mode enabled
+   */
+  isEditMode() {
+    return this.editMode;
+  }
+
+  /**
+   * Can edit attributes
+   */
+  canEdit() {
+    // Read the role 'write-user' from the web.xml configuration mapping
+    return this.authenticationService.hasRole('write-user');
+  }
+
+  /**
+   * Switch the tree edit mode
+   * 
+   * @param editMode true if edit mode, false if leaving edit mode
+   * @param save when leaving edit mode, true then save data, false then cancel data
+   */
+  changeTreeEdit(editMode: boolean, save: boolean) {
+    let type = null;
+    if (this.isUUT()) {
+      type = "UNITUNDERTEST";
+    } else if (this.isTE()) {
+      type = "TESTEQUIPMENT";
+    } else if (this.isTS()) {
+      type = "TESTSEQUENCE";
+    }
+
+    this.editMode = editMode;
+
+    if (this.editMode) {
+      // clone tree
+      this.tmpTreeNodes = JSON.parse(JSON.stringify(this.contexts[type]));
+    }
+
+    if (!editMode && save) {
+      // either cancel or save
+      this.putContext(this.selectedNode, type);
+      this.tmpTreeNodes = null;
+    } else if (!editMode && !save) {
+      this.undoEditChanges(type, true);
+    }
+  }
+
+  /**
+   * Method to revert table changes back to the original state
+   * 
+   * @param type
+   */
+  undoEditChanges(type: string, editMode: boolean) {
+    if (this.contexts != undefined && editMode && this.tmpTreeNodes != undefined) {
+      if (type == undefined) {
+        if (this.isUUT()) {
+          type = "UNITUNDERTEST";
+        } else if (this.isTE()) {
+          type = "TESTEQUIPMENT";
+        } else if (this.isTS()) {
+          type = "TESTSEQUENCE";
+        }
+      }
+      // contexts is the origin, so we revert this back as the tree attributes are just references
+      this.contexts[type] = this.tmpTreeNodes;
+      // revert back
+      this.bsTreeNodes.next(this.mapContexts(this.contexts));
+      this.tmpTreeNodes = null;
+    }
+  }
+
+  /**
+   * Get the updated nodes from the current context
+   *
+   * @param context
+   * @param type the context type
+   * @param ordered true if ordered data, false if measured data
+   */
+  getNodesWithUpdatedContent(context: Context, type: string, ordered: boolean) {
+    let list = [];
+    for (let i in context) {
+      let parentNodeId = context[i].relations != null && context[i].relations.length > 0 ? context[i].relations[0].parentId : null;
+      if (parentNodeId == null) {
+        let attrs = [];
+        for (let j in context[i].attributes) {
+          let attr = new ContextAttribute();
+          let addAttr = true;
+          attr.dataType = context[i].attributes[j].dataType;
+          attr.name = context[i].attributes[j].name;
+          attr.unit = context[i].attributes[j].unit;
+          attr.value = "";
+          if (ordered && isArray(context[i].attributes[j].value) && context[i].attributes[j].value.length > 0) {
+            attr.value = context[i].attributes[j].value[0];
+          }
+          else if (!ordered && isArray(context[i].attributes[j].value) && context[i].attributes[j].value.length > 1) {
+            attr.value = context[i].attributes[j].value[1];
+          }
+          // lookup new value from treenodes
+
+          if (attr.dataType === 'BOOLEAN' && attr.value != null && attr.value.toString().length > 0) {
+            attr.value = attr.value.toString() === 'true' ? '1' : '0';
+          }
+
+          // BUG: don't add if non-string as this throws an parsing error in the middleware
+          if (attr.dataType !== 'STRING' && (attr.value == null || attr.value.toString().length == 0))
+            addAttr = false;
+
+          if (addAttr && attr.dataType === 'DATE') {
+            attr.value = this.convertFixedDateStr(attr.value, false);
+          }
+
+          if (addAttr) {
+            let confirmedChange = false;
+            let found = false;
+            // lookup from the original and check if the value was modified
+            for (let i1 in this.tmpTreeNodes) {
+              if (found) break;
+              if (this.tmpTreeNodes[i1].name == context[i].name) {
+                for (let j1 in this.tmpTreeNodes[i1].attributes) {
+                  if (this.tmpTreeNodes[i1].attributes[j1].name == attr.name && isArray(this.tmpTreeNodes[i1].attributes[j1].value)) {
+                    found = true;
+                    let orgValue = ordered ? this.tmpTreeNodes[i1].attributes[j1].value[0] :
+                      this.tmpTreeNodes[i1].attributes[j1].value.length > 1 ? this.tmpTreeNodes[i1].attributes[j1].value[1] : undefined;
+                    if (orgValue != undefined) {
+                      if (attr.dataType === 'BOOLEAN') {
+                        // server value = true or false, UI value = 1 or 0
+                        confirmedChange = attr.value == '0' && orgValue == 'true'
+                          || attr.value == '1' && orgValue == 'false'
+                          || attr.value != '' && orgValue == '';
+                      } else {
+                        // plain comparison
+                        confirmedChange = attr.value != orgValue;
+                      }
+                      break;
+                    }
+                  }
+                }
+              }
+            }
+
+            if (confirmedChange)
+              attrs.push(attr);
+          }
+        }
+        // un-merged list
+        //context[i].attributes = attrs;
+        if (attrs.length > 0) {
+          let component = JSON.parse(JSON.stringify(context[i]));
+          component.attributes = attrs;
+          list.push(component);
+        }
+      }
+    }
+    return list;
+  }
+
+  /** *********************
+   * Edit functions end
+   ********************** */
+
 }
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail.component.html b/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail.component.html
index d8a3f0f..51c70c9 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail.component.html
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail.component.html
@@ -19,7 +19,7 @@
   }
 </style>
 
-<nav class="navbar navbar-expand bg-light detail-nav ui-corner-all">
+<nav class="navbar navbar-expand bg-light detail-nav ui-corner-all" *ngIf="isVisible()">
   <div class="container-fluid">
     <div class="collapse navbar-collapse" id="bs-mdm-detail-navbar">
       <ul class="nav navbar-nav mdm-link-list">
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail.component.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail.component.ts
index ad99198..c3f41fd 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail.component.ts
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail.component.ts
@@ -13,12 +13,16 @@
  ********************************************************************************/
 
 
-import {Component} from '@angular/core';
+import { Component } from '@angular/core';
+import { Router, ActivatedRoute } from '@angular/router';
 
 import {MDMDetailViewComponent} from './mdm-detail-view.component';
 import {MDMDescriptiveDataComponent} from './mdm-detail-descriptive-data.component';
 import {SensorComponent} from './sensor.component';
 
+import { Node } from '../navigator/node';
+import { NavigatorService } from '../navigator/navigator.service';
+
 @Component({
   selector: 'mdm-detail',
   templateUrl: 'mdm-detail.component.html',
@@ -26,4 +30,33 @@
 })
 export class MDMDetailComponent {
 
+  visible = false;
+
+  constructor(private route: ActivatedRoute,
+    private router: Router,
+    private navigatorService: NavigatorService) {
+
+    this.refreshVisibility(this.navigatorService.getSelectedNode());
+
+    this.navigatorService.selectedNodeChanged
+      .subscribe(node => this.refreshVisibility(node));
+  }
+
+  refreshVisibility(node: Node) {
+    this.visible = false;
+    if (node != undefined && node.type != undefined && (node.type.toLowerCase() === 'measurement' || node.type.toLowerCase() === 'teststep' || node.type.toLowerCase() === 'test')) {
+       this.visible = true;
+    }
+
+    // check if we are in the general node and if the context tabs are visible
+    if (!this.visible && this.router.url !== '/navigator/details/general') {
+      // redirect to correct router path
+      this.router.navigate(['/navigator/details/general']);
+    }
+  }
+
+  isVisible() {
+    return this.visible;
+  }
+
 }
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail.module.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail.module.ts
index fa13b59..446d4bd 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail.module.ts
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/details/mdm-detail.module.ts
@@ -19,6 +19,8 @@
 
 import { MDMCoreModule } from '../core/mdm-core.module';
 import { PanelModule } from 'primeng/panel';
+import { TreeTableModule } from 'primeng/treetable';
+import { TooltipModule } from 'primeng/tooltip';
 
 import { MDMDetailComponent } from './mdm-detail.component';
 import { MDMDetailViewComponent } from './mdm-detail-view.component';
@@ -27,12 +29,18 @@
 import { SensorComponent } from './sensor.component';
 import { ContextService } from './context.service';
 import { DetailPanelComponent } from './detail-panel/detail-panel.component';
+import { AttributeEditorComponent } from './attribute-editor/attribute-editor.component';
+import { DatePipe } from '@angular/common';
+import { AuthenticationModule } from '../authentication/authentication.module';
 
 @NgModule({
   imports: [
     MDMDetailRoutingModule,
     MDMCoreModule,
-    PanelModule
+    PanelModule,
+    TreeTableModule,
+    TooltipModule,
+    AuthenticationModule
   ],
   declarations: [
     MDMDetailComponent,
@@ -40,13 +48,15 @@
     MDMDescriptiveDataComponent,
     SensorComponent,
     DetailPanelComponent,
+    AttributeEditorComponent
   ],
   exports: [
     MDMDetailComponent
   ],
   providers: [
     DetailViewService,
-    ContextService
+    ContextService,
+    DatePipe
   ]
 })
 export class MDMDetailModule {
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/navigator-view/mdm-navigator-view.component.html b/org.eclipse.mdm.application/src/main/webapp/src/app/navigator-view/mdm-navigator-view.component.html
index e5ea941..c743f87 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/navigator-view/mdm-navigator-view.component.html
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/navigator-view/mdm-navigator-view.component.html
@@ -11,43 +11,41 @@
  * SPDX-License-Identifier: EPL-2.0
  *
  ********************************************************************************-->
-
-
-<vertical-split-pane primary-component-minsize="{{minWidthLeft()}}" secondary-component-minsize="{{minWidthRight()}}" primary-component-initialratio="{{initRatio()}}">
-  <div class="split-pane-content-primary">
-    <nav class="navigator">
-      <div class="navbar navbar-default container-fluid" style="padding: 0px 5px;">
-        <div class="navbar-header">
-          <a class="navbar-brand" (click)="activate('Navigation')" style="cursor:pointer;">{{ 'navigator-view.mdm-navigator-view.navigator' | translate }}</a>
-        </div>
-        <div>
-          <ul class="nav navbar-nav navbar-right">
-            <li [ngClass]="isDropActive('Dropdown')" title="{{ 'navigator-view.mdm-navigator-view.select-node-provider' | translate }}" dropdown>
-              <a (click)="activate('Dropdown')" class="dropdown-toggle" dropdownToggle aria-haspopup="true" aria-expanded="false" style="cursor:pointer;">
+  <div class="mainnavigation">
+    <div id="leftsidenav" class="split">
+      <nav class="navigator">
+        <div class="navbar navbar-default container-fluid" style="padding: 0px 5px;">
+          <div class="navbar-header">
+            <a class="navbar-brand" (click)="activate('Navigation')" style="cursor:pointer;">{{ 'navigator-view.mdm-navigator-view.navigator' | translate }}</a>
+          </div>
+          <div>
+            <ul class="nav navbar-nav navbar-right">
+              <li [ngClass]="isDropActive('Dropdown')" title="{{ 'navigator-view.mdm-navigator-view.select-node-provider' | translate }}" dropdown>
+                <a (click)="activate('Dropdown')" class="dropdown-toggle" dropdownToggle aria-haspopup="true" aria-expanded="false" style="cursor:pointer;">
                   {{activeNodeprovider.name}}
-                <em class="caret" ></em>
-              </a>
-              <ul class="dropdown-menu" *dropdownMenu>
-                <li *ngFor="let np of getNodeproviders()">
-                  <a class="dropdown-item" (click)="activateNodeProvider(np)" style="cursor:pointer;">
+                  <em class="caret"></em>
+                </a>
+                <ul class="dropdown-menu" *dropdownMenu>
+                  <li *ngFor="let np of getNodeproviders()">
+                    <a class="dropdown-item" (click)="activateNodeProvider(np)" style="cursor:pointer;">
                       {{np.name}}
-                  </a>
-                </li>
-              </ul>
-            </li>
-          </ul>
+                    </a>
+                  </li>
+                </ul>
+              </li>
+            </ul>
+          </div>
         </div>
-      </div>
-      <mdm-navigator></mdm-navigator>
-    </nav>
-  </div>
-  <div class="split-pane-content-secondary">
-    <div class="navigator-content" (scroll)=onScroll($event)>
-      <router-outlet></router-outlet>
-      <mdm-basket (onSelect)="updateSelectedNode($event)" [activeNode]=activeNode (onActive)="updateActiveNode($event)"></mdm-basket>
-      <div *ngIf="scrollBtnVisible" style="position: fixed; bottom: 30px; right: 35px;">
-        <button class="btn btn-default" (click)="onScrollTop()" style="z-index: 10000;"><span class="fa fa-arrow-up" style="z-index: 10000;" title="{{ 'navigator-view.mdm-navigator-view.tooltip-scroll-up' | translate }}"></span></button>
+        <mdm-navigator></mdm-navigator>
+      </nav>
+    </div>
+    <div id="rightsidenav" class="split">
+      <div class="navigator-content" (scroll)=onScroll($event)>
+        <router-outlet></router-outlet>
+        <mdm-basket (onSelect)="updateSelectedNode($event)" [activeNode]=activeNode (onActive)="updateActiveNode($event)"></mdm-basket>
+        <div *ngIf="scrollBtnVisible" style="position: fixed; bottom: 30px; right: 35px;">
+          <button class="btn btn-default" (click)="onScrollTop()" style="z-index: 10000;"><span class="fa fa-arrow-up" style="z-index: 10000;" title="{{ 'navigator-view.mdm-navigator-view.tooltip-scroll-up' | translate }}"></span></button>
+        </div>
       </div>
     </div>
   </div>
-</vertical-split-pane>
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/navigator-view/mdm-navigator-view.component.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/navigator-view/mdm-navigator-view.component.ts
index 94e3479..017b192 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/navigator-view/mdm-navigator-view.component.ts
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/navigator-view/mdm-navigator-view.component.ts
@@ -13,18 +13,18 @@
  ********************************************************************************/
 
 
-import {Component, ViewEncapsulation, OnInit, OnDestroy} from '@angular/core';
+import { Component, ViewEncapsulation, OnInit, OnDestroy, AfterViewInit } from '@angular/core';
 
 import { BsDropdownModule, AccordionConfig, BsDropdownConfig } from 'ngx-bootstrap';
 
 import {NodeService} from '../navigator/node.service';
 import {Node} from '../navigator/node';
 import {NodeproviderService} from '../navigator/nodeprovider.service';
-import { SplitPaneModule } from 'ng2-split-pane/lib/ng2-split-pane';
 
 import {MDMNotificationService} from '../core/mdm-notification.service';
 
 import { TranslateService } from '@ngx-translate/core';
+import Split from 'split.js';
 
 @Component({
   selector: 'mdm-navigator-view',
@@ -33,7 +33,7 @@
   providers: [BsDropdownConfig, AccordionConfig],
   encapsulation: ViewEncapsulation.None
 })
-export class MDMNavigatorViewComponent implements OnInit, OnDestroy {
+export class MDMNavigatorViewComponent implements OnInit, OnDestroy, AfterViewInit {
 
   selectedNode = new Node;
   activeNode: Node;
@@ -46,6 +46,8 @@
   div: any;
   scrollBtnVisible = false;
 
+  split: Split;
+
   constructor(private nodeProviderService: NodeproviderService,
               private notificationService: MDMNotificationService,
               private translateService: TranslateService) {}
@@ -84,7 +86,22 @@
           np => this.activeNodeprovider = np,
           error => this.notificationService.notifyError(
             this.translateService.instant('navigator-view.mdm-navigator-view.err-cannot-update-node-provider'), error)
-        );
+    );
+
+  }
+
+  ngAfterViewInit(): void {
+    this.split = Split(['#leftsidenav', '#rightsidenav'], {
+      sizes: [this.initRatio(), this.initRatioRight()],
+      minSize: this.minWidthLeft(),
+      gutterSize: 10,
+      gutterStyle: function (dimension, gutterSize) {
+        return {
+          'width': gutterSize + 'px',
+          'height': (document.getElementById('leftsidenav').clientHeight - 5) + 'px'
+        }
+      },
+    });
   }
 
   ngOnDestroy() {
@@ -115,7 +132,11 @@
      return 0.20 * window.innerWidth;
    }
 
-   initRatio() {
-     return Math.max(250 / window.innerWidth, 0.20);
-   }
+  initRatio() {
+    return Math.floor(Math.max(250 / window.innerWidth, 0.20) * 100);
+  }
+  initRatioRight() {
+    return 100 - this.initRatio();
+  }
+
 }
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/navigator-view/mdm-navigator-view.module.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/navigator-view/mdm-navigator-view.module.ts
index 30d70e6..c11ea44 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/navigator-view/mdm-navigator-view.module.ts
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/navigator-view/mdm-navigator-view.module.ts
@@ -24,7 +24,6 @@
 import { MDMNavigatorModule } from '../navigator/mdm-navigator.module';
 import { MDMModulesModule } from '../modules/mdm-modules.module';
 import { MDMBasketModule } from '../basket/mdm-basket.module';
-import { SplitPaneModule } from 'ng2-split-pane/lib/ng2-split-pane';
 
 @NgModule({
   imports: [
@@ -32,8 +31,7 @@
     MDMNavigatorViewRoutingModule,
     MDMNavigatorModule,
     MDMModulesModule,
-    MDMBasketModule,
-    SplitPaneModule
+    MDMBasketModule
   ],
   declarations: [
     MDMNavigatorViewComponent
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/navigator/node.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/navigator/node.ts
index 74b58e4..7b11779 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/navigator/node.ts
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/navigator/node.ts
@@ -20,6 +20,10 @@
   value: string;
   unit: string;
   dataType: string;
+  sortIndex: number;
+  readOnly: boolean;
+  mandatory: boolean;
+  description: string;
 }
 
 export class Relation {
@@ -28,6 +32,7 @@
   entityType: string;
   contextType: string;
   ids: string[];
+  parentId: string;
 }
 
 export class Node {
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/assets/i18n/de.json b/org.eclipse.mdm.application/src/main/webapp/src/assets/i18n/de.json
index 01373ee..0ac2c84 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/assets/i18n/de.json
+++ b/org.eclipse.mdm.application/src/main/webapp/src/assets/i18n/de.json
@@ -80,11 +80,16 @@
 			"err-cannot-load-data": "Daten können nicht geladen werden.",
 			"err-cannot-load-scope": "Bereich kann nicht geladen werden.",
 			"status-loading": "Lädt...",
+      "status-saving": "Speichert...",
 			"status-no-descriptive-data-available": "Keine beschriebenden Daten verfügbar.",
 			"status-no-nodes-available": "Keine Knoten verfügbar.",
 			"tblhdr-measured": "Gemessen",
 			"tblhdr-name": "Name",
-			"tblhdr-ordered": "Beauftragt"
+      "tblhdr-ordered": "Beauftragt",
+      "btn-edit": "Bearbeiten",
+      "btn-cancel": "Abbrechen",
+      "btn-save": "Speichern",
+      "input-dateformat": "dd.mm.yy"
 		},
 		"mdm-detail-view": {
 			"cannot-update-node": "Knoten kann nicht aktualisiert werden."
@@ -346,4 +351,4 @@
 			"tension": "Tension: 0 = Linear, 0.4 = Bezierkurve"
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/assets/i18n/en.json b/org.eclipse.mdm.application/src/main/webapp/src/assets/i18n/en.json
index c8ff776..3fc4730 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/assets/i18n/en.json
+++ b/org.eclipse.mdm.application/src/main/webapp/src/assets/i18n/en.json
@@ -75,17 +75,22 @@
 			"err-cannot-load-preference-for-attributes-to-ignore": "Cannot load preference for attributes to ignore.",
 			"err-faulty-preference-for-attributes-to-ignore": "Faulty preference for attributes to ignore."
 		},
-		"mdm-detail-descriptive-data": {
-			"err-cannot-load-context": "Cannot load context.",
-			"err-cannot-load-data": "Cannot load data.",
-			"err-cannot-load-scope": "Cannot load scope.",
-			"status-loading": "Loading...",
-			"status-no-descriptive-data-available": "No descriptive data available.",
-			"status-no-nodes-available": "No nodes available.",
-			"tblhdr-measured": "Measured",
-			"tblhdr-name": "Name",
-			"tblhdr-ordered": "Ordered"
-		},
+    "mdm-detail-descriptive-data": {
+      "err-cannot-load-context": "Cannot load context.",
+      "err-cannot-load-data": "Cannot load data.",
+      "err-cannot-load-scope": "Cannot load scope.",
+      "status-loading": "Loading...",
+      "status-saving": "Saving...",
+      "status-no-descriptive-data-available": "No descriptive data available.",
+      "status-no-nodes-available": "No nodes available.",
+      "tblhdr-measured": "Measured",
+      "tblhdr-name": "Name",
+      "tblhdr-ordered": "Ordered",
+      "btn-edit": "Edit",
+      "btn-cancel": "Cancel",
+      "btn-save": "Save",
+      "input-dateformat": "mm/dd/yy"
+    },
 		"mdm-detail-view": {
 			"cannot-update-node": "Cannot update node."
 		},
@@ -346,4 +351,4 @@
 			"tension": "Line tension: 0 = linear, 0.4 = Bezier curve"
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/styles.css b/org.eclipse.mdm.application/src/main/webapp/src/styles.css
index 9905f4d..0fbd61f 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/styles.css
+++ b/org.eclipse.mdm.application/src/main/webapp/src/styles.css
@@ -165,4 +165,66 @@
 .mdm-link-list > li > a {
   cursor: pointer;
   color: #888;
-}
\ No newline at end of file
+}
+
+/**
+  Define style sheets for the MDM detail component viewer
+  All units in EM as they are scalable
+*/
+.mdm-details-attributes .ui-treetable-table thead > tr > th {
+  position: relative;
+}
+.mdm-details-attributes .ui-treetable-table thead > tr > th .inlinebuttons {
+  position: absolute;
+  right: 0.25em;
+  top: 0.25em;
+}
+.mdm-details-attributes .ui-treetable-table thead > tr > th .inlinebuttons button {
+  margin-left: 0.1em;
+}
+.mdm-details-attributes .ui-treetable-table tbody > tr > td {
+  position: relative;
+}
+.mdm-details-attributes .ui-treetable-table tbody > tr > td .inlinecontent {
+  position: absolute;
+  right: 0.25em;
+  top: 0.25em;
+}
+.mdm-details-attributes .ui-treetable-table tbody td {
+  line-height: 1;
+  padding: 0.15em 0.15em !important;
+}
+.mdm-details-attributes .ui-treetable-table tbody .mdm-component-row {
+  background-color: #e3e3e3;
+}
+
+.mainnavigation {
+  display: block;
+  position: relative;
+}
+.mainnavigation #leftsidenav .navbar {
+  margin-bottom: 0.5em !important;
+}
+.mainnavigation .split {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+  overflow-y: auto;
+  overflow-x: hidden;
+  height: 100%;
+}
+.mainnavigation .gutter {
+  background-color: #eee;
+  background-repeat: no-repeat;
+  background-position: 50%;
+  margin-left: 2px;
+  width: 8px !important;
+}
+.mainnavigation .gutter.gutter-horizontal {
+  background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==');
+}
+.mainnavigation .split,
+.mainnavigation .gutter.gutter-horizontal {
+  display: inline-block;
+  vertical-align: top;
+}
diff --git a/org.eclipse.mdm.application/src/main/webconfig/web.xml b/org.eclipse.mdm.application/src/main/webconfig/web.xml
index 3f38a2a..8745286 100644
--- a/org.eclipse.mdm.application/src/main/webconfig/web.xml
+++ b/org.eclipse.mdm.application/src/main/webconfig/web.xml
@@ -21,6 +21,7 @@
 		</web-resource-collection>
 		<auth-constraint>
 			<role-name>MDM</role-name>
+			<role-name>write-user</role-name>
 		</auth-constraint>
 	</security-constraint>
 
@@ -53,6 +54,10 @@
 		<role-name>MDM</role-name>
 	</security-role>
 
+	<security-role>
+		<role-name>write-user</role-name>
+	</security-role>
+
 	<login-config>
 		<auth-method>FORM</auth-method>
 		<realm-name>MDMRealm</realm-name>
diff --git a/org.eclipse.mdm.businessobjects/build.gradle b/org.eclipse.mdm.businessobjects/build.gradle
index dbb45ff..a85bd54 100644
--- a/org.eclipse.mdm.businessobjects/build.gradle
+++ b/org.eclipse.mdm.businessobjects/build.gradle
@@ -22,7 +22,7 @@
 
 dependencies {
 	compile project(':org.eclipse.mdm.connector')
-	compileOnly 'com.fasterxml.jackson.core:jackson-databind:2.5.1'
+	compile 'com.fasterxml.jackson.core:jackson-databind:2.5.1'
 	compile 'io.vavr:vavr:0.9.1'
 	
 	compile 'com.google.protobuf:protobuf-java:3.2.0'
diff --git a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/MeasurementResource.java b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/MeasurementResource.java
index cb19c16..7285cbf 100644
--- a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/MeasurementResource.java
+++ b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/MeasurementResource.java
@@ -154,6 +154,9 @@
 	 * @return the result of the delegated request as {@link Response}
 	 */
 	@GET
+	@Operation(summary = "Get the complete context data for a Mesurement", description = "Returns the complete context", responses = {
+			@ApiResponse(responseCode = "200", description = "The Measurement context data", content = @Content(schema = @Schema(implementation = ContextResponse.class))),
+			@ApiResponse(responseCode = "500", description = "Error") })
 	@Produces(MediaType.APPLICATION_JSON)
 	@Path("/{" + REQUESTPARAM_ID + "}/contexts")
 	public Response findContext(@PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
@@ -194,6 +197,9 @@
 	 * @return the result of the delegated request as {@link Response}
 	 */
 	@GET
+	@Operation(summary = "Get the UnitUnderTest context data for a Measurment", description = "Returns the complete context", responses = {
+			@ApiResponse(responseCode = "200", description = "The UnitUnderTest context data", content = @Content(schema = @Schema(implementation = ContextResponse.class))),
+			@ApiResponse(responseCode = "500", description = "Error") })
 	@Produces(MediaType.APPLICATION_JSON)
 	@Path("/{" + REQUESTPARAM_ID + "}/contexts/unitundertest")
 	public Response findContextUUT(@PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
@@ -237,6 +243,9 @@
 	 * @return the result of the delegated request as {@link Response}
 	 */
 	@GET
+	@Operation(summary = "Get the TestSequence context data for a Measurement", description = "Returns the TestSequence context data", responses = {
+			@ApiResponse(responseCode = "200", description = "The TestSequence context data", content = @Content(schema = @Schema(implementation = ContextResponse.class))),
+			@ApiResponse(responseCode = "500", description = "Error") })
 	@Produces(MediaType.APPLICATION_JSON)
 	@Path("/{" + REQUESTPARAM_ID + "}/contexts/testsequence")
 	public Response findContextTSQ(@PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
@@ -280,6 +289,9 @@
 	 * @return the result of the delegated request as {@link Response}
 	 */
 	@GET
+	@Operation(summary = "Get the TestEquipment context data for a Measurement", description = "Returns the TestEquipment context data", responses = {
+			@ApiResponse(responseCode = "200", description = "The TestEquipment context data", content = @Content(schema = @Schema(implementation = ContextResponse.class))),
+			@ApiResponse(responseCode = "500", description = "Error") })
 	@Produces(MediaType.APPLICATION_JSON)
 	@Path("/{" + REQUESTPARAM_ID + "}/contexts/testequipment")
 	public Response findContextTEQ(@PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
@@ -323,6 +335,9 @@
 	 * @return the result of the delegated request as {@link Response}
 	 */
 	@GET
+	@Operation(summary = "Get the Sensor context data", description = "Returns the Sensor context data of TestEquipments", responses = {
+			@ApiResponse(responseCode = "200", description = "The Sensor context data", content = @Content(schema = @Schema(implementation = ContextResponse.class))),
+			@ApiResponse(responseCode = "500", description = "Error") })
 	@Produces(MediaType.APPLICATION_JSON)
 	@Path("/{" + REQUESTPARAM_ID + "}/contexts/testequipment/sensors")
 	public Response getContextTEQSensors(@PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
@@ -363,13 +378,14 @@
 	 * @return the created {@link Measurement} as {@link Response}.
 	 */
 	@POST
-	@Operation(summary = "Create a new Measurement",  responses = {
+	@Operation(summary = "Create a new Measurement", responses = {
 			@ApiResponse(description = "The created Measurement", content = @Content(schema = @Schema(implementation = MDMEntityResponse.class))),
 			@ApiResponse(responseCode = "500", description = "Error") })
 	@Produces(MediaType.APPLICATION_JSON)
 	@Consumes(MediaType.APPLICATION_JSON)
 	public Response create(
-			@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName, String body) {
+			@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
+			String body) {
 		Seq<Value<?>> args = entityService
 				.extractRequestBody(body, sourceName, io.vavr.collection.List.of(TestStep.class))
 				.append(V(new ContextRoot[] {}));
@@ -395,7 +411,7 @@
 	@Consumes(MediaType.APPLICATION_JSON)
 	@Path("/{" + REQUESTPARAM_ID + "}")
 	public Response update(
-			@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName, 
+			@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
 			@Parameter(description = "ID of the Measurement", required = true) @PathParam(REQUESTPARAM_ID) String id,
 			String body) {
 		RequestBody requestBody = RequestBody.create(body);
@@ -447,7 +463,7 @@
 	@Path("/{" + REQUESTPARAM_ID + "}/files/{remotePath}")
 	public Response streamFileLink(
 			@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
-			@Parameter(description = "ID of the Measurement containing the file link", required = true) @PathParam(REQUESTPARAM_ID) String id, 
+			@Parameter(description = "ID of the Measurement containing the file link", required = true) @PathParam(REQUESTPARAM_ID) String id,
 			@Parameter(description = "The remote path of the file link whose content is to be retrieved", required = true) @PathParam("remotePath") String remotePath) {
 
 		return entityService.find(V(sourceName), Measurement.class, V(id)).map(fa -> new EntityFileLink(fa, remotePath))
diff --git a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/TestResource.java b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/TestResource.java
index 9c8cbb1..6cb70fa 100644
--- a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/TestResource.java
+++ b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/TestResource.java
@@ -21,6 +21,7 @@
 import java.util.Map;
 import java.util.NoSuchElementException;
 
+import javax.annotation.security.RolesAllowed;
 import javax.ejb.EJB;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -41,6 +42,7 @@
 import org.eclipse.mdm.api.base.model.Environment;
 import org.eclipse.mdm.api.base.model.FileLink;
 import org.eclipse.mdm.api.base.model.Test;
+import org.eclipse.mdm.api.base.model.TestStep;
 import org.eclipse.mdm.api.dflt.model.Classification;
 import org.eclipse.mdm.api.dflt.model.Domain;
 import org.eclipse.mdm.api.dflt.model.Pool;
@@ -48,9 +50,11 @@
 import org.eclipse.mdm.api.dflt.model.TemplateTest;
 import org.eclipse.mdm.api.dflt.model.ValueList;
 import org.eclipse.mdm.businessobjects.control.FileLinkActivity;
+import org.eclipse.mdm.businessobjects.entity.ContextResponse;
 import org.eclipse.mdm.businessobjects.entity.I18NResponse;
 import org.eclipse.mdm.businessobjects.entity.MDMEntityResponse;
 import org.eclipse.mdm.businessobjects.entity.SearchAttributeResponse;
+import org.eclipse.mdm.businessobjects.service.ContextService;
 import org.eclipse.mdm.businessobjects.service.EntityFileLink;
 import org.eclipse.mdm.businessobjects.service.EntityService;
 import org.eclipse.mdm.businessobjects.utils.RequestBody;
@@ -91,6 +95,9 @@
 	private EntityService entityService;
 
 	@EJB
+	private ContextService contextService;
+
+	@EJB
 	private FileLinkActivity fileLinkActivity;
 
 	/**
@@ -261,6 +268,7 @@
 	@Produces(MediaType.APPLICATION_JSON)
 	@Consumes(MediaType.APPLICATION_JSON)
 	@Path("/{" + REQUESTPARAM_ID + "}")
+	@RolesAllowed({ "write-user" })
 	public Response update(
 			@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
 			@Parameter(description = "ID of the Test", required = true) @PathParam(REQUESTPARAM_ID) String id,
@@ -322,4 +330,48 @@
 						efl.getFileLink().getMimeType().toString()).build())
 				.recover(ServiceUtils.ERROR_RESPONSE_SUPPLIER).getOrElse(ServiceUtils.SERVER_ERROR_RESPONSE);
 	}
+
+	/**
+	 * delegates the request to the {@link TestStepService}
+	 *
+	 * @param sourceName name of the source (MDM {@link Environment} name)
+	 * @param id         id of the {@link TestStep}
+	 * @return the result of the delegated request as {@link Response}
+	 */
+	@GET
+	@Operation(summary = "Get the test constant context data for a Test", description = "Returns the test constant context", responses = {
+			@ApiResponse(responseCode = "200", description = "The test constant context data", content = @Content(schema = @Schema(implementation = ContextResponse.class))),
+			@ApiResponse(responseCode = "500", description = "Error") })
+	@Produces(MediaType.APPLICATION_JSON)
+	@Path("/{" + REQUESTPARAM_ID + "}/contexts")
+	public Response findContext(@PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
+			@PathParam(REQUESTPARAM_ID) String id) {
+		return contextService.getTestContext(V(sourceName), V(id), false).map(ServiceUtils::contextMapToJava)
+				.map(ContextResponse::new).map(contextResponse -> ServiceUtils.toResponse(contextResponse, Status.OK))
+				.recover(ServiceUtils.ERROR_RESPONSE_SUPPLIER).getOrElse(ServiceUtils.SERVER_ERROR_RESPONSE);
+	}
+
+	/**
+	 * Updates the context of {@link TestStep} with all parameters set in the given
+	 * JSON body of the request.
+	 *
+	 * @param sourceName name of the source (MDM {@link Environment} name)
+	 * @param id         the identifier of the {@link TestStep} to update.
+	 * @param body       the body of the request containing the attributes to update
+	 * @return the context map of the updated {@link TestStep}
+	 */
+	@PUT
+	@Produces(MediaType.APPLICATION_JSON)
+	@Consumes(MediaType.APPLICATION_JSON)
+	@Path("/{" + REQUESTPARAM_ID + "}/contexts")
+	@RolesAllowed({ "write-user" })
+	public Response updateContext(@PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
+			@PathParam(REQUESTPARAM_ID) String id, String body) {
+
+		return entityService.find(V(sourceName), TestStep.class, V(id))
+				.map(testStep -> contextService.updateContext(body, testStep)).map(ContextResponse::new)
+				.map(contextResponse -> ServiceUtils.toResponse(contextResponse, Status.OK))
+				.recover(ServiceUtils.ERROR_RESPONSE_SUPPLIER).getOrElse(ServiceUtils.SERVER_ERROR_RESPONSE);
+	}
+
 }
diff --git a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/TestStepResource.java b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/TestStepResource.java
index 247f946..1ffdc84 100644
--- a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/TestStepResource.java
+++ b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/TestStepResource.java
@@ -18,6 +18,7 @@
 import static org.eclipse.mdm.businessobjects.boundary.ResourceConstants.REQUESTPARAM_SOURCENAME;
 import static org.eclipse.mdm.businessobjects.service.EntityService.V;
 
+import javax.annotation.security.RolesAllowed;
 import javax.ejb.EJB;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -154,6 +155,9 @@
 	 * @return the result of the delegated request as {@link Response}
 	 */
 	@GET
+	@Operation(summary = "Get the complete context data for a TestStep", description = "Returns the complete context", responses = {
+			@ApiResponse(responseCode = "200", description = "The TestStep context data", content = @Content(schema = @Schema(implementation = ContextResponse.class))),
+			@ApiResponse(responseCode = "500", description = "Error") })
 	@Produces(MediaType.APPLICATION_JSON)
 	@Path("/{" + REQUESTPARAM_ID + "}/contexts")
 	public Response findContext(
@@ -169,7 +173,7 @@
 	 * JSON body of the request.
 	 * 
 	 * @param sourceName name of the source (MDM {@link Environment} name)
-	 * @param id         the identifier of the {@link TestStepValue} to update.
+	 * @param id         the identifier of the {@link TestStep} to update.
 	 * @param body       the body of the request containing the attributes to update
 	 * @return the context map of the updated {@link TestStep}
 	 */
@@ -177,6 +181,7 @@
 	@Produces(MediaType.APPLICATION_JSON)
 	@Consumes(MediaType.APPLICATION_JSON)
 	@Path("/{" + REQUESTPARAM_ID + "}/contexts")
+	@RolesAllowed({ "write-user" })
 	public Response updateContext(@PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
 			@PathParam(REQUESTPARAM_ID) String id, String body) {
 
@@ -194,6 +199,9 @@
 	 * @return the result of the delegated request as {@link Response}
 	 */
 	@GET
+	@Operation(summary = "Get the UnitUnderTest context data for a TestStep", description = "Returns the complete context", responses = {
+			@ApiResponse(responseCode = "200", description = "The UnitUnderTest context data", content = @Content(schema = @Schema(implementation = ContextResponse.class))),
+			@ApiResponse(responseCode = "500", description = "Error") })
 	@Produces(MediaType.APPLICATION_JSON)
 	@Path("/{" + REQUESTPARAM_ID + "}/contexts/unitundertest")
 	public Response findContextUUT(@PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
@@ -210,7 +218,7 @@
 	 * with all parameters set in the given JSON body of the request.
 	 * 
 	 * @param sourceName name of the source (MDM {@link Environment} name)
-	 * @param id         the identifier of the {@link TestStepValue} to update.
+	 * @param id         the identifier of the {@link TestStep} to update.
 	 * @param body       the body of the request containing the attributes to update
 	 * @return the context map of {@link ContextType} UNITUNDERTEST of the updated
 	 *         {@link TestStep}
@@ -219,6 +227,7 @@
 	@Produces(MediaType.APPLICATION_JSON)
 	@Consumes(MediaType.APPLICATION_JSON)
 	@Path("/{" + REQUESTPARAM_ID + "}/contexts/unitundertest")
+	@RolesAllowed({ "write-user" })
 	public Response updateContextUUT(@PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
 			@PathParam(REQUESTPARAM_ID) String id, String body) {
 
@@ -236,6 +245,9 @@
 	 * @return the result of the delegated request as {@link Response}
 	 */
 	@GET
+	@Operation(summary = "Get the TestSequence context data for a TestStep", description = "Returns the TestSequence context data", responses = {
+			@ApiResponse(responseCode = "200", description = "The TestSequence context data", content = @Content(schema = @Schema(implementation = ContextResponse.class))),
+			@ApiResponse(responseCode = "500", description = "Error") })
 	@Produces(MediaType.APPLICATION_JSON)
 	@Path("/{" + REQUESTPARAM_ID + "}/contexts/testsequence")
 	public Response findContextTSQ(@PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
@@ -252,7 +264,7 @@
 	 * with all parameters set in the given JSON body of the request.
 	 * 
 	 * @param sourceName name of the source (MDM {@link Environment} name)
-	 * @param id         the identifier of the {@link TestStepValue} to update.
+	 * @param id         the identifier of the {@link TestStep} to update.
 	 * @param body       the body of the request containing the attributes to update
 	 * @return the context map of {@link ContextType} TESTSEQUENCE of the updated
 	 *         {@link TestStep}
@@ -261,6 +273,7 @@
 	@Produces(MediaType.APPLICATION_JSON)
 	@Consumes(MediaType.APPLICATION_JSON)
 	@Path("/{" + REQUESTPARAM_ID + "}/contexts/testsequence")
+	@RolesAllowed({ "write-user" })
 	public Response updateContextTSQ(@PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
 			@PathParam(REQUESTPARAM_ID) String id, String body) {
 
@@ -278,6 +291,9 @@
 	 * @return the result of the delegated request as {@link Response}
 	 */
 	@GET
+	@Operation(summary = "Get the TestEquipment context data for a TestStep", description = "Returns the TestEquipment context data", responses = {
+			@ApiResponse(responseCode = "200", description = "The TestEquipment context data", content = @Content(schema = @Schema(implementation = ContextResponse.class))),
+			@ApiResponse(responseCode = "500", description = "Error") })
 	@Produces(MediaType.APPLICATION_JSON)
 	@Path("/{" + REQUESTPARAM_ID + "}/contexts/testequipment")
 	public Response findContextTEQ(@PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
@@ -294,7 +310,7 @@
 	 * with all parameters set in the given JSON body of the request.
 	 * 
 	 * @param sourceName name of the source (MDM {@link Environment} name)
-	 * @param id         the identifier of the {@link TestStepValue} to update.
+	 * @param id         the identifier of the {@link TestStep} to update.
 	 * @param body       the body of the request containing the attributes to update
 	 * @return the context map of {@link ContextType} TESTEQUIPMENT of the updated
 	 *         {@link TestStep}
@@ -303,6 +319,7 @@
 	@Produces(MediaType.APPLICATION_JSON)
 	@Consumes(MediaType.APPLICATION_JSON)
 	@Path("/{" + REQUESTPARAM_ID + "}/contexts/testequipment")
+	@RolesAllowed({ "write-user" })
 	public Response updateContextTEQ(@PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
 			@PathParam(REQUESTPARAM_ID) String id, String body) {
 
@@ -320,6 +337,9 @@
 	 * @return the result of the delegated request as {@link Response}
 	 */
 	@GET
+	@Operation(summary = "Get the Sensor context data", description = "Returns the Sensor context data of TestEquipments", responses = {
+			@ApiResponse(responseCode = "200", description = "The Sensor context data", content = @Content(schema = @Schema(implementation = ContextResponse.class))),
+			@ApiResponse(responseCode = "500", description = "Error") })
 	@Produces(MediaType.APPLICATION_JSON)
 	@Path("/{" + REQUESTPARAM_ID + "}/contexts/testequipment/sensors")
 	public Response getContextTEQSensors(@PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
@@ -382,7 +402,7 @@
 	 * of the request.
 	 * 
 	 * @param sourceName name of the source (MDM {@link Environment} name)
-	 * @param id         the identifier of the {@link TestStepValue} to update.
+	 * @param id         the identifier of the {@link TestStep} to update.
 	 * @param body       the body of the request containing the attributes to update
 	 * @return the updated {@link TestStep}
 	 */
@@ -393,6 +413,7 @@
 	@Produces(MediaType.APPLICATION_JSON)
 	@Consumes(MediaType.APPLICATION_JSON)
 	@Path("/{" + REQUESTPARAM_ID + "}")
+	@RolesAllowed({ "write-user" })
 	public Response update(
 			@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName,
 			@Parameter(description = "ID of the TestStep", required = true) @PathParam(REQUESTPARAM_ID) String id,
diff --git a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/UserResource.java b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/UserResource.java
new file mode 100644
index 0000000..26737fb
--- /dev/null
+++ b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/UserResource.java
@@ -0,0 +1,74 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.businessobjects.boundary;
+
+import org.eclipse.mdm.businessobjects.control.MDMEntityAccessException;
+import org.eclipse.mdm.businessobjects.entity.User;
+
+import javax.annotation.security.PermitAll;
+import javax.security.auth.Subject;
+import javax.security.jacc.PolicyContext;
+import javax.security.jacc.PolicyContextException;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.*;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+
+@Path("/user")
+@PermitAll
+public class UserResource {
+
+	@Context
+	public SecurityContext securityContext;
+
+	@GET
+	@Path("/current")
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response currentUser() {
+		User user = new User();
+		user.setUsername(securityContext.getUserPrincipal().getName());
+		user.setRoles(getRolesInGlassfish());
+		return Response.ok(user).build();
+	}
+
+	/**
+	 * Getting the roles of a user is heavily dependent on the used application
+	 * server. This method will only work with Glassfish. (It was tested with
+	 * Glassfish 4.1.2). The following blog entry gives a good overview of the
+	 * issues concerning JAAS.
+	 *
+	 * @see https://arjan-tijms.omnifaces.org/2014/02/jaas-in-java-ee-is-not-universal.html
+	 * @return list of rules of the logged in user.
+	 */
+	private static List<String> getRolesInGlassfish() {
+		List<String> list = new ArrayList<>();
+
+		try {
+			Subject subject = (Subject) PolicyContext.getContext("javax.security.auth.Subject.container");
+			for (Principal principal : subject.getPrincipals()) {
+				if ("org.glassfish.security.common.Group".equals(principal.getClass().getName())) {
+					Principal role = (Principal) principal;
+					list.add(role.getName());
+				}
+			}
+		} catch (PolicyContextException e) {
+			throw new MDMEntityAccessException("Could not load roles for user!", e);
+		}
+		return list;
+	}
+}
diff --git a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/ValuesResource.java b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/ValuesResource.java
index 2348b03..cff97c3 100644
--- a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/ValuesResource.java
+++ b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/boundary/ValuesResource.java
@@ -32,6 +32,7 @@
 import io.swagger.v3.oas.annotations.Parameter;

 import io.swagger.v3.oas.annotations.media.Content;

 import io.swagger.v3.oas.annotations.media.Schema;

+import io.swagger.v3.oas.annotations.parameters.RequestBody;

 import io.swagger.v3.oas.annotations.responses.ApiResponse;

 import io.swagger.v3.oas.annotations.tags.Tag;

 

@@ -49,9 +50,9 @@
 	@Operation(summary = "Read measurement data", description = "Read measurement specified by a ReadRequest.", responses = {

 			@ApiResponse(description = "A list with MeasuredValues. Each MeasuredValues represents the values of a Channel.", content = @Content(schema = @Schema(implementation = Mdm.MeasuredValuesList.class))),

 			@ApiResponse(responseCode = "400", description = "Error") })

-	public Response find(

+	public Response read(

 			@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName,

-			@Parameter(description = "ReadRequest specifying the Channels and the portion of the Channel's data to read.", required = true, content = @Content(schema = @Schema(implementation = Mdm.ReadRequest.class))) Mdm.ReadRequest protoReadRequest) {

+			@RequestBody(description = "ReadRequest specifying the Channels and the portion of the Channel's data to read.", required = true, content = @Content(schema = @Schema(implementation = Mdm.ReadRequest.class))) Mdm.ReadRequest protoReadRequest) {

 

 		return Response.ok(valuesService.load(sourceName, protoReadRequest)).build();

 	}

@@ -61,9 +62,9 @@
 	@Operation(summary = "Write measurement data", description = "Write measurement data for the specified ChannelGroup and Channels. Both ChannelGroup and Channels must exist.", responses = {

 			@ApiResponse(description = "An empty response"),

 			@ApiResponse(responseCode = "400", description = "Error") })

-	public Response find(

+	public Response write(

 			@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName,

-			Mdm.WriteRequestList protoWriteRequestList) {

+			@RequestBody(description = "WriteRequestList specifying the Channels and measurement data to write.", required = true, content = @Content(schema = @Schema(implementation = Mdm.WriteRequestList.class))) Mdm.WriteRequestList protoWriteRequestList) {

 

 		valuesService.write(sourceName, protoWriteRequestList);

 

@@ -77,7 +78,7 @@
 			@ApiResponse(responseCode = "400", description = "Error") })

 	public Response preview(

 			@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName,

-			@Parameter(description = "PreviewRequest specifying the Channels and number of chunks to read.", required = true, content = @Content(schema = @Schema(implementation = Mdm.PreviewRequest.class))) Mdm.PreviewRequest previewRequest) {

+			@RequestBody(description = "PreviewRequest specifying the Channels and number of chunks to read.", required = true, content = @Content(schema = @Schema(implementation = Mdm.PreviewRequest.class))) Mdm.PreviewRequest previewRequest) {

 

 		return Response.ok(valuesService.preview(sourceName, previewRequest)).build();

 	}

diff --git a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/ContextCollection.java b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/ContextCollection.java
index 23c8eee..3288721 100644
--- a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/ContextCollection.java
+++ b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/ContextCollection.java
@@ -15,6 +15,8 @@
 package org.eclipse.mdm.businessobjects.entity;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -32,16 +34,16 @@
 public class ContextCollection {
 
 	// consistent naming to ContextActivity.CONTEXT_GROUP_MEASURED
-	public Map<ContextType, List<MDMEntity>> measured = new HashMap<>();
+	public Map<ContextType, List<MDMContextEntity>> measured = new HashMap<>();
 	// consistent naming to ContextActivity.CONTEXT_GROUP_ORDERED
-	public Map<ContextType, List<MDMEntity>> ordered = new HashMap<>();
+	public Map<ContextType, List<MDMContextEntity>> ordered = new HashMap<>();
 
 	/**
 	 * set the measured context data map
 	 * 
 	 * @param contextMap the measured context data map
 	 */
-	public void setMeasuredContext(Map<ContextType, ContextRoot> contextMap) {
+	public void setMeasured(Map<ContextType, ContextRoot> contextMap) {
 
 		for (java.util.Map.Entry<ContextType, ContextRoot> setEntry : contextMap.entrySet()) {
 
@@ -51,9 +53,13 @@
 			this.measured.put(contextType, new ArrayList<>());
 
 			for (ContextComponent contextComponent : contextRoot.getContextComponents()) {
-				MDMEntity entity = new MDMEntity(contextComponent);
+				MDMContextEntity entity = new MDMContextEntity(contextComponent);
 				this.measured.get(contextType).add(entity);
 			}
+
+			// sort by SortIndex
+			Collections.sort(this.measured.get(contextType), Comparator.comparing(MDMContextEntity::getSortIndex));
+
 		}
 	}
 
@@ -62,7 +68,7 @@
 	 * 
 	 * @param contextMap the ordered context data map
 	 */
-	public void setOrderedContext(Map<ContextType, ContextRoot> contextMap) {
+	public void setOrdered(Map<ContextType, ContextRoot> contextMap) {
 
 		for (java.util.Map.Entry<ContextType, ContextRoot> setEntry : contextMap.entrySet()) {
 
@@ -72,9 +78,12 @@
 			this.ordered.put(contextType, new ArrayList<>());
 
 			for (ContextComponent contextComponent : contextRoot.getContextComponents()) {
-				MDMEntity entity = new MDMEntity(contextComponent);
+				MDMContextEntity entity = new MDMContextEntity(contextComponent);
 				this.ordered.get(contextType).add(entity);
 			}
+
+			// sort by SortIndex
+			Collections.sort(this.ordered.get(contextType), Comparator.comparing(MDMContextEntity::getSortIndex));
 		}
 	}
 
diff --git a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/ContextResponse.java b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/ContextResponse.java
index bbcbc11..6c1a843 100644
--- a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/ContextResponse.java
+++ b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/ContextResponse.java
@@ -43,8 +43,8 @@
 	public ContextResponse(Map<String, Map<ContextType, ContextRoot>> contextMap) {
 		this.data = new ArrayList<>();
 		ContextCollection contextData = new ContextCollection();
-		contextData.setOrderedContext(contextMap.get(ContextActivity.CONTEXT_GROUP_ORDERED));
-		contextData.setMeasuredContext(contextMap.get(ContextActivity.CONTEXT_GROUP_MEASURED));
+		contextData.setOrdered(contextMap.get(ContextActivity.CONTEXT_GROUP_ORDERED));
+		contextData.setMeasured(contextMap.get(ContextActivity.CONTEXT_GROUP_MEASURED));
 		this.data.add(contextData);
 	}
 
@@ -57,8 +57,8 @@
 	public ContextResponse(DescribableContexts context) {
 		this.data = new ArrayList<>();
 		ContextCollection contextData = new ContextCollection();
-		contextData.setOrderedContext(context.getOrderedContext());
-		contextData.setMeasuredContext(context.getMeasuredContext());
+		contextData.setOrdered(context.getOrderedContext());
+		contextData.setMeasured(context.getMeasuredContext());
 		this.data.add(contextData);
 	}
 
diff --git a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMAttribute.java b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMAttribute.java
index 41313a7..599806b 100644
--- a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMAttribute.java
+++ b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMAttribute.java
@@ -49,6 +49,18 @@
 		this.dataType = dataType;
 	}
 
+	/**
+	 * Copy constructor
+	 * 
+	 * @param attribute attribute to copy
+	 */
+	public MDMAttribute(MDMAttribute attribute) {
+		this.name = attribute.getName();
+		this.value = attribute.getValue();
+		this.unit = attribute.getUnit();
+		this.dataType = attribute.getDataType();
+	}
+
 	@Schema(description = "name of the attribute")
 	public String getName() {
 		return this.name;
diff --git a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMContextAttribute.java b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMContextAttribute.java
new file mode 100644
index 0000000..cc0d579
--- /dev/null
+++ b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMContextAttribute.java
@@ -0,0 +1,78 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.businessobjects.entity;
+
+/**
+ * Attribute (Entity for attribute information)
+ *
+ * @author Juergen Kleck, Peak Solution GmbH
+ *
+ */
+public class MDMContextAttribute extends MDMAttribute {
+
+	/** The sort index of the template */
+	private final Integer sortIndex;
+	/** boolean flag if this attribute is readonly or writeable in edit mode */
+	private final Boolean readOnly;
+	/** boolean flag if this attribute is optional in edit mode */
+	private final Boolean optional;
+	/** description text of this attribute */
+	private final String description;
+
+	/**
+	 * Constructor
+	 *
+	 * @param name      name of the attribute value
+	 * @param value     value of the attribute value
+	 * @param unit      unit of the attribute value
+	 * @param dataType  data type of the attribute value
+	 * @param sortIndex optional sort index of the attribute value
+	 * @param readOnly  optional flag if it is readonly in edit mode
+	 * @param optional  optional flag if it is optinal in edit mode
+	 */
+	public MDMContextAttribute(String name, Object value, String unit, String dataType, Integer sortIndex,
+			Boolean readOnly, Boolean optional, String description) {
+		super(name, value, unit, dataType);
+		this.sortIndex = sortIndex;
+		this.readOnly = readOnly;
+		this.optional = optional;
+		this.description = description;
+	}
+
+	public MDMContextAttribute(MDMAttribute attribute, Integer sortIndex, Boolean readOnly, Boolean optinal,
+			String description) {
+		super(attribute);
+		this.sortIndex = sortIndex;
+		this.readOnly = readOnly;
+		this.optional = optinal;
+		this.description = description;
+	}
+
+	public Integer getSortIndex() {
+		return sortIndex;
+	}
+
+	public Boolean getReadOnly() {
+		return readOnly;
+	}
+
+	public Boolean isOptional() {
+		return optional;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+}
diff --git a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMContextEntity.java b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMContextEntity.java
new file mode 100644
index 0000000..2f0fe97
--- /dev/null
+++ b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMContextEntity.java
@@ -0,0 +1,166 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.businessobjects.entity;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.model.BaseEntity;
+import org.eclipse.mdm.api.base.model.ContextComponent;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Sortable;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.dflt.model.TemplateAttribute;
+import org.eclipse.mdm.api.dflt.model.TemplateComponent;
+
+/**
+ * MDMEntity (Entity for a business object (contains a list of
+ * {@link MDMContextAttribute}s)
+ *
+ * @author Juergen Kleck, Peak Solution GmbH
+ */
+public class MDMContextEntity extends MDMEntity {
+
+	/**
+	 * sort index of the MDM business object
+	 */
+	private final Integer sortIndex;
+	/**
+	 * list of attribute to transfer
+	 */
+	private List<MDMContextAttribute> attributes;
+	/**
+	 * list of relations to transfer
+	 */
+	private List<MDMContextRelation> relations;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param entity the business object
+	 */
+	public MDMContextEntity(Entity entity) {
+		super(entity);
+		// special handling for context component
+		if (entity instanceof ContextComponent) {
+			TemplateComponent tplCmp = TemplateComponent.of((ContextComponent) entity).get();
+			this.sortIndex = tplCmp.getSortIndex();
+			this.attributes = convertAttributeValues(entity.getValues(), tplCmp.getTemplateAttributes());
+			this.relations = convertRelations(entity, tplCmp);
+		} else {
+			this.sortIndex = 0;
+			this.attributes = convertAttributeValues(entity.getValues(), null);
+			this.relations = convertRelations(entity, null);
+		}
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param name       Name of the Entity
+	 * @param id         ID of the Entity
+	 * @param type       Type of the Entity
+	 * @param sourceType Source type of the Entity
+	 * @param sourceName Source name of the Entity
+	 * @param attributes Attributes of the Entity
+	 */
+	public MDMContextEntity(String name, String id, String type, String sourceType, String sourceName,
+			List<MDMContextAttribute> attributes) {
+		super(name, id, type, sourceType, sourceName, Collections.emptyList());
+		this.sortIndex = 0;
+		if (attributes != null) {
+			this.attributes = new ArrayList<>(attributes);
+		} else {
+			this.attributes = new ArrayList<>();
+		}
+		this.relations = new ArrayList<>();
+	}
+
+	public Integer getSortIndex() {
+		return sortIndex;
+	}
+
+	public List<MDMContextAttribute> getAttributes() {
+		return Collections.unmodifiableList(this.attributes);
+	}
+
+	public List<MDMContextRelation> getRelations() {
+		return Collections.unmodifiableList(this.relations);
+	}
+
+	/**
+	 * converts the MDM business object values to string values
+	 *
+	 * @param values        values of a MDM business object
+	 * @param tplAttributes optional list of template attributes
+	 * @return list with converted attribute values
+	 */
+	private List<MDMContextAttribute> convertAttributeValues(Map<String, Value> values,
+			List<TemplateAttribute> tplAttributes) {
+
+		List<MDMContextAttribute> listAttrs = new ArrayList<>();
+		for (MDMAttribute attr : super.convertAttributeValues(values)) {
+			TemplateAttribute tplAttr = null;
+
+			if (tplAttributes != null && !tplAttributes.isEmpty()) {
+				tplAttr = tplAttributes.stream().filter(tpl -> tpl.getName().equals(attr.getName())).findFirst()
+						.orElse(null);
+			}
+
+			listAttrs.add(toContextAttribute(attr, tplAttr));
+		}
+
+		// clear unneeded elements
+		listAttrs.removeIf(attr -> attr.getName().equals(BaseEntity.ATTR_NAME)
+				|| attr.getName().equals(BaseEntity.ATTR_MIMETYPE) || attr.getName().equals(Sortable.ATTR_SORT_INDEX));
+
+		// pre-sort attributes by sort index
+		Collections.sort(listAttrs, Comparator.comparing(MDMContextAttribute::getSortIndex));
+		return listAttrs;
+	}
+
+	private MDMContextAttribute toContextAttribute(MDMAttribute attr, TemplateAttribute tplAttr) {
+		Integer sortIndex = null;
+		Boolean optional = null;
+		Boolean readOnly = null;
+		String description = null;
+		if (tplAttr != null) {
+			sortIndex = tplAttr.getCatalogAttribute().getSortIndex();
+			description = tplAttr.getCatalogAttribute().getDescription();
+			optional = (Boolean) tplAttr.isOptional();
+			readOnly = (Boolean) tplAttr.isValueReadOnly();
+		}
+		return new MDMContextAttribute(attr, sortIndex, readOnly, optional, description);
+	}
+
+	/**
+	 * Converts all relations to MDMContextRelations. The potential ContextType of
+	 * the children is assumed to be the parent's one.
+	 *
+	 * @param entity to get {@link MDMContextRelation}s for
+	 * @return a list of {@link MDMContextRelation}s
+	 */
+	private List<MDMContextRelation> convertRelations(Entity entity, TemplateComponent tplCmp) {
+
+		String parentId = tplCmp.getParentTemplateComponent().map(p -> p.getID()).orElse(null);
+
+		return convertRelations(entity).stream().map(m -> new MDMContextRelation(m, parentId))
+				.collect(Collectors.toList());
+	}
+}
diff --git a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMContextRelation.java b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMContextRelation.java
new file mode 100644
index 0000000..2d37981
--- /dev/null
+++ b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMContextRelation.java
@@ -0,0 +1,68 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.businessobjects.entity;
+
+import java.util.List;
+
+import org.eclipse.mdm.api.base.model.ContextType;
+
+/**
+ * Relation (Entity for relation information)
+ *
+ * @author Juergen Kleck, Peak Solution GmbH
+ *
+ */
+public class MDMContextRelation extends MDMRelation {
+
+	private String parentId;
+
+	/**
+	 * Default constructor used for entity deserialization
+	 */
+	public MDMContextRelation() {
+
+	}
+
+	/**
+	 * Constructor
+	 *
+	 * @param name        name of the relation
+	 * @param type        type of the relation
+	 * @param entityType  type of the related entity
+	 * @param contextType ContextType of the entity if the entityType has one
+	 * @param ids         ids of the related entities
+	 * @param parentId    the parent template id
+	 */
+	public MDMContextRelation(String name, RelationType type, String entityType, ContextType contextType,
+			List<String> ids, String parentId) {
+		super(name, type, entityType, contextType, ids);
+		this.parentId = parentId;
+	}
+
+	/**
+	 * Constructor
+	 *
+	 * @param relation MDMRelation
+	 * @param parentId parentId
+	 */
+	public MDMContextRelation(MDMRelation relation, String parentId) {
+		super(relation);
+		this.parentId = parentId;
+	}
+
+	public String getParentId() {
+		return parentId;
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMEntity.java b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMEntity.java
index 2de08d3..84ec915 100644
--- a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMEntity.java
+++ b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMEntity.java
@@ -28,41 +28,51 @@
 import org.eclipse.mdm.businessobjects.utils.Serializer;
 import org.eclipse.mdm.businessobjects.utils.ServiceUtils;
 
-import io.vavr.collection.HashMap;
-
 import io.swagger.v3.oas.annotations.media.Schema;
+import io.vavr.collection.HashMap;
 
 /**
  * MDMEntity (Entity for a business object (contains a list of
  * {@link MDMAttribute}s)
- * 
- * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
  *
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
  */
 @Schema(description = "Representation of a MDM entity")
 public class MDMEntity {
 
-	/** name of the MDM business object */
+	/**
+	 * name of the MDM business object
+	 */
 	private final String name;
-	/** id of the MDM business object */
+	/**
+	 * id of the MDM business object
+	 */
 	private final String id;
-	/** type as String of the MDM business object (e.g. TestStep) */
+	/**
+	 * type as String of the MDM business object (e.g. TestStep)
+	 */
 	private final String type;
-	/** source type name of the business object at the data source */
+	/**
+	 * source type name of the business object at the data source
+	 */
 	private final String sourceType;
-	/** source name (e.g. MDM Environment name) */
+	/**
+	 * source name (e.g. MDM Environment name)
+	 */
 	private final String sourceName;
-	/** list of attribute to transfer */
+	/**
+	 * list of attribute to transfer
+	 */
 	private List<MDMAttribute> attributes;
 
-	/** list of relations to transfer */
+	/**
+	 * list of relations to transfer
+	 */
 	private List<MDMRelation> relations;
 
-	private String status;
-
 	/**
 	 * Constructor.
-	 * 
+	 *
 	 * @param entity the business object
 	 */
 	public MDMEntity(Entity entity) {
@@ -77,7 +87,7 @@
 
 	/**
 	 * Constructor.
-	 * 
+	 *
 	 * @param name       Name of the Entity
 	 * @param id         ID of the Entity
 	 * @param type       Type of the Entity
@@ -87,18 +97,12 @@
 	 */
 	public MDMEntity(String name, String id, String type, String sourceType, String sourceName,
 			List<MDMAttribute> attributes) {
-		this.name = name;
-		this.id = id;
-		this.type = type;
-		this.sourceType = sourceType;
-		this.sourceName = sourceName;
-		this.attributes = new ArrayList<>(attributes);
-		this.relations = new ArrayList<>();
+		this(name, id, type, sourceType, sourceName, attributes, Collections.emptyList());
 	}
 
 	/**
 	 * Constructor.
-	 * 
+	 *
 	 * @param name       Name of the Entity
 	 * @param id         ID of the Entity
 	 * @param type       Type of the Entity
@@ -108,14 +112,22 @@
 	 * @param relations  Relations of the Entity
 	 */
 	public MDMEntity(String name, String id, String type, String sourceType, String sourceName,
-			List<MDMAttribute> attributes, List<MDMRelation> relations) {
+			List<MDMAttribute> attributes, List<? extends MDMRelation> relations) {
 		this.name = name;
 		this.id = id;
 		this.type = type;
 		this.sourceType = sourceType;
 		this.sourceName = sourceName;
-		this.attributes = new ArrayList<>(attributes);
-		this.relations = new ArrayList<>(relations);
+		if (attributes != null) {
+			this.attributes = new ArrayList<>(attributes);
+		} else {
+			this.attributes = new ArrayList<>();
+		}
+		if (relations != null) {
+			this.relations = new ArrayList<>(relations);
+		} else {
+			this.relations = new ArrayList<>();
+		}
 	}
 
 	public String getName() {
@@ -138,21 +150,21 @@
 		return this.sourceName;
 	}
 
-	public List<MDMAttribute> getAttributes() {
+	public List<? extends MDMAttribute> getAttributes() {
 		return Collections.unmodifiableList(this.attributes);
 	}
 
-	public List<MDMRelation> getRelations() {
+	public List<? extends MDMRelation> getRelations() {
 		return Collections.unmodifiableList(this.relations);
 	}
 
 	/**
 	 * converts the MDM business object values to string values
-	 * 
+	 *
 	 * @param values values of a MDM business object
 	 * @return list with converted attribute values
 	 */
-	private List<MDMAttribute> convertAttributeValues(Map<String, Value> values) {
+	protected List<MDMAttribute> convertAttributeValues(Map<String, Value> values) {
 		List<MDMAttribute> listAttrs = new ArrayList<>();
 		Set<java.util.Map.Entry<String, Value>> set = values.entrySet();
 
@@ -180,12 +192,12 @@
 
 	/**
 	 * converts a single type MDM business object value to a attribute
-	 * 
+	 *
 	 * @param name        name of the attribute value
 	 * @param singleValue single MDM business object value
 	 * @return the converted attribute value
 	 */
-	private MDMAttribute singleType2Attribute(String name, Value singleValue) {
+	protected MDMAttribute singleType2Attribute(String name, Value singleValue) {
 		Object value = Serializer.serializeValue(singleValue);
 		String unit = singleValue.getUnit();
 		String dt = singleValue.getValueType().toString();
@@ -194,12 +206,12 @@
 
 	/**
 	 * converts a sequence type MDM business object value to a attribute
-	 * 
+	 *
 	 * @param name          name of the attribute value
 	 * @param sequenceValue sequence MDM business object value
 	 * @return the converted attribute value
 	 */
-	private MDMAttribute sequenceType2Attribute(String name, Value sequenceValue) {
+	protected MDMAttribute sequenceType2Attribute(String name, Value sequenceValue) {
 
 		if (sequenceValue.getValueType().isStringSequence()) {
 			return stringSeq2Attribute(name, sequenceValue);
@@ -217,12 +229,12 @@
 	/**
 	 * converts a string sequence MDM business object value to a attribute The
 	 * result is a separated string (separator: ';')
-	 * 
+	 *
 	 * @param name  name of the attribute value
 	 * @param value string sequence MDM business object value
 	 * @return the converted attribute value
 	 */
-	private MDMAttribute stringSeq2Attribute(String name, Value value) {
+	protected MDMAttribute stringSeq2Attribute(String name, Value value) {
 		String[] stringSeq = value.extract();
 		StringBuffer sb = new StringBuffer();
 
@@ -239,12 +251,12 @@
 	/**
 	 * Converts all relations to MDMRelations. The potential ContextType of the
 	 * children is assumed to be the parent's one.
-	 * 
+	 *
 	 * @param entity to get
 	 *               {@link org.eclipse.mdm.businessobjects.entity.MDMRelation}s for
 	 * @return a list of {@link org.eclipse.mdm.businessobjects.entity.MDMRelation}s
 	 */
-	private List<MDMRelation> convertRelations(Entity entity) {
+	protected List<MDMRelation> convertRelations(Entity entity) {
 		// write out children
 		Core core = ServiceUtils.getCore(entity);
 		// get children hash (type is key)
diff --git a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMRelation.java b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMRelation.java
index ea5b84e..d30b4d1 100644
--- a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMRelation.java
+++ b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/MDMRelation.java
@@ -65,6 +65,19 @@
 		this.ids = ids;
 	}
 
+	/**
+	 * Copy constructor
+	 * 
+	 * @param relation relation to copy
+	 */
+	public MDMRelation(MDMRelation relation) {
+		this.name = relation.getName();
+		this.type = relation.getType();
+		this.entityType = relation.getEntityType();
+		this.contextType = relation.getContextType();
+		this.ids = relation.getIds();
+	}
+
 	public String getName() {
 		return this.name;
 	}
diff --git a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/User.java b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/User.java
new file mode 100644
index 0000000..90fcb81
--- /dev/null
+++ b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/entity/User.java
@@ -0,0 +1,35 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.businessobjects.entity;
+
+import java.util.List;
+
+public class User {
+	private String username;
+	private List<String> roles;
+	
+	public String getUsername() {
+		return username;
+	}
+	public void setUsername(String username) {
+		this.username = username;
+	}
+	public List<String> getRoles() {
+		return roles;
+	}
+	public void setRoles(List<String> roles) {
+		this.roles = roles;
+	}
+}
diff --git a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/service/ContextService.java b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/service/ContextService.java
index e6e5aa2..af26786 100644
--- a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/service/ContextService.java
+++ b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/service/ContextService.java
@@ -17,6 +17,7 @@
 import static org.eclipse.mdm.businessobjects.control.ContextActivity.CONTEXT_GROUP_MEASURED;
 import static org.eclipse.mdm.businessobjects.control.ContextActivity.CONTEXT_GROUP_ORDERED;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.NoSuchElementException;
@@ -34,15 +35,17 @@
 import org.eclipse.mdm.api.base.model.Entity;
 import org.eclipse.mdm.api.base.model.Environment;
 import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.Test;
 import org.eclipse.mdm.api.base.model.TestStep;
 import org.eclipse.mdm.api.dflt.EntityManager;
 import org.eclipse.mdm.api.dflt.model.EntityFactory;
+import org.eclipse.mdm.api.dflt.model.TemplateComponent;
 import org.eclipse.mdm.api.dflt.model.TemplateRoot;
 import org.eclipse.mdm.api.dflt.model.TemplateTestStep;
 import org.eclipse.mdm.businessobjects.control.ContextActivity;
 import org.eclipse.mdm.businessobjects.control.MDMEntityAccessException;
-import org.eclipse.mdm.businessobjects.entity.MDMAttribute;
-import org.eclipse.mdm.businessobjects.entity.MDMEntity;
+import org.eclipse.mdm.businessobjects.entity.MDMContextAttribute;
+import org.eclipse.mdm.businessobjects.entity.MDMContextEntity;
 import org.eclipse.mdm.businessobjects.utils.RequestBody;
 import org.eclipse.mdm.businessobjects.utils.Serializer;
 import org.eclipse.mdm.businessobjects.utils.ServiceUtils;
@@ -83,6 +86,31 @@
 	 * Possible {@link ContextType}s are {@link ContextType}.UNITUNDERTEST,
 	 * {@link ContextType}.TESTSEQUENCE and {@link ContextType}.TESTEQUIPMENT.
 	 * 
+	 * @param sourceName      name of the source (MDM {@link Environment} name)
+	 * @param testId          the id of {@link TestStep} context is looked up for
+	 * @param includeVariable true then teststep variable data is included, false
+	 *                        only test constant data is included
+	 * @param contextTypes    list of {@link ContextType}s
+	 * @return the ordered and measured context data as context object for the
+	 *         identified {@link TestStep}
+	 */
+	public Try<Map<String, Map<ContextType, ContextRoot>>> getTestContext(Value<String> sourceName,
+			Value<String> testId, boolean includeVariable, ContextType... contextTypes) {
+		Try<Test> test = entityService.find(sourceName, Test.class, testId);
+		return getTestContext(sourceName, test, includeVariable, contextTypes);
+	}
+
+	/**
+	 * Vavr conform version of contextActivity getTestStepContext function.
+	 *
+	 * returns the ordered and measurement context for a {@link TestStep}. If no
+	 * {@link ContextType}s are defined for this method call, the method returns all
+	 * context informations of the available {@link ContextType}s. Otherwise you can
+	 * specify a list of {@link ContextType}s.
+	 *
+	 * Possible {@link ContextType}s are {@link ContextType}.UNITUNDERTEST,
+	 * {@link ContextType}.TESTSEQUENCE and {@link ContextType}.TESTEQUIPMENT.
+	 *
 	 * @param sourceName   name of the source (MDM {@link Environment} name)
 	 * @param testStepId   the id of {@link TestStep} context is looked up for
 	 * @param contextTypes list of {@link ContextType}s
@@ -130,6 +158,105 @@
 	}
 
 	/**
+	 * Vavr conform version of contextActivity getTestContext function.
+	 *
+	 * returns the ordered and measurement context for a {@link Test}. If no
+	 * {@link ContextType}s are defined for this method call, the method returns all
+	 * context informations of the available {@link ContextType}s. Otherwise you can
+	 * specify a list of {@link ContextType}s.
+	 *
+	 * Possible {@link ContextType}s are {@link ContextType}.UNITUNDERTEST,
+	 * {@link ContextType}.TESTSEQUENCE and {@link ContextType}.TESTEQUIPMENT.
+	 *
+	 * @param sourceName      name of the source (MDM {@link Environment} name)
+	 * @param test            {@link Try} of the {@link Test}
+	 * @param includeVariable true then teststep variable data is included, false
+	 *                        only test constant data is included
+	 * @param contextTypes    list of {@link ContextType}s
+	 * @return the ordered and measured context data as context object for the
+	 *         identified {@link TestStep}
+	 */
+	private Try<Map<String, Map<ContextType, ContextRoot>>> getTestContext(Value<String> sourceName, Try<Test> test,
+			boolean includeVariable, ContextType... contextTypes) {
+
+		// init an empty hashmap
+		HashMap<ContextType, ContextRoot> mapOrdered = HashMap.empty();
+		HashMap<ContextType, ContextRoot> mapMeasured = HashMap.empty();
+
+		if (test.isSuccess()) {
+
+			java.util.List<TestStep> list = getEntityManager(sourceName).get().loadChildren(test.get(), TestStep.class);
+
+			// merge all attributes from all test steps together
+			for (TestStep testStep : list) {
+				Try<Map<ContextType, ContextRoot>> contextOrdered = getEntityManager(sourceName)
+						.map(e -> HashMap.ofAll(e.loadContexts(testStep, contextTypes)));
+
+				if (contextOrdered.isSuccess()) {
+					mapOrdered = mapOrdered.merge(contextOrdered.get());
+				}
+
+				Try<Map<ContextType, ContextRoot>> contextMeasured = getEntityManager(sourceName).map(e -> HashMap
+						.ofAll(e.loadContexts(findMeasurements(sourceName, testStep).get().get(), contextTypes)));
+
+				if (contextMeasured.isSuccess()) {
+					mapMeasured = mapMeasured.merge(contextMeasured.get());
+				}
+			}
+
+			// filter data out to reduce traffic in the json rest service
+			if (!includeVariable) {
+				mapOrdered.values().forEach(ctxRoot -> {
+					java.util.List<ContextComponent> removals = new ArrayList<>();
+					ctxRoot.getContextComponents().forEach(ctxCmp -> {
+						if (TemplateComponent.of(ctxCmp).isPresent()) {
+							org.eclipse.mdm.api.base.model.Value attr = TemplateComponent.of(ctxCmp).get()
+									.getValue("TestStepSeriesVariable");
+							if (attr.isValid() && ((Boolean) attr.extract()).booleanValue()) {
+								removals.add(ctxCmp);
+							}
+						}
+					});
+					for (ContextComponent ctxCmp : removals) {
+						ctxRoot.removeContextComponent(ctxCmp.getName());
+					}
+				});
+				mapMeasured.values().forEach(ctxRoot -> {
+					java.util.List<ContextComponent> removals = new ArrayList<>();
+					ctxRoot.getContextComponents().forEach(ctxCmp -> {
+						if (TemplateComponent.of(ctxCmp).isPresent()) {
+							org.eclipse.mdm.api.base.model.Value attr = TemplateComponent.of(ctxCmp).get()
+									.getValue("TestStepSeriesVariable");
+							if (attr.isValid() && ((Boolean) attr.extract()).booleanValue()) {
+								removals.add(ctxCmp);
+							}
+						}
+					});
+					for (ContextComponent ctxCmp : removals) {
+						ctxRoot.removeContextComponent(ctxCmp.getName());
+					}
+				});
+			}
+		}
+
+		// set final for follow-up lambda
+		final HashMap<ContextType, ContextRoot> tmpMapOrdered = mapOrdered;
+		final HashMap<ContextType, ContextRoot> tmpMapMeasured = mapMeasured;
+
+		// convert to try class object
+		Try<Map<ContextType, ContextRoot>> contextOrdered = Try.of(() -> tmpMapOrdered);
+		Try<Map<ContextType, ContextRoot>> contextMeasured = Try.of(() -> tmpMapMeasured);
+
+		return Try
+				.of(() -> Lazy
+						.of(() -> HashMap.of(CONTEXT_GROUP_ORDERED,
+								contextOrdered.recover(NoSuchElementException.class, t -> HashMap.empty()).get(),
+								CONTEXT_GROUP_MEASURED,
+								contextMeasured.recover(NoSuchElementException.class, t -> HashMap.empty()).get()))
+						.get());
+	}
+
+	/**
 	 * Vavr conform version of contextActivity getMeasurementContext function.
 	 * 
 	 * returns the ordered and measurement context for a {@link Measurement}. If no
@@ -204,11 +331,22 @@
 	}
 
 	/**
-	 * 
+	 *
 	 * @param sourceName
 	 * @param testStep
 	 * @return
 	 */
+	private Try<List<Measurement>> findMeasurements(Value<String> sourceName, TestStep testStep) {
+		return getEntityManager(sourceName)
+				.map(e -> Lazy.of(() -> List.ofAll(e.loadChildren(testStep, TestStep.CHILD_TYPE_MEASUREMENT))).get());
+	}
+
+	/**
+	 * 
+	 * @param sourceName
+	 * @param measurement
+	 * @return
+	 */
 	private Try<TestStep> findTestStep(Value<String> sourceName, Try<Measurement> measurement) {
 		return getEntityManager(sourceName)
 				.map(e -> Lazy.of(() -> e.loadParent(measurement.get(), Measurement.PARENT_TYPE_TESTSTEP).get()).get());
@@ -300,7 +438,8 @@
 		});
 	}
 
-	private void updateContextComponent(ContextComponent contextComponent, java.util.List<MDMAttribute> nameValues) {
+	private void updateContextComponent(ContextComponent contextComponent,
+			java.util.List<MDMContextAttribute> nameValues) {
 		nameValues.forEach(attribute -> Serializer.applyValue(contextComponent.getValue(attribute.getName()),
 				attribute.getValue()));
 	}
@@ -405,8 +544,8 @@
 		}
 	}
 
-	private MDMEntity transformToMDMEntity(Map<String, Object> component) {
-		return new MDMEntity(
+	private MDMContextEntity transformToMDMEntity(Map<String, Object> component) {
+		return new MDMContextEntity(
 				component.get("name").map(Object::toString)
 						.getOrElseThrow(() -> new MDMEntityAccessException("Missing attribute 'name' in MDMEntity")),
 				component.get("id").map(Object::toString).getOrElse(""),
@@ -416,7 +555,7 @@
 				transformList(component.get("attributes").getOrElseThrow(
 						() -> new MDMEntityAccessException("Missing attribute 'attributes' in MDMEntity")))
 								.map(this::transformMap)
-								.map(m -> new MDMAttribute(
+								.map(m -> new MDMContextAttribute(
 										m.get("name").map(Object::toString)
 												.getOrElseThrow(() -> new MDMEntityAccessException(
 														"Missing attribute 'name' in MDMAttribute")),
@@ -424,7 +563,7 @@
 												.getOrElseThrow(() -> new MDMEntityAccessException(
 														"Missing attribute 'value' in MDMAttribute")),
 										m.get("unit").map(Object::toString).getOrElse(""),
-										m.get("datatype").map(Object::toString).getOrElse("")))
+										m.get("datatype").map(Object::toString).getOrElse(""), null, null, null, null))
 								.toJavaList());
 	}
 }
diff --git a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/utils/ISODateDeseralizer.java b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/utils/ISODateDeseralizer.java
index 122c743..7705277 100755
--- a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/utils/ISODateDeseralizer.java
+++ b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/utils/ISODateDeseralizer.java
@@ -17,6 +17,7 @@
 import java.io.IOException;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
+import java.util.regex.Pattern;
 
 import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.core.JsonTokenId;
@@ -39,6 +40,9 @@
 
 	transient DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
 
+	// use pattern for the dateformat as we only compile this
+	private static final Pattern pattern = Pattern.compile("\\d{4}-\\d{2}-\\d{2}T\\d{2}\\:\\d{2}\\:\\d{2}Z");
+
 	/**
 	 * Deserialize JSON and try to parse every String as an ISO8601 date
 	 */
@@ -47,8 +51,9 @@
 		// try to parse every string as a date
 		// TODO anehmer on 2018-04-30: this approach could lead to a performance leak as
 		// every incoming string is tried to be converted into a date though the
-		// appraoch is very generic
-		if (jp.getCurrentTokenId() == JsonTokenId.ID_STRING) {
+		// approach is very generic
+		// Optimized with pre-compiled pattern to avoid random exception throwing
+		if (jp.getCurrentTokenId() == JsonTokenId.ID_STRING && jp.getTextLength() > 0 && pattern.matcher(jp.getText()).matches()) {
 			try {
 				return LocalDateTime.parse(jp.getText(), dateFormatter);
 			} catch (Exception e) {
diff --git a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/utils/RequestBody.java b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/utils/RequestBody.java
index a39451a..0c45ad5 100644
--- a/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/utils/RequestBody.java
+++ b/org.eclipse.mdm.businessobjects/src/main/java/org/eclipse/mdm/businessobjects/utils/RequestBody.java
@@ -44,7 +44,8 @@
 	static {
 		mapper = new ObjectMapper();
 		SimpleModule simpleModule = new SimpleModule();
-		simpleModule.addDeserializer(Object.class, new ISODateDeseralizer());
+		// disabled deserializer as ContextService.updateContextDescribableContext invokes a parsing of ISO date anyways
+		//simpleModule.addDeserializer(Object.class, new ISODateDeseralizer());
 		mapper.registerModule(simpleModule);
 	}
 
diff --git a/org.eclipse.mdm.openatfx/build.gradle b/org.eclipse.mdm.openatfx/build.gradle
index 974dc4f..38e4910 100644
--- a/org.eclipse.mdm.openatfx/build.gradle
+++ b/org.eclipse.mdm.openatfx/build.gradle
@@ -33,6 +33,11 @@
 	testCompile 'org.apache.commons:commons-math:2.2'
 }
 
+configurations.all {
+	// stax-api is included in Java 6 or higher
+	exclude group: 'javax.xml.stream', module: 'stax-api'
+}
+
 task downloadOpenATFX(type: Download) {
 	acceptAnyCertificate true
 	overwrite false
diff --git a/release_notes.md b/release_notes.md
index e69cf5b..f8081c1 100644
--- a/release_notes.md
+++ b/release_notes.md
@@ -22,7 +22,7 @@
 * New method: o.e.m.a.d.m.EnttiyFactory#createTestStep(String, Test, Classification)
 * New method: o.e.m.a.d.m.EntityFactory#createTestStep(String, Test, TemplateTestStep, Classification)
 * Renamed classes in org.eclipse.mdm.nucleus.api.copy
-
+* New method: o.e.m.a.b.q.Query#limit(int limit)
 
 ### Changes ###
 
@@ -33,9 +33,14 @@
 * [553162](https://bugs.eclipse.org/bugs/show_bug.cgi?id=553162) - Webclient: Add Quantity and Unit to DetailView
 * [553163](https://bugs.eclipse.org/bugs/show_bug.cgi?id=553163) - Implement a session check / reconnect for Freetextindexer
 * [553164](https://bugs.eclipse.org/bugs/show_bug.cgi?id=553164) - Improve template resolving in apicopy
+* [550002](https://bugs.eclipse.org/bugs/show_bug.cgi?id=550002) - Add relation information to REST-API
+* [549844](https://bugs.eclipse.org/bugs/show_bug.cgi?id=549844) - [REST] Add unit info on /channels response
+* [544850](https://bugs.eclipse.org/bugs/show_bug.cgi?id=544850) - Allow to limit number of search results
 
 ### Bugzilla Bugs fixed ###
 
+* [553369](https://bugs.eclipse.org/bugs/show_bug.cgi?id=553369) - ATFX Import fails if multiple version of a Quantity exist 
+* [559366](https://bugs.eclipse.org/bugs/show_bug.cgi?id=559366) - [REST] Swagger Codegen leads to an error when using the provided openAPI files
 * [553266](https://bugs.eclipse.org/bugs/show_bug.cgi?id=553266)) - Contributions of Peak Solution (2019/11)
   - ATFX export now correctly includes Context Data
   - Fixed EntityService#satisfiesParameters