From 393962ce4427ecca5c22b3b5b8e5eea7a457fa6f Mon Sep 17 00:00:00 2001
From: Joze RIHTARSIC <joze.rihtarsic@ext.ec.europa.eu>
Date: Fri, 19 Oct 2018 13:25:55 +0200
Subject: [PATCH] update service group search add service metadata dialog
 update service group deialog

---
 smp-angular/package-lock.json                 |   6 +-
 .../src/app/alerts/alerts.component.ts        |   3 +-
 smp-angular/src/app/app.component.html        |   2 +-
 smp-angular/src/app/app.module.ts             |   7 +-
 smp-angular/src/app/app.routes.ts             |   2 +-
 .../search-table/search-table.component.html  |   3 +
 .../search-table/search-table.component.ts    |  29 +++--
 .../domain-details-dialog.component.html      |  65 ++++++----
 .../domain-details-dialog.component.ts        |  34 +++--
 ...ervice-group-details-dialog.component.html |  72 +++++++----
 .../service-group-details-dialog.component.ts |  50 ++++----
 .../service-group-edit-controller.ts          |  43 +++++--
 .../service-group-edit-ro.model.ts            |   2 +
 .../service-group-edit.component.css          |  16 +++
 .../service-group-edit.component.html         |  39 +++---
 .../service-group-edit.component.ts           | 116 +++++++++++++++---
 ...rvice-group-metadata-dialog.component.html |  89 ++++++++------
 ...service-group-metadata-dialog.component.ts |  55 ++++++++-
 .../service-metadata-edit-ro.model.ts         |   9 +-
 .../service-group-search.component.css        |  20 ++-
 .../service-group-search.component.html       |  36 +++---
 .../service-group-search.component.ts         |  34 +++--
 smp-angular/src/app/smp.constants.ts          |   2 +
 .../ec/edelivery/smp/data/dao/BaseDao.java    |   7 +-
 .../smp/data/dao/ServiceGroupDao.java         |  81 ++++++++++++
 .../smp/data/model/DBServiceGroupDomain.java  |   4 +
 .../smp/data/ui/ServiceMetadataRO.java        |  10 ++
 .../exceptions/SMPTestIsALiveException.java   |  12 ++
 .../edelivery/smp/logging/SMPMessageCode.java |  17 +--
 .../services/ui/UIServiceGroupService.java    |  30 ++++-
 .../ui/filters/ServiceGroupFilter.java        |   2 +-
 .../dao/ServiceGroupDaoIntegrationBase.java   |  19 ++-
 .../dao/ServiceGroupDaoIntegrationTest.java   |  49 ++++++++
 .../edelivery/smp/config/SmpWebAppConfig.java |   5 +-
 .../smp/controllers/RootController.java       |  65 ++++++++++
 .../smp/monitor/MonitorResource.java          |   8 +-
 .../ec/edelivery/smp/ui/SearchResource.java   |   5 +-
 .../smp/ui/ServiceGroupResource.java          |  16 ++-
 .../smp/ui/exception/UIException.java         |  28 +++++
 .../validation/ServiceMetadataValidator.java  |  28 +++++
 smp-webapp/src/main/resources/index.html      |  32 +++++
 smp-webapp/src/main/webapp/index.html         |  31 +++++
 .../main/webapp/static_resources/index.html   |   1 +
 .../smp/monitor/MonitorResourceTest.java      |   3 +-
 44 files changed, 929 insertions(+), 258 deletions(-)
 create mode 100644 smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/SMPTestIsALiveException.java
 rename {smp-webapp/src/main/java/eu/europa/ec/edelivery/smp => smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services}/ui/filters/ServiceGroupFilter.java (91%)
 create mode 100644 smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/RootController.java
 create mode 100644 smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/exception/UIException.java
 create mode 100644 smp-webapp/src/main/resources/index.html
 create mode 100644 smp-webapp/src/main/webapp/index.html

