From e79806f61eba1aba6336258a5ecb51006d589708 Mon Sep 17 00:00:00 2001
From: Sebastian-Ion TINCU <Sebastian-Ion.TINCU@ext.ec.europa.eu>
Date: Sun, 12 May 2024 12:17:29 +0200
Subject: [PATCH] EDELIVERY-12848 Implement additional search filters in the
 search page

Add extra filters for the domain code and the document type.
---
 smp-angular/src/app/app.module.ts             |  2 +
 .../services/resource-metadata.service.ts     | 15 +++++
 .../resource-search.component.html            | 29 +++++++--
 .../resource-search.component.ts              | 34 +++++++----
 smp-angular/src/app/smp.constants.ts          |  3 +-
 .../edelivery/smp/data/dao/DocumentDao.java   | 11 ++++
 .../ec/edelivery/smp/data/dao/DomainDao.java  | 10 ++++
 .../ec/edelivery/smp/data/dao/QueryNames.java |  3 +
 .../edelivery/smp/data/dao/ResourceDao.java   | 57 ++++++++++++++++--
 .../ec/edelivery/smp/data/model/DBDomain.java |  1 +
 .../smp/data/model/doc/DBDocument.java        |  2 +
 .../smp/data/model/doc/DBResource.java        | 14 +++--
 .../smp/data/ui/ServiceGroupSearchRO.java     |  9 +++
 .../services/ui/UIResourceSearchService.java  | 60 ++++++++++++-------
 .../services/ui/filters/ResourceFilter.java   | 16 +++++
 .../smp/data/dao/ResourceDaoSearchTest.java   | 44 +++++++-------
 .../edelivery/smp/ui/ResourceConstants.java   |  2 +
 .../smp/ui/external/SearchResource.java       | 20 +++++--
 18 files changed, 255 insertions(+), 77 deletions(-)
 create mode 100644 smp-angular/src/app/common/services/resource-metadata.service.ts

diff --git a/smp-angular/src/app/app.module.ts b/smp-angular/src/app/app.module.ts
index ad34702c5..ff91911dd 100644
--- a/smp-angular/src/app/app.module.ts
+++ b/smp-angular/src/app/app.module.ts
@@ -147,6 +147,7 @@ import {DnsToolsService} from "./tools/dns-tools/dns-tools.service";
 import {
   DnsQueryPanelComponent
 } from "./tools/dns-tools/dns-query-panel/dns-query-panel.component";
