diff --git a/smp-angular/src/app/app.module.ts b/smp-angular/src/app/app.module.ts
index 2234f5b068e8f4ffe850120bbdcd96ec23f7730e..3ecf401ae17a1f3dfba33927c164918fde250618 100644
--- a/smp-angular/src/app/app.module.ts
+++ b/smp-angular/src/app/app.module.ts
@@ -42,12 +42,11 @@ import {AlertService} from './alert/alert.service';
 import {FooterComponent} from './footer/footer.component';
 import {SmpInfoService} from './app-info/smp-info.service';
 import {AuthorizedAdminGuard} from './guards/authorized-admin.guard';
-import {ServiceGroupComponent} from './service-group-edit/service-group.component';
+import {ServiceGroupEditComponent} from './service-group-edit/service-group-edit.component';
 import {ServiceGroupSearchComponent} from './service-group-search/service-group-search.component';
 import {DomainComponent} from './domain/domain.component';
 import {UserComponent} from './user/user.component';
 import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
-import {ServiceGroupMetadataListDialogComponent} from './service-group-edit/service-group-metadata-list-dialog/service-group-metadata-list-dialog.component';
 import {RowLimiterComponent} from './common/row-limiter/row-limiter.component';
 import {DatePipe} from './custom-date/date.pipe';
 import {CapitalizeFirstPipe} from './common/capitalize-first.pipe';
@@ -79,7 +78,7 @@ import {CertificateService} from './user/certificate.service';
     AppComponent,
     LoginComponent,
     HomeComponent,
-    ServiceGroupComponent,
+    ServiceGroupEditComponent,
     ServiceGroupSearchComponent,
     DomainComponent,
     DomainDetailsDialogComponent,
@@ -88,7 +87,6 @@ import {CertificateService} from './user/certificate.service';
     FooterComponent,
     IsAuthorized,
     SaveDialogComponent,
-    ServiceGroupMetadataListDialogComponent,
     ServiceGroupMetadataDialogComponent,
     ServiceGroupExtensionDialogComponent,
     CancelDialogComponent,
