From 8b12f332b4db265490cf4ab030221d3d62277b0f Mon Sep 17 00:00:00 2001
From: Joze RIHTARSIC <joze.rihtarsic@ext.ec.europa.eu>
Date: Sun, 21 Oct 2018 17:27:35 +0200
Subject: [PATCH] Implementation of metadata dialog, service group dialog,

---
 smp-angular/src/app/app.module.ts             |  24 +-
 .../confirmation-dialog.component.html        |   4 +-
 .../confirmation-dialog.component.ts          |  21 +-
 .../page-header/page-header.component.css     |   5 +
 .../search-table/search-table-controller.ts   |   1 +
 .../search-table/search-table.component.css   |   5 +
 .../search-table/search-table.component.html  |   7 +-
 .../search-table/search-table.component.ts    |  95 +--
 .../src/app/domain/domain-controller.ts       |   9 +-
 .../domain-details-dialog.component.html      |  16 +-
 .../domain-details-dialog.component.ts        |  51 +-
 .../src/app/domain/domain.component.ts        |   7 +-
 ...ervice-group-details-dialog.component.html | 129 +++-
 .../service-group-details-dialog.component.ts | 283 ++++++---
 .../service-group-domain-edit-ro.model.ts     |  16 +-
 .../service-group-edit-controller.ts          |  16 +-
 .../service-group-edit-ro.model.ts            |  11 +-
 .../service-group-edit.component.html         |  20 +-
 .../service-group-edit.component.ts           |  87 ++-
 ...group-extension-wizard-dialog.component.ts |  24 +-
 ...rvice-group-metadata-dialog.component.html | 158 +++--
 ...service-group-metadata-dialog.component.ts | 188 +++++-
 ...rvice-metadata-validation-edit-ro.model.ts |  10 +
 .../service-metadata-edit-ro.model.ts         |   7 +-
 ...vice-metadata-wizard-dialog.component.html | 107 +++-
 ...ervice-metadata-wizard-dialog.component.ts |  66 +-
 .../service-metadata-wizard-edit-ro.model.ts  |  18 +-
 .../service-group-search-controller.ts        |   4 +-
 .../service-group-search.component.html       |   2 +-
 .../service-group-search.component.ts         |  14 +-
 smp-angular/src/app/smp.constants.ts          |   4 +
 smp-angular/src/app/user/user-controller.ts   |   3 +
 smp-angular/src/styles.css                    |   4 +-
 .../conversion/CaseSensitivityNormalizer.java |  14 +-
 .../smp/conversion/ExtensionConverter.java    |  16 +-
 .../conversion/ServiceMetadataConverter.java  |   2 +
 .../smp/data/model/DBServiceGroup.java        |  23 +-
 .../smp/data/model/DBServiceGroupDomain.java  |  21 +
 .../ec/edelivery/smp/data/ui/BaseRO.java      |   4 +-
 .../edelivery/smp/data/ui/CertificateRO.java  |   9 +
 .../smp/data/ui/ServiceGroupDomainRO.java     |  65 +-
 .../smp/data/ui/ServiceGroupExtensionRO.java  |  30 +-
 .../edelivery/smp/data/ui/ServiceGroupRO.java |  35 +-
 .../smp/data/ui/ServiceGroupSearchRO.java     |  36 +-
 .../smp/data/ui/ServiceMetadataRO.java        |  40 +-
 .../data/ui/ServiceMetadataValidationRO.java  |  67 ++
 .../smp/exceptions/ErrorBusinessCode.java     |   1 +
 .../edelivery/smp/exceptions/ErrorCode.java   |  11 +
 .../smp/services/ServiceGroupService.java     |  11 +-
 .../ui/UIServiceGroupSearchService.java       | 207 +------
 .../services/ui/UIServiceGroupService.java    | 581 +++++++++++++++---
 .../services/ui/UIServiceMetadataService.java | 579 ++---------------
 .../smp/services/ui/UIUserService.java        | 119 ++--
 .../conversion/ExtensionConverterTest.java    |   5 +-
 .../ServiceGroupServiceTestService.java       |   1 -
 .../UIServiceGroupServiceIntegrationTest.java | 271 +++++++-
 .../ui/UIUserServiceIntegrationTest.java      |  33 +-
 .../edelivery/smp/testutil/TestDBUtils.java   |   8 +-
 .../edelivery/smp/testutil/TestROUtils.java   | 178 +++---
 .../examples/extensions/extensionCustom.xml   |   4 +-
 .../examples/extensions/extensionInvalid.xml  |  13 +-
 .../extensions/extensionValidMultiple.xml     |  12 +-
 .../examples/extensions/extensionValidOne.xml |  11 +-
 .../src/test/resources/keystores/SMPtest.crt  |  19 -
 .../src/test/resources/keystores/TestCase.crt |  19 -
 .../mysql-4.1_integration_test_data.sql       |   2 +-
 .../smp/monitor/MonitorResource.java          |   1 -
 .../ec/edelivery/smp/ui/SearchResource.java   |  17 +-
 .../smp/ui/ServiceGroupResource.java          |  27 +-
 .../smp/ui/ServiceMetadataResource.java       |  35 +-
 .../ec/edelivery/smp/ui/UserResource.java     |  11 +-
 .../mysql5innodb-4.1.0-SNAPSHOT.ddl           |   4 +-
 .../oracle10g-4.1.0-SNAPSHOT.ddl              |   4 +-
 .../smp/ui/ServiceGroupResourceTest.java      |  29 +-
 .../webapp_integration_test_data.sql          |   8 +-
 75 files changed, 2328 insertions(+), 1671 deletions(-)
 create mode 100644 smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-metadata-validation-edit-ro.model.ts
 create mode 100644 smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceMetadataValidationRO.java
 delete mode 100644 smp-server-library/src/test/resources/keystores/SMPtest.crt
 delete mode 100644 smp-server-library/src/test/resources/keystores/TestCase.crt

diff --git a/smp-angular/src/app/app.module.ts b/smp-angular/src/app/app.module.ts
index e6055012d..c95ff58fd 100644
--- a/smp-angular/src/app/app.module.ts
+++ b/smp-angular/src/app/app.module.ts
@@ -5,22 +5,20 @@ import {HttpClient, HttpClientModule} from '@angular/common/http';
 import {FlexLayoutModule} from "@angular/flex-layout";
 import {
   MatButtonModule,
+  MatCardModule,
+  MatDatepickerModule,
   MatDialogModule,
+  MatExpansionModule,
   MatIconModule,
   MatInputModule,
   MatListModule,
   MatMenuModule,
   MatSelectModule,
   MatSidenavModule,
-  MatTooltipModule,
-  MatExpansionModule,
-  MatDatepicker,
-  MatCardModule,
-  MatDatepickerModule,
   MatSlideToggleModule,
-  MatTab,
-  MatAccordion,
   MatTabsModule,
+  MatToolbarModule,
+  MatTooltipModule,
 } from '@angular/material';
 import "hammerjs";
 
@@ -72,9 +70,11 @@ import {DomainDetailsDialogComponent} from './domain/domain-details-dialog/domai
 import {UserDetailsDialogComponent} from './user/user-details-dialog/user-details-dialog.component';
 import {DownloadService} from './download/download.service';
 import {UserService} from './user/user.service';
-import {RoleService} from './security/role.service';
 import {CertificateService} from './user/certificate.service';
 import {GlobalLookups} from "./common/global-lookups";