+import {ResourceMetadataService} from "./common/services/resource-metadata.service";
 
 
 @NgModule({
@@ -296,6 +297,7 @@ import {
     GlobalLookups,
     HttpEventService,
     NavigationService,
+    ResourceMetadataService,
     SecurityEventService,
     SecurityService,
     SmlIntegrationService,
diff --git a/smp-angular/src/app/common/services/resource-metadata.service.ts b/smp-angular/src/app/common/services/resource-metadata.service.ts
new file mode 100644
index 000000000..1f71f36e4
--- /dev/null
+++ b/smp-angular/src/app/common/services/resource-metadata.service.ts
@@ -0,0 +1,15 @@
+import {Injectable} from "@angular/core";
+import {HttpClient} from "@angular/common/http";
+import {Observable} from "rxjs";
+import {SmpConstants} from "../../smp.constants";
+import {ResourceMetadataRo} from "../model/resource-metadata-ro.model";
+
+@Injectable()
+export class ResourceMetadataService {
+
+  constructor(private http: HttpClient) { }
+
+  getResourceMetadata$(): Observable<ResourceMetadataRo> {
+    return this.http.get<ResourceMetadataRo>(SmpConstants.REST_PUBLIC_SEARCH_RESOURCE_METADATA);
+  }
+}
diff --git a/smp-angular/src/app/resource-search/resource-search.component.html b/smp-angular/src/app/resource-search/resource-search.component.html
index ecb41d8f4..666087b9a 100644
--- a/smp-angular/src/app/resource-search/resource-search.component.html
+++ b/smp-angular/src/app/resource-search/resource-search.component.html
@@ -16,7 +16,6 @@
        href="{{contextPath}}{{createResourceURL(row)}}">Open URL</a>
   </ng-template>
 
-
   <ng-template #searchPanel>
     <div style="display: flex;flex-direction: row;width: 100%">
     <mat-form-field class="smp-data-panel-field">
@@ -30,15 +29,37 @@
       <input matInput  name="ResourceScheme" [(ngModel)]="filter.participantScheme"
              #messageId="ngModel" id="ResourceScheme">
     </mat-form-field>
+    <mat-form-field class="smp-data-panel-field">
+      <mat-label>Domain</mat-label>
+      <mat-select placeholder="Domain"
+                  matTooltip="Domain"
+                  id="Domain"
+                  [(value)]="filter.domainCode">
+        <mat-option *ngFor="let domainCode of domainList"
+                    [value]="domainCode">
+          {{domainCode}}
+        </mat-option>
+      </mat-select>
+    </mat-form-field>
+      <mat-form-field class="smp-data-panel-field">
+        <mat-label>Document Type</mat-label>
+        <mat-select placeholder="Document type"
+                    matTootip="Document type"
+                    id="DocumentType"
+                    [(value)]="filter.documentType">
+          <mat-option *ngFor="let documentType of documentTypeList"
+                      [value]="documentType">
+            {{documentType}}
+          </mat-option>
+        </mat-select>
+      </mat-form-field>
     </div>
   </ng-template>
 
-
   <ng-template #additionalToolButtons>
   </ng-template>
 
   <ng-template #tableRowDetailContainer let-row="row">
-
     <div *ngIf="row.serviceMetadata.length===0" style="padding-left:20px;">
       No subresources
     </div>
@@ -64,8 +85,6 @@
             URL</a>
         </ng-template>
       </ngx-datatable>
-
     </div>
   </ng-template>
-
 </smp-search-table>
diff --git a/smp-angular/src/app/resource-search/resource-search.component.ts b/smp-angular/src/app/resource-search/resource-search.component.ts
index 9f78ec7bf..1e96a58c9 100644
--- a/smp-angular/src/app/resource-search/resource-search.component.ts
+++ b/smp-angular/src/app/resource-search/resource-search.component.ts
@@ -18,6 +18,8 @@ import {GlobalLookups} from "../common/global-lookups";
 import {SearchTableComponent} from "../common/search-table/search-table.component";
 import {ResourceSearchRo} from "./resource-search-ro.model";
 import {SubresourceSearchRo} from "./subresource-search-ro.model";
+import {ResourceMetadataService} from "../common/services/resource-metadata.service";
+import {ResourceMetadataRo} from "../common/model/resource-metadata-ro.model";
 
 @Component({
   templateUrl: './resource-search.component.html',
@@ -34,19 +36,29 @@ export class ResourceSearchComponent implements OnInit, AfterViewInit, AfterView
   filter: any = {};
   contextPath: string = location.pathname.substring(0, location.pathname.length - 3); // remove /ui s
   baseUrl: string;
+  domainList: string[];
+  documentTypeList: string[];
 
   constructor(protected lookups: GlobalLookups,
               protected http: HttpClient,
-              protected alertService:
-                AlertMessageService,
+              protected alertService: AlertMessageService,
               public dialog: MatDialog,
-              private changeDetector: ChangeDetectorRef) {
+              private changeDetector: ChangeDetectorRef,
+              private resourceMetadataService: ResourceMetadataService) {
 
     this.baseUrl = SmpConstants.REST_PUBLIC_SEARCH_RESOURCE;
   }
 
-  ngOnInit(): void {
-    this.resourceSearchController = new ResourceSearchController(this.dialog);
+  ngOnInit() {
+    this.resourceMetadataService.getResourceMetadata$().subscribe({
+      next: (value: ResourceMetadataRo) => {
+        this.domainList = value.availableDomains || [];
+        this.documentTypeList = value.availableDocumentTypes || [];
+
+        this.resourceSearchController = new ResourceSearchController(this.dialog);
+      },
+      error: (err) => this.alertService.exception('Error occurred while retrieving the resource metadata', err)
+    });
   }
 
   initColumns(): void {
@@ -82,6 +94,13 @@ export class ResourceSearchComponent implements OnInit, AfterViewInit, AfterView
         resizable: 'true',
         showInitially: true,
       },
+      {
+        name: 'Document type',
+        prop: 'documentType',
+        width: 450,
+        resizable: 'true',
+        showInitially: true,
+      },
       {
         cellTemplate: this.rowSMPUrlLinkAction,
         name: 'Resource URL',
@@ -103,23 +122,18 @@ export class ResourceSearchComponent implements OnInit, AfterViewInit, AfterView
   }
 
   createResourceURL(row: ResourceSearchRo) {
-
     return (!row?.domainCode? "" : row.domainCode+ '/')
           + (!row?.resourceDefUrlSegment?"" : row.resourceDefUrlSegment + '/')
           + encodeURIComponent((!row.participantScheme ? '' : row.participantScheme) + '::' + row.participantIdentifier);
   }
 
   createServiceMetadataURL(row: ResourceSearchRo, rowSMD: SubresourceSearchRo) {
-
     return this.createResourceURL(row)
             + '/' + rowSMD.subresourceDefUrlSegment + '/'
             + encodeURIComponent((!rowSMD.documentIdentifierScheme ? '' : rowSMD.documentIdentifierScheme) + '::' + rowSMD.documentIdentifier);
   }
 
-
-
   details(row: any) {
     this.resourceSearchController.showDetails(row);
-
   }
 }
diff --git a/smp-angular/src/app/smp.constants.ts b/smp-angular/src/app/smp.constants.ts
index 05cf40aea..5d8546138 100644
--- a/smp-angular/src/app/smp.constants.ts
+++ b/smp-angular/src/app/smp.constants.ts
@@ -19,6 +19,7 @@ export class SmpConstants {
   public static readonly PATH_ACTION_UPDATE_RESOURCE_TYPES = 'update-resource-types';
   public static readonly PATH_ACTION_UPDATE_SML_INTEGRATION = 'update-sml-integration-data';
   public static readonly PATH_ACTION_GENERATE_DNS_QUERY : string = 'generate-dns-query';
+
   /* URL variables */
   public static readonly PATH_PARAM_ENC_USER_ID = '{user-id}';
   public static readonly PATH_PARAM_ENC_DOMAIN_ID = '{domain-id}';
@@ -46,7 +47,6 @@ export class SmpConstants {
   public static readonly PATH_RESOURCE_TYPE_DOCUMENT = 'document';
   public static readonly PATH_QUERY_FILTER_TYPE = 'type'
 
-
   //------------------------------
   // public endpoints
   public static readonly REST_PUBLIC = 'public/rest/';
@@ -72,6 +72,7 @@ export class SmpConstants {
 
   /* Public services */
   public static readonly REST_PUBLIC_SEARCH_RESOURCE = SmpConstants.REST_PUBLIC + SmpConstants.PATH_ACTION_SEARCH;
+  public static readonly REST_PUBLIC_SEARCH_RESOURCE_METADATA = SmpConstants.REST_PUBLIC + SmpConstants.PATH_ACTION_SEARCH + "/metadata";
   public static readonly REST_PUBLIC_DOMAIN = SmpConstants.REST_PUBLIC + SmpConstants.PATH_RESOURCE_TYPE_DOMAIN;
   public static readonly REST_PUBLIC_DNS_TOOLS = SmpConstants.REST_PUBLIC  + SmpConstants.PATH_DNS_TOOLS;
   public static readonly REST_PUBLIC_DNS_TOOLS_GEN_QUERY: string = SmpConstants.REST_PUBLIC_DNS_TOOLS + '/' + SmpConstants.PATH_ACTION_GENERATE_DNS_QUERY;
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DocumentDao.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DocumentDao.java
index 860bde5ab..3bddc435e 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DocumentDao.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DocumentDao.java
@@ -118,4 +118,15 @@ public class DocumentDao extends BaseDao<DBDocument> {
         query.setParameter(PARAM_SUBRESOURCE_ID, subresource.getId());
         return query.getResultList();
     }
+
+    /**
+     * Returns document type records from smp_domain table.
+     *
+     * @return the list of document types from smp_domain table
+     */
+    public List<String> getAllDocumentTypes() {
+        TypedQuery<String> query = memEManager.createNamedQuery(QUERY_DOCUMENT_ALL_TYPES, String.class);
+        return query.getResultList();
+    }
+
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainDao.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainDao.java
index 4c739082a..a31bc1cb5 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainDao.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/DomainDao.java
@@ -77,6 +77,16 @@ public class DomainDao extends BaseDao<DBDomain> {
         return query.getResultList();
     }
 
+    /**
+     * Returns domain code records from smp_domain table.
+     *
+     * @return the list of domain codes from smp_domain table
+     */
+    public List<String> getAllDomainCodes() {
+        TypedQuery<String> query = memEManager.createNamedQuery(QUERY_DOMAIN_ALL_CODES, String.class);
+        return query.getResultList();
+    }
+
 
     public Optional<DBDomain> getFirstDomain() {
         TypedQuery<DBDomain> query = memEManager.createNamedQuery(QUERY_DOMAIN_ALL, DBDomain.class);
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/QueryNames.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/QueryNames.java
index 7d77d21af..96d7d1494 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/QueryNames.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/QueryNames.java
@@ -30,6 +30,7 @@ public class QueryNames {
 
 
     public static final String QUERY_DOMAIN_ALL = "DBDomain.getAll";
+    public static final String QUERY_DOMAIN_ALL_CODES = "DBDomain.getAllCodes";
     public static final String QUERY_DOMAIN_CODE = "DBDomain.getDomainByCode";
 
     public static final String QUERY_DOMAIN_SMP_SML_ID = "DBDomain.getDomainBySmlSmpId";
@@ -120,6 +121,7 @@ public class QueryNames {
     public static final String QUERY_RESOURCE_DEF_BY_IDENTIFIER_EXTENSION = "DBExtResourceDef.getByIdentifierExtension";
 
     public static final String QUERY_DOCUMENT_FOR_RESOURCE = "DBDocument.getForResource";
+    public static final String QUERY_DOCUMENT_ALL_TYPES = "DBDocument.getAllTypes";
 
     public static final String QUERY_DOCUMENT_VERSION_CURRENT_FOR_RESOURCE = "DBDocumentVersion.forCurrentForResource";
     public static final String QUERY_DOCUMENT_VERSION_LIST_FOR_RESOURCE = "DBDocumentVersion.getAllForResource";
@@ -189,6 +191,7 @@ public class QueryNames {
     public static final String PARAM_DOMAIN_IDS = "domain_ids";
 
     public static final String PARAM_DOCUMENT_ID = "document_id";
+    public static final String PARAM_DOCUMENT_TYPE = "document_type";
 
     public static final String PARAM_GROUP_ID = "group_id";
     public static final String PARAM_GROUP_IDS = "group_ids";
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ResourceDao.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ResourceDao.java
index 7de33a2b3..93b25d5d6 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ResourceDao.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/dao/ResourceDao.java
@@ -33,9 +33,11 @@ import org.springframework.transaction.annotation.Transactional;
 
 import javax.persistence.NoResultException;
 import javax.persistence.NonUniqueResultException;
+import javax.persistence.Tuple;
 import javax.persistence.TypedQuery;
 import java.util.List;
 import java.util.Optional;
+import java.util.stream.Collectors;
 
 import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.*;
 
@@ -49,6 +51,39 @@ public class ResourceDao extends BaseDao<DBResource> {
 
     private static final SMPLogger LOG = SMPLoggerFactory.getLogger(ResourceDao.class);
 
+    public static final class DBResourceWrapper {
+
+        private final DBResource dbResource;
+
+        private final String domainCode;
+
+        private final String documentType;
+
+        private final String urlSegment;
+
+        public DBResourceWrapper(DBResource dbResource, String domainCode, String documentType, String urlSegment) {
+            this.dbResource = dbResource;
+            this.domainCode = domainCode;
+            this.documentType = documentType;
+            this.urlSegment = urlSegment;
+        }
+
+        public DBResource getDbResource() {
+            return dbResource;
+        }
+
+        public String getDomainCode() {
+            return domainCode;
+        }
+
+        public String getDocumentType() {
+            return documentType;
+        }
+
+        public String getUrlSegment() {
+            return urlSegment;
+        }
+    }
 
     /**
      * The method returns DBResource for the participant identifier, domain, and resource type. If the resource does not exist, it returns an empty Option.
@@ -76,7 +111,6 @@ public class ResourceDao extends BaseDao<DBResource> {
         }
     }
 
-
     public Long getResourcesForFilterCount(DBResourceFilter resourceFilter) {
         LOG.debug("Get resources count for filter [{}]", resourceFilter);
 
@@ -110,10 +144,10 @@ public class ResourceDao extends BaseDao<DBResource> {
         return query.getResultList();
     }
 
-    public List<DBResource> getPublicResourcesSearch(int iPage, int iPageSize, DBUser user, String schema, String identifier) {
+    public List<DBResourceWrapper> getPublicResourcesSearch(int iPage, int iPageSize, DBUser user, String schema, String identifier, String domainCode, String documentType) {
         LOG.debug("Get resources list for user [{}], search scheme [{}] and search value [{}]", user, schema, identifier);
 
-        TypedQuery<DBResource> query = memEManager.createNamedQuery(QUERY_RESOURCE_ALL_FOR_USER, DBResource.class);
+        TypedQuery<Tuple> query = memEManager.createNamedQuery(QUERY_RESOURCE_ALL_FOR_USER, Tuple.class);
         if (iPageSize > -1 && iPage > -1) {
             query.setFirstResult(iPage * iPageSize);
         }
@@ -123,17 +157,28 @@ public class ResourceDao extends BaseDao<DBResource> {
         query.setParameter(PARAM_USER_ID, user != null ? user.getId() : null);
         query.setParameter(PARAM_RESOURCE_SCHEME, StringUtils.isBlank(schema) ? null : StringUtils.wrapIfMissing(schema, "%"));
         query.setParameter(PARAM_RESOURCE_IDENTIFIER, StringUtils.isBlank(identifier) ? null : StringUtils.wrapIfMissing(identifier, "%"));
-
-        return query.getResultList();
+        query.setParameter(PARAM_DOMAIN_CODE, StringUtils.defaultIfBlank(domainCode, null));
+        query.setParameter(PARAM_DOCUMENT_TYPE, StringUtils.defaultIfBlank(documentType, null));
+        List<Tuple> resultList = query.getResultList();
+
+        return resultList.stream().map(tuple -> {
+            DBResource resource = tuple.get(0, DBResource.class);
+            String domainCodeValue = tuple.get("domainCode").toString();
+            String documentTypeValue = tuple.get("documentType").toString();
+            String urlSegment = tuple.get("urlSegment").toString();
+            return new DBResourceWrapper(resource, domainCodeValue, documentTypeValue, urlSegment);
+        }).collect(Collectors.toList());
     }
 
-    public Long getPublicResourcesSearchCount(DBUser user, String schema, String identifier) {
+    public Long getPublicResourcesSearchCount(DBUser user, String schema, String identifier, String domainCode, String documentType) {
         LOG.debug("Get resources count for user [{}], search scheme [{}] and search value [{}]", user, schema, identifier);
         TypedQuery<Long> query = memEManager.createNamedQuery(QUERY_RESOURCE_ALL_FOR_USER_COUNT, Long.class);
 
         query.setParameter(PARAM_USER_ID, user != null ? user.getId() : null);
         query.setParameter(PARAM_RESOURCE_SCHEME, StringUtils.isBlank(schema) ? null : StringUtils.wrapIfMissing(schema, "%"));
         query.setParameter(PARAM_RESOURCE_IDENTIFIER, StringUtils.isBlank(identifier) ? null : StringUtils.wrapIfMissing(identifier, "%"));
+        query.setParameter(PARAM_DOMAIN_CODE, StringUtils.defaultIfBlank(domainCode, null));
+        query.setParameter(PARAM_DOCUMENT_TYPE, StringUtils.defaultIfBlank(documentType, null));
 
         return query.getSingleResult();
     }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomain.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomain.java
index c826b4c6b..be3c09fdf 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomain.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/DBDomain.java
@@ -41,6 +41,7 @@ import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.*;
         indexes = {@Index(name = "SMP_DOM_UNIQ_CODE_IDX", columnList = "DOMAIN_CODE", unique = true)
         })
 @NamedQuery(name = QUERY_DOMAIN_ALL, query = "SELECT d FROM DBDomain d order by d.id asc")
+@NamedQuery(name = QUERY_DOMAIN_ALL_CODES, query = "SELECT DISTINCT d.domainCode FROM DBDomain d")
 @NamedQuery(name = QUERY_DOMAIN_CODE, query = "SELECT d FROM DBDomain d WHERE d.domainCode = :domain_code")
 @NamedQuery(name = QUERY_DOMAIN_SMP_SML_ID, query = "SELECT d FROM DBDomain d WHERE lower(d.smlSmpId) = lower(:sml_smp_id)")
 
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/doc/DBDocument.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/doc/DBDocument.java
index b4f9dd9db..debc62511 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/doc/DBDocument.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/doc/DBDocument.java
@@ -31,6 +31,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
+import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.QUERY_DOCUMENT_ALL_TYPES;
 import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.QUERY_DOCUMENT_FOR_RESOURCE;
 
 /**
@@ -47,6 +48,7 @@ import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.QUERY_DOCUMENT_FOR_
 @org.hibernate.annotations.Table(appliesTo = "SMP_DOCUMENT", comment = "SMP document entity for resources and subresources")
 @NamedQueries({
         @NamedQuery(name = QUERY_DOCUMENT_FOR_RESOURCE, query = "SELECT d FROM DBResource r JOIN r.document d WHERE r.id =:resource_id"),
+        @NamedQuery(name = QUERY_DOCUMENT_ALL_TYPES, query = "SELECT DISTINCT d.name FROM DBDocument d"),
 })
 public class DBDocument extends BaseEntity {
     private static final SMPLogger LOG = SMPLoggerFactory.getLogger(DBDocument.class);
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/doc/DBResource.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/doc/DBResource.java
index 34c01df66..6890502a7 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/doc/DBResource.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/model/doc/DBResource.java
@@ -99,7 +99,9 @@ import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.*;
         " AND (:resource_identifier IS NULL OR r.identifierValue like :resource_identifier )" +
         " AND (:resource_scheme IS NULL OR r.identifierScheme like :resource_scheme) order by r.identifierScheme, r.identifierValue"
 )
-@NamedQuery(name = QUERY_RESOURCE_ALL_FOR_USER, query = "SELECT DISTINCT r FROM  DBResource r LEFT JOIN DBResourceMember rm ON r.id = rm.resource.id WHERE " +
+@NamedQuery(name = QUERY_RESOURCE_ALL_FOR_USER, query = "SELECT DISTINCT r, r.domainResourceDef.domain.domainCode as domainCode, " +
+        "   r.domainResourceDef.resourceDef.urlSegment as urlSegment, r.document.name as documentType " +
+        "FROM  DBResource r LEFT JOIN DBResourceMember rm ON r.id = rm.resource.id WHERE " +
         " (:resource_identifier IS NULL OR r.identifierValue like :resource_identifier) " +
         " AND (:resource_scheme IS NULL OR r.identifierScheme like :resource_scheme) " +
         " AND ( :user_id IS NOT NULL AND rm.user.id = :user_id "  +
@@ -112,8 +114,10 @@ import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.*;
         "            OR  (select count(dm.id) from DBDomainMember dm where dm.user.id = :user_id and dm.domain.id = r.group.domain.id) > 0 " +
         "            OR (select count(gm.id) from DBGroupMember gm where gm.user.id = :user_id and gm.group.domain.id = r.group.domain.id) > 0 " +
         "            OR (select count(rm.id) from DBResourceMember rm where rm.user.id = :user_id and rm.resource.group.domain.id = r.group.domain.id) > 0 " +
-        ")))"+
-        "order by r.identifierScheme, r.identifierValue"
+        "))) " +
+        " AND (:domain_code IS NULL OR r.domainResourceDef.domain.domainCode = :domain_code) " +
+        " AND (:document_type IS NULL OR r.document.name = :document_type) " +
+        " ORDER BY r.identifierScheme, r.identifierValue"
 )
 @NamedQuery(name = QUERY_RESOURCE_ALL_FOR_USER_COUNT, query = "SELECT count(distinct r.id) FROM  DBResource r LEFT JOIN DBResourceMember rm ON r.id = rm.resource.id WHERE " +
         " (:resource_identifier IS NULL OR r.identifierValue like :resource_identifier) " +
@@ -128,7 +132,9 @@ import static eu.europa.ec.edelivery.smp.data.dao.QueryNames.*;
         "            OR  (select count(dm.id) from DBDomainMember dm where dm.user.id = :user_id and dm.domain.id = r.group.domain.id) > 0 " +
         "            OR (select count(gm.id) from DBGroupMember gm where gm.user.id = :user_id and gm.group.domain.id = r.group.domain.id) > 0 " +
         "            OR (select count(rm.id) from DBResourceMember rm where rm.user.id = :user_id and rm.resource.group.domain.id = r.group.domain.id) > 0 " +
-        ")))"
+        "))) " +
+        " AND (:domain_code IS NULL OR r.domainResourceDef.domain.domainCode = :domain_code) " +
+        " AND (:document_type IS NULL OR r.document.name = :document_type) "
 )
 public class DBResource extends BaseEntity {
 
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupSearchRO.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupSearchRO.java
index cdf665c99..cf080ac99 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupSearchRO.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/data/ui/ServiceGroupSearchRO.java
@@ -36,6 +36,7 @@ public class ServiceGroupSearchRO extends BaseRO {
     private Long id;
 
     private String domainCode;
+    private String documentType;
     private String resourceDefUrlSegment;
     private String participantIdentifier;
     private String participantScheme;
@@ -85,4 +86,12 @@ public class ServiceGroupSearchRO extends BaseRO {
     public List<ServiceMetadataRO> getServiceMetadata() {
         return lstServiceMetadata;
     }
+
+    public String getDocumentType() {
+        return documentType;
+    }
+
+    public void setDocumentType(String documentType) {
+        this.documentType = documentType;
+    }
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIResourceSearchService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIResourceSearchService.java
index df80781d4..71aa71b6a 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIResourceSearchService.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIResourceSearchService.java
@@ -18,12 +18,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.ResourceDao;
-import eu.europa.ec.edelivery.smp.data.dao.UserDao;
+import eu.europa.ec.edelivery.smp.data.dao.*;
 import eu.europa.ec.edelivery.smp.data.model.doc.DBResource;
 import eu.europa.ec.edelivery.smp.data.model.user.DBUser;
+import eu.europa.ec.edelivery.smp.data.ui.ResourceMetadataResult;
 import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupSearchRO;
 import eu.europa.ec.edelivery.smp.data.ui.ServiceMetadataRO;
 import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
@@ -31,7 +29,7 @@ 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.ResourceFilter;
 import eu.europa.ec.edelivery.smp.utils.SessionSecurityUtils;
-import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.convert.ConversionService;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -42,14 +40,23 @@ import java.util.List;
 public class UIResourceSearchService extends UIServiceBase<DBResource, ServiceGroupSearchRO> {
     private static final SMPLogger LOG = SMPLoggerFactory.getLogger(UIResourceSearchService.class);
 
-    @Autowired
-    DomainDao domainDao;
+    private final DomainDao domainDao;
 
-    @Autowired
-    ResourceDao resourceDao;
+    private final ResourceDao resourceDao;
 
-    @Autowired
-    UserDao userDao;
+    private final UserDao userDao;
+
+    private final DocumentDao documentDao;
+
+    private final ConversionService conversionService;
+
+    public UIResourceSearchService(DomainDao domainDao, ResourceDao resourceDao, UserDao userDao, DocumentDao documentDao, ConversionService conversionService) {
+        this.domainDao = domainDao;
+        this.resourceDao = resourceDao;
+        this.userDao = userDao;
+        this.documentDao = documentDao;
+        this.conversionService = conversionService;
+    }
 
 
     @Override
@@ -77,7 +84,7 @@ public class UIResourceSearchService extends UIServiceBase<DBResource, ServiceGr
         sg.setPageSize(pageSize);
         DBUser user = SessionSecurityUtils.getSessionUserDetails() != null ? SessionSecurityUtils.getSessionUserDetails().getUser() : null;
 
-        long iCnt = resourceDao.getPublicResourcesSearchCount(user, filter.getIdentifierSchemeLike(), filter.getIdentifierValueLike());
+        long iCnt = resourceDao.getPublicResourcesSearchCount(user, filter.getIdentifierSchemeLike(), filter.getIdentifierValueLike(), filter.getDomainCode(), filter.getDocumentType());
         sg.setCount(iCnt);
 
         if (iCnt > 0) {
@@ -87,10 +94,10 @@ public class UIResourceSearchService extends UIServiceBase<DBResource, ServiceGr
                 sg.setPage(page); // go back for a page
                 iStartIndex = pageSize < 0 ? -1 : page * pageSize;
             }
-            List<DBResource> lst = resourceDao.getPublicResourcesSearch(page, pageSize, user, filter.getIdentifierSchemeLike(), filter.getIdentifierValueLike());
+            List<ResourceDao.DBResourceWrapper> lst = resourceDao.getPublicResourcesSearch(page, pageSize, user, filter.getIdentifierSchemeLike(), filter.getIdentifierValueLike(), filter.getDomainCode(), filter.getDocumentType());
             List<ServiceGroupSearchRO> lstRo = new ArrayList<>();
-            for (DBResource resource : lst) {
-                ServiceGroupSearchRO serviceGroupRo = convertToRo(resource);
+            for (ResourceDao.DBResourceWrapper resource : lst) {
+                ServiceGroupSearchRO serviceGroupRo = convert(resource);
                 serviceGroupRo.setIndex(iStartIndex++);
                 lstRo.add(serviceGroupRo);
             }
@@ -102,19 +109,20 @@ public class UIResourceSearchService extends UIServiceBase<DBResource, ServiceGr
     /**
      * Convert Database object to Rest object for UI
      *
-     * @param resource - database  entity
+     * @param resource     - database entity wrapper
      * @return ServiceGroupRO
      */
-    public ServiceGroupSearchRO convertToRo(DBResource resource) {
+    private ServiceGroupSearchRO convert(ResourceDao.DBResourceWrapper resource) {
         ServiceGroupSearchRO serviceGroupRo = new ServiceGroupSearchRO();
 
-        serviceGroupRo.setId(resource.getId());
-        serviceGroupRo.setDomainCode(resource.getDomainResourceDef().getDomain().getDomainCode());
-        serviceGroupRo.setResourceDefUrlSegment(resource.getDomainResourceDef().getResourceDef().getUrlSegment());
-        serviceGroupRo.setParticipantIdentifier(resource.getIdentifierValue());
-        serviceGroupRo.setParticipantScheme(resource.getIdentifierScheme());
+        serviceGroupRo.setId(resource.getDbResource().getId());
+        serviceGroupRo.setDomainCode(resource.getDomainCode());
+        serviceGroupRo.setDocumentType(resource.getDocumentType());
+        serviceGroupRo.setResourceDefUrlSegment(resource.getUrlSegment());
+        serviceGroupRo.setParticipantIdentifier(resource.getDbResource().getIdentifierValue());
+        serviceGroupRo.setParticipantScheme(resource.getDbResource().getIdentifierScheme());
 
-        resource.getSubresources().forEach(subresource -> {
+        resource.getDbResource().getSubresources().forEach(subresource -> {
             ServiceMetadataRO smdro = new ServiceMetadataRO();
             smdro.setSubresourceDefUrlSegment(subresource.getSubresourceDef().getUrlSegment());
             smdro.setDocumentIdentifier(subresource.getIdentifierValue());
@@ -124,4 +132,10 @@ public class UIResourceSearchService extends UIServiceBase<DBResource, ServiceGr
 
         return serviceGroupRo;
     }
+
+    public ResourceMetadataResult getResourceMetadata() {
+        List<String> domainCodes = domainDao.getAllDomainCodes();
+        List<String> documentTypes = documentDao.getAllDocumentTypes();
+        return new ResourceMetadataResult(domainCodes, documentTypes);
+    }
 }
diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/filters/ResourceFilter.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/filters/ResourceFilter.java
index 79e041716..d4da3d9c6 100644
--- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/filters/ResourceFilter.java
+++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/filters/ResourceFilter.java
@@ -27,6 +27,7 @@ public class ResourceFilter {
 
     private DBUser owner;
     private DBDomain domain;
+    private String documentType;
 
     public String getIdentifierValueLike() {
         return identifierValue;
@@ -59,4 +60,19 @@ public class ResourceFilter {
     public void setDomain(DBDomain domain) {
         this.domain = domain;
     }
+
+    public String getDomainCode() {
+        if (domain == null) {
+            return null;
+        }
+        return domain.getDomainCode();
+    }
+
+    public String getDocumentType() {
+        return documentType;
+    }
+
+    public void setDocumentType(String documentType) {
+        this.documentType = documentType;
+    }
 }
diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ResourceDaoSearchTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ResourceDaoSearchTest.java
index 9be8653f6..cbab7cad2 100644
--- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ResourceDaoSearchTest.java
+++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/data/dao/ResourceDaoSearchTest.java
@@ -62,44 +62,44 @@ class ResourceDaoSearchTest extends AbstractBaseDao {
         assertEquals(8, allResources.size());
 
         // only one group is public -
-        List<DBResource> result = testInstance.getPublicResourcesSearch(-1, -1, null, null, null);
+        List<ResourceDao.DBResourceWrapper> result = testInstance.getPublicResourcesSearch(-1, -1, null, null, null, null, null);
         assertEquals(1, result.size());
         assertResources(result, "1-1-1::pubPubPub");
 
         // user1 (admin) and user2 (viewer) are members of all resources
-        result = testInstance.getPublicResourcesSearch(-1, -1, testUtilsDao.getUser2(), null, null);
+        result = testInstance.getPublicResourcesSearch(-1, -1, testUtilsDao.getUser2(), null, null, null, null);
         assertEquals(8, result.size());
 
-        result = testInstance.getPublicResourcesSearch(-1, -1, testUtilsDao.getUser1(), null, "pubPub");
+        result = testInstance.getPublicResourcesSearch(-1, -1, testUtilsDao.getUser1(), null, "pubPub", null, null);
         assertEquals(2, result.size());
-        result.forEach(resource -> assertThat(resource.getIdentifierValue(), CoreMatchers.containsString("pubPub")));
+        result.forEach(resource -> assertThat(resource.getDbResource().getIdentifierValue(), CoreMatchers.containsString("pubPub")));
 
-        result = testInstance.getPublicResourcesSearch(-1, -1, testUtilsDao.getUser1(), "1-1", null);
+        result = testInstance.getPublicResourcesSearch(-1, -1, testUtilsDao.getUser1(), "1-1", null, null, null);
         assertEquals(1, result.size());
-        result.forEach(resource -> assertThat(resource.getIdentifierScheme(), CoreMatchers.containsString("1-1")));
+        result.forEach(resource -> assertThat(resource.getDbResource().getIdentifierScheme(), CoreMatchers.containsString("1-1")));
 
-        result = testInstance.getPublicResourcesSearch(-1, -1, testUtilsDao.getUser1(), "1-1", "priv");
+        result = testInstance.getPublicResourcesSearch(-1, -1, testUtilsDao.getUser1(), "1-1", "priv", null, null);
         assertEquals(0, result.size());
 
-        result = testInstance.getPublicResourcesSearch(-1, -1, testUtilsDao.getUser2(), null, null);
+        result = testInstance.getPublicResourcesSearch(-1, -1, testUtilsDao.getUser2(), null, null, null, null);
         assertEquals(8, result.size());
 
 
         // user3 is direct member of private domain - can see only public resource on public groups
-        result = testInstance.getPublicResourcesSearch(-1, -1, testUtilsDao.getUser3(), null, null);
+        result = testInstance.getPublicResourcesSearch(-1, -1, testUtilsDao.getUser3(), null, null, null, null);
         assertResources(result, "1-1-1::pubPubPub", "5-5-5::privPubPub");
 
         // user4 is direct member of private group in private domain
-        result = testInstance.getPublicResourcesSearch(-1, -1, testUtilsDao.getUser4(), null, null);
+        result = testInstance.getPublicResourcesSearch(-1, -1, testUtilsDao.getUser4(), null, null, null, null);
         assertResources(result, "1-1-1::pubPubPub", "5-5-5::privPubPub", "7-7-7::privPrivPub");
 
         // user5 is direct member of private resource in  private group in private domain
-        result = testInstance.getPublicResourcesSearch(-1, -1, testUtilsDao.getUser5(), null, null);
+        result = testInstance.getPublicResourcesSearch(-1, -1, testUtilsDao.getUser5(), null, null, null, null);
         assertResources(result, "1-1-1::pubPubPub", "5-5-5::privPubPub", "7-7-7::privPrivPub", "8-8-8::privPrivPriv");
     }
 
-    public void assertResources(List<DBResource> result, String... resourceIdentifiers) {
-        List<String> resultIdentifiers = result.stream().map(val -> val.getIdentifierScheme() + "::" + val.getIdentifierValue()).collect(Collectors.toList());
+    public void assertResources(List<ResourceDao.DBResourceWrapper> result, String... resourceIdentifiers) {
+        List<String> resultIdentifiers = result.stream().map(val -> val.getDbResource().getIdentifierScheme() + "::" + val.getDbResource().getIdentifierValue()).collect(Collectors.toList());
         System.out.println(resultIdentifiers);
         assertArrayEquals(resourceIdentifiers, resultIdentifiers.stream().toArray());
     }
@@ -110,35 +110,35 @@ class ResourceDaoSearchTest extends AbstractBaseDao {
         assertEquals(8, allResources.size());
 
         // only one group is public -
-        Long result = testInstance.getPublicResourcesSearchCount(null, null, null);
+        Long result = testInstance.getPublicResourcesSearchCount(null, null, null, null, null);
         assertEquals(1, result.intValue());
 
         // user1 (admin) and user2 (viewer) are members of all resources
-        result = testInstance.getPublicResourcesSearchCount(testUtilsDao.getUser1(), null, null);
+        result = testInstance.getPublicResourcesSearchCount(testUtilsDao.getUser1(), null, null, null, null);
         assertEquals(8, result.intValue());
 
-        result = testInstance.getPublicResourcesSearchCount(testUtilsDao.getUser1(), null, "pubPub");
+        result = testInstance.getPublicResourcesSearchCount(testUtilsDao.getUser1(), null, "pubPub", null, null);
         assertEquals(2, result.intValue());
 
-        result = testInstance.getPublicResourcesSearchCount(testUtilsDao.getUser1(), "1-1", null);
+        result = testInstance.getPublicResourcesSearchCount(testUtilsDao.getUser1(), "1-1", null, null, null);
         assertEquals(1, result.intValue());
 
-        result = testInstance.getPublicResourcesSearchCount(testUtilsDao.getUser1(), "1-1", "priv");
+        result = testInstance.getPublicResourcesSearchCount(testUtilsDao.getUser1(), "1-1", "priv", null, null);
         assertEquals(0, result.intValue());
 
-        result = testInstance.getPublicResourcesSearchCount(testUtilsDao.getUser2(), null, null);
+        result = testInstance.getPublicResourcesSearchCount(testUtilsDao.getUser2(), null, null, null, null);
         assertEquals(8, result.intValue());
 
         // user3 is direct member of private domain - can see only public resource on public groups
-        result = testInstance.getPublicResourcesSearchCount(testUtilsDao.getUser3(), null, null);
+        result = testInstance.getPublicResourcesSearchCount(testUtilsDao.getUser3(), null, null, null, null);
         assertEquals(2, result.intValue());
 
         // user4 is direct member of private group in private domain
-        result = testInstance.getPublicResourcesSearchCount(testUtilsDao.getUser4(), null, null);
+        result = testInstance.getPublicResourcesSearchCount(testUtilsDao.getUser4(), null, null, null, null);
         assertEquals(3, result.intValue());
 
         // user5 is direct member of private resource in  private group in private domain
-        result = testInstance.getPublicResourcesSearchCount(testUtilsDao.getUser5(), null, null);
+        result = testInstance.getPublicResourcesSearchCount(testUtilsDao.getUser5(), null, null, null, null);
         assertEquals(4, result.intValue());
 
     }
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ResourceConstants.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ResourceConstants.java
index 806dc4554..9b06aa610 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ResourceConstants.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/ResourceConstants.java
@@ -132,6 +132,7 @@ public class ResourceConstants {
     public static final String SUB_CONTEXT_PATH_EDIT_DOCUMENT_SUBRESOURCE_GENERATE =  SUB_CONTEXT_PATH_EDIT_DOCUMENT_GET_SUBRESOURCE +  URL_PATH_SEPARATOR + PATH_ACTION_GENERATE;
     // public
     public static final String CONTEXT_PATH_PUBLIC_SEARCH_PARTICIPANT = CONTEXT_PATH_PUBLIC + PATH_ACTION_SEARCH;
+    public static final String CONTEXT_PATH_PUBLIC_SEARCH_PARTICIPANT_METADATA = CONTEXT_PATH_PUBLIC_SEARCH_PARTICIPANT + "/metadata";
     public static final String CONTEXT_PATH_PUBLIC_DOMAIN = CONTEXT_PATH_PUBLIC + PATH_RESOURCE_TYPE_DOMAIN;
     public static final String CONTEXT_PATH_PUBLIC_APPLICATION = CONTEXT_PATH_PUBLIC + "application";
     public static final String CONTEXT_PATH_PUBLIC_USER = CONTEXT_PATH_PUBLIC + "user";
@@ -167,6 +168,7 @@ public class ResourceConstants {
     public static final String PARAM_QUERY_DOMAIN_CODE = "domainCode";
     public static final String PARAM_QUERY_USER = "user";
     public static final String PARAM_QUERY_PROPERTY = "property";
+    public static final String PARAM_QUERY_DOCUMENT_TYPE = "documentType";
 
     private ResourceConstants() {
     }
diff --git a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/SearchResource.java b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/SearchResource.java
index b53cddeac..6d9b814db 100644
--- a/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/SearchResource.java
+++ b/smp-webapp/src/main/java/eu/europa/ec/edelivery/smp/ui/external/SearchResource.java
@@ -18,8 +18,8 @@
  */
 package eu.europa.ec.edelivery.smp.ui.external;
 
-
 import eu.europa.ec.edelivery.smp.data.dao.DomainDao;
+import eu.europa.ec.edelivery.smp.data.ui.ResourceMetadataResult;
 import eu.europa.ec.edelivery.smp.data.ui.ServiceGroupSearchRO;
 import eu.europa.ec.edelivery.smp.data.ui.ServiceResult;
 import eu.europa.ec.edelivery.smp.logging.SMPLogger;
@@ -45,7 +45,7 @@ import static eu.europa.ec.edelivery.smp.ui.ResourceConstants.*;
  * @since 4.1
  */
 @RestController
-@RequestMapping(path = CONTEXT_PATH_PUBLIC_SEARCH_PARTICIPANT)
+@RequestMapping(produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
 public class SearchResource {
 
     private static final SMPLogger LOG = SMPLoggerFactory.getLogger(SearchResource.class);
@@ -58,7 +58,7 @@ public class SearchResource {
         this.domainDao = domainDao;
     }
 
-    @GetMapping(produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
+    @GetMapping(path = CONTEXT_PATH_PUBLIC_SEARCH_PARTICIPANT)
     public ServiceResult<ServiceGroupSearchRO> getServiceGroupList(
             @RequestParam(value = PARAM_PAGINATION_PAGE, defaultValue = "0") int page,
             @RequestParam(value = PARAM_PAGINATION_PAGE_SIZE, defaultValue = "10") int pageSize,
@@ -66,24 +66,32 @@ public class SearchResource {
             @RequestParam(value = PARAM_PAGINATION_ORDER_TYPE, defaultValue = "asc", required = false) String orderType,
             @RequestParam(value = PARAM_QUERY_PARTC_ID, required = false) String participantIdentifier,
             @RequestParam(value = PARAM_QUERY_PARTC_SCHEME, required = false) String participantScheme,
-            @RequestParam(value = PARAM_QUERY_DOMAIN_CODE, required = false) String domainCode) {
+            @RequestParam(value = PARAM_QUERY_DOMAIN_CODE, required = false) String domainCode,
+            @RequestParam(value = PARAM_QUERY_DOCUMENT_TYPE, required = false) String documentType) {
 
         String participantIdentifierDecoded = decodeUrlToUTF8(participantIdentifier);
         String participantSchemeDecoded = decodeUrlToUTF8(participantScheme);
         String domainCodeDecoded = decodeUrlToUTF8(domainCode);
+        String documentTypeDecoded = decodeUrlToUTF8(documentType);
 
-        LOG.info("Search for page: {}, page size: {}, part. id: {}, part sch: {}, domain {}", page, pageSize, participantIdentifierDecoded,
-                participantSchemeDecoded, domainCodeDecoded);
+        LOG.info("Search for page: {}, page size: {}, part. id: {}, part sch: {}, domain: {}, document type: {}", page, pageSize, participantIdentifierDecoded,
+                participantSchemeDecoded, domainCodeDecoded, documentTypeDecoded);
 
         ResourceFilter sgf = new ResourceFilter();
         sgf.setIdentifierValueLike(participantIdentifierDecoded);
         sgf.setIdentifierSchemeLike(participantSchemeDecoded);
         // add domain search parameter
         sgf.setDomain(domainDao.validateDomainCode(domainCodeDecoded));
+        sgf.setDocumentType(documentTypeDecoded);
 
         return uiServiceGroupService.getTableList(page, pageSize, orderBy, orderType, sgf);
     }
 
+    @GetMapping(path = CONTEXT_PATH_PUBLIC_SEARCH_PARTICIPANT_METADATA)
+    public ResourceMetadataResult serviceMetadataResultList() {
+        return uiServiceGroupService.getResourceMetadata();
+    }
+
     private String decodeUrlToUTF8(String value) {
         if (StringUtils.isBlank(value)) {
             return null;
-- 
GitLab