diff --git a/smp-angular/package-lock.json b/smp-angular/package-lock.json
index 7bd1dcb8d..6eab6f6b0 100644
--- a/smp-angular/package-lock.json
+++ b/smp-angular/package-lock.json
@@ -3403,9 +3403,9 @@
       }
     },
     "file-saver": {
-      "version": "1.3.8",
-      "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-1.3.3.tgz",
-      "integrity": "sha512-spKHSBQIxxS81N/O21WmuXA2F6wppUCsutpzenOeZzOCCJ5gEfcbqJP983IrpLXzYmXnMUa6J03SubcNPdKrlg=="
+      "version": "1.3.3",
+      "resolved": "http://registry.npmjs.org/file-saver/-/file-saver-1.3.3.tgz",
+      "integrity": "sha1-zdTETTqiZOrC9o7BZbx5HDSvEjI="
     },
     "filename-regex": {
       "version": "2.0.1",
diff --git a/smp-angular/src/app/alerts/alerts.component.ts b/smp-angular/src/app/alerts/alerts.component.ts
index 320be0f5a..1efd1223a 100644
--- a/smp-angular/src/app/alerts/alerts.component.ts
+++ b/smp-angular/src/app/alerts/alerts.component.ts
@@ -206,10 +206,11 @@ export class AlertsComponent implements OnInit {
       this.aTypes = result.alertsType;
 
       this.loading = false;
-
+/*
       if(this.count > AlertComponent.MAX_COUNT_CSV) {
         this.alertService.error("Maximum number of rows reached for downloading CSV");
       }
+      */
     }, (error: any) => {
       console.log("error getting the alerts:" + error);
       this.loading = false;
diff --git a/smp-angular/src/app/app.component.html b/smp-angular/src/app/app.component.html
index 4957b3e62..bc76e90bb 100644
--- a/smp-angular/src/app/app.component.html
+++ b/smp-angular/src/app/app.component.html
@@ -4,7 +4,7 @@
     <div id="topLogo">
       <img src="assets/images/smp_logo_icon.svg" [attr.height]="fullMenu ? '74px' : '40px'" [attr.width]="fullMenu ? '74px' : '40px'"/>
       <div id="topLogoText" *ngIf="fullMenu">
-        <h1>eDeliver SMP <span>Administration <br>Console</span></h1>
+        <h1>eDelivery SMP <span>Administration <br>Console</span></h1>
       </div>
     </div>
 
diff --git a/smp-angular/src/app/app.module.ts b/smp-angular/src/app/app.module.ts
index 721bd6f1c..a748369f2 100644
--- a/smp-angular/src/app/app.module.ts
+++ b/smp-angular/src/app/app.module.ts
@@ -2,7 +2,7 @@ import {BrowserModule} from '@angular/platform-browser';
 import {NgModule} from '@angular/core';
 import {FormsModule, ReactiveFormsModule} from '@angular/forms';
 import {HttpClient, HttpClientModule} from '@angular/common/http';
-import { FlexLayoutModule } from "@angular/flex-layout";
+import {FlexLayoutModule} from "@angular/flex-layout";
 import {
   MatButtonModule,
   MatDialogModule,
@@ -17,7 +17,7 @@ import {
   MatDatepicker,
   MatCardModule,
   MatDatepickerModule,
-  MatSlideToggleModule,
+  MatSlideToggleModule, MatTab, MatAccordion, MatTabsModule,
 } from '@angular/material';
 import "hammerjs";
 
@@ -71,6 +71,7 @@ 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";
 
 @NgModule({
   declarations: [
@@ -130,6 +131,7 @@ import {CertificateService} from './user/certificate.service';
     MatListModule,
     MatSidenavModule,
     MatSelectModule,
+    MatTabsModule,
     MatSlideToggleModule,
     routing,
     ReactiveFormsModule,
@@ -151,6 +153,7 @@ import {CertificateService} from './user/certificate.service';
     UserService,
     CertificateService,
     RoleService,
+    GlobalLookups,
     {
       provide: ExtendedHttpClient,
       useFactory: extendedHttpClientCreator,
diff --git a/smp-angular/src/app/app.routes.ts b/smp-angular/src/app/app.routes.ts
index 9044c4b66..079536ecb 100644
--- a/smp-angular/src/app/app.routes.ts
+++ b/smp-angular/src/app/app.routes.ts
@@ -20,4 +20,4 @@ const appRoutes: Routes = [
 
 ];
 
-export const routing = RouterModule.forRoot(appRoutes);
+export const routing = RouterModule.forRoot(appRoutes, {useHash: true});
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 2b52cd6f8..67c1b7e94 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
@@ -71,6 +71,9 @@
 
     <ng-template #rowActions let-row="row" ngx-datatable-cell-template>
       <div>
+        <ng-container [ngTemplateOutlet]="additionalRowActionButtons"
+                      [ngTemplateOutletContext]="{row:row}"></ng-container>
+
         <button mat-icon-button color="primary" [disabled]="row.deleted || loading"
                 (click)="editSearchTableEntityRow(row)" tooltip="Edit">
           <mat-icon>edit</mat-icon>
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 27ecf945b..61af407ce 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
@@ -30,6 +30,7 @@ export class SearchTableComponent implements OnInit {
   @ViewChild('rowIndex') rowIndex: TemplateRef<any>;
 
   @Input() @ViewChild('additionalToolButtons') additionalToolButtons: TemplateRef<any>;
+  @Input() @ViewChild('additionalRowActionButtons') additionalRowActionButtons: TemplateRef<any>;
   @Input() @ViewChild('searchPanel') searchPanel: TemplateRef<any>;
   @Input() @ViewChild('tableRowDetailContainer') tableRowDetailContainer: TemplateRef<any>;
 
@@ -65,6 +66,7 @@ export class SearchTableComponent implements OnInit {
               protected alertService: AlertService,
               private downloadService: DownloadService,
               public dialog: MatDialog) {
+
   }
 
   ngOnInit() {
@@ -79,8 +81,8 @@ export class SearchTableComponent implements OnInit {
     this.columnActions = {
       cellTemplate: this.rowActions,
       name: 'Actions',
-      width: 120,
-      maxWidth:150,
+      width: 250,
+      maxWidth:250,
       sortable: false
     };
     this.columnExpandDetails= {
@@ -108,7 +110,6 @@ export class SearchTableComponent implements OnInit {
         this.columnPicker.selectedColumns.push(this.columnActions);
       }
     }
-    this.page(this.offset, this.rowLimiter.pageSize, this.orderBy, this.asc);
   }
 
   getRowClass(row) {
@@ -156,10 +157,10 @@ export class SearchTableComponent implements OnInit {
           status: SearchTableEntityStatus.PERSISTED,
           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);
     });
@@ -207,10 +208,10 @@ export class SearchTableComponent implements OnInit {
     });
     formRef.afterClosed().subscribe(result => {
       if (result) {
-        this.rows = [...this.rows, {...formRef.componentInstance.current}];
+        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();
       }
@@ -305,11 +306,20 @@ export class SearchTableComponent implements OnInit {
         const status = row.status === SearchTableEntityStatus.PERSISTED
           ? SearchTableEntityStatus.UPDATED
           : row.status;
-        this.rows[rowNumber] = {...formRef.componentInstance.current, status};
-        this.rows = [...this.rows];
+         this.rows[rowNumber] = {...formRef.componentInstance.getCurrent(), status};
+         this.rows = [...this.rows];
       }
     });
   }
+  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);
+  }
+
+
   private editSearchTableEntityRow(row: SearchTableEntity) {
       let rowNumber = this.rows.indexOf(row);
       this.editSearchTableEntity(rowNumber);
@@ -326,6 +336,7 @@ export class SearchTableComponent implements OnInit {
       if (row.status === SearchTableEntityStatus.NEW) {
         this.rows.splice(this.rows.indexOf(row), 1);
       } else {
+        this.searchTableController.delete(row);
         row.status = SearchTableEntityStatus.REMOVED;
         row.deleted = true;
       }
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 48af80189..49f9bcb12 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
@@ -1,48 +1,59 @@
 <h2 mat-dialog-title>{{formTitle}}</h2>
 <mat-dialog-content>
-
+  <form [formGroup]="domainForm">
   <mat-card>
+    <mat-card-title>Domain properties</mat-card-title>
     <mat-card-content>
-      <div class="panel">
         <fieldset style="border: none;">
           <mat-form-field style="width:100%">
-            <input matInput placeholder="Domain Code ()" name="domainCode" value="{{current.domainCode}}" id="domainCode_id"
-                   (blur)="updateDomainCode($event)" [formControl]="domainForm.controls['domainCode']" maxlength="255" required>
+            <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.
+             Domain could must contain only chars and numbers.
             </div>
           </mat-form-field>
           <mat-form-field style="width:100%">
-            <input matInput placeholder="SML domain (Part of DNS Zone: ex.eHealth: 'ehealth', peppol: '', ..)" name="smlSubdomain" value="{{current.smlSubdomain}}" id="smldomain_id"
-                   (blur)="updateSmlDomain($event)" [formControl]="domainForm.controls['smlSubdomain']" maxlength="255" required>
+            <input matInput placeholder="SML domain (Part of DNS Zone: ex.eHealth: 'ehealth', peppol: '', ..)" name="smlSubdomain"  id="smldomain_id"
+                    [formControl]="domainForm.controls['smlSubdomain']" maxlength="255" >
             <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 -).
+              SML domain must be valid DNS part (AlphaNumeric with optional char - or must be empty for peppol).
             </div>
           </mat-form-field>
           <mat-form-field style="width:100%">
-            <input matInput placeholder="SML SMP identifier (SMP ID used for SML )" name="smlSmpId" value="{{current.smlSmpId}}" id="smlSMPId_id"
-                   (blur)="updateSmlSmpId($event)" [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 -).
-            </div>
-
-          </mat-form-field>
-          <mat-form-field style="width:100%">
-            <input matInput placeholder="SML Client certificate" name="Client certificate" value="{{current.smlClientKeyAlias}}" id="smlClientKeyAlias_id"
-                   (blur)="updateSmlClientKeyAlias($event)" [formControl]="domainForm.controls['smlClientKeyAlias']" maxlength="255" required>
-          </mat-form-field>
-          <mat-form-field style="width:100%">
-            <input matInput placeholder="Response signature Certificate" name="signatureKeyAlias" value="{{current.signatureKeyAlias}}" id="signatureKeyAlias_id"
-                   (blur)="updateSignatureKeyAlias($event)" [formControl]="domainForm.controls['signatureKeyAlias']" maxlength="255" required>
+            <input matInput placeholder="Response signature Certificate" name="signatureKeyAlias" id="signatureKeyAlias_id"
+                   [formControl]="domainForm.controls['signatureKeyAlias']" maxlength="255" >
           </mat-form-field>
         </fieldset>
-        <!-- label class="custom-file-upload">
-          <input #fileInput type="file" id="custom-file-upload" accept=".cer" (change)="uploadCertificate()" >
-          <span class="custom-file-upload-inner">Import</span>
-        </label-->
-      </div>
     </mat-card-content>
   </mat-card>
+    <mat-card>
+      <mat-card-title>SML integration data</mat-card-title>
+      <mat-card-content>
+        <fieldset style="border: none;">
+            <mat-form-field style="width:100%">
+              <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 -).
+              </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" >
+            </mat-form-field>
+            <mat-form-field style="width:100%">
+              <input matInput placeholder="ClientCert Alias" name="Client certificate" id="smlClientKeyAlias_id"
+                     [formControl]="domainForm.controls['smlClientKeyAlias']" maxlength="255" >
+            </mat-form-field>
+          </fieldset>
+          <!-- label class="custom-file-upload">
+            <input #fileInput type="file" id="custom-file-upload" accept=".cer" (change)="uploadCertificate()" >
+            <span class="custom-file-upload-inner">Import</span>
+          </label-->
+      </mat-card-content>
+    </mat-card>
+  </form>
 </mat-dialog-content>
 
 <table class="buttonsRow">
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 092a11652..d2204ad31 100644
--- a/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts
+++ b/smp-angular/src/app/domain/domain-details-dialog/domain-details-dialog.component.ts
@@ -18,15 +18,13 @@ export class DomainDetailsDialogComponent {
 
   static readonly NEW_MODE = 'New Domain';
   static readonly EDIT_MODE = 'Domain Edit';
-  readonly dnsDomainPattern = '^(?!(\\d|-|_).+)[a-zA-Z0-9-]{1,63}$';
-  readonly domainCodePattern = '^[a-zA-Z]{1,255}$';
+  readonly dnsDomainPattern = '^(?![0-9]+$)(?!.*-$)(?!-)[a-zA-Z0-9-]{0,63}$';
+  readonly domainCodePattern = '^[a-zA-Z0-9]{1,255}$';
 
   editMode: boolean;
   formTitle: string;
   current: DomainRo & { confirmation?: string };
   domainForm: FormGroup;
-
-
   domain;
 
 
@@ -52,16 +50,22 @@ export class DomainDetailsDialogComponent {
 
     this.domainForm = fb.group({
 
-      'domainCode': new FormControl({value: this.current.domainCode, disabled: this.editMode}, [Validators.pattern(this.domainCodePattern)]),
-      'smlSubdomain': new FormControl({value: this.current.smlSubdomain, disabled: this.editMode},  [Validators.pattern(this.dnsDomainPattern)]),
-      'smlSmpId': new FormControl({value: this.current.smlSmpId}, [Validators.required, Validators.pattern(this.dnsDomainPattern)]),
-      'smlClientKeyAlias': new FormControl({value: this.current.smlClientKeyAlias}, null),
-      'signatureKeyAlias': new FormControl({value: this.current.signatureKeyAlias}, null),
-
+      '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)]),
+      'smlClientKeyAlias': 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['smlClientKeyAlias'].setValue(this.current.smlClientKeyAlias);
+    this.domainForm.controls['signatureKeyAlias'].setValue(this.current.signatureKeyAlias);
+
+
   }
   submitForm() {
     this.checkValidity(this.domainForm)
@@ -81,7 +85,17 @@ export class DomainDetailsDialogComponent {
     });
   }
 
+  public getCurrent(): DomainRo {
+
+    this.current.domainCode = this.domainForm.value['domainCode'];
+    this.current.smlSubdomain = this.domainForm.value['smlSubdomain'];
+    this.current.smlSmpId = this.domainForm.value['smlSmpId'];
+    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;
   }
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 d29e25dc3..8161bf22d 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,11 +1,12 @@
 <h2 mat-dialog-title>{{formTitle}}</h2>
 
-<mat-dialog-content style="height:600px;width:1100px">
+<mat-dialog-content style="height:620px;width:1200px">
   <div fxLayout="row">
     <div fxLayout="column">
       <mat-card fxFlex="200px">
-        <mat-card-title>Identifier</mat-card-title>
-        <mat-card-content>
+        <!-- mat-card-title>Identifier</mat-card-title -->
+        <mat-card-content style="height: 100px">
+          <div class="panel">
           <mat-form-field style="width:100%">
             <input matInput placeholder="Participant identifier" name="participantIdentifier"
                    value="{{current.participantIdentifier}}" id="participantIdentifier_id"
@@ -29,25 +30,54 @@
               Participant scheme must not be empty.
             </div>
           </mat-form-field>
+          </div>
         </mat-card-content>
       </mat-card>
       <mat-card>
-        <mat-card-title>Owners</mat-card-title>
+        <!-- mat-card-title>Owners/Domains</mat-card-title -->
         <mat-card-content>
-          <p>Selected user count: {{usersSelected.selectedOptions.selected.length}}</p>
-        <mat-selection-list #usersSelected [compareWith]="compareUserById"
-                            (selectionChange)="userListChanged(usersSelected.selectedOptions.selected,$event)"
-                            [formControl]="formControlUsers"
-                            style="height: 200px;  overflow-y: scroll; overflow-x: auto;">
-          <mat-list-option *ngFor="let user of userlist" [value]='user'>
-            {{user.id}} - {{user.username?user.username:user.id}}
-          </mat-list-option>
-        </mat-selection-list>
-        <div
-          *ngIf="(!editMode && dialogForm.controls['users'].touched || editMode) &&  dialogForm.controls['users'].hasError('minCountOwners')"
-          style="color:red; font-size: 70%">
-          At least one user (owner) must be selected!
-        </div>
+
+          <mat-accordion>
+            <mat-expansion-panel [expanded]="true">
+              <mat-expansion-panel-header>
+                <mat-panel-title>Owners</mat-panel-title>
+                <mat-panel-description>
+                  Selected user count: {{usersSelected.selectedOptions.selected.length}}
+                </mat-panel-description>
+              </mat-expansion-panel-header>
+              <mat-selection-list  #usersSelected [compareWith]="compareTableItemById"
+                                  (selectionChange)="userListChanged(usersSelected.selectedOptions.selected,$event)"
+                                  [formControl]="formControlUsers"
+                                  style="height: 200px;  overflow-y: scroll; overflow-x: auto;">
+                <mat-list-option *ngFor="let user of userlist" [value]='user'>
+                  {{user.id}} - {{user.username?user.username:user.id}}
+                </mat-list-option>
+              </mat-selection-list>
+            </mat-expansion-panel>
+
+            <mat-expansion-panel >
+              <mat-expansion-panel-header>
+                <mat-panel-title>Domains</mat-panel-title>
+                <mat-panel-description>
+                  Selected domain count: {{domainSelected.selectedOptions.selected.length}}
+                </mat-panel-description>
+              </mat-expansion-panel-header>
+              <mat-selection-list  #domainSelected [compareWith]="compareTableItemById"
+                                   [formControl]="formControlDomain"
+                                   style="height: 200px;  overflow-y: scroll; overflow-x: auto;">
+                <mat-list-option *ngFor="let domain of domainList" [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>
@@ -58,9 +88,9 @@
         <p>
           Extension is automatically wrapped to root element to form vaild XML! No ExtensionWrapper element is needed.
         </p>
-        <mat-form-field>
-          <textarea id="extensionTextArea" resizeable="false" placeholder="Extension"  name="extension" ></textarea>
-        </mat-form-field>
+        <!--mat-form-field>
+          < textarea id="extensionTextArea" resizeable="false" placeholder="Extension" name="extension"></textarea>
+        </mat-form-field -->
       </mat-card-content>
     </mat-card>
   </div>
diff --git a/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.ts b/smp-angular/src/app/service-group-edit/service-group-details-dialog/service-group-details-dialog.component.ts
index 1af2b0bd1..7d17a32f1 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
@@ -12,6 +12,7 @@ import {SearchTableEntityStatus} from "../../common/search-table/search-table-en
 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',
@@ -27,6 +28,7 @@ export class ServiceGroupDetailsDialogComponent {
   userObserver:  Observable< SearchTableResult> ;
   domainObserver:  Observable< SearchTableResult> ;
   userlist: Array<UserRo> = [];
+  domainList: Array<DomainRo> = [];
   editMode: boolean;
   formTitle: string;
   current: ServiceGroupEditRo & { confirmation?: string };
@@ -34,12 +36,13 @@ export class ServiceGroupDetailsDialogComponent {
   dialogForm: FormGroup;
   dialogFormBuilder: FormBuilder;
   formControlUsers: FormControl;
+  formControlDomain: FormControl;
   /*
   selectedDomain: DomainRo;
   domainList: Array<any>;
 */
 
-  minCountOwners(min: number) {
+  minSelectedListCount(min: number) {
     return (c: AbstractControl): {[key: string]: any} => {
       if (c.value.length >= min)
         return null;
@@ -48,13 +51,14 @@ export class ServiceGroupDetailsDialogComponent {
     }
   }
 
-  constructor(protected http: HttpClient, public dialogRef: MatDialogRef<ServiceGroupDetailsDialogComponent>,
-                private alertService: AlertService,
+  constructor(protected http: HttpClient,
+              public dialogRef: MatDialogRef<ServiceGroupDetailsDialogComponent>,
+              private alertService: AlertService,
+              private 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 = 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);
@@ -62,24 +66,21 @@ export class ServiceGroupDetailsDialogComponent {
       this.userlist = users.serviceEntities.map(serviceEntity => {
         return {...<UserRo>serviceEntity}
       });
-      this.updateData();
+      this.updateUserData();
     });
-    /*
-    // init domains
-    this.domainObserver = this.http.get<SearchTableResult>(SmpConstants.REST_DOMAIN);
-    this.domainObserver.subscribe((domains: SearchTableResult) => {
+    // domain service group
+    this.lookups.getDomainLookupObservable().subscribe((domains: SearchTableResult) => {
       this.domainList = new Array(domains.serviceEntities.length)
-        .map((v, index) => {domains.serviceEntities[index] as DomainRo;
-          if ( this.editMode && v.domainCode ===data.row.domainCode) {
-            this.selectedDomain = v as DomainRo;
-          }
-        });
+        .map((v, index) => domains.serviceEntities[index] as DomainRo);
 
       this.domainList = domains.serviceEntities.map(serviceEntity => {
-        return {...serviceEntity}
+        return {...<DomainRo>serviceEntity}
       });
+      this.updateDomainData();
     });
-*/
+
+
+
     this.dialogFormBuilder = fb;
     this.editMode = data.edit;
     this.formTitle = this.editMode ?  ServiceGroupDetailsDialogComponent.EDIT_MODE: ServiceGroupDetailsDialogComponent.NEW_MODE;
@@ -98,25 +99,28 @@ export class ServiceGroupDetailsDialogComponent {
       };
 
     this.dialogForm = this.dialogFormBuilder.group({
-
       'participantIdentifier': new FormControl({value: this.current.participantIdentifier, disabled: this.editMode}, this.editMode ? Validators.required : null),
       'participantScheme': new FormControl({value: this.current.participantScheme, disabled: this.editMode},  this.editMode ? Validators.required : null),
       'domainCode': new FormControl({value: this.current.domainCode},this.editMode ? Validators.required : null),
 
-      //'users': [new FormControl({value: this.current.users}, [ this.minCountOwners(1)] )],
     });
 
 
   }
 
-  updateData(){
+  updateUserData(){
     this.formControlUsers = new FormControl(this.current.users);
-    this.formControlUsers.setValidators( [ this.minCountOwners(1)]);
-
+    this.formControlUsers.setValidators( [ this.minSelectedListCount(1)]);
     this.dialogForm.addControl("users",this.formControlUsers );
 
   }
 
+  updateDomainData(){
+    this.formControlDomain = new FormControl(this.current.domains);
+    this.formControlDomain.setValidators( [ this.minSelectedListCount(1)]);
+    this.dialogForm.addControl("domains",this.formControlDomain );
+  }
+
 
   submitForm() {
     this.checkValidity(this.dialogForm)
@@ -150,7 +154,7 @@ export class ServiceGroupDetailsDialogComponent {
       this.current.users.push(usr.value);
     }
   }
-  compareUserById(item1, item2): boolean{
+  compareTableItemById(item1, item2): boolean{
     return item1.id=== item2.id;
   }
 
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 fa802d8a0..23dc032ef 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
@@ -5,43 +5,70 @@ 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 {
 
-  constructor(public dialog: MatDialog) { }
+  constructor(public dialog: MatDialog) {
+  }
 
-  public showDetails( row: any, config?: MatDialogConfig,) {
+  public showDetails(row: any, config?: MatDialogConfig,) {
     let dialogRef: MatDialogRef<ServiceGroupDetailsDialogComponent>
       = this.dialog.open(ServiceGroupDetailsDialogComponent);
     dialogRef.afterClosed().subscribe(result => {
       //Todo:
     });
-
   }
 
-  public showMetadataList(row: any) {
 
+  public edit(row: any) {
   }
 
+  public delete(row: any) {
 
-  public edit(row: any) { }
+    // set all rows as deleted
+    let sgRow =  row as ServiceGroupEditRo;
+    sgRow.serviceMetadata.forEach(function(part, index, metaDataList) {
+      metaDataList[index].status = SearchTableEntityStatus.REMOVED;
+      metaDataList[index].deleted=true;
+    });
 
-  public delete(row: any) { }
+  }
 
   public newDialog(config?: MatDialogConfig): MatDialogRef<ServiceGroupDetailsDialogComponent> {
     return this.dialog.open(ServiceGroupDetailsDialogComponent, config);
   }
 
+  public newMetadataDialog(config?: MatDialogConfig): MatDialogRef<ServiceGroupMetadataDialogComponent> {
+    return this.dialog.open(ServiceGroupMetadataDialogComponent, config);
+  }
+
   public newRow(): ServiceGroupEditRo {
     return {
       id: null,
       index: null,
-      participantIdentifier:'',
+      participantIdentifier: '',
       participantScheme: '',
       domainCode: '',
       smlSubdomain: '',
-      serviceMetadata:[],
+      serviceMetadata: [],
       users: [],
+      domains: [],
+      status: SearchTableEntityStatus.NEW
+    };
+  }
+
+  public newServiceMetadataRow(): ServiceMetadataEditRo {
+    return {
+      id:null,
+      documentIdentifier: '',
+      documentIdentifierScheme: '',
+      smlSubdomain: '',
+      domainCode: '',
+      processSchema: '',
+      processIdentifier: '',
+      endpointUrl: '',
+      endpointCertificate: '',
       status: SearchTableEntityStatus.NEW
     };
   }
diff --git a/smp-angular/src/app/service-group-edit/service-group-edit-ro.model.ts b/smp-angular/src/app/service-group-edit/service-group-edit-ro.model.ts
index 9b626bc7e..0fcbd1d60 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,6 +1,7 @@
 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 {
   id: number;
@@ -9,5 +10,6 @@ export interface ServiceGroupEditRo extends SearchTableEntity {
   domainCode:'',
   smlSubdomain:'',
   serviceMetadata: Array<ServiceMetadataEditRo>;
+  domains: Array<DomainRo>;
   users: Array<UserRo>;
 }
diff --git a/smp-angular/src/app/service-group-edit/service-group-edit.component.css b/smp-angular/src/app/service-group-edit/service-group-edit.component.css
index d1a612141..14b69d931 100644
--- a/smp-angular/src/app/service-group-edit/service-group-edit.component.css
+++ b/smp-angular/src/app/service-group-edit/service-group-edit.component.css
@@ -16,3 +16,19 @@
 .datatable-body{
   overflow-y: scroll;
 }
+
+
+/deep/ .inner-table {
+  margin-left: 100px;
+  width: 80%;
+}
+
+/deep/ .inner-table .datatable-body-cell {
+  padding:  1.5em 2px !important;
+
+}
+
+/deep/ .inner-table .mat-icon-button {
+  height: auto !important;;
+  line-height: unset !important;
+}
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 894019e35..1db04a19c 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
@@ -1,4 +1,4 @@
-<smp-search-table
+<smp-search-table #searchTable
   page_id='edit_id'
   title='Edit'
   [columnPicker]="columnPicker"
@@ -8,16 +8,20 @@
   [filter]="filter"
   [searchTableController]="serviceGroupEditController"
   [tableRowDetailContainer]="tableRowDetailContainer"
+  [additionalRowActionButtons]="additionalRowActionButtons"
 >
 
   <ng-template #rowMetadataAction let-row="row" let-value="value" ngx-datatable-cell-template>
-
     <button mat-button color="primary"
             (click)="metadataRowButtonAction(row)" id="metadataRowButtonAction{{row.$$index}}_id" tooltip="Metadata">
       <mat-icon>view_list</mat-icon>
       <span>Metadata</span>
     </button>
+  </ng-template>
 
+  <ng-template #rowSMPUrlLinkAction let-row="row" let-value="value" ngx-datatable-cell-template>
+    <a target="_blank"
+       href="{{contextPath}}{{row.participantScheme}}::{{row.participantIdentifier}}" >Open URL</a>
   </ng-template>
 
 
@@ -30,26 +34,25 @@
       <input matInput placeholder="Participant schema" name="patricipantSchema" [(ngModel)]="filter.messageId"
              #messageId="ngModel" id="participanschema_id">
     </mat-form-field>
-    <mat-select placeholder="Domain " [(ngModel)]="filter.messageStatus" name="messageStatus"
-               id="messagestatus_id">
+
+    <mat-select placeholder="Domain (sml subdomain)" [(ngModel)]="filter.domain" name="domain"
+                id="domain_id">
       <mat-option [value]="''">
       </mat-option>
-      <mat-option *ngFor="let mstatus of msgStatus" [value]="mstatus">
-        {{mstatus}}
+      <mat-option *ngFor="let domain of domainlist" [value]="domain.domainCode">
+        {{domain.domainCode}} ({{domain.smlSubdomain}})
       </mat-option>
     </mat-select>
   </ng-template>
 
 
-  <ng-template #additionalToolButtons>
-    <div style="background-color: #03A9F4; display: inline-block; width: 3px; height: 100%; margin-right: 8px">&nbsp;
-    </div>
-    <button mat-raised-button color="primary"
-            id="metadatabutton_id">
-      <mat-icon>view_list</mat-icon>
-      <span>Metadata</span>
-    </button>
+  <ng-template #additionalToolButtons></ng-template>
 
+  <ng-template #additionalRowActionButtons let-row="row">
+    <button mat-icon-button color="primary" [disabled]="row?.deleted || loading"
+            (click)="onAddMetadataRow(row)" tooltip="Edit">
+      <mat-icon>playlist_add</mat-icon>
+    </button>
   </ng-template>
 
   <ng-template #tableRowDetailContainer let-row="row">
@@ -59,14 +62,14 @@
     </div>
     <div *ngIf="row.serviceMetadata.length !== 0" >
       <ngx-datatable
-        class='material striped'
-        style="width: 80%"
+        class='inner-table material striped'
         [loadingIndicator]="loading"
         [rows]='row.serviceMetadata'
         [columnMode]='"force"'
         [headerHeight]='50'
         [footerHeight]='50'
-        [rowHeight]='"auto"'>
+        [rowHeight]='"auto"'
+        [rowClass]="getRowClass">
         <ngx-datatable-column prop="domainCode" name="Domain" maxWidth="250" ></ngx-datatable-column>
         <ngx-datatable-column prop="documentIdentifierScheme" name="Document identifier scheme" maxWidth="350" ></ngx-datatable-column>
         <ngx-datatable-column prop="documentIdentifier" name="Document identifier" maxWidth="250" ></ngx-datatable-column>
@@ -86,7 +89,7 @@
             <mat-icon>edit</mat-icon>
           </button>
           <button mat-icon-button color="primary" [disabled]="rowSmd.deleted || loading"
-                  (click)="onDeleteMetadataRowActionClicked(rowSmd)" tooltip="Delete">
+                  (click)="onDeleteMetadataRowActionClicked(row, rowSmd)" tooltip="Delete">
             <mat-icon>delete</mat-icon>
           </button>
         </div>
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 b81066cb4..73b6f9211 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
@@ -9,28 +9,36 @@ 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,
-  templateUrl:'./service-group-edit.component.html',
+  templateUrl: './service-group-edit.component.html',
   styleUrls: ['./service-group-edit.component.css']
 })
 export class ServiceGroupEditComponent implements OnInit {
 
   @ViewChild('rowMetadataAction') rowMetadataAction: TemplateRef<any>
   @ViewChild('rowActions') rowActions: TemplateRef<any>;
-  @ViewChild('rowSMPUrlLinkAction') rowSMPUrlLinkAction: TemplateRef<any>
+  @ViewChild('rowSMPUrlLinkAction') rowSMPUrlLinkAction: TemplateRef<any>;
+  @ViewChild('searchTable') searchTable: SearchTableComponent;
 
   columnPicker: ColumnPicker = new ColumnPicker();
   serviceGroupEditController: ServiceGroupEditController;
   filter: any = {};
   baseUrl: string = SmpConstants.REST_EDIT;
 
-  userObserver:  Observable< SearchTableResult> ;
-  domainObserver:  Observable< SearchTableResult> ;
+  userObserver: Observable<SearchTableResult>;
+  domainObserver: Observable<SearchTableResult>;
   userlist: Array<UserRo> = [];
+  domainlist: Array<any>;
 
-  constructor(protected http: HttpClient, protected alertService: AlertService, public dialog: MatDialog) {
+  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) => {
@@ -41,29 +49,43 @@ export class ServiceGroupEditComponent implements OnInit {
         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() {
+
+
     this.serviceGroupEditController = new ServiceGroupEditController(this.dialog);
 
     this.columnPicker.allColumns = [
       {
         name: 'Metadata size',
         prop: 'serviceMetadata.length',
-        width: 80,
-        maxWidth: 120
+        width: 120,
+        maxWidth: 120,
+        resizable: "false"
       },
       {
         name: 'Owners size',
         prop: 'users.length',
-        width: 80,
-        maxWidth: 120
+        width: 120,
+        maxWidth: 120,
+        resizable: "false"
       },
       {
         name: 'Participant scheme',
         prop: 'participantScheme',
-        width: 250,
-        maxWidth: 300
+        width: 300,
+        maxWidth: 300,
+        resizable: "false"
       },
       {
         name: 'Participant identifier',
@@ -72,8 +94,9 @@ export class ServiceGroupEditComponent implements OnInit {
       {
         cellTemplate: this.rowSMPUrlLinkAction,
         name: 'OASIS ServiceGroup URL',
-        width: 150,
+        width: 250,
         maxWidth: 250,
+        resizable: "false",
         sortable: false
       },
 
@@ -84,19 +107,72 @@ export class ServiceGroupEditComponent implements OnInit {
     });
   }
 
-  metadataRowButtonAction(row: any){
-    this.serviceGroupEditController.showMetadataList(row);
-  }
-
   details(row: any) {
     this.serviceGroupEditController.showDetails(row);
 
   }
 
-  onEditMetadataRow(row:any){
-    alert("edit" + row);
+  onAddMetadataRow(row: any) {
+    let rowNumber = this.searchTable.rows.indexOf(row);
+
+    const formRef: MatDialogRef<any> = this.serviceGroupEditController.newMetadataDialog({
+      data: {edit: true, serviceGroup: row, metadata: null}
+    });
+    formRef.afterClosed().subscribe(result => {
+      if (result) {
+        const status = row.status === SearchTableEntityStatus.PERSISTED
+          ? SearchTableEntityStatus.UPDATED
+          : row.status;
+
+        let data = this.serviceGroupEditController.newServiceMetadataRow();
+        data.documentIdentifier = "aaaaaaaaa";
+        data.documentIdentifierScheme = "aaaaaaaaa";
+        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];*/
+
+      }
+    });
+
+  }
+
+  getRowClass(row) {
+    return {
+      'table-row-new': (row.status === SearchTableEntityStatus.NEW),
+      'table-row-updated': (row.status === SearchTableEntityStatus.UPDATED),
+      'deleted': (row.status === SearchTableEntityStatus.REMOVED)
+    };
   }
-  onDeleteMetadataRowActionClicked(row:any){
-    alert("delete" + row);
+
+  onEditMetadataRow(metaDataRow: any) {
+
+  }
+
+  onDeleteMetadataRowActionClicked(serviceGroupRow: any, metaDataRow: any) {
+    let rowNumber = this.searchTable.rows.indexOf(serviceGroupRow);
+
+    if (metaDataRow.status === SearchTableEntityStatus.NEW) {
+      serviceGroupRow.splice(serviceGroupRow.indexOf(metaDataRow), 1);
+    } else {
+      metaDataRow.status = SearchTableEntityStatus.REMOVED;
+      metaDataRow.deleted = true;
+      // set row as updated
+      const status = serviceGroupRow.status === SearchTableEntityStatus.PERSISTED
+        ? SearchTableEntityStatus.UPDATED
+        : serviceGroupRow.status;
+      serviceGroupRow.status = status;
+
+      // do not do that it updates the whole table
+      // this.searchTable.rows[rowNumber] = {...serviceGroupRow, status};
+      // this.searchTable.rows = [...this.searchTable.rows];
+    }
   }
 }
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 efb822ceb..0e54d9c7b 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,41 +1,58 @@
 <h2 mat-dialog-title>ServiceGroup Metadata</h2>
-<mat-dialog-content style="height:460px;width:950px">
-  <textarea style="width: 100%; height: 95%">&lt;ServiceMetadata xmlns="http://docs.oasis-open.org/bdxr/ns/SMP/2016/05"&gt;
-    &lt;ServiceInformation&gt;
-        &lt;ParticipantIdentifier scheme="participantSchema"&gt;participantIdentifier&lt;/ParticipantIdentifier&gt;
-        &lt;DocumentIdentifier scheme="docSchema"&gt;docTypeIdentifier&lt;/DocumentIdentifier&gt;
-        &lt;ProcessList&gt;
-            &lt;Process&gt;
-                &lt;ProcessIdentifier scheme="cenbii-procid-ubl"&gt;urn:www.cenbii.eu:profile:bii04:ver1.0&lt;/ProcessIdentifier&gt;
-                &lt;ServiceEndpointList&gt;
-                    &lt;Endpoint transportProfile="busdox-transport-start"&gt;
-                        &lt;EndpointURI&gt;https://poland.pl/theService&lt;/EndpointURI&gt;
-                        &lt;RequireBusinessLevelSignature&gt;true&lt;/RequireBusinessLevelSignature&gt;
-                        &lt;ServiceActivationDate&gt;2003-01-01T00:00:00&lt;/ServiceActivationDate&gt;
-                        &lt;ServiceExpirationDate&gt;2020-05-01T00:00:00&lt;/ServiceExpirationDate&gt;
-                        &lt;Certificate&gt;MIICUTCCAbqgAwIBAgIEWoKrxzANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQGEwJCRTEcMBoGA1UECgwTRXVyb3BlYW4gQ29tbWlzc2lvbjEYMBYGA1UECwwPRElHSVQgZURlbGl2ZXJ5MSYwJAYDVQQDDB1TYW1wbGUgU2lnbmF0dXJlcyBDZXJ0aWZpY2F0ZTAeFw0xODAyMTMwOTEzMjBaFw0zODAyMTMwOTEzMjBaMG0xCzAJBgNVBAYTAkJFMRwwGgYDVQQKDBNFdXJvcGVhbiBDb21taXNzaW9uMRgwFgYDVQQLDA9ESUdJVCBlRGVsaXZlcnkxJjAkBgNVBAMMHVNhbXBsZSBTaWduYXR1cmVzIENlcnRpZmljYXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIWYibbbJ6YT3uLQ0oup8kB1jJO/o16nlRfB3CbCbmpGZ2r+zCh67EMstKLltuk3peJ6QTcSaFV2oS1KLKWxwWsV4iEs5qggA5BTkzUicTsQWw39OcPPe0wniJeXdNUlOUFP2ab0ZQ9UMrJgVtlyF2uLijoKx1XR0mpTKmajh1CQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBABoFFJ+vgOo/78SPv73+MEdxkydn5EMsZ+Q4Vt1BmBaq78RcjeS7LpvPZtRxSzW+w59825BbaOCJ5K0oc6lwOXc+SS0ZI0JK2vMlp/2REFLedqHqnhpSWFKWM0Zrq80o1SzBQHC1hq95RXml6RzzPEEK0Ll0dVH7HXRpekRScGic&lt;/Certificate&gt;
-                        &lt;ServiceDescription&gt;Sample description of invoicing service&lt;/ServiceDescription&gt;
-                        &lt;TechnicalContactUrl&gt;https://example.com&lt;/TechnicalContactUrl&gt;
-                    &lt;/Endpoint&gt;
-                &lt;/ServiceEndpointList&gt;
-                &lt;Extension&gt;
-                    &lt;ExtensionID&gt;optional sample ID&lt;/ExtensionID&gt;
-                    &lt;ExtensionName&gt;UTF-8 characters are handled, i.e. polish special ones: zażółć gęślą jaźń&lt;/ExtensionName&gt;
-                    &lt;ExtensionAgencyID&gt;text&lt;/ExtensionAgencyID&gt;
-                    &lt;ExtensionAgencyName&gt;text&lt;/ExtensionAgencyName&gt;
-                    &lt;ex:dummy xmlns:ex="http://test.eu"&gt;dummy1&lt;/ex:dummy&gt;
-                &lt;/Extension&gt;
-                &lt;Extension&gt;
-                    &lt;ex:dummy xmlns:ex="http://test.eu"&gt;dumm2&lt;/ex:dummy&gt;
-                &lt;/Extension&gt;
-            &lt;/Process&gt;
-        &lt;/ProcessList&gt;
-        &lt;Extension&gt;
-            &lt;ex:dummynode xmlns:ex="http://test.eu"&gt;Sample not mandatory extension&lt;/ex:dummynode&gt;
-        &lt;/Extension&gt;
-    &lt;/ServiceInformation&gt;
-&lt;/ServiceMetadata&gt;</textarea>
+<mat-dialog-content  style="height:460px;width:950px">
 
+  <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-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.
+        </div>
+      </mat-form-field>
+
+      <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-form-field style="width:100%">
+        <input matInput placeholder="Process identifier" name="processidentifier" id="processidentifier_id"
+               [formControl]="dialogForm.controls['processIdentifier']" 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>
+
+      <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-tab>
+    <mat-tab label="XML">
+      <h1>Some more tab content</h1>
+      <textarea style="width: 100%; height: 95%"></textarea>
+    </mat-tab>
+  </mat-tab-group>
 </mat-dialog-content>
 
 <mat-dialog-actions>
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 196c6499d..544447520 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,5 +1,11 @@
-import {Component} from '@angular/core';
-import {MatDialogRef} from '@angular/material';
+import {Component, Inject} from '@angular/core';
+import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material';
+import {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";
 
 @Component({
   selector: 'app-messagelog-dialog',
@@ -8,7 +14,50 @@ import {MatDialogRef} from '@angular/material';
 })
 export class ServiceGroupMetadataDialogComponent {
 
-  constructor(public dialogRef: MatDialogRef<ServiceGroupMetadataDialogComponent>) {
+  static readonly NEW_MODE = 'New ServiceMetadata';
+  static readonly EDIT_MODE = 'Domain ServiceMetadata';
+
+  editMode: boolean;
+  formTitle: string;
+  current: ServiceMetadataEditRo & { confirmation?: string };
+  dialogForm: FormGroup;
+
+
+  constructor(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.current = this.editMode
+      ? {
+        ...data.row,
+      }
+      : {
+        documentIdentifier: '',
+        documentIdentifierScheme: '',
+        smlSubdomain: '',
+        domainCode: '',
+        processSchema: '',
+        processIdentifier: '',
+        endpointUrl:  '',
+        endpointCertificate: '',
+        status: SearchTableEntityStatus.NEW,
+      };
+
+    this.dialogForm = fb.group({
+
+      '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),
+
+    });
+
   }
 
 }
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 c6c2b94be..ab2123729 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
@@ -1,9 +1,14 @@
 import {SearchTableEntity} from "../common/search-table/search-table-entity.model";
-import {ServiceGroupDetailsDialogComponent} from "./service-group-details-dialog/service-group-details-dialog.component";
+
 
 export interface ServiceMetadataEditRo extends SearchTableEntity  {
   documentIdentifier: string;
-  documentIdentifierScheme: string;
+  documentIdentifierScheme : string;
   smlSubdomain: string;
   domainCode: string;
+  processSchema: string;
+  processIdentifier: string;
+  endpointUrl: string;
+  endpointCertificate: string;
+
 }
diff --git a/smp-angular/src/app/service-group-search/service-group-search.component.css b/smp-angular/src/app/service-group-search/service-group-search.component.css
index d1a612141..65c9eab51 100644
--- a/smp-angular/src/app/service-group-search/service-group-search.component.css
+++ b/smp-angular/src/app/service-group-search/service-group-search.component.css
@@ -5,8 +5,8 @@
 
 /* --- Button  ---*/
 .group-btn {
-   margin-top:20px;
- }
+  margin-top:20px;
+}
 
 #hiddenButtonId {
   position: fixed;
@@ -16,3 +16,19 @@
 .datatable-body{
   overflow-y: scroll;
 }
+
+
+/deep/ .inner-table {
+  margin-left: 100px;
+  width: 80%;
+}
+
+/deep/ .inner-table .datatable-body-cell {
+  padding:  1.5em 2px !important;
+
+}
+
+/deep/ .inner-table .mat-icon-button {
+  height: auto !important;;
+  line-height: unset !important;
+}
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 ab20e7b28..190aeca38 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
@@ -11,8 +11,6 @@
   [showActionButtons]="false"
   [showIndexColumn]="true"
 >
-
-
   <ng-template #rowExtensionAction let-row="row" let-value="value" ngx-datatable-cell-template>
 
     <button mat-button color="primary"
@@ -25,8 +23,7 @@
 
   <ng-template #rowSMPUrlLinkAction let-row="row" let-value="value" ngx-datatable-cell-template>
     <a target="_blank"
-       href="{{contextPath}}{{row.participantScheme}}::{{row.participantIdentifier}}" >Open URL</a>
-
+       href="{{contextPath}}{{row.participantScheme}}::{{row.participantIdentifier}}">Open URL</a>
   </ng-template>
 
 
@@ -40,25 +37,18 @@
       <input matInput placeholder="Participant scheme" name="patricipantScheme" [(ngModel)]="filter.participantScheme"
              #messageId="ngModel" id="participantScheme">
     </mat-form-field>
-    <mat-select placeholder="Domain " [(ngModel)]="filter.domain" name="domain"
+    <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.smlSubdomain">
-        {{domain.smlSubdomain}}
+      <mat-option *ngFor="let domain of domainlist" [value]="domain.domainCode">
+        {{domain.domainCode}} ({{domain.smlSubdomain}})
       </mat-option>
     </mat-select>
   </ng-template>
 
 
-
-
   <ng-template #additionalToolButtons>
-    <!-- button mat-raised-button color="primary"
-            id="extensionbutton_id">
-      <mat-icon>code</mat-icon>
-      <span>Extension</span>
-    </button -->
   </ng-template>
 
   <ng-template #tableRowDetailContainer let-row="row">
@@ -66,24 +56,28 @@
     <div *ngIf="row.serviceMetadata.length===0" style="padding-left:20px;">
       No service metadata
     </div>
-    <div *ngIf="row.serviceMetadata.length !== 0" >
+    <div *ngIf="row.serviceMetadata.length !== 0">
       <ngx-datatable
         class='material striped'
         style="width: 80%"
         [loadingIndicator]="loading"
         [rows]='row.serviceMetadata'
-         [columnMode]='"force"'
+        [columnMode]='"force"'
         [headerHeight]='50'
         [footerHeight]='50'
         [rowHeight]='"auto"'>
-        <ngx-datatable-column prop="domainCode" name="Domain" maxWidth="250" ></ngx-datatable-column>
-        <ngx-datatable-column prop="documentIdentifierScheme" name="Document identifier scheme" maxWidth="350" ></ngx-datatable-column>
-        <ngx-datatable-column prop="documentIdentifier" name="Document identifier" maxWidth="250" ></ngx-datatable-column>
-        <ngx-datatable-column [cellTemplate]="rowMetadataSMPUrlLinkAction" name="URL" maxWidth="250" ></ngx-datatable-column>
+        <ngx-datatable-column prop="domainCode" name="Domain" maxWidth="250"></ngx-datatable-column>
+        <ngx-datatable-column prop="documentIdentifierScheme" name="Document identifier scheme"
+                              maxWidth="350"></ngx-datatable-column>
+        <ngx-datatable-column prop="documentIdentifier" name="Document identifier"
+                              maxWidth="250"></ngx-datatable-column>
+        <ngx-datatable-column [cellTemplate]="rowMetadataSMPUrlLinkAction" name="URL"
+                              maxWidth="250"></ngx-datatable-column>
 
         <ng-template #rowMetadataSMPUrlLinkAction let-rowSmd="row" ngx-datatable-cell-template>
           <a target="_blank"
-             href="{{contextPath}}{{row.participantScheme}}::{{row.participantIdentifier}}/services/{{rowSmd.documentIdentifierScheme}}::{{rowSmd.documentIdentifier}}" >Open URL</a>
+             href="{{contextPath}}{{row.participantScheme}}::{{row.participantIdentifier}}/services/{{rowSmd.documentIdentifierScheme}}::{{rowSmd.documentIdentifier}}">Open
+            URL</a>
         </ng-template>
       </ngx-datatable>
 
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 04d95e9f0..bc8111bc7 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
@@ -9,10 +9,11 @@ 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";
 
 @Component({
   moduleId: module.id,
-  templateUrl:'./service-group-search.component.html',
+  templateUrl: './service-group-search.component.html',
   styleUrls: ['./service-group-search.component.css']
 })
 export class ServiceGroupSearchComponent implements OnInit {
@@ -25,20 +26,11 @@ export class ServiceGroupSearchComponent implements OnInit {
   serviceGroupSearchController: ServiceGroupSearchController;
   filter: any = {};
   domainlist: Array<any>;
-  domainObserver:  Observable< SearchTableResult> ;
-  contextPath: string = location.pathname.substring(0,location.pathname.length -3); // remove /ui s
+  contextPath: string = location.pathname.substring(0, location.pathname.length - 3); // remove /ui s
   baseUrl: string = SmpConstants.REST_SEARCH;
 
-  constructor(protected http: HttpClient, protected alertService: AlertService, public dialog: MatDialog) {
-    this.domainObserver = this.http.get<SearchTableResult>(SmpConstants.REST_DOMAIN);
-    this.domainObserver.subscribe((domains: SearchTableResult) => {
-      this.domainlist = new Array(domains.serviceEntities.length)
-        .map((v, index) => domains.serviceEntities[index] as DomainRo);
+  constructor(protected lookups: GlobalLookups, protected http: HttpClient, protected alertService: AlertService, public dialog: MatDialog) {
 
-      this.domainlist = domains.serviceEntities.map(serviceEntity => {
-        return {...serviceEntity}
-      });
-    });
   }
 
   ngOnDestroy() {
@@ -46,6 +38,15 @@ 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);
 
     this.columnPicker.allColumns = [
@@ -71,18 +72,11 @@ export class ServiceGroupSearchComponent implements OnInit {
         maxWidth: 250,
         sortable: false
       },
-      /*
-      {
-        cellTemplate: this.rowExtensionAction,
-        name: 'Extension',
-        width: 80,
-        sortable: false
-      }*/
     ];
 
 
     this.columnPicker.selectedColumns = this.columnPicker.allColumns.filter(col => {
-      return ["Metadata size", "Participant scheme", "Participant identifier","OASIS ServiceGroup URL"].indexOf(col.name) != -1
+      return ["Metadata size", "Participant scheme", "Participant identifier", "OASIS ServiceGroup URL"].indexOf(col.name) != -1
     });
   }
 
diff --git a/smp-angular/src/app/smp.constants.ts b/smp-angular/src/app/smp.constants.ts
index f78f13a5f..e0b6974de 100644
--- a/smp-angular/src/app/smp.constants.ts
+++ b/smp-angular/src/app/smp.constants.ts
@@ -4,4 +4,6 @@ export class SmpConstants {
   public static readonly REST_USER = 'rest/user';
   public static readonly REST_SEARCH = 'rest/search';
   public static readonly REST_EDIT = 'rest/servicegroup';
+  public static readonly REST_METADATA = 'rest/servicemetadata';
+
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/BaseDao.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/BaseDao.java
index f941d6f16..2a92ab63f 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/BaseDao.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/BaseDao.java
@@ -14,6 +14,7 @@
 package eu.europa.ec.edelivery.smp.data.dao;
 
 import eu.europa.ec.edelivery.smp.data.model.BaseEntity;
+import eu.europa.ec.edelivery.smp.exceptions.SMPTestIsALiveException;
 import eu.europa.ec.edelivery.smp.logging.SMPLogger;
 import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
 import eu.europa.ec.edelivery.smp.services.ServiceGroupService;
@@ -65,10 +66,12 @@ public abstract class BaseDao<E extends BaseEntity> {
      * @param entity
      */
     @Transactional
-    public void testPersist(E entity, String message) {
+    public void testPersist(E entity, boolean rollbackWithException, String message) {
         memEManager.persist(entity);
         memEManager.flush();
-        throw new RuntimeException(message);
+        if (rollbackWithException) {
+            throw new SMPTestIsALiveException(message);
+        }
     }
 
 
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDao.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDao.java
index cd58acc6f..2d4c3827b 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDao.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDao.java
@@ -12,14 +12,21 @@
  */
 
 package eu.europa.ec.edelivery.smp.data.dao;
+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.exceptions.ErrorCode;
+import eu.europa.ec.edelivery.smp.services.ui.filters.ServiceGroupFilter;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Repository;
 
 import javax.persistence.NoResultException;
 import javax.persistence.NonUniqueResultException;
 import javax.persistence.TypedQuery;
+import javax.persistence.criteria.*;
 import javax.transaction.Transactional;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Optional;
 
 /**
@@ -81,7 +88,81 @@ public class ServiceGroupDao extends BaseDao<DBServiceGroup> {
         memEManager.remove(memEManager.contains(dbServiceGroup) ? dbServiceGroup : memEManager.merge(dbServiceGroup));
     }
 
+    public long getServiceGroupCount(ServiceGroupFilter filters, DBDomain domain) {
 
+        CriteriaQuery<Long> cqCount = createSearchCriteria(filters, true,
+                null,
+                null, domain);
+        return memEManager.createQuery(cqCount).getSingleResult();
+    }
+
+    public List<DBServiceGroup> getServiceGroupList(int startingAt, int maxResultCnt,
+                               String sortField,
+                               String sortOrder, ServiceGroupFilter filters, DBDomain domain) {
+
+        List<DBServiceGroup> lstResult;
+        try {
+            CriteriaQuery<DBServiceGroup> cq = createSearchCriteria(filters,
+                    false, sortField,
+                    sortOrder, domain);
+            TypedQuery<DBServiceGroup> q = memEManager.createQuery(cq);
+            if (maxResultCnt > 0) {
+                q.setMaxResults(maxResultCnt);
+            }
+            if (startingAt > 0) {
+                q.setFirstResult(startingAt);
+            }
+            lstResult = q.getResultList();
+        } catch (NoResultException ex) {
+            //LOG.warn("No result for '" + filterType.getName() + "' does not have a setter!", ex);
+            lstResult = new ArrayList<>();
+        }
+        return lstResult;
+    }
+
+    protected  CriteriaQuery createSearchCriteria(ServiceGroupFilter searchParams,
+                                                  boolean forCount, String sortField, String sortOrder, DBDomain domain) {
+        CriteriaBuilder cb = memEManager.getCriteriaBuilder();
+        CriteriaQuery cq = forCount ? cb.createQuery(Long.class) : cb.createQuery(DBServiceGroup.class);
+        Root<DBServiceGroup> serviceGroup = cq.from(DBServiceGroup.class);
+        if (forCount) {
+            cq.select(cb.count(serviceGroup));
+        } else if (sortField != null) {
+            if (sortOrder != null && sortOrder.equalsIgnoreCase("desc")) {
+                cq.orderBy(cb.asc(serviceGroup.get(sortField)));
+            } else {
+                cq.orderBy(cb.desc(serviceGroup.get(sortField)));
+            }
+        } else {
+            if (!StringUtils.isBlank(defaultSortMethod)) {
+                cq.orderBy(cb.desc(serviceGroup.get(defaultSortMethod)));
+            }
+        }
+
+       // Join<DBServiceGroupDomain, DBDomain> serviceGroupDomainJoinDomain = null;
+        Join<DBServiceGroup, DBServiceGroupDomain> serviceGroupJoinServiceGroupDomain = null;
+        //Join<DBServiceGroupDomain, DBDomain> serviceGroupDomainJoinDomain = null;
+        if (domain!=null){
+            serviceGroupJoinServiceGroupDomain =  serviceGroup.join("serviceGroupDomains", JoinType.INNER);
+            serviceGroupJoinServiceGroupDomain = serviceGroupJoinServiceGroupDomain.on(cb.equal(serviceGroupJoinServiceGroupDomain.get("domain"), domain));
+        }
+
+
+        // set order by
+        if (searchParams != null) {
+            List<Predicate> lstPredicate = createPredicates(searchParams, serviceGroup, cb);
+
+            if (serviceGroupJoinServiceGroupDomain!=null) {
+                lstPredicate.add(serviceGroupJoinServiceGroupDomain.getOn());
+            }
+
+            if (!lstPredicate.isEmpty()) {
+                Predicate[] tblPredicate = lstPredicate.stream().toArray(Predicate[]::new);
+                cq.where(cb.and(tblPredicate));
+            }
+        }
+        return cq;
+    }
 
 
 
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 d47915011..9e5fc783b 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
@@ -46,6 +46,10 @@ public class DBServiceGroupDomain extends BaseEntity {
 
     // list<> and set<> does not make any difference in hi
     // hibernate performance this case!
+    // this list could also be on ServiceGroup entity because it does not make any difference for
+    // dynamic discovery but it is here just user -service group admin to know for which
+    // domain he orignally registred a service - to make metadata more organized...
+
     @OneToMany(mappedBy = "serviceGroupDomain", cascade = CascadeType.ALL,
             orphanRemoval = true,
             fetch = FetchType.LAZY)
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 f47c78dc5..6d8605402 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
@@ -17,6 +17,8 @@ public class ServiceMetadataRO extends BaseRO {
     String smlSubdomain;
     String domainCode;
 
+    String xmlContent;
+
     public String getDocumentIdentifier() {
         return documentIdentifier;
     }
@@ -48,4 +50,12 @@ public class ServiceMetadataRO extends BaseRO {
     public void setDomainCode(String domainCode) {
         this.domainCode = domainCode;
     }
+
+    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/SMPTestIsALiveException.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/SMPTestIsALiveException.java
new file mode 100644
index 000000000..56e2841a6
--- /dev/null
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/exceptions/SMPTestIsALiveException.java
@@ -0,0 +1,12 @@
+package eu.europa.ec.edelivery.smp.exceptions;
+
+/**
+ * Exception for testing database connection - rollback exception
+ */
+public class SMPTestIsALiveException extends RuntimeException  {
+
+    public SMPTestIsALiveException(String message ) {
+        super(message);
+    }
+
+}
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/logging/SMPMessageCode.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/logging/SMPMessageCode.java
index aeb63d031..7db631120 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/logging/SMPMessageCode.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/logging/SMPMessageCode.java
@@ -16,18 +16,19 @@ public enum SMPMessageCode implements MessageCode {
     BUS_HTTP_DELETE_END_SERVICE_GROUP ("BUS-004", "End Http DELETE ServiceGroup from user {} from host: {}. ServiceGroup id: {}."),
     BUS_HTTP_GET_SERVICE_GROUP ("BUS-005", "Http GET ServiceGroup from host: {}, ServiceGroup id: {}."),
     BUS_HTTP_GET_END_SERVICE_GROUP ("BUS-006", "End Http GET ServiceGroup from host: {}, ServiceGroup id: {}."),
+    BUS_HTTP_GET_END_STATIC_CONTENT ("BUS-007", "End Http GET static content from host: {}, Path: {}."),
 
 
-    BUS_HTTP_PUT_SERVICE_METADATA ("BUS-007", "Http PUT ServiceGroupMetadata from user {} from host: {}. ServiceGroup with domain: {}, ServiceGroup id: {} , metadata id {}."),
-    BUS_HTTP_PUT_END_SERVICE_METADATA ("BUS-008", "End http PUT ServiceGroupMetadata from user {}, host: {}. ServiceGroup with domain {}, ServiceGroup id: {} , metadata id {}, created {}"),
-    BUS_HTTP_DELETE_SERVICE_METADATA ("BUS-009", "Http DELETE ServiceGroupMetadata from user {} from host: {}. ServiceGroup id: {} , metadata id {}."),
-    BUS_HTTP_DELETE_END_SERVICE_METADATA ("BUS-010", "End Http DELETE ServiceGroupMetadata from user {} from host: {}. ServiceGroup id: {} , metadata id {}."),
+    BUS_HTTP_PUT_SERVICE_METADATA ("BUS-008", "Http PUT ServiceGroupMetadata from user {} from host: {}. ServiceGroup with domain: {}, ServiceGroup id: {} , metadata id {}."),
+    BUS_HTTP_PUT_END_SERVICE_METADATA ("BUS-009", "End http PUT ServiceGroupMetadata from user {}, host: {}. ServiceGroup with domain {}, ServiceGroup id: {} , metadata id {}, created {}"),
+    BUS_HTTP_DELETE_SERVICE_METADATA ("BUS-010", "Http DELETE ServiceGroupMetadata from user {} from host: {}. ServiceGroup id: {} , metadata id {}."),
+    BUS_HTTP_DELETE_END_SERVICE_METADATA ("BUS-011", "End Http DELETE ServiceGroupMetadata from user {} from host: {}. ServiceGroup id: {} , metadata id {}."),
 
-    BUS_HTTP_GET_SERVICE_METADATA ("BUS-011", "Http GET ServiceGroup from host: {}, ServiceGroup id: {}, metadata id {}."),
-    BUS_HTTP_GET_END_SERVICE_METADATA ("BUS-012", "End Http GET ServiceGroup from host: {}, ServiceGroup id: {}, metadata id {}."),
+    BUS_HTTP_GET_SERVICE_METADATA ("BUS-012", "Http GET ServiceGroup from host: {}, ServiceGroup id: {}, metadata id {}."),
+    BUS_HTTP_GET_END_SERVICE_METADATA ("BUS-013", "End Http GET ServiceGroup from host: {}, ServiceGroup id: {}, metadata id {}."),
 
-    BUS_SAVE_SERVICE_GROUP ("BUS-013", "Start inserting/updating ServiceGroup for domain {}, part. Id: {} part. schema {}."),
-    BUS_SAVE_SERVICE_GROUP_FAILED ("BUS-014", "Inserting/updating ServiceGroup for domain {}, part. Id: {} part. schema {} failed! Error: [{}]"),
+    BUS_SAVE_SERVICE_GROUP ("BUS-014", "Start inserting/updating ServiceGroup for domain {}, part. Id: {} part. schema {}."),
+    BUS_SAVE_SERVICE_GROUP_FAILED ("BUS-015", "Inserting/updating ServiceGroup for domain {}, part. Id: {} part. schema {} failed! Error: [{}]"),
 
 
     BUS_INVALID_XML("BUS-030", "Invalid XML for {}. Error: [{}]"),
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 de751e9a9..3670a5651 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,8 +1,10 @@
 package eu.europa.ec.edelivery.smp.services.ui;
 
 import eu.europa.ec.edelivery.smp.data.dao.BaseDao;
+import eu.europa.ec.edelivery.smp.data.dao.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;
@@ -10,6 +12,10 @@ import eu.europa.ec.edelivery.smp.data.ui.ServiceMetadataRO;
 import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
 import eu.europa.ec.edelivery.smp.data.ui.UserRO;
 import eu.europa.ec.edelivery.smp.data.ui.enums.EntityROStatus;
+import 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 org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -17,10 +23,14 @@ import org.springframework.transaction.annotation.Transactional;
 import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 
 @Service
 public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, ServiceGroupRO> {
+    private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UIServiceGroupService.class);
 
+    @Autowired
+    DomainDao domainDao;
 
     @Autowired
     ServiceGroupDao serviceGroupDao;
@@ -45,18 +55,30 @@ public class UIServiceGroupService extends UIServiceBase<DBServiceGroup, Service
      */
     @Transactional
     public ServiceResult<ServiceGroupRO> getTableList(int page, int pageSize,
-                                                 String sortField,
-                                                 String sortOrder, Object filter) {
+                                                      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 {
+                LOG.error("Domain with code {} does not exists ", domainCode);
+            }
+
+        }
+
 
         ServiceResult<ServiceGroupRO> sg = new ServiceResult<>();
         sg.setPage(page < 0 ? 0 : page);
         sg.setPageSize(pageSize);
-        long iCnt = getDatabaseDao().getDataListCount(filter);
+        long iCnt = serviceGroupDao.getServiceGroupCount(filter, d);
         sg.setCount(iCnt);
 
         if (iCnt > 0) {
             int iStartIndex = pageSize < 0 ? -1 : page * pageSize;
-            List<DBServiceGroup> lst = getDatabaseDao().getDataList(iStartIndex, pageSize, sortField, sortOrder, filter);
+            List<DBServiceGroup> lst = serviceGroupDao.getServiceGroupList(iStartIndex, pageSize, sortField, sortOrder, filter, d);
 
             List<ServiceGroupRO> lstRo = new ArrayList<>();
             for (DBServiceGroup dbServiceGroup : lst) {
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/filters/ServiceGroupFilter.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/filters/ServiceGroupFilter.java
similarity index 91%
rename from smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/filters/ServiceGroupFilter.java
rename to smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/filters/ServiceGroupFilter.java
index 8e2fa893e..08e5a2543 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/filters/ServiceGroupFilter.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/filters/ServiceGroupFilter.java
@@ -1,4 +1,4 @@
-package eu.europa.ec.edelivery.smp.ui.filters;
+package eu.europa.ec.edelivery.smp.services.ui.filters;
 
 public class ServiceGroupFilter {
     private String participantIdentifier;
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDaoIntegrationBase.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDaoIntegrationBase.java
index af6e2beb9..89daa0fda 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDaoIntegrationBase.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDaoIntegrationBase.java
@@ -5,6 +5,7 @@ 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.model.DBUser;
+import eu.europa.ec.edelivery.smp.testutil.TestConstants;
 import eu.europa.ec.edelivery.smp.testutil.TestDBUtils;
 import org.junit.Before;
 import org.junit.Rule;
@@ -56,14 +57,28 @@ public abstract class ServiceGroupDaoIntegrationBase extends AbstractBaseDao{
 
    @Transactional
    public DBServiceGroup createAndSaveNewServiceGroup(){
+       return createAndSaveNewServiceGroup(TEST_DOMAIN_CODE_1, TestConstants.TEST_SG_ID_1, TestConstants.TEST_SG_SCHEMA_1);
+   }
 
-       DBDomain d = domainDao.getDomainByCode(TEST_DOMAIN_CODE_1).get();
-       DBServiceGroup sg = TestDBUtils.createDBServiceGroup();
+   private DBServiceGroup createAndSaveNewServiceGroup(String domain, String participantId, String participantSchema){
+       DBDomain d = domainDao.getDomainByCode(domain).get();
+       DBServiceGroup sg = TestDBUtils.createDBServiceGroup(participantId, participantSchema);
        sg.addDomain(d);
        testInstance.persistFlushDetach(sg);
        return sg;
    }
 
+
+    @Transactional
+    public void createAndSaveNewServiceGroups(int iCount, String domain, String participant){
+
+        int i =0;
+        while (i++ < iCount){
+            createAndSaveNewServiceGroup(domain,  participant+":"+i, TestConstants.TEST_SG_SCHEMA_1);
+
+        }
+    }
+
     @Transactional
     public DBServiceGroup createAndSaveNewServiceGroupWithMetadata(){
 
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDaoIntegrationTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDaoIntegrationTest.java
index a59b51b75..1451cc3ac 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDaoIntegrationTest.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ServiceGroupDaoIntegrationTest.java
@@ -2,6 +2,8 @@ package eu.europa.ec.edelivery.smp.data.dao;
 
 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.ui.ServiceGroupRO;
+import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
 import eu.europa.ec.edelivery.smp.testutil.TestConstants;
 import eu.europa.ec.edelivery.smp.testutil.TestDBUtils;
 import org.junit.Test;
@@ -10,6 +12,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
 import javax.transaction.Transactional;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Optional;
 import java.util.UUID;
 
@@ -160,4 +163,50 @@ public class ServiceGroupDaoIntegrationTest extends ServiceGroupDaoIntegrationBa
         assertFalse(optResDel.isPresent());
     }
 
+    @Test
+    public void testGetServiceGroupListNotEmpty(){
+        // given
+        // add additional domain
+        DBDomain d2 = TestDBUtils.createDBDomain(TEST_DOMAIN_CODE_2);
+        domainDao.persistFlushDetach(d2);
+        createAndSaveNewServiceGroups(10, TEST_DOMAIN_CODE_1, TestConstants.TEST_SG_ID_1);
+        createAndSaveNewServiceGroups(5, TEST_DOMAIN_CODE_2, TestConstants.TEST_SG_ID_2);
+        //when
+        List<DBServiceGroup> res = testInstance.getServiceGroupList(-1,-1,null, null,null, null);
+        // then
+        assertNotNull(res);
+        assertEquals(15, res.size());
+
+    }
+
+    @Test
+    public void testGetServiceGroupListByDomain(){
+        // given
+        // add additional domain
+        DBDomain d2 = TestDBUtils.createDBDomain(TEST_DOMAIN_CODE_2);
+        domainDao.persistFlushDetach(d2);
+        createAndSaveNewServiceGroups(10, TEST_DOMAIN_CODE_1, TestConstants.TEST_SG_ID_1);
+        createAndSaveNewServiceGroups(5, TEST_DOMAIN_CODE_2, TestConstants.TEST_SG_ID_2);
+
+        //when
+        List<DBServiceGroup> res = testInstance.getServiceGroupList(-1,-1,null, null,null, d2);
+        // then
+        assertNotNull(res);
+        assertEquals(5, res.size());
+
+    }
+
+    @Test
+    public void testGetTableListEmpty(){
+
+        // given
+
+        //when
+        List<DBServiceGroup> res = testInstance.getServiceGroupList(-1,-1,null, null,null, null);
+        // then
+        assertNotNull(res);
+        assertTrue(res.isEmpty());
+
+    }
+
 }
\ No newline at end of file
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SmpWebAppConfig.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SmpWebAppConfig.java
index da24d8c4e..91141c049 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SmpWebAppConfig.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/config/SmpWebAppConfig.java
@@ -34,15 +34,14 @@ import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;
         "eu.europa.ec.edelivery.smp.ui"})
 @Import({GlobalMethodSecurityConfig.class, ErrorMappingControllerAdvice.class})
 public class SmpWebAppConfig implements WebMvcConfigurer {
-
+/*
     @Override
     public void addViewControllers(ViewControllerRegistry registry) {
         registry.addViewController("/").setViewName("/index.html");
         registry.addViewController("/ui/").setViewName("/ui/index.html");
-
         //Home page used by SMP 2.x and 3.x - needed for backward compatibility in some EC's environments
         registry.addViewController("/web/index.html").setViewName("/index.html");
-    }
+    }*/
 
     @Override
     public void addResourceHandlers(ResourceHandlerRegistry registry) {
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/RootController.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/RootController.java
new file mode 100644
index 000000000..0384287dc
--- /dev/null
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/controllers/RootController.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017 European Commission | CEF eDelivery
+ *
+ * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ *
+ * You may obtain a copy of the Licence attached in file: LICENCE-EUPL-v1.2.pdf
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and limitations under the Licence.
+ */
+
+package eu.europa.ec.edelivery.smp.controllers;
+
+import eu.europa.ec.edelivery.smp.logging.SMPLogger;
+import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
+import eu.europa.ec.edelivery.smp.logging.SMPMessageCode;
+import org.apache.commons.lang.StringUtils;
+import org.apache.cxf.helpers.IOUtils;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.MediaType;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;
+import static org.springframework.core.Ordered.LOWEST_PRECEDENCE;
+
+
+@RestController
+@RequestMapping("/")
+public class RootController {
+
+    private static final SMPLogger LOG = SMPLoggerFactory.getLogger(RootController.class);
+
+
+    @GetMapping( produces = MediaType.TEXT_HTML_VALUE, value={"", "/", "web/index.html","index.html"})
+    @Order(HIGHEST_PRECEDENCE)
+    public byte[] getServiceGroup(HttpServletRequest httpReq) throws IOException {
+        String host = httpReq.getRemoteHost();
+        LOG.businessInfo(SMPMessageCode.BUS_HTTP_GET_END_STATIC_CONTENT,host,httpReq.getPathInfo());
+        return IOUtils.readBytesFromStream(RootController.class.getResourceAsStream("/index.html"));
+    }
+
+    /**
+     * redirect angular pages to index.html
+     * solve the 404 error on refresh
+     * @param model
+     * @return
+*/
+    //@GetMapping(value={"/ui","/ui/edit","/ui/search","/ui/search","/ui/domain","/ui/user"})
+    @GetMapping(value={"/ui"})
+    public ModelAndView redirectWithUsingRedirectPrefix(ModelMap model) {
+        return new ModelAndView("redirect:/ui/index.html", model);
+    }
+
+    public String getRemoteHost(HttpServletRequest httpReq){
+        String host = httpReq.getHeader("X-Forwarded-For");
+        return StringUtils.isBlank(host)?httpReq.getRemoteHost():host;
+    }
+}
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 96850dbca..0c17693b9 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
@@ -7,12 +7,14 @@ 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.model.DBDomain;
 import eu.europa.ec.edelivery.smp.data.model.DBServiceGroup;
+import eu.europa.ec.edelivery.smp.exceptions.SMPTestIsALiveException;
 import eu.europa.ec.edelivery.smp.logging.SMPLogger;
 import eu.europa.ec.edelivery.smp.logging.SMPLoggerFactory;
 import eu.europa.ec.edelivery.smp.services.ServiceGroupService;
 import eu.europa.ec.edelivery.smp.validation.ServiceGroupValidator;
 import eu.europa.ec.smp.api.exceptions.XmlInvalidAgainstSchemaException;
 import eu.europa.ec.smp.api.validators.BdxSmpOasisValidator;
+import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.cxf.helpers.IOUtils;
 import org.oasis_open.docs.bdxr.ns.smp._2016._05.ServiceGroup;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -86,8 +88,10 @@ public class MonitorResource {
         boolean suc = false;
         try {
             suc= testDatabase();
-        }catch (Exception ex){
+        }catch (SMPTestIsALiveException ex){
             suc = Objects.equals(TEST_DB_SUCCESSFUL_ROLLBACK, ex.getMessage());
+        } catch(Throwable th) {
+            LOG.error("Error occured while testing database connection: Msg:" + ExceptionUtils.getRootCauseMessage(th), th);
         }
        return suc?ResponseEntity.ok().build():ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
 
@@ -107,7 +111,7 @@ public class MonitorResource {
         newSg.addDomain(lstDomain.get(0)); // add initial domain
         newSg.setSmlRegistered(false);
         // persist (make sure this is not in transaction)
-        serviceGroupDao.testPersist(newSg, TEST_DB_SUCCESSFUL_ROLLBACK);
+        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 db693136d..05af6c1b4 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
@@ -6,7 +6,7 @@ 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.ui.filters.ServiceGroupFilter;
+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;
@@ -50,6 +50,7 @@ public class SearchResource {
         ServiceGroupFilter sgf = new ServiceGroupFilter();
         sgf.setParticipantIdentifierLike(participantIdentifier);
         sgf.setParticipantSchemeLike(participantScheme);
-        return uiServiceGroupService.getTableList(page,pageSize, orderBy, orderType, sgf );
+
+        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 543657db9..0c7f620e0 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
@@ -7,12 +7,13 @@ 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;
 
 /**
@@ -24,7 +25,7 @@ import java.util.Arrays;
 @RequestMapping(value = "/ui/rest/servicegroup")
 public class ServiceGroupResource {
 
-    private static final SMPLogger LOG = SMPLoggerFactory.getLogger(DomainResource.class);
+    private static final SMPLogger LOG = SMPLoggerFactory.getLogger(ServiceGroupResource.class);
 
     @Autowired
     private UIServiceGroupService uiServiceGroupService;
@@ -42,11 +43,16 @@ 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 participantId,
-            @RequestParam(value = "participantSchema", required = false) String participantSchema,
+            @RequestParam(value = "participantId", required = false) String participantIdentifier,
+            @RequestParam(value = "participantSchema", required = false) String participantScheme,
             @RequestParam(value = "domain", required = false) String domain
     ) {
-        return uiServiceGroupService.getTableList(page, pageSize, orderBy, orderType, null);
+        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);
     }
 
     @ResponseBody
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/exception/UIException.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/exception/UIException.java
new file mode 100644
index 000000000..0cb934e4b
--- /dev/null
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/exception/UIException.java
@@ -0,0 +1,28 @@
+package eu.europa.ec.edelivery.smp.ui.exception;
+
+import org.springframework.http.HttpStatus;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class UIException {
+
+
+        private HttpStatus status;
+        private String message;
+        private List<String> errors;
+
+        public UIException(HttpStatus status, String message, List<String> errors) {
+            super();
+            this.status = status;
+            this.message = message;
+            this.errors = errors;
+        }
+
+        public UIException(HttpStatus status, String message, String error) {
+            super();
+            this.status = status;
+            this.message = message;
+            errors = Arrays.asList(error);
+        }
+    }
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/validation/ServiceMetadataValidator.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/validation/ServiceMetadataValidator.java
index 219fe5922..202a26d9c 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/validation/ServiceMetadataValidator.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/validation/ServiceMetadataValidator.java
@@ -74,6 +74,34 @@ public class ServiceMetadataValidator {
         validateServiceInformation(serviceInformation);
     }
 
+    public ServiceInformationType validate(String serviceGroupIdStr,
+                         byte[] serviceMetadataBody
+    ) throws XmlInvalidAgainstSchemaException {
+
+        BdxSmpOasisValidator.validateXSD(serviceMetadataBody);
+
+        ParticipantIdentifierType serviceGroupId = asParticipantId(serviceGroupIdStr);
+        ServiceMetadata serviceMetadata = ServiceMetadataConverter.unmarshal(serviceMetadataBody);
+        ServiceInformationType serviceInformation = serviceMetadata.getServiceInformation();
+
+        if (serviceInformation == null) {
+            String errorMessage = "Missing service information";
+            throw new BadRequestException(WRONG_FIELD, errorMessage);
+        }
+
+
+
+        if (!serviceGroupId.equals(serviceInformation.getParticipantIdentifier())) {
+            String errorMessage = String.format("Save service metadata was called with bad Participant ID parameters. Message body param: %s URL param: %s",
+                    asString(serviceInformation.getParticipantIdentifier()),
+                    asString(serviceGroupId));
+            log.info(errorMessage);
+            throw new BadRequestException(WRONG_FIELD, errorMessage);
+        }
+        validateServiceInformation(serviceInformation);
+        return serviceInformation;
+    }
+
     private void validateServiceInformation(ServiceInformationType serviceInformation) {
         ProcessListType processList = serviceInformation.getProcessList();
         if (processList == null) {
diff --git a/smp-webapp/src/main/resources/index.html b/smp-webapp/src/main/resources/index.html
new file mode 100644
index 000000000..3f5273e65
--- /dev/null
+++ b/smp-webapp/src/main/resources/index.html
@@ -0,0 +1,32 @@
+<!--
+  ~ Copyright 2017 European Commission | CEF eDelivery
+  ~
+  ~ Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent versions of the EUPL (the "Licence");
+  ~ You may not use this work except in compliance with the Licence.
+  ~
+  ~ You may obtain a copy of the Licence attached in file: LICENCE-EUPL-v1.2.pdf
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software distributed under the Licence is distributed on an "AS IS" basis,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the Licence for the specific language governing permissions and limitations under the Licence.
+  -->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+    <title>SMP</title>
+    <link rel="shortcut icon" href="favicon-16x16.png" />
+    <style type="text/css">
+    body { font-family: Arial, Helvetica, sans-serif; }
+    a, a:link, a:visited, a:hover, a:active { color: blue; }
+    </style>
+  </head>
+  <body>
+    <h1>SMP (Service Metadata Publishing)</h1>
+    <h2>Version: ${project.version}</h2>
+    <h6>Build timestamp: ${buildtimestamp}</h6>
+    <h6>Specification: <a href="http://docs.oasis-open.org/bdxr/bdx-smp/v1.0/bdx-smp-v1.0.html" target="_blank">http://docs.oasis-open.org/bdxr/bdx-smp/v1.0/bdx-smp-v1.0.html</a></h6>
+    <h6>UI: <a href="ui/index.html" target="_blank">eDelivery SMP</a></h6>
+  </body>
+</html>
diff --git a/smp-webapp/src/main/webapp/index.html b/smp-webapp/src/main/webapp/index.html
new file mode 100644
index 000000000..c870461f3
--- /dev/null
+++ b/smp-webapp/src/main/webapp/index.html
@@ -0,0 +1,31 @@
+<!--
+  ~ Copyright 2017 European Commission | CEF eDelivery
+  ~
+  ~ Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent versions of the EUPL (the "Licence");
+  ~ You may not use this work except in compliance with the Licence.
+  ~
+  ~ You may obtain a copy of the Licence attached in file: LICENCE-EUPL-v1.2.pdf
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software distributed under the Licence is distributed on an "AS IS" basis,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the Licence for the specific language governing permissions and limitations under the Licence.
+  -->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+    <title>SMP</title>
+    <link rel="shortcut icon" href="favicon-16x16.png" />
+    <style type="text/css">
+    body { font-family: Arial, Helvetica, sans-serif; }
+    a, a:link, a:visited, a:hover, a:active { color: blue; }
+    </style>
+  </head>
+  <body>
+    <h1>SMP (Service Metadata Publishing)</h1>
+    <h2>Version: ${project.version}</h2>
+    <h6>Build timestamp: ${buildtimestamp}</h6>
+    <h6>Specification: <a href="http://docs.oasis-open.org/bdxr/bdx-smp/v1.0/bdx-smp-v1.0.html" target="_blank">http://docs.oasis-open.org/bdxr/bdx-smp/v1.0/bdx-smp-v1.0.html</a></h6>
+  </body>
+</html>
diff --git a/smp-webapp/src/main/webapp/static_resources/index.html b/smp-webapp/src/main/webapp/static_resources/index.html
index c870461f3..3f5273e65 100644
--- a/smp-webapp/src/main/webapp/static_resources/index.html
+++ b/smp-webapp/src/main/webapp/static_resources/index.html
@@ -27,5 +27,6 @@
     <h2>Version: ${project.version}</h2>
     <h6>Build timestamp: ${buildtimestamp}</h6>
     <h6>Specification: <a href="http://docs.oasis-open.org/bdxr/bdx-smp/v1.0/bdx-smp-v1.0.html" target="_blank">http://docs.oasis-open.org/bdxr/bdx-smp/v1.0/bdx-smp-v1.0.html</a></h6>
+    <h6>UI: <a href="ui/index.html" target="_blank">eDelivery SMP</a></h6>
   </body>
 </html>
diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/monitor/MonitorResourceTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/monitor/MonitorResourceTest.java
index b680d69b8..e85f8aeee 100644
--- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/monitor/MonitorResourceTest.java
+++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/monitor/MonitorResourceTest.java
@@ -4,6 +4,7 @@ import eu.europa.ec.edelivery.smp.config.PropertiesTestConfig;
 import eu.europa.ec.edelivery.smp.config.SmpAppConfig;
 import eu.europa.ec.edelivery.smp.config.SmpWebAppConfig;
 import eu.europa.ec.edelivery.smp.config.SpringSecurityConfig;
+import eu.europa.ec.edelivery.smp.exceptions.SMPTestIsALiveException;
 import eu.europa.ec.edelivery.smp.monitor.MonitorResource;
 import org.junit.Before;
 import org.junit.Rule;
@@ -95,7 +96,7 @@ public class MonitorResourceTest {
     public void testDatabase() {
         // given
         expectedEx.expectMessage("TEST_DB_SUCCESSFUL_ROLLBACK MESSAGE");
-        expectedEx.expect(RuntimeException.class);
+        expectedEx.expect(SMPTestIsALiveException.class);
         // when
         boolean bval = testInstance.testDatabase();
         //then
-- 
GitLab