+import {ServiceGroupExtensionWizardDialogComponent} from "./service-group-edit/service-group-extension-wizard-dialog/service-group-extension-wizard-dialog.component";
+import {ServiceMetadataWizardDialogComponent} from "./service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-dialog.component";
+import {ConfirmationDialogComponent} from "./common/confirmation-dialog/confirmation-dialog.component";
 
 @NgModule({
   declarations: [
@@ -92,11 +92,14 @@ import {GlobalLookups} from "./common/global-lookups";
     SaveDialogComponent,
     ServiceGroupMetadataDialogComponent,
     CancelDialogComponent,
+    ConfirmationDialogComponent,
     RowLimiterComponent,
     DatePipe,
     CapitalizeFirstPipe,
     DefaultPasswordDialogComponent,
     ServiceGroupDetailsDialogComponent,
+    ServiceGroupExtensionWizardDialogComponent,
+    ServiceMetadataWizardDialogComponent,
     ColumnPickerComponent,
     PageHelperComponent,
     ClearInvalidDirective,
@@ -110,9 +113,12 @@ import {GlobalLookups} from "./common/global-lookups";
     AppComponent,
     ServiceGroupMetadataDialogComponent,
     ServiceGroupDetailsDialogComponent,
+    ServiceGroupExtensionWizardDialogComponent,
+    ServiceMetadataWizardDialogComponent,
     DomainDetailsDialogComponent,
     UserDetailsDialogComponent,
     CancelDialogComponent,
+    ConfirmationDialogComponent,
     SaveDialogComponent,
     DefaultPasswordDialogComponent,
   ],
@@ -128,6 +134,7 @@ import {GlobalLookups} from "./common/global-lookups";
     MatDatepickerModule,
     MatDialogModule,
     MatTooltipModule,
+    MatToolbarModule,
     MatMenuModule,
     MatInputModule,
     MatIconModule,
@@ -155,7 +162,6 @@ import {GlobalLookups} from "./common/global-lookups";
     DownloadService,
     UserService,
     CertificateService,
-    RoleService,
     GlobalLookups,
     DatePipe,
     {
diff --git a/smp-angular/src/app/common/confirmation-dialog/confirmation-dialog.component.html b/smp-angular/src/app/common/confirmation-dialog/confirmation-dialog.component.html
index d8bc1fd3c..6b9640536 100644
--- a/smp-angular/src/app/common/confirmation-dialog/confirmation-dialog.component.html
+++ b/smp-angular/src/app/common/confirmation-dialog/confirmation-dialog.component.html
@@ -1,6 +1,6 @@
 <div style="width: 500px;text-align: center">
-  <h1 mat-dialog-title>Do you want to cancel all unsaved operations?</h1>
-
+  <h1 mat-dialog-title>{{title}}</h1>
+  <div class="panel">{{description}}</div>
   <div class="divTable">
     <div class="divTableBody">
 
diff --git a/smp-angular/src/app/common/confirmation-dialog/confirmation-dialog.component.ts b/smp-angular/src/app/common/confirmation-dialog/confirmation-dialog.component.ts
index add7e0939..35d6694cf 100644
--- a/smp-angular/src/app/common/confirmation-dialog/confirmation-dialog.component.ts
+++ b/smp-angular/src/app/common/confirmation-dialog/confirmation-dialog.component.ts
@@ -1,14 +1,21 @@
-import {Component} from '@angular/core';
-import {MatDialogRef} from '@angular/material';
+import {Component, Inject} from '@angular/core';
+import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material';
 
 @Component({
-  selector: 'app-cancel-dialog',
-  templateUrl: './cancel-dialog.component.html',
-  styleUrls: ['./cancel-dialog.component.css']
+  selector: 'app-confirmation-dialog',
+  templateUrl: './confirmation-dialog.component.html',
+  styleUrls: ['./confirmation-dialog.component.css']
 })
-export class CancelDialogComponent {
+export class ConfirmationDialogComponent {
 
-  constructor(public dialogRef: MatDialogRef<CancelDialogComponent>) {
+  title: string;
+  description: string
+
+  constructor(public dialogRef: MatDialogRef<ConfirmationDialogComponent>,
+              @Inject(MAT_DIALOG_DATA) public data: any) {
+    this.title=data.title;
+    this.description=data.description;
   }
 
+
 }
diff --git a/smp-angular/src/app/common/page-header/page-header.component.css b/smp-angular/src/app/common/page-header/page-header.component.css
index e25fefba3..f55524a56 100644
--- a/smp-angular/src/app/common/page-header/page-header.component.css
+++ b/smp-angular/src/app/common/page-header/page-header.component.css
@@ -1,4 +1,9 @@
 :host:before {
 	display: none !important;
 	content: '' !important;
+  margin-bottom: 0 !important;
+}
+
+.h1 {
+  margin-bottom: 0 !important;
 }
diff --git a/smp-angular/src/app/common/search-table/search-table-controller.ts b/smp-angular/src/app/common/search-table/search-table-controller.ts
index ad5d26b1a..9ccf73d49 100644
--- a/smp-angular/src/app/common/search-table/search-table-controller.ts
+++ b/smp-angular/src/app/common/search-table/search-table-controller.ts
@@ -7,4 +7,5 @@ export interface SearchTableController {
   delete(row);
   newRow(): SearchTableEntity;
   newDialog(config?: MatDialogConfig): MatDialogRef<any>;
+  dataSaved();
 }
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 3da6057ee..2a6978a2f 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
@@ -41,3 +41,8 @@
   padding: 0 !important;
   margin: 0 !important;
 }
+
+.h1 {
+  margin-bottom: 0 !important;
+}
+
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 67c1b7e94..89fa000b2 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
@@ -1,6 +1,5 @@
 <div fxLayout="column" style="position: absolute; top: 5px; bottom: 5px; left: 5px; right: 5px;">
-  <page-header flex id="{{id}}_header_id">{{title}}</page-header>
-
+  <h1  flex id="{{id}}_header_id" style="margin: 0 !important;">{{title}}</h1>
   <div *ngIf="showSearchPanel" fxFlex="20" class="selectionCriteria">
     <mat-card>
       <mat-card-content>
@@ -22,7 +21,7 @@
   <div class="panel" fxFlex fxLayout="column">
     <div class="group-filter-button" fxFlex="50px">
       <span class="row-button">
-        <app-row-limiter [pageSizes]="rowLimiter.pageSizes"
+        <app-row-limiter  [pageSizes]="rowLimiter.pageSizes"
                          (onPageSizeChanged)="changePageSize($event.value)"></app-row-limiter>
       </span>
       <!-- no need for this for SMP 4.1 <span class="column-filter-button">
@@ -51,7 +50,7 @@
                    (page)="onPage($event)"
                    (sort)="onSort($event)"
                    [selected]="selected"
-                   [selectionType]="'single'"
+                   [selectionType]="'multi'"
                    (activate)="onActivate($event)"
                    (select)="onSelect($event)"
                     >
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 b91db7ca1..57361d241 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
@@ -1,19 +1,19 @@
-import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, TemplateRef, ViewChild} from '@angular/core';
+import {Component, Input, OnInit, TemplateRef, ViewChild} from '@angular/core';
 import {SearchTableResult} from './search-table-result.model';
 import {Observable} from 'rxjs';
 import {AlertService} from '../../alert/alert.service';
 import {MatDialog, MatDialogRef} from '@angular/material';
 import {ColumnPicker} from '../column-picker/column-picker.model';
 import {RowLimiter} from '../row-limiter/row-limiter.model';
-import {AlertComponent} from '../../alert/alert.component';
 import {SearchTableController} from './search-table-controller';
-import {finalize, map} from 'rxjs/operators';
+import {finalize} from 'rxjs/operators';
 import {SearchTableEntity} from './search-table-entity.model';
 import {SearchTableEntityStatus} from './search-table-entity-status.model';
 import {CancelDialogComponent} from '../cancel-dialog/cancel-dialog.component';
 import {SaveDialogComponent} from '../save-dialog/save-dialog.component';
 import {DownloadService} from '../../download/download.service';
 import {HttpClient, HttpParams} from '@angular/common/http';
+import {ConfirmationDialogComponent} from "../confirmation-dialog/confirmation-dialog.component";
 
 
 @Component({
@@ -61,6 +61,7 @@ export class SearchTableComponent implements OnInit {
   offset: number = 0;
   orderBy: string = null;
   asc = false;
+  forceRefresh: boolean = false;
 
   constructor(protected http: HttpClient,
               protected alertService: AlertService,
@@ -74,7 +75,7 @@ export class SearchTableComponent implements OnInit {
       cellTemplate: this.rowIndex,
       name: 'Index',
       width: 50,
-      maxWidth:80,
+      maxWidth: 80,
       sortable: false
     };
 
@@ -82,25 +83,25 @@ export class SearchTableComponent implements OnInit {
       cellTemplate: this.rowActions,
       name: 'Actions',
       width: 250,
-      maxWidth:250,
+      maxWidth: 250,
       sortable: false
     };
-    this.columnExpandDetails= {
+    this.columnExpandDetails = {
       cellTemplate: this.rowExpand,
       name: ' ',
       width: 40,
-      maxWidth:50,
+      maxWidth: 50,
       sortable: false
     };
 
     // Add actions to last column
     if (this.columnPicker) {
       // prepend columns
-      if (!!this.tableRowDetailContainer){
+      if (!!this.tableRowDetailContainer) {
         this.columnPicker.allColumns.unshift(this.columnExpandDetails);
         this.columnPicker.selectedColumns.unshift(this.columnExpandDetails);
       }
-      if (this.showIndexColumn){
+      if (this.showIndexColumn) {
         this.columnPicker.allColumns.unshift(this.columnIndex);
         this.columnPicker.selectedColumns.unshift(this.columnIndex);
       }
@@ -124,8 +125,8 @@ export class SearchTableComponent implements OnInit {
   getTableDataEntries$(offset: number, pageSize: number, orderBy: string, asc: boolean): Observable<SearchTableResult> {
 
     let params: HttpParams = new HttpParams()
-       .set('page', offset.toString())
-       .set('pageSize', pageSize.toString());
+      .set('page', offset.toString())
+      .set('pageSize', pageSize.toString());
 
 
     for (let filterProperty in this.filter) {
@@ -134,9 +135,8 @@ export class SearchTableComponent implements OnInit {
       }
     }
 
-    // TODO move to the HTTP service
     this.loading = true;
-    return this.http.get<SearchTableResult>(this.url, { params }).pipe(
+    return this.http.get<SearchTableResult>(this.url, {params}).pipe(
       finalize(() => {
         this.loading = false;
       })
@@ -144,29 +144,48 @@ export class SearchTableComponent implements OnInit {
   }
 
   page(offset: number, pageSize: number, orderBy: string, asc: boolean) {
-    this.getTableDataEntries$(offset, pageSize, orderBy, asc).subscribe((result: SearchTableResult ) => {
+    if (this.safeRefresh) {
+
+      this.dialog.open(ConfirmationDialogComponent, {
+        data: {
+          title: "Not persisted data!",
+          description: "Action will refresh all data and not saved data will be lost. Do you wish to continue?"
+        }
+      }).afterClosed().subscribe(result => {
+        if (result) {
+          this.pageInternal(offset, pageSize, orderBy, asc);
+        }
+      })
+    } else {
+      this.pageInternal(offset, pageSize, orderBy, asc);
+    }
+  }
+
+  private pageInternal(offset: number, pageSize: number, orderBy: string, asc: boolean) {
+    this.getTableDataEntries$(offset, pageSize, orderBy, asc).subscribe((result: SearchTableResult) => {
       this.offset = offset;
       this.rowLimiter.pageSize = pageSize;
       this.orderBy = orderBy;
       this.asc = asc;
 
       this.unselectRows();
+      this.forceRefresh=false;
       this.count = result.count; // must be set else table can not calculate page numbers
       this.rows = result.serviceEntities.map(serviceEntity => {
-        return {...serviceEntity,
+        return {
+          ...serviceEntity,
           status: SearchTableEntityStatus.PERSISTED,
-          deleted: false}
+          deleted: false
+        }
       });
-      /*
-      if(this.count > AlertComponent.MAX_COUNT_CSV) {
-        this.alertService.error("Maximum number of rows reached for downloading CSV");
-      }*/
     }, (error: any) => {
       this.alertService.error("Error occurred:" + error);
     });
   }
 
   onPage(event) {
+
+
     this.page(event.offset, event.pageSize, this.orderBy, this.asc);
   }
 
@@ -177,8 +196,8 @@ export class SearchTableComponent implements OnInit {
 
   onSelect({selected}) {
     this.selected = [...selected];
-    if(this.editButtonEnabled) {
-      this.rowNumber = this.selected[0]["$$index"];
+    if (this.editButtonEnabled) {
+      this.rowNumber = this.rows.indexOf(this.selected[0]);
     }
   }
 
@@ -203,14 +222,14 @@ export class SearchTableComponent implements OnInit {
 
   onNewButtonClicked() {
     const formRef: MatDialogRef<any> = this.searchTableController.newDialog({
-      data: { edit: false }
+      data: {edit: false}
     });
     formRef.afterClosed().subscribe(result => {
       if (result) {
         this.rows = [...this.rows, {...formRef.componentInstance.getCurrent()}];
         //this.rows = this.rows.concat(formRef.componentInstance.current);
         this.count++;
-       // this.searchtable.refresh();
+        // this.searchtable.refresh();
       } else {
         this.unselectRows();
       }
@@ -244,13 +263,13 @@ export class SearchTableComponent implements OnInit {
             // this.isBusy = false;
             // this.getUsers();
             this.alertService.success('The operation \'update\' completed successfully.', false);
+            this.forceRefresh = true;
             this.onRefresh();
+            this.searchTableController.dataSaved();
             if (withDownloadCSV) {
               this.downloadService.downloadNative(/*UserComponent.USER_CSV_URL TODO: use CSV url*/ '');
             }
           }, err => {
-            // this.isBusy = false;
-            // this.getUsers();
             this.alertService.exception('The operation \'update\' not completed successfully.', err, false);
           });
         } else {
@@ -295,6 +314,10 @@ export class SearchTableComponent implements OnInit {
     return dirty;
   }
 
+  get safeRefresh(): boolean {
+    return !(!this.submitButtonsEnabled ||  this.forceRefresh) ;
+  }
+
   private editSearchTableEntity(rowNumber: number) {
     const row = this.rows[rowNumber];
     const formRef: MatDialogRef<any> = this.searchTableController.newDialog({
@@ -305,23 +328,25 @@ export class SearchTableComponent implements OnInit {
         const status = row.status === SearchTableEntityStatus.PERSISTED
           ? SearchTableEntityStatus.UPDATED
           : row.status;
-         this.rows[rowNumber] = {...formRef.componentInstance.getCurrent(), status};
-         this.rows = [...this.rows];
+        this.rows[rowNumber] = {...formRef.componentInstance.getCurrent(), status};
+        this.rows = [...this.rows];
       }
     });
   }
-  public updateTableRow(rowNumber:number, row:any, status:SearchTableEntityStatus ) {
+
+  public updateTableRow(rowNumber: number, row: any, status: SearchTableEntityStatus) {
     this.rows[rowNumber] = {...row, status};
     this.rows = [...this.rows];
   }
-  public getRowNumber(row:any){
-    return  this.rows.indexOf(row);
+
+  public getRowNumber(row: any) {
+    return this.rows.indexOf(row);
   }
 
 
   private editSearchTableEntityRow(row: SearchTableEntity) {
-      let rowNumber = this.rows.indexOf(row);
-      this.editSearchTableEntity(rowNumber);
+    let rowNumber = this.rows.indexOf(row);
+    this.editSearchTableEntity(rowNumber);
   }
 
   private deleteSearchTableEntities(rows: Array<SearchTableEntity>) {
@@ -348,12 +373,12 @@ export class SearchTableComponent implements OnInit {
     this.selected = [];
   }
 
-  toggleExpandRow(selectedRow: any){
+  toggleExpandRow(selectedRow: any) {
     //this.searchTableController.toggleExpandRow(selectedRow);
     this.searchTable.rowDetail.toggleExpandRow(selectedRow);
   }
 
-  onDetailToggle (event){
+  onDetailToggle(event) {
 
   }
 }
diff --git a/smp-angular/src/app/domain/domain-controller.ts b/smp-angular/src/app/domain/domain-controller.ts
index 7cf4aea7c..6eb47da5f 100644
--- a/smp-angular/src/app/domain/domain-controller.ts
+++ b/smp-angular/src/app/domain/domain-controller.ts
@@ -3,14 +3,14 @@ import {MatDialog, MatDialogConfig, MatDialogRef} from '@angular/material';
 import {DomainDetailsDialogComponent} from './domain-details-dialog/domain-details-dialog.component';
 import {DomainRo} from './domain-ro.model';
 import {SearchTableEntityStatus} from '../common/search-table/search-table-entity-status.model';
-import {UserDetailsDialogComponent} from "../user/user-details-dialog/user-details-dialog.component";
+import {GlobalLookups} from "../common/global-lookups";
 
 export class DomainController implements SearchTableController {
 
-  constructor(public dialog: MatDialog) {
+  constructor(protected lookups: GlobalLookups, public dialog: MatDialog) {
   }
 
-  public showDetails(row: any) {
+  public showDetails( row: any) {
     let dialogRef: MatDialogRef<DomainDetailsDialogComponent> = this.dialog.open(DomainDetailsDialogComponent);
     dialogRef.afterClosed().subscribe(result => {
       //Todo:
@@ -40,4 +40,7 @@ export class DomainController implements SearchTableController {
       status: SearchTableEntityStatus.NEW
     }
   }
+  public dataSaved() {
+    this.lookups.refreshDomainLookup();
+  }
 }
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 49f9bcb12..d20d64954 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
@@ -9,7 +9,10 @@
             <input matInput placeholder="Domain Code (For WS API integration: the Domain property.)" name="domainCode" id="domainCode_id"
                    [formControl]="domainForm.controls['domainCode']" maxlength="255" required>
             <div *ngIf="(!editMode && domainForm.controls['domainCode'].touched || editMode) &&  domainForm.controls['domainCode'].hasError('pattern')" style="color:red; font-size: 70%">
-             Domain could must contain only chars and numbers.
+             Domain code must contain only chars and numbers.
+            </div>
+            <div *ngIf="(!editMode && domainForm.controls['domainCode'].touched || editMode) &&  domainForm.controls['domainCode'].hasError('notInList')" style="color:red; font-size: 70%">
+              The Domain code already exists!
             </div>
           </mat-form-field>
           <mat-form-field style="width:100%">
@@ -18,6 +21,9 @@
             <div *ngIf="(!editMode && domainForm.controls['smlSubdomain'].touched || editMode) &&  domainForm.controls['smlSubdomain'].hasError('pattern')" style="color:red; font-size: 70%">
               SML domain must be valid DNS part (AlphaNumeric with optional char - or must be empty for peppol).
             </div>
+            <div *ngIf="(!editMode && domainForm.controls['smlSubdomain'].touched || editMode) &&  domainForm.controls['smlSubdomain'].hasError('notInList')" style="color:red; font-size: 70%">
+              The SML subdomain is already defined!
+            </div>
           </mat-form-field>
           <mat-form-field style="width:100%">
             <input matInput placeholder="Response signature Certificate" name="signatureKeyAlias" id="signatureKeyAlias_id"
@@ -34,13 +40,15 @@
               <input matInput placeholder="SML SMP identifier (SMP ID used for SML )" name="smlSmpId" id="smlSMPId_id"
                      [formControl]="domainForm.controls['smlSmpId']" maxlength="255" required>
               <div *ngIf="(!editMode && domainForm.controls['smlSmpId'].touched || editMode) &&  domainForm.controls['smlSmpId'].hasError('pattern')" style="color:red; font-size: 70%">
-                SML SMP ID  must be valid DNS part (AlphaNumeric with optional char -).
+                SML SMP ID  must be valid DNS part (AlphaNumeric with optional char -)!
+              </div>
+              <div *ngIf="(!editMode && domainForm.controls['smlSmpId'].touched || editMode) &&  domainForm.controls['smlSmpId'].hasError('notInList')" style="color:red; font-size: 70%">
+                SML SMP ID already exists!
               </div>
-
             </mat-form-field>
             <mat-form-field style="width:100%">
               <input matInput placeholder="ClientCert Header" name="Client certificate" id="smlClientHeader_id"
-                     [formControl]="domainForm.controls['smlClientKeyAlias']" maxlength="255" >
+                     [formControl]="domainForm.controls['smlClientCertHeader']" maxlength="255" >
             </mat-form-field>
             <mat-form-field style="width:100%">
               <input matInput placeholder="ClientCert Alias" name="Client certificate" id="smlClientKeyAlias_id"
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 9454eafb3..611a90067 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
@@ -1,13 +1,10 @@
 import {Component, Inject} from '@angular/core';
 import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material';
-import {UserRo} from "../../user/user-ro.model";
-import {FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms";
+import {AbstractControl, FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms";
 import {DomainRo} from "../domain-ro.model";
 import {AlertService} from "../../alert/alert.service";
-import {UserDetailsDialogComponent} from "../../user/user-details-dialog/user-details-dialog.component";
-import {CertificateService} from "../../user/certificate.service";
-import {UserService} from "../../user/user.service";
 import {SearchTableEntityStatus} from "../../common/search-table/search-table-entity-status.model";
+import {GlobalLookups} from "../../common/global-lookups";
 
 @Component({
   selector: 'domain-details-dialog',
@@ -26,14 +23,23 @@ export class DomainDetailsDialogComponent {
   domainForm: FormGroup;
   domain;
 
+  notInList(list: string[], exception: string) {
+    return (c: AbstractControl): { [key: string]: any } => {
+      if (c.value && c.value !== exception && list.includes(c.value))
+        return {'notInList': {valid: false}};
 
-  constructor(private dialogRef: MatDialogRef<DomainDetailsDialogComponent>,
+      return null;
+    }
+  }
+
+  constructor(private lookups: GlobalLookups,
+              private dialogRef: MatDialogRef<DomainDetailsDialogComponent>,
               private alertService: AlertService,
               @Inject(MAT_DIALOG_DATA) public data: any,
               private fb: FormBuilder) {
 
     this.editMode = data.edit;
-    this.formTitle = this.editMode ?  DomainDetailsDialogComponent.EDIT_MODE: DomainDetailsDialogComponent.NEW_MODE;
+    this.formTitle = this.editMode ? DomainDetailsDialogComponent.EDIT_MODE : DomainDetailsDialogComponent.NEW_MODE;
     this.current = this.editMode
       ? {
         ...data.row,
@@ -49,26 +55,33 @@ export class DomainDetailsDialogComponent {
 
     this.domainForm = fb.group({
 
-      'domainCode': new FormControl({value:'', disabled: this.editMode}, [Validators.pattern(this.domainCodePattern)]),
-      'smlSubdomain': new FormControl({value: '', disabled: this.editMode},  [Validators.pattern(this.dnsDomainPattern)]),
-      'smlSmpId': new FormControl({value: ''}, [Validators.pattern(this.dnsDomainPattern)]),
+      'domainCode': new FormControl({value: '', disabled: this.editMode}, [Validators.pattern(this.domainCodePattern),
+        this.notInList(this.lookups.cachedDomainList.map(a => a.domainCode), this.current.domainCode)]),
+      'smlSubdomain': new FormControl({
+        value: '',
+        disabled: this.editMode
+      }, [Validators.pattern(this.dnsDomainPattern),
+        this.notInList(this.lookups.cachedDomainList.map(a => a.smlSubdomain), this.current.smlSubdomain)]),
+      'smlSmpId': new FormControl({value: ''}, [Validators.pattern(this.dnsDomainPattern),
+        this.notInList(this.lookups.cachedDomainList.map(a => a.smlSmpId), this.current.smlSmpId)]),
+      'smlClientCertHeader': new FormControl({value: ''}, null),
       'smlClientKeyAlias': new FormControl({value: ''}, null),
-      'signatureKeyAlias': new FormControl({value:''}, null),
+      'signatureKeyAlias': new FormControl({value: ''}, null),
 
-    }, {
-      //validator: this.passwordConfirmationValidator
     });
     this.domainForm.controls['domainCode'].setValue(this.current.domainCode);
     this.domainForm.controls['smlSubdomain'].setValue(this.current.smlSubdomain);
     this.domainForm.controls['smlSmpId'].setValue(this.current.smlSmpId);
+    this.domainForm.controls['smlClientCertHeader'].setValue(this.current.smlClientCertHeader);
     this.domainForm.controls['smlClientKeyAlias'].setValue(this.current.smlClientKeyAlias);
     this.domainForm.controls['signatureKeyAlias'].setValue(this.current.signatureKeyAlias);
 
 
   }
+
   submitForm() {
     this.checkValidity(this.domainForm)
-     this.dialogRef.close(true);
+    this.dialogRef.close(true);
   }
 
   checkValidity(g: FormGroup) {
@@ -86,21 +99,27 @@ export class DomainDetailsDialogComponent {
 
   public getCurrent(): DomainRo {
 
-    this.current.domainCode = this.domainForm.value['domainCode'];
-    this.current.smlSubdomain = this.domainForm.value['smlSubdomain'];
+    if (!this.editMode) {
+      this.current.domainCode = this.domainForm.value['domainCode'];
+      this.current.smlSubdomain = this.domainForm.value['smlSubdomain'];
+    }
     this.current.smlSmpId = this.domainForm.value['smlSmpId'];
+    this.current.smlClientCertHeader = this.domainForm.value['smlClientCertHeader'];
     this.current.smlClientKeyAlias = this.domainForm.value['smlClientKeyAlias'];
     this.current.signatureKeyAlias = this.domainForm.value['signatureKeyAlias'];
 
     return this.current;
 
   }
+
   updateDomainCode(event) {
     this.current.domainCode = event.target.value;
   }
+
   updateSmlDomain(event) {
     this.current.smlSubdomain = event.target.value;
   }
+
   updateSmlSmpId(event) {
     this.current.smlSmpId = event.target.value;
   }
diff --git a/smp-angular/src/app/domain/domain.component.ts b/smp-angular/src/app/domain/domain.component.ts
index 73e617c23..34e1d6c87 100644
--- a/smp-angular/src/app/domain/domain.component.ts
+++ b/smp-angular/src/app/domain/domain.component.ts
@@ -1,11 +1,12 @@
 import {Component, OnInit, TemplateRef, ViewChild} from '@angular/core';
 import {ColumnPicker} from '../common/column-picker/column-picker.model';
-import {MatDialog, MatDialogRef} from '@angular/material';
+import {MatDialog} 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";
+import {GlobalLookups} from "../common/global-lookups";
 
 @Component({
   moduleId: module.id,
@@ -24,11 +25,11 @@ export class DomainComponent implements OnInit {
   filter: any = {};
 
 
-  constructor(protected http: HttpClient, protected alertService: AlertService, public dialog: MatDialog) {
+  constructor(protected lookups: GlobalLookups, protected http: HttpClient, protected alertService: AlertService, public dialog: MatDialog) {
   }
 
   ngOnInit() {
-    this.domainController = new DomainController(this.dialog);
+    this.domainController = new DomainController(this.lookups, this.dialog);
 
     this.columnPicker.allColumns = [
       {
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 8161bf22d..30a844949 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,6 +1,6 @@
 <h2 mat-dialog-title>{{formTitle}}</h2>
 
-<mat-dialog-content style="height:620px;width:1200px">
+<mat-dialog-content style="height:600px;width:1200px">
   <div fxLayout="row">
     <div fxLayout="column">
       <mat-card fxFlex="200px">
@@ -9,8 +9,7 @@
           <div class="panel">
           <mat-form-field style="width:100%">
             <input matInput placeholder="Participant identifier" name="participantIdentifier"
-                   value="{{current.participantIdentifier}}" id="participantIdentifier_id"
-                   (blur)="updateParticipantIdentifier($event)"
+                   id="participantIdentifier_id"
                    [formControl]="dialogForm.controls['participantIdentifier']" maxlength="255" required>
             <div
               *ngIf="(!editMode && dialogForm.controls['participantIdentifier'].touched || editMode) &&  dialogForm.controls['participantIdentifier'].hasError('required')"
@@ -21,8 +20,8 @@
 
           <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']"
+                   id="participantScheme_id"
+                   [formControl]="dialogForm.controls['participantScheme']"
                    maxlength="255" required>
             <div
               *ngIf="(!editMode && dialogForm.controls['participantScheme'].touched || editMode) &&  dialogForm.controls['participantScheme'].hasError('required')"
@@ -34,22 +33,27 @@
         </mat-card-content>
       </mat-card>
       <mat-card>
-        <!-- mat-card-title>Owners/Domains</mat-card-title -->
         <mat-card-content>
-
           <mat-accordion>
             <mat-expansion-panel [expanded]="true">
               <mat-expansion-panel-header>
-                <mat-panel-title>Owners</mat-panel-title>
+                <mat-panel-title>Owners*
+                </mat-panel-title>
                 <mat-panel-description>
-                  Selected user count: {{usersSelected.selectedOptions.selected.length}}
+                  <div>
+                  Selected user count: {{usersSelected.selectedOptions?.selected.length}}
+                  <div
+                    *ngIf="(!editMode && dialogForm.controls['users'].touched || editMode) &&  dialogForm.controls['users'].hasError('minSelectedListCount')"
+                    style="color:red; font-size: 70%">
+                    At least one user (owner) must be selected!
+                  </div>
+                  </div>
                 </mat-panel-description>
               </mat-expansion-panel-header>
               <mat-selection-list  #usersSelected [compareWith]="compareTableItemById"
-                                  (selectionChange)="userListChanged(usersSelected.selectedOptions.selected,$event)"
-                                  [formControl]="formControlUsers"
+                                  [formControl]="dialogForm.controls['users']"
                                   style="height: 200px;  overflow-y: scroll; overflow-x: auto;">
-                <mat-list-option *ngFor="let user of userlist" [value]='user'>
+                <mat-list-option *ngFor="let user of lookups?.cachedUserList" [value]='user'>
                   {{user.id}} - {{user.username?user.username:user.id}}
                 </mat-list-option>
               </mat-selection-list>
@@ -57,39 +61,104 @@
 
             <mat-expansion-panel >
               <mat-expansion-panel-header>
-                <mat-panel-title>Domains</mat-panel-title>
+                <mat-panel-title>Domains*</mat-panel-title>
                 <mat-panel-description>
-                  Selected domain count: {{domainSelected.selectedOptions.selected.length}}
+                  <div>
+                    Selected domain count: {{domainSelector.selectedOptions?.selected.length}}
+                    <div
+                      *ngIf="(!editMode && dialogForm.controls['serviceGroupDomains'].touched || editMode) &&  dialogForm.controls['serviceGroupDomains'].hasError('minSelectedListCount')"
+                      style="color:red; font-size: 70%">
+                      At least one domain must be selected!
+                    </div>
+                  </div>
                 </mat-panel-description>
               </mat-expansion-panel-header>
-              <mat-selection-list  #domainSelected [compareWith]="compareTableItemById"
-                                   [formControl]="formControlDomain"
+              <mat-selection-list  #domainSelector [compareWith]="compareDomain"
+                                   [formControl]="dialogForm.controls['serviceGroupDomains']"
+                                   (selectionChange)="onDomainSelectionChanged($event)"
                                    style="height: 200px;  overflow-y: scroll; overflow-x: auto;">
-                <mat-list-option *ngFor="let domain of domainList" [value]='domain'>
+                <mat-list-option *ngFor="let domain of lookups.cachedDomainList" [value]='domain'>
                   {{domain.domainCode}} ({{domain.smlSubdomain}})
                 </mat-list-option>
               </mat-selection-list>
             </mat-expansion-panel>
           </mat-accordion>
-
-
-          <div
-            *ngIf="(!editMode && dialogForm.controls['users'].touched || editMode) &&  dialogForm.controls['users'].hasError('minSelectedListCount')"
-            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>
+      <mat-card-title>Extension
+        <div style="font-size:70%">
           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>
+        </div>
+      </mat-card-title>
+
+      <mat-card-content >
+        <mat-toolbar>
+          <mat-toolbar-row>
+            <button mat-raised-button color="primary"
+                    matTooltip="Clear the extension content."
+                    matTooltipPosition="below"
+            (click)="onExtensionDelete()" >
+              <mat-icon>clear</mat-icon>
+              <span>Clear</span>
+            </button>
+            <button mat-raised-button color="primary"
+                    matTooltip="Opens wizard for adding new Extension. New extension is appended to existing extensions."
+                    matTooltipPosition="below"
+              (click)="onStartWizardDialog()">
+              <mat-icon>add_box</mat-icon>
+              <span>Extension wizard</span>
+            </button>
+            <button mat-raised-button color="primary"
+                    atTooltip="Validate extension by XSD schema."
+                    matTooltipPosition="below"
+                    (click)="onExtensionValidate()">
+              <mat-icon>warning</mat-icon>
+              <span>Validate</span>
+            </button>
+            <!--  add and test this fuction on backend
+            button mat-raised-button color="primary"
+                    atTooltip="Pritty print extension!"
+                    matTooltipPosition="below"
+                    (click)="onPrettyPrintExtension()">
+              <mat-icon>warning</mat-icon>
+              <span>format XML</span>
+            </button -->
+          </mat-toolbar-row>
+        </mat-toolbar>
+
+        <div style="display: block;" style="border:1px; solid: #999999;margin:5px 0; padding:3px;">
+          <div class="textwrapper">
+            <textarea matInput style="width:100%;border: #03A9F4 1px solid" cols="2" rows="30"
+                      resizeable="false"
+                      id="extensionTextArea"
+                      placeholder="Extension" name="extension"
+                      [formControl]="dialogForm.controls['extension']"
+            ></textarea>
+          </div>
+          <div
+            *ngIf="extensionValidationMessage"
+            [style.color]="isExtensionValid?'green':'red'">
+            {{extensionValidationMessage}}
+          </div>
+
+        </div>
+
+
+
+        <!-- mat-form-field>
+          <div>
+          <textarea style="width:100% !important;height: 400px !important;  -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;"
+
+                    matInput id="extensionTextArea"
+                    placeholder="Extension" name="extension"
+                    [formControl]="dialogForm.controls['extension']"
+          ></textarea>
+  </div>
         </mat-form-field -->
       </mat-card-content>
     </mat-card>
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 7d17a32f1..37ae66154 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,124 +1,118 @@
-import {Component, Inject} from '@angular/core';
-import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material';
+import {ChangeDetectorRef, Component, Inject, OnInit, ViewChild} from '@angular/core';
+import {MAT_DIALOG_DATA, MatDialog, 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";
 import {GlobalLookups} from "../../common/global-lookups";
+import {ServiceGroupExtensionWizardDialogComponent} from "../service-group-extension-wizard-dialog/service-group-extension-wizard-dialog.component";
+import {ServiceGroupExtensionRo} from "./service-extension-edit-ro.model";
+import {DomainRo} from "../../domain/domain-ro.model";
+import {ServiceGroupDomainEditRo} from "../service-group-domain-edit-ro.model";
+import {ConfirmationDialogComponent} from "../../common/confirmation-dialog/confirmation-dialog.component";
 
 @Component({
-  selector: 'app-messagelog-details',
+  selector: 'service-group-details',
   templateUrl: './service-group-details-dialog.component.html',
   styleUrls: ['./service-group-details-dialog.component.css']
 })
-export class ServiceGroupDetailsDialogComponent {
+export class ServiceGroupDetailsDialogComponent implements OnInit {
 
   static readonly NEW_MODE = 'New ServiceGroup';
   static readonly EDIT_MODE = 'ServiceGroup Edit';
 
+  @ViewChild('domainSelector') domainSelector: any;
 
-  userObserver:  Observable< SearchTableResult> ;
-  domainObserver:  Observable< SearchTableResult> ;
-  userlist: Array<UserRo> = [];
-  domainList: Array<DomainRo> = [];
   editMode: boolean;
   formTitle: string;
   current: ServiceGroupEditRo & { confirmation?: string };
 
   dialogForm: FormGroup;
-  dialogFormBuilder: FormBuilder;
-  formControlUsers: FormControl;
-  formControlDomain: FormControl;
-  /*
-  selectedDomain: DomainRo;
-  domainList: Array<any>;
-*/
+  extensionObserver: Observable<ServiceGroupExtensionRo>;
+
+  extensionValidationMessage: String = null;
+  isExtensionValid: boolean = true;
+
+  serviceGroupDomain: ServiceGroupDomainEditRo[];
+
 
   minSelectedListCount(min: number) {
-    return (c: AbstractControl): {[key: string]: any} => {
-      if (c.value.length >= min)
+    return (c: AbstractControl): { [key: string]: any } => {
+      if (c.value && c.value.length >= min)
         return null;
 
-      return { 'minCountOwners': {valid: false }};
+      return {'minSelectedListCount': {valid: false}};
     }
   }
 
-  constructor(protected http: HttpClient,
+  constructor(public dialog: MatDialog,
+              protected http: HttpClient,
               public dialogRef: MatDialogRef<ServiceGroupDetailsDialogComponent>,
               private alertService: AlertService,
-              private lookups: GlobalLookups,
+              public lookups: GlobalLookups,
               @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.updateUserData();
-    });
-    // domain service group
-    this.lookups.getDomainLookupObservable().subscribe((domains: SearchTableResult) => {
-      this.domainList = new Array(domains.serviceEntities.length)
-        .map((v, index) => domains.serviceEntities[index] as DomainRo);
-
-      this.domainList = domains.serviceEntities.map(serviceEntity => {
-        return {...<DomainRo>serviceEntity}
-      });
-      this.updateDomainData();
-    });
-
-
-
-    this.dialogFormBuilder = fb;
-    this.editMode = data.edit;
-    this.formTitle = this.editMode ?  ServiceGroupDetailsDialogComponent.EDIT_MODE: ServiceGroupDetailsDialogComponent.NEW_MODE;
+              private dialogFormBuilder: FormBuilder,
+              private changeDetector: ChangeDetectorRef) {
+    this.editMode = this.data.edit;
+    this.formTitle = this.editMode ? ServiceGroupDetailsDialogComponent.EDIT_MODE : ServiceGroupDetailsDialogComponent.NEW_MODE;
     this.current = this.editMode
       ? {
-        ...data.row,
+        ...this.data.row,
       }
       : {
         id: null,
         participantIdentifier: '',
-        participantScheme:  '',
-        serviceMetadata:[],
-        users:[],
-        domainCode:'',
+        participantScheme: '',
+        serviceMetadata: [],
+        users: [],
+        serviceGroupDomains: [],
+        extension: '',
         status: SearchTableEntityStatus.NEW,
       };
+    // user is new when reopening the new item in edit mode!
+    // allow to change data but warn on error!
 
     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),
+      'participantIdentifier': new FormControl({
+          value: '',
+          disabled: this.current.status !== SearchTableEntityStatus.NEW
+        },
+        this.current.status !== SearchTableEntityStatus.NEW ? Validators.required : null),
+      'participantScheme': new FormControl({value: '', disabled: this.current.status !== SearchTableEntityStatus.NEW},
+        this.current.status !== SearchTableEntityStatus.NEW ? Validators.required : null),
+      'serviceGroupDomains': new FormControl({value: []}, [this.minSelectedListCount(1)]),
+      'users': new FormControl({value: []}, [this.minSelectedListCount(1)]),
+      'extension': new FormControl({value: []}, []),
 
-    });
 
+    });
+    // update values
+    this.dialogForm.controls['participantIdentifier'].setValue(this.current.participantIdentifier);
+    this.dialogForm.controls['participantScheme'].setValue(this.current.participantScheme);
+    this.dialogForm.controls['serviceGroupDomains'].setValue(this.current.serviceGroupDomains);
+    this.dialogForm.controls['users'].setValue(this.current.users)
+    this.dialogForm.controls['extension'].setValue(this.current.extension)
 
   }
 
-  updateUserData(){
-    this.formControlUsers = new FormControl(this.current.users);
-    this.formControlUsers.setValidators( [ this.minSelectedListCount(1)]);
-    this.dialogForm.addControl("users",this.formControlUsers );
-
-  }
+  ngOnInit() {
+    // retrieve xml extension for this service group
+    if (this.current.status !== SearchTableEntityStatus.NEW && !this.current.extension) {
+      // init domains
+      this.extensionObserver = this.http.get<ServiceGroupExtensionRo>(SmpConstants.REST_SERVICE_GROUP_EXTENSION+'/' + this.current.id);
+      this.extensionObserver.subscribe((res: ServiceGroupExtensionRo) => {
+        this.dialogForm.get('extension').setValue(res.extension);
+      });
+    }
 
-  updateDomainData(){
-    this.formControlDomain = new FormControl(this.current.domains);
-    this.formControlDomain.setValidators( [ this.minSelectedListCount(1)]);
-    this.dialogForm.addControl("domains",this.formControlDomain );
+    // detect changes for updated values in mat-selection-list (check change detection operations)
+    // else the following error is thrown :xpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value:
+    // 'aria-selected: false'. Current value: 'aria-selected: true'
+    //
+    this.changeDetector.detectChanges()
   }
 
 
@@ -141,24 +135,145 @@ export class ServiceGroupDetailsDialogComponent {
   }
 
 
-  updateParticipantIdentifier(event) {
-    this.current.participantIdentifier = event.target.value;
+  compareTableItemById(item1, item2): boolean {
+    return item1.id === item2.id;
   }
-  updateParticipantScheme(event) {
-    this.current.participantScheme = event.target.value;
+
+  compareDomain(domain: DomainRo, serviceGroupDomain: ServiceGroupDomainEditRo): boolean {
+    return domain.id === serviceGroupDomain.domainId;
   }
 
-  userListChanged(usersSelected, event){
-    this.current.users = [];
-    for(let usr of usersSelected) {
-      this.current.users.push(usr.value);
+
+  public getCurrent(): ServiceGroupEditRo {
+    // change this two properties only on new
+    if (this.current.status === SearchTableEntityStatus.NEW) {
+      this.current.participantIdentifier = this.dialogForm.value['participantIdentifier'];
+      this.current.participantScheme = this.dialogForm.value['participantScheme'];
+    } else {
+      this.current.extensionStatus = SearchTableEntityStatus.UPDATED;
     }
+    this.current.users = this.dialogForm.value['users'];
+    this.current.extension = this.dialogForm.value['extension'];
+
+
+    let domainOptions = this.domainSelector.options._results;
+    domainOptions.forEach(opt => {
+      let domValue = opt.value;
+      let sgd = this.getServiceGroupDomain(domValue.domainCode);
+      // if contains and deselected  - delete
+      if (sgd && !opt.selected) {
+        this.current.serviceMetadata.forEach(metadata=>{
+          if (metadata.domainCode === sgd.domainCode) {
+            metadata.status = SearchTableEntityStatus.REMOVED;
+            metadata.deleted = true;
+          }
+        });
+
+        var index = this.current.serviceGroupDomains.indexOf(sgd);
+        if (index !== -1) this.current.serviceGroupDomains.splice(index, 1);
+
+        // delete service group
+      } else if (!sgd && opt.selected) {
+        let newDomain: ServiceGroupDomainEditRo = {
+          id: null,
+          domainId: domValue.id,
+          domainCode: domValue.domainCode,
+          smlSubdomain: domValue.domainCode,
+          smlRegistered: false,
+          serviceMetadataCount: 0,
+          status: SearchTableEntityStatus.NEW,
+        };
+        this.current.serviceGroupDomains.push(newDomain);
+      }
+    });
+    return this.current;
   }
-  compareTableItemById(item1, item2): boolean{
-    return item1.id=== item2.id;
+
+  onExtensionDelete() {
+    this.dialogForm.controls['extension'].setValue("");
+  }
+
+  onStartWizardDialog() {
+
+    const formRef: MatDialogRef<any> = this.dialog.open(ServiceGroupExtensionWizardDialogComponent);
+    formRef.afterClosed().subscribe(result => {
+      if (result) {
+        let existingXML = this.dialogForm.controls['extension'].value;
+        let val = (existingXML ? existingXML + '\n' : '') + formRef.componentInstance.getExtensionXML();
+        this.dialogForm.controls['extension'].setValue(val);
+      }
+    });
+  }
+
+  onExtensionValidate() {
+    let existingXML = this.dialogForm.controls['extension'].value;
+    let request: ServiceGroupExtensionRo = {
+      serviceGroupId: this.current.id,
+      extension: existingXML,
+    }
+    //
+    let validationObservable = this.http.post<ServiceGroupExtensionRo>(SmpConstants.REST_SERVICE_GROUP_EXTENSION_VALIDATE, request);
+    validationObservable.subscribe((res: ServiceGroupExtensionRo) => {
+      if (res.errorMessage) {
+        this.extensionValidationMessage = res.errorMessage;
+        this.isExtensionValid = false;
+      } else {
+        this.extensionValidationMessage = "Extension is valid!";
+        this.isExtensionValid = true;
+      }
+
+    });
+  }
+
+  onPrettyPrintExtension() {
+    let existingXML = this.dialogForm.controls['extension'].value;
+    let request: ServiceGroupExtensionRo = {
+      serviceGroupId: this.current.id,
+      extension: existingXML,
+    }
+    let validationObservable = this.http.post<ServiceGroupExtensionRo>(SmpConstants.REST_SERVICE_GROUP_EXTENSION_FORMAT, request);
+    validationObservable.subscribe((res: ServiceGroupExtensionRo) => {
+      if (res.errorMessage) {
+        this.extensionValidationMessage = res.errorMessage;
+        this.isExtensionValid = false;
+      } else {
+        this.dialogForm.get('extension').setValue(res.extension);
+        this.isExtensionValid = true;
+      }
+
+    });
   }
 
-  isSelected(id): boolean {
-    return !!this.current.users.find(user => user.id===id);
+  onDomainSelectionChanged(event) {
+    // if deselected warn  serviceMetadata will be deleted
+    let domainCode = event.option.value.domainCode;
+    if (!event.option.selected) {
+      this.dialog.open(ConfirmationDialogComponent, {
+        data: {
+          title: "Registred serviceMetadata on domain!",
+          description: "Unregistration of domain will also delete it's serviceMetadata. Do you want to continue?"
+        }
+      }).afterClosed().subscribe(result => {
+        if (!result) {
+          event.option.selected = true;
+        }
+      })
+
+
+    }
+  }
+
+  public getServiceMetadataCountOnDomain(domainCode: String) {
+    return this.current.serviceMetadata.filter(smd => {
+      return smd.domainCode === domainCode
+    }).length;
   }
+
+  public getServiceGroupDomain(domainCode: String) {
+    return this.current.serviceGroupDomains?
+    this.current.serviceGroupDomains.find(smd => {
+      return smd.domainCode === domainCode
+    }):null;
+  }
+
 }
diff --git a/smp-angular/src/app/service-group-edit/service-group-domain-edit-ro.model.ts b/smp-angular/src/app/service-group-edit/service-group-domain-edit-ro.model.ts
index 048bff1ae..e23ff4e73 100644
--- a/smp-angular/src/app/service-group-edit/service-group-domain-edit-ro.model.ts
+++ b/smp-angular/src/app/service-group-edit/service-group-domain-edit-ro.model.ts
@@ -1,14 +1,10 @@
-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";
-import {DomainRo} from "../domain/domain-ro.model";
 
-export interface ServiceGroupEditRo extends SearchTableEntity {
+export interface ServiceGroupDomainEditRo extends SearchTableEntity {
   id: number;
-  participantIdentifier: string;
-  participantScheme: string;
-  serviceMetadata: Array<ServiceMetadataEditRo>;
-  serviceGroupDomains: Array<ServiceGroupDomainRo>;
-  users: Array<UserRo>;
-  extension?: string;
+  domainId: number;
+  domainCode: string;
+  smlSubdomain: string;
+  smlRegistered: boolean;
+  serviceMetadataCount?: number;
 }
diff --git a/smp-angular/src/app/service-group-edit/service-group-edit-controller.ts b/smp-angular/src/app/service-group-edit/service-group-edit-controller.ts
index 23dc032ef..7c37c53c1 100644
--- a/smp-angular/src/app/service-group-edit/service-group-edit-controller.ts
+++ b/smp-angular/src/app/service-group-edit/service-group-edit-controller.ts
@@ -4,7 +4,6 @@ import {ServiceGroupDetailsDialogComponent} from './service-group-details-dialog
 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";
 import {ServiceGroupMetadataDialogComponent} from "./service-group-metadata-dialog/service-group-metadata-dialog.component";
 
 export class ServiceGroupEditController implements SearchTableController {
@@ -49,11 +48,10 @@ export class ServiceGroupEditController implements SearchTableController {
       index: null,
       participantIdentifier: '',
       participantScheme: '',
-      domainCode: '',
-      smlSubdomain: '',
       serviceMetadata: [],
       users: [],
-      domains: [],
+      serviceGroupDomains: [],
+      extensionStatus: SearchTableEntityStatus.NEW,
       status: SearchTableEntityStatus.NEW
     };
   }
@@ -65,12 +63,12 @@ export class ServiceGroupEditController implements SearchTableController {
       documentIdentifierScheme: '',
       smlSubdomain: '',
       domainCode: '',
-      processSchema: '',
-      processIdentifier: '',
-      endpointUrl: '',
-      endpointCertificate: '',
-      status: SearchTableEntityStatus.NEW
+      domainId:null,
+      status: SearchTableEntityStatus.NEW,
+      xmlContentStatus: SearchTableEntityStatus.NEW,
     };
   }
 
+  public dataSaved() {}
+
 }
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
index 0fcbd1d60..df6bdd5b2 100644
--- 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
@@ -1,15 +1,16 @@
-import { ServiceMetadataEditRo } from './service-metadata-edit-ro.model';
+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";
-import {DomainRo} from "../domain/domain-ro.model";
+import {ServiceGroupDomainEditRo} from "./service-group-domain-edit-ro.model";
+import {SearchTableEntityStatus} from "../common/search-table/search-table-entity-status.model";
 
 export interface ServiceGroupEditRo extends SearchTableEntity {
   id: number;
   participantIdentifier: string;
   participantScheme: string;
-  domainCode:'',
-  smlSubdomain:'',
   serviceMetadata: Array<ServiceMetadataEditRo>;
-  domains: Array<DomainRo>;
+  serviceGroupDomains: Array<ServiceGroupDomainEditRo>;
   users: Array<UserRo>;
+  extension?: string;
+  extensionStatus: SearchTableEntityStatus;
 }
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
index 1db04a19c..79540ced1 100644
--- 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
@@ -27,19 +27,19 @@
 
   <ng-template #searchPanel>
     <mat-form-field>
-      <input matInput placeholder="Participant Id" name="messageId" [(ngModel)]="filter.messageId"
-             #messageId="ngModel" id="messageid_id">
+      <input matInput placeholder="Participant Identifier" name="ParticipantIdentifier"
+             [(ngModel)]="filter.participantIdentifier"
+             #messageId="ngModel" id="participantIdentifier">
     </mat-form-field>
     <mat-form-field>
-      <input matInput placeholder="Participant schema" name="patricipantSchema" [(ngModel)]="filter.messageId"
-             #messageId="ngModel" id="participanschema_id">
+      <input matInput placeholder="Participant scheme" name="patricipantScheme" [(ngModel)]="filter.participantScheme"
+             #messageId="ngModel" id="participantScheme">
     </mat-form-field>
-
     <mat-select placeholder="Domain (sml subdomain)" [(ngModel)]="filter.domain" name="domain"
                 id="domain_id">
       <mat-option [value]="''">
       </mat-option>
-      <mat-option *ngFor="let domain of domainlist" [value]="domain.domainCode">
+      <mat-option *ngFor="let domain of lookups.cachedDomainList" [value]="domain.domainCode">
         {{domain.domainCode}} ({{domain.smlSubdomain}})
       </mat-option>
     </mat-select>
@@ -70,12 +70,16 @@
         [footerHeight]='50'
         [rowHeight]='"auto"'
         [rowClass]="getRowClass">
-        <ngx-datatable-column prop="domainCode" name="Domain" maxWidth="250" ></ngx-datatable-column>
+        <ngx-datatable-column [cellTemplate]="rowDomain" 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 #rowDomain let-rowSmd="row" ngx-datatable-cell-template>
+          {{rowSmd.domainCode}} ({{rowSmd.smlSubdomain}})
+        </ng-template>
+
         <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>
@@ -85,7 +89,7 @@
       <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">
+                  (click)="onEditMetadataRow(row, rowSmd)" tooltip="Edit">
             <mat-icon>edit</mat-icon>
           </button>
           <button mat-icon-button color="primary" [disabled]="rowSmd.deleted || loading"
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
index 73b6f9211..648246108 100644
--- 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
@@ -1,20 +1,13 @@
-import {Component, OnInit, TemplateRef, ViewChild} from '@angular/core';
+import {ChangeDetectorRef, 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";
 import {SearchTableEntityStatus} from "../common/search-table/search-table-entity-status.model";
 import {SearchTableComponent} from "../common/search-table/search-table.component";
-import {ServiceMetadataEditRo} from "./service-metadata-edit-ro.model";
-import {ServiceGroupEditRo} from "./service-group-edit-ro.model";
 import {GlobalLookups} from "../common/global-lookups";
-import {DomainRo} from "../domain/domain-ro.model";
 
 @Component({
   moduleId: module.id,
@@ -33,31 +26,12 @@ export class ServiceGroupEditComponent implements OnInit {
   filter: any = {};
   baseUrl: string = SmpConstants.REST_EDIT;
 
-  userObserver: Observable<SearchTableResult>;
-  domainObserver: Observable<SearchTableResult>;
-  userlist: Array<UserRo> = [];
-  domainlist: Array<any>;
+  constructor(protected lookups: GlobalLookups,
+              protected http: HttpClient,
+              protected alertService: AlertService,
+              public dialog: MatDialog,
+              private changeDetector: ChangeDetectorRef) {
 
-  constructor(protected lookups: GlobalLookups, 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}
-      });
-    });
-
-    this.lookups.getDomainLookupObservable().subscribe((domains: SearchTableResult) => {
-      this.domainlist = new Array(domains.serviceEntities.length)
-        .map((v, index) => domains.serviceEntities[index] as DomainRo);
-
-      this.domainlist = domains.serviceEntities.map(serviceEntity => {
-        return {...<DomainRo>serviceEntity}
-      });
-    });
   }
 
   ngOnInit() {
@@ -116,7 +90,7 @@ export class ServiceGroupEditComponent implements OnInit {
     let rowNumber = this.searchTable.rows.indexOf(row);
 
     const formRef: MatDialogRef<any> = this.serviceGroupEditController.newMetadataDialog({
-      data: {edit: true, serviceGroup: row, metadata: null}
+      data: {edit: false, serviceGroup: row, metadata: this.serviceGroupEditController.newServiceMetadataRow()}
     });
     formRef.afterClosed().subscribe(result => {
       if (result) {
@@ -124,21 +98,9 @@ export class ServiceGroupEditComponent implements OnInit {
           ? SearchTableEntityStatus.UPDATED
           : row.status;
 
-        let data = this.serviceGroupEditController.newServiceMetadataRow();
-        data.documentIdentifier = "aaaaaaaaa";
-        data.documentIdentifierScheme = "aaaaaaaaa";
+        let data = formRef.componentInstance.getCurrent();
         row.serviceMetadata.push(data);
-
         this.searchTable.updateTableRow(rowNumber, row, status);
-        //this.searchTable.rows[rowNumber] = {...row, status};
-        //this.searchTable.rows = [...this.searchTable.rows];
-        /*
-        const status = row.status === SearchTableEntityStatus.PERSISTED
-          ? SearchTableEntityStatus.UPDATED
-          : row.status;
-        this.rows[rowNumber] = {...formRef.componentInstance.current, status};
-        this.rows = [...this.rows];*/
-
       }
     });
 
@@ -152,7 +114,38 @@ export class ServiceGroupEditComponent implements OnInit {
     };
   }
 
-  onEditMetadataRow(metaDataRow: any) {
+  onEditMetadataRow(serviceGroupRow: any,metaDataRow: any) {
+    let metadataRowNumber = serviceGroupRow.serviceMetadata.indexOf(metaDataRow);
+
+    const formRef: MatDialogRef<any> = this.serviceGroupEditController.newMetadataDialog({
+      data: {edit: true, serviceGroup: serviceGroupRow, metadata: metaDataRow}
+    });
+    formRef.afterClosed().subscribe(result => {
+      if (result) {
+
+        let statusMetadata =metaDataRow.status === SearchTableEntityStatus.PERSISTED
+          ? SearchTableEntityStatus.UPDATED
+          : metaDataRow;
+
+
+        metaDataRow.status = statusMetadata;
+        metaDataRow  = {...formRef.componentInstance.getCurrent()};
+
+        serviceGroupRow.serviceMetadata [metadataRowNumber] = {...metaDataRow };
+        // change reference to fire table update
+        serviceGroupRow.serviceMetadata = [...serviceGroupRow.serviceMetadata]
+
+        // set row as updated
+        const status = serviceGroupRow.status === SearchTableEntityStatus.PERSISTED
+          ? SearchTableEntityStatus.UPDATED
+          : serviceGroupRow.status;
+        serviceGroupRow.status = status;
+
+        this.changeDetector.detectChanges();
+
+      }
+    });
+    //
 
   }
 
diff --git a/smp-angular/src/app/service-group-edit/service-group-extension-wizard-dialog/service-group-extension-wizard-dialog.component.ts b/smp-angular/src/app/service-group-edit/service-group-extension-wizard-dialog/service-group-extension-wizard-dialog.component.ts
index b2b3246f0..96428bb26 100644
--- a/smp-angular/src/app/service-group-edit/service-group-extension-wizard-dialog/service-group-extension-wizard-dialog.component.ts
+++ b/smp-angular/src/app/service-group-edit/service-group-extension-wizard-dialog/service-group-extension-wizard-dialog.component.ts
@@ -1,23 +1,11 @@
-import {ChangeDetectorRef, Component, Inject, OnInit} 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";
-import {GlobalLookups} from "../common/global-lookups";
+import {Component} from '@angular/core';
+import {MatDialogRef} from '@angular/material';
+import {FormBuilder, FormControl, FormGroup} from "@angular/forms";
 
 @Component({
-  selector: 'app-messagelog-details',
-  templateUrl: './service-group-metadata-wizard-dialog/service-group-extension-wizard-dialog.component.html',
-  styleUrls: ['./service-group-metadata-wizard-dialog/service-group-extension-wizard-dialog.component.css']
+  selector: 'service-group-metadata-wizard',
+  templateUrl: './service-group-extension-wizard-dialog.component.html',
+  styleUrls:  ['./service-group-extension-wizard-dialog.component.css']
 })
 export class ServiceGroupExtensionWizardDialogComponent  {
   dialogForm: FormGroup;
diff --git a/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.html b/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.html
index 0e54d9c7b..7359f01be 100644
--- a/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.html
+++ b/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.html
@@ -1,72 +1,126 @@
-<h2 mat-dialog-title>ServiceGroup Metadata</h2>
-<mat-dialog-content  style="height:460px;width:950px">
+<h2 mat-dialog-title>{{formTitle}}</h2>
+<mat-dialog-content style="height:750px;width:1200px">
+  <div fxLayout="column">
+    <mat-card   >
 
-  <mat-tab-group fxFlex="column">
-    <mat-tab label="Metadata data">
-      <mat-form-field style="width:100%">
-        <input matInput placeholder="Document identifier schema" name="documentIdentifierScheme" id="documentIdentifierScheme_id"
-               [formControl]="dialogForm.controls['documentIdentifierScheme']" maxlength="255">
+      <mat-card-content >
+        <div class="panel">
+          <mat-form-field  style="width:30%">
+            <input matInput placeholder="Participant schema" name="patricipantSchema"  id="participanSchema_id"
+                   [formControl]="dialogForm.controls['participantScheme']"
+            >
+          </mat-form-field>
+          <mat-form-field style="width:40%">
+            <input matInput placeholder="Participant Identifier" name="participantIdentifier"  id="participantIdentifier_id"
+                   [formControl]="dialogForm.controls['participantIdentifier']">
+          </mat-form-field>
+          <mat-select #domainList [compareWith]="compareDomainCode" placeholder="Domain (sml subdomain)" id="domain_id" style="width:20%"
+                      [formControl]="dialogForm.controls['domainCode']">
+            <mat-option *ngFor="let domain of currentServiceGroup.serviceGroupDomains" [value]="domain">
+              {{domain.domainCode}} ({{domain.smlSubdomain}})
+            </mat-option>
+          </mat-select>
+          <div
+            *ngIf="(!editMode && dialogForm.controls['domainCode'].touched || editMode) &&  dialogForm.controls['domainCode'].hasError('required')"
+            style="color:red; font-size: 70%">
+            Domain must be selected.
+          </div>
 
-      </mat-form-field>
-
-      <mat-form-field style="width:100%">
-        <input matInput placeholder="Document identifier" name="documentIdentifier" id="documentIdentifier_id"
-               [formControl]="dialogForm.controls['documentIdentifier']" maxlength="255" required>
-
-        <div *ngIf="(!editMode && dialogForm.controls['documentIdentifier'].touched || editMode) &&  dialogForm.controls['documentIdentifier'].hasError('required')" style="color:red; font-size: 70%">
-          Document identifier must not be empty.
+          <mat-form-field  style="width:30%">
+            <input matInput placeholder="Document schema" name="documentScheme"  id="documentScheme_id"
+                   [formControl]="dialogForm.controls['documentIdentifierScheme']">
+          </mat-form-field>
+            <mat-form-field style="width:55%">
+              <input matInput placeholder="Document identifier" name="documentIdentifier"  id="documentIdentifier_id"
+                     [formControl]="dialogForm.controls['documentIdentifier']">
+            </mat-form-field>
         </div>
-      </mat-form-field>
+      </mat-card-content>
+    </mat-card>
 
-      <mat-form-field style="width:100%">
-        <input matInput placeholder="Process schema" name="processSchema" id="processSchema_id"
-               [formControl]="dialogForm.controls['processSchema']" maxlength="255" required>
 
-        <div *ngIf="(!editMode && dialogForm.controls['processSchema'].touched || editMode) &&  dialogForm.controls['processSchema'].hasError('required')" style="color:red; font-size: 70%">
-          Process identifier must not be empty.
-        </div>
-      </mat-form-field>
+    <mat-card>
+      <mat-card-content>
+        <mat-toolbar>
+          <mat-toolbar-row>
+            <button mat-raised-button color="primary"
+                    matTooltip="Clear the metadata content."
+                    matTooltipPosition="below"
+                    (click)="onClearServiceMetadata()">
+              <mat-icon>clear</mat-icon>
+              <span>Clear</span>
+            </button>
+            <button mat-raised-button color="primary"
+                    matTooltip="Generates simple XML"
+                    matTooltipPosition="below"
+                    (click)="onGenerateSimpleXML()">
+              <mat-icon>settings_ethernet</mat-icon>
+              <span>Generate XML</span>
+            </button>
+            <!-- button mat-raised-button color="primary"
+                    matTooltip="Opens wizard to configure ServiceMetadata xml."
+                    matTooltipPosition="below"
+                    (click)="onStartWizardDialog()">
+              <mat-icon>add_box</mat-icon>
+              <span>Metadata wizard</span>
+            </button -->
+            <button mat-raised-button color="primary"
+                    atTooltip="Validate serviceMetadata XML."
+                    matTooltipPosition="below"
+                    (click)="onServiceMetadataValidate()">
+              <mat-icon>warning</mat-icon>
+              <span>Validate</span>
+            </button>
+          </mat-toolbar-row>
+        </mat-toolbar>
 
-      <mat-form-field style="width:100%">
-        <input matInput placeholder="Process identifier" name="processidentifier" id="processidentifier_id"
-               [formControl]="dialogForm.controls['processIdentifier']" maxlength="255" required>
+        <div style="display: block;" style="border:1px; solid: #999999;margin:5px 0; padding:3px;">
+          <div class="textwrapper">
+            <textarea matInput style="width:100%;border: #03A9F4 1px solid" cols="2" rows="25"
+                      resizeable="false"
+                      id="MetadataTextArea"
+                      placeholder="Metadata XML" name="metadataXML"
+                      [formControl]="dialogForm.controls['xmlContent']"
 
-        <div *ngIf="(!editMode && dialogForm.controls['processIdentifier'].touched || editMode) &&  dialogForm.controls['processIdentifier'].hasError('required')" style="color:red; font-size: 70%">
-          Process identifier must not be empty.
-        </div>
-      </mat-form-field>
+            ></textarea>
+          </div>
+          <div
+            *ngIf="metadataValidationMessage"
+            [style.color]="isMetadataValid?'green':'red'">
+            {{metadataValidationMessage}}
+          </div>
 
-      <mat-form-field style="width:100%">
-        <input matInput placeholder="Endpoint Url" name="endpointUrl" id="endpointUrl_id"
-               [formControl]="dialogForm.controls['endpointUrl']" maxlength="255" required>
-
-        <div *ngIf="(!editMode && dialogForm.controls['endpointUrl'].touched || editMode) &&  dialogForm.controls['endpointUrl'].hasError('required')" style="color:red; font-size: 70%">
-          Endpoint URL must not be empty.
         </div>
-      </mat-form-field>
 
 
+        <!-- mat-form-field>
+          <div>
+          <textarea style="width:100% !important;height: 400px !important;  -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;"
 
-    </mat-tab>
-    <mat-tab label="XML">
-      <h1>Some more tab content</h1>
-      <textarea style="width: 100%; height: 95%"></textarea>
-    </mat-tab>
-  </mat-tab-group>
+                    matInput id="extensionTextArea"
+                    placeholder="Extension" name="extension"
+                    [formControl]="dialogForm.controls['extension']"
+          ></textarea>
+    </div>
+        </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 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 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-metadata-dialog/service-group-metadata-dialog.component.ts b/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.ts
index 544447520..cce601df2 100644
--- a/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.ts
+++ b/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-group-metadata-dialog.component.ts
@@ -1,63 +1,207 @@
-import {Component, Inject} from '@angular/core';
-import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material';
+import {Component, Inject, OnInit, ViewChild} from '@angular/core';
+import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material';
 import {FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms";
-import {DomainRo} from "../../domain/domain-ro.model";
 import {AlertService} from "../../alert/alert.service";
-import {DomainDetailsDialogComponent} from "../../domain/domain-details-dialog/domain-details-dialog.component";
 import {SearchTableEntityStatus} from "../../common/search-table/search-table-entity-status.model";
 import {ServiceMetadataEditRo} from "../service-metadata-edit-ro.model";
+import {GlobalLookups} from "../../common/global-lookups";
+import {ServiceMetadataWizardDialogComponent} from "../service-metadata-wizard-dialog/service-metadata-wizard-dialog.component";
+import {ServiceGroupEditRo} from "../service-group-edit-ro.model";
+import {SmpConstants} from "../../smp.constants";
+import {Observable} from "rxjs/internal/Observable";
+import {HttpClient} from "@angular/common/http";
+import {ServiceGroupDomainEditRo} from "../service-group-domain-edit-ro.model";
+import {ServiceMetadataValidationEditRo} from "./service-metadata-validation-edit-ro.model";
 
 @Component({
   selector: 'app-messagelog-dialog',
   templateUrl: './service-group-metadata-dialog.component.html',
   styleUrls: ['./service-group-metadata-dialog.component.css']
 })
-export class ServiceGroupMetadataDialogComponent {
+export class ServiceGroupMetadataDialogComponent implements OnInit {
 
   static readonly NEW_MODE = 'New ServiceMetadata';
-  static readonly EDIT_MODE = 'Domain ServiceMetadata';
+  static readonly EDIT_MODE = 'Edit ServiceMetadata';
+
+  @ViewChild('domainList') domainList: any;
+
 
   editMode: boolean;
   formTitle: string;
   current: ServiceMetadataEditRo & { confirmation?: string };
+  currentServiceGroup: ServiceGroupEditRo;
   dialogForm: FormGroup;
+  metadataValidationMessage: string;
+  xmlServiceMetadataObserver: Observable<ServiceMetadataEditRo>;
+  isMetadataValid: boolean = true;
 
 
-  constructor(private dialogRef: MatDialogRef<ServiceGroupMetadataDialogComponent>,
+  constructor(public dialog: MatDialog,
+              protected http: HttpClient,
+              public lookups: GlobalLookups,
+              private dialogRef: MatDialogRef<ServiceGroupMetadataDialogComponent>,
               private alertService: AlertService,
               @Inject(MAT_DIALOG_DATA) public data: any,
               private fb: FormBuilder) {
 
     this.editMode = data.edit;
-    this.formTitle = this.editMode ?  ServiceGroupMetadataDialogComponent.EDIT_MODE: ServiceGroupMetadataDialogComponent.NEW_MODE;
+    this.formTitle = this.editMode ? ServiceGroupMetadataDialogComponent.EDIT_MODE : ServiceGroupMetadataDialogComponent.NEW_MODE;
+    this.currentServiceGroup = data.serviceGroup;
     this.current = this.editMode
       ? {
-        ...data.row,
+        ...data.metadata,
       }
       : {
         documentIdentifier: '',
         documentIdentifierScheme: '',
-        smlSubdomain: '',
-        domainCode: '',
-        processSchema: '',
-        processIdentifier: '',
-        endpointUrl:  '',
-        endpointCertificate: '',
+        smlSubdomain: this.currentServiceGroup.serviceGroupDomains[0].smlSubdomain,
+        domainCode: this.currentServiceGroup.serviceGroupDomains[0].domainCode,
+        domainId: null,
         status: SearchTableEntityStatus.NEW,
+        xmlContentStatus: SearchTableEntityStatus.NEW,
       };
 
     this.dialogForm = fb.group({
+      'participantIdentifier': new FormControl({value: this.currentServiceGroup.participantIdentifier, disabled: true}),
+      'participantScheme': new FormControl({value: this.currentServiceGroup.participantScheme, disabled: true}),
+      'domainCode': new FormControl({}, [Validators.required]),
+
+      'documentIdentifier': new FormControl({value: this.current.documentIdentifier, disabled: this.editMode},
+        [Validators.required]),
+      'documentIdentifierScheme': new FormControl({
+          value: this.current.documentIdentifierScheme,
+          disabled: this.editMode
+        },
+        [Validators.required]),
+      'xmlContent': new FormControl({value: []}, []),
+    });
+
+    // update values
+    this.dialogForm.controls['domainCode'].setValue(this.current.domainCode);
+    this.dialogForm.controls['xmlContent'].setValue(this.current.xmlContent);
+  }
+
+  ngOnInit() {
+
+    // retrieve xml extension for this service group
+    if (this.current.status !== SearchTableEntityStatus.NEW && !this.current.xmlContent) {
+      // init domains
+      this.xmlServiceMetadataObserver = this.http.get<ServiceMetadataEditRo>(SmpConstants.REST_METADATA + '/' + this.current.id);
+      this.xmlServiceMetadataObserver.subscribe((res: ServiceMetadataEditRo) => {
+        this.dialogForm.get('xmlContent').setValue(res.xmlContent);
+      });
+    }
+
+    // detect changes for updated values in mat-selection-list (check change detection operations)
+    // else the following error is thrown :xpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value:
+    // 'aria-selected: false'. Current value: 'aria-selected: true'
+    //
+    //this.changeDetector.detectChanges()
 
-      'documentIdentifier': new FormControl({value: this.current.documentIdentifier}, [Validators.required]),
-      'documentIdentifierScheme':  new FormControl({value: this.current.documentIdentifierScheme  }, null),
-      'domainCode':  new FormControl({value: this.current.domainCode}, [Validators.required]),
-      'processSchema':  new FormControl({value: this.current.processSchema}, [Validators.required]),
-      'processIdentifier':  new FormControl({value: this.current.processIdentifier}, [Validators.required]),
-      'endpointUrl':  new FormControl({value: this.current.endpointUrl}, [Validators.required]),
-      'endpointCertificate':  new FormControl({value: this.current.endpointCertificate}, null),
+  }
 
+  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();
     });
+  }
 
+  submitForm() {
+    this.checkValidity(this.dialogForm)
+    this.dialogRef.close(true);
   }
 
+
+  onClearServiceMetadata() {
+    this.dialogForm.controls['xmlContent'].setValue("");
+  }
+
+  onStartWizardDialog() {
+    const formRef: MatDialogRef<any> = this.dialog.open(ServiceMetadataWizardDialogComponent);
+    formRef.afterClosed().subscribe(result => {
+      if (result) {
+        let existingXML = this.dialogForm.controls['extension'].value;
+        let val = (existingXML ? existingXML + '\n' : '') + formRef.componentInstance.getExtensionXML();
+        this.dialogForm.controls['extension'].setValue(val);
+      }
+    });
+  }
+
+  onGenerateSimpleXML() {
+    let exampleXML = '<ServiceMetadata xmlns="http://docs.oasis-open.org/bdxr/ns/SMP/2016/05">' +
+      '\n    <ServiceInformation>' +
+      '\n        <ParticipantIdentifier scheme="' + this.dialogForm.controls['participantScheme'].value + '">' + this.dialogForm.controls['participantIdentifier'].value + '</ParticipantIdentifier>' +
+      '\n        <DocumentIdentifier scheme="' + this.dialogForm.controls['documentIdentifierScheme'].value + '">' + this.dialogForm.controls['documentIdentifier'].value + '</DocumentIdentifier>' +
+      '\n        <ProcessList>' +
+      '\n            <Process>' +
+      '\n                <ProcessIdentifier scheme="[enterProcessType]">[enterProcessName]</ProcessIdentifier>' +
+      '\n                <ServiceEndpointList>' +
+      '\n                   <Endpoint transportProfile="bdxr-transport-ebms3-as4-v1p0">' +
+      '\n                        <EndpointURI>https://mypage.eu</EndpointURI>' +
+      '\n                        <RequireBusinessLevelSignature>true</RequireBusinessLevelSignature>' +
+      '\n                        <Certificate>UGFzdGUgYmFzZTY0IGVuY29kZWQgY2VydGlmaWNhdGUgb2YgQVA=</Certificate>' +
+      '\n                        <ServiceDescription>Service description for partners</ServiceDescription>' +
+      '\n                        <TechnicalContactUrl>www.best-page.eu</TechnicalContactUrl>' +
+      '\n                    </Endpoint>' +
+      '\n                </ServiceEndpointList>' +
+      '\n            </Process>' +
+      '\n        </ProcessList>' +
+      '\n    </ServiceInformation>' +
+      '\n</ServiceMetadata>';
+    this.dialogForm.controls['xmlContent'].setValue(exampleXML);
+  }
+
+  onServiceMetadataValidate() {
+
+    let request: ServiceMetadataValidationEditRo = {
+      participantScheme: this.dialogForm.controls['participantScheme'].value,
+      participantIdentifier: this.dialogForm.controls['participantIdentifier'].value,
+      documentIdentifierScheme: this.dialogForm.controls['documentIdentifierScheme'].value,
+      documentIdentifier: this.dialogForm.controls['documentIdentifier'].value,
+      xmlContent: this.dialogForm.controls['xmlContent'].value,
+    }
+    //
+    let validationObservable = this.http.post<ServiceMetadataValidationEditRo>(SmpConstants.REST_METADATA_VALIDATE, request);
+    validationObservable.subscribe((res: ServiceMetadataValidationEditRo) => {
+      if (res.errorMessage) {
+        this.metadataValidationMessage = res.errorMessage;
+        this.isMetadataValid = false;
+      } else {
+        this.metadataValidationMessage = "ServiceMetada is valid!";
+        this.isMetadataValid = true;
+      }
+
+    });
+  }
+
+  public getCurrent(): ServiceMetadataEditRo {
+
+    this.current.domainCode = this.domainList.selected.value.domainCode;
+    this.current.smlSubdomain = this.domainList.selected.value.smlSubdomain;
+    this.current.domainId = this.domainList.selected.value.domainId;
+
+    this.current.xmlContent = this.dialogForm.value['xmlContent'];
+    // change this two properties only on new
+    if (this.current.status === SearchTableEntityStatus.NEW) {
+      this.current.documentIdentifier = this.dialogForm.value['documentIdentifier'];
+      this.current.documentIdentifierScheme = this.dialogForm.value['documentIdentifierScheme'];
+    } else if (this.current.status === SearchTableEntityStatus.PERSISTED) {
+      this.current.status = SearchTableEntityStatus.UPDATED;
+      this.current.xmlContentStatus = SearchTableEntityStatus.UPDATED;
+    }
+    return this.current;
+  }
+
+  compareDomainCode(sgDomain: ServiceGroupDomainEditRo, domainCode: String): boolean {
+    return sgDomain.domainCode === domainCode;
+  }
+
+
 }
diff --git a/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-metadata-validation-edit-ro.model.ts b/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-metadata-validation-edit-ro.model.ts
new file mode 100644
index 000000000..f6efa05dc
--- /dev/null
+++ b/smp-angular/src/app/service-group-edit/service-group-metadata-dialog/service-metadata-validation-edit-ro.model.ts
@@ -0,0 +1,10 @@
+
+export interface ServiceMetadataValidationEditRo {
+  participantScheme: string;
+  participantIdentifier: string;
+  documentIdentifierScheme: string;
+  documentIdentifier: string;
+
+  errorMessage?: string;
+  xmlContent?: string;
+}
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
index ab2123729..50880525b 100644
--- 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
@@ -6,9 +6,8 @@ export interface ServiceMetadataEditRo extends SearchTableEntity  {
   documentIdentifierScheme : string;
   smlSubdomain: string;
   domainCode: string;
-  processSchema: string;
-  processIdentifier: string;
-  endpointUrl: string;
-  endpointCertificate: string;
+  domainId: null,
+  xmlContent?:string,
+  xmlContentStatus:number,
 
 }
diff --git a/smp-angular/src/app/service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-dialog.component.html b/smp-angular/src/app/service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-dialog.component.html
index 831c4715b..e9fa2cd3a 100644
--- a/smp-angular/src/app/service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-dialog.component.html
+++ b/smp-angular/src/app/service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-dialog.component.html
@@ -1,56 +1,103 @@
-<h2 mat-dialog-title>Extension properties</h2>
+<h2 mat-dialog-title>ServiceMetadataWizard</h2>
 
 <mat-dialog-content>
   <form [formGroup]="dialogForm">
     <mat-card>
       <mat-card-content>
-        <fieldset style="border: none;">
-
-
-          <mat-form-field style="width:100%">
-            <input matInput placeholder="Document identifier schema" name="documentIdentifierScheme" id="documentIdentifierScheme_id"
-                   [formControl]="dialogForm.controls['documentIdentifierScheme']" maxlength="255">
-
+        <div class="panel">
+          <!-- Participant -->
+          <mat-form-field style="width:35%">
+            <input matInput placeholder="Participant identifier schema" name="participantIdentifierScheme"
+                   id="participantIdentifierScheme_id" maxlength="255">
           </mat-form-field>
-
-          <mat-form-field style="width:100%">
-            <input matInput placeholder="Document identifier" name="documentIdentifier" id="documentIdentifier_id"
-                   [formControl]="dialogForm.controls['documentIdentifier']" maxlength="255" required>
-
-            <div *ngIf="(!editMode && dialogForm.controls['documentIdentifier'].touched || editMode) &&  dialogForm.controls['documentIdentifier'].hasError('required')" style="color:red; font-size: 70%">
+          <mat-form-field style="width:60%">
+            <input matInput placeholder="Participant identifier" name="ParticipantIdentifier" id="ParticipantIdentifier_id"
+                   maxlength="255" required>
+            <div
+              *ngIf="(!editMode && dialogForm.controls['documentIdentifier'].touched || editMode) &&  dialogForm.controls['documentIdentifier'].hasError('required')"
+              style="color:red; font-size: 70%">
               Document identifier must not be empty.
             </div>
           </mat-form-field>
+          <!-- Document -->
+          <mat-form-field style="width:35%">
+            <input matInput placeholder="Document identifier schema" name="documentIdentifierScheme"
+                   id="documentIdentifierScheme_id"
+                   maxlength="255">
+          </mat-form-field>
 
-          <mat-form-field style="width:100%">
+          <mat-form-field style="width:60%">
+            <input matInput placeholder="Document identifier" name="documentIdentifier" id="documentIdentifier_id"
+                    maxlength="255" required>
+          </mat-form-field>
+          <!-- Process -->
+          <mat-form-field style="width:35%">
             <input matInput placeholder="Process schema" name="processSchema" id="processSchema_id"
-                   [formControl]="dialogForm.controls['processSchema']" maxlength="255" required>
-
-            <div *ngIf="(!editMode && dialogForm.controls['processSchema'].touched || editMode) &&  dialogForm.controls['processSchema'].hasError('required')" style="color:red; font-size: 70%">
-              Process identifier must not be empty.
-            </div>
+                   maxlength="255" required>
           </mat-form-field>
 
-          <mat-form-field style="width:100%">
+          <mat-form-field style="width:60%">
             <input matInput placeholder="Process identifier" name="processidentifier" id="processidentifier_id"
-                   [formControl]="dialogForm.controls['processIdentifier']" maxlength="255" required>
+                   maxlength="255" required>
 
-            <div *ngIf="(!editMode && dialogForm.controls['processIdentifier'].touched || editMode) &&  dialogForm.controls['processIdentifier'].hasError('required')" style="color:red; font-size: 70%">
-              Process identifier must not be empty.
-            </div>
+          </mat-form-field>
+<!-- transport -->
+          <mat-form-field style="width:35%">
+            <input matInput placeholder="Transport profile" name="transportProfile" id="transportProfiler_id"
+                    maxlength="255" required>
           </mat-form-field>
 
-          <mat-form-field style="width:100%">
+          <mat-form-field style="width:60%">
             <input matInput placeholder="Endpoint Url" name="endpointUrl" id="endpointUrl_id"
-                   [formControl]="dialogForm.controls['endpointUrl']" maxlength="255" required>
+                   maxlength="255" required>
+          </mat-form-field>
 
-            <div *ngIf="(!editMode && dialogForm.controls['endpointUrl'].touched || editMode) &&  dialogForm.controls['endpointUrl'].hasError('required')" style="color:red; font-size: 70%">
-              Endpoint URL must not be empty.
+          <div style="display: block;" style="border:1px; solid: #999999;margin:5px 0; padding:3px;">
+            <input
+              type="file" (change)="onFileChanged($event)"
+              #fileInput>
+            <button (click)="onUpload()">Upload!</button>
+            <div class="textwrapper">
+            <textarea matInput style="width:100%;border: #03A9F4 1px solid" cols="2" rows="10"
+                      resizeable="false"
+                      id="metadatacertificate_id"
+                      placeholder="X509Certificate" name="certificate"
+
+            ></textarea>
             </div>
+            <div
+              *ngIf="certificateValidationMessage"
+              [style.color]="isCertificateValid?'green':'red'">
+              {{certificateValidationMessage}}
+            </div>
+
+          </div>
+
+
+          <!-- -->
+
+
+          <!-- mat-form-field style="width:47%">
+            <input matInput placeholder="ServiceActivationDate" name="serviceActivationDate" id="serviceActivationDate_id"
+                   [formControl]="dialogForm.controls['serviceActivationDate']" maxlength="255" required>
+          </mat-form-field>
+          <mat-form-field style="width:47%">
+            <input matInput placeholder="ServiceExpirationDate" name="serviceExpirationDate" id="serviceExpirationDate"
+                   [formControl]="dialogForm.controls['serviceExpirationDate']" maxlength="255" required>
+          </mat-form-field -->
+
+<!-- ServiceDescription -->
+          <mat-form-field style="width:100%">
+            <input matInput placeholder="Service description" name="serviceDescription" id="serviceDescription_id"
+                   [formControl]="dialogForm.controls['serviceDescription']" maxlength="255" required>
+          </mat-form-field>
+          <mat-form-field style="width:100%">
+            <input matInput placeholder="Technical Contact Url" name="technicalContactUrl" id="technicalContactUrl_id"
+                   [formControl]="dialogForm.controls['technicalContactUrl_id']" maxlength="255" required>
           </mat-form-field>
 
 
-        </fieldset>
+        </div>
       </mat-card-content>
     </mat-card>
   </form>
diff --git a/smp-angular/src/app/service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-dialog.component.ts b/smp-angular/src/app/service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-dialog.component.ts
index fafc2a070..9e9dfecc8 100644
--- a/smp-angular/src/app/service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-dialog.component.ts
+++ b/smp-angular/src/app/service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-dialog.component.ts
@@ -1,46 +1,63 @@
-import {ChangeDetectorRef, Component, Inject, OnInit} 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 {Component} from '@angular/core';
+import {MatDialogRef} from '@angular/material';
+import {FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms";
 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";
-import {GlobalLookups} from "../../common/global-lookups";
+
 
 @Component({
-  selector: 'app-messagelog-details',
-  templateUrl: './service-group-extension-wizard-dialog.component.html',
-  styleUrls: ['./service-group-extension-wizard-dialog.component.css']
+  selector: 'service-metadata-wizard-dialog',
+  templateUrl: './service-metadata-wizard-dialog.component.html',
+  styleUrls: ['./service-metadata-wizard-dialog.component.css']
 })
-export class ServiceGroupExtensionWizardDialogComponent  {
+export class ServiceMetadataWizardDialogComponent {
+
+  static readonly NEW_MODE = 'New ServiceMetadata XML';
+  static readonly EDIT_MODE = 'Edit ServiceMetadata XML';
+
+  editMode: boolean;
+  formTitle: string;
+  current: ServiceMetadataEditRo & { confirmation?: string };
   dialogForm: FormGroup;
+  certificateValidationMessage: string;
+  isCertificateValid: string;
+  selectedFile: File;
 
-  dummyXML: string ="<!-- Custom element is mandatory by OASIS SMP schema.\n    Replace following element with your XML structure. -->\n<ext:example xmlns:ext=\"http://my.namespace.eu\">my mandatory content</ext:example>"
+  dummyXML: string = "<!-- Custom element is mandatory by OASIS SMP schema.\n    Replace following element with your XML structure. -->\n<ext:example xmlns:ext=\"http://my.namespace.eu\">my mandatory content</ext:example>"
 
 
-  constructor(public dialogRef: MatDialogRef<ServiceGroupExtensionWizardDialogComponent>,
+  constructor( protected http: HttpClient,
+               public dialogRef: MatDialogRef<ServiceMetadataWizardDialogComponent>,
               private dialogFormBuilder: FormBuilder) {
 
     this.dialogForm = dialogFormBuilder.group({
 
       'documentIdentifier': new FormControl({value: ''}, [Validators.required]),
-      'documentIdentifierScheme':  new FormControl({value: ''  }, null),
-      'processSchema':  new FormControl({value: ''}, [Validators.required]),
-      'processIdentifier':  new FormControl({value: ''}, [Validators.required]),
-      'endpointUrl':  new FormControl({value: ''}, [Validators.required]),
-      'endpointCertificate':  new FormControl({value: ''}, null),
+      'documentIdentifierScheme': new FormControl({value: ''}, null),
+      'processSchema': new FormControl({value: ''}, [Validators.required]),
+      'processIdentifier': new FormControl({value: ''}, [Validators.required]),
+      'endpointUrl': new FormControl({value: ''}, [Validators.required]),
+      'endpointCertificate': new FormControl({value: ''}, null),
 
     });
   }
 
-  getExtensionXML(){
+  onFileChanged(event) {
+    this.selectedFile = event.target.files[0]
+  }
+
+  onUpload() {
+    // this.http is the injected HttpClient
+    this.http.post(SmpConstants.REST_CERTIFICATE, this.selectedFile)
+      .subscribe(event => {
+
+        console.log(event); // handle event here
+      });
+  }
+
+
+  getExtensionXML() {
     /*
     var xmlString = '<Extension xmlns="http://docs.oasis-open.org/bdxr/ns/SMP/2016/05">'
     let arrayLength = this.elements.length;
@@ -64,5 +81,4 @@ export class ServiceGroupExtensionWizardDialogComponent  {
   }
 
 
-
 }
diff --git a/smp-angular/src/app/service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-edit-ro.model.ts b/smp-angular/src/app/service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-edit-ro.model.ts
index 9c2d25b7d..abc19b6b0 100644
--- a/smp-angular/src/app/service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-edit-ro.model.ts
+++ b/smp-angular/src/app/service-group-edit/service-metadata-wizard-dialog/service-metadata-wizard-edit-ro.model.ts
@@ -1,6 +1,16 @@
 
-export interface ServiceGroupExtensionRo  {
-  serviceGroupId: number;
-  extension: string;
-  errorMessage?: string;
+export interface ServiceMetadataWizardRo  {
+  participantIdentifierScheme: string;
+  participantIdentifier: string;
+  documentIdentifierScheme: string;
+  documentIdentifier: string;
+  processSchema: string;
+  processIdentifier: string;
+  transportProfile: string;
+  endpointUrl: string;
+  certificate: string;
+  serviceDescription: string;
+  technicalContactUrl: string;
+  contentXML: string
+  errorMessage: string
 }
diff --git a/smp-angular/src/app/service-group-search/service-group-search-controller.ts b/smp-angular/src/app/service-group-search/service-group-search-controller.ts
index 28c1698b6..2432c65fe 100644
--- a/smp-angular/src/app/service-group-search/service-group-search-controller.ts
+++ b/smp-angular/src/app/service-group-search/service-group-search-controller.ts
@@ -1,5 +1,5 @@
 import {SearchTableController} from '../common/search-table/search-table-controller';
-import {MatDialog, MatDialogConfig, MatDialogRef} from '@angular/material';
+import {MatDialog, MatDialogConfig} from '@angular/material';
 import {ServiceGroupSearchRo} from './service-group-search-ro.model';
 
 export class ServiceGroupSearchController implements SearchTableController {
@@ -23,4 +23,6 @@ export class ServiceGroupSearchController implements SearchTableController {
   public newRow(): ServiceGroupSearchRo {
     return null;
   }
+
+  public dataSaved() {}
 }
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 190aeca38..7493ccbe5 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
@@ -41,7 +41,7 @@
                 id="domain_id">
       <mat-option [value]="''">
       </mat-option>
-      <mat-option *ngFor="let domain of domainlist" [value]="domain.domainCode">
+      <mat-option *ngFor="let domain of lookups.cachedDomainList" [value]="domain.domainCode">
         {{domain.domainCode}} ({{domain.smlSubdomain}})
       </mat-option>
     </mat-select>
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 bc8111bc7..c626c00bc 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,13 +1,10 @@
 ///<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';
+import {MatDialog} from '@angular/material';
 import {AlertService} from '../alert/alert.service';
 import {ServiceGroupSearchController} from './service-group-search-controller';
 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";
 import {GlobalLookups} from "../common/global-lookups";
 
@@ -25,7 +22,6 @@ export class ServiceGroupSearchComponent implements OnInit {
   columnPicker: ColumnPicker = new ColumnPicker();
   serviceGroupSearchController: ServiceGroupSearchController;
   filter: any = {};
-  domainlist: Array<any>;
   contextPath: string = location.pathname.substring(0, location.pathname.length - 3); // remove /ui s
   baseUrl: string = SmpConstants.REST_SEARCH;
 
@@ -38,14 +34,6 @@ export class ServiceGroupSearchComponent implements OnInit {
   }
 
   ngOnInit() {
-    this.lookups.getDomainLookupObservable().subscribe((domains: SearchTableResult) => {
-      this.domainlist = new Array(domains.serviceEntities.length)
-        .map((v, index) => domains.serviceEntities[index] as DomainRo);
-
-      this.domainlist = domains.serviceEntities.map(serviceEntity => {
-        return {...serviceEntity}
-      });
-    });
 
     this.serviceGroupSearchController = new ServiceGroupSearchController(this.dialog);
 
diff --git a/smp-angular/src/app/smp.constants.ts b/smp-angular/src/app/smp.constants.ts
index 0e1b1715c..df2285a0b 100644
--- a/smp-angular/src/app/smp.constants.ts
+++ b/smp-angular/src/app/smp.constants.ts
@@ -7,5 +7,9 @@ export class SmpConstants {
   public static readonly REST_METADATA = 'rest/servicemetadata';
 
   public static readonly REST_CERTIFICATE = `${SmpConstants.REST_USER}/certdata`;
+  public static readonly REST_SERVICE_GROUP_EXTENSION = `${SmpConstants.REST_EDIT}/extension`;
+  public static readonly REST_SERVICE_GROUP_EXTENSION_VALIDATE = `${SmpConstants.REST_SERVICE_GROUP_EXTENSION}/validate`;
+  public static readonly REST_SERVICE_GROUP_EXTENSION_FORMAT = `${SmpConstants.REST_SERVICE_GROUP_EXTENSION}/format`;
+  public static readonly REST_METADATA_VALIDATE = `${SmpConstants.REST_METADATA}/validate`;
 
 }
diff --git a/smp-angular/src/app/user/user-controller.ts b/smp-angular/src/app/user/user-controller.ts
index 448282595..b8a2ad3d8 100644
--- a/smp-angular/src/app/user/user-controller.ts
+++ b/smp-angular/src/app/user/user-controller.ts
@@ -33,4 +33,7 @@ export class UserController implements SearchTableController {
       status: SearchTableEntityStatus.NEW
     }
   }
+
+  public dataSaved() {
+  }
 }
diff --git a/smp-angular/src/styles.css b/smp-angular/src/styles.css
index 95c98d193..0426d0567 100644
--- a/smp-angular/src/styles.css
+++ b/smp-angular/src/styles.css
@@ -25,7 +25,9 @@ html, body {
   font-weight: bolder !important;
   margin: 0 2px  !important;
 }
-
+.mat-card{
+  padding: 10px !important;
+}
 .text-select {
   -webkit-user-select: text;
   -moz-user-select: text;
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/CaseSensitivityNormalizer.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/CaseSensitivityNormalizer.java
index b66ba56f8..ddd5bb0c4 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/CaseSensitivityNormalizer.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/CaseSensitivityNormalizer.java
@@ -45,9 +45,7 @@ public class CaseSensitivityNormalizer {
         toLowerCaseStringList(this.caseSensitiveParticipantSchemes);
     }
 
-    public ParticipantIdentifierType normalize(final ParticipantIdentifierType participantIdentifier) {
-        String scheme = participantIdentifier.getScheme();
-        String value = participantIdentifier.getValue();
+    public ParticipantIdentifierType normalizeParticipantIdentifier(String scheme, String value) {
         if (!caseSensitiveParticipantSchemes.contains(scheme.toLowerCase())) {
             scheme = scheme.toLowerCase();
             value = value.toLowerCase();
@@ -55,9 +53,19 @@ public class CaseSensitivityNormalizer {
         return new ParticipantIdentifierType(value, scheme);
     }
 
+    public ParticipantIdentifierType normalize(final ParticipantIdentifierType participantIdentifier) {
+        String scheme = participantIdentifier.getScheme();
+        String value = participantIdentifier.getValue();
+        return normalizeParticipantIdentifier(scheme, value);
+    }
+
     public DocumentIdentifier normalize(final DocumentIdentifier documentIdentifier) {
         String scheme = documentIdentifier.getScheme();
         String value = documentIdentifier.getValue();
+        return normalizeDocumentIdentifier(scheme, value);
+    }
+
+    public DocumentIdentifier normalizeDocumentIdentifier( String scheme, String value) {
         if (!caseSensitiveDocumentSchemes.contains(scheme.toLowerCase())) {
             scheme = scheme.toLowerCase();
             value = value.toLowerCase();
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/ExtensionConverter.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/ExtensionConverter.java
index 423875c0e..931fef73a 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/ExtensionConverter.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/ExtensionConverter.java
@@ -15,6 +15,8 @@ package eu.europa.ec.edelivery.smp.conversion;
 
 import eu.europa.ec.edelivery.smp.logging.SMPLogger;
 import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
+import eu.europa.ec.smp.api.exceptions.XmlInvalidAgainstSchemaException;
+import eu.europa.ec.smp.api.validators.BdxSmpOasisValidator;
 import org.apache.cxf.staxutils.PrettyPrintXMLStreamWriter;
 import org.oasis_open.docs.bdxr.ns.smp._2016._05.ExtensionType;
 
@@ -41,6 +43,8 @@ public class ExtensionConverter {
    // private static final String WRAPPED_FORMAT = "<ExtensionsWrapper xmlns=\"http://docs.oasis-open.org/bdxr/ns/SMP/2016/05\">%s</ExtensionsWrapper>";
     private static final byte[] WRAPPED_FORMAT_START = "<ExtensionsWrapper xmlns=\"http://docs.oasis-open.org/bdxr/ns/SMP/2016/05\">".getBytes();
     private static final byte[] WRAPPED_FORMAT_END = "</ExtensionsWrapper>".getBytes();
+    private static final byte[] WRAPPED_SERVICE_GROUP_START = "<ServiceGroup xmlns=\"http://docs.oasis-open.org/bdxr/ns/SMP/2016/05\"> <ParticipantIdentifier scheme=\"schema\">value</ParticipantIdentifier><ServiceMetadataReferenceCollection/>".getBytes();
+    private static final byte[] WRAPPED_SERVICE_GROUP_END = "</ServiceGroup>".getBytes();
     private static final QName EXT_TYPE_QNAME = new QName("http://docs.oasis-open.org/bdxr/ns/SMP/2016/05", "Extension");
 
     /**
@@ -119,7 +123,7 @@ public class ExtensionConverter {
         return baos.toByteArray();
     }
 
-    protected static List<ExtensionType> unmarshalExtensions(byte[] xml) throws JAXBException {
+    public static List<ExtensionType> unmarshalExtensions(byte[] xml) throws JAXBException {
 
 
         InputStream inStream = new ByteArrayInputStream(concatByteArrays(WRAPPED_FORMAT_START,xml,WRAPPED_FORMAT_END  ));
@@ -133,6 +137,16 @@ public class ExtensionConverter {
         }
     }
 
+    /**
+     * Method validates extension by schema In order to do that wraps the content to simple servicegroup.
+     *
+     * @param xml
+     */
+    public static  void validateExtensionBySchema(byte[] xml) throws XmlInvalidAgainstSchemaException {
+        byte[] buff = concatByteArrays(WRAPPED_SERVICE_GROUP_START,xml,WRAPPED_SERVICE_GROUP_END);
+        BdxSmpOasisValidator.validateXSD(buff);
+    }
+
     /**
      * Method concat the bytearrays to one array
      *
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/ServiceMetadataConverter.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/ServiceMetadataConverter.java
index 41db2fbdb..0e069b188 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/ServiceMetadataConverter.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/conversion/ServiceMetadataConverter.java
@@ -127,4 +127,6 @@ public class ServiceMetadataConverter {
     }
 
 
+
+
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBServiceGroup.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBServiceGroup.java
index d37e28c0a..e36ae4ec4 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBServiceGroup.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBServiceGroup.java
@@ -70,8 +70,7 @@ public class DBServiceGroup extends BaseEntity {
 
     @Column(name = "PARTICIPANT_SCHEME", length = CommonColumnsLengths.MAX_PARTICIPANT_IDENTIFIER_SCHEME_LENGTH, nullable = false)
     String participantScheme;
-    @Column(name = "SML_REGISTRED", nullable = false)
-    private boolean smlRegistered = false;
+
 
     @OneToOne(mappedBy = "dbServiceGroup", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
     private DBServiceGroupExtension serviceGroupExtension;
@@ -123,14 +122,6 @@ public class DBServiceGroup extends BaseEntity {
         return this.users;
     }
 
-    public boolean isSmlRegistered() {
-        return smlRegistered;
-    }
-
-    public void setSmlRegistered(boolean smlRegistered) {
-        this.smlRegistered = smlRegistered;
-    }
-
     public DBServiceGroupExtension getServiceGroupExtension() {
         return serviceGroupExtension;
     }
@@ -173,6 +164,18 @@ public class DBServiceGroup extends BaseEntity {
         }
     }
 
+    public Optional<DBServiceGroupDomain> findServiceGroupDomainForMetadata(String docId, String docSch){
+        for (DBServiceGroupDomain serviceGroupDomain : serviceGroupDomains) {
+            for (DBServiceMetadata dbServiceMetadata : serviceGroupDomain.getServiceMetadata()) {
+                if (Objects.equals(docId, dbServiceMetadata.getDocumentIdentifier())
+                        && Objects.equals(docId, dbServiceMetadata.getDocumentIdentifier()) ) {
+                    return Optional.of(serviceGroupDomain);
+                }
+            }
+        }
+        return Optional.empty();
+    }
+
 
 
     @Transient
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBServiceGroupDomain.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBServiceGroupDomain.java
index 9e5fc783b..cde68f389 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBServiceGroupDomain.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBServiceGroupDomain.java
@@ -55,6 +55,10 @@ public class DBServiceGroupDomain extends BaseEntity {
             fetch = FetchType.LAZY)
     private List<DBServiceMetadata> serviceMetadata = new ArrayList<>();
 
+
+    @Column(name = "SML_REGISTRED", nullable = false)
+    private boolean smlRegistered = false;
+
     @Column(name = "CREATED_ON" , nullable = false)
     LocalDateTime createdOn;
     @Column(name = "LAST_UPDATED_ON", nullable = false)
@@ -98,6 +102,15 @@ public class DBServiceGroupDomain extends BaseEntity {
         this.domain = domain;
     }
 
+    public boolean isSmlRegistered() {
+        return smlRegistered;
+    }
+
+    public void setSmlRegistered(boolean smlRegistered) {
+        this.smlRegistered = smlRegistered;
+    }
+
+
     public void addServiceMetadata(DBServiceMetadata metadata) {
         serviceMetadata.add(metadata);
         metadata.setServiceGroupDomain(this);
@@ -108,6 +121,14 @@ public class DBServiceGroupDomain extends BaseEntity {
         metadata.setServiceGroupDomain(null);
     }
 
+    public DBServiceMetadata removeServiceMetadata(String docId, String docSch) {
+        DBServiceMetadata dbServiceMetadata =  getServiceMetadata(docId,docSch );
+        if (dbServiceMetadata!=null) {
+            removeServiceMetadata(dbServiceMetadata);
+        }
+        return dbServiceMetadata;
+    }
+
     @Transient
     public DBServiceMetadata getServiceMetadata(int index) {
         return serviceMetadata.get(index);
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/BaseRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/BaseRO.java
index b19a0fec8..a2e393ba0 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/BaseRO.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/BaseRO.java
@@ -6,8 +6,8 @@ import java.io.Serializable;
 
 public class BaseRO  implements Serializable {
 
-    private int status;
-    private int index = EntityROStatus.PERSISTED.getStatusNumber();
+    private int status = EntityROStatus.PERSISTED.getStatusNumber();
+    private int index;
 
     public int getStatus() {
         return status;
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
index 6555e3708..7637bdfc8 100644
--- 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
@@ -14,6 +14,7 @@ public class CertificateRO extends BaseRO {
     private String subject;
     private String issuer;
     private String serialNumber;
+    private String encodedValue;
     private LocalDateTime validFrom;
     private LocalDateTime validTo;
 
@@ -71,4 +72,12 @@ public class CertificateRO extends BaseRO {
     public void setValidTo(LocalDateTime validTo) {
         this.validTo = validTo;
     }
+
+    public String getEncodedValue() {
+        return encodedValue;
+    }
+
+    public void setEncodedValue(String encodedValue) {
+        this.encodedValue = encodedValue;
+    }
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupDomainRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupDomainRO.java
index cbd5e1ed8..23e960e5e 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupDomainRO.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupDomainRO.java
@@ -1,31 +1,21 @@
 package eu.europa.ec.edelivery.smp.data.ui;
 
 
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * @author Joze Rihtarsic
  * @since 4.1
  */
 
 
-public class ServiceGroupRO extends BaseRO {
+public class ServiceGroupDomainRO extends BaseRO {
 
 
-    private static final long serialVersionUID = -7523221767041516157L;
+    private static final long serialVersionUID = -7111221767041516157L;
     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 List<DomainRO> lstDomains = new ArrayList<>();
-    private String extension;
-
-
-
+    private Long domainId;
+    String domainCode;
+    String smlSubdomain;
+    boolean smlRegistered;
 
 
     public Long getId() {
@@ -36,46 +26,35 @@ public class ServiceGroupRO extends BaseRO {
         this.id = id;
     }
 
-    public String getParticipantIdentifier() {
-        return participantIdentifier;
+    public Long getDomainId() {
+        return domainId;
     }
 
-    public void setParticipantIdentifier(String participantIdentifier) {
-        this.participantIdentifier = participantIdentifier;
+    public void setDomainId(Long domainId) {
+        this.domainId = domainId;
     }
 
-    public String getParticipantScheme() {
-        return participantScheme;
+    public String getDomainCode() {
+        return domainCode;
     }
 
-    public void setParticipantScheme(String participantScheme) {
-        this.participantScheme = participantScheme;
+    public void setDomainCode(String domainCode) {
+        this.domainCode = domainCode;
     }
 
-    public boolean isSmlRegistered() {
-        return smlRegistered;
+    public String getSmlSubdomain() {
+        return smlSubdomain;
     }
 
-    public void setSmlRegistered(boolean smlRegistered) {
-        this.smlRegistered = smlRegistered;
+    public void setSmlSubdomain(String smlSubdomain) {
+        this.smlSubdomain = smlSubdomain;
     }
 
-    public String getExtension() {
-        return extension;
-    }
-
-    public void setExtension(String extension) {
-        this.extension = extension;
+    public boolean isSmlRegistered() {
+        return smlRegistered;
     }
 
-    public List<ServiceMetadataRO> getServiceMetadata() {
-        return lstServiceMetadata;
+    public void setSmlRegistered(boolean registered) {
+        this.smlRegistered = registered;
     }
-    public List<UserRO> getUsers() {
-        return lstUser;
-    }
-    public List<DomainRO> getDomains() {
-        return lstDomains;
-    }
-
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupExtensionRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupExtensionRO.java
index 7867b2680..0fc54379c 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupExtensionRO.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupExtensionRO.java
@@ -1,4 +1,32 @@
 package eu.europa.ec.edelivery.smp.data.ui;
 
-public class ServiceGroupExtensionRO {
+public class ServiceGroupExtensionRO extends BaseRO {
+    private static final long serialVersionUID = -7555221767041516157L;
+    Long serviceGroupId;
+    String extension;
+    String errorMessage;
+
+    public Long getServiceGroupId() {
+        return serviceGroupId;
+    }
+
+    public void setServiceGroupId(Long serviceGroupId) {
+        this.serviceGroupId = serviceGroupId;
+    }
+
+    public String getExtension() {
+        return extension;
+    }
+
+    public void setExtension(String extension) {
+        this.extension = extension;
+    }
+
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
 }
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 f3da826f1..6ca51f3a0 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
@@ -1,7 +1,8 @@
 package eu.europa.ec.edelivery.smp.data.ui;
 
 
-import java.io.Serializable;
+import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -19,11 +20,12 @@ public class ServiceGroupRO extends BaseRO {
     private String participantIdentifier;
     private String participantScheme;
     private boolean smlRegistered = false;
-    private List<ServiceMetadataRO> lstServiceMetadata = new ArrayList<>();
     private List<UserRO> lstUser = new ArrayList<>();
-
-
-
+    private List<ServiceGroupDomainRO> serviceGroupDomains = new ArrayList<>();
+    // for UI  service groups are  in one list.
+    private List<ServiceMetadataRO> serviceMetadata = new ArrayList<>();
+    private int extensionStatus = EntityROStatus.PERSISTED.getStatusNumber();
+    private String extension;
 
 
     public Long getId() {
@@ -58,12 +60,31 @@ public class ServiceGroupRO extends BaseRO {
         this.smlRegistered = smlRegistered;
     }
 
+    public int getExtensionStatus() {
+        return extensionStatus;
+    }
 
-    public List<ServiceMetadataRO> getServiceMetadata() {
-        return lstServiceMetadata;
+    public void setExtensionStatus(int extensionStatus) {
+        this.extensionStatus = extensionStatus;
+    }
+
+    public String getExtension() {
+        return extension;
     }
+
+    public void setExtension(String extension) {
+        this.extension = extension;
+    }
+
     public List<UserRO> getUsers() {
         return lstUser;
     }
 
+    public List<ServiceGroupDomainRO> getServiceGroupDomains() {
+        return serviceGroupDomains;
+    }
+
+    public List<ServiceMetadataRO> getServiceMetadata() {
+        return serviceMetadata;
+    }
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupSearchRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupSearchRO.java
index cbd5e1ed8..947392f7c 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupSearchRO.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupSearchRO.java
@@ -1,31 +1,24 @@
 package eu.europa.ec.edelivery.smp.data.ui;
 
 
-import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
 /**
+ * Lighter (without administration walues) ServiceGroup object for searching service group and its metadata.
+ *
  * @author Joze Rihtarsic
  * @since 4.1
  */
 
-
-public class ServiceGroupRO extends BaseRO {
+public class ServiceGroupSearchRO 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 List<DomainRO> lstDomains = new ArrayList<>();
-    private String extension;
-
-
-
 
 
     public Long getId() {
@@ -52,30 +45,7 @@ public class ServiceGroupRO extends BaseRO {
         this.participantScheme = participantScheme;
     }
 
-    public boolean isSmlRegistered() {
-        return smlRegistered;
-    }
-
-    public void setSmlRegistered(boolean smlRegistered) {
-        this.smlRegistered = smlRegistered;
-    }
-
-    public String getExtension() {
-        return extension;
-    }
-
-    public void setExtension(String extension) {
-        this.extension = extension;
-    }
-
     public List<ServiceMetadataRO> getServiceMetadata() {
         return lstServiceMetadata;
     }
-    public List<UserRO> getUsers() {
-        return lstUser;
-    }
-    public List<DomainRO> getDomains() {
-        return lstDomains;
-    }
-
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceMetadataRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceMetadataRO.java
index 6d8605402..dad9a1dd2 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceMetadataRO.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceMetadataRO.java
@@ -1,7 +1,7 @@
 package eu.europa.ec.edelivery.smp.data.ui;
 
 
-import java.io.Serializable;
+import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus;
 
 /**
  * @author Joze Rihtarsic
@@ -11,14 +11,40 @@ public class ServiceMetadataRO extends BaseRO {
 
 
     private static final long serialVersionUID = 67944640449327185L;
-
+    private Long id;
     String documentIdentifier;
     String documentIdentifierScheme;
+    Long serviceGroupDomainId;
+   // Long domainId;
     String smlSubdomain;
     String domainCode;
-
+    private int xmlContentStatus = EntityROStatus.PERSISTED.getStatusNumber();
     String xmlContent;
 
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getServiceGroupDomainId() {
+        return serviceGroupDomainId;
+    }
+
+    public void setServiceGroupDomainId(Long serviceGroupDomainId) {
+        this.serviceGroupDomainId = serviceGroupDomainId;
+    }
+/*
+    public Long getDomainId() {
+        return domainId;
+    }
+
+    public void setDomainId(Long domainId) {
+        this.domainId = domainId;
+    }
+*/
     public String getDocumentIdentifier() {
         return documentIdentifier;
     }
@@ -58,4 +84,12 @@ public class ServiceMetadataRO extends BaseRO {
     public void setXmlContent(String xmlContent) {
         this.xmlContent = xmlContent;
     }
+
+    public int getXmlContentStatus() {
+        return xmlContentStatus;
+    }
+
+    public void setXmlContentStatus(int xmlContentStatus) {
+        this.xmlContentStatus = xmlContentStatus;
+    }
 }
\ No newline at end of file
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceMetadataValidationRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceMetadataValidationRO.java
new file mode 100644
index 000000000..37e7bc5ec
--- /dev/null
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceMetadataValidationRO.java
@@ -0,0 +1,67 @@
+package eu.europa.ec.edelivery.smp.data.ui;
+
+/**
+ * @author Joze Rihtarsic
+ * @since 4.1
+ */
+public class ServiceMetadataValidationRO extends BaseRO {
+
+
+    private static final long serialVersionUID = 65555540449327185L;
+
+    String participantScheme;
+    String participantIdentifier;
+    String documentIdentifierScheme;
+    String documentIdentifier;
+
+    String errorMessage;
+    String xmlContent;
+
+    public String getParticipantScheme() {
+        return participantScheme;
+    }
+
+    public void setParticipantScheme(String participantScheme) {
+        this.participantScheme = participantScheme;
+    }
+
+    public String getParticipantIdentifier() {
+        return participantIdentifier;
+    }
+
+    public void setParticipantIdentifier(String participantIdentifier) {
+        this.participantIdentifier = participantIdentifier;
+    }
+
+    public String getDocumentIdentifierScheme() {
+        return documentIdentifierScheme;
+    }
+
+    public void setDocumentIdentifierScheme(String documentIdentifierScheme) {
+        this.documentIdentifierScheme = documentIdentifierScheme;
+    }
+
+    public String getDocumentIdentifier() {
+        return documentIdentifier;
+    }
+
+    public void setDocumentIdentifier(String documentIdentifier) {
+        this.documentIdentifier = documentIdentifier;
+    }
+
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
+
+    public String getXmlContent() {
+        return xmlContent;
+    }
+
+    public void setXmlContent(String xmlContent) {
+        this.xmlContent = xmlContent;
+    }
+}
\ No newline at end of file
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorBusinessCode.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorBusinessCode.java
index 0aa830f22..13081b04c 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorBusinessCode.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorBusinessCode.java
@@ -27,5 +27,6 @@ public enum ErrorBusinessCode {
     UNAUTHORIZED,
     NOT_FOUND,
     USER_NOT_FOUND,
+    INVALID_INPUT_DATA,
     TECHNICAL;
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorCode.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorCode.java
index a279e25d2..bcf7791e2 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorCode.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/ErrorCode.java
@@ -17,6 +17,8 @@ public enum ErrorCode {
     INVALID_DOMAIN_CODE(400,"SMP:112",ErrorBusinessCode.FORMAT_ERROR,"Provided Domain Code '%s' does not match required pattern: '%s'"),
     ILLEGAL_STATE_DOMAIN_MULTIPLE_ENTRY(500,"SMP:113",ErrorBusinessCode.TECHNICAL,"More than one domain entry  (domain: '%s') is defined in database!"),
     MISSING_DOMAIN(400,"SMP:114",ErrorBusinessCode.MISSING_FIELD,"More than one domain registred on SMP. The domain must be defined!"),
+
+
     // user error messages
     INVALID_USER_NO_IDENTIFIERS (400,"SMP:120",ErrorBusinessCode.MISSING_FIELD,"Invalid user - no identifiers!"),
     ILLEGAL_STATE_USERNAME_MULTIPLE_ENTRY(500,"SMP:121",ErrorBusinessCode.TECHNICAL,"More than one user entry (username: '%s') is defined in database!"),
@@ -31,11 +33,19 @@ public enum ErrorCode {
     SG_NOT_EXISTS(404,"SMP:131",ErrorBusinessCode.NOT_FOUND,"ServiceGroup not found (dpart. id: '%s', part. sch.: '%s')!"),
     SG_NOT_REGISTRED_FOR_DOMAIN(400,"SMP:131",ErrorBusinessCode.NOT_FOUND,"Service group not registred for domain (domain: %s, part. id:~ '%s', part. sch.: '%s')!"),
     INVALID_EXTENSION_FOR_SG (400,"SMP:132",ErrorBusinessCode.XSD_INVALID,"Invalid extension for service group (part. id: '%s', part. sch.: '%s'). Error: %s!"),
+    DUPLICATE_DOMAIN_FOR_SG (400,"SMP:133",ErrorBusinessCode.INVALID_INPUT_DATA,"Repeated domain for Service group (part. id: '%s', part. sch.: '%s', domainCode %s, smlDomain %s).!"),
+    MISSING_SG_ID (400,"SMP:134",ErrorBusinessCode.INVALID_INPUT_DATA,"Missing service group(part. id: '%s', part. sch.: '%s'!"),
+
+    INVALID_SG_ID (400,"SMP:135",ErrorBusinessCode.INVALID_INPUT_DATA,"Invalid Id for Service group(part. id: '%s', part. sch.: '%s', id %d).!"),
+
+
     // service metadata error
     ILLEGAL_STATE_SMD_MULTIPLE_ENTRY (500,"SMP:140",ErrorBusinessCode.TECHNICAL,"More than one service metadata ( doc. id: %s, doc. sch.: '%s') for participant ( part. id %s, part. sch. : '%s') is defined in database!"),
     METADATA_NOT_EXISTS(404,"SMP:141",ErrorBusinessCode.NOT_FOUND,"ServiceMetadata not found (part. id: '%s', part. sch.: '%s',doc. id: '%s', doc. sch.: '%s')!"),
     SMD_NOT_EXISTS_FOR_DOMAIN(404,"SMP:142",ErrorBusinessCode.NOT_FOUND,"ServiceMetadata not found for domain (domain: %s, part. id: '%s', part. sch.: '%s')!"),
     INVALID_SMD_XML (400,"SMP:143",ErrorBusinessCode.XSD_INVALID,"Invalid service metada. Error: %s"),
+    IVALID_SMD_DOCUMENT_DATA (400,"SMP:143",ErrorBusinessCode.INVALID_INPUT_DATA,"XML serviceMetadata document (doc. id: '%s', doc. sch.: '%s') " +
+            "do not match metadata request (doc. id: '%s', doc. sch.: '%s')."),
 
     // SML integration
     SML_INTEGRATION_EXCEPTION (500,"SMP:150",ErrorBusinessCode.TECHNICAL,"Could not create new DNS entry through SML! Error: %s "),
@@ -45,6 +55,7 @@ public enum ErrorCode {
 
     JAXB_INITIALIZATION (500,"SMP:511",ErrorBusinessCode.TECHNICAL, "Could not create Unmarshaller for class %s!"),
     XML_PARSE_EXCEPTION (500,"SMP:512",ErrorBusinessCode.TECHNICAL, "Error occured while parsing input stream for %s.  Error: %s!"),
+    INVALID_REQEUST (500,"SMP:513",ErrorBusinessCode.TECHNICAL, "Invalid request %s.  Error: %s!"),
 
     //
     ;
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ServiceGroupService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ServiceGroupService.java
index ca7ab211c..8f201e56f 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ServiceGroupService.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ServiceGroupService.java
@@ -124,14 +124,14 @@ public class ServiceGroupService {
             DBServiceGroup sg = dbServiceGroup.get();
             validateOwnership(newOwnerName, sg);
             //check is domain exists
-            Optional<DBServiceGroupDomain> sgd = dbServiceGroup.get().getServiceGroupForDomain(dmn.getDomainCode());
+            Optional<DBServiceGroupDomain> sgd = sg.getServiceGroupForDomain(dmn.getDomainCode());
             if (!sgd.isPresent()){
                 SMPRuntimeException ex = new SMPRuntimeException(SG_NOT_REGISTRED_FOR_DOMAIN,domain,normalizedParticipantId.getValue(), normalizedParticipantId.getScheme());
                 LOG.businessError(SMPMessageCode.BUS_SAVE_SERVICE_GROUP_FAILED,domain,normalizedParticipantId.getValue(), normalizedParticipantId.getScheme(), ex.getMessage()  );
                 throw ex;
             }
             //update extensions
-            dbServiceGroup.get().setExtension(extensions);
+            sg.setExtension(extensions);
             serviceGroupDao.update(sg);
             return false;
         } else {
@@ -141,15 +141,16 @@ public class ServiceGroupService {
             newSg.setParticipantScheme(normalizedParticipantId.getScheme());
             newSg.setExtension(extensions);
             newSg.addDomain(dmn); // add initial domain
+            // set initial domain as not registered
+            newSg.getServiceGroupDomains().get(0).setSmlRegistered(false);
             newSg.getUsers().add(newOwner.get());
-            newSg.setSmlRegistered(false);
             // persist (make sure this is not in transaction)
             serviceGroupDao.persistFlushDetach(newSg);
             // register to SML
             boolean registered = smlConnector.registerInDns(normalizedParticipantId, dmn);
             if (registered) {
                 // update status in database
-                newSg.setSmlRegistered(true);
+                newSg.getServiceGroupDomains().get(0).setSmlRegistered(false);
                 serviceGroupDao.update(newSg);
             }
             return true;
@@ -195,7 +196,7 @@ public class ServiceGroupService {
     /**
      * Method validates if user owner with identifier is owner of servicegroup
      * @param  ownerIdentifier
-     * @param dbsg
+     * @param serviceGroupIdentifier
      */
     @Transactional
     public boolean isServiceGroupOwner(String ownerIdentifier, String serviceGroupIdentifier ){
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceGroupSearchService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceGroupSearchService.java
index e399f41ea..21a9beb72 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceGroupSearchService.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceGroupSearchService.java
@@ -1,44 +1,33 @@
 package eu.europa.ec.edelivery.smp.services.ui;
 
-import eu.europa.ec.edelivery.smp.conversion.ExtensionConverter;
 import eu.europa.ec.edelivery.smp.data.dao.BaseDao;
 import eu.europa.ec.edelivery.smp.data.dao.DomainDao;
 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.DBDomain;
 import eu.europa.ec.edelivery.smp.data.model.DBServiceGroup;
-import eu.europa.ec.edelivery.smp.data.model.DBServiceGroupDomain;
-import eu.europa.ec.edelivery.smp.data.model.DBUser;
-import eu.europa.ec.edelivery.smp.data.ui.*;
-import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus;
+import eu.europa.ec.edelivery.smp.data.ui.DomainRO;
+import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupSearchRO;
+import eu.europa.ec.edelivery.smp.data.ui.ServiceMetadataRO;
+import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
 import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException;
 import eu.europa.ec.edelivery.smp.logging.SMPLogger;
 import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
 import eu.europa.ec.edelivery.smp.services.ui.filters.ServiceGroupFilter;
-import eu.europa.ec.smp.api.exceptions.XmlInvalidAgainstSchemaException;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import javax.xml.transform.*;
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.stream.StreamSource;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
 
 import static eu.europa.ec.edelivery.smp.exceptions.ErrorCode.DOMAIN_NOT_EXISTS;
-import static eu.europa.ec.edelivery.smp.exceptions.ErrorCode.INVALID_ENCODING;
-import static eu.europa.ec.edelivery.smp.exceptions.ErrorCode.INVALID_REQEUST;
 
 @Service
-public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, ServiceGroupRO> {
-    private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UIServiceGroupService.class);
+public class UIServiceGroupSearchService extends UIServiceBase<DBServiceGroup, ServiceGroupSearchRO> {
+    private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UIServiceGroupSearchService.class);
 
     @Autowired
     DomainDao domainDao;
@@ -50,7 +39,6 @@ public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, Service
     UserDao userDao;
 
 
-
     @Override
     protected BaseDao<DBServiceGroup> getDatabaseDao() {
         return serviceGroupDao;
@@ -67,21 +55,21 @@ public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, Service
      * @return
      */
     @Transactional
-    public ServiceResult<ServiceGroupRO> getTableList(int page, int pageSize,
-                                                      String sortField,
-                                                      String sortOrder, ServiceGroupFilter filter, String domainCode) {
+    public ServiceResult<ServiceGroupSearchRO> getTableList(int page, int pageSize,
+                                                            String sortField,
+                                                            String sortOrder, ServiceGroupFilter filter, String domainCode) {
 
-        DBDomain d  = null;
-        if (!StringUtils.isBlank(domainCode)){
+        DBDomain d = null;
+        if (!StringUtils.isBlank(domainCode)) {
             Optional<DBDomain> od = domainDao.getDomainByCode(domainCode);
-            if (od.isPresent()){
+            if (od.isPresent()) {
                 d = od.get();
             } else {
                 throw new SMPRuntimeException(DOMAIN_NOT_EXISTS, domainCode);
             }
-
         }
-        ServiceResult<ServiceGroupRO> sg = new ServiceResult<>();
+
+        ServiceResult<ServiceGroupSearchRO> sg = new ServiceResult<>();
         sg.setPage(page < 0 ? 0 : page);
         sg.setPageSize(pageSize);
         long iCnt = serviceGroupDao.getServiceGroupCount(filter, d);
@@ -90,9 +78,9 @@ public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, Service
         if (iCnt > 0) {
             int iStartIndex = pageSize < 0 ? -1 : page * pageSize;
             List<DBServiceGroup> lst = serviceGroupDao.getServiceGroupList(iStartIndex, pageSize, sortField, sortOrder, filter, d);
-            List<ServiceGroupRO> lstRo = new ArrayList<>();
+            List<ServiceGroupSearchRO> lstRo = new ArrayList<>();
             for (DBServiceGroup dbServiceGroup : lst) {
-                ServiceGroupRO serviceGroupRo = convertToRo(dbServiceGroup);
+                ServiceGroupSearchRO serviceGroupRo = convertToRo(dbServiceGroup);
                 serviceGroupRo.setIndex(iStartIndex++);
                 lstRo.add(serviceGroupRo);
             }
@@ -103,21 +91,17 @@ public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, Service
 
     /**
      * Convert Database object to Rest object for UI
+     *
      * @param dbServiceGroup - database  entity
      * @return ServiceGroupRO
      */
-    public ServiceGroupRO convertToRo(DBServiceGroup dbServiceGroup) {
-        ServiceGroupRO serviceGroupRo = new ServiceGroupRO();
+    public ServiceGroupSearchRO convertToRo(DBServiceGroup dbServiceGroup) {
+        ServiceGroupSearchRO serviceGroupRo = new ServiceGroupSearchRO();
         serviceGroupRo.setId(dbServiceGroup.getId());
         serviceGroupRo.setParticipantIdentifier(dbServiceGroup.getParticipantIdentifier());
         serviceGroupRo.setParticipantScheme(dbServiceGroup.getParticipantScheme());
         dbServiceGroup.getServiceGroupDomains().forEach(sgd -> {
             DomainRO dmn = new DomainRO();
-            dmn.setId(sgd.getDomain().getId());
-            dmn.setDomainCode(sgd.getDomain().getDomainCode());
-            dmn.setSmlSubdomain(sgd.getDomain().getSmlSubdomain());
-            serviceGroupRo.getDomains().add(dmn);
-
             sgd.getServiceMetadata().forEach(sgmd -> {
                 ServiceMetadataRO smdro = new ServiceMetadataRO();
                 smdro.setDocumentIdentifier(sgmd.getDocumentIdentifier());
@@ -127,159 +111,6 @@ 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);
-        });
         return serviceGroupRo;
     }
-
-    @Transactional
-    public ServiceGroupRO getServiceGroupById(Long serviceGroupId) {
-        DBServiceGroup dbServiceGroup = getDatabaseDao().find(serviceGroupId);
-        return  convertToRo(dbServiceGroup);
-    }
-
-    @Transactional
-    public ServiceGroupExtensionRO getServiceGroupExtensionById(Long serviceGroupId) {
-        ServiceGroupExtensionRO ex = new ServiceGroupExtensionRO();
-        DBServiceGroup dbServiceGroup = getDatabaseDao().find(serviceGroupId);
-        ex.setServiceGroupId(dbServiceGroup.getId());
-        if (dbServiceGroup.getExtension()!=null) {
-            ex.setExtension(new String(dbServiceGroup.getExtension()));
-        }
-        return ex;
-    }
-
-    @Transactional
-    public void updateServiceGroupList(List<ServiceGroupRO> lst) {
-        boolean suc = false;
-        for (ServiceGroupRO dRo: lst){
-
-
-            if (dRo.getStatus() == EntityROStatus.NEW.getStatusNumber()) {
-                addNewServiceGroup(dRo);
-            } else if (dRo.getStatus() == EntityROStatus.UPDATED.getStatusNumber()) {
-               updateServiceGroup(dRo);
-            } else if (dRo.getStatus() == EntityROStatus.REMOVE.getStatusNumber()) {
-                DBServiceGroup upd = getDatabaseDao().find(dRo.getId());
-                serviceGroupDao.removeServiceGroup(upd);
-            }
-        }
-    }
-
-
-
-    /**
-     *  Method converts UI resource object entity to database entity and persists it to database
-     * @param dRo
-     */
-    private void addNewServiceGroup(ServiceGroupRO dRo){
-        DBServiceGroup dDb = convertFromRo(dRo);
-        for (UserRO userRO: dRo.getUsers()) {
-            DBUser du = userDao.find(userRO.getId());
-            dDb.getUsers().add(du);
-        }
-        for (DomainRO domainRO: dRo.getDomains()) {
-            DBDomain dmn = domainDao.find(domainRO.getId());
-            DBServiceGroupDomain dsgdomain = new DBServiceGroupDomain();
-            dsgdomain.setDomain(dmn);
-            dDb.getServiceGroupDomains().add(dsgdomain);
-        }
-        if (dRo.getExtension()!=null){
-            try {
-                dDb.setExtension(dRo.getExtension().getBytes("UTF-8"));
-            } catch (UnsupportedEncodingException e) {
-                throw new SMPRuntimeException(INVALID_ENCODING, "UTF-8");
-            }
-        }
-        getDatabaseDao().persistFlushDetach(dDb);
-    }
-
-    /**
-     *  Method converts UI resource object entity to database entity and update changes  to database
-     * @param dRo
-     */
-    private void updateServiceGroup(ServiceGroupRO dRo){
-        DBServiceGroup upd = getDatabaseDao().find(dRo.getId());
-        upd.getUsers().clear();
-        // update users
-        List<UserRO> lstUsers = dRo.getUsers();
-        for (UserRO userRO: lstUsers) {
-            System.out.println("GET USER ID: " + userRO.getId());
-            DBUser du = userDao.find(userRO.getId());
-            upd.getUsers().add(du);
-        }/*
-        // get domains
-        List<DBServiceGroupDomain> lstDomains = dRo.getDomains();
-        for (DBDomain domainRO: dRo.getDomains()) {
-            System.out.println("GET USER ID: " + userRO.getId());
-            DBUser du = userDao.find(userRO.getId());
-            upd.getUsers().add(du);
-        }*/
-
-        // and domain
-        getDatabaseDao().update(upd);
-    }
-
-
-    public ServiceGroupExtensionRO validateExtension(ServiceGroupExtensionRO sgExtension){
-        if (sgExtension==null) {
-            throw new SMPRuntimeException(INVALID_REQEUST, "Validate extension", "Missing Extension parameter");
-        }
-        else if (StringUtils.isBlank(sgExtension.getExtension()) ){
-            sgExtension.setErrorMessage("Empty extension");
-        }
-        else {
-            try {
-                byte[] buff = sgExtension.getExtension().getBytes("UTF-8");
-                ExtensionConverter.validateExtensionBySchema(buff); // validate by schema
-                sgExtension.setErrorMessage(null);
-            } catch (XmlInvalidAgainstSchemaException e) {
-                sgExtension.setErrorMessage(ExceptionUtils.getRootCauseMessage(e));
-            } catch (UnsupportedEncodingException e) {
-                sgExtension.setErrorMessage(ExceptionUtils.getRootCauseMessage(e));
-            }
-        }
-        return sgExtension;
-    }
-
-    /**
-     * TODO format extension - add root element and format...
-     * @param sgExtension
-     * @return
-     */
-    public ServiceGroupExtensionRO formatExtension(ServiceGroupExtensionRO sgExtension) {
-        if (sgExtension==null) {
-            throw new SMPRuntimeException(INVALID_REQEUST, "Format extension", "Missing Extension parameter");
-        }
-        else if (StringUtils.isBlank(sgExtension.getExtension()) ){
-            sgExtension.setErrorMessage("Empty extension");
-        }
-        else {
-            try {
-                Source xmlInput = new StreamSource(new StringReader(sgExtension.getExtension()));
-                StringWriter stringWriter = new StringWriter();
-                StreamResult xmlOutput = new StreamResult(stringWriter);
-                TransformerFactory transformerFactory = TransformerFactory.newInstance();
-                transformerFactory.setAttribute("indent-number", 4);
-                Transformer transformer = transformerFactory.newTransformer();
-                transformer.setOutputProperty(OutputKeys.INDENT, "yes");
-                transformer.transform(xmlInput, xmlOutput);
-                sgExtension.setExtension(xmlOutput.getWriter().toString());
-            } catch (TransformerConfigurationException e) {
-                sgExtension.setErrorMessage(ExceptionUtils.getRootCauseMessage(e));
-            } catch (TransformerException e) {
-                sgExtension.setErrorMessage(ExceptionUtils.getRootCauseMessage(e));
-            }
-        }
-        return sgExtension;
-    }
-
 }
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 3670a5651..585874790 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
@@ -1,29 +1,42 @@
 package eu.europa.ec.edelivery.smp.services.ui;
 
+import eu.europa.ec.edelivery.smp.conversion.CaseSensitivityNormalizer;
+import eu.europa.ec.edelivery.smp.conversion.ExtensionConverter;
+import eu.europa.ec.edelivery.smp.conversion.ServiceMetadataConverter;
 import eu.europa.ec.edelivery.smp.data.dao.BaseDao;
 import eu.europa.ec.edelivery.smp.data.dao.DomainDao;
 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.DBDomain;
-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.model.*;
+import eu.europa.ec.edelivery.smp.data.ui.*;
 import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus;
+import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException;
 import eu.europa.ec.edelivery.smp.logging.SMPLogger;
 import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
 import eu.europa.ec.edelivery.smp.services.ui.filters.ServiceGroupFilter;
+import eu.europa.ec.smp.api.exceptions.XmlInvalidAgainstSchemaException;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.oasis_open.docs.bdxr.ns.smp._2016._05.DocumentIdentifier;
+import org.oasis_open.docs.bdxr.ns.smp._2016._05.ParticipantIdentifierType;
+import org.oasis_open.docs.bdxr.ns.smp._2016._05.ServiceMetadata;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.time.LocalDateTime;
+import javax.xml.transform.*;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static eu.europa.ec.edelivery.smp.exceptions.ErrorCode.*;
 
 @Service
 public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, ServiceGroupRO> {
@@ -38,6 +51,10 @@ public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, Service
     @Autowired
     UserDao userDao;
 
+    @Autowired
+    private CaseSensitivityNormalizer caseSensitivityNormalizer;
+
+
     @Override
     protected BaseDao<DBServiceGroup> getDatabaseDao() {
         return serviceGroupDao;
@@ -58,18 +75,16 @@ public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, Service
                                                       String sortField,
                                                       String sortOrder, ServiceGroupFilter filter, String domainCode) {
 
-        DBDomain d  = null;
-        if (!StringUtils.isBlank(domainCode)){
+        DBDomain d = null;
+        if (!StringUtils.isBlank(domainCode)) {
             Optional<DBDomain> od = domainDao.getDomainByCode(domainCode);
-            if (od.isPresent()){
+            if (od.isPresent()) {
                 d = od.get();
             } else {
-                LOG.error("Domain with code {} does not exists ", domainCode);
+                throw new SMPRuntimeException(DOMAIN_NOT_EXISTS, domainCode);
             }
 
         }
-
-
         ServiceResult<ServiceGroupRO> sg = new ServiceResult<>();
         sg.setPage(page < 0 ? 0 : page);
         sg.setPageSize(pageSize);
@@ -79,37 +94,13 @@ public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, Service
         if (iCnt > 0) {
             int iStartIndex = pageSize < 0 ? -1 : page * pageSize;
             List<DBServiceGroup> lst = serviceGroupDao.getServiceGroupList(iStartIndex, pageSize, sortField, sortOrder, filter, d);
-
             List<ServiceGroupRO> lstRo = new ArrayList<>();
             for (DBServiceGroup dbServiceGroup : lst) {
-                ServiceGroupRO serviceGroupRo = new ServiceGroupRO();
+                ServiceGroupRO serviceGroupRo = convertToRo(dbServiceGroup);
+                serviceGroupRo.setStatus(EntityROStatus.PERSISTED.getStatusNumber());
                 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();
-                        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);
-                });
                 lstRo.add(serviceGroupRo);
             }
-
             sg.getServiceEntities().addAll(lstRo);
         }
         return sg;
@@ -118,23 +109,358 @@ public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, Service
     @Transactional
     public ServiceGroupRO getServiceGroupById(Long serviceGroupId) {
         DBServiceGroup dbServiceGroup = getDatabaseDao().find(serviceGroupId);
+        return convertToRo(dbServiceGroup);
+    }
+
+    @Transactional
+    public ServiceGroupExtensionRO getServiceGroupExtensionById(Long serviceGroupId) {
+        ServiceGroupExtensionRO ex = new ServiceGroupExtensionRO();
+        DBServiceGroup dbServiceGroup = getDatabaseDao().find(serviceGroupId);
+        ex.setServiceGroupId(dbServiceGroup.getId());
+        if (dbServiceGroup.getExtension() != null) {
+            ex.setExtension(new String(dbServiceGroup.getExtension()));
+        }
+        return ex;
+    }
+
+    @Transactional
+    public void updateServiceGroupList(List<ServiceGroupRO> lst) {
+        boolean suc = false;
+        for (ServiceGroupRO dRo : lst) {
+            if (dRo.getStatus() == EntityROStatus.NEW.getStatusNumber()) {
+                addNewServiceGroup(dRo);
+            } else if (dRo.getStatus() == EntityROStatus.UPDATED.getStatusNumber()) {
+                updateServiceGroup(dRo);
+            } else if (dRo.getStatus() == EntityROStatus.REMOVE.getStatusNumber()) {
+                DBServiceGroup upd = getDatabaseDao().find(dRo.getId());
+                serviceGroupDao.removeServiceGroup(upd);
+            }
+        }
+    }
+
+    /**
+     * Method validates and converts UI resource object entity to database entity and persists it to database
+     *
+     * @param serviceGroupRO
+     */
+    private void addNewServiceGroup(ServiceGroupRO serviceGroupRO) {
+        // normalize indentifiers
+        normalizeIdentifiers(serviceGroupRO);
+
+        DBServiceGroup dbServiceGroup = new DBServiceGroup();
+        dbServiceGroup.setParticipantIdentifier(serviceGroupRO.getParticipantIdentifier());
+        dbServiceGroup.setParticipantScheme(serviceGroupRO.getParticipantScheme());
+
+        // add users
+        updateUsersOnServiceGroup(serviceGroupRO, dbServiceGroup);
+
+        // first update domains
+        // validate (if domains are added only once) and  create domain list for service group.
+        createDomainsForNewServiceGroup(serviceGroupRO, dbServiceGroup);
+
+
+        // sort service metadata by domain
+        List<ServiceMetadataRO> serviceMetadataROList = serviceGroupRO.getServiceMetadata();
+        serviceMetadataROList.forEach(serviceMetadataRO -> {
+            // find the domain
+            Optional<DBServiceGroupDomain> dbServiceGroupDomain = dbServiceGroup.getServiceGroupForDomain(serviceMetadataRO.getDomainCode());
+            if (dbServiceGroupDomain.isPresent()) {
+                dbServiceGroupDomain.get().addServiceMetadata(createServiceMetadataFromRo(serviceMetadataRO));
+            } else {
+                throw new SMPRuntimeException(SG_NOT_REGISTRED_FOR_DOMAIN, serviceMetadataRO.getDomainCode(),
+                        serviceGroupRO.getParticipantIdentifier(), serviceGroupRO.getParticipantScheme());
+            }
+        });
+
+        // add extension
+        if (serviceGroupRO.getExtension() != null) {
+            byte[] buff = validateExtension(serviceGroupRO);
+            dbServiceGroup.setExtension(buff);
+        }
+        getDatabaseDao().persistFlushDetach(dbServiceGroup);
+    }
+
+    private void normalizeIdentifiers(ServiceGroupRO sgo){
+        ParticipantIdentifierType pti = caseSensitivityNormalizer.normalizeParticipant(sgo.getParticipantScheme()+"::"+sgo.getParticipantIdentifier());
+        sgo.setParticipantScheme(pti.getScheme());
+        sgo.setParticipantIdentifier(pti.getValue());
+        sgo.getServiceMetadata().forEach(smd->{
+            DocumentIdentifier dit = caseSensitivityNormalizer.normalizeDocumentIdentifier(smd.getDocumentIdentifierScheme(), smd.getDocumentIdentifier());
+            smd.setDocumentIdentifierScheme(dit.getScheme());
+            smd.setDocumentIdentifier(dit.getValue());
+
+        });
+
+    }
+
+    /**
+     * Validate (if domains are added only once) and  create domain list for service group.
+     *
+     * @param serviceGroupRO
+     * @param dbServiceGroup
+     */
+    protected void createDomainsForNewServiceGroup(ServiceGroupRO serviceGroupRO, DBServiceGroup dbServiceGroup) {
+        // first update domains
+        List<ServiceGroupDomainRO> serviceGroupDomainROList = validateDomainList(serviceGroupRO);
+        // validate (if domains are added only once) and  create domain list for service group.
+        serviceGroupDomainROList.forEach(dro -> {
+            // everting ok  find domain and add it to service group
+            Optional<DBDomain> dmn = domainDao.getDomainByCode(dro.getDomainCode());
+            if (dmn.isPresent()) {
+                dbServiceGroup.addDomain(dmn.get());
+            } else {
+                throw new SMPRuntimeException(DOMAIN_NOT_EXISTS, dro.getDomainCode());
+            }
+        });
+    }
+
+
+    /**
+     * Method converts UI resource object entity to database entity and update changes  to database
+     *
+     * @param serviceGroupRO
+     */
+    protected void updateServiceGroup(ServiceGroupRO serviceGroupRO) {
+        // normalize indentifiers
+        normalizeIdentifiers(serviceGroupRO);
+        // find and validate service group
+        DBServiceGroup dbServiceGroup = findAndValidateServiceGroup(serviceGroupRO);
+
+        // update users
+        updateUsersOnServiceGroup(serviceGroupRO, dbServiceGroup);
+
+        // update domain
+        updateDomainsForServiceGroup(serviceGroupRO, dbServiceGroup);
+
+        //update service metadata
+        List<ServiceMetadataRO> serviceMetadataROList = serviceGroupRO.getServiceMetadata();
+        serviceMetadataROList.forEach(serviceMetadataRO -> {
+
+            Optional<DBServiceGroupDomain> optionalDbServiceGroupDomain =
+                    dbServiceGroup.findServiceGroupDomainForMetadata(serviceMetadataRO.getDocumentIdentifier(),serviceMetadataRO.getDocumentIdentifierScheme() );
+            // remove service metadata
+            if (serviceMetadataRO.getStatus() == EntityROStatus.REMOVE.getStatusNumber()) {
+                // if the domain was not removed then remove only metadata
+                if (optionalDbServiceGroupDomain.isPresent()) {
+                    DBServiceGroupDomain dbServiceGroupDomain = optionalDbServiceGroupDomain.get();
+                    // remove from domain
+                    dbServiceGroupDomain.removeServiceMetadata(serviceMetadataRO.getDocumentIdentifier(),
+                            serviceMetadataRO.getDocumentIdentifierScheme());
+                }
+
+            } else if (serviceMetadataRO.getStatus() == EntityROStatus.NEW.getStatusNumber()) {
+                // add to new service group.. find servicegroup domain by code
+                optionalDbServiceGroupDomain = dbServiceGroup.getServiceGroupForDomain(serviceMetadataRO.getDomainCode());
+                if (optionalDbServiceGroupDomain.isPresent()) {
+                    optionalDbServiceGroupDomain.get().addServiceMetadata(createServiceMetadataFromRo(serviceMetadataRO));
+                } else {
+                    throw new SMPRuntimeException(SG_NOT_REGISTRED_FOR_DOMAIN, serviceMetadataRO.getDomainCode(),
+                            serviceGroupRO.getParticipantIdentifier(), serviceGroupRO.getParticipantScheme());
+                }
+            } else if (serviceMetadataRO.getStatus() == EntityROStatus.UPDATED.getStatusNumber()) {
+                if (optionalDbServiceGroupDomain.isPresent()) {
+
+                    DBServiceGroupDomain dbServiceGroupDomain = optionalDbServiceGroupDomain.get();
+                    if (serviceMetadataRO.getXmlContentStatus() == EntityROStatus.UPDATED.getStatusNumber()) {
+                        // get service metadata
+                        byte[] buff = validateServiceMetadata(serviceMetadataRO);
+
+                        DBServiceMetadata dbServiceMetadata = dbServiceGroupDomain.getServiceMetadata(serviceMetadataRO.getDocumentIdentifier(),
+                                serviceMetadataRO.getDocumentIdentifierScheme());
+                        dbServiceMetadata.setXmlContent(buff);
+                    }
+
+                    if (!Objects.equals(serviceMetadataRO.getDomainCode(), dbServiceGroupDomain.getDomain().getDomainCode())) {
+                       // remove from old doman
+                        DBServiceMetadata smd = dbServiceGroupDomain.removeServiceMetadata(serviceMetadataRO.getDocumentIdentifier(),
+                                serviceMetadataRO.getDocumentIdentifierScheme());
+                        // find new domain and add
+                        Optional<DBServiceGroupDomain> optNewDomain = dbServiceGroup.getServiceGroupForDomain(serviceMetadataRO.getDomainCode());
+                        if(optNewDomain.isPresent()) {
+                            optNewDomain.get().addServiceMetadata(smd);
+                        } else {
+                            throw new SMPRuntimeException(SG_NOT_REGISTRED_FOR_DOMAIN, serviceMetadataRO.getDomainCode(),
+                                    serviceGroupRO.getParticipantIdentifier(), serviceGroupRO.getParticipantScheme());
+                        }
+                    }
+                } else {
+                    throw new SMPRuntimeException(SG_NOT_REGISTRED_FOR_DOMAIN, serviceMetadataRO.getDomainCode(),
+                            serviceGroupRO.getParticipantIdentifier(), serviceGroupRO.getParticipantScheme());
+                }
+            }
+
+        });
+
+        //
+        // add extension
+        if (serviceGroupRO.getExtensionStatus() != EntityROStatus.PERSISTED.getStatusNumber()) {
+            byte[] buff = validateExtension(serviceGroupRO);
+            dbServiceGroup.setExtension(buff);
+        }
+
+
+        // persist it to databse
+        getDatabaseDao().update(dbServiceGroup);
+    }
+
+    /**
+     * Validate (if domains are added only once) and  update domain list for service group.
+     *
+     * @param serviceGroupRO
+     * @param dbServiceGroup
+     */
+    protected void updateDomainsForServiceGroup(ServiceGroupRO serviceGroupRO, DBServiceGroup dbServiceGroup) {
+        // / validate (if domains are added only once) and  create domain list for service group.
+        List<ServiceGroupDomainRO> serviceGroupDomainROList = validateDomainList(serviceGroupRO);
+        // copy array list of old domains and then put them back. Domain not added back will be deleted by hibernate
+        // ...
+        List<DBServiceGroupDomain> lstOldSGDomains = new ArrayList<>();
+        lstOldSGDomains.addAll(dbServiceGroup.getServiceGroupDomains());
+        dbServiceGroup.getServiceGroupDomains().clear();
+
+
+        serviceGroupDomainROList.forEach(serviceGroupDomainRO -> {
+            DBServiceGroupDomain dsg = getSGDomainFromList(lstOldSGDomains, serviceGroupDomainRO);
+            if (dsg != null) {
+                // put it back - no need to call addDomain
+                dbServiceGroup.getServiceGroupDomains().add(dsg);
+                // remove from list
+                lstOldSGDomains.remove(dsg);
+            } else {
+                // everting ok  find domain and add it to service group
+                Optional<DBDomain> dmn = domainDao.getDomainByCode(serviceGroupDomainRO.getDomainCode());
+                if (dmn.isPresent()) {
+                    dbServiceGroup.addDomain(dmn.get());
+                } else {
+                    throw new SMPRuntimeException(DOMAIN_NOT_EXISTS, serviceGroupDomainRO.getDomainCode());
+                }
+            }
+        });
+        // remove references
+        lstOldSGDomains.forEach(dbServiceGroupDomain -> {
+            dbServiceGroupDomain.setServiceGroup(null);
+        });
+    }
+
+    /**
+     * Method validates if domain list in consistent - code and sml subdomain are used only oncet
+     *
+     * @param serviceGroupRO
+     * @return
+     */
+    protected List<ServiceGroupDomainRO> validateDomainList(ServiceGroupRO serviceGroupRO) {
+        List<ServiceGroupDomainRO> serviceGroupDomainROList = serviceGroupRO.getServiceGroupDomains();
+        // validate (if domains are added only once) and  create domain list for service group.
+        serviceGroupDomainROList.forEach(dro -> {
+            List<ServiceGroupDomainRO> result = serviceGroupDomainROList.stream()
+                    .filter(domainToAdd -> Objects.equals(domainToAdd.getDomainCode(), dro.getDomainCode())
+                            || Objects.equals(domainToAdd.getSmlSubdomain(), dro.getSmlSubdomain()))
+                    .collect(Collectors.toList());
+            if (result.size() != 1) {
+                throw new SMPRuntimeException(DUPLICATE_DOMAIN_FOR_SG, serviceGroupRO.getParticipantIdentifier(),
+                        serviceGroupRO.getParticipantScheme(), dro.getDomainCode(), dro.getSmlSubdomain());
+            }
+        });
+        return serviceGroupDomainROList;
+    }
+
+    /**
+     * Update users on service group. Method is OK for update and add new domain
+     *
+     * @param serviceGroupRO
+     * @param dbServiceGroup
+     */
+    protected void updateUsersOnServiceGroup(ServiceGroupRO serviceGroupRO, DBServiceGroup dbServiceGroup) {
+        // update users
+        dbServiceGroup.getUsers().clear();
+        List<UserRO> lstUsers = serviceGroupRO.getUsers();
+        for (UserRO userRO : lstUsers) {
+            DBUser du = userDao.find(userRO.getId());
+            dbServiceGroup.getUsers().add(du);
+        }
+    }
+
+    /**
+     * Method retrieve servicegroup data from database and validates id and participant
+     *
+     * @param serviceGroupRO
+     * @return
+     */
+    private DBServiceGroup findAndValidateServiceGroup(ServiceGroupRO serviceGroupRO) {
+        // find and validate service group
+        if (serviceGroupRO.getId() == null) {
+            throw new SMPRuntimeException(MISSING_SG_ID, serviceGroupRO.getParticipantIdentifier(), serviceGroupRO.getParticipantScheme());
+        }
+        // validate service group id
+        DBServiceGroup dbServiceGroup = getDatabaseDao().find(serviceGroupRO.getId());
+        if (!Objects.equals(serviceGroupRO.getParticipantIdentifier(), dbServiceGroup.getParticipantIdentifier())
+                || !Objects.equals(serviceGroupRO.getParticipantScheme(), dbServiceGroup.getParticipantScheme())) {
+            throw new SMPRuntimeException(INVALID_SG_ID, serviceGroupRO.getParticipantIdentifier(),
+                    serviceGroupRO.getParticipantScheme(), serviceGroupRO.getId());
+        }
+        return dbServiceGroup;
+    }
+
+    /**
+     * Check if service metadata parsers and if data match servicemetadata and service group...
+     *
+     * @param serviceMetadataRO
+     * @return
+     */
+    private byte[] validateServiceMetadata(ServiceMetadataRO serviceMetadataRO) {
+        byte[] buff;
+
+        try {
+            buff = serviceMetadataRO.getXmlContent().getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            throw new SMPRuntimeException(INVALID_ENCODING, "UTF-8");
+        }
+        ServiceMetadata smd = ServiceMetadataConverter.unmarshal(buff);
+        DocumentIdentifier di = caseSensitivityNormalizer.normalize(smd.getServiceInformation().getDocumentIdentifier());
+        if (Objects.equals(di.getScheme(), serviceMetadataRO.getDocumentIdentifierScheme())
+                && Objects.equals(di.getValue(), serviceMetadataRO.getDocumentIdentifier()))
+        {
+            return buff;
+        } else {
+            throw new SMPRuntimeException(IVALID_SMD_DOCUMENT_DATA, di.getValue(), di.getScheme(),
+                    serviceMetadataRO.getDocumentIdentifier(), serviceMetadataRO.getDocumentIdentifierScheme());
+        }
+    }
+
+
+    /**
+     * Convert Database object to Rest object for UI. It does not set blobs - extensions and metadataservice xml!
+     * They are retrieved to UI when needed.
+     *
+     * @param dbServiceGroup - database  entity
+     * @return ServiceGroupRO
+     */
+    public ServiceGroupRO convertToRo(DBServiceGroup dbServiceGroup) {
         ServiceGroupRO serviceGroupRo = new ServiceGroupRO();
         serviceGroupRo.setId(dbServiceGroup.getId());
         serviceGroupRo.setParticipantIdentifier(dbServiceGroup.getParticipantIdentifier());
         serviceGroupRo.setParticipantScheme(dbServiceGroup.getParticipantScheme());
-        // add service groups
+        // add domains
         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);
-            });
+            ServiceGroupDomainRO servGrpDomain = new ServiceGroupDomainRO();
+            servGrpDomain.setId(sgd.getId());
+            servGrpDomain.setDomainId(sgd.getDomain().getId());
+            servGrpDomain.setDomainCode(sgd.getDomain().getDomainCode());
+            servGrpDomain.setSmlSubdomain(sgd.getDomain().getSmlSubdomain());
+            // add service metadata to service group NOT TO service group domain
+            // little different view from DB Model - all for the users :) ..
+            sgd.getServiceMetadata().stream().map(this::convertServiceMetadataToRo)
+                    .forEach(smdro -> {
+                        smdro.setSmlSubdomain(servGrpDomain.getSmlSubdomain());
+                        smdro.setDomainCode(servGrpDomain.getDomainCode());
+                        smdro.setServiceGroupDomainId(servGrpDomain.getId());
+                        serviceGroupRo.getServiceMetadata().add(smdro);
+                    });
+            //also add domain to service group
+            serviceGroupRo.getServiceGroupDomains().add(servGrpDomain);
         });
         // add users
-        dbServiceGroup.getUsers().forEach(usr->{
+        dbServiceGroup.getUsers().forEach(usr -> {
             UserRO userRO = new UserRO();
             userRO.setId(usr.getId());
             userRO.setUsername(usr.getUsername());
@@ -143,49 +469,138 @@ public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, Service
             userRO.setRole(usr.getRole());
             serviceGroupRo.getUsers().add(userRO);
         });
+        // do not add service extension to gain performance.
         return serviceGroupRo;
     }
 
-    @Transactional
-    public void updateServiceGroupList(List<ServiceGroupRO> lst) {
-        boolean suc = false;
-        for (ServiceGroupRO dRo: lst){
+    /**
+     * Convert database entity to resource object ServiceMetadataRO. To gain UI performance do not copy XM for UI.
+     * It is retrieved when needed!
+     *
+     * @param sgmd
+     * @return
+     */
+    private ServiceMetadataRO convertServiceMetadataToRo(DBServiceMetadata sgmd) {
+        ServiceMetadataRO smdro = new ServiceMetadataRO();
+        smdro.setId(sgmd.getId());
+        smdro.setDocumentIdentifier(sgmd.getDocumentIdentifier());
+        smdro.setDocumentIdentifierScheme(sgmd.getDocumentIdentifierScheme());
+        return smdro;
+    }
 
+    /**
+     * Create new database entity - service metadata from resource object
+     *
+     * @param serviceMetadataRO
+     * @return new database entity DBServiceMetadata
+     */
+    private DBServiceMetadata createServiceMetadataFromRo(ServiceMetadataRO serviceMetadataRO) {
 
-            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);
+        byte[] buff = validateServiceMetadata(serviceMetadataRO);
+        DBServiceMetadata dbServiceMetadata = new DBServiceMetadata();
+        dbServiceMetadata.setDocumentIdentifier(serviceMetadataRO.getDocumentIdentifier());
+        dbServiceMetadata.setDocumentIdentifierScheme(serviceMetadataRO.getDocumentIdentifierScheme());
+        dbServiceMetadata.setXmlContent(buff);
+
+        return dbServiceMetadata;
+    }
 
-                }
-                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);
 
+    /**
+     * for ServiceGroupDomainRO returns DBServiceGroupDomain  from ServiceGroup list of domain. ServiceGroup domain is matched by Id
+     * and verified by domain id.
+     *
+     * @param lstSGDomains
+     * @param domainRo
+     * @return
+     */
+    private DBServiceGroupDomain getSGDomainFromList(List<DBServiceGroupDomain> lstSGDomains, ServiceGroupDomainRO domainRo) {
+        for (DBServiceGroupDomain dbServiceGroupDomain : lstSGDomains) {
+            if (Objects.equals(dbServiceGroupDomain.getId(), domainRo.getId())) {
+                // double check for domain
+                if (!Objects.equals(dbServiceGroupDomain.getDomain().getId(), domainRo.getDomainId())) {
+                    throw new SMPRuntimeException(INVALID_REQEUST, "Domain mismatch!","Domain id for does not match for servicegroup domain");
                 }
-                // 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);
+                return dbServiceGroupDomain;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Validate if extension is valid by schema.
+     *
+     * @param sgExtension
+     * @return
+     */
+    public ServiceGroupExtensionRO validateExtension(ServiceGroupExtensionRO sgExtension) {
+        if (sgExtension == null) {
+            throw new SMPRuntimeException(INVALID_REQEUST, "Validate extension", "Missing Extension parameter");
+        } else if (StringUtils.isBlank(sgExtension.getExtension())) {
+            sgExtension.setErrorMessage("Empty extension");
+        } else {
+            try {
+                byte[] buff = sgExtension.getExtension().getBytes("UTF-8");
+                ExtensionConverter.validateExtensionBySchema(buff); // validate by schema
+                sgExtension.setErrorMessage(null);
+            } catch (XmlInvalidAgainstSchemaException e) {
+                sgExtension.setErrorMessage(ExceptionUtils.getRootCauseMessage(e));
+            } catch (UnsupportedEncodingException e) {
+                sgExtension.setErrorMessage(ExceptionUtils.getRootCauseMessage(e));
+            }
+        }
+        return sgExtension;
+    }
+
+    /**
+     * Validate if extension is valid by schema.
+     *
+     * @param serviceGroupRO
+     * @return
+     */
+    public byte[] validateExtension(ServiceGroupRO serviceGroupRO) {
+        if (StringUtils.isBlank(serviceGroupRO.getExtension())) {
+            return null;
+        }
+        try {
+            byte[] buff = serviceGroupRO.getExtension().getBytes("UTF-8");
+            ExtensionConverter.validateExtensionBySchema(buff); // validate by schema
+            return buff;
+        } catch (UnsupportedEncodingException | XmlInvalidAgainstSchemaException e) {
+            throw new SMPRuntimeException(INVALID_EXTENSION_FOR_SG, serviceGroupRO.getParticipantIdentifier(),
+                    serviceGroupRO.getParticipantScheme(), ExceptionUtils.getRootCauseMessage(e));
+        }
+    }
+
+    /**
+     * TODO format extension - add root element and format...
+     *
+     * @param sgExtension
+     * @return
+     */
+    public ServiceGroupExtensionRO formatExtension(ServiceGroupExtensionRO sgExtension) {
+        if (sgExtension == null) {
+            throw new SMPRuntimeException(INVALID_REQEUST, "Format extension", "Missing Extension parameter");
+        } else if (StringUtils.isBlank(sgExtension.getExtension())) {
+            sgExtension.setErrorMessage("Empty extension");
+        } else {
+            try {
+                Source xmlInput = new StreamSource(new StringReader(sgExtension.getExtension()));
+                StringWriter stringWriter = new StringWriter();
+                StreamResult xmlOutput = new StreamResult(stringWriter);
+                TransformerFactory transformerFactory = TransformerFactory.newInstance();
+                transformerFactory.setAttribute("indent-number", 4);
+                Transformer transformer = transformerFactory.newTransformer();
+                transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+                transformer.transform(xmlInput, xmlOutput);
+                sgExtension.setExtension(xmlOutput.getWriter().toString());
+            } catch (TransformerConfigurationException e) {
+                sgExtension.setErrorMessage(ExceptionUtils.getRootCauseMessage(e));
+            } catch (TransformerException e) {
+                sgExtension.setErrorMessage(ExceptionUtils.getRootCauseMessage(e));
             }
         }
+        return sgExtension;
     }
 
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceMetadataService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceMetadataService.java
index 825cf29cb..2eabaffae 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceMetadataService.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceMetadataService.java
@@ -1,23 +1,19 @@
 package eu.europa.ec.edelivery.smp.services.ui;
 
 import eu.europa.ec.edelivery.smp.conversion.CaseSensitivityNormalizer;
-import eu.europa.ec.edelivery.smp.conversion.ExtensionConverter;
 import eu.europa.ec.edelivery.smp.conversion.ServiceMetadataConverter;
 import eu.europa.ec.edelivery.smp.data.dao.BaseDao;
 import eu.europa.ec.edelivery.smp.data.dao.DomainDao;
-import eu.europa.ec.edelivery.smp.data.dao.ServiceGroupDao;
+import eu.europa.ec.edelivery.smp.data.dao.ServiceMetadataDao;
 import eu.europa.ec.edelivery.smp.data.dao.UserDao;
-import eu.europa.ec.edelivery.smp.data.model.*;
-import eu.europa.ec.edelivery.smp.data.ui.*;
-import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus;
-import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException;
+import eu.europa.ec.edelivery.smp.data.model.DBServiceMetadata;
+import eu.europa.ec.edelivery.smp.data.ui.ServiceMetadataRO;
+import eu.europa.ec.edelivery.smp.data.ui.ServiceMetadataValidationRO;
 import eu.europa.ec.edelivery.smp.logging.SMPLogger;
 import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
-import eu.europa.ec.edelivery.smp.services.ui.filters.ServiceGroupFilter;
 import eu.europa.ec.smp.api.exceptions.XmlInvalidAgainstSchemaException;
-import org.apache.commons.lang3.StringUtils;
+import eu.europa.ec.smp.api.validators.BdxSmpOasisValidator;
 import org.apache.commons.lang3.exception.ExceptionUtils;
-import org.busdox.transport.identifiers._1.DocumentIdentifierType;
 import org.oasis_open.docs.bdxr.ns.smp._2016._05.DocumentIdentifier;
 import org.oasis_open.docs.bdxr.ns.smp._2016._05.ParticipantIdentifierType;
 import org.oasis_open.docs.bdxr.ns.smp._2016._05.ServiceMetadata;
@@ -25,29 +21,18 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import javax.xml.transform.*;
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.stream.StreamSource;
-import java.io.StringReader;
-import java.io.StringWriter;
 import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-import static eu.europa.ec.edelivery.smp.exceptions.ErrorCode.*;
 
 @Service
-public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, ServiceGroupRO> {
-    private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UIServiceGroupService.class);
+public class UIServiceMetadataService extends UIServiceBase<DBServiceMetadata, ServiceMetadataRO> {
+    private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UIServiceMetadataService.class);
 
     @Autowired
     DomainDao domainDao;
 
     @Autowired
-    ServiceGroupDao serviceGroupDao;
+    ServiceMetadataDao serviceMetadataDao;
+
 
     @Autowired
     UserDao userDao;
@@ -57,331 +42,20 @@ public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, Service
 
 
     @Override
-    protected BaseDao<DBServiceGroup> getDatabaseDao() {
-        return serviceGroupDao;
-    }
-
-    /**
-     * Method return list of service group entities with service metadata for given search parameters and page.
-     *
-     * @param page
-     * @param pageSize
-     * @param sortField
-     * @param sortOrder
-     * @param filter
-     * @return
-     */
-    @Transactional
-    public ServiceResult<ServiceGroupRO> getTableList(int page, int pageSize,
-                                                      String sortField,
-                                                      String sortOrder, ServiceGroupFilter filter, String domainCode) {
-
-        DBDomain d = null;
-        if (!StringUtils.isBlank(domainCode)) {
-            Optional<DBDomain> od = domainDao.getDomainByCode(domainCode);
-            if (od.isPresent()) {
-                d = od.get();
-            } else {
-                throw new SMPRuntimeException(DOMAIN_NOT_EXISTS, domainCode);
-            }
-
-        }
-        ServiceResult<ServiceGroupRO> sg = new ServiceResult<>();
-        sg.setPage(page < 0 ? 0 : page);
-        sg.setPageSize(pageSize);
-        long iCnt = serviceGroupDao.getServiceGroupCount(filter, d);
-        sg.setCount(iCnt);
-
-        if (iCnt > 0) {
-            int iStartIndex = pageSize < 0 ? -1 : page * pageSize;
-            List<DBServiceGroup> lst = serviceGroupDao.getServiceGroupList(iStartIndex, pageSize, sortField, sortOrder, filter, d);
-            List<ServiceGroupRO> lstRo = new ArrayList<>();
-            for (DBServiceGroup dbServiceGroup : lst) {
-                ServiceGroupRO serviceGroupRo = convertToRo(dbServiceGroup);
-                serviceGroupRo.setStatus(EntityROStatus.PERSISTED.getStatusNumber());
-                serviceGroupRo.setIndex(iStartIndex++);
-                lstRo.add(serviceGroupRo);
-            }
-            sg.getServiceEntities().addAll(lstRo);
-        }
-        return sg;
+    protected BaseDao<DBServiceMetadata> getDatabaseDao() {
+        return serviceMetadataDao;
     }
 
     @Transactional
-    public ServiceGroupRO getServiceGroupById(Long serviceGroupId) {
-        DBServiceGroup dbServiceGroup = getDatabaseDao().find(serviceGroupId);
-        return convertToRo(dbServiceGroup);
-    }
-
-    @Transactional
-    public ServiceGroupExtensionRO getServiceGroupExtensionById(Long serviceGroupId) {
-        ServiceGroupExtensionRO ex = new ServiceGroupExtensionRO();
-        DBServiceGroup dbServiceGroup = getDatabaseDao().find(serviceGroupId);
-        ex.setServiceGroupId(dbServiceGroup.getId());
-        if (dbServiceGroup.getExtension() != null) {
-            ex.setExtension(new String(dbServiceGroup.getExtension()));
-        }
-        return ex;
-    }
-
-    @Transactional
-    public void updateServiceGroupList(List<ServiceGroupRO> lst) {
-        boolean suc = false;
-        for (ServiceGroupRO dRo : lst) {
-            if (dRo.getStatus() == EntityROStatus.NEW.getStatusNumber()) {
-                addNewServiceGroup(dRo);
-            } else if (dRo.getStatus() == EntityROStatus.UPDATED.getStatusNumber()) {
-                updateServiceGroup(dRo);
-            } else if (dRo.getStatus() == EntityROStatus.REMOVE.getStatusNumber()) {
-                DBServiceGroup upd = getDatabaseDao().find(dRo.getId());
-                serviceGroupDao.removeServiceGroup(upd);
-            }
-        }
-    }
-
-    /**
-     * Method validates and converts UI resource object entity to database entity and persists it to database
-     *
-     * @param serviceGroupRO
-     */
-    private void addNewServiceGroup(ServiceGroupRO serviceGroupRO) {
-        // normalize indentifiers
-        normalizeIdentifiers(serviceGroupRO);
-
-        DBServiceGroup dbServiceGroup = new DBServiceGroup();
-        dbServiceGroup.setParticipantIdentifier(serviceGroupRO.getParticipantIdentifier());
-        dbServiceGroup.setParticipantScheme(serviceGroupRO.getParticipantScheme());
-
-        // add users
-        updateUsersOnServiceGroup(serviceGroupRO, dbServiceGroup);
-
-        // first update domains
-        // validate (if domains are added only once) and  create domain list for service group.
-        createDomainsForNewServiceGroup(serviceGroupRO, dbServiceGroup);
-
-
-        // sort service metadata by domain
-        List<ServiceMetadataRO> serviceMetadataROList = serviceGroupRO.getServiceMetadata();
-        serviceMetadataROList.forEach(serviceMetadataRO -> {
-            // find the domain
-            Optional<DBServiceGroupDomain> dbServiceGroupDomain = dbServiceGroup.getServiceGroupForDomain(serviceMetadataRO.getDomainCode());
-            if (dbServiceGroupDomain.isPresent()) {
-                dbServiceGroupDomain.get().addServiceMetadata(createServiceMetadataFromRo(serviceMetadataRO));
-            } else {
-                throw new SMPRuntimeException(SG_NOT_REGISTRED_FOR_DOMAIN, serviceMetadataRO.getDomainCode(),
-                        serviceGroupRO.getParticipantIdentifier(), serviceGroupRO.getParticipantScheme());
-            }
-        });
-
-        // add extension
-        if (serviceGroupRO.getExtension() != null) {
-            byte[] buff = validateExtension(serviceGroupRO);
-            dbServiceGroup.setExtension(buff);
-        }
-        getDatabaseDao().persistFlushDetach(dbServiceGroup);
-    }
-
-    private void normalizeIdentifiers(ServiceGroupRO sgo){
-        ParticipantIdentifierType pti = caseSensitivityNormalizer.normalizeParticipant(sgo.getParticipantScheme()+"::"+sgo.getParticipantIdentifier());
-        sgo.setParticipantScheme(pti.getScheme());
-        sgo.setParticipantIdentifier(pti.getValue());
-        sgo.getServiceMetadata().forEach(smd->{
-            DocumentIdentifier dit = caseSensitivityNormalizer.normalizeDocumentIdentifier(smd.getDocumentIdentifierScheme(), smd.getDocumentIdentifier());
-            smd.setDocumentIdentifierScheme(dit.getScheme());
-            smd.setDocumentIdentifier(dit.getValue());
-
-        });
-
-    }
-
-    /**
-     * Validate (if domains are added only once) and  create domain list for service group.
-     *
-     * @param serviceGroupRO
-     * @param dbServiceGroup
-     */
-    protected void createDomainsForNewServiceGroup(ServiceGroupRO serviceGroupRO, DBServiceGroup dbServiceGroup) {
-        // first update domains
-        List<ServiceGroupDomainRO> serviceGroupDomainROList = validateDomainList(serviceGroupRO);
-        // validate (if domains are added only once) and  create domain list for service group.
-        serviceGroupDomainROList.forEach(dro -> {
-            // everting ok  find domain and add it to service group
-            Optional<DBDomain> dmn = domainDao.getDomainByCode(dro.getDomainCode());
-            if (dmn.isPresent()) {
-                dbServiceGroup.addDomain(dmn.get());
-            } else {
-                throw new SMPRuntimeException(DOMAIN_NOT_EXISTS, dro.getDomainCode());
-            }
-        });
-    }
-
-
-    /**
-     * Method converts UI resource object entity to database entity and update changes  to database
-     *
-     * @param serviceGroupRO
-     */
-    protected void updateServiceGroup(ServiceGroupRO serviceGroupRO) {
-        // normalize indentifiers
-        normalizeIdentifiers(serviceGroupRO);
-        // find and validate service group
-        DBServiceGroup dbServiceGroup = findAndValidateServiceGroup(serviceGroupRO);
-
-        // update users
-        updateUsersOnServiceGroup(serviceGroupRO, dbServiceGroup);
-
-        // update domain
-        updateDomainsForServiceGroup(serviceGroupRO, dbServiceGroup);
-
-        //update service metadata
-        List<ServiceMetadataRO> serviceMetadataROList = serviceGroupRO.getServiceMetadata();
-        serviceMetadataROList.forEach(serviceMetadataRO -> {
-            Optional<DBServiceGroupDomain> optionalDbServiceGroupDomain = dbServiceGroup.getServiceGroupForDomain(serviceMetadataRO.getDomainCode());
-            // remove service metadata
-            if (serviceMetadataRO.getStatus() == EntityROStatus.REMOVE.getStatusNumber()) {
-                // if the domain was not removed then remove only metadata
-                if (optionalDbServiceGroupDomain.isPresent()) {
-                    DBServiceGroupDomain dbServiceGroupDomain = optionalDbServiceGroupDomain.get();
-                    // remove from domain
-                    dbServiceGroupDomain.removeServiceMetadata(serviceMetadataRO.getDocumentIdentifier(),
-                            serviceMetadataRO.getDocumentIdentifierScheme());
-                }
-
-            } else if (serviceMetadataRO.getStatus() == EntityROStatus.NEW.getStatusNumber()) {
-                if (optionalDbServiceGroupDomain.isPresent()) {
-                    optionalDbServiceGroupDomain.get().addServiceMetadata(createServiceMetadataFromRo(serviceMetadataRO));
-                } else {
-                    throw new SMPRuntimeException(SG_NOT_REGISTRED_FOR_DOMAIN, serviceMetadataRO.getDomainCode(),
-                            serviceGroupRO.getParticipantIdentifier(), serviceGroupRO.getParticipantScheme());
-                }
-            } else if (serviceMetadataRO.getStatus() == EntityROStatus.UPDATED.getStatusNumber()) {
-                if (optionalDbServiceGroupDomain.isPresent()) {
-                    // get service metadata
-                    byte[] buff = validateServiceMetadata(serviceMetadataRO);
-
-                    DBServiceGroupDomain dbServiceGroupDomain = optionalDbServiceGroupDomain.get();
-                    DBServiceMetadata dbServiceMetadata = dbServiceGroupDomain.getServiceMetadata(serviceMetadataRO.getDocumentIdentifier(),
-                            serviceMetadataRO.getDocumentIdentifierScheme());
-
-
-                    dbServiceMetadata.setXmlContent(buff);
-
-                } else {
-                    throw new SMPRuntimeException(SG_NOT_REGISTRED_FOR_DOMAIN, serviceMetadataRO.getDomainCode(),
-                            serviceGroupRO.getParticipantIdentifier(), serviceGroupRO.getParticipantScheme());
-                }
-            }
-
-        });
-
-        //
-        // add extension
-        if (serviceGroupRO.getExtensionStatus() != EntityROStatus.PERSISTED.getStatusNumber()) {
-            byte[] buff = validateExtension(serviceGroupRO);
-            dbServiceGroup.setExtension(buff);
-        }
-
-
-        // persist it to databse
-        getDatabaseDao().update(dbServiceGroup);
-    }
-
-    /**
-     * Validate (if domains are added only once) and  update domain list for service group.
-     *
-     * @param serviceGroupRO
-     * @param dbServiceGroup
-     */
-    protected void updateDomainsForServiceGroup(ServiceGroupRO serviceGroupRO, DBServiceGroup dbServiceGroup) {
-        // / validate (if domains are added only once) and  create domain list for service group.
-        List<ServiceGroupDomainRO> serviceGroupDomainROList = validateDomainList(serviceGroupRO);
-        // copy array list of old domains and then put them back. Domain not added back will be deleted by hibernate
-        // ...
-        List<DBServiceGroupDomain> lstOldSGDomains = new ArrayList<>();
-        lstOldSGDomains.addAll(dbServiceGroup.getServiceGroupDomains());
-        dbServiceGroup.getServiceGroupDomains().clear();
-
-
-        serviceGroupDomainROList.forEach(serviceGroupDomainRO -> {
-            DBServiceGroupDomain dsg = getSGDomainFromList(lstOldSGDomains, serviceGroupDomainRO);
-            if (dsg != null) {
-                // put it back - no need to call addDomain
-                dbServiceGroup.getServiceGroupDomains().add(dsg);
-                // remove from list
-                lstOldSGDomains.remove(dsg);
-            } else {
-                // everting ok  find domain and add it to service group
-                Optional<DBDomain> dmn = domainDao.getDomainByCode(serviceGroupDomainRO.getDomainCode());
-                if (dmn.isPresent()) {
-                    dbServiceGroup.addDomain(dmn.get());
-                } else {
-                    throw new SMPRuntimeException(DOMAIN_NOT_EXISTS, serviceGroupDomainRO.getDomainCode());
-                }
-            }
-        });
-        // remove references
-        lstOldSGDomains.forEach(dbServiceGroupDomain -> {
-            dbServiceGroupDomain.setServiceGroup(null);
-        });
-    }
+    public ServiceMetadataRO getServiceMetadataXMLById(Long serviceMetadataId) {
+        DBServiceMetadata dbServiceMetadata = serviceMetadataDao.find(serviceMetadataId);
+        ServiceMetadataRO serviceMetadataRO = new ServiceMetadataRO();
 
-    /**
-     * Method validates if domain list in consistent - code and sml subdomain are used only oncet
-     *
-     * @param serviceGroupRO
-     * @return
-     */
-    protected List<ServiceGroupDomainRO> validateDomainList(ServiceGroupRO serviceGroupRO) {
-        List<ServiceGroupDomainRO> serviceGroupDomainROList = serviceGroupRO.getServiceGroupDomains();
-        // validate (if domains are added only once) and  create domain list for service group.
-        serviceGroupDomainROList.forEach(dro -> {
-            List<ServiceGroupDomainRO> result = serviceGroupDomainROList.stream()
-                    .filter(domainToAdd -> Objects.equals(domainToAdd.getDomainCode(), dro.getDomainCode())
-                            || Objects.equals(domainToAdd.getSmlSubdomain(), dro.getSmlSubdomain()))
-                    .collect(Collectors.toList());
-            if (result.size() != 1) {
-                throw new SMPRuntimeException(DUPLICATE_DOMAIN_FOR_SG, serviceGroupRO.getParticipantIdentifier(),
-                        serviceGroupRO.getParticipantScheme(), dro.getDomainCode(), dro.getSmlSubdomain());
-            }
-        });
-        return serviceGroupDomainROList;
-    }
-
-    /**
-     * Update users on service group. Method is OK for update and add new domain
-     *
-     * @param serviceGroupRO
-     * @param dbServiceGroup
-     */
-    protected void updateUsersOnServiceGroup(ServiceGroupRO serviceGroupRO, DBServiceGroup dbServiceGroup) {
-        // update users
-        dbServiceGroup.getUsers().clear();
-        List<UserRO> lstUsers = serviceGroupRO.getUsers();
-        for (UserRO userRO : lstUsers) {
-            DBUser du = userDao.find(userRO.getId());
-            dbServiceGroup.getUsers().add(du);
-        }
-    }
-
-    /**
-     * Method retrieve servicegroup data from database and validates id and participant
-     *
-     * @param serviceGroupRO
-     * @return
-     */
-    private DBServiceGroup findAndValidateServiceGroup(ServiceGroupRO serviceGroupRO) {
-        // find and validate service group
-        if (serviceGroupRO.getId() == null) {
-            throw new SMPRuntimeException(MISSING_SG_ID, serviceGroupRO.getParticipantIdentifier(), serviceGroupRO.getParticipantScheme());
-        }
-        // validate service group id
-        DBServiceGroup dbServiceGroup = getDatabaseDao().find(serviceGroupRO.getId());
-        if (!Objects.equals(serviceGroupRO.getParticipantIdentifier(), dbServiceGroup.getParticipantIdentifier())
-                || !Objects.equals(serviceGroupRO.getParticipantScheme(), dbServiceGroup.getParticipantScheme())) {
-            throw new SMPRuntimeException(INVALID_SG_ID, serviceGroupRO.getParticipantIdentifier(),
-                    serviceGroupRO.getParticipantScheme(), serviceGroupRO.getId());
-        }
-        return dbServiceGroup;
+        serviceMetadataRO.setId(dbServiceMetadata.getId());
+        serviceMetadataRO.setDocumentIdentifier(dbServiceMetadata.getDocumentIdentifier());
+        serviceMetadataRO.setDocumentIdentifierScheme(dbServiceMetadata.getDocumentIdentifierScheme());
+        serviceMetadataRO.setXmlContent(new String(dbServiceMetadata.getXmlContent()));
+        return serviceMetadataRO;
     }
 
     /**
@@ -390,206 +64,49 @@ public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, Service
      * @param serviceMetadataRO
      * @return
      */
-    private byte[] validateServiceMetadata(ServiceMetadataRO serviceMetadataRO) {
+
+    public ServiceMetadataValidationRO validateServiceMetadata(ServiceMetadataValidationRO serviceMetadataRO) {
         byte[] buff;
 
+        // convert to utf-8 byte array
         try {
             buff = serviceMetadataRO.getXmlContent().getBytes("UTF-8");
+            serviceMetadataRO.setXmlContent(""); // no need to return back schema
         } catch (UnsupportedEncodingException e) {
-            throw new SMPRuntimeException(INVALID_ENCODING, "UTF-8");
-        }
-        ServiceMetadata smd = ServiceMetadataConverter.unmarshal(buff);
-        DocumentIdentifier di = caseSensitivityNormalizer.normalize(smd.getServiceInformation().getDocumentIdentifier());
-        if (Objects.equals(di.getScheme(), serviceMetadataRO.getDocumentIdentifierScheme())
-                && Objects.equals(di.getValue(), serviceMetadataRO.getDocumentIdentifier()))
-        {
-            return buff;
-        } else {
-            throw new SMPRuntimeException(IVALID_SMD_DOCUMENT_DATA, di.getValue(), di.getScheme(),
-                    serviceMetadataRO.getDocumentIdentifier(), serviceMetadataRO.getDocumentIdentifierScheme());
+            serviceMetadataRO.setErrorMessage(ExceptionUtils.getRootCauseMessage(e));
+            serviceMetadataRO.setXmlContent(""); // no need to return back schema
+            return serviceMetadataRO;
         }
-    }
-
-
-    /**
-     * Convert Database object to Rest object for UI. It does not set blobs - extensions and metadataservice xml!
-     * They are retrieved to UI when needed.
-     *
-     * @param dbServiceGroup - database  entity
-     * @return ServiceGroupRO
-     */
-    public ServiceGroupRO convertToRo(DBServiceGroup dbServiceGroup) {
-        ServiceGroupRO serviceGroupRo = new ServiceGroupRO();
-        serviceGroupRo.setId(dbServiceGroup.getId());
-        serviceGroupRo.setParticipantIdentifier(dbServiceGroup.getParticipantIdentifier());
-        serviceGroupRo.setParticipantScheme(dbServiceGroup.getParticipantScheme());
-        // add domains
-        dbServiceGroup.getServiceGroupDomains().forEach(sgd -> {
-            ServiceGroupDomainRO servGrpDomain = new ServiceGroupDomainRO();
-            servGrpDomain.setId(sgd.getId());
-            servGrpDomain.setDomainId(sgd.getDomain().getId());
-            servGrpDomain.setDomainCode(sgd.getDomain().getDomainCode());
-            servGrpDomain.setSmlSubdomain(sgd.getDomain().getSmlSubdomain());
-            // add service metadata to service group NOT TO service group domain
-            // little different view from DB Model - all for the users :) ..
-            sgd.getServiceMetadata().stream().map(this::convertServiceMetadataToRo)
-                    .forEach(smdro -> {
-                        smdro.setSmlSubdomain(servGrpDomain.getSmlSubdomain());
-                        smdro.setDomainCode(servGrpDomain.getDomainCode());
-                        smdro.setDomainId(servGrpDomain.getDomainId());
-                        smdro.setServiceGroupDomainId(servGrpDomain.getId());
-                        serviceGroupRo.getServiceMetadata().add(smdro);
-                    });
-            //also add domain to service group
-            serviceGroupRo.getServiceGroupDomains().add(servGrpDomain);
-        });
-        // 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);
-        });
-        // do not add service extension to gain performance.
-        return serviceGroupRo;
-    }
-
-    /**
-     * Convert database entity to resource object ServiceMetadataRO. To gain UI performance do not copy XM for UI.
-     * It is retrieved when needed!
-     *
-     * @param sgmd
-     * @return
-     */
-    private ServiceMetadataRO convertServiceMetadataToRo(DBServiceMetadata sgmd) {
-        ServiceMetadataRO smdro = new ServiceMetadataRO();
-        smdro.setId(sgmd.getId());
-        smdro.setDocumentIdentifier(sgmd.getDocumentIdentifier());
-        smdro.setDocumentIdentifierScheme(sgmd.getDocumentIdentifierScheme());
-        return smdro;
-    }
-
-    /**
-     * Create new database entity - service metadata from resource object
-     *
-     * @param serviceMetadataRO
-     * @return new database entity DBServiceMetadata
-     */
-    private DBServiceMetadata createServiceMetadataFromRo(ServiceMetadataRO serviceMetadataRO) {
-
-        byte[] buff = validateServiceMetadata(serviceMetadataRO);
-        DBServiceMetadata dbServiceMetadata = new DBServiceMetadata();
-        dbServiceMetadata.setDocumentIdentifier(serviceMetadataRO.getDocumentIdentifier());
-        dbServiceMetadata.setDocumentIdentifierScheme(serviceMetadataRO.getDocumentIdentifierScheme());
-        dbServiceMetadata.setXmlContent(buff);
 
-        return dbServiceMetadata;
-    }
-
-
-    /**
-     * for ServiceGroupDomainRO returns DBServiceGroupDomain  from ServiceGroup list of domain. ServiceGroup domain is matched by Id
-     * and verified by domain id.
-     *
-     * @param lstSGDomains
-     * @param domainRo
-     * @return
-     */
-    private DBServiceGroupDomain getSGDomainFromList(List<DBServiceGroupDomain> lstSGDomains, ServiceGroupDomainRO domainRo) {
-        for (DBServiceGroupDomain dbServiceGroupDomain : lstSGDomains) {
-            if (Objects.equals(dbServiceGroupDomain.getId(), domainRo.getId())) {
-                // double check for domain
-                if (!Objects.equals(dbServiceGroupDomain.getDomain().getId(), domainRo.getDomainId())) {
-                    throw new SMPRuntimeException(INVALID_REQEUST, "Domain mismatch!","Domain id for does not match for servicegroup domain");
-                }
-                return dbServiceGroupDomain;
-            }
+        // validate by schema
+        try {
+            BdxSmpOasisValidator.validateXSD(buff);
+        } catch (XmlInvalidAgainstSchemaException e) {
+            serviceMetadataRO.setErrorMessage(ExceptionUtils.getRootCauseMessage(e));
+            return serviceMetadataRO;
         }
-        return null;
-    }
 
-    /**
-     * Validate if extension is valid by schema.
-     *
-     * @param sgExtension
-     * @return
-     */
-    public ServiceGroupExtensionRO validateExtension(ServiceGroupExtensionRO sgExtension) {
-        if (sgExtension == null) {
-            throw new SMPRuntimeException(INVALID_REQEUST, "Validate extension", "Missing Extension parameter");
-        } else if (StringUtils.isBlank(sgExtension.getExtension())) {
-            sgExtension.setErrorMessage("Empty extension");
-        } else {
-            try {
-                byte[] buff = sgExtension.getExtension().getBytes("UTF-8");
-                ExtensionConverter.validateExtensionBySchema(buff); // validate by schema
-                sgExtension.setErrorMessage(null);
-            } catch (XmlInvalidAgainstSchemaException e) {
-                sgExtension.setErrorMessage(ExceptionUtils.getRootCauseMessage(e));
-            } catch (UnsupportedEncodingException e) {
-                sgExtension.setErrorMessage(ExceptionUtils.getRootCauseMessage(e));
-            }
-        }
-        return sgExtension;
-    }
+        // validate data
+        ServiceMetadata smd = ServiceMetadataConverter.unmarshal(buff);
+        DocumentIdentifier xmlDI = caseSensitivityNormalizer.normalize(smd.getServiceInformation().getDocumentIdentifier());
+        DocumentIdentifier headerDI = caseSensitivityNormalizer.normalizeDocumentIdentifier(serviceMetadataRO.getDocumentIdentifierScheme(),
+                serviceMetadataRO.getDocumentIdentifier());
+        ParticipantIdentifierType xmlPI = caseSensitivityNormalizer.normalize(smd.getServiceInformation().getParticipantIdentifier());
+        ParticipantIdentifierType headerPI = caseSensitivityNormalizer.normalizeParticipantIdentifier(
+                serviceMetadataRO.getParticipantScheme(),
+                serviceMetadataRO.getParticipantIdentifier());
 
-    /**
-     * Validate if extension is valid by schema.
-     *
-     * @param serviceGroupRO
-     * @return
-     */
-    public byte[] validateExtension(ServiceGroupRO serviceGroupRO) {
-        if (StringUtils.isBlank(serviceGroupRO.getExtension())) {
-            return null;
-        }
-        try {
-            byte[] buff = serviceGroupRO.getExtension().getBytes("UTF-8");
-            ExtensionConverter.validateExtensionBySchema(buff); // validate by schema
-            return buff;
-        } catch (UnsupportedEncodingException | XmlInvalidAgainstSchemaException e) {
-            throw new SMPRuntimeException(INVALID_EXTENSION_FOR_SG, serviceGroupRO.getParticipantIdentifier(),
-                    serviceGroupRO.getParticipantScheme(), ExceptionUtils.getRootCauseMessage(e));
+        if (!xmlDI.equals(headerDI)) {
+            serviceMetadataRO.setErrorMessage("Document identifier and schema does not match!");
+            return serviceMetadataRO;
         }
-    }
 
-    /**
-     * TODO format extension - add root element and format...
-     *
-     * @param sgExtension
-     * @return
-     */
-    public ServiceGroupExtensionRO formatExtension(ServiceGroupExtensionRO sgExtension) {
-        if (sgExtension == null) {
-            throw new SMPRuntimeException(INVALID_REQEUST, "Format extension", "Missing Extension parameter");
-        } else if (StringUtils.isBlank(sgExtension.getExtension())) {
-            sgExtension.setErrorMessage("Empty extension");
-        } else {
-            try {
-                Source xmlInput = new StreamSource(new StringReader(sgExtension.getExtension()));
-                StringWriter stringWriter = new StringWriter();
-                StreamResult xmlOutput = new StreamResult(stringWriter);
-                TransformerFactory transformerFactory = TransformerFactory.newInstance();
-                transformerFactory.setAttribute("indent-number", 4);
-                Transformer transformer = transformerFactory.newTransformer();
-                transformer.setOutputProperty(OutputKeys.INDENT, "yes");
-                transformer.transform(xmlInput, xmlOutput);
-                sgExtension.setExtension(xmlOutput.getWriter().toString());
-            } catch (TransformerConfigurationException e) {
-                sgExtension.setErrorMessage(ExceptionUtils.getRootCauseMessage(e));
-            } catch (TransformerException e) {
-                sgExtension.setErrorMessage(ExceptionUtils.getRootCauseMessage(e));
-            }
+        if (!xmlPI.equals(headerPI)) {
+            serviceMetadataRO.setErrorMessage("Participant identifier and schema does not match!");
+            return serviceMetadataRO;
         }
-        return sgExtension;
-    }
-
-    @Transactional
-    public  ServiceMetadataRO getServiceMetadata(Long serviceMetadataId){
 
+        return serviceMetadataRO;
     }
 
 }
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 bceb3a071..697f3e9f2 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
@@ -10,8 +10,6 @@ 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.exceptions.ErrorCode;
-import eu.europa.ec.edelivery.smp.exceptions.SMPRuntimeException;
 import eu.europa.ec.edelivery.smp.logging.SMPLogger;
 import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
 import org.apache.commons.beanutils.BeanUtils;
@@ -21,18 +19,18 @@ import org.springframework.security.crypto.bcrypt.BCrypt;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import javax.xml.bind.DatatypeConverter;
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.reflect.InvocationTargetException;
 import java.math.BigInteger;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
+import java.util.Base64;
 import java.util.List;
 
 @Service
@@ -40,6 +38,9 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
 
     private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UIUserService.class);
 
+    private static final byte[] S_PEM_START_TAG= "-----BEGIN CERTIFICATE-----\n".getBytes();
+    private static final byte[] S_PEM_END_TAG= "\n-----END CERTIFICATE-----".getBytes();
+
     @Autowired
     UserDao userDao;
 
@@ -49,21 +50,21 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
     }
 
     /**
-     * Method returns user resource object list for page.
+     * Method returns user resource object list for  UI list page.
      *
      * @param page
      * @param pageSize
      * @param sortField
      * @param sortOrder
      * @param filter
-     * @return
+     * @return ServiceResult wiht list
      */
     @Transactional
     public ServiceResult<UserRO> getTableList(int page, int pageSize,
-                                                 String sortField,
-                                                 String sortOrder, Object filter) {
+                                              String sortField,
+                                              String sortOrder, Object filter) {
 
-        ServiceResult<UserRO> resUsers =  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;
     }
@@ -116,31 +117,65 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
         }
     }
 
-    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 CertificateRO getCertificateData(byte[] buff) throws CertificateException, IOException {
+
+        // get pem encoding -
+        InputStream isCert = createPEMFormat(buff);
+
+        CertificateFactory fact = CertificateFactory.getInstance("X.509");
+        X509Certificate cert = (X509Certificate) fact.generateCertificate(isCert);
+        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()));
+        cro.setEncodedValue(Base64.getMimeEncoder().encodeToString(cert.getEncoded()));
+
+        return cro;
+    }
+
+    public boolean isCertificatePemEncoded(byte[] certData){
+        if (certData!=null && certData.length >S_PEM_START_TAG.length){
+
+            for (int i=0; i<certData.length;i++){
+                if (certData[i] != S_PEM_START_TAG[i]) {
+                    return false;
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Method tests if certificate is in PEM  format. If not it creates pem format else returns original data.
+     * @param certData - certificate data
+     * @return
+     * @throws IOException
+     */
+    public ByteArrayInputStream  createPEMFormat(byte[] certData) throws IOException {
+        ByteArrayInputStream is;
+        if (isCertificatePemEncoded(certData)){
+            is = new ByteArrayInputStream(certData);
+        } else {
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+             bos.write(S_PEM_START_TAG);
+             bos.write(Base64.getMimeEncoder().encode(certData));
+             bos.write(S_PEM_END_TAG);
+            is = new ByteArrayInputStream(bos.toByteArray());
+        }
+        return is;
     }
 
-    public String getCertificateIdFromCertificate(String subject, String issuer, BigInteger serial ){
+    public String getCertificateIdFromCertificate(String subject, String issuer, BigInteger serial) {
         return new PreAuthenticatedCertificatePrincipal(subject, issuer, serial).getName();
     }
 
@@ -150,15 +185,15 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
             UserRO dro = new UserRO();
             BeanUtils.copyProperties(dro, d);
 
-            if (d.getCertificate()!=null) {
+            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 );
+        } 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);
         }
     }
@@ -169,16 +204,16 @@ public class UIUserService extends UIServiceBase<DBUser, UserRO> {
             DBUser dro = new DBUser();
             BeanUtils.copyProperties(dro, d);
             DBCertificate cert = new DBCertificate();
-            if (d.getCertificateData()!=null) {
+            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 );
+        } 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/conversion/ExtensionConverterTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/conversion/ExtensionConverterTest.java
index 5487b68d6..e3c1b5fb2 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/conversion/ExtensionConverterTest.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/conversion/ExtensionConverterTest.java
@@ -27,7 +27,8 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
 
 /**
  * Created by migueti on 13/02/2017.
@@ -36,7 +37,7 @@ public class ExtensionConverterTest {
 
     private static final String WRAPPED_FORMAT = "<ExtensionsWrapper xmlns=\"http://docs.oasis-open.org/bdxr/ns/SMP/2016/05\">%s</ExtensionsWrapper>";
 
-    private static final String RES_PATH = "/examples/extensions/";
+    public static final String RES_PATH = "/examples/extensions/";
 
     private static final String UTF8_SEQUENCE = "ẞßÄäËëÏïÖöÜüẄẅŸÿЁёЇїӜӝ-Zażółć gęślą jaźń-ÆæØøÅå-ÀÆÇßãÿαΩƒ";
 
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceGroupServiceTestService.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceGroupServiceTestService.java
index 52da8a296..aa6d1454e 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceGroupServiceTestService.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceGroupServiceTestService.java
@@ -77,5 +77,4 @@ public class ServiceGroupServiceTestService extends AbstractServiceIntegrationTe
         testInstance.validateOwnership(USER_CERT_3, dbsg.get());
 
     }
-
 }
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceGroupServiceIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceGroupServiceIntegrationTest.java
index 6813cda9c..81f81c39c 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceGroupServiceIntegrationTest.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ui/UIServiceGroupServiceIntegrationTest.java
@@ -1,28 +1,38 @@
 package eu.europa.ec.edelivery.smp.services.ui;
 
 
+import eu.europa.ec.edelivery.smp.data.model.DBDomain;
 import eu.europa.ec.edelivery.smp.data.model.DBServiceGroup;
+import eu.europa.ec.edelivery.smp.data.model.DBServiceMetadata;
+import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupExtensionRO;
 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.enums.EntityROStatus;
 import eu.europa.ec.edelivery.smp.services.AbstractServiceIntegrationTest;
 import eu.europa.ec.edelivery.smp.testutil.TestConstants;
 import eu.europa.ec.edelivery.smp.testutil.TestDBUtils;
+import eu.europa.ec.edelivery.smp.testutil.TestROUtils;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.test.context.ContextConfiguration;
 
+import java.io.IOException;
+import java.util.Collections;
+
+import static org.hamcrest.core.StringContains.containsString;
 import static org.junit.Assert.*;
 
 
 /**
- *  Purpose of class is to test ServiceGroupService base methods
+ * Purpose of class is to test ServiceGroupService base methods
  *
  * @author Joze Rihtarsic
  * @since 4.1
  */
-@ContextConfiguration(classes= UIServiceGroupService.class)
+@ContextConfiguration(classes = {UIServiceGroupService.class, UIServiceMetadataService.class})
 public class UIServiceGroupServiceIntegrationTest extends AbstractServiceIntegrationTest {
     @Rule
     public ExpectedException expectedExeption = ExpectedException.none();
@@ -30,20 +40,29 @@ public class UIServiceGroupServiceIntegrationTest extends AbstractServiceIntegra
     @Autowired
     protected UIServiceGroupService testInstance;
 
-    protected void insertDataObjects(int size){
-        for (int i=0; i < size; i++){
-            DBServiceGroup d = TestDBUtils.createDBServiceGroup(String.format("0007:%4d:utest",i),TestConstants.TEST_SG_SCHEMA_1);
-            serviceGroupDao.persistFlushDetach(d);
+    @Autowired
+    protected UIServiceMetadataService uiServiceMetadataService;
+
+    protected void insertDataObjects(int size) {
+        for (int i = 0; i < size; i++) {
+            insertServiceGroup(String.format("%4d", i), true);
         }
     }
 
+    protected DBServiceGroup insertServiceGroup(String id, boolean withExtension) {
+        DBServiceGroup d = TestDBUtils.createDBServiceGroup(String.format("0007:%s:utest", id), TestConstants.TEST_SG_SCHEMA_1, withExtension);
+        serviceGroupDao.persistFlushDetach(d);
+        return d;
+    }
+
+
     @Test
-    public void testGetTableListEmpty(){
+    public void testGetTableListEmpty() {
 
         // given
 
         //when
-        ServiceResult<ServiceGroupRO> res = testInstance.getTableList(-1,-1,null, null,null);
+        ServiceResult<ServiceGroupRO> res = testInstance.getTableList(-1, -1, null, null, null);
         // then
         assertNotNull(res);
         assertEquals(0, res.getCount().intValue());
@@ -54,12 +73,12 @@ public class UIServiceGroupServiceIntegrationTest extends AbstractServiceIntegra
     }
 
     @Test
-    public void testGetTableList15(){
+    public void testGetTableList15() {
 
         // given
         insertDataObjects(15);
         //when
-        ServiceResult<ServiceGroupRO> res = testInstance.getTableList(-1,-1,null, null, null);
+        ServiceResult<ServiceGroupRO> res = testInstance.getTableList(-1, -1, null, null, null);
 
 
         // then
@@ -75,4 +94,236 @@ public class UIServiceGroupServiceIntegrationTest extends AbstractServiceIntegra
         assertNotNull(res.getServiceEntities().get(0).getParticipantIdentifier());
         assertNotNull(res.getServiceEntities().get(0).getParticipantScheme());
     }
+
+    @Test
+    public void testAddServiceWithMetadata() {
+
+        // given
+        DBDomain testDomain01 = TestDBUtils.createDBDomain(TestConstants.TEST_DOMAIN_CODE_1);
+        domainDao.persistFlushDetach(testDomain01);
+
+        ServiceGroupRO sgnew = TestROUtils.createROServiceGroupForDomains(testDomain01);
+        // add service metadata
+        ServiceMetadataRO mtro = TestROUtils.createServiceMetadataDomain(testDomain01, sgnew, TestConstants.TEST_DOC_ID_1, TestConstants.TEST_DOC_SCHEMA_1);
+        sgnew.getServiceMetadata().add(mtro);
+
+        //when
+        testInstance.updateServiceGroupList(Collections.singletonList(sgnew));
+
+        // then
+        ServiceResult<ServiceGroupRO> res = testInstance.getTableList(-1, -1, null, null, null);
+
+        assertNotNull(res);
+        assertEquals(1, res.getCount().intValue());
+        ServiceGroupRO sgAdded = res.getServiceEntities().get(0);
+        ServiceGroupExtensionRO sgExt = testInstance.getServiceGroupExtensionById(sgAdded.getId());
+
+
+        // all table properties should not be null
+        assertNotNull(sgAdded);
+        assertEquals(sgnew.getParticipantIdentifier(), sgAdded.getParticipantIdentifier());
+        assertEquals(sgnew.getParticipantScheme(), sgAdded.getParticipantScheme());
+        assertNull(sgAdded.getExtension()); // with list extension must be empty - extension is retrived by some other call
+        assertEquals(sgnew.getExtension(), sgExt.getExtension());
+        assertEquals(1, sgAdded.getServiceGroupDomains().size());
+        assertEquals(1, sgAdded.getServiceMetadata().size());
+    }
+
+    @Test
+    public void testUpdateServiceGroupExtensionAndServiceMetadaXML() {
+
+        // given
+        DBDomain testDomain01 = TestDBUtils.createDBDomain(TestConstants.TEST_DOMAIN_CODE_1);
+        domainDao.persistFlushDetach(testDomain01);
+        DBServiceGroup dbServiceGroup = TestDBUtils.createDBServiceGroup();
+        dbServiceGroup.addDomain(testDomain01);
+        DBServiceMetadata dbServiceMetadata = TestDBUtils.createDBServiceMetadata(dbServiceGroup.getParticipantIdentifier(), dbServiceGroup.getParticipantScheme());
+        dbServiceGroup.getServiceGroupDomains().get(0).addServiceMetadata(dbServiceMetadata);
+        serviceGroupDao.persistFlushDetach(dbServiceGroup);
+
+        String newMetadataXML = TestROUtils.generateServiceMetadata(dbServiceGroup.getParticipantIdentifier(), dbServiceGroup.getParticipantScheme(),
+                dbServiceMetadata.getDocumentIdentifier(), dbServiceMetadata.getDocumentIdentifierScheme());
+        String newExtension = TestROUtils.generateExtension();
+
+        ServiceResult<ServiceGroupRO> res = testInstance.getTableList(-1, -1, null, null, null);
+        assertEquals(1, res.getCount().intValue());
+        ServiceGroupRO sgChange = res.getServiceEntities().get(0);
+        ServiceMetadataRO smdXML = uiServiceMetadataService.getServiceMetadataXMLById(res.getServiceEntities().get(0).getServiceMetadata().get(0).getId());
+        // test new extension
+        assertNotEquals(newExtension, sgChange.getExtension());
+        assertNotEquals(newMetadataXML, smdXML.getXmlContent());
+        // set new extension
+        sgChange.setStatus(EntityROStatus.UPDATED.getStatusNumber());
+        sgChange.setExtension(newExtension);
+        sgChange.setExtensionStatus(EntityROStatus.UPDATED.getStatusNumber());
+        // set new XMLContent
+        sgChange.getServiceMetadata().get(0).setStatus(EntityROStatus.UPDATED.getStatusNumber());
+        sgChange.getServiceMetadata().get(0).setXmlContentStatus(EntityROStatus.UPDATED.getStatusNumber());
+        sgChange.getServiceMetadata().get(0).setXmlContent(newMetadataXML);
+
+        //when
+        testInstance.updateServiceGroupList(Collections.singletonList(sgChange));
+
+        // then
+        res = testInstance.getTableList(-1, -1, null, null, null);
+
+        assertNotNull(res);
+        assertEquals(1, res.getCount().intValue());
+        ServiceGroupRO sgUpdated = res.getServiceEntities().get(0);
+        ServiceGroupExtensionRO sgExt = testInstance.getServiceGroupExtensionById(sgUpdated.getId());
+        assertEquals(1, sgChange.getServiceMetadata().size());
+        // retrive service metadata xml with special service - it is not retrieve by browsing list
+        ServiceMetadataRO smdXMLNew = uiServiceMetadataService.getServiceMetadataXMLById(sgUpdated.getServiceMetadata().get(0).getId());
+
+        // all table properties should not be null
+        assertNotNull(sgUpdated);
+        assertEquals(sgUpdated.getParticipantIdentifier(), sgUpdated.getParticipantIdentifier());
+        assertEquals(sgUpdated.getParticipantScheme(), sgUpdated.getParticipantScheme());
+        assertEquals(newExtension, sgExt.getExtension());
+        assertEquals(1, sgChange.getServiceGroupDomains().size());
+        assertNotNull(smdXMLNew.getXmlContent());
+        assertEquals(newMetadataXML, smdXMLNew.getXmlContent());
+    }
+
+
+
+    @Test
+    public void testUpdateServiceMatadataChangeDomain() {
+
+        // given
+        DBDomain testDomain01 = TestDBUtils.createDBDomain(TestConstants.TEST_DOMAIN_CODE_1);
+        domainDao.persistFlushDetach(testDomain01);
+        DBDomain testDomain02 = TestDBUtils.createDBDomain(TestConstants.TEST_DOMAIN_CODE_2);
+        domainDao.persistFlushDetach(testDomain02);
+
+        DBServiceGroup dbServiceGroup = TestDBUtils.createDBServiceGroup();
+        dbServiceGroup.addDomain(testDomain01);
+        DBServiceMetadata dbServiceMetadata = TestDBUtils.createDBServiceMetadata(dbServiceGroup.getParticipantIdentifier(), dbServiceGroup.getParticipantScheme());
+        dbServiceGroup.getServiceGroupDomains().get(0).addServiceMetadata(dbServiceMetadata);
+        // add second domain
+        dbServiceGroup.addDomain(testDomain02);
+        serviceGroupDao.persistFlushDetach(dbServiceGroup);
+
+        ServiceResult<ServiceGroupRO> res = testInstance.getTableList(-1, -1, null, null, null);
+
+        assertNotNull(res);
+        assertEquals(1, res.getCount().intValue());
+        ServiceGroupRO sgChanged = res.getServiceEntities().get(0);
+        ServiceMetadataRO smdToChange = sgChanged.getServiceMetadata().get(0);
+        assertEquals(testDomain01.getDomainCode(), smdToChange.getDomainCode());
+        assertEquals(testDomain01.getSmlSubdomain(), smdToChange.getSmlSubdomain());
+
+        // then
+        sgChanged.setStatus(EntityROStatus.UPDATED.getStatusNumber());
+        smdToChange.setStatus(EntityROStatus.UPDATED.getStatusNumber());
+        smdToChange.setDomainCode(testDomain02.getDomainCode());
+        smdToChange.setSmlSubdomain(testDomain02.getSmlSubdomain());
+        testInstance.updateServiceGroupList(Collections.singletonList(sgChanged));
+
+        res = testInstance.getTableList(-1, -1, null, null, null);
+        ServiceGroupRO sgUpdated = res.getServiceEntities().get(0);
+        ServiceMetadataRO smdUpdated = sgUpdated.getServiceMetadata().get(0);
+
+        assertEquals(testDomain02.getDomainCode(), smdUpdated.getDomainCode());
+        assertEquals(testDomain02.getSmlSubdomain(), smdUpdated.getSmlSubdomain());
+
+    }
+
+
+    @Test
+    public void validateExtensionVaild() throws IOException {
+        // given
+        ServiceGroupExtensionRO sg = TestROUtils.getValidExtension();
+
+        // when
+        testInstance.validateExtension(sg);
+
+        // then
+        assertNull(sg.getErrorMessage());
+        assertNotNull(sg.getExtension());
+    }
+
+    @Test
+    public void validateExtensionMultipleVaild() throws IOException {
+        // given
+        ServiceGroupExtensionRO sg = TestROUtils.getValidMultipleExtension();
+
+        // when
+        testInstance.validateExtension(sg);
+
+        // then
+        assertNull(sg.getErrorMessage());
+        assertNotNull(sg.getExtension());
+    }
+
+    @Test
+    public void validateExtensionCustomTextInvaldValid() throws IOException {
+        // given
+        ServiceGroupExtensionRO sg = TestROUtils.getValidCustomText();
+
+        // when
+        testInstance.validateExtension(sg);
+
+        // then
+        assertNotNull(sg.getErrorMessage());
+        assertThat(sg.getErrorMessage(), containsString("Element 'ServiceGroup' cannot have character "));
+        assertNotNull(sg.getExtension());
+    }
+
+    @Test
+    public void validateExtensionInvalid() throws IOException {
+        ServiceGroupExtensionRO sg = TestROUtils.getInvalid();
+
+        // when
+        testInstance.validateExtension(sg);
+
+        // then
+        assertNotNull(sg.getErrorMessage());
+        assertThat(sg.getErrorMessage(), containsString(" Invalid content was found starting with element 'ExtensionID'."));
+        assertNotNull(sg.getExtension());
+    }
+
+    @Test
+    public void validateCustomExtension() throws IOException {
+        ServiceGroupExtensionRO sg = TestROUtils.getCustomExtension();
+
+        // when
+        testInstance.validateExtension(sg);
+
+        // then
+        assertNull(sg.getErrorMessage());
+        assertNotNull(sg.getExtension());
+    }
+
+
+    @Test
+    public void getEmptyExtensionById() throws IOException {
+        DBServiceGroup sg = insertServiceGroup("testExt", false);
+        assertNotNull(sg);
+        assertNotNull(sg.getId());
+        assertNull(sg.getExtension());
+
+        // when
+        ServiceGroupExtensionRO res = testInstance.getServiceGroupExtensionById(sg.getId());
+
+        // then
+        assertNotNull(res);
+        assertNull(res.getExtension());
+    }
+
+    @Test
+    public void getExtensionById() throws IOException {
+        DBServiceGroup sg = insertServiceGroup("testExt", true);
+        assertNotNull(sg);
+        assertNotNull(sg.getId());
+        assertNotNull(sg.getExtension());
+
+        // when
+        ServiceGroupExtensionRO res = testInstance.getServiceGroupExtensionById(sg.getId());
+
+        // then
+        assertNotNull(res);
+        assertNotNull(res.getExtension());
+    }
+
 }
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 62305ae17..a7d9def81 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
@@ -10,8 +10,6 @@ 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;
@@ -19,13 +17,15 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.crypto.bcrypt.BCrypt;
 import org.springframework.test.context.ContextConfiguration;
 
+import java.io.FileInputStream;
 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 java.util.Calendar;
+import java.util.Collections;
+import java.util.Optional;
+import java.util.UUID;
 
 import static org.junit.Assert.*;
 
@@ -252,9 +252,9 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest
     }
 
     @Test
-    public void testGetCertificateData() throws IOException, CertificateException {
+    public void testGetCertificateDataPEM() throws IOException, CertificateException {
         // given
-        byte[] buff = IOUtils.toByteArray(UIUserServiceIntegrationTest.class.getResourceAsStream("/keystores/SMPtest.crt"));
+        byte[] buff = IOUtils.toByteArray(UIUserServiceIntegrationTest.class.getResourceAsStream("/truststore/SMPtest.crt"));
         // when
         CertificateRO cer = testInstance.getCertificateData(buff);
         //then
@@ -265,12 +265,23 @@ public class UIUserServiceIntegrationTest extends AbstractServiceIntegrationTest
         assertNotNull(cer.getValidFrom());
         assertNotNull(cer.getValidTo());
         assertTrue(cer.getValidFrom().isBefore(cer.getValidTo()));
-
-
     }
 
+    @Test
+    public void testGetCertificateDataDER() throws IOException, CertificateException {
+        // given
+        byte[] buff = IOUtils.toByteArray(new FileInputStream("src/test/resources/truststore/NewPeppolAPaa.crt"));
 
-
-
+        // when
+        CertificateRO cer = testInstance.getCertificateData(buff);
+        //then
+        assertEquals("CN=POP000004,O=European Commission,C=BE:474980c51478cf62761667461aef5e8e", cer.getCertificateId());
+        assertEquals("CN=PEPPOL ACCESS POINT TEST CA - G2, OU=FOR TEST ONLY, O=OpenPEPPOL AISBL, C=BE", cer.getIssuer());
+        assertEquals("C=BE, O=European Commission, OU=PEPPOL TEST AP, CN=POP000004", cer.getSubject());
+        assertEquals("474980c51478cf62761667461aef5e8e", cer.getSerialNumber());
+        assertNotNull(cer.getValidFrom());
+        assertNotNull(cer.getValidTo());
+        assertTrue(cer.getValidFrom().isBefore(cer.getValidTo()));
+    }
 
 }
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestDBUtils.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestDBUtils.java
index 357dbf742..347d009ca 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestDBUtils.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestDBUtils.java
@@ -53,10 +53,16 @@ public class TestDBUtils {
     }
 
     public static DBServiceGroup createDBServiceGroup(String id, String sch) {
+        return createDBServiceGroup(id, sch, true);
+    }
+
+    public static DBServiceGroup createDBServiceGroup(String id, String sch, boolean withExtension) {
         DBServiceGroup grp = new DBServiceGroup();
         grp.setParticipantIdentifier(id);
         grp.setParticipantScheme(sch);
-        grp.setExtension(generateExtension());
+        if (withExtension) {
+            grp.setExtension(generateExtension());
+        }
         return grp;
     }
 
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestROUtils.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestROUtils.java
index 357dbf742..2e318c107 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestROUtils.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/TestROUtils.java
@@ -1,146 +1,110 @@
 package eu.europa.ec.edelivery.smp.testutil;
 
-import eu.europa.ec.edelivery.smp.data.model.*;
-
-import java.time.LocalDateTime;
+import eu.europa.ec.edelivery.smp.data.model.DBDomain;
+import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupDomainRO;
+import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupExtensionRO;
+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.enums.EntityROStatus;
+
+import java.io.IOException;
+import java.util.Arrays;
 import java.util.UUID;
 
+import static eu.europa.ec.edelivery.smp.conversion.ExtensionConverterTest.RES_PATH;
 import static eu.europa.ec.edelivery.smp.testutil.TestConstants.SIMPLE_DOCUMENT_XML;
 import static eu.europa.ec.edelivery.smp.testutil.TestConstants.SIMPLE_EXTENSION_XML;
 
-public class TestDBUtils {
-
-    public static DBDomain createDBDomain(String domainCode) {
-        DBDomain domain = new DBDomain();
-        domain.setDomainCode(domainCode);
-        domain.setSignatureKeyAlias(UUID.randomUUID().toString());
-        domain.setSmlClientCertHeader(UUID.randomUUID().toString());
-        domain.setSmlClientKeyAlias(UUID.randomUUID().toString());
-        domain.setSmlSubdomain(UUID.randomUUID().toString());
-        domain.setSmlParticipantIdentifierRegExp(UUID.randomUUID().toString());
-        return domain;
-    }
+public class TestROUtils {
 
 
-    public static DBDomain createDBDomain() {
-        return createDBDomain(TestConstants.TEST_DOMAIN_CODE_1);
+    public static ServiceMetadataRO createServiceMetadataDomain(DBDomain domain, ServiceGroupRO sgo, String docid, String docSch){
+        ServiceMetadataRO sgdmd = new ServiceMetadataRO();
+        sgdmd.setDomainCode(domain.getDomainCode());
+        sgdmd.setSmlSubdomain(domain.getSmlSubdomain());
+        sgdmd.setDocumentIdentifier(docid);
+        sgdmd.setDocumentIdentifierScheme(docSch);
+        sgdmd.setXmlContent(generateServiceMetadata(sgo.getParticipantIdentifier(), sgo.getParticipantScheme(), docid,docSch ));
+        return sgdmd;
     }
 
-    public static DBServiceGroup createDBServiceGroup() {
-        return createDBServiceGroup(TestConstants.TEST_SG_ID_1, TestConstants.TEST_SG_SCHEMA_1);
-    }
+    public static ServiceGroupDomainRO createServiceGroupDomain(DBDomain domain){
 
-    public static DBServiceMetadata createDBServiceMetadata(String partcId, String partcSch) {
-        return createDBServiceMetadata(partcId,partcSch, UUID.randomUUID().toString(), UUID.randomUUID().toString(), UUID.randomUUID().toString()  );
-    }
-    public static DBServiceMetadata createDBServiceMetadata(String partcId, String partcSch, String docId, String docSch ) {
-        return createDBServiceMetadata(partcId,partcSch, docId, docSch, UUID.randomUUID().toString()  );
+        ServiceGroupDomainRO sgd = new ServiceGroupDomainRO();
+        sgd.setDomainId(domain.getId());
+        sgd.setDomainCode(domain.getDomainCode());
+        sgd.setSmlSubdomain(domain.getSmlSubdomain());
+        return sgd;
     }
 
-    public static DBServiceMetadata createDBServiceMetadata(String partcId, String partcSch, String docId, String docSch, String desc) {
-        DBServiceMetadata grp = new DBServiceMetadata();
-        grp.setDocumentIdentifier(docId);
-        grp.setDocumentIdentifierScheme(docSch);
-        grp.setXmlContent(generateDocumentSample(partcSch, partcId,docSch, docId, desc));
-        return grp;
+    public static ServiceGroupRO createROServiceGroup() {
+        return createROServiceGroup(TestConstants.TEST_SG_ID_1, TestConstants.TEST_SG_SCHEMA_1);
     }
 
-    public static  byte[]  generateDocumentSample(String partcId, String partcSch, String docId, String docSch, String desc){
-        return String.format(SIMPLE_DOCUMENT_XML,partcSch, partcId,docSch, docId, desc).getBytes();
+    public static ServiceGroupRO createROServiceGroupForDomains(DBDomain ... domains) {
+        ServiceGroupRO sgo =  createROServiceGroup(TestConstants.TEST_SG_ID_1, TestConstants.TEST_SG_SCHEMA_1);
+        Arrays.asList(domains).forEach(domain -> {
+            ServiceGroupDomainRO sgd = createServiceGroupDomain(domain);
+            sgo.getServiceGroupDomains().add(sgd);
+        });
+        return sgo;
     }
-    public static byte[] generateExtension(){
-        return String.format(SIMPLE_EXTENSION_XML, UUID.randomUUID().toString()).getBytes();
+
+    public static ServiceGroupRO createROServiceGroup(String id, String sch) {
+        return createROServiceGroup(id, sch, true);
     }
 
-    public static DBServiceGroup createDBServiceGroup(String id, String sch) {
-        DBServiceGroup grp = new DBServiceGroup();
+    public static ServiceGroupRO createROServiceGroup(String id, String sch, boolean withExtension) {
+        ServiceGroupRO grp = new ServiceGroupRO();
+        grp.setStatus(EntityROStatus.NEW.getStatusNumber());
         grp.setParticipantIdentifier(id);
         grp.setParticipantScheme(sch);
-        grp.setExtension(generateExtension());
+        if (withExtension) {
+            grp.setExtensionStatus(EntityROStatus.NEW.getStatusNumber());
+            grp.setExtension(generateExtension());
+        }
         return grp;
     }
 
-
-
-    public static DBUser createDBUser(String username1) {
-        return createDBUserByUsername(TestConstants.USERNAME_1);
+    public static String generateExtension(){
+        return String.format(SIMPLE_EXTENSION_XML, UUID.randomUUID().toString());
     }
 
-    public static DBUser createDBUserByUsername(String userName) {
-        DBUser dbuser = new DBUser();
-        dbuser.setUsername(userName);
-        dbuser.setRole("test");
-        dbuser.setEmail("test@test.eu");
-        dbuser.setPasswordChanged(LocalDateTime.now());
-        dbuser.setPassword(UUID.randomUUID().toString());
-        return dbuser;
+    public static String generateServiceMetadata(String partId, String partSch, String docId, String docSch){
+        return String.format(SIMPLE_DOCUMENT_XML, partSch, partId,docSch, docId, UUID.randomUUID().toString()  );
     }
 
-    public static DBCertificate createDBCertificate() {
-        return createDBCertificate(TestConstants.USER_CERT_1);
-    }
-    public static DBCertificate createDBCertificate(String certId) {
-        DBCertificate dbcert = new DBCertificate();
-        dbcert.setCertificateId(certId);
-        dbcert.setValidFrom(LocalDateTime.now());
-        dbcert.setValidTo(LocalDateTime.now());
-        return dbcert;
-    }
-    public static DBUser createDBUserByCertificate(String certId) {
-        DBUser dbuser = new DBUser();
-        dbuser.setRole("test");
-
-        DBCertificate dbcert = new DBCertificate();
-        dbcert.setCertificateId(certId);
-        dbcert.setValidFrom(LocalDateTime.now());
-        dbcert.setValidTo(LocalDateTime.now());
-        dbuser.setCertificate(dbcert);
-        return dbuser;
+    public static ServiceGroupExtensionRO getValidExtension() throws IOException {
+        String inputDoc = XmlTestUtils.loadDocumentAsString(RES_PATH + "extensionValidOne.xml");
+        return getExtensionRO(inputDoc);
     }
 
-    public static DBUser createDBUser(String userName, String certId) {
-        DBUser dbuser =createDBUserByUsername(userName);
-        DBCertificate dbcert =createDBCertificate(certId);
-        dbuser.setCertificate(dbcert);
-        return dbuser;
-    }
-
-
-    /*
-    public static DBOwnership createDBOwnership(){
-        DBServiceGroup grp = createDBServiceGroup();
-
-        DBUser dbuser = createDBUser();
-
-        DBOwnershipId ownID = new DBOwnershipId();
-        ownID.setBusinessIdentifier(grp.getId().getBusinessIdentifier());
-        ownID.setBusinessIdentifierScheme(grp.getId().getBusinessIdentifierScheme());
-        ownID.setUsername(dbuser.getUsername());
 
-        DBOwnership own = new DBOwnership();
-        own.setId(ownID);
-        own.setServiceGroup(grp);
-        own.setUser(dbuser);
-        return own;
+    public static ServiceGroupExtensionRO getValidMultipleExtension() throws IOException {
+        String inputDoc = XmlTestUtils.loadDocumentAsString(RES_PATH + "extensionValidMultiple.xml");
+        return getExtensionRO(inputDoc);
     }
 
-    public static DBServiceMetadata createDBServiceMetadata(){
-        DBServiceGroup grp = createDBServiceGroup();
-
+    public static ServiceGroupExtensionRO getValidCustomText() throws IOException {
+        String inputDoc = XmlTestUtils.loadDocumentAsString(RES_PATH + "extensionCustomText.xml");
+        return getExtensionRO(inputDoc);
+    }
 
-        DBServiceMetadataId smdId = new DBServiceMetadataId();
-        smdId.setBusinessIdentifier(grp.getId().getBusinessIdentifier());
-        smdId.setBusinessIdentifierScheme(grp.getId().getBusinessIdentifierScheme());
-        smdId.setDocumentIdentifier(REVISION_DOCUMENT_ID);
-        smdId.setDocumentIdentifierScheme(REVISION_DOCUMENT_SCH);
+    public static ServiceGroupExtensionRO getInvalid() throws IOException {
+        String inputDoc = XmlTestUtils.loadDocumentAsString(RES_PATH + "extensionInvalid.xml");
+        return getExtensionRO(inputDoc);
+    }
 
-        DBServiceMetadata smd = new DBServiceMetadata();
-        smd.setId(smdId);
-        smd.setServiceGroup(grp);
-        smd.setXmlContent(UUID.randomUUID().toString());
+    public static ServiceGroupExtensionRO getCustomExtension() throws IOException {
+        String inputDoc = XmlTestUtils.loadDocumentAsString(RES_PATH + "extensionCustom.xml");
+        return getExtensionRO(inputDoc);
+    }
 
 
-        return smd;
+    public static ServiceGroupExtensionRO getExtensionRO(String extension) {
+        ServiceGroupExtensionRO sg = new ServiceGroupExtensionRO();
+        sg.setServiceGroupId((long) 1);
+        sg.setExtension(extension);
+        return sg;
     }
-    */
 }
diff --git a/smp-server-library/src/test/resources/examples/extensions/extensionCustom.xml b/smp-server-library/src/test/resources/examples/extensions/extensionCustom.xml
index 08e00ed29..a5038039e 100644
--- a/smp-server-library/src/test/resources/examples/extensions/extensionCustom.xml
+++ b/smp-server-library/src/test/resources/examples/extensions/extensionCustom.xml
@@ -1 +1,3 @@
-Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
\ No newline at end of file
+<Extension xmlns="http://docs.oasis-open.org/bdxr/ns/SMP/2016/05">
+    <ext:example xmlns:ext="http://my.namespace.eu">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</ext:example>
+</Extension>
\ No newline at end of file
diff --git a/smp-server-library/src/test/resources/examples/extensions/extensionInvalid.xml b/smp-server-library/src/test/resources/examples/extensions/extensionInvalid.xml
index a1aafe933..61fe8faf7 100644
--- a/smp-server-library/src/test/resources/examples/extensions/extensionInvalid.xml
+++ b/smp-server-library/src/test/resources/examples/extensions/extensionInvalid.xml
@@ -1,4 +1,5 @@
-<Extension xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns="http://docs.oasis-open.org/bdxr/ns/SMP/2016/05">
+<Extension xmlns="http://docs.oasis-open.org/bdxr/ns/SMP/2016/05">
+    <ExtensionName>name1</ExtensionName>
     <ExtensionID>id1</ExtensionID>
     <ExtensionName>name1</ExtensionName>
     <ExtensionAgencyName>agencyName1</ExtensionAgencyName>
@@ -6,13 +7,5 @@
     <ExtensionVersionID>versionId1</ExtensionVersionID>
     <ExtensionReasonCode>reasonCode1</ExtensionReasonCode>
     <ExtensionReason>reason1</ExtensionReason>
-</Extension>
-<Extension xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns="http://docs.oasis-open.org/bdxr/ns/SMP/2016/05">
-    <ExtensionID>id2</ExtensionID>
-    <ExtensionName>name2</ExtensionName>
-    <ExtensionAgencyName>agencyName2</ExtensionAgencyName>
-    <ExtensionAgencyURI>agencyUri2</ExtensionAgencyURI>
-    <ExtensionVersionID>versionId2</ExtensionVersionID>
-    <ExtensionReasonCode>reasonCode2</ExtensionReasonCode>
-    <ExtensionReason>reason2</ExtensionReason>
+    <ext:example xmlns:ext="http://my.namespace.eu">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</ext:example>
 </Extension>
diff --git a/smp-server-library/src/test/resources/examples/extensions/extensionValidMultiple.xml b/smp-server-library/src/test/resources/examples/extensions/extensionValidMultiple.xml
index a11a10e5e..579531c77 100644
--- a/smp-server-library/src/test/resources/examples/extensions/extensionValidMultiple.xml
+++ b/smp-server-library/src/test/resources/examples/extensions/extensionValidMultiple.xml
@@ -1,4 +1,4 @@
-<Extension xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns="http://docs.oasis-open.org/bdxr/ns/SMP/2016/05">
+<Extension xmlns="http://docs.oasis-open.org/bdxr/ns/SMP/2016/05">
     <ExtensionID>id1</ExtensionID>
     <ExtensionName>name1</ExtensionName>
     <ExtensionAgencyName>agencyName1</ExtensionAgencyName>
@@ -8,3 +8,13 @@
     <ExtensionReason>reason1</ExtensionReason>
     <ext:example xmlns:ext="http://my.namespace.eu">token1</ext:example>
 </Extension>
+<Extension xmlns="http://docs.oasis-open.org/bdxr/ns/SMP/2016/05">
+<ExtensionID>id1</ExtensionID>
+<ExtensionName>name1</ExtensionName>
+<ExtensionAgencyName>agencyName1</ExtensionAgencyName>
+<ExtensionAgencyURI>agencyUri1</ExtensionAgencyURI>
+<ExtensionVersionID>versionId1</ExtensionVersionID>
+<ExtensionReasonCode>reasonCode1</ExtensionReasonCode>
+<ExtensionReason>reason1</ExtensionReason>
+<ext:example xmlns:ext="http://my.namespace.eu">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</ext:example>
+</Extension>
\ No newline at end of file
diff --git a/smp-server-library/src/test/resources/examples/extensions/extensionValidOne.xml b/smp-server-library/src/test/resources/examples/extensions/extensionValidOne.xml
index 7c20d3eb5..3c667f411 100644
--- a/smp-server-library/src/test/resources/examples/extensions/extensionValidOne.xml
+++ b/smp-server-library/src/test/resources/examples/extensions/extensionValidOne.xml
@@ -1 +1,10 @@
-<Extension xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns="http://docs.oasis-open.org/bdxr/ns/SMP/2016/05"><ExtensionID>id1</ExtensionID><ExtensionName>name1</ExtensionName><ExtensionAgencyName>agencyName1</ExtensionAgencyName><ExtensionAgencyURI>agencyUri1</ExtensionAgencyURI><ExtensionVersionID>versionId1</ExtensionVersionID><ExtensionReasonCode>reasonCode1</ExtensionReasonCode><ExtensionReason>reason1</ExtensionReason></Extension>
+<Extension xmlns="http://docs.oasis-open.org/bdxr/ns/SMP/2016/05">
+    <ExtensionID>id1</ExtensionID>
+    <ExtensionName>name1</ExtensionName>
+    <ExtensionAgencyName>agencyName1</ExtensionAgencyName>
+    <ExtensionAgencyURI>agencyUri1</ExtensionAgencyURI>
+    <ExtensionVersionID>versionId1</ExtensionVersionID>
+    <ExtensionReasonCode>reasonCode1</ExtensionReasonCode>
+    <ExtensionReason>reason1</ExtensionReason>
+    <ext:example xmlns:ext="http://my.namespace.eu">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</ext:example>
+</Extension>
diff --git a/smp-server-library/src/test/resources/keystores/SMPtest.crt b/smp-server-library/src/test/resources/keystores/SMPtest.crt
deleted file mode 100644
index f02b16998..000000000
--- a/smp-server-library/src/test/resources/keystores/SMPtest.crt
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDGjCCAgKgAwIBAgIBAzANBgkqhkiG9w0BAQUFADA3MQswCQYDVQQGEwJCRTEO
-MAwGA1UEChMFRElHSVQxGDAWBgNVBAMTD0ludGVybWVkaWF0ZSBDQTAeFw0xODA1
-MjIxODU5MDBaFw0xOTA1MjIxODU2MDBaME0xCzAJBgNVBAYTAkJFMQ4wDAYDVQQK
-EwVESUdJVDERMA8GA1UEAxMIU01QIHRlc3QxGzAZBgkqhkiG9w0BCQEWDHNtcEB0
-ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2GBB4bW5HA
-lPY4z71I36v34xFWz6iv80PFe9dSA4hSH621bC8xjB6tKvgol8/9oSDO8OL2Do+I
-x16Scn7u5iFnV3c64XnsBVtglRcntjJi7RoXje3AfJnxkBOptbBeNaV6UFqsabRa
-3mapZbJ/8Bog7rayCRp27UZEJVK/1lw/f2p8/9iyKInchHYWuC8KtUGxwpjVy6eb
-Zh+TX32U3KU9UDNkbhEkKG0M+aC6BhCo21qnkv1KZ0QO4ol1MDoG7d1seQlJBb9C
-dQOhDN4USc62biqShcZthDwsJpoPIJuGhwEH5tigyUVJ0zv+MzSPvzqpgn7BMvKe
-MPH0/2m1Kv0CAwEAAaMbMBkwCQYDVR0TBAIwADAMBgNVHQ8EBQMDB/mAMA0GCSqG
-SIb3DQEBBQUAA4IBAQAfJkY3mF/1aftAgiQHdSJEm0OwT/Ow1Wv3nlljz5RlR5Wz
-Co3I83TLum6F8bnF0taA0nks3NzYBjInd6DKHhV54lhCga1JydCIMr1DFrGPbLui
-OlnF89y4TWkIkGOWd74alxLv+ioE0PiPDWZjMXxOWcAkYz+Qjo0BkdbEaWglTjLA
-LBWMjpiVV7Pf7wH2R+D6KW4ktKTnO+yM1VihJkaDPMtGxv4nGK7npATg560BR+hJ
-kY53TEz2RhRMedwUz6weNibI4cfRyD1qIElMGOtol55bRNFcby1LfXLz7ljcY+LB
-VXbP7yNUsICtrN+9pWW51TGw8/lkSTeYkzsiQ5as
------END CERTIFICATE-----
diff --git a/smp-server-library/src/test/resources/keystores/TestCase.crt b/smp-server-library/src/test/resources/keystores/TestCase.crt
deleted file mode 100644
index 15520e1eb..000000000
--- a/smp-server-library/src/test/resources/keystores/TestCase.crt
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDGTCCAgGgAwIBAgIBATANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJiZTER
-MA8GA1UEBxMIYnJ1c3NlbHMxDjAMBgNVBAsTBURJR0lUMR4wHAYDVQQDExVUZXNU
-IFVQUEVSIGxvd2VyIENBU0UwHhcNMTgwOTA2MDc1MDAwWhcNMTkwNTIyMTg0OTAw
-WjBQMQswCQYDVQQGEwJiZTERMA8GA1UEBxMIYnJ1c3NlbHMxDjAMBgNVBAsTBURJ
-R0lUMR4wHAYDVQQDExVUZXNUIFVQUEVSIGxvd2VyIENBU0UwggEiMA0GCSqGSIb3
-DQEBAQUAA4IBDwAwggEKAoIBAQDCYHH85zNNJaMuwdPJCCx67O+DNQ0NtpISLdFt
-nLQ6EtGBbjxgoAeg7QTc6GFe3KhP9PdZiczwoTPl0PhmpT/hWinElDO6x0JBefWs
-7lgPUgATceRYYH/ecPF0bl7a8BpQrYlIyPYmjb1aYSrz0SjQMYLaUhhoeFP3UmaU
-CSNUnPqoZ7/DfUYhDPWayoHo0Q+w6QurqNzh8v5dbT19MhbAGv9L3Gx0dh2tviy/
-a3mg8roCtv44jsoKenJ+2Q433d7IgcbCJm8CHetTdtWJ7xYY19MoEqCFLxlo4iSC
-E6WQuxfPrL5MK4+6Dl7vJhp6XiqBKuU35ptrWukgYh+bcIIJAgMBAAEwDQYJKoZI
-hvcNAQEFBQADggEBAJSmevfTz/xSuqSZiSXb17SuGrDLhVbgm3ECdx+e6A/X3TDF
-uZHcPHlascB++aRmCuE+zid93pFxpoHNG7Jr1He7jTp2OlZJU6P3mf9dj0tQ5WE4
-tg3d+r++iv6zABsTxJNU4McizuuhMzLaFzlKOn20CsJol7pFKzwGKGLZ60FTscnT
-6aw/LWbeE0N5ODir456sJ/ySSBEFQqczJXFxCtkjqCPudbXxlMhwNWHqggVizjsE
-GG86ZAY9230H6QNn0GL9jz4jxGIDkSSBvzGn3ehr1bc4eYHazPA7b/yTCQf+QzG6
-RBAuhkzeL3WW+DDEeMxld5Gue54HBjkL6hCrDhw=
------END CERTIFICATE-----
diff --git a/smp-soapui-tests/groovy/mysql-4.1_integration_test_data.sql b/smp-soapui-tests/groovy/mysql-4.1_integration_test_data.sql
index 9f1bcf7ed..fd9b1d4e3 100644
--- a/smp-soapui-tests/groovy/mysql-4.1_integration_test_data.sql
+++ b/smp-soapui-tests/groovy/mysql-4.1_integration_test_data.sql
@@ -42,7 +42,7 @@ update SMP_USER_SEQ set next_val=100 where next_val=1;
 -- insert domain
 insert into SMP_DOMAIN (ID, DOMAIN_CODE, SML_SUBDOMAIN, SIGNATURE_KEY_ALIAS, CREATED_ON, LAST_UPDATED_ON) values (1, 'domain','subdomain','sig-key', NOW(), NOW());
 insert into SMP_DOMAIN (ID, DOMAIN_CODE, SML_SUBDOMAIN, SML_SMP_ID, SIGNATURE_KEY_ALIAS, CREATED_ON, LAST_UPDATED_ON) values (2, 'domainB','subdomain002', 'CEF-SMP-002','sig-key',CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP());
-insert into SMP_DOMAIN (ID, DOMAIN_CODE, SML_SUBDOMAIN, SML_SMP_ID, SIGNATURE_KEY_ALIAS, CREATED_ON, LAST_UPDATED_ON) values (3, 'domainC','subdomain003', 'CEF-SMP-003','sig-key',CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP());
+insert into SMP_DOMAIN (ID, DOMAIN_CODE, SML_SUBDOMAIN, SML_SMP_ID, SIGNATURE_KEY_ALIAS, CREATED_ON, LAST_UPDATED_ON) values (3, 'domainC$$','subdomain003$$', 'CEF$$SMP-003','sig-key',CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP());
 insert into SMP_DOMAIN (ID, DOMAIN_CODE, SML_SUBDOMAIN, SML_SMP_ID, SIGNATURE_KEY_ALIAS, CREATED_ON, LAST_UPDATED_ON) values (4, 'domainD','subdomain004', 'CEF-SMP-004','sig-key',CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP());
 insert into SMP_DOMAIN (ID, DOMAIN_CODE, SML_SUBDOMAIN, SML_SMP_ID, SIGNATURE_KEY_ALIAS, CREATED_ON, LAST_UPDATED_ON) values (5, 'domainE','subdomain005', 'CEF-SMP-005','sig-key',CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP());
 insert into SMP_DOMAIN (ID, DOMAIN_CODE, SML_SUBDOMAIN, SML_SMP_ID, SIGNATURE_KEY_ALIAS, CREATED_ON, LAST_UPDATED_ON) values (6, 'domainF','subdomain006', 'CEF-SMP-006','sig-key',CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP());
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/monitor/MonitorResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/monitor/MonitorResource.java
index 0c17693b9..034ce4626 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/monitor/MonitorResource.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/monitor/MonitorResource.java
@@ -109,7 +109,6 @@ public class MonitorResource {
         newSg.setParticipantScheme(TEST_PART_SCHEMA);
         newSg.setExtension(TEST_EXTENSION_XML.getBytes());
         newSg.addDomain(lstDomain.get(0)); // add initial domain
-        newSg.setSmlRegistered(false);
         // persist (make sure this is not in transaction)
         serviceGroupDao.testPersist(newSg,true, TEST_DB_SUCCESSFUL_ROLLBACK);
         return false;
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 05af6c1b4..99f944777 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
@@ -1,14 +1,12 @@
 package eu.europa.ec.edelivery.smp.ui;
 
 
-import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupRO;
+import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupSearchRO;
 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 eu.europa.ec.edelivery.smp.services.ui.UIServiceGroupSearchService;
 import eu.europa.ec.edelivery.smp.services.ui.filters.ServiceGroupFilter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
@@ -26,7 +24,7 @@ public class SearchResource {
     private static final SMPLogger LOG = SMPLoggerFactory.getLogger(SearchResource.class);
 
     @Autowired
-    private UIServiceGroupService uiServiceGroupService;
+    private UIServiceGroupSearchService uiServiceGroupService;
 
     @PostConstruct
     protected void init() {
@@ -36,7 +34,7 @@ public class SearchResource {
     @PutMapping(produces = {"application/json"})
     @ResponseBody
     @RequestMapping(method = RequestMethod.GET)
-    public  ServiceResult<ServiceGroupRO> getServiceGroupList(
+    public ServiceResult<ServiceGroupSearchRO> getServiceGroupList(
             @RequestParam(value = "page", defaultValue = "0") int page,
             @RequestParam(value = "pageSize", defaultValue = "10") int pageSize,
             @RequestParam(value = "orderBy", required = false) String orderBy,
@@ -44,13 +42,12 @@ public class SearchResource {
             @RequestParam(value = "participantIdentifier", required = false) String participantIdentifier,
             @RequestParam(value = "participantScheme", required = false) String participantScheme,
             @RequestParam(value = "domain", required = false) String domain
-            ) {
+    ) {
 
-        LOG.info("Search for page: {}, page size: {}, part. id: {}, part sch: {}, domain {}",page, pageSize, participantIdentifier, participantScheme, domain );
+        LOG.info("Search for page: {}, page size: {}, part. id: {}, part sch: {}, domain {}", page, pageSize, participantIdentifier, participantScheme, domain);
         ServiceGroupFilter sgf = new ServiceGroupFilter();
         sgf.setParticipantIdentifierLike(participantIdentifier);
         sgf.setParticipantSchemeLike(participantScheme);
-
-        return uiServiceGroupService.getTableList(page,pageSize, orderBy, orderType, sgf, domain);
+        return uiServiceGroupService.getTableList(page, pageSize, orderBy, orderType, sgf, domain);
     }
 }
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 0c7f620e0..8ea5d61da 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,19 +1,17 @@
 package eu.europa.ec.edelivery.smp.ui;
 
 
-import eu.europa.ec.edelivery.smp.data.ui.DomainRO;
+import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupExtensionRO;
 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 eu.europa.ec.edelivery.smp.services.ui.filters.ServiceGroupFilter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
-import javax.annotation .PostConstruct;
+import javax.annotation.PostConstruct;
 import java.util.Arrays;
 
 /**
@@ -43,8 +41,8 @@ public class ServiceGroupResource {
             @RequestParam(value = "pageSize", defaultValue = "10") int pageSize,
             @RequestParam(value = "orderBy", required = false) String orderBy,
             @RequestParam(value = "orderType", defaultValue = "asc", required = false) String orderType,
-            @RequestParam(value = "participantId", required = false) String participantIdentifier,
-            @RequestParam(value = "participantSchema", required = false) String participantScheme,
+            @RequestParam(value = "participantIdentifier", required = false) String participantIdentifier,
+            @RequestParam(value = "participantScheme", required = false) String participantScheme,
             @RequestParam(value = "domain", required = false) String domain
     ) {
         LOG.info("Search for page: {}, page size: {}, part. id: {}, part sch: {}, domain {}",page, pageSize, participantIdentifier, participantScheme, domain );
@@ -59,11 +57,26 @@ public class ServiceGroupResource {
     @PutMapping(produces = {"application/json"})
     @RequestMapping(method = RequestMethod.GET, path = "{serviceGroupId}")
     public ServiceGroupRO getServiceGroupById(@PathVariable Long serviceGroupId) {
+        return uiServiceGroupService.getServiceGroupById(serviceGroupId);
+    }
 
+    @ResponseBody
+    @PutMapping(produces = {"application/json"})
+    @RequestMapping(method = RequestMethod.GET, path = "extension/{serviceGroupId}")
+    public ServiceGroupExtensionRO getExtensionServiceGroupById(@PathVariable Long serviceGroupId) {
+        return uiServiceGroupService.getServiceGroupExtensionById(serviceGroupId);
+    }
+    @RequestMapping(path = "extension/validate", method = RequestMethod.POST)
+    public ServiceGroupExtensionRO getExtensionServiceGroupById(@RequestBody(required = true) ServiceGroupExtensionRO sg) {
+        return uiServiceGroupService.validateExtension(sg);
+    }
 
-        return uiServiceGroupService.getServiceGroupById(serviceGroupId);
+    @RequestMapping(path = "extension/format", method = RequestMethod.POST)
+    public ServiceGroupExtensionRO formatExtension(@RequestBody(required = true) ServiceGroupExtensionRO sg) {
+        return uiServiceGroupService.formatExtension(sg);
     }
 
+
     @PutMapping(produces = {"application/json"})
     @RequestMapping(method = RequestMethod.PUT)
     public void updateDomainList(@RequestBody(required = true) ServiceGroupRO[] updateEntities ){
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ServiceMetadataResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ServiceMetadataResource.java
index f4d666059..5e184e870 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ServiceMetadataResource.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ServiceMetadataResource.java
@@ -1,22 +1,14 @@
 package eu.europa.ec.edelivery.smp.ui;
 
 
-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.ServiceMetadataValidationRO;
 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 eu.europa.ec.edelivery.smp.ui.DomainResource;
-import eu.europa.ec.edelivery.smp.validation.ServiceMetadataValidator;
-import eu.europa.ec.smp.api.exceptions.XmlInvalidAgainstSchemaException;
-import eu.europa.ec.smp.api.validators.BdxSmpOasisValidator;
+import eu.europa.ec.edelivery.smp.services.ui.UIServiceMetadataService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
-import javax.annotation.PostConstruct;
-import java.util.Arrays;
-
 /**
  * @author Joze Rihtarsic
  * @since 4.1
@@ -29,30 +21,19 @@ public class ServiceMetadataResource {
     private static final SMPLogger LOG = SMPLoggerFactory.getLogger(ServiceMetadataResource.class);
 
     @Autowired
-    ServiceMetadataValidator serviceMetadataValidator;
-
-    @Autowired
-    private UIServiceGroupService uiServiceGroupService;
+    private UIServiceMetadataService uiServiceMetadataService;
 
 
     @ResponseBody
     @PutMapping(produces = {"application/json"})
     @RequestMapping(method = RequestMethod.GET, path = "{serviceMetadataId}")
-    public ServiceGroupRO getServiceGroupById(@PathVariable Long serviceMetadataId) {
-        return uiServiceGroupService.getServiceGroupById(serviceMetadataId);
+    public ServiceMetadataRO getServiceGroupById(@PathVariable Long serviceMetadataId) {
+        return uiServiceMetadataService.getServiceMetadataXMLById(serviceMetadataId);
     }
 
-    private void validateServiceMetadata(ServiceMetadataRO val){
-/*
-        try {
-           // serviceMetadataValidator.validate();
-            //BdxSmpOasisValidator.validateXSD(xml.getBytes());
-
-
-        } catch (XmlInvalidAgainstSchemaException e) {
-            e.printStackTrace();
-        }
-*/
+    @RequestMapping(path = "validate", method = RequestMethod.POST)
+    public ServiceMetadataValidationRO validateServiceMetadata(@RequestBody(required = true) ServiceMetadataValidationRO serviceMetadataValidationRO) {
+        return uiServiceMetadataService.validateServiceMetadata(serviceMetadataValidationRO);
     }
 }
 
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 569447d41..25d0a62a0 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
@@ -2,25 +2,16 @@ 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;
 
@@ -71,7 +62,7 @@ public class UserResource {
         LOG.info("Got certificate data: " + data.length);
         try {
             return uiUserService.getCertificateData(data);
-        } catch (CertificateException e) {
+        } catch (IOException | 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 00c0e53d0..f9fdc1fe1 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
@@ -97,7 +97,6 @@
         LAST_UPDATED_ON datetime not null,
         PARTICIPANT_IDENTIFIER varchar(256)  CHARACTER SET utf8 COLLATE utf8_bin not null,
         PARTICIPANT_SCHEME varchar(256)  CHARACTER SET utf8 COLLATE utf8_bin not null,
-        SML_REGISTRED bit not null,
         primary key (ID)
     ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
@@ -109,7 +108,6 @@
         LAST_UPDATED_ON datetime,
         PARTICIPANT_IDENTIFIER varchar(256)  CHARACTER SET utf8 COLLATE utf8_bin,
         PARTICIPANT_SCHEME varchar(256)  CHARACTER SET utf8 COLLATE utf8_bin,
-        SML_REGISTRED bit,
         primary key (ID, REV)
     ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
@@ -117,6 +115,7 @@
        ID bigint not null,
         CREATED_ON datetime not null,
         LAST_UPDATED_ON datetime not null,
+        SML_REGISTRED bit not null,
         FK_DOMAIN_ID bigint,
         FK_SG_ID bigint,
         primary key (ID)
@@ -128,6 +127,7 @@
         REVTYPE tinyint,
         CREATED_ON datetime,
         LAST_UPDATED_ON datetime,
+        SML_REGISTRED bit,
         FK_DOMAIN_ID bigint,
         FK_SG_ID bigint,
         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 2cf7e6aac..1d8eda096 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
@@ -91,7 +91,6 @@ create sequence SMP_USER_SEQ start with 1 increment by  50;
         LAST_UPDATED_ON timestamp not null,
         PARTICIPANT_IDENTIFIER varchar2(256 char) not null,
         PARTICIPANT_SCHEME varchar2(256 char) not null,
-        SML_REGISTRED number(1,0) not null,
         primary key (ID)
     );
 
@@ -103,7 +102,6 @@ create sequence SMP_USER_SEQ start with 1 increment by  50;
         LAST_UPDATED_ON timestamp,
         PARTICIPANT_IDENTIFIER varchar2(256 char),
         PARTICIPANT_SCHEME varchar2(256 char),
-        SML_REGISTRED number(1,0),
         primary key (ID, REV)
     );
 
@@ -111,6 +109,7 @@ create sequence SMP_USER_SEQ start with 1 increment by  50;
        ID number(19,0) not null,
         CREATED_ON timestamp not null,
         LAST_UPDATED_ON timestamp not null,
+        SML_REGISTRED number(1,0) not null,
         FK_DOMAIN_ID number(19,0),
         FK_SG_ID number(19,0),
         primary key (ID)
@@ -122,6 +121,7 @@ create sequence SMP_USER_SEQ start with 1 increment by  50;
         REVTYPE number(3,0),
         CREATED_ON timestamp,
         LAST_UPDATED_ON timestamp,
+        SML_REGISTRED number(1,0),
         FK_DOMAIN_ID number(19,0),
         FK_SG_ID number(19,0),
         primary key (ID, REV)
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
index ab02e47f6..86ac0ce4e 100644
--- 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
@@ -27,11 +27,9 @@ 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.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.request.MockMvcRequestBuilders.put;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
 /**
@@ -116,30 +114,11 @@ public class ServiceGroupResourceTest {
         assertEquals(1, res.getUsers().size());
         assertEquals("test_user_hashed_pass", res.getUsers().get(0).getUsername());
 
+        assertEquals(1, res.getServiceGroupDomains().size());
         assertEquals(1, res.getServiceMetadata().size());
         assertEquals("doc_7", res.getServiceMetadata().get(0).getDocumentIdentifier());
+        assertEquals(res.getServiceGroupDomains().get(0).getId(), res.getServiceMetadata().get(0).getServiceGroupDomainId());
     }
 
 
-    @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/resources/webapp_integration_test_data.sql b/smp-webapp/src/test/resources/webapp_integration_test_data.sql
index 0c02bb89d..4da0acac4 100644
--- a/smp-webapp/src/test/resources/webapp_integration_test_data.sql
+++ b/smp-webapp/src/test/resources/webapp_integration_test_data.sql
@@ -21,8 +21,8 @@ insert into SMP_USER(ID, USERNAME, ROLE, ACTIVE, CREATED_ON, LAST_UPDATED_ON) va
 insert into SMP_CERTIFICATE (ID, CERTIFICATE_ID, VALID_FROM, VALID_TO, CREATED_ON, LAST_UPDATED_ON) values (6, 'CN=utf-8_ż_SMP,O=EC,C=BE:0000000000000666', null,null,CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP());
 
 -- 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, CREATED_ON, LAST_UPDATED_ON) values (100000, 'urn:australia:ncpb', 'ehealth-actorid-qns', CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP());
+insert into SMP_SERVICE_GROUP(ID, PARTICIPANT_IDENTIFIER, PARTICIPANT_SCHEME, CREATED_ON, LAST_UPDATED_ON) values (200000, 'urn:brazil:ncpb', 'ehealth-actorid-qns', CURRENT_TIMESTAMP(),CURRENT_TIMESTAMP());
 
 -- set ownership
 insert into SMP_OWNERSHIP (FK_SG_ID, FK_USER_ID) values (100000, 2);
@@ -30,9 +30,9 @@ 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_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,SML_REGISTRED,  CREATED_ON, LAST_UPDATED_ON) values (1000,200000, 1, 0, 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_GROUP_DOMAIN (ID, FK_SG_ID, FK_DOMAIN_ID,SML_REGISTRED,  CREATED_ON, LAST_UPDATED_ON) values (1001,100000, 1, 0 ,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());
 
 
-- 
GitLab