@@ -108,7 +106,6 @@ import {CertificateService} from './user/certificate.service';
   ],
   entryComponents: [
     AppComponent,
-    ServiceGroupMetadataListDialogComponent,
     ServiceGroupMetadataDialogComponent,
     ServiceGroupDetailsDialogComponent,
     ServiceGroupExtensionDialogComponent,
diff --git a/smp-angular/src/app/app.routes.ts b/smp-angular/src/app/app.routes.ts
index 6d09b43e6dbb38723cc9d1b084e9be070f88bd43..9044c4b6660ab6f535f97cc2c839832d2313f4d3 100644
--- a/smp-angular/src/app/app.routes.ts
+++ b/smp-angular/src/app/app.routes.ts
@@ -1,7 +1,7 @@
 import {RouterModule, Routes} from '@angular/router';
 import {LoginComponent} from './login/login.component';
 import {ServiceGroupSearchComponent} from './service-group-search/service-group-search.component';
-import {ServiceGroupComponent} from './service-group-edit/service-group.component';
+import {ServiceGroupEditComponent} from './service-group-edit/service-group-edit.component';
 import {DomainComponent} from './domain/domain.component';
 import {AuthenticatedGuard} from './guards/authenticated.guard';
 import {UserComponent} from './user/user.component';
@@ -10,13 +10,13 @@ import {UserComponent} from './user/user.component';
 const appRoutes: Routes = [
   {path: '', component: ServiceGroupSearchComponent},
   {path: 'search', component: ServiceGroupSearchComponent},
-  {path: 'edit', component: ServiceGroupComponent},
+  {path: 'edit', component: ServiceGroupEditComponent},
   {path: 'domain', component: DomainComponent},
   {path: 'user', component: UserComponent},
 
 
   {path: 'login', component: LoginComponent},
-  {path: '**', component: ServiceGroupComponent, canActivate: [AuthenticatedGuard]}
+  {path: '**', component: ServiceGroupEditComponent, canActivate: [AuthenticatedGuard]}
 
 ];
 
diff --git a/smp-angular/src/app/common/search-table/search-table-entity.model.ts b/smp-angular/src/app/common/search-table/search-table-entity.model.ts
index bb9c07e56d35f99584586972297f341cd5b23763..ba45d9bd72ad4a85c29103b186f9a559e4690eb3 100644
--- a/smp-angular/src/app/common/search-table/search-table-entity.model.ts
+++ b/smp-angular/src/app/common/search-table/search-table-entity.model.ts
@@ -1,6 +1,7 @@
 import {SearchTableEntityStatus} from './search-table-entity-status.model';
 
 export interface SearchTableEntity {
+  index: number;
   status: SearchTableEntityStatus;
   deleted?: boolean;
 }
diff --git a/smp-angular/src/app/common/search-table/search-table.component.css b/smp-angular/src/app/common/search-table/search-table.component.css
index 9cdb4f04898b062cc8287c4f9a45e319793a9ce3..84f05baf748be2e6d2d54c3adfe5f21cb4378f41 100644
--- a/smp-angular/src/app/common/search-table/search-table.component.css
+++ b/smp-angular/src/app/common/search-table/search-table.component.css
@@ -18,6 +18,18 @@
 
 /deep/ .deleted span[title] {
   text-decoration: line-through !important;
+  font-weight: bold;
+}
+/deep/ .newTableRow span[title] {
+
+  color: darkgreen !important;
+  font-weight: bold;
+}
+/deep/ .updatedTableRow span[title] {
+  font-weight: bold;
+}
+/deep/ .tableRow span[title] {
+  font-weight: normal;
 }
 
 .group-action-button {
diff --git a/smp-angular/src/app/common/search-table/search-table.component.html b/smp-angular/src/app/common/search-table/search-table.component.html
index 5f1075801fcdb3a60f2f369d58779014170d600a..2b52cd6f8eeb1bbf98d85f65ad60578b6d3ceea4 100644
--- a/smp-angular/src/app/common/search-table/search-table.component.html
+++ b/smp-angular/src/app/common/search-table/search-table.component.html
@@ -25,7 +25,7 @@
         <app-row-limiter [pageSizes]="rowLimiter.pageSizes"
                          (onPageSizeChanged)="changePageSize($event.value)"></app-row-limiter>
       </span>
-      <!-- no need for this span class="column-filter-button">
+      <!-- no need for this for SMP 4.1 <span class="column-filter-button">
         <app-column-picker [allColumns]="columnPicker.allColumns" [selectedColumns]="columnPicker.selectedColumns"
                            (onSelectedColumnsChanged)="columnPicker.changeSelectedColumns($event)"></app-column-picker>
       </span -->
@@ -53,7 +53,8 @@
                    [selected]="selected"
                    [selectionType]="'single'"
                    (activate)="onActivate($event)"
-                   (select)="onSelect($event)">
+                   (select)="onSelect($event)"
+                    >
       <!-- Row Detail Template -->
       <ngx-datatable-row-detail id="rowDetail" [rowHeight]="'auto'" #searchTableDetailRow
                                 (toggle)="onDetailToggle($event)">
@@ -65,7 +66,7 @@
     </ngx-datatable>
 
     <ng-template #rowIndex let-row="row" ngx-datatable-cell-template>
-      <span>{{row.index}}</span>
+      <span>{{row.index + 1}}</span>
     </ng-template>
 
     <ng-template #rowActions let-row="row" ngx-datatable-cell-template>
@@ -82,7 +83,7 @@
     </ng-template>
 
     <ng-template #rowExpand let-row="row" let-expanded="expanded" let-disabled="disabled" ngx-datatable-cell-template >
-      <span *ngIf="!!disabled">( )</span>
+      <span *ngIf="disabled">( )</span>
       <a *ngIf="!disabled" class="table-button-expand"
         href="javascript:void(0)"
         title="Expand/Collapse Row"
diff --git a/smp-angular/src/app/common/search-table/search-table.component.ts b/smp-angular/src/app/common/search-table/search-table.component.ts
index 821648863b7d4cbca5b60b3ad75761d8a7bcbcb0..14c3c7d206e390b54217478f5e110c1dc59b86fe 100644
--- a/smp-angular/src/app/common/search-table/search-table.component.ts
+++ b/smp-angular/src/app/common/search-table/search-table.component.ts
@@ -111,10 +111,15 @@ export class SearchTableComponent implements OnInit {
     this.page(this.offset, this.rowLimiter.pageSize, this.orderBy, this.asc);
   }
 
-  getRowClass(row): string {
-    return row.deleted ? 'deleted' : '';
+  getRowClass(row) {
+    return {
+      'newTableRow': (row.status === SearchTableEntityStatus.NEW),
+      'updatedTableRow': (row.status === SearchTableEntityStatus.UPDATED),
+      'deleted': (row.status === SearchTableEntityStatus.REMOVED)
+    };
   }
 
+
   getTableDataEntries$(offset: number, pageSize: number, orderBy: string, asc: boolean): Observable<SearchTableResult> {
 
     let params: HttpParams = new HttpParams()
diff --git a/smp-angular/src/app/domain/domain-controller.ts b/smp-angular/src/app/domain/domain-controller.ts
index 38499f3da01dfb0fe2abceefcdd5aeb3547f9dd9..7cf4aea7c8cbe559f94cb8e066fec31ff438685d 100644
--- a/smp-angular/src/app/domain/domain-controller.ts
+++ b/smp-angular/src/app/domain/domain-controller.ts
@@ -29,6 +29,7 @@ export class DomainController implements SearchTableController {
 
   public newRow(): DomainRo {
     return {
+      index: null,
       domainCode: '',
       smlSubdomain: '',
       smlSmpId: '',
diff --git a/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.html b/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.html
index ebb925e0ecbb5d1f00035c70f4336fb39c1bb3b2..48af8018950d9733009ae0dd26ab7d7dd80e9658 100644
--- a/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.html
+++ b/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.html
@@ -49,7 +49,7 @@
   <tr>
     <td>
       <button mat-raised-button color="primary" [mat-dialog-close]="true" (click)="submitForm()" [disabled]="!domainForm.valid">
-        <mat-icon>ok</mat-icon>
+        <mat-icon>check_circle</mat-icon>
         <span>OK</span>
       </button>
       <button mat-raised-button color="primary" mat-dialog-close>
diff --git a/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts b/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts
index 3e4478b989cfb0b721f03d5f8213238a01aab6e4..092a1165267012cecfca3c12645b65d0316a2ce0 100644
--- a/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts
+++ b/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts
@@ -18,7 +18,7 @@ export class DomainDetailsDialogComponent {
 
   static readonly NEW_MODE = 'New Domain';
   static readonly EDIT_MODE = 'Domain Edit';
-  readonly dnsDomainPattern = '^(?!(\\d|-|_)+)[a-zA-Z0-9-]{1,63}$';
+  readonly dnsDomainPattern = '^(?!(\\d|-|_).+)[a-zA-Z0-9-]{1,63}$';
   readonly domainCodePattern = '^[a-zA-Z]{1,255}$';
 
   editMode: boolean;
@@ -26,8 +26,6 @@ export class DomainDetailsDialogComponent {
   current: DomainRo & { confirmation?: string };
   domainForm: FormGroup;
 
-  userSwitch: boolean;
-  certificateSwitch: boolean;
 
   domain;
 
@@ -45,12 +43,11 @@ export class DomainDetailsDialogComponent {
       }
       : {
         domainCode: '',
-        email: '',
-        password: '',
-        confirmation: '',
-        role: '',
+        smlSubdomain: '',
+        smlSmpId: '',
+        smlClientKeyAlias: '',
+        signatureKeyAlias: '',
         status: SearchTableEntityStatus.NEW,
-        certificate: {},
       };
 
     this.domainForm = fb.group({
@@ -58,7 +55,7 @@ export class DomainDetailsDialogComponent {
       'domainCode': new FormControl({value: this.current.domainCode, disabled: this.editMode}, [Validators.pattern(this.domainCodePattern)]),
       'smlSubdomain': new FormControl({value: this.current.smlSubdomain, disabled: this.editMode},  [Validators.pattern(this.dnsDomainPattern)]),
       'smlSmpId': new FormControl({value: this.current.smlSmpId}, [Validators.required, Validators.pattern(this.dnsDomainPattern)]),
-      'smlClientKeyAlias': new FormControl({value: this.current.signatureKeyAlias}, null),
+      'smlClientKeyAlias': new FormControl({value: this.current.smlClientKeyAlias}, null),
       'signatureKeyAlias': new FormControl({value: this.current.signatureKeyAlias}, null),
 
 
diff --git a/smp-angular/src/app/domain/domain.component.html b/smp-angular/src/app/domain/domain.component.html
index 89d894c64bde8d4481e31de00c9c4354cb313717..6dd642be9cca558c1b08a2326210e490ff17de63 100644
--- a/smp-angular/src/app/domain/domain.component.html
+++ b/smp-angular/src/app/domain/domain.component.html
@@ -3,7 +3,7 @@
   page_id= 'domain_id'
   title= 'Domains'
   [columnPicker] = "columnPicker"
-  url="rest/domain"
+  [url]="baseUrl"
   [additionalToolButtons]="additionalToolButtons"
   [searchTableController]="domainController"
   [showSearchPanel]="false"
diff --git a/smp-angular/src/app/domain/domain.component.ts b/smp-angular/src/app/domain/domain.component.ts
index 49167818efb8aadb164b74d7bcd2a0fd9c9d4550..73e617c23fcedfd0c9356c4d0a4c4cd73c3e4920 100644
--- a/smp-angular/src/app/domain/domain.component.ts
+++ b/smp-angular/src/app/domain/domain.component.ts
@@ -5,6 +5,7 @@ import {MatDialog, MatDialogRef} from '@angular/material';
 import {AlertService} from '../alert/alert.service';
 import {DomainController} from './domain-controller';
 import {HttpClient} from '@angular/common/http';
+import {SmpConstants} from "../smp.constants";
 
 @Component({
   moduleId: module.id,
@@ -17,10 +18,12 @@ export class DomainComponent implements OnInit {
   @ViewChild('rowExtensionAction') rowExtensionAction: TemplateRef<any>;
   @ViewChild('rowActions') rowActions: TemplateRef<any>;
 
+  baseUrl = SmpConstants.REST_DOMAIN;
   columnPicker: ColumnPicker = new ColumnPicker();
   domainController: DomainController;
   filter: any = {};
 
+
   constructor(protected http: HttpClient, protected alertService: AlertService, public dialog: MatDialog) {
   }
 
diff --git a/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.css b/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.css
new file mode 100644
index 0000000000000000000000000000000000000000..66c5204a6d4d3b0cee28761c51cfce5310bdb950
--- /dev/null
+++ b/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.css
@@ -0,0 +1,8 @@
+#extensionTextArea {
+  border: none;
+  width: 610px;
+  height:340px;
+  -webkit-box-sizing: border-box; /* <=iOS4, <= Android  2.3 */
+  -moz-box-sizing: border-box; /* FF1+ */
+  box-sizing: border-box; /* Chrome, IE8, Opera, Safari 5.1*/
+}
diff --git a/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.html b/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.html
index 0810d76791c2c22bdd5c1ffda86908680c30c538..d29e25dc3a8d47cb4659606b70451d800c9cc69b 100644
--- a/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.html
+++ b/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.html
@@ -1,38 +1,83 @@
-<h2 mat-dialog-title>ServiceGroup details</h2>
-<mat-dialog-content style="height:260px;width:650px">
-  <mat-card>
-    <mat-card-content>
-      <mat-form-field style="width:100%">
-        <input matInput placeholder="Participant Id" value="{{servicegroup.serviceGroupROId.participantId}}" readonly/>
-      </mat-form-field>
+<h2 mat-dialog-title>{{formTitle}}</h2>
 
-      <mat-form-field style="width:100%">
-        <input matInput placeholder="Participant schema" value="{{servicegroup.serviceGroupROId.participantSchema}}" readonly/>
-      </mat-form-field>
+<mat-dialog-content style="height:600px;width:1100px">
+  <div fxLayout="row">
+    <div fxLayout="column">
+      <mat-card fxFlex="200px">
+        <mat-card-title>Identifier</mat-card-title>
+        <mat-card-content>
+          <mat-form-field style="width:100%">
+            <input matInput placeholder="Participant identifier" name="participantIdentifier"
+                   value="{{current.participantIdentifier}}" id="participantIdentifier_id"
+                   (blur)="updateParticipantIdentifier($event)"
+                   [formControl]="dialogForm.controls['participantIdentifier']" maxlength="255" required>
+            <div
+              *ngIf="(!editMode && dialogForm.controls['participantIdentifier'].touched || editMode) &&  dialogForm.controls['participantIdentifier'].hasError('required')"
+              style="color:red; font-size: 70%">
+              Participant identifier must not be empty.
+            </div>
+          </mat-form-field>
 
-      <mat-form-field style="width:100%">
-        <input matInput placeholder="Domain" value="{{servicegroup.domain}}" readonly/>
-      </mat-form-field>
-
-    </mat-card-content>
-  </mat-card>
+          <mat-form-field style="width:100%">
+            <input matInput placeholder="Participant scheme" name="participantScheme"
+                   value="{{current.participantScheme}}" id="participantScheme_id"
+                   (blur)="updateParticipantScheme($event)" [formControl]="dialogForm.controls['participantScheme']"
+                   maxlength="255" required>
+            <div
+              *ngIf="(!editMode && dialogForm.controls['participantScheme'].touched || editMode) &&  dialogForm.controls['participantScheme'].hasError('required')"
+              style="color:red; font-size: 70%">
+              Participant scheme must not be empty.
+            </div>
+          </mat-form-field>
+        </mat-card-content>
+      </mat-card>
+      <mat-card>
+        <mat-card-title>Owners</mat-card-title>
+        <mat-card-content>
+          <p>Selected user count: {{usersSelected.selectedOptions.selected.length}}</p>
+        <mat-selection-list #usersSelected [compareWith]="compareUserById"
+                            (selectionChange)="userListChanged(usersSelected.selectedOptions.selected,$event)"
+                            [formControl]="formControlUsers"
+                            style="height: 200px;  overflow-y: scroll; overflow-x: auto;">
+          <mat-list-option *ngFor="let user of userlist" [value]='user'>
+            {{user.id}} - {{user.username?user.username:user.id}}
+          </mat-list-option>
+        </mat-selection-list>
+        <div
+          *ngIf="(!editMode && dialogForm.controls['users'].touched || editMode) &&  dialogForm.controls['users'].hasError('minCountOwners')"
+          style="color:red; font-size: 70%">
+          At least one user (owner) must be selected!
+        </div>
+        </mat-card-content>
+      </mat-card>
+    </div>
 
+    <mat-card fxFlex="60">
+      <mat-card-title>Extension</mat-card-title>
+      <mat-card-content>
+        <p>
+          Extension is automatically wrapped to root element to form vaild XML! No ExtensionWrapper element is needed.
+        </p>
+        <mat-form-field>
+          <textarea id="extensionTextArea" resizeable="false" placeholder="Extension"  name="extension" ></textarea>
+        </mat-form-field>
+      </mat-card-content>
+    </mat-card>
+  </div>
 </mat-dialog-content>
 
 <mat-dialog-actions>
-  <div class="group-action-button" >
-  <button id="ServiceGroupsSaveButton" mat-raised-button color="primary" (click)="dialogRef.close({})"
-          style="margin-top:10px">
-    <mat-icon>save</mat-icon>
-    <span>Save</span>
-  </button>
+  <div class="group-action-button">
+    <button mat-raised-button color="primary" [mat-dialog-close]="true" (click)="submitForm()"
+            [disabled]="!dialogForm.valid">
+      <mat-icon>check_circle</mat-icon>
+      <span>OK</span>
+    </button>
 
-
-  <button id="ServiceGroupsCloseButton" mat-raised-button color="primary" (click)="dialogRef.close({})"
-          style="margin-top:10px">
-    <mat-icon>close</mat-icon>
-    <span>Close</span>
-  </button>
+    <button mat-raised-button color="primary" mat-dialog-close>
+      <mat-icon>cancel</mat-icon>
+      <span>Cancel</span>
+    </button>
   </div>
 </mat-dialog-actions>
-
+<div style="text-align: right; font-size: 70%">* required fields</div>
diff --git a/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.ts b/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.ts
index c29da914f969e189522816a2bde4c3a849f33b5f..1af2b0bd13e8fb486dbce7a374c0c27dc9e515dd 100644
--- a/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.ts
+++ b/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.ts
@@ -1,16 +1,160 @@
-import {Component} from '@angular/core';
-import {MatDialogRef} from '@angular/material';
+import {Component, Inject} from '@angular/core';
+import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material';
+import {Observable} from "rxjs/internal/Observable";
+import {SearchTableResult} from "../../common/search-table/search-table-result.model";
+import {HttpClient} from "@angular/common/http";
+import {SmpConstants} from "../../smp.constants";
+import {UserRo} from "../../user/user-ro.model";
+import {AlertService} from "../../alert/alert.service";
+import {DomainDetailsDialogComponent} from "../../domain/domain-details-dialog/domain-details-dialog.component";
+import {AbstractControl, FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms";
+import {SearchTableEntityStatus} from "../../common/search-table/search-table-entity-status.model";
+import {DomainRo} from "../../domain/domain-ro.model";
+import {ServiceGroupEditRo} from "../service-group-edit-ro.model";
+import {ServiceMetadataEditRo} from "../service-metadata-edit-ro.model";
 
 @Component({
   selector: 'app-messagelog-details',
-  templateUrl: './service-group-details-dialog.component.html'
+  templateUrl: './service-group-details-dialog.component.html',
+  styleUrls: ['./service-group-details-dialog.component.css']
 })
 export class ServiceGroupDetailsDialogComponent {
 
-  servicegroup;
-  dateFormat: String = 'yyyy-MM-dd HH:mm:ssZ';
+  static readonly NEW_MODE = 'New ServiceGroup';
+  static readonly EDIT_MODE = 'ServiceGroup Edit';
+
+
+  userObserver:  Observable< SearchTableResult> ;
+  domainObserver:  Observable< SearchTableResult> ;
+  userlist: Array<UserRo> = [];
+  editMode: boolean;
+  formTitle: string;
+  current: ServiceGroupEditRo & { confirmation?: string };
+
+  dialogForm: FormGroup;
+  dialogFormBuilder: FormBuilder;
+  formControlUsers: FormControl;
+  /*
+  selectedDomain: DomainRo;
+  domainList: Array<any>;
+*/
+
+  minCountOwners(min: number) {
+    return (c: AbstractControl): {[key: string]: any} => {
+      if (c.value.length >= min)
+        return null;
+
+      return { 'minCountOwners': {valid: false }};
+    }
+  }
+
+  constructor(protected http: HttpClient, public dialogRef: MatDialogRef<ServiceGroupDetailsDialogComponent>,
+                private alertService: AlertService,
+              @Inject(MAT_DIALOG_DATA) public data: any,
+              private fb: FormBuilder) {
+    // init user list
+
+   this.userObserver = this.http.get<SearchTableResult>(SmpConstants.REST_USER);
+    this.userObserver.subscribe((users: SearchTableResult) => {
+      this.userlist = new Array(users.serviceEntities.length)
+        .map((v, index) => users.serviceEntities[index] as UserRo);
+
+      this.userlist = users.serviceEntities.map(serviceEntity => {
+        return {...<UserRo>serviceEntity}
+      });
+      this.updateData();
+    });
+    /*
+    // init domains
+    this.domainObserver = this.http.get<SearchTableResult>(SmpConstants.REST_DOMAIN);
+    this.domainObserver.subscribe((domains: SearchTableResult) => {
+      this.domainList = new Array(domains.serviceEntities.length)
+        .map((v, index) => {domains.serviceEntities[index] as DomainRo;
+          if ( this.editMode && v.domainCode ===data.row.domainCode) {
+            this.selectedDomain = v as DomainRo;
+          }
+        });
+
+      this.domainList = domains.serviceEntities.map(serviceEntity => {
+        return {...serviceEntity}
+      });
+    });
+*/
+    this.dialogFormBuilder = fb;
+    this.editMode = data.edit;
+    this.formTitle = this.editMode ?  ServiceGroupDetailsDialogComponent.EDIT_MODE: ServiceGroupDetailsDialogComponent.NEW_MODE;
+    this.current = this.editMode
+      ? {
+        ...data.row,
+      }
+      : {
+        id: null,
+        participantIdentifier: '',
+        participantScheme:  '',
+        serviceMetadata:[],
+        users:[],
+        domainCode:'',
+        status: SearchTableEntityStatus.NEW,
+      };
+
+    this.dialogForm = this.dialogFormBuilder.group({
+
+      'participantIdentifier': new FormControl({value: this.current.participantIdentifier, disabled: this.editMode}, this.editMode ? Validators.required : null),
+      'participantScheme': new FormControl({value: this.current.participantScheme, disabled: this.editMode},  this.editMode ? Validators.required : null),
+      'domainCode': new FormControl({value: this.current.domainCode},this.editMode ? Validators.required : null),
+
+      //'users': [new FormControl({value: this.current.users}, [ this.minCountOwners(1)] )],
+    });
+
 
-  constructor(public dialogRef: MatDialogRef<ServiceGroupDetailsDialogComponent>) {
   }
 
+  updateData(){
+    this.formControlUsers = new FormControl(this.current.users);
+    this.formControlUsers.setValidators( [ this.minCountOwners(1)]);
+
+    this.dialogForm.addControl("users",this.formControlUsers );
+
+  }
+
+
+  submitForm() {
+    this.checkValidity(this.dialogForm)
+    this.dialogRef.close(true);
+  }
+
+  checkValidity(g: FormGroup) {
+    Object.keys(g.controls).forEach(key => {
+      g.get(key).markAsDirty();
+    });
+    Object.keys(g.controls).forEach(key => {
+      g.get(key).markAsTouched();
+    });
+    //!!! updateValueAndValidity - else some filed did no update current / on blur never happened
+    Object.keys(g.controls).forEach(key => {
+      g.get(key).updateValueAndValidity();
+    });
+  }
+
+
+  updateParticipantIdentifier(event) {
+    this.current.participantIdentifier = event.target.value;
+  }
+  updateParticipantScheme(event) {
+    this.current.participantScheme = event.target.value;
+  }
+
+  userListChanged(usersSelected, event){
+    this.current.users = [];
+    for(let usr of usersSelected) {
+      this.current.users.push(usr.value);
+    }
+  }
+  compareUserById(item1, item2): boolean{
+    return item1.id=== item2.id;
+  }
+
+  isSelected(id): boolean {
+    return !!this.current.users.find(user => user.id===id);
+  }
 }
diff --git a/smp-angular/src/app/service-group-edit/service-group-controller.ts b/smp-angular/src/app/service-group-edit/service-group-edit-controller.ts
similarity index 56%
rename from smp-angular/src/app/service-group-edit/service-group-controller.ts
rename to smp-angular/src/app/service-group-edit/service-group-edit-controller.ts
index c3c790a216e8d71563239c89260de544b44a959b..4942ebc87fedcc6d052b697d6e224f279252e509 100644
--- a/smp-angular/src/app/service-group-edit/service-group-controller.ts
+++ b/smp-angular/src/app/service-group-edit/service-group-edit-controller.ts
@@ -1,24 +1,23 @@
 import {SearchTableController} from '../common/search-table/search-table-controller';
 import {MatDialog, MatDialogConfig, MatDialogRef} from '@angular/material';
 import {ServiceGroupDetailsDialogComponent} from './service-group-details-dialog/service-group-details-dialog.component';
-import {AlertService} from '../alert/alert.service';
 import {ServiceGroupExtensionDialogComponent} from './service-group-extension-dialog/service-group-extension-dialog.component';
-import {ServiceGroupMetadataListDialogComponent} from './service-group-metadata-list-dialog/service-group-metadata-list-dialog.component';
-import {UserDetailsDialogComponent} from '../user/user-details-dialog/user-details-dialog.component';
-import {SearchTableEntity} from '../common/search-table/search-table-entity.model';
-import {ServiceGroupRo} from './service-group-ro.model';
+import {ServiceGroupEditRo} from './service-group-edit-ro.model';
 import {SearchTableEntityStatus} from '../common/search-table/search-table-entity-status.model';
+import {ServiceMetadataEditRo} from "./service-metadata-edit-ro.model";
+import {DomainDetailsDialogComponent} from "../domain/domain-details-dialog/domain-details-dialog.component";
 
-export class ServiceGroupController implements SearchTableController {
+export class ServiceGroupEditController implements SearchTableController {
 
   constructor(public dialog: MatDialog) { }
 
-  public showDetails(row: any) {
-    let dialogRef: MatDialogRef<ServiceGroupDetailsDialogComponent> = this.newDialog();
-    dialogRef.componentInstance.servicegroup = row;
+  public showDetails( row: any, config?: MatDialogConfig,) {
+    let dialogRef: MatDialogRef<ServiceGroupDetailsDialogComponent>
+      = this.dialog.open(ServiceGroupDetailsDialogComponent);
     dialogRef.afterClosed().subscribe(result => {
       //Todo:
     });
+
   }
 
   public showExtension(row: any) {
@@ -30,11 +29,7 @@ export class ServiceGroupController implements SearchTableController {
   }
 
   public showMetadataList(row: any) {
-    let dialogRef: MatDialogRef<ServiceGroupMetadataListDialogComponent> = this.dialog.open(ServiceGroupMetadataListDialogComponent);
-   // dialogRef.componentInstance.servicegroup = row;
-    dialogRef.afterClosed().subscribe(result => {
-      //Todo:
-    });
+
   }
 
 
@@ -46,13 +41,16 @@ export class ServiceGroupController implements SearchTableController {
     return this.dialog.open(ServiceGroupDetailsDialogComponent, config);
   }
 
-  public newRow(): ServiceGroupRo {
+  public newRow(): ServiceGroupEditRo {
     return {
-      domain: '',
-      serviceGroupROId: {
-        participantId: '',
-        participantSchema: ''
-      },
+      id: null,
+      index: null,
+      participantIdentifier:'',
+      participantScheme: '',
+      domainCode: '',
+      smlSubdomain: '',
+      serviceMetadata:[],
+      users: [],
       status: SearchTableEntityStatus.NEW
     };
   }
diff --git a/smp-angular/src/app/service-group-edit/service-group-edit-ro.model.ts b/smp-angular/src/app/service-group-edit/service-group-edit-ro.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9b626bc7ee710dd378bce97b5eb42324f73249e5
--- /dev/null
+++ b/smp-angular/src/app/service-group-edit/service-group-edit-ro.model.ts
@@ -0,0 +1,13 @@
+import { ServiceMetadataEditRo } from './service-metadata-edit-ro.model';
+import {SearchTableEntity} from "../common/search-table/search-table-entity.model";
+import {UserRo} from "../user/user-ro.model";
+
+export interface ServiceGroupEditRo extends SearchTableEntity {
+  id: number;
+  participantIdentifier: string;
+  participantScheme: string;
+  domainCode:'',
+  smlSubdomain:'',
+  serviceMetadata: Array<ServiceMetadataEditRo>;
+  users: Array<UserRo>;
+}
diff --git a/smp-angular/src/app/service-group-edit/service-group.component.css b/smp-angular/src/app/service-group-edit/service-group-edit.component.css
similarity index 100%
rename from smp-angular/src/app/service-group-edit/service-group.component.css
rename to smp-angular/src/app/service-group-edit/service-group-edit.component.css
diff --git a/smp-angular/src/app/service-group-edit/service-group-edit.component.html b/smp-angular/src/app/service-group-edit/service-group-edit.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..379697f11a2fda226b0e9ade4736e19d8c85b6fa
--- /dev/null
+++ b/smp-angular/src/app/service-group-edit/service-group-edit.component.html
@@ -0,0 +1,112 @@
+<smp-search-table
+  page_id='edit_id'
+  title='Edit'
+  [columnPicker]="columnPicker"
+  [url]="baseUrl"
+  [additionalToolButtons]="additionalToolButtons"
+  [searchPanel]="searchPanel"
+  [filter]="filter"
+  [searchTableController]="serviceGroupEditController"
+  [tableRowDetailContainer]="tableRowDetailContainer"
+>
+
+  <ng-template #rowMetadataAction let-row="row" let-value="value" ngx-datatable-cell-template>
+
+    <button mat-button color="primary"
+            (click)="metadataRowButtonAction(row)" id="metadataRowButtonAction{{row.$$index}}_id" tooltip="Metadata">
+      <mat-icon>view_list</mat-icon>
+      <span>Metadata</span>
+    </button>
+
+  </ng-template>
+
+  <ng-template #rowExtensionAction let-row="row" let-value="value" ngx-datatable-cell-template>
+
+    <button mat-button color="primary"
+            (click)="extensionRowButtonAction(row)" id="extensionRowButtonAction{{row.$$index}}_id" tooltip="Extension">
+      <mat-icon>code</mat-icon>
+      <span>Extension</span>
+    </button>
+
+  </ng-template>
+
+  <ng-template #searchPanel>
+    <mat-form-field>
+      <input matInput placeholder="Participant Id" name="messageId" [(ngModel)]="filter.messageId"
+             #messageId="ngModel" id="messageid_id">
+    </mat-form-field>
+    <mat-form-field>
+      <input matInput placeholder="Participant schema" name="patricipantSchema" [(ngModel)]="filter.messageId"
+             #messageId="ngModel" id="participanschema_id">
+    </mat-form-field>
+    <mat-select placeholder="Domain " [(ngModel)]="filter.messageStatus" name="messageStatus"
+               id="messagestatus_id">
+      <mat-option [value]="''">
+      </mat-option>
+      <mat-option *ngFor="let mstatus of msgStatus" [value]="mstatus">
+        {{mstatus}}
+      </mat-option>
+    </mat-select>
+  </ng-template>
+
+
+  <ng-template #additionalToolButtons>
+    <div style="background-color: #03A9F4; display: inline-block; width: 3px; height: 100%; margin-right: 8px">&nbsp;
+    </div>
+    <button mat-raised-button color="primary"
+            id="metadatabutton_id">
+      <mat-icon>view_list</mat-icon>
+      <span>Metadata</span>
+    </button>
+
+    <button mat-raised-button color="primary"
+            id="extensionbutton_id">
+      <mat-icon>code</mat-icon>
+      <span>Extension</span>
+    </button>
+  </ng-template>
+
+  <ng-template #tableRowDetailContainer let-row="row">
+
+    <div *ngIf="row.serviceMetadata.length===0" style="padding-left:20px;">
+      No service metadata
+    </div>
+    <div *ngIf="row.serviceMetadata.length !== 0" >
+      <ngx-datatable
+        class='material striped'
+        style="width: 80%"
+        [loadingIndicator]="loading"
+        [rows]='row.serviceMetadata'
+        [columnMode]='"force"'
+        [headerHeight]='50'
+        [footerHeight]='50'
+        [rowHeight]='"auto"'>
+        <ngx-datatable-column prop="domainCode" name="Domain" maxWidth="250" ></ngx-datatable-column>
+        <ngx-datatable-column prop="documentIdentifierScheme" name="Document identifier scheme" maxWidth="350" ></ngx-datatable-column>
+        <ngx-datatable-column prop="documentIdentifier" name="Document identifier" maxWidth="250" ></ngx-datatable-column>
+        <ngx-datatable-column [cellTemplate]="rowMetadataSMPUrlLinkAction" name="URL" maxWidth="250" ></ngx-datatable-column>
+        <ngx-datatable-column [cellTemplate]="rowMetadataActions" name="Actions" maxWidth="150" ></ngx-datatable-column>
+
+        <ng-template #rowMetadataSMPUrlLinkAction let-rowSmd="row" ngx-datatable-cell-template>
+          <a target="_blank"
+             href="{{contextPath}}{{row.participantScheme}}::{{row.participantIdentifier}}/services/{{rowSmd.documentIdentifierScheme}}::{{rowSmd.documentIdentifier}}" >Open URL</a>
+        </ng-template>
+      </ngx-datatable>
+
+      <ng-template #rowMetadataActions let-rowSmd="row" ngx-datatable-cell-template>
+        <div>
+          <button mat-icon-button color="primary" [disabled]="rowSmd.deleted || loading"
+                  (click)="onEditMetadataRow(rowSmd)" tooltip="Edit">
+            <mat-icon>edit</mat-icon>
+          </button>
+          <button mat-icon-button color="primary" [disabled]="rowSmd.deleted || loading"
+                  (click)="onDeleteMetadataRowActionClicked(rowSmd)" tooltip="Delete">
+            <mat-icon>delete</mat-icon>
+          </button>
+        </div>
+      </ng-template>
+
+    </div>
+  </ng-template>
+
+</smp-search-table>
diff --git a/smp-angular/src/app/service-group-edit/service-group-edit.component.ts b/smp-angular/src/app/service-group-edit/service-group-edit.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..64e4c6709a1d28f36ab1542c508c476f41234f8a
--- /dev/null
+++ b/smp-angular/src/app/service-group-edit/service-group-edit.component.ts
@@ -0,0 +1,114 @@
+import {Component, OnInit, TemplateRef, ViewChild} from '@angular/core';
+import {ColumnPicker} from '../common/column-picker/column-picker.model';
+import {MatDialog, MatDialogRef} from '@angular/material';
+import {AlertService} from '../alert/alert.service';
+import {ServiceGroupEditController} from './service-group-edit-controller';
+import {HttpClient} from '@angular/common/http';
+import {ServiceGroupDetailsDialogComponent} from "./service-group-details-dialog/service-group-details-dialog.component";
+import {SmpConstants} from "../smp.constants";
+import {Observable} from "rxjs/internal/Observable";
+import {UserRo} from "../user/user-ro.model";
+import {SearchTableResult} from "../common/search-table/search-table-result.model";
+
+@Component({
+  moduleId: module.id,
+  templateUrl:'./service-group-edit.component.html',
+  styleUrls: ['./service-group-edit.component.css']
+})
+export class ServiceGroupEditComponent implements OnInit {
+
+  @ViewChild('rowMetadataAction') rowMetadataAction: TemplateRef<any>
+  @ViewChild('rowExtensionAction') rowExtensionAction: TemplateRef<any>
+  @ViewChild('rowActions') rowActions: TemplateRef<any>;
+  @ViewChild('rowSMPUrlLinkAction') rowSMPUrlLinkAction: TemplateRef<any>
+
+  columnPicker: ColumnPicker = new ColumnPicker();
+  serviceGroupEditController: ServiceGroupEditController;
+  filter: any = {};
+  baseUrl: string = SmpConstants.REST_EDIT;
+
+  userObserver:  Observable< SearchTableResult> ;
+  domainObserver:  Observable< SearchTableResult> ;
+  userlist: Array<UserRo> = [];
+
+  constructor(protected http: HttpClient, protected alertService: AlertService, public dialog: MatDialog) {
+
+    this.userObserver = this.http.get<SearchTableResult>(SmpConstants.REST_USER);
+    this.userObserver.subscribe((users: SearchTableResult) => {
+      this.userlist = new Array(users.serviceEntities.length)
+        .map((v, index) => users.serviceEntities[index] as UserRo);
+
+      this.userlist = users.serviceEntities.map(serviceEntity => {
+        return {...<UserRo>serviceEntity}
+      });
+    });
+  }
+
+  ngOnInit() {
+    this.serviceGroupEditController = new ServiceGroupEditController(this.dialog);
+
+    this.columnPicker.allColumns = [
+      {
+        name: 'Metadata size',
+        prop: 'serviceMetadata.length',
+        width: 80,
+        maxWidth: 120
+      },
+      {
+        name: 'Owners size',
+        prop: 'users.length',
+        width: 80,
+        maxWidth: 120
+      },
+      {
+        name: 'Participant scheme',
+        prop: 'participantScheme',
+        width: 250,
+        maxWidth: 300
+      },
+      {
+        name: 'Participant identifier',
+        prop: 'participantIdentifier',
+      },
+      {
+        cellTemplate: this.rowExtensionAction,
+        name: 'Extension',
+        width: 80,
+        maxwidth: 120,
+        sortable: false
+      },
+      {
+        cellTemplate: this.rowSMPUrlLinkAction,
+        name: 'OASIS ServiceGroup URL',
+        width: 150,
+        maxWidth: 250,
+        sortable: false
+      },
+
+    ];
+
+    this.columnPicker.selectedColumns = this.columnPicker.allColumns.filter(col => {
+      return ["Metadata size", 'Owners size', "Participant scheme", "Participant identifier", "Extension", "OASIS ServiceGroup URL"].indexOf(col.name) != -1
+    });
+  }
+
+  extensionRowButtonAction(row: any){
+    this.serviceGroupEditController.showExtension(row);
+  }
+
+  metadataRowButtonAction(row: any){
+    this.serviceGroupEditController.showMetadataList(row);
+  }
+
+  details(row: any) {
+    this.serviceGroupEditController.showDetails(row);
+
+  }
+
+  onEditMetadataRow(row:any){
+    alert("edit" + row);
+  }
+  onDeleteMetadataRowActionClicked(row:any){
+    alert("delete" + row);
+  }
+}
diff --git a/smp-angular/src/app/service-group-edit/service-group-metadata-list-dialog/service-group-metadata-list-dialog.component.css b/smp-angular/src/app/service-group-edit/service-group-metadata-list-dialog/service-group-metadata-list-dialog.component.css
deleted file mode 100644
index 7389196e506b0fce5076d0efd30cd2795f7454bd..0000000000000000000000000000000000000000
--- a/smp-angular/src/app/service-group-edit/service-group-metadata-list-dialog/service-group-metadata-list-dialog.component.css
+++ /dev/null
@@ -1,41 +0,0 @@
-label:hover, label:active, input:hover + label, input:active + label {
-  color: #3f51b5;
-}
-
-.divTable {
-  display: table;
-  width: 100%;
-}
-
-.divTableRow {
-  display: table-row;
-}
-
-.divTableHeading {
-  background-color: #EEE;
-  display: table-header-group;
-}
-
-.divTableCell, .divTableHead {
-  /*border: 1px solid #999999;*/
-  display: table-cell;
-  padding: 3px 3px;
-  text-align: center;
-}
-
-.divTableHeading {
-  background-color: #EEE;
-  display: table-header-group;
-  font-weight: bold;
-}
-
-.divTableFoot {
-  background-color: #EEE;
-  display: table-footer-group;
-  font-weight: bold;
-}
-
-.divTableBody {
-  display: table-row-group;
-}
-
diff --git a/smp-angular/src/app/service-group-edit/service-group-metadata-list-dialog/service-group-metadata-list-dialog.component.html b/smp-angular/src/app/service-group-edit/service-group-metadata-list-dialog/service-group-metadata-list-dialog.component.html
deleted file mode 100644
index 3527a80f2e88b3c6540f5f79117a493b4dc03c0f..0000000000000000000000000000000000000000
--- a/smp-angular/src/app/service-group-edit/service-group-metadata-list-dialog/service-group-metadata-list-dialog.component.html
+++ /dev/null
@@ -1,75 +0,0 @@
-<h2 mat-dialog-title>ServiceGroup Metadata list</h2>
-<mat-dialog-content style="height:460px;width:950px">
-
-
-  <ngx-datatable
-    id="metadataTable"
-    class="material striped"
-    style="height: 400px;width: 920px;"
-    [rows]="rows"
-    [columns]="columnPicker.selectedColumns"
-    [columnMode]="'force'"
-    [headerHeight]="50"
-    [footerHeight]="50"
-    [rowHeight]="'auto'"
-    [scrollbarH]="true"
-    [externalPaging]="true"
-    [externalSorting]="true"
-    [loadingIndicator]="loading"
-    [count]="count"
-    [offset]="offset"
-    [limit]="rowLimiter.pageSize"
-    [sorts]="[{prop: 'received', dir: 'desc'}]"
-
-    [selected]="selected"
-    [selectionType]="'multi'"
-   >
-  </ngx-datatable>
-
-
-  <ng-template #rowActions let-row="row" let-value="value" ngx-datatable-cell-template>
-
-    <button mat-icon-button color="primary"
-            (click)="editRowButtonAction(row)" id="editButtonRow{{row.$$index}}_id" tooltip="Edit">
-      <mat-icon>edit</mat-icon>
-    </button>
-
-
-    <button mat-icon-button color="primary" (click)="deleteRowButtonAction(row)"
-            id="deleteButtonRow{{row.$$index}}_id" tooltip="Delete">
-      <mat-icon>delete</mat-icon>
-    </button>
-  </ng-template>
-
-</mat-dialog-content>
-
-<mat-dialog-actions>
-  <div class="group-action-button">
-
-    <button mat-raised-button color="primary" (click)="newButtonAction()"
-            id="add_id">
-      <mat-icon>add</mat-icon>
-      <span>New</span>
-    </button>
-
-    <button mat-raised-button color="primary" [disabled]="!isRowSelected()" (click)="editButtonAction()"
-            id="edit_id">
-      <mat-icon>edit</mat-icon>
-      <span>Edit</span>
-    </button>
-
-    <button mat-raised-button color="primary" [disabled]="!isRowSelected()" (click)="deleteButtonAction()"
-            id="resendbutton_id">
-      <mat-icon>delete</mat-icon>
-      <span>Delete</span>
-    </button>
-    <div style="background-color: #03A9F4; display: inline-block; width: 3px; height: 20px; margin-right: 8px">&nbsp;
-    </div>
-    <button id="ServiceGroupMetadataListCloseButton" mat-raised-button color="primary" (click)="dialogRef.close({})"
-            style="margin-top:10px">
-      <mat-icon>close</mat-icon>
-      <span>Close</span>
-    </button>
-  </div>
-</mat-dialog-actions>
-
diff --git a/smp-angular/src/app/service-group-edit/service-group-metadata-list-dialog/service-group-metadata-list-dialog.component.spec.ts b/smp-angular/src/app/service-group-edit/service-group-metadata-list-dialog/service-group-metadata-list-dialog.component.spec.ts
deleted file mode 100644
index d01831eaf44f03a3efa49e631290cfd493e2821b..0000000000000000000000000000000000000000
--- a/smp-angular/src/app/service-group-edit/service-group-metadata-list-dialog/service-group-metadata-list-dialog.component.spec.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { ServiceGroupMetadataListDialogComponent } from './service-group-metadata-list-dialog.component';
-
-describe('ServiceGroupMetadataListDialogComponent', () => {
-  let component: ServiceGroupMetadataListDialogComponent;
-  let fixture: ComponentFixture<ServiceGroupMetadataListDialogComponent>;
-
-  beforeEach(async(() => {
-    TestBed.configureTestingModule({
-      declarations: [ ServiceGroupMetadataListDialogComponent ]
-    })
-    .compileComponents();
-  }));
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(ServiceGroupMetadataListDialogComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});
diff --git a/smp-angular/src/app/service-group-edit/service-group-metadata-list-dialog/service-group-metadata-list-dialog.component.ts b/smp-angular/src/app/service-group-edit/service-group-metadata-list-dialog/service-group-metadata-list-dialog.component.ts
deleted file mode 100644
index f4e0d3933a600b5cc1190a04531ec9fff97a358d..0000000000000000000000000000000000000000
--- a/smp-angular/src/app/service-group-edit/service-group-metadata-list-dialog/service-group-metadata-list-dialog.component.ts
+++ /dev/null
@@ -1,100 +0,0 @@
-import {Component, EventEmitter, OnInit, TemplateRef, ViewChild} from '@angular/core';
-import {MatDialog, MatDialogRef} from '@angular/material';
-import {ColumnPicker} from '../../common/column-picker/column-picker.model';
-import {ServiceGroupController} from '../service-group-controller';
-import {RowLimiter} from '../../common/row-limiter/row-limiter.model';
-import {ServiceGroupExtensionDialogComponent} from '../service-group-extension-dialog/service-group-extension-dialog.component';
-import {ServiceGroupMetadataDialogComponent} from '../service-group-metadata-dialog/service-group-metadata-dialog.component';
-
-@Component({
-  selector: 'app-messagelog-dialog',
-  templateUrl: './service-group-metadata-list-dialog.component.html',
-  styleUrls: ['./service-group-metadata-list-dialog.component.css']
-})
-export class ServiceGroupMetadataListDialogComponent implements OnInit {
-
-  @ViewChild('rowActions') rowActions: TemplateRef<any>;
-
-  columnPicker: ColumnPicker = new ColumnPicker();
-  columnActions:any;
-  rowLimiter: RowLimiter = new RowLimiter();
-  selected = [];
-
-  filter: any = {};
-  loading: boolean = false;
-  rows = [];
-  count: number = 0;
-  offset: number = 0;
-  //default value
-  orderBy: string = null;
-  //default value
-  asc: boolean = false;
-
-  messageResent = new EventEmitter(false);
-
-  constructor(public dialogRef: MatDialogRef<ServiceGroupMetadataListDialogComponent>, public dialog: MatDialog) {
-  }
-
-  ngOnInit() {
-    this.columnPicker.allColumns = [
-      {
-        name: 'Document Id',
-        prop: 'documentId',
-        width: 200,
-      },
-      {
-        name: 'Document schema',
-        prop: 'documentSchema',
-        width: 200,
-      }, {
-        cellTemplate: this.rowActions,
-        name: 'Actions',
-        width: 60,
-        sortable: false
-      }
-    ];
-
-    this.columnPicker.selectedColumns = this.columnPicker.allColumns.filter(col => {
-      return ["Document Id", "Document schema", "Actions"].indexOf(col.name) != -1
-    });
-
-    this.rows = [{
-      documentId:"urn:be:ncpb",
-      documentSchema:"ehealth-docid-qns",
-    },
-      {
-        documentId:"urn:pl:ncpb",
-        documentSchema:"ehealth-docid-qns",
-      },
-      {
-        documentId:"urn:ge:ncpb",
-        documentSchema:"ehealth-docid-qns",
-      },
-      {
-        documentId:"urn:si:ncpb",
-        documentSchema:"ehealth-docid-qns",
-      }];
-    this.count=3;
-    this.offset=0;
-    this.loading = false;
-  }
-
-  isRowSelected() {
-    if (this.selected)
-      return true;
-
-    return false;
-  }
-
-  newButtonAction (){this.details()}
-  editButtonAction (){this.details()}
-  deleteButtonAction (){}
-
-  details() {
-    let dialogRef: MatDialogRef<ServiceGroupMetadataDialogComponent> = this.dialog.open(ServiceGroupMetadataDialogComponent);
-    //dialogRef.componentInstance.servicegroup = row;
-    dialogRef.afterClosed().subscribe(result => {
-      //Todo:
-    });
-  }
-}
diff --git a/smp-angular/src/app/service-group-edit/service-group-ro-id.model.ts b/smp-angular/src/app/service-group-edit/service-group-ro-id.model.ts
deleted file mode 100644
index 003f2db4347f667f2b4fd755a873a6768a340cd8..0000000000000000000000000000000000000000
--- a/smp-angular/src/app/service-group-edit/service-group-ro-id.model.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export interface ServiceGroupROId {
-  participantId: string;
-  participantSchema: string;
-}
diff --git a/smp-angular/src/app/service-group-edit/service-group-ro.model.ts b/smp-angular/src/app/service-group-edit/service-group-ro.model.ts
deleted file mode 100644
index 8b29fd39670215a747894b21745d288d5db961d0..0000000000000000000000000000000000000000
--- a/smp-angular/src/app/service-group-edit/service-group-ro.model.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { ServiceGroupROId } from './service-group-ro-id.model';
-import {SearchTableEntity} from '../common/search-table/search-table-entity.model';
-
-export interface ServiceGroupRo extends SearchTableEntity {
-  serviceGroupROId: ServiceGroupROId;
-  domain: string;
-}
diff --git a/smp-angular/src/app/service-group-edit/service-group.component.html b/smp-angular/src/app/service-group-edit/service-group.component.html
deleted file mode 100644
index 0bdf69b5bfde596a446e45656788df3b8e5b5049..0000000000000000000000000000000000000000
--- a/smp-angular/src/app/service-group-edit/service-group.component.html
+++ /dev/null
@@ -1,73 +0,0 @@
-<smp-search-table
-  page_id='participants_id'
-  title='Participants'
-  [columnPicker]="columnPicker"
-  url="rest/servicegroup"
-  [additionalToolButtons]="additionalToolButtons"
-  [searchPanel]="searchPanel"
-  [filter]="filter"
-  [searchTableController]="serviceGroupController"
->
-
-  <ng-template #rowMetadataAction let-row="row" let-value="value" ngx-datatable-cell-template>
-
-    <button mat-button color="primary"
-            (click)="metadataRowButtonAction(row)" id="metadataRowButtonAction{{row.$$index}}_id" tooltip="Metadata">
-      <mat-icon>view_list</mat-icon>
-      <span>Metadata</span>
-    </button>
-
-  </ng-template>
-
-  <ng-template #rowExtensionAction let-row="row" let-value="value" ngx-datatable-cell-template>
-
-    <button mat-button color="primary"
-            (click)="extensionRowButtonAction(row)" id="extensionRowButtonAction{{row.$$index}}_id" tooltip="Extension">
-      <mat-icon>code</mat-icon>
-      <span>Extension</span>
-    </button>
-
-  </ng-template>
-
-  <ng-template #searchPanel>
-    <mat-form-field>
-      <input matInput placeholder="Participant Id" name="messageId" [(ngModel)]="filter.messageId"
-             #messageId="ngModel" id="messageid_id">
-    </mat-form-field>
-    <mat-form-field>
-      <input matInput placeholder="Participant schema" name="patricipantSchema" [(ngModel)]="filter.messageId"
-             #messageId="ngModel" id="participanschema_id">
-    </mat-form-field>
-    <mat-select placeholder="Domain " [(ngModel)]="filter.messageStatus" name="messageStatus"
-               id="messagestatus_id">
-      <mat-option [value]="''">
-      </mat-option>
-      <mat-option *ngFor="let mstatus of msgStatus" [value]="mstatus">
-        {{mstatus}}
-      </mat-option>
-    </mat-select>
-  </ng-template>
-
-
-  <ng-template #additionalToolButtons>
-
-    <div style="background-color: #03A9F4; display: inline-block; width: 3px; height: 100%; margin-right: 8px">&nbsp;
-    </div>
-
-
-    <button mat-raised-button color="primary"
-            id="metadatabutton_id">
-      <mat-icon>view_list</mat-icon>
-      <span>Metadata</span>
-    </button>
-
-    <button mat-raised-button color="primary"
-            id="extensionbutton_id">
-      <mat-icon>code</mat-icon>
-      <span>Extension</span>
-    </button>
-
-
-  </ng-template>
-
-</smp-search-table>
diff --git a/smp-angular/src/app/service-group-edit/service-group.component.ts b/smp-angular/src/app/service-group-edit/service-group.component.ts
deleted file mode 100644
index 3edbb969c6be831ee961e2b6427594dc51ff3688..0000000000000000000000000000000000000000
--- a/smp-angular/src/app/service-group-edit/service-group.component.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import {Component, OnInit, TemplateRef, ViewChild} from '@angular/core';
-import {ColumnPicker} from '../common/column-picker/column-picker.model';
-import {MatDialog, MatDialogRef} from '@angular/material';
-import {AlertService} from '../alert/alert.service';
-import {ServiceGroupController} from './service-group-controller';
-import {HttpClient} from '@angular/common/http';
-
-@Component({
-  moduleId: module.id,
-  templateUrl:'./service-group.component.html',
-  styleUrls: ['./service-group.component.css']
-})
-export class ServiceGroupComponent implements OnInit {
-
-  @ViewChild('rowMetadataAction') rowMetadataAction: TemplateRef<any>
-  @ViewChild('rowExtensionAction') rowExtensionAction: TemplateRef<any>
-  @ViewChild('rowActions') rowActions: TemplateRef<any>;
-
-  columnPicker: ColumnPicker = new ColumnPicker();
-  serviceGroupController: ServiceGroupController;
-  filter: any = {};
-
-  constructor(protected http: HttpClient, protected alertService: AlertService, public dialog: MatDialog) {
-  }
-
-  ngOnInit() {
-    this.serviceGroupController = new ServiceGroupController(this.dialog);
-
-    this.columnPicker.allColumns = [
-      {
-        name: 'Participant Id',
-        prop: 'serviceGroupROId.participantId',
-        width: 275
-      },
-      {
-        name: 'Participant schema',
-        prop: 'serviceGroupROId.participantSchema',
-      },
-      {
-        name: 'Domain',
-        prop: 'domain',
-      },
-      {
-        cellTemplate: this.rowMetadataAction,
-        name: 'Matadata',
-        width: 80,
-        sortable: false
-      },
-      {
-        cellTemplate: this.rowExtensionAction,
-        name: 'Extesion',
-        width: 80,
-        sortable: false
-      }
-    ];
-
-    this.columnPicker.selectedColumns = this.columnPicker.allColumns.filter(col => {
-      return ["Participant Id", "Participant schema", "Domain", "Matadata", "Extesion"].indexOf(col.name) != -1
-    });
-  }
-
-  extensionRowButtonAction(row: any){
-    this.serviceGroupController.showExtension(row);
-  }
-
-  metadataRowButtonAction(row: any){
-    this.serviceGroupController.showMetadataList(row);
-  }
-
-  details(row: any) {
-    this.serviceGroupController.showDetails(row);
-
-  }
-}
diff --git a/smp-angular/src/app/service-group-edit/service-metadata-edit-ro.model.ts b/smp-angular/src/app/service-group-edit/service-metadata-edit-ro.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..abff0abd849f755adba43986ff04c169246e8b85
--- /dev/null
+++ b/smp-angular/src/app/service-group-edit/service-metadata-edit-ro.model.ts
@@ -0,0 +1,10 @@
+import {SearchTableEntity} from "../common/search-table/search-table-entity.model";
+import {ServiceGroupDetailsDialogComponent} from "./service-group-details-dialog/service-group-details-dialog.component";
+
+export interface ServiceMetadataEditRo extends SearchTableEntity  {
+  id: number;
+  documentIdentifier: string;
+  documentIdentifierScheme: string;
+  smlSubdomain: string;
+  domainCode: string;
+}
diff --git a/smp-angular/src/app/service-group-search/service-group-search.component.html b/smp-angular/src/app/service-group-search/service-group-search.component.html
index d9f40a701964ec8f183017c322dffa907e7b87e9..ab20e7b28e73e24901b81a68d1a17ed255004cb6 100644
--- a/smp-angular/src/app/service-group-search/service-group-search.component.html
+++ b/smp-angular/src/app/service-group-search/service-group-search.component.html
@@ -2,7 +2,7 @@
   page_id='search_id'
   title='Search'
   [columnPicker]="columnPicker"
-  url="rest/search"
+  [url]="baseUrl"
   [additionalToolButtons]="additionalToolButtons"
   [searchPanel]="searchPanel"
   [filter]="filter"
@@ -67,42 +67,26 @@
       No service metadata
     </div>
     <div *ngIf="row.serviceMetadata.length !== 0" >
-
-      <!-- ngx-datatable
+      <ngx-datatable
         class='material striped'
         style="width: 80%"
         [loadingIndicator]="loading"
         [rows]='row.serviceMetadata'
-        [columns]='[{name:"Domain", prop:"domainCode", maxWidth: 250 },{name:"Document identifier scheme",prop:"documentIdentifierScheme",maxWidth: 350},{name:"Document identifier", prop:"documentIdentifier"},{name:"OASIS SMP URL",maxWidth: 350}]'
-        [columnMode]='"force"'
+         [columnMode]='"force"'
         [headerHeight]='50'
         [footerHeight]='50'
         [rowHeight]='"auto"'>
-        <ng-template #rowMetadataSMPUrlLinkAction let-row="smdRow" let-value="value" ngx-datatable-cell-template>
+        <ngx-datatable-column prop="domainCode" name="Domain" maxWidth="250" ></ngx-datatable-column>
+        <ngx-datatable-column prop="documentIdentifierScheme" name="Document identifier scheme" maxWidth="350" ></ngx-datatable-column>
+        <ngx-datatable-column prop="documentIdentifier" name="Document identifier" maxWidth="250" ></ngx-datatable-column>
+        <ngx-datatable-column [cellTemplate]="rowMetadataSMPUrlLinkAction" name="URL" maxWidth="250" ></ngx-datatable-column>
 
+        <ng-template #rowMetadataSMPUrlLinkAction let-rowSmd="row" ngx-datatable-cell-template>
           <a target="_blank"
-             href="{{contextPath}}{{row.participantScheme}}::{{row.participantIdentifier}}/services/{{smdRow.documentIdentifierScheme}}::{{smdRow.documentIdentifier}}" >Open URL</a>
-
+             href="{{contextPath}}{{row.participantScheme}}::{{row.participantIdentifier}}/services/{{rowSmd.documentIdentifierScheme}}::{{rowSmd.documentIdentifier}}" >Open URL</a>
         </ng-template>
-      </ngx-datatable -->
-
-      <table style="width: 80%">
-        <tr>
-          <th>Domain</th>
-          <th>Document identifier scheme</th>
-          <th>Document identifier</th>
-          <th>OASIS SMP URL</th>
-        </tr>
-        <tr *ngFor="let smd of row.serviceMetadata">
-          <td style="width: 100em">{{smd.domainCode}}</td>
-          <td style="width: 250em">{{smd.documentIdentifierScheme}}</td>
-          <td >{{smd.documentIdentifier}}</td>
-          <td style="width: 50em">
-            <a target="_blank"
-               href="{{contextPath}}{{row.participantScheme}}::{{row.participantIdentifier}}/services/{{smd.documentIdentifierScheme}}::{{smd.documentIdentifier}}">OASIS ServiceMetadata URL</a>
-          </td>
-        </tr>
-      </table>
+      </ngx-datatable>
+
     </div>
   </ng-template>
 
diff --git a/smp-angular/src/app/service-group-search/service-group-search.component.ts b/smp-angular/src/app/service-group-search/service-group-search.component.ts
index c2768351135ab9b90256a7ec3973d8cd0198a228..04d95e9f0e346102347092d7260c49151b7cab46 100644
--- a/smp-angular/src/app/service-group-search/service-group-search.component.ts
+++ b/smp-angular/src/app/service-group-search/service-group-search.component.ts
@@ -1,3 +1,4 @@
+///<reference path="../smp.constants.ts"/>
 import {Component, OnInit, TemplateRef, ViewChild} from '@angular/core';
 import {ColumnPicker} from '../common/column-picker/column-picker.model';
 import {MatDialog, MatDialogRef} from '@angular/material';
@@ -7,6 +8,7 @@ import {HttpClient} from '@angular/common/http';
 import {Observable} from "rxjs/index";
 import {SearchTableResult} from "../common/search-table/search-table-result.model";
 import {DomainRo} from "../domain/domain-ro.model";
+import {SmpConstants} from "../smp.constants";
 
 @Component({
   moduleId: module.id,
@@ -25,9 +27,10 @@ export class ServiceGroupSearchComponent implements OnInit {
   domainlist: Array<any>;
   domainObserver:  Observable< SearchTableResult> ;
   contextPath: string = location.pathname.substring(0,location.pathname.length -3); // remove /ui s
+  baseUrl: string = SmpConstants.REST_SEARCH;
 
   constructor(protected http: HttpClient, protected alertService: AlertService, public dialog: MatDialog) {
-    this.domainObserver = this.http.get<SearchTableResult>('rest/domain');
+    this.domainObserver = this.http.get<SearchTableResult>(SmpConstants.REST_DOMAIN);
     this.domainObserver.subscribe((domains: SearchTableResult) => {
       this.domainlist = new Array(domains.serviceEntities.length)
         .map((v, index) => domains.serviceEntities[index] as DomainRo);
@@ -39,7 +42,7 @@ export class ServiceGroupSearchComponent implements OnInit {
   }
 
   ngOnDestroy() {
-  //  this.domainObserver.unsubscribe();
+
   }
 
   ngOnInit() {
@@ -47,10 +50,10 @@ export class ServiceGroupSearchComponent implements OnInit {
 
     this.columnPicker.allColumns = [
       {
-        name: 'Metadata count',
+        name: 'Metadata size',
         prop: 'serviceMetadata.length',
-        width: 60,
-        maxWidth: 80
+        width: 80,
+        maxWidth: 120
       },
       {
         name: 'Participant scheme',
@@ -79,7 +82,7 @@ export class ServiceGroupSearchComponent implements OnInit {
 
 
     this.columnPicker.selectedColumns = this.columnPicker.allColumns.filter(col => {
-      return ["Metadata count", "Participant scheme", "Participant identifier","OASIS ServiceGroup URL"].indexOf(col.name) != -1
+      return ["Metadata size", "Participant scheme", "Participant identifier","OASIS ServiceGroup URL"].indexOf(col.name) != -1
     });
   }
 
diff --git a/smp-angular/src/app/smp.constants.ts b/smp-angular/src/app/smp.constants.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f78f13a5fb3ef36b66c92f53b7bdcce8309bf047
--- /dev/null
+++ b/smp-angular/src/app/smp.constants.ts
@@ -0,0 +1,7 @@
+export class SmpConstants {
+
+  public static readonly REST_DOMAIN = 'rest/domain';
+  public static readonly REST_USER = 'rest/user';
+  public static readonly REST_SEARCH = 'rest/search';
+  public static readonly REST_EDIT = 'rest/servicegroup';
+}
diff --git a/smp-angular/src/app/user/certificate-ro.model.ts b/smp-angular/src/app/user/certificate-ro.model.ts
index e697f01b35a8ee4f7042bd61fa21d9cb99f040d9..bb66f1de22a6312cf70397fc8560850e1e6beded 100644
--- a/smp-angular/src/app/user/certificate-ro.model.ts
+++ b/smp-angular/src/app/user/certificate-ro.model.ts
@@ -1,7 +1,9 @@
 export interface CertificateRo {
+  certificateId: string;
   subject: string;
   validFrom: Date;
   validUntil: Date;
   issuer: string;
+  serialNumber: string;
   fingerprints: string;
 }
diff --git a/smp-angular/src/app/user/certificate.service.ts b/smp-angular/src/app/user/certificate.service.ts
index 284c7c190efb0ec46550a4e44150035f466535a4..d7af521f998cd9dac938c5ae1c1ae803ec511ec9 100644
--- a/smp-angular/src/app/user/certificate.service.ts
+++ b/smp-angular/src/app/user/certificate.service.ts
@@ -8,8 +8,14 @@ export class CertificateService {
 
   constructor(private http: HttpClient) {}
 
-  uploadCertificate$(payload, userName: string): Observable<CertificateRo> {
-    return this.http.put<CertificateRo>(`rest/user/${userName}/certificate`, payload);
+  uploadCertificate$(payload, username: string): Observable<CertificateRo> {
+    return this.http.put<CertificateRo>(`rest/user/${username}/certificate`, payload);
   }
 
+
+
+  onUpload(file) {
+
+    return this.http.post<CertificateRo>('rest/user/certdata',file, )
+  }
 }
diff --git a/smp-angular/src/app/user/user-controller.ts b/smp-angular/src/app/user/user-controller.ts
index 0eee2a77ea9c75011bacbcbf5bc5b82e27163b8e..448282595e98a5219c33d8118e20ddd60d3e3dee 100644
--- a/smp-angular/src/app/user/user-controller.ts
+++ b/smp-angular/src/app/user/user-controller.ts
@@ -25,7 +25,9 @@ export class UserController implements SearchTableController {
 
   public newRow(): UserRo {
     return {
-      userName: '',
+      id: null,
+      index: null,
+      username: '',
       email: '',
       role: '',
       status: SearchTableEntityStatus.NEW
diff --git a/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.html b/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.html
index 3ced86082ea021159cfd019d1f65262fdf35516c..83d39a4be1c6ad94eac020ed0c407b734d5285c1 100644
--- a/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.html
+++ b/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.html
@@ -13,8 +13,8 @@
           <div class="panel">
             <div style="margin-top:15px;">
               <mat-form-field style="width:100%">
-                <input matInput placeholder="Username" name="userName" id="userName" [value]="current.userName" (blur)="updateUserName($event)" [formControl]="userForm.controls['userName']" maxlength="255" required>
-                <div *ngIf="userForm.controls['userName'].hasError('required') && userForm.controls['userName'].touched" style="color:red; font-size: 70%">You should type an username</div>
+                <input matInput placeholder="Username" name="username" id="username" [value]="current.username" (blur)="updateUserName($event)" [formControl]="userForm.controls['username']" maxlength="255" required>
+                <div *ngIf="userForm.controls['username'].hasError('required') && userForm.controls['username'].touched" style="color:red; font-size: 70%">You should type an username</div>
               </mat-form-field>
             </div>
 
@@ -80,6 +80,13 @@
                 <input matInput placeholder="Fingerprints" name="fingerPrint" value="{{current.certificate?.fingerprints}}" id="fingerPrint_id">
               </mat-form-field>
             </fieldset>
+
+            <input
+              type="file" (change)="onFileChanged($event)"
+              #fileInput>
+            <button (click)="onUpload()">Upload!</button>
+
+
             <label class="custom-file-upload">
               <input #fileInput type="file" id="custom-file-upload" accept=".cer" (change)="uploadCertificate()" [disabled]="!certificateSwitch">
               <span class="custom-file-upload-inner">Import</span>
diff --git a/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.ts b/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.ts
index 90dd083ec00ff4fa0234b9c824990c5decf92fc7..a5b36c61bc266a5007337ef0b4d9dc46bfc5f010 100644
--- a/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.ts
+++ b/smp-angular/src/app/user/user-details-dialog/user-details-dialog.component.ts
@@ -8,6 +8,10 @@ import {UserRo} from '../user-ro.model';
 import {SearchTableEntityStatus} from '../../common/search-table/search-table-entity-status.model';
 import {AlertService} from '../../alert/alert.service';
 import {CertificateService} from '../certificate.service';
+import {Observable} from "rxjs/index";
+import {CertificateRo} from "../certificate-ro.model";
+import {SearchTableResult} from "../../common/search-table/search-table-result.model";
+
 
 @Component({
   selector: 'user-details-dialog',
@@ -37,6 +41,8 @@ export class UserDetailsDialogComponent {
   @ViewChild('fileInput')
   private fileInput;
 
+
+
   private passwordConfirmationValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => {
     const password = control.get('password');
     const confirmation = control.get('confirmation');
@@ -60,7 +66,7 @@ export class UserDetailsDialogComponent {
         certificate: data.row.certificate,
       }
       : {
-        userName: '',
+        username: '',
         email: '',
         password: '',
         confirmation: '',
@@ -70,12 +76,10 @@ export class UserDetailsDialogComponent {
       };
 
     this.userForm = fb.group({
-      'userName': new FormControl({value: this.current.userName, disabled: this.editMode}, this.editMode ? Validators.nullValidator : null),
+      'username': new FormControl({value: this.current.username, disabled: this.editMode}, this.editMode ? Validators.nullValidator : null),
       'role': new FormControl(this.current.role, Validators.required),
       'password': new FormControl(this.current.password, [Validators.required, Validators.pattern(this.passwordPattern)]),
-      'confirmation': new FormControl(this.current.password, Validators.pattern(this.passwordPattern)),
-    }, {
-      validator: this.passwordConfirmationValidator
+      'confirmation': new FormControl(this.current.password, Validators.pattern(this.passwordPattern)), }, {  validator: this.passwordConfirmationValidator
     });
 
     this.userService.getUserRoles$().subscribe(userRoles => {
@@ -91,7 +95,7 @@ export class UserDetailsDialogComponent {
   }
 
   updateUserName(event) {
-    this.current.userName = event.target.value;
+    this.current.username = event.target.value;
   }
 
   updatePassword(event) {
@@ -137,4 +141,21 @@ export class UserDetailsDialogComponent {
 
     reader.readAsArrayBuffer(file);
   }
+
+
+  // example
+  selectedFile: File;
+  obrs:  Observable< CertificateRo> ;
+  certData:  CertificateRo;
+  onFileChanged(event) {
+    this.selectedFile = event.target.files[0]
+  }
+
+  onUpload() {
+     this.obrs = this.certificateService.onUpload(this.selectedFile);
+    this.obrs.subscribe((cert: CertificateRo) => {
+      this.certData = cert;
+    });
+
+  }
 }
diff --git a/smp-angular/src/app/user/user-ro.model.ts b/smp-angular/src/app/user/user-ro.model.ts
index c6e8dfa9a6ae7d38522eb3a08c741d3216b41836..6dcc00e2b6ec5f86942ee094a592ba1e8826e864 100644
--- a/smp-angular/src/app/user/user-ro.model.ts
+++ b/smp-angular/src/app/user/user-ro.model.ts
@@ -2,7 +2,8 @@ import {SearchTableEntity} from '../common/search-table/search-table-entity.mode
 import {CertificateRo} from './certificate-ro.model';
 
 export interface UserRo extends SearchTableEntity {
-  userName: string;
+  id: number;
+  username: string;
   email: string;
   password?: string;
   role: string;
diff --git a/smp-angular/src/app/user/user.component.html b/smp-angular/src/app/user/user.component.html
index 4ff6670bfabbd16692fdef038dc1917cb8c64f75..00fc2f9ece5894755c6c89f92a3df8cca10c1254 100644
--- a/smp-angular/src/app/user/user.component.html
+++ b/smp-angular/src/app/user/user.component.html
@@ -12,7 +12,7 @@
 
   <ng-template #searchPanel>
     <mat-form-field>
-      <input matInput placeholder="Username" name="Username" [(ngModel)]="filter.userName" #messageId="ngModel">
+      <input matInput placeholder="Username" name="Username" [(ngModel)]="filter.username" #messageId="ngModel">
     </mat-form-field>
   </ng-template>
 </smp-search-table>
diff --git a/smp-angular/src/app/user/user.component.ts b/smp-angular/src/app/user/user.component.ts
index 294159cc257ff097752d520adf7dcd37b1fbb972..4ae256bc10e8ff1baeee53d3247fc95abf49b580 100644
--- a/smp-angular/src/app/user/user.component.ts
+++ b/smp-angular/src/app/user/user.component.ts
@@ -28,7 +28,7 @@ export class UserComponent implements OnInit {
     this.columnPicker.allColumns = [
       {
         name: 'Username',
-        prop: 'userName',
+        prop: 'username',
         canAutoResize: true
       },
       {
diff --git a/smp-server-library/pom.xml b/smp-server-library/pom.xml
index bdc60fe6fae4edc37b01e55a241f24bea8179004..bb34c4f79c8cfe999f7af76910cde763f1ca2976 100644
--- a/smp-server-library/pom.xml
+++ b/smp-server-library/pom.xml
@@ -51,6 +51,10 @@
             <groupId>eu.europa.ec.bdmsl</groupId>
             <artifactId>bdmsl-client</artifactId>
         </dependency>
+        <dependency>
+            <groupId>eu.europa.ec.edelivery</groupId>
+            <artifactId>edelivery-springsecurity-2-way-ssl-auth</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/CommonColumnsLengths.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/CommonColumnsLengths.java
index b9883b6b03336ab625bd2cfbbfc9af7dafd9b3ce..bb50e6f397976ec7d3785d5118250979913e4a5c 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/CommonColumnsLengths.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/CommonColumnsLengths.java
@@ -29,5 +29,8 @@ public class CommonColumnsLengths {
     public static final int MAX_SML_SUBDOMAIN_LENGTH = 256;
     public static final int MAX_SML_SMP_ID_LENGTH = 256;
     public static final int MAX_USER_ROLE_LENGTH = 256;
+    public static final int MAX_TEXT_LENGTH_512 = 512;
+    public static final int MAX_TEXT_LENGTH_128 = 128;
+
 
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBCertificate.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBCertificate.java
index cca264671cea29ee975eacc1b4862077c870df12..93787a203689e7682c97f649d085b2f156a2eba2 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBCertificate.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBCertificate.java
@@ -39,6 +39,15 @@ public class DBCertificate extends BaseEntity {
     private LocalDateTime validFrom;
     @Column(name = "VALID_TO")
     private LocalDateTime validTo;
+
+    @Column(name = "subject", length = CommonColumnsLengths.MAX_TEXT_LENGTH_512)
+    private String  subject;
+    @Column(name = "issuer", length = CommonColumnsLengths.MAX_TEXT_LENGTH_512)
+    private String  issuer;
+    @Column(name = "serialNumber", length = CommonColumnsLengths.MAX_TEXT_LENGTH_128)
+    private String  serialNumber;
+
+
     @Column(name = "CREATED_ON" , nullable = false)
     LocalDateTime createdOn;
     @Column(name = "LAST_UPDATED_ON", nullable = false)
@@ -93,6 +102,31 @@ public class DBCertificate extends BaseEntity {
         this.dbUser = dbUser;
     }
 
+
+    public String getSubject() {
+        return subject;
+    }
+
+    public void setSubject(String subject) {
+        this.subject = subject;
+    }
+
+    public String getIssuer() {
+        return issuer;
+    }
+
+    public void setIssuer(String issuer) {
+        this.issuer = issuer;
+    }
+
+    public String getSerialNumber() {
+        return serialNumber;
+    }
+
+    public void setSerialNumber(String serialNumber) {
+        this.serialNumber = serialNumber;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
@@ -138,4 +172,5 @@ public class DBCertificate extends BaseEntity {
     public void setLastUpdatedOn(LocalDateTime lastUpdatedOn) {
         this.lastUpdatedOn = lastUpdatedOn;
     }
+
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CertificateRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CertificateRO.java
new file mode 100644
index 0000000000000000000000000000000000000000..37f7a40acb7ef6224a055828af32c81025fd908d
--- /dev/null
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/CertificateRO.java
@@ -0,0 +1,87 @@
+package eu.europa.ec.edelivery.smp.data.ui;
+
+
+
+
+
+import eu.europa.ec.edelivery.smp.data.model.CommonColumnsLengths;
+
+import javax.persistence.Column;
+import javax.persistence.Id;
+import java.math.BigInteger;
+import java.time.LocalDateTime;
+
+
+/**
+ * @author Joze Rihtarsic
+ * @since 4.1
+ */
+public class CertificateRO extends BaseRO {
+
+
+
+    private static final long serialVersionUID = -4971552086560325302L;
+
+    private String certificateId;
+    private String subject;
+    private String issuer;
+    private String serialNumber;
+    private LocalDateTime validFrom;
+    private LocalDateTime validTo;
+
+    public CertificateRO(){
+
+    }
+
+    public static long getSerialVersionUID() {
+        return serialVersionUID;
+    }
+
+    public String getCertificateId() {
+        return certificateId;
+    }
+
+    public void setCertificateId(String certificateId) {
+        this.certificateId = certificateId;
+    }
+
+    public String getSubject() {
+        return subject;
+    }
+
+    public void setSubject(String subject) {
+        this.subject = subject;
+    }
+
+    public String getIssuer() {
+        return issuer;
+    }
+
+    public void setIssuer(String issuer) {
+        this.issuer = issuer;
+    }
+
+    public String getSerialNumber() {
+        return serialNumber;
+    }
+
+    public void setSerialNumber(String serialNumber) {
+        this.serialNumber = serialNumber;
+    }
+
+    public LocalDateTime getValidFrom() {
+        return validFrom;
+    }
+
+    public void setValidFrom(LocalDateTime validFrom) {
+        this.validFrom = validFrom;
+    }
+
+    public LocalDateTime getValidTo() {
+        return validTo;
+    }
+
+    public void setValidTo(LocalDateTime validTo) {
+        this.validTo = validTo;
+    }
+}
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupRO.java
index 9755ed0418a1d82b2d9dadafef0385f25377b1ac..f3da826f10980d93b21242e5ac11f9c0a52952d6 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupRO.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupRO.java
@@ -15,22 +15,23 @@ public class ServiceGroupRO extends BaseRO {
 
 
     private static final long serialVersionUID = -7523221767041516157L;
+    private Long id;
     private String participantIdentifier;
     private String participantScheme;
     private boolean smlRegistered = false;
     private List<ServiceMetadataRO> lstServiceMetadata = new ArrayList<>();
+    private List<UserRO> lstUser = new ArrayList<>();
 
 
 
-    private String domain;
 
 
-    public String getDomain() {
-        return domain;
+    public Long getId() {
+        return id;
     }
 
-    public void setDomain(String domain) {
-        this.domain = domain;
+    public void setId(Long id) {
+        this.id = id;
     }
 
     public String getParticipantIdentifier() {
@@ -61,5 +62,8 @@ public class ServiceGroupRO extends BaseRO {
     public List<ServiceMetadataRO> getServiceMetadata() {
         return lstServiceMetadata;
     }
+    public List<UserRO> getUsers() {
+        return lstUser;
+    }
 
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/UserRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/UserRO.java
index dd6c885c5b95e260144684d48304d0b11e13269d..fd6764754daabeabbcb1ecae971126884a58a616 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/UserRO.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/UserRO.java
@@ -15,6 +15,7 @@ import java.time.LocalDateTime;
 public class UserRO extends BaseRO {
 
 
+
     private static final long serialVersionUID = -4971552086560325302L;
     private String username;
     private String password;
@@ -22,11 +23,20 @@ public class UserRO extends BaseRO {
     LocalDateTime passwordChanged;
     private boolean active = true;
     private String role;
+    private Long id;
+    private CertificateRO certificateData;
 
     public UserRO(){
 
     }
 
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
 
     public String getUsername() {
         return username;
@@ -75,4 +85,12 @@ public class UserRO extends BaseRO {
     public void setRole(String role) {
         this.role = role;
     }
+
+    public CertificateRO getCertificateData() {
+        return certificateData;
+    }
+
+    public void setCertificateData(CertificateRO certificate) {
+        this.certificateData = certificate;
+    }
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceBase.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceBase.java
index edf8b64afcf5a83dabaf868a85ce68ac1b74f418..c796fc57f0d7491f4b66dde05b38e9376c32fc31 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceBase.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceBase.java
@@ -77,6 +77,7 @@ abstract class UIServiceBase<E extends BaseEntity, R> {
         return sg;
     }
 
+
     /**
      * Simple method for converting types. Property name and property type must match
      * @param d
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceGroupService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceGroupService.java
index 0782d9830e14edda44908c23af22320b68b5c379..de751e9a90ea02caff5eac49d39f6d8bbffa3328 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceGroupService.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceGroupService.java
@@ -2,23 +2,32 @@ package eu.europa.ec.edelivery.smp.services.ui;
 
 import eu.europa.ec.edelivery.smp.data.dao.BaseDao;
 import eu.europa.ec.edelivery.smp.data.dao.ServiceGroupDao;
+import eu.europa.ec.edelivery.smp.data.dao.UserDao;
 import eu.europa.ec.edelivery.smp.data.model.DBServiceGroup;
+import eu.europa.ec.edelivery.smp.data.model.DBUser;
 import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupRO;
 import eu.europa.ec.edelivery.smp.data.ui.ServiceMetadataRO;
 import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
+import eu.europa.ec.edelivery.smp.data.ui.UserRO;
+import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.List;
 
 @Service
 public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, ServiceGroupRO> {
 
+
     @Autowired
     ServiceGroupDao serviceGroupDao;
 
+    @Autowired
+    UserDao userDao;
+
     @Override
     protected BaseDao<DBServiceGroup> getDatabaseDao() {
         return serviceGroupDao;
@@ -53,9 +62,9 @@ public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, Service
             for (DBServiceGroup dbServiceGroup : lst) {
                 ServiceGroupRO serviceGroupRo = new ServiceGroupRO();
                 serviceGroupRo.setIndex(iStartIndex++);
+                serviceGroupRo.setId(dbServiceGroup.getId());
                 serviceGroupRo.setParticipantIdentifier(dbServiceGroup.getParticipantIdentifier());
                 serviceGroupRo.setParticipantScheme(dbServiceGroup.getParticipantScheme());
-
                 dbServiceGroup.getServiceGroupDomains().forEach(sgd -> {
                     sgd.getServiceMetadata().forEach(sgmd -> {
                         ServiceMetadataRO smdro = new ServiceMetadataRO();
@@ -66,6 +75,16 @@ public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, Service
                         serviceGroupRo.getServiceMetadata().add(smdro);
                     });
                 });
+                // add users
+                dbServiceGroup.getUsers().forEach(usr->{
+                    UserRO userRO = new UserRO();
+                    userRO.setId(usr.getId());
+                    userRO.setUsername(usr.getUsername());
+                    userRO.setActive(usr.isActive());
+                    userRO.setEmail(usr.getEmail());
+                    userRO.setRole(usr.getRole());
+                    serviceGroupRo.getUsers().add(userRO);
+                });
                 lstRo.add(serviceGroupRo);
             }
 
@@ -74,4 +93,77 @@ public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, Service
         return sg;
     }
 
+    @Transactional
+    public ServiceGroupRO getServiceGroupById(Long serviceGroupId) {
+        DBServiceGroup dbServiceGroup = getDatabaseDao().find(serviceGroupId);
+        ServiceGroupRO serviceGroupRo = new ServiceGroupRO();
+        serviceGroupRo.setId(dbServiceGroup.getId());
+        serviceGroupRo.setParticipantIdentifier(dbServiceGroup.getParticipantIdentifier());
+        serviceGroupRo.setParticipantScheme(dbServiceGroup.getParticipantScheme());
+        // add service groups
+        dbServiceGroup.getServiceGroupDomains().forEach(sgd -> {
+            sgd.getServiceMetadata().forEach(sgmd -> {
+                ServiceMetadataRO smdro = new ServiceMetadataRO();
+                smdro.setDocumentIdentifier(sgmd.getDocumentIdentifier());
+                smdro.setDocumentIdentifierScheme(sgmd.getDocumentIdentifierScheme());
+                smdro.setDomainCode(sgd.getDomain().getDomainCode());
+                smdro.setSmlSubdomain(sgd.getDomain().getSmlSubdomain());
+                serviceGroupRo.getServiceMetadata().add(smdro);
+            });
+        });
+        // add users
+        dbServiceGroup.getUsers().forEach(usr->{
+            UserRO userRO = new UserRO();
+            userRO.setId(usr.getId());
+            userRO.setUsername(usr.getUsername());
+            userRO.setActive(usr.isActive());
+            userRO.setEmail(usr.getEmail());
+            userRO.setRole(usr.getRole());
+            serviceGroupRo.getUsers().add(userRO);
+        });
+        return serviceGroupRo;
+    }
+
+    @Transactional
+    public void updateServiceGroupList(List<ServiceGroupRO> lst) {
+        boolean suc = false;
+        for (ServiceGroupRO dRo: lst){
+
+
+            if (dRo.getStatus() == EntityROStatus.NEW.getStatusNumber()) {
+                DBServiceGroup dDb = convertFromRo(dRo);
+                for (UserRO userRO: dRo.getUsers()) {
+                    System.out.println("GET USER ID: " + userRO.getId());
+                    DBUser du = userDao.find(userRO.getId());
+                    dDb.getUsers().add(du);
+
+                }
+                getDatabaseDao().persistFlushDetach(dDb);
+            } else if (dRo.getStatus() == EntityROStatus.UPDATED.getStatusNumber()) {
+                DBServiceGroup upd = getDatabaseDao().find(dRo.getId());
+                upd.getUsers().clear();
+                for (UserRO userRO: dRo.getUsers()) {
+                    System.out.println("GET USER ID: " + userRO.getId());
+                    DBUser du = userDao.find(userRO.getId());
+                    upd.getUsers().add(du);
+
+                }
+                // only servicegroup users can be changed__
+                /*
+                upd.setSmlSmpId(dRo.getSmlSmpId());
+                upd.setSmlClientKeyAlias(dRo.getSmlClientKeyAlias());
+                upd.setSmlClientCertHeader(dRo.getSmlClientCertHeader());
+                upd.setSmlParticipantIdentifierRegExp(dRo.getSmlParticipantIdentifierRegExp());
+                upd.setSmlSubdomain(dRo.getSmlSubdomain());
+                upd.setDomainCode(dRo.getDomainCode());
+                upd.setSignatureKeyAlias(dRo.getSignatureKeyAlias());
+                upd.setLastUpdatedOn(LocalDateTime.now());*/
+                getDatabaseDao().update(upd);
+            } else if (dRo.getStatus() == EntityROStatus.REMOVE.getStatusNumber()) {
+                DBServiceGroup upd = getDatabaseDao().find(dRo.getId());
+                serviceGroupDao.removeServiceGroup(upd);
+            }
+        }
+    }
+
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java
index 6a0ef1eb8b9227ff2f047b96f8e413493aa5595c..480b2a00356dec43776099755be0085a735b9543 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIUserService.java
@@ -1,17 +1,45 @@
 package eu.europa.ec.edelivery.smp.services.ui;
 
+import eu.europa.ec.edelivery.security.PreAuthenticatedCertificatePrincipal;
+import eu.europa.ec.edelivery.smp.BCryptPasswordHash;
 import eu.europa.ec.edelivery.smp.data.dao.BaseDao;
 import eu.europa.ec.edelivery.smp.data.dao.UserDao;
+import eu.europa.ec.edelivery.smp.data.model.DBCertificate;
+import eu.europa.ec.edelivery.smp.data.model.DBDomain;
 import eu.europa.ec.edelivery.smp.data.model.DBUser;
+import eu.europa.ec.edelivery.smp.data.ui.CertificateRO;
+import eu.europa.ec.edelivery.smp.data.ui.DomainRO;
 import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
 import eu.europa.ec.edelivery.smp.data.ui.UserRO;
+import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus;
+import eu.europa.ec.edelivery.smp.logging.SMPLogger;
+import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
+import eu.europa.ec.edelivery.smp.services.ServiceGroupService;
+import org.apache.commons.beanutils.BeanUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.crypto.bcrypt.BCrypt;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import javax.ejb.Local;
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.math.BigInteger;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.List;
+
 @Service
 public class UIUserService extends UIServiceBase<DBUser, UserRO> {
 
+    private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UIUserService.class);
+
     @Autowired
     UserDao userDao;
 
@@ -21,7 +49,7 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
     }
 
     /**
-     * Method returns Domain resource object list for page.
+     * Method returns user resource object list for page.
      *
      * @param page
      * @param pageSize
@@ -35,7 +63,127 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
                                                  String sortField,
                                                  String sortOrder, Object filter) {
 
-        return super.getTableList(page, pageSize, sortField, sortOrder, filter);
+        ServiceResult<UserRO> resUsers =  super.getTableList(page, pageSize, sortField, sortOrder, filter);
+        resUsers.getServiceEntities().forEach(usr -> usr.setPassword(null));
+        return resUsers;
+    }
+
+    @Transactional
+    public void updateUserList(List<UserRO> lst) {
+        boolean suc = false;
+        for (UserRO userRO : lst) {
+
+            if (userRO.getStatus() == EntityROStatus.NEW.getStatusNumber()) {
+                DBUser dbUser = convertFromRo(userRO);
+                userDao.persistFlushDetach(dbUser);
+            } else if (userRO.getStatus() == EntityROStatus.UPDATED.getStatusNumber()) {
+                DBUser dbUser = userDao.find(userRO.getId());
+                dbUser.setEmail(userRO.getEmail());
+                dbUser.setRole(userRO.getRole());
+                dbUser.setActive(userRO.isActive());
+                // check for new password
+                if (!StringUtils.isBlank(userRO.getPassword())) {
+                    if (!StringUtils.isBlank(dbUser.getPassword())) {
+                        if (!BCrypt.checkpw(userRO.getPassword(), dbUser.getPassword())) {
+                            LOG.debug("User with id {} changed password!", dbUser.getId());
+
+                            dbUser.setPassword(BCryptPasswordHash.hashPassword(userRO.getPassword().trim()));
+                            dbUser.setPasswordChanged(LocalDateTime.now());
+                        }
+                    } else {
+                        dbUser.setPassword(BCryptPasswordHash.hashPassword(userRO.getPassword()));
+                    }
+                }
+                // update certificate data
+                if (userRO.getCertificateData() == null) {
+                    dbUser.setCertificate(null);
+                } else {
+                    CertificateRO certificateRO = userRO.getCertificateData();
+                    DBCertificate dbCertificate = dbUser.getCertificate() != null ? dbUser.getCertificate() : new DBCertificate();
+                    dbUser.setCertificate(dbCertificate);
+                    dbCertificate.setValidFrom(certificateRO.getValidFrom());
+                    dbCertificate.setValidFrom(certificateRO.getValidTo());
+                    dbCertificate.setCertificateId(certificateRO.getCertificateId());
+                    dbCertificate.setSerialNumber(certificateRO.getSerialNumber());
+                    dbCertificate.setSubject(certificateRO.getSubject());
+                    dbCertificate.setIssuer(certificateRO.getIssuer());
+                }
+                dbUser.setLastUpdatedOn(LocalDateTime.now());
+                userDao.update(dbUser);
+            } else if (userRO.getStatus() == EntityROStatus.REMOVE.getStatusNumber()) {
+                userDao.removeById(userRO.getId());
+            }
+        }
+    }
+
+    public CertificateRO getCertificateData(byte[] buff)  throws CertificateException{
+
+        CertificateFactory fact = null;
+
+            fact = CertificateFactory.getInstance("X.509");
+            ByteArrayInputStream is = new ByteArrayInputStream(buff);
+            X509Certificate cert = (X509Certificate)  fact.generateCertificate(is);
+            String subject = cert.getSubjectDN().getName();
+            String issuer = cert.getIssuerDN().getName();
+            String hash = cert.getIssuerDN().getName();
+            BigInteger serial = cert.getSerialNumber();
+            String certId = getCertificateIdFromCertificate(subject,issuer, serial );
+            CertificateRO cro = new CertificateRO();
+            cro.setCertificateId(certId);
+            cro.setSubject(subject);
+            cro.setIssuer(issuer);
+            // set serial as HEX
+            cro.setSerialNumber(serial.toString(16));
+            cro.setValidFrom(LocalDateTime.ofInstant(cert.getNotBefore().toInstant(), ZoneId.systemDefault()));
+            cro.setValidTo(LocalDateTime.ofInstant(cert.getNotAfter().toInstant(), ZoneId.systemDefault()));
+
+            return cro;
+
+
+
+    }
+
+    public String getCertificateIdFromCertificate(String subject, String issuer, BigInteger serial ){
+        return new PreAuthenticatedCertificatePrincipal(subject, issuer, serial).getName();
+    }
+
+    @Override
+    public UserRO convertToRo(DBUser d) {
+        try {
+            UserRO dro = new UserRO();
+            BeanUtils.copyProperties(dro, d);
+
+            if (d.getCertificate()!=null) {
+                CertificateRO certData = new CertificateRO();
+                BeanUtils.copyProperties(certData, d.getCertificate());
+                dro.setCertificateData(certData);
+            }
+            return dro;
+        } catch ( InvocationTargetException | IllegalAccessException e) {
+            String msg = "Error occurred while converting to RO Entity for " +UserRO.class.getName();
+            LOG.error(msg, e );
+            throw new RuntimeException(msg, e);
+        }
+    }
+
+    @Override
+    public DBUser convertFromRo(UserRO d) {
+        try {
+            DBUser dro = new DBUser();
+            BeanUtils.copyProperties(dro, d);
+            DBCertificate cert = new DBCertificate();
+            if (d.getCertificateData()!=null) {
+                DBCertificate certData = new DBCertificate();
+                BeanUtils.copyProperties(certData, d.getCertificateData());
+                dro.setCertificate(cert);
+            }
+
+            return dro;
+        } catch ( InvocationTargetException | IllegalAccessException e) {
+            String msg = "Error occurred while converting to RO Entity for " +UserRO.class.getName();
+            LOG.error(msg, e );
+            throw new RuntimeException(msg, e);
+        }
     }
 
 }
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java
index 4950f5255efad8589205b4539330c504e7bf4781..62305ae17bcd0bc24b9244a8591a9eb176140c15 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIUserServiceIntegrationTest.java
@@ -1,17 +1,32 @@
 package eu.europa.ec.edelivery.smp.services.ui;
 
 
+import eu.europa.ec.edelivery.smp.data.model.DBCertificate;
 import eu.europa.ec.edelivery.smp.data.model.DBUser;
+import eu.europa.ec.edelivery.smp.data.ui.CertificateRO;
 import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
 import eu.europa.ec.edelivery.smp.data.ui.UserRO;
+import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus;
 import eu.europa.ec.edelivery.smp.services.AbstractServiceIntegrationTest;
 import eu.europa.ec.edelivery.smp.testutil.TestDBUtils;
+import org.apache.commons.io.IOUtils;
+import org.hibernate.type.BigIntegerType;
+import org.hibernate.type.descriptor.java.UUIDTypeDescriptor;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.crypto.bcrypt.BCrypt;
 import org.springframework.test.context.ContextConfiguration;
 
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CertificateException;
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.TemporalUnit;
+import java.util.*;
+
 import static org.junit.Assert.*;
 
 
@@ -29,20 +44,21 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest
     @Autowired
     protected UIUserService testInstance;
 
-    protected void insertDataObjects(int size){
-        for (int i=0; i < size; i++){
-            DBUser d = TestDBUtils.createDBUserByUsername("user"+i);
+    protected void insertDataObjects(int size) {
+        for (int i = 0; i < size; i++) {
+            DBUser d = TestDBUtils.createDBUserByUsername("user" + i);
+            d.setPassword(BCrypt.hashpw(d.getPassword(), BCrypt.gensalt()));
             userDao.persistFlushDetach(d);
         }
     }
 
     @Test
-    public void testGetTableListEmpty(){
+    public void testGetTableListEmpty() {
 
         // given
 
         //when
-        ServiceResult<UserRO> res = testInstance.getTableList(-1,-1,null, null,null);
+        ServiceResult<UserRO> res = testInstance.getTableList(-1, -1, null, null, null);
         // then
         assertNotNull(res);
         assertEquals(0, res.getCount().intValue());
@@ -53,13 +69,12 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest
     }
 
     @Test
-    public void testGetTableList15(){
+    public void testGetTableList15() {
 
         // given
         insertDataObjects(15);
         //when
-        ServiceResult<UserRO> res = testInstance.getTableList(-1,-1,null, null,null);
-
+        ServiceResult<UserRO> res = testInstance.getTableList(-1, -1, null, null, null);
 
         // then
         assertNotNull(res);
@@ -71,10 +86,191 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest
 
         // all table properties should not be null
         assertNotNull(res);
+        assertNotNull(res.getServiceEntities().get(0).getId());
         assertNotNull(res.getServiceEntities().get(0).getUsername());
         assertNotNull(res.getServiceEntities().get(0).getEmail());
-        assertNotNull(res.getServiceEntities().get(0).getPassword());
+        assertNull(res.getServiceEntities().get(0).getPassword()); // Service list must not return passwords
         assertNotNull(res.getServiceEntities().get(0).getPasswordChanged());
         assertNotNull(res.getServiceEntities().get(0).getRole());
     }
+
+    @Test
+    public void testUpdateUserPassword() {
+        // given
+        insertDataObjects(1);
+        String newPassword = "TestPasswd!@#" + Calendar.getInstance().getTime();
+        ServiceResult<UserRO> urTest  =  testInstance.getTableList(-1,-1,null, null, null);
+        assertEquals(1, urTest.getServiceEntities().size());
+
+        UserRO usr = urTest.getServiceEntities().get(0);
+
+        //when
+        usr.setPassword(newPassword);
+        usr.setStatus(EntityROStatus.UPDATED.getStatusNumber());
+        testInstance.updateUserList(Collections.singletonList(usr));
+
+        // then
+        DBUser dbuser = userDao.find(usr.getId());
+        assertTrue(BCrypt.checkpw(newPassword, dbuser.getPassword()));
+    }
+
+
+    @Test
+    public void testAddUserWithoutCertificate() {
+        // given
+        insertDataObjects(15);
+        long  iCnt = userDao.getDataListCount(null);
+
+        UserRO user = new UserRO();
+        user.setPassword(UUID.randomUUID().toString());
+        user.setUsername(UUID.randomUUID().toString());
+        user.setEmail(UUID.randomUUID().toString());
+        user.setRole("ROLE");
+        user.setStatus(EntityROStatus.NEW.getStatusNumber());
+
+        //when
+        testInstance.updateUserList(Collections.singletonList(user));
+        // then
+        long  iCntNew  = userDao.getDataListCount(null);
+        assertEquals(iCnt+1, iCntNew);
+        Optional<DBUser> oUsr =  userDao.findUserByUsername(user.getUsername());
+        assertTrue(oUsr.isPresent());
+        assertEquals(user.getPassword(), oUsr.get().getPassword());
+        assertEquals(user.getUsername(), oUsr.get().getUsername());
+        assertEquals(user.getRole(), oUsr.get().getRole());
+        assertEquals(user.getEmail(), oUsr.get().getEmail());
+        assertNull(oUsr.get().getCertificate());
+    }
+
+    @Test
+    public void testAddUserWithCertificate() {
+        // given
+        insertDataObjects(15);
+        long  iCnt = userDao.getDataListCount(null);
+
+        LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES);
+        LocalDateTime future =now.plusYears(1);
+
+        UserRO user = new UserRO();
+        user.setPassword(UUID.randomUUID().toString());
+        user.setUsername(UUID.randomUUID().toString());
+        user.setEmail(UUID.randomUUID().toString());
+        user.setRole("ROLE");
+        CertificateRO cert = new CertificateRO();
+        cert.setSubject(UUID.randomUUID().toString());
+        cert.setIssuer(UUID.randomUUID().toString());
+        cert.setSerialNumber(UUID.randomUUID().toString());
+        cert.setCertificateId(UUID.randomUUID().toString());
+        cert.setValidFrom(now);
+        cert.setValidTo(future);
+        user.setCertificateData(cert);
+
+        user.setStatus(EntityROStatus.NEW.getStatusNumber());
+
+
+        //when
+        testInstance.updateUserList(Collections.singletonList(user));
+        // then
+        long  iCntNew  = userDao.getDataListCount(null);
+        assertEquals(iCnt+1, iCntNew);
+        Optional<DBUser> oUsr =  userDao.findUserByUsername(user.getUsername());
+        assertTrue(oUsr.isPresent());
+        assertEquals(user.getPassword(), oUsr.get().getPassword());
+        assertEquals(user.getUsername(), oUsr.get().getUsername());
+        assertEquals(user.getRole(), oUsr.get().getRole());
+        assertEquals(user.getEmail(), oUsr.get().getEmail());
+        assertNotNull(oUsr.get().getCertificate());
+        assertEquals(cert.getCertificateId(), cert.getCertificateId());
+        assertEquals(cert.getSubject(), cert.getSubject());
+        assertEquals(cert.getIssuer(), cert.getIssuer());
+        assertEquals(cert.getSerialNumber(), cert.getSerialNumber());
+        assertEquals(now, cert.getValidFrom());
+        assertEquals(future, cert.getValidTo());
+    }
+
+
+    @Test
+    public void testUserRemoveCertificate() {
+        // given
+
+
+        LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES);
+        LocalDateTime future =now.plusYears(1);
+
+        DBUser user = new DBUser();
+        user.setPassword(UUID.randomUUID().toString());
+        user.setUsername(UUID.randomUUID().toString());
+        user.setEmail(UUID.randomUUID().toString());
+        user.setRole("ROLE");
+        DBCertificate cert = new DBCertificate();
+        cert.setSubject(UUID.randomUUID().toString());
+        cert.setIssuer(UUID.randomUUID().toString());
+        cert.setSerialNumber(UUID.randomUUID().toString());
+        cert.setCertificateId(UUID.randomUUID().toString());
+        cert.setValidFrom(now);
+        cert.setValidTo(future);
+        user.setCertificate(cert);
+        userDao.persistFlushDetach(user);
+        ServiceResult<UserRO> urTest  =  testInstance.getTableList(-1,-1,null, null, null);
+        assertEquals(1, urTest.getServiceEntities().size());
+        UserRO userRO = urTest.getServiceEntities().get(0);
+        assertNotNull(userRO.getCertificateData());
+
+        //when
+        userRO.setCertificateData(null);
+        userRO.setStatus(EntityROStatus.UPDATED.getStatusNumber());
+
+        testInstance.updateUserList(Collections.singletonList(userRO));
+        // then
+        ServiceResult<UserRO> res  =  testInstance.getTableList(-1,-1,null, null, null);
+        assertEquals(1, urTest.getServiceEntities().size());
+        UserRO userResRO = urTest.getServiceEntities().get(0);
+        assertNull(userResRO.getCertificateData());
+
+    }
+
+    @Test
+    public void testDeleteUser() {
+        // given
+        insertDataObjects(15);
+        ServiceResult<UserRO> urTest  =  testInstance.getTableList(-1,-1,null, null, null);
+        assertEquals(15, urTest.getServiceEntities().size());
+
+        UserRO user = urTest.getServiceEntities().get(0);
+        user.setStatus(EntityROStatus.REMOVE.getStatusNumber());
+
+        //when
+        testInstance.updateUserList(Collections.singletonList(user));
+
+        // then
+        long  iCntNew  = userDao.getDataListCount(null);
+        Optional<DBUser> rmUsr = userDao.findUserByUsername(user.getUsername());
+
+        assertEquals( urTest.getServiceEntities().size()-1, iCntNew);
+        assertFalse(rmUsr.isPresent());
+
+    }
+
+    @Test
+    public void testGetCertificateData() throws IOException, CertificateException {
+        // given
+        byte[] buff = IOUtils.toByteArray(UIUserServiceIntegrationTest.class.getResourceAsStream("/keystores/SMPtest.crt"));
+        // when
+        CertificateRO cer = testInstance.getCertificateData(buff);
+        //then
+        assertEquals("CN=SMP test,O=DIGIT,C=BE:0000000000000003", cer.getCertificateId());
+        assertEquals("CN=Intermediate CA, O=DIGIT, C=BE", cer.getIssuer());
+        assertEquals("EMAILADDRESS=smp@test.com, CN=SMP test, O=DIGIT, C=BE", cer.getSubject());
+        assertEquals("3", cer.getSerialNumber());
+        assertNotNull(cer.getValidFrom());
+        assertNotNull(cer.getValidTo());
+        assertTrue(cer.getValidFrom().isBefore(cer.getValidTo()));
+
+
+    }
+
+
+
+
+
 }
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SmpWebAppConfig.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SmpWebAppConfig.java
index d496bb6c9a1557714d88ab5ee22927d26b923e09..da24d8c4e3e8fb287d9cfb19682447c5ca6d4e48 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SmpWebAppConfig.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SmpWebAppConfig.java
@@ -38,7 +38,7 @@ public class SmpWebAppConfig implements WebMvcConfigurer {
     @Override
     public void addViewControllers(ViewControllerRegistry registry) {
         registry.addViewController("/").setViewName("/index.html");
-        registry.addRedirectViewController("/ui/","/ui/index.html");
+        registry.addViewController("/ui/").setViewName("/ui/index.html");
 
         //Home page used by SMP 2.x and 3.x - needed for backward compatibility in some EC's environments
         registry.addViewController("/web/index.html").setViewName("/index.html");
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupController.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupController.java
index 909a0d78653d8c083bc067fd2e59449a6b7bff24..ce39c2a8fe3fa5faf6269c9b435d5f8dc45debf2 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupController.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/ServiceGroupController.java
@@ -55,7 +55,7 @@ import static org.springframework.http.ResponseEntity.ok;
  */
 
 @RestController
-@RequestMapping("/{serviceGroupId}")
+@RequestMapping("/{serviceGroupId:^(?!ui).*}")
 public class ServiceGroupController {
 
     private static final SMPLogger LOG = SMPLoggerFactory.getLogger(ServiceGroupController.class);
@@ -75,6 +75,8 @@ public class ServiceGroupController {
 
     @GetMapping(produces = "text/xml; charset=UTF-8")
     public ServiceGroup getServiceGroup(HttpServletRequest httpReq, @PathVariable String serviceGroupId) {
+
+
         String host = httpReq.getRemoteHost();
         LOG.businessInfo(SMPMessageCode.BUS_HTTP_GET_SERVICE_GROUP,host, serviceGroupId);
 
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/SearchResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/SearchResource.java
index 64ff10bfb4136947a141de31d20269bcbc74debc..db693136d3bd9d80dcc9c2531bdaab6ee0f79e00 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/SearchResource.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/SearchResource.java
@@ -50,8 +50,6 @@ public class SearchResource {
         ServiceGroupFilter sgf = new ServiceGroupFilter();
         sgf.setParticipantIdentifierLike(participantIdentifier);
         sgf.setParticipantSchemeLike(participantScheme);
-
-
         return uiServiceGroupService.getTableList(page,pageSize, orderBy, orderType, sgf );
     }
 }
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ServiceGroupResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ServiceGroupResource.java
index f28b7c3dc531d8414551d4f32d7c302ac02b5e87..543657db916756c851c4eecf8f33bf3c061c1a6b 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ServiceGroupResource.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ServiceGroupResource.java
@@ -1,8 +1,11 @@
 package eu.europa.ec.edelivery.smp.ui;
 
 
+import eu.europa.ec.edelivery.smp.data.ui.DomainRO;
 import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupRO;
 import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
+import eu.europa.ec.edelivery.smp.logging.SMPLogger;
+import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
 import eu.europa.ec.edelivery.smp.services.ui.UIServiceGroupService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -10,6 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.PostConstruct;
+import java.util.Arrays;
 
 /**
  * @author Joze Rihtarsic
@@ -20,7 +24,7 @@ import javax.annotation.PostConstruct;
 @RequestMapping(value = "/ui/rest/servicegroup")
 public class ServiceGroupResource {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(ServiceGroupResource.class);
+    private static final SMPLogger LOG = SMPLoggerFactory.getLogger(DomainResource.class);
 
     @Autowired
     private UIServiceGroupService uiServiceGroupService;
@@ -33,7 +37,7 @@ public class ServiceGroupResource {
     @PutMapping(produces = {"application/json"})
     @ResponseBody
     @RequestMapping(method = RequestMethod.GET)
-    public  ServiceResult<ServiceGroupRO> getServiceGroupList(
+    public ServiceResult<ServiceGroupRO> getServiceGroupList(
             @RequestParam(value = "page", defaultValue = "0") int page,
             @RequestParam(value = "pageSize", defaultValue = "10") int pageSize,
             @RequestParam(value = "orderBy", required = false) String orderBy,
@@ -41,9 +45,24 @@ public class ServiceGroupResource {
             @RequestParam(value = "participantId", required = false) String participantId,
             @RequestParam(value = "participantSchema", required = false) String participantSchema,
             @RequestParam(value = "domain", required = false) String domain
-            ) {
+    ) {
+        return uiServiceGroupService.getTableList(page, pageSize, orderBy, orderType, null);
+    }
+
+    @ResponseBody
+    @PutMapping(produces = {"application/json"})
+    @RequestMapping(method = RequestMethod.GET, path = "{serviceGroupId}")
+    public ServiceGroupRO getServiceGroupById(@PathVariable Long serviceGroupId) {
 
 
-        return uiServiceGroupService.getTableList(page,pageSize, orderBy, orderType, null );
+        return uiServiceGroupService.getServiceGroupById(serviceGroupId);
+    }
+
+    @PutMapping(produces = {"application/json"})
+    @RequestMapping(method = RequestMethod.PUT)
+    public void updateDomainList(@RequestBody(required = true) ServiceGroupRO[] updateEntities ){
+        LOG.info("GOT LIST OF ServiceGroupRO to UPDATE: " + updateEntities.length);
+        uiServiceGroupService.updateServiceGroupList(Arrays.asList(updateEntities));
     }
 }
+
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/UserResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/UserResource.java
index 0898cbec527ef683db4b5392a918f1e48c76f7b1..569447d41d4d543309e944f8323186077f3b4799 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/UserResource.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/UserResource.java
@@ -1,15 +1,28 @@
 package eu.europa.ec.edelivery.smp.ui;
 
 
+import eu.europa.ec.edelivery.smp.data.ui.CertificateRO;
+import eu.europa.ec.edelivery.smp.data.ui.DomainRO;
 import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
 import eu.europa.ec.edelivery.smp.data.ui.UserRO;
+import eu.europa.ec.edelivery.smp.logging.SMPLogger;
+import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
 import eu.europa.ec.edelivery.smp.services.ui.UIUserService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.PostConstruct;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.CertificateException;
+import java.util.Arrays;
 
 /**
  * @author Joze Rihtarsic
@@ -20,7 +33,7 @@ import javax.annotation.PostConstruct;
 @RequestMapping(value = "/ui/rest/user")
 public class UserResource {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(UserResource.class);
+    private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UserResource.class);
 
     @Autowired
     private UIUserService uiUserService;
@@ -44,4 +57,24 @@ public class UserResource {
 
         return  uiUserService.getTableList(page,pageSize, orderBy, orderType, null);
     }
+
+    @PutMapping(produces = {"application/json"})
+    @RequestMapping(method = RequestMethod.PUT)
+    public void updateUserList(@RequestBody(required = true) UserRO[] updateEntities ){
+        LOG.info("Update user list, count: {}" + updateEntities.length);
+        uiUserService.updateUserList(Arrays.asList(updateEntities));
+    }
+
+
+    @RequestMapping(path = "certdata", method = RequestMethod.POST)
+    public CertificateRO uploadFile(@RequestBody byte[] data) {
+        LOG.info("Got certificate data: " + data.length);
+        try {
+            return uiUserService.getCertificateData(data);
+        } catch (CertificateException e) {
+            LOG.error("Error occured while parsing certificate.", e);
+        }
+        return null;
+
+    }
 }
diff --git a/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb-4.1.0-SNAPSHOT.ddl b/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb-4.1.0-SNAPSHOT.ddl
index 4c8221aa86dc2cebca60beac48e5c07db0882197..00c0e53d00e4ffedee211fbeb506fe0750ba2f17 100644
--- a/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb-4.1.0-SNAPSHOT.ddl
+++ b/smp-webapp/src/main/smp-setup/database-scripts/mysql5innodb-4.1.0-SNAPSHOT.ddl
@@ -3,7 +3,10 @@
        ID bigint not null,
         CERTIFICATE_ID varchar(4000)  CHARACTER SET utf8 COLLATE utf8_bin,
         CREATED_ON datetime not null,
+        issuer varchar(512)  CHARACTER SET utf8 COLLATE utf8_bin,
         LAST_UPDATED_ON datetime not null,
+        serialNumber varchar(128)  CHARACTER SET utf8 COLLATE utf8_bin,
+        subject varchar(512)  CHARACTER SET utf8 COLLATE utf8_bin,
         VALID_FROM datetime,
         VALID_TO datetime,
         primary key (ID)
@@ -15,7 +18,10 @@
         REVTYPE tinyint,
         CERTIFICATE_ID varchar(4000)  CHARACTER SET utf8 COLLATE utf8_bin,
         CREATED_ON datetime,
+        issuer varchar(512)  CHARACTER SET utf8 COLLATE utf8_bin,
         LAST_UPDATED_ON datetime,
+        serialNumber varchar(128)  CHARACTER SET utf8 COLLATE utf8_bin,
+        subject varchar(512)  CHARACTER SET utf8 COLLATE utf8_bin,
         VALID_FROM datetime,
         VALID_TO datetime,
         primary key (ID, REV)
diff --git a/smp-webapp/src/main/smp-setup/database-scripts/oracle10g-4.1.0-SNAPSHOT.ddl b/smp-webapp/src/main/smp-setup/database-scripts/oracle10g-4.1.0-SNAPSHOT.ddl
index d3531a4c216208f1c4bf239d2dc9432592fd9355..2cf7e6aac5b3817d92bbd49cfc784580e4f5aad9 100644
--- a/smp-webapp/src/main/smp-setup/database-scripts/oracle10g-4.1.0-SNAPSHOT.ddl
+++ b/smp-webapp/src/main/smp-setup/database-scripts/oracle10g-4.1.0-SNAPSHOT.ddl
@@ -9,7 +9,10 @@ create sequence SMP_USER_SEQ start with 1 increment by  50;
        ID number(19,0) not null,
         CERTIFICATE_ID varchar2(4000 char),
         CREATED_ON timestamp not null,
+        issuer varchar2(512 char),
         LAST_UPDATED_ON timestamp not null,
+        serialNumber varchar2(128 char),
+        subject varchar2(512 char),
         VALID_FROM timestamp,
         VALID_TO timestamp,
         primary key (ID)
@@ -21,7 +24,10 @@ create sequence SMP_USER_SEQ start with 1 increment by  50;
         REVTYPE number(3,0),
         CERTIFICATE_ID varchar2(4000 char),
         CREATED_ON timestamp,
+        issuer varchar2(512 char),
         LAST_UPDATED_ON timestamp,
+        serialNumber varchar2(128 char),
+        subject varchar2(512 char),
         VALID_FROM timestamp,
         VALID_TO timestamp,
         primary key (ID, REV)
diff --git a/smp-webapp/src/main/webapp/WEB-INF/web.xml b/smp-webapp/src/main/webapp/WEB-INF/web.xml
index 4f2375f2880c40ad267ef17828dfcf90045f0457..b8ff0b251e59001364370260f7fe3815ffc6ab22 100644
--- a/smp-webapp/src/main/webapp/WEB-INF/web.xml
+++ b/smp-webapp/src/main/webapp/WEB-INF/web.xml
@@ -24,7 +24,22 @@
     -->
 
 
-    <display-name>SMP - OASIS REST services</display-name>
+    <display-name>eDelivery SMP</display-name>
+
+    <servlet>
+        <servlet-name>fistPage</servlet-name>
+        <jsp-file>/static_resources/index.html</jsp-file>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>fistPage</servlet-name>
+        <url-pattern>/</url-pattern>
+    </servlet-mapping>
+    <servlet-mapping>
+        <servlet-name>fistPage</servlet-name>
+        <url-pattern>/web/index.html</url-pattern>
+    </servlet-mapping>
+
 
     <servlet>
         <servlet-name>smpRestServlet</servlet-name>
@@ -44,6 +59,7 @@
     </servlet-mapping>
 
 
+
     <!-- SpringSecurity & Application Context-->
 
     <context-param>
diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/ServiceGroupResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/ServiceGroupResourceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ab02e47f6b1f5099943d97349287eb41ab874ddc
--- /dev/null
+++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/ServiceGroupResourceTest.java
@@ -0,0 +1,145 @@
+package eu.europa.ec.edelivery.smp.ui;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import eu.europa.ec.edelivery.smp.config.PropertiesTestConfig;
+import eu.europa.ec.edelivery.smp.config.SmpAppConfig;
+import eu.europa.ec.edelivery.smp.config.SmpWebAppConfig;
+import eu.europa.ec.edelivery.smp.config.SpringSecurityConfig;
+import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupRO;
+import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.mock.web.MockServletContext;
+import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.jdbc.SqlConfig;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.ContextLoaderListener;
+import org.springframework.web.context.WebApplicationContext;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import static org.junit.Assert.*;
+import static org.springframework.http.MediaType.APPLICATION_JSON;
+import static org.springframework.http.MediaType.APPLICATION_XML_VALUE;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+/**
+ * @author Joze Rihtarsic
+ * @since 4.1
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = {
+        PropertiesTestConfig.class,
+        SmpAppConfig.class,
+        SmpWebAppConfig.class,
+        SpringSecurityConfig.class})
+@WebAppConfiguration
+@Sql("classpath:/cleanup-database.sql")
+@Sql("classpath:/webapp_integration_test_data.sql")
+@SqlConfig(encoding = "UTF-8")
+public class ServiceGroupResourceTest {
+
+    private static final String PATH="/ui/rest/servicegroup";
+
+    private static final String PARTICIPANT_IDENTIFIER= "urn:australia:ncpb";
+    private static final String PARTICIPANT_SCHEME= "ehealth-actorid-qns";
+
+    @Autowired
+    private WebApplicationContext webAppContext;
+
+    private MockMvc mvc;
+
+    @Before
+    public void setup() {
+        mvc = MockMvcBuilders.webAppContextSetup(webAppContext)
+                .apply(SecurityMockMvcConfigurers.springSecurity())
+                .build();
+
+        initServletContext();
+    }
+
+    private void initServletContext() {
+        MockServletContext sc = new MockServletContext("");
+        ServletContextListener listener = new ContextLoaderListener(webAppContext);
+        ServletContextEvent event = new ServletContextEvent(sc);
+    }
+
+    @Test
+    public void getServiceGroupList() throws Exception {
+        // given when
+        MvcResult result = mvc.perform(get(PATH)).
+                andExpect(status().isOk()).andReturn();
+
+        //them
+        ObjectMapper mapper = new ObjectMapper();
+        ServiceResult res = mapper.readValue(result.getResponse().getContentAsString(), ServiceResult.class);
+
+
+        assertNotNull(res);
+        assertEquals(2, res.getServiceEntities().size());
+        res.getServiceEntities().forEach(sgMap-> {
+            ServiceGroupRO  sgro = mapper.convertValue(sgMap, ServiceGroupRO.class);
+            assertNotNull(sgro.getId());
+            assertNotNull(sgro.getParticipantScheme());
+            assertNotNull(sgro.getParticipantIdentifier());
+            assertEquals(1, sgro.getUsers().size());
+            assertEquals("test_user_hashed_pass", sgro.getUsers().get(0).getUsername());
+        });
+    }
+
+    @Test
+    public void getServiceGroupById() throws Exception{
+
+        // given when
+        MvcResult result = mvc.perform(get(PATH+"/100000")).
+                andExpect(status().isOk()).andReturn();
+
+        //them
+        ObjectMapper mapper = new ObjectMapper();
+        ServiceGroupRO res = mapper.readValue(result.getResponse().getContentAsString(), ServiceGroupRO.class);
+
+        assertNotNull(res);
+        assertEquals(100000, res.getId().intValue());
+        assertEquals(PARTICIPANT_IDENTIFIER, res.getParticipantIdentifier());
+        assertEquals(PARTICIPANT_SCHEME, res.getParticipantScheme());
+        assertEquals(1, res.getUsers().size());
+        assertEquals("test_user_hashed_pass", res.getUsers().get(0).getUsername());
+
+        assertEquals(1, res.getServiceMetadata().size());
+        assertEquals("doc_7", res.getServiceMetadata().get(0).getDocumentIdentifier());
+    }
+
+
+    @Test
+    public void updateServiceGroupList() throws Exception{
+/*
+        // given when
+        MvcResult result = mvc.perform(put(PATH)).
+                andExpect(status().isOk()).andReturn();
+
+        //them
+        ObjectMapper mapper = new ObjectMapper();
+        ServiceGroupRO res = mapper.readValue(result.getResponse().getContentAsString(), ServiceGroupRO.class);
+
+        assertNotNull(res);
+        assertEquals(100000, res.getId().intValue());
+        assertEquals(PARTICIPANT_IDENTIFIER, res.getParticipantIdentifier());
+        assertEquals(PARTICIPANT_SCHEME, res.getParticipantScheme());
+        assertEquals(1, res.getUsers().size());
+        assertEquals("test_user_hashed_pass", res.getUsers().get(0).getUsername());
+
+        assertEquals(1, res.getServiceMetadata().size());
+        assertEquals("doc_7", res.getServiceMetadata().get(0).getDocumentIdentifier());*/
+    }
+}
\ No newline at end of file
diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/UserResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/UserResourceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..6b41f4d018e725e198728d098492a5aeacfcbf3a
--- /dev/null
+++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/ui/UserResourceTest.java
@@ -0,0 +1,96 @@
+package eu.europa.ec.edelivery.smp.ui;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import eu.europa.ec.edelivery.smp.config.PropertiesTestConfig;
+import eu.europa.ec.edelivery.smp.config.SmpAppConfig;
+import eu.europa.ec.edelivery.smp.config.SmpWebAppConfig;
+import eu.europa.ec.edelivery.smp.config.SpringSecurityConfig;
+import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupRO;
+import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
+import eu.europa.ec.edelivery.smp.data.ui.UserRO;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.mock.web.MockServletContext;
+import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.jdbc.SqlConfig;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.ContextLoaderListener;
+import org.springframework.web.context.WebApplicationContext;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+/**
+ * @author Joze Rihtarsic
+ * @since 4.1
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = {
+        PropertiesTestConfig.class,
+        SmpAppConfig.class,
+        SmpWebAppConfig.class,
+        SpringSecurityConfig.class})
+@WebAppConfiguration
+@Sql("classpath:/cleanup-database.sql")
+@Sql("classpath:/webapp_integration_test_data.sql")
+@SqlConfig(encoding = "UTF-8")
+public class UserResourceTest {
+
+    private static final String PATH="/ui/rest/user";
+
+    @Autowired
+    private WebApplicationContext webAppContext;
+
+    private MockMvc mvc;
+
+    @Before
+    public void setup() {
+        mvc = MockMvcBuilders.webAppContextSetup(webAppContext)
+                .apply(SecurityMockMvcConfigurers.springSecurity())
+                .build();
+
+        initServletContext();
+    }
+
+    private void initServletContext() {
+        MockServletContext sc = new MockServletContext("");
+        ServletContextListener listener = new ContextLoaderListener(webAppContext);
+        ServletContextEvent event = new ServletContextEvent(sc);
+    }
+
+    @Test
+    public void getUserList() throws Exception {
+        // given when
+        MvcResult result = mvc.perform(get(PATH)).
+                andExpect(status().isOk()).andReturn();
+
+        //them
+        ObjectMapper mapper = new ObjectMapper();
+        ServiceResult res = mapper.readValue(result.getResponse().getContentAsString(), ServiceResult.class);
+
+
+        assertNotNull(res);
+        assertEquals(6, res.getServiceEntities().size());
+        res.getServiceEntities().forEach(sgMap-> {
+            UserRO  sgro = mapper.convertValue(sgMap, UserRO.class);
+            assertNotNull(sgro.getId());
+            assertNotNull(sgro.getUsername());
+            assertNotNull(sgro.getRole());
+        });
+    }
+
+
+}
\ No newline at end of file
diff --git a/smp-webapp/src/test/resources/webapp_integration_test_data.sql b/smp-webapp/src/test/resources/webapp_integration_test_data.sql
index c049c0018ab9fee8ef31e7d041e2ae8c32b61350..0c02bb89da6094a8c67a5385d6b4b75f66aeec71 100644
--- a/smp-webapp/src/test/resources/webapp_integration_test_data.sql
+++ b/smp-webapp/src/test/resources/webapp_integration_test_data.sql
@@ -23,13 +23,16 @@ insert into SMP_CERTIFICATE (ID, CERTIFICATE_ID, VALID_FROM, VALID_TO, CREATED_O
 -- set the ids to higher values - tests are using sequnce which stars from 1
 insert into SMP_SERVICE_GROUP(ID, PARTICIPANT_IDENTIFIER, PARTICIPANT_SCHEME,SML_REGISTRED, CREATED_ON, LAST_UPDATED_ON) values (100000, 'urn:australia:ncpb', 'ehealth-actorid-qns', 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP());
 insert into SMP_SERVICE_GROUP(ID, PARTICIPANT_IDENTIFIER, PARTICIPANT_SCHEME,SML_REGISTRED, CREATED_ON, LAST_UPDATED_ON) values (200000, 'urn:brazil:ncpb', 'ehealth-actorid-qns', 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP());
---insert into SMP_SERVICE_GROUP(ID, PARTICIPANT_IDENTIFIER, PARTICIPANT_SCHEME,SML_REGISTRED) values (3, 'urn:poland:ncpb', 'ehealth-participantid-qns', 1);
+
+-- set ownership
+insert into SMP_OWNERSHIP (FK_SG_ID, FK_USER_ID) values (100000, 2);
+insert into SMP_OWNERSHIP (FK_SG_ID, FK_USER_ID) values (200000, 2);
 
 insert into SMP_DOMAIN (ID, DOMAIN_CODE, SML_SUBDOMAIN, SML_SMP_ID, SIGNATURE_KEY_ALIAS, CREATED_ON, LAST_UPDATED_ON) values (1, 'domain','subdomain', 'CEF-SMP-001','sig-key',CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP());
 
- --insert into SMP_OWNERSHIP (FK_SG_ID, FK_USER_ID) values (3, 1);
---insert into SMP_SERVICE_GROUP_DOMAIN (ID, FK_SG_ID, FK_DOMAIN_ID) values (1, 3, 1);
--- insert into smp_ownership(username, businessidentifier, businessidentifierscheme) values ('CN=EHEALTH_SMP_TEST_BRAZIL,O=European Commission,C=BE:48b681ee8e0dcc08', 'urn:australia:ncpb', 'ehealth-actorid-qns');
+insert into SMP_SERVICE_GROUP_DOMAIN (ID, FK_SG_ID, FK_DOMAIN_ID, CREATED_ON, LAST_UPDATED_ON) values (1000,200000, 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP());
 
+insert into SMP_SERVICE_GROUP_DOMAIN (ID, FK_SG_ID, FK_DOMAIN_ID, CREATED_ON, LAST_UPDATED_ON) values (1001,100000, 1,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP());
+insert into SMP_SERVICE_METADATA (ID, FK_SG_DOM_ID, DOCUMENT_IDENTIFIER, DOCUMENT_SCHEME, LAST_UPDATED_ON, CREATED_ON)  values (1000,1001,'doc_7','busdox-docid-qns',CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP());