From d8025dc3bf1e8715667da3f4dea66f1f5961cf4a Mon Sep 17 00:00:00 2001
From: "Fuentes Serna  Juan Mariano (ID SIS)" <juanf@bs-mbpr28.d.ethz.ch>
Date: Thu, 22 Feb 2018 15:57:27 +0100
Subject: [PATCH] SSDM-6196 : New V3 API Sort option
 sortBy().fetchedFieldsScore(), java implementation + basic unitests

---
 .../AbstractGetObjectsOperationExecutor.java  |   2 +-
 ...bstractSearchObjectsOperationExecutor.java |   6 +-
 .../AuthorizationGroupComparatorFactory.java  |   5 +-
 .../ExperimentComparatorFactory.java          |   7 +-
 .../GlobalSearchObjectComparatorFactory.java  |   5 +-
 .../project/ProjectComparatorFactory.java     |   7 +-
 .../PropertyAssignmentComparatorFactory.java  |   6 +-
 .../PropertyTypeComparatorFactory.java        |   5 +-
 .../sample/SampleComparatorFactory.java       |   7 +-
 .../v3/helper/sort/ComparatorFactory.java     |   5 +-
 .../helper/sort/EntityComparatorFactory.java  |   5 +-
 ...EntityWithPropertiesComparatorFactory.java |  12 +-
 .../sort/FetchedFieldsScoreComparator.java    | 351 ++++++++++++++++++
 .../asapi/v3/helper/sort/SortAndPage.java     |  25 +-
 .../v3/helper/tag/TagComparatorFactory.java   |   5 +-
 .../VocabularyComparatorFactory.java          |   5 +-
 .../VocabularyTermComparatorFactory.java      |   5 +-
 .../sample/SampleTypeTranslator.java          |   2 +-
 .../asapi/v3/helper/sort/SortAndPageTest.java | 169 ++++++++-
 .../EntityWithPropertiesSortOptions.java      |  20 +-
 .../dto/common/fetchoptions/SortOptions.java  |   8 +-
 .../common/fetchoptions/SortParameter.java    |  30 ++
 .../v3/dto/common/fetchoptions/Sorting.java   |  15 +-
 23 files changed, 662 insertions(+), 45 deletions(-)
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/FetchedFieldsScoreComparator.java
 create mode 100644 openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/SortParameter.java

diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/get/AbstractGetObjectsOperationExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/get/AbstractGetObjectsOperationExecutor.java
index 00c85047085..2ced14b81ed 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/get/AbstractGetObjectsOperationExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/get/AbstractGetObjectsOperationExecutor.java
@@ -67,7 +67,7 @@ public abstract class AbstractGetObjectsOperationExecutor<OBJECT_ID extends IObj
         
         // sort and page the objects internal collections - ignore the top level changes
         // (we want to maintain all the results and keep them in order of the passed ids)
-        new SortAndPage().sortAndPage(idToObjectMap.values(), operation.getFetchOptions());
+        new SortAndPage().sortAndPage(idToObjectMap.values(), null, operation.getFetchOptions());
 
         return getOperationResult(idToObjectMap);
     }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/search/AbstractSearchObjectsOperationExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/search/AbstractSearchObjectsOperationExecutor.java
index 8abc1cce9a9..fe8b92e6a27 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/search/AbstractSearchObjectsOperationExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/search/AbstractSearchObjectsOperationExecutor.java
@@ -77,7 +77,7 @@ public abstract class AbstractSearchObjectsOperationExecutor<OBJECT, OBJECT_PE,
         }
 
         Collection<OBJECT> allResults = searchAndTranslate(context, criteria, fetchOptions);
-        List<OBJECT> sortedAndPaged = sortAndPage(context, allResults, fetchOptions);
+        List<OBJECT> sortedAndPaged = sortAndPage(context, allResults, criteria, fetchOptions);
 
         SearchResult<OBJECT> searchResult = new SearchResult<OBJECT>(sortedAndPaged, allResults.size());
         return getOperationResult(searchResult);
@@ -119,7 +119,7 @@ public abstract class AbstractSearchObjectsOperationExecutor<OBJECT, OBJECT_PE,
         return objects;
     }
 
-    private List<OBJECT> sortAndPage(IOperationContext context, Collection<OBJECT> results, FETCH_OPTIONS fetchOptions)
+    private List<OBJECT> sortAndPage(IOperationContext context, Collection<OBJECT> results,  CRITERIA criteria, FETCH_OPTIONS fetchOptions)
     {
         if (results == null || results.isEmpty())
         {
@@ -127,7 +127,7 @@ public abstract class AbstractSearchObjectsOperationExecutor<OBJECT, OBJECT_PE,
         }
 
         SortAndPage sap = new SortAndPage();
-        Collection<OBJECT> objects = sap.sortAndPage(results, fetchOptions);
+        Collection<OBJECT> objects = sap.sortAndPage(results, criteria, fetchOptions);
 
         operationLog.info("Return " + objects.size() + " object(s) after sorting and paging.");
 
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/authorizationgroup/AuthorizationGroupComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/authorizationgroup/AuthorizationGroupComparatorFactory.java
index ab031cbce34..67a721fe9ff 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/authorizationgroup/AuthorizationGroupComparatorFactory.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/authorizationgroup/AuthorizationGroupComparatorFactory.java
@@ -17,9 +17,12 @@
 package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.authorizationgroup;
 
 import java.util.Comparator;
+import java.util.Map;
 
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.authorizationgroup.AuthorizationGroup;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.authorizationgroup.fetchoptions.AuthorizationGroupSortOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.CodeComparator;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.ComparatorFactory;
 
@@ -38,7 +41,7 @@ public class AuthorizationGroupComparatorFactory extends ComparatorFactory
     }
 
     @Override
-    public Comparator<AuthorizationGroup> getComparator(String field)
+    public Comparator<AuthorizationGroup> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria)
     {
         if (AuthorizationGroupSortOptions.CODE.equals(field))
         {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/experiment/ExperimentComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/experiment/ExperimentComparatorFactory.java
index f63b3cfb13d..5ef251a3136 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/experiment/ExperimentComparatorFactory.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/experiment/ExperimentComparatorFactory.java
@@ -17,7 +17,10 @@
 package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.experiment;
 
 import java.util.Comparator;
+import java.util.Map;
 
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.Experiment;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.fetchoptions.ExperimentSortOptions;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.EntityWithPropertiesComparatorFactory;
@@ -36,13 +39,13 @@ public class ExperimentComparatorFactory extends EntityWithPropertiesComparatorF
     }
 
     @Override
-    public Comparator<Experiment> getComparator(String field)
+    public Comparator<Experiment> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria)
     {
         if (ExperimentSortOptions.IDENTIFIER.equals(field))
         {
             return new IdentifierComparator<Experiment>();
         }
-        return super.getComparator(field);
+        return super.getComparator(field, parameters, criteria);
     }
 
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/globalsearch/GlobalSearchObjectComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/globalsearch/GlobalSearchObjectComparatorFactory.java
index ee861127a94..51d0e92d347 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/globalsearch/GlobalSearchObjectComparatorFactory.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/globalsearch/GlobalSearchObjectComparatorFactory.java
@@ -18,7 +18,10 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.globalsearch;
 
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Map;
 
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.global.GlobalSearchObject;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.global.fetchoptions.GlobalSearchObjectSortOptions;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.ComparatorFactory;
@@ -37,7 +40,7 @@ public class GlobalSearchObjectComparatorFactory extends ComparatorFactory
     }
 
     @Override
-    public Comparator<GlobalSearchObject> getComparator(String field)
+    public Comparator<GlobalSearchObject> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria)
     {
         if (GlobalSearchObjectSortOptions.SCORE.equals(field))
         {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/project/ProjectComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/project/ProjectComparatorFactory.java
index ed573d53159..b469076fd30 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/project/ProjectComparatorFactory.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/project/ProjectComparatorFactory.java
@@ -17,7 +17,10 @@
 package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.project;
 
 import java.util.Comparator;
+import java.util.Map;
 
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.Project;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.fetchoptions.ProjectSortOptions;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.EntityComparatorFactory;
@@ -36,13 +39,13 @@ public class ProjectComparatorFactory extends EntityComparatorFactory<Project>
     }
 
     @Override
-    public Comparator<Project> getComparator(String field)
+    public Comparator<Project> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria)
     {
         if (ProjectSortOptions.IDENTIFIER.equals(field))
         {
             return new IdentifierComparator<Project>();
         }
-        return super.getComparator(field);
+        return super.getComparator(field, parameters, criteria);
     }
 
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/property/PropertyAssignmentComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/property/PropertyAssignmentComparatorFactory.java
index 251b1e47e6c..93b07657b74 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/property/PropertyAssignmentComparatorFactory.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/property/PropertyAssignmentComparatorFactory.java
@@ -20,6 +20,8 @@ import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Map;
 
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.PropertyAssignment;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.PropertyType;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.fetchoptions.PropertyAssignmentSortOptions;
@@ -69,7 +71,7 @@ public class PropertyAssignmentComparatorFactory extends ComparatorFactory
     }
 
     @Override
-    public Comparator<?> getComparator(String field)
+    public Comparator<?> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria)
     {
         return COMPARATORS_BY_FIELD.get(field);
     }
@@ -77,7 +79,7 @@ public class PropertyAssignmentComparatorFactory extends ComparatorFactory
     @Override
     public Comparator<?> getDefaultComparator()
     {
-        return getComparator(PropertyAssignmentSortOptions.ORDINAL);
+        return getComparator(PropertyAssignmentSortOptions.ORDINAL, null, null);
     }
 
     private abstract static class AbstractPropertyAssignmentComparator extends AbstractStringComparator<PropertyAssignment>
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/property/PropertyTypeComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/property/PropertyTypeComparatorFactory.java
index ef68061cd58..f8c044fa695 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/property/PropertyTypeComparatorFactory.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/property/PropertyTypeComparatorFactory.java
@@ -17,7 +17,10 @@
 package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.property;
 
 import java.util.Comparator;
+import java.util.Map;
 
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.PropertyType;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.fetchoptions.PropertyTypeSortOptions;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.fetchoptions.VocabularySortOptions;
@@ -38,7 +41,7 @@ public class PropertyTypeComparatorFactory extends ComparatorFactory
     }
 
     @Override
-    public Comparator<PropertyType> getComparator(String field)
+    public Comparator<PropertyType> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria)
     {
         if (VocabularySortOptions.CODE.equals(field))
         {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sample/SampleComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sample/SampleComparatorFactory.java
index 4218ac4f930..8a1c3ddb2d2 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sample/SampleComparatorFactory.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sample/SampleComparatorFactory.java
@@ -17,7 +17,10 @@
 package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sample;
 
 import java.util.Comparator;
+import java.util.Map;
 
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.Sample;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.fetchoptions.SampleSortOptions;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.EntityWithPropertiesComparatorFactory;
@@ -36,13 +39,13 @@ public class SampleComparatorFactory extends EntityWithPropertiesComparatorFacto
     }
 
     @Override
-    public Comparator<Sample> getComparator(String field)
+    public Comparator<Sample> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria)
     {
         if (SampleSortOptions.IDENTIFIER.equals(field))
         {
             return new IdentifierComparator<Sample>();
         }
-        return super.getComparator(field);
+        return super.getComparator(field, parameters, criteria);
     }
 
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/ComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/ComparatorFactory.java
index 3a8e1b7b56c..ebc78b3ba3f 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/ComparatorFactory.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/ComparatorFactory.java
@@ -19,7 +19,10 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort;
 import java.util.Comparator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.authorizationgroup.AuthorizationGroupComparatorFactory;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.dataset.DataSetComparatorFactory;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.experiment.ExperimentComparatorFactory;
@@ -62,7 +65,7 @@ public abstract class ComparatorFactory
 
     public abstract boolean accepts(Class<?> sortOptionsClass);
 
-    public abstract Comparator getComparator(String field);
+    public abstract Comparator getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria);
 
     public abstract Comparator getDefaultComparator();
 
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/EntityComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/EntityComparatorFactory.java
index 88deff478fa..213a197831c 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/EntityComparatorFactory.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/EntityComparatorFactory.java
@@ -17,12 +17,15 @@
 package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort;
 
 import java.util.Comparator;
+import java.util.Map;
 
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.EntitySortOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.ICodeHolder;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IModificationDateHolder;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IPermIdHolder;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IRegistrationDateHolder;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
 
 /**
  * @author pkupczyk
@@ -38,7 +41,7 @@ public class EntityComparatorFactory<OBJECT extends ICodeHolder & IPermIdHolder
     }
 
     @Override
-    public Comparator<OBJECT> getComparator(String field)
+    public Comparator<OBJECT> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria)
     {
         if (EntitySortOptions.CODE.equals(field))
         {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/EntityWithPropertiesComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/EntityWithPropertiesComparatorFactory.java
index 0ba498077cf..e57c58e1198 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/EntityWithPropertiesComparatorFactory.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/EntityWithPropertiesComparatorFactory.java
@@ -17,14 +17,17 @@
 package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort;
 
 import java.util.Comparator;
+import java.util.Map;
 
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.EntityWithPropertiesSortOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.ICodeHolder;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IEntityTypeHolder;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IModificationDateHolder;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IPermIdHolder;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IPropertiesHolder;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IRegistrationDateHolder;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
 
 /**
  * @author pkupczyk
@@ -40,9 +43,12 @@ public class EntityWithPropertiesComparatorFactory<OBJECT extends ICodeHolder &
     }
 
     @Override
-    public Comparator<OBJECT> getComparator(String field)
+    public Comparator<OBJECT> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria)
     {
-        if (field.equals(EntityWithPropertiesSortOptions.TYPE))
+    	if (field.equals(EntityWithPropertiesSortOptions.FETCHED_FIELDS_SCORE))
+        {
+            return new FetchedFieldsScoreComparator<OBJECT>(parameters, criteria);
+        } if (field.equals(EntityWithPropertiesSortOptions.TYPE))
         {
             return new TypeComparator<OBJECT>();
         } else if (field.startsWith(EntityWithPropertiesSortOptions.PROPERTY))
@@ -50,7 +56,7 @@ public class EntityWithPropertiesComparatorFactory<OBJECT extends ICodeHolder &
             return new PropertyComparator<OBJECT>(field.substring(EntityWithPropertiesSortOptions.PROPERTY.length()));
         } else
         {
-            return super.getComparator(field);
+            return super.getComparator(field, parameters, criteria);
         }
     }
 
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/FetchedFieldsScoreComparator.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/FetchedFieldsScoreComparator.java
new file mode 100644
index 00000000000..4104cd4bd58
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/FetchedFieldsScoreComparator.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2016 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IEntityTypeHolder;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IPermIdHolder;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IPropertiesHolder;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.AbstractEntitySearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.CodeSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.StringPropertySearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSet;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.search.DataSetTypeSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.search.AbstractEntityTypeSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.Experiment;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.search.ExperimentTypeSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.Material;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.search.MaterialTypeSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.Sample;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.search.SampleTypeSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.ICodeHolder;
+
+
+/**
+ * @author juanf
+ */
+public class FetchedFieldsScoreComparator<OBJECT extends IEntityTypeHolder & IPropertiesHolder & ICodeHolder & IPermIdHolder> extends AbstractComparator<OBJECT, Integer>
+{
+
+	private Map<SortParameter, String> parameters;
+	private AbstractEntitySearchCriteria criteria;
+    private List<Pattern> partialMatchTerms = new ArrayList<Pattern>();
+    private List<String> exactMatchTerms = new ArrayList<String>();
+    private List<Boost> boosts = new ArrayList<Boost>();
+    private Map<OBJECT, Integer> scoreCache = new HashMap<>();
+    
+	public FetchedFieldsScoreComparator(Map<SortParameter, String> parameters, ISearchCriteria criteria) {
+		if (criteria == null || (criteria instanceof AbstractEntitySearchCriteria) == false)
+        {
+            throw new IllegalArgumentException("Missing criteria");
+        }
+        
+        if (parameters == null)
+        {
+            throw new IllegalArgumentException("Missing score parameters");
+        }
+        
+		this.parameters = parameters;
+		this.criteria = (AbstractEntitySearchCriteria) criteria;
+		
+        // Shared
+        this.partialMatchTerms = new ArrayList<Pattern>();
+        this.exactMatchTerms = new ArrayList<String>();
+        this.boosts = new ArrayList<Boost>();
+
+        for(ISearchCriteria subCriteria:this.criteria.getCriteria()) {
+        		ISearchCriteriaParser<ISearchCriteria> parser = criteriaParsers.get(subCriteria.getClass());
+        		
+        		if(parser != null) {
+        			String value = parser.getValue(subCriteria);
+        			
+        			// Full Index
+        			partialMatchTerms.add(getPartialMatchTerm(value));
+        			exactMatchTerms.add(getExactMatchTerm(value));
+        			boosts.add(parser.getBoost(subCriteria, 10));
+
+        			// Split Index
+        			String[] splitIndexes = value.replace("*", " ").replace("?", " ").replaceAll("\\s+", " ").trim().split(" ");
+
+        			for (String splitIndex : splitIndexes)
+        			{
+        				partialMatchTerms.add(getPartialMatchTerm(splitIndex));
+        				exactMatchTerms.add(getExactMatchTerm(splitIndex));
+        				boosts.add(parser.getBoost(subCriteria, 1));
+        			}
+        		}
+        		
+        }
+        
+	}
+    
+	@Override
+    public int compare(OBJECT o1, OBJECT o2)
+    {
+        return -1 * super.compare(o1, o2); // Higher scores first
+    }
+	
+    @Override
+    protected Integer getValue(OBJECT o)
+    {
+    		Integer score = scoreCache.get(o);
+    		if(score == null) {
+    			score = calculateScore(o);
+    			scoreCache.put(o, score);
+    		}
+    		return score;
+    }
+    
+    //
+    // V3 Helper Methods
+    //
+    
+    private static Map<Class, ISearchCriteriaParser> criteriaParsers = new HashMap<>(3);
+    
+    static {
+    		criteriaParsers.put(CodeSearchCriteria.class, new CodeCriteriaParser());
+    		criteriaParsers.put(StringPropertySearchCriteria.class, new StringPropertySearchCriteriaParser());
+    		criteriaParsers.put(SampleTypeSearchCriteria.class, new AbstractEntityTypeSearchCriteriaParser());
+    		criteriaParsers.put(ExperimentTypeSearchCriteria.class, new AbstractEntityTypeSearchCriteriaParser());
+    		criteriaParsers.put(DataSetTypeSearchCriteria.class, new AbstractEntityTypeSearchCriteriaParser());
+    		criteriaParsers.put(MaterialTypeSearchCriteria.class, new AbstractEntityTypeSearchCriteriaParser());
+    }
+
+    private static interface ISearchCriteriaParser<ISearchCriteria> {
+    		public String getValue(ISearchCriteria criteria);
+    		public Boost getBoost(ISearchCriteria criteria, int boost);
+    }
+    
+    private static class CodeCriteriaParser implements ISearchCriteriaParser<CodeSearchCriteria> {
+		@Override
+		public String getValue(CodeSearchCriteria criteria) {
+			return criteria.getFieldValue().getValue();
+		}
+
+		@Override
+		public Boost getBoost(CodeSearchCriteria criteria, int boost) {
+			return new Boost(boost, 0, 0, 0, null);
+		}
+    }
+    
+    private static class StringPropertySearchCriteriaParser implements ISearchCriteriaParser<StringPropertySearchCriteria> {
+		@Override
+		public String getValue(StringPropertySearchCriteria criteria) {
+			return criteria.getFieldValue().getValue();
+		}
+
+		@Override
+		public Boost getBoost(StringPropertySearchCriteria criteria, int boost) {
+			return new Boost(0, 0, 0, boost, criteria.getFieldName());
+		}
+    }
+    
+    private static class AbstractEntityTypeSearchCriteriaParser implements ISearchCriteriaParser<AbstractEntityTypeSearchCriteria> {
+		@Override
+		public String getValue(AbstractEntityTypeSearchCriteria criteria) {
+			for(ISearchCriteria subCriteria:criteria.getCriteria()) {
+				if(subCriteria instanceof CodeSearchCriteria) {
+					return criteriaParsers.get(subCriteria.getClass()).getValue(subCriteria);
+				}
+			}
+			return null;
+		}
+
+		@Override
+		public Boost getBoost(AbstractEntityTypeSearchCriteria criteria, int boost) {
+			return new Boost(0, boost, 0, 0, null);
+		}
+    }
+    
+    //
+    // Scoring algorithm
+    //
+	
+    private boolean hasType(OBJECT o ) {
+    		if(o instanceof Sample) {
+    			return ((Sample)o).getFetchOptions().hasType();
+    		} else if(o instanceof Experiment) {
+    			return ((Experiment)o).getFetchOptions().hasType();
+    		} if(o instanceof DataSet) {
+    			return ((DataSet)o).getFetchOptions().hasType();
+    		} if(o instanceof Material) {
+    			return ((Material)o).getFetchOptions().hasType();
+    		} else {
+    			return false;
+    		}
+    }
+    
+    private boolean hasProperties(OBJECT o ) {
+		if(o instanceof Sample) {
+			return ((Sample)o).getFetchOptions().hasProperties();
+		} else if(o instanceof Experiment) {
+			return ((Experiment)o).getFetchOptions().hasProperties();
+		} if(o instanceof DataSet) {
+			return ((DataSet)o).getFetchOptions().hasProperties();
+		} if(o instanceof Material) {
+			return ((Material)o).getFetchOptions().hasProperties();
+		} else {
+			return false;
+		}
+}
+    
+	private Integer calculateScore(OBJECT o ) {
+		int score = 0;
+		String code = o.getCode();
+		String typeCode = (hasType(o))?o.getType().getCode():null;
+		Map<String, String> properties = (hasProperties(o))?o.getProperties():null;
+		
+		for (int i = 0; i < exactMatchTerms.size(); i++)
+	    {
+	        Pattern partialTerm = partialMatchTerms.get(i);
+	        String exactTerm = exactMatchTerms.get(i);
+	        Boost boost = boosts.get(i);
+	
+	        // 1. Code
+	        if(code != null) {
+	        		if (isPartialMatch(code, partialTerm))
+	            { // If code matches partially
+	                score += 100000 * boost.getCodeBoost();
+	                if (isExactMatch(code, exactTerm))
+	                { // If code matches exactly
+	                    score += 1000000 * boost.getCodeBoost();
+	                }
+	            }
+	        }
+	
+	        // 2. Entity type code
+	        if(typeCode != null) 
+	        {
+	        		if (isExactMatch(typeCode, exactTerm))
+	            { // If type matches exactly
+	                score += 1000 * boost.getTypeCodeBoost();
+	            }
+	        }
+	        
+	
+	        // 3. Properties
+	        if(properties != null) {
+	        		if (properties != null && properties.keySet() != null)
+	            {
+	                for (String propertykey : properties.keySet())
+	                {
+	                    String propertyValue = properties.get(propertykey);
+	                    if (isPartialMatch(propertyValue, partialTerm))
+	                    { // If property matches partially
+	                        score += 100 * boost.getPropertyBoost(propertykey);
+	                        if (isExactMatch(propertyValue, exactTerm))
+	                        { // If property matches exactly
+	                            score += 10000 * boost.getPropertyBoost(propertykey);
+	                        }
+	                    }
+	                }
+	            }
+	        }
+	    }
+		
+		System.out.println("CODE: "+ code + " SCORE: " + score);
+		return score;
+	}
+	
+    //
+    // Helper Methods
+    //
+    
+    private static class Boost
+    {
+        private int codeBoost;
+
+        private int typeCodeBoost;
+
+        private int propertyBoost;
+
+        private int propertyDefaultBoost;
+
+        private String propertyName;
+
+        public Boost(int codeBoost, int typeCodeBoost, int propertyDefaultBoost, int propertyBoost, String propertyName)
+        {
+            super();
+            this.codeBoost = codeBoost;
+            this.typeCodeBoost = typeCodeBoost;
+            this.propertyDefaultBoost = propertyDefaultBoost;
+            this.propertyBoost = propertyBoost;
+            this.propertyName = propertyName;
+        }
+
+        public int getCodeBoost()
+        {
+            return codeBoost;
+        }
+
+        public int getTypeCodeBoost()
+        {
+            return typeCodeBoost;
+        }
+
+        public int getPropertyBoost(String propertyNameToBoost)
+        {
+            if (this.propertyName != null && this.propertyName.equals(propertyNameToBoost))
+            {
+                return propertyBoost;
+            } else
+            {
+                return propertyDefaultBoost;
+            }
+        }
+
+    }
+
+    private Pattern getPartialMatchTerm(String term)
+    {
+        return Pattern.compile(("*" + term + "*").replace("*", ".*").replace("?", ".?"), Pattern.CASE_INSENSITIVE);
+    }
+
+    private String getExactMatchTerm(String term)
+    {
+        return term.replace("*", "").replace("?", "");
+    }
+
+    private boolean isExactMatch(String value, String term)
+    {
+        if (value != null && term != null)
+        {
+            return value.equalsIgnoreCase(term);
+        } else
+        {
+            return false;
+        }
+    }
+
+    private boolean isPartialMatch(String value, Pattern pattern)
+    {
+        if (value != null && pattern != null)
+        {
+            return pattern.matcher(value).matches();
+        } else
+        {
+            return false;
+        }
+    }
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/SortAndPage.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/SortAndPage.java
index 63d9eba47c8..80afc702f5a 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/SortAndPage.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/SortAndPage.java
@@ -37,6 +37,7 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.Sorting;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.view.AbstractCollectionView;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.view.ListView;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.view.SetView;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
 
 /**
  * @author pkupczyk
@@ -49,7 +50,7 @@ public class SortAndPage
 
     private MethodsCache methodsCache = new MethodsCache();
 
-    public <T, C extends Collection<T>> C sortAndPage(C objects, FetchOptions fo)
+    public <T, C extends Collection<T>> C sortAndPage(C objects, ISearchCriteria c, FetchOptions fo)
     {
         C newObjects = objects;
 
@@ -58,21 +59,21 @@ public class SortAndPage
             newObjects = (C) ((AbstractCollectionView) objects).getOriginalCollection();
         }
 
-        newObjects = (C) sort(newObjects, fo);
+        newObjects = (C) sort(newObjects, c, fo);
         newObjects = (C) page(newObjects, fo);
-        nest(newObjects, fo);
+        nest(newObjects, c, fo);
 
         return newObjects;
     }
-
-    private Collection sort(Collection objects, FetchOptions fo)
+    
+    private Collection sort(Collection objects, ISearchCriteria c, FetchOptions fo)
     {
         if (objects == null || objects.isEmpty())
         {
             return objects;
         }
 
-        Comparator comparator = getComparator(fo);
+        Comparator comparator = getComparator(c, fo);
 
         if (comparator != null)
         {
@@ -135,7 +136,7 @@ public class SortAndPage
         }
     }
 
-    private void nest(Collection objects, FetchOptions fo)
+    private void nest(Collection objects, ISearchCriteria c, FetchOptions fo)
     {
         if (objects == null || objects.isEmpty())
         {
@@ -177,14 +178,14 @@ public class SortAndPage
                         {
                             if (value instanceof Collection)
                             {
-                                Collection newValue = sortAndPage((Collection) value, subFo);
+                                Collection newValue = sortAndPage((Collection) value, c, subFo);
                                 setMethod.invoke(object, newValue);
                             } else if (value instanceof Map)
                             {
-                                sortAndPage(((Map) value).values(), subFo);
+                                sortAndPage(((Map) value).values(), c, subFo);
                             } else
                             {
-                                Collection newValue = sortAndPage(Collections.singleton(value), subFo);
+                                Collection newValue = sortAndPage(Collections.singleton(value), c, subFo);
                                 if (setMethod != null)
                                 {
                                     setMethod.invoke(object, newValue.iterator().next());
@@ -200,7 +201,7 @@ public class SortAndPage
         }
     }
 
-    protected Comparator getComparator(FetchOptions fetchOptions)
+    protected Comparator getComparator(ISearchCriteria criteria, FetchOptions fetchOptions)
     {
         if (fetchOptions == null)
         {
@@ -240,7 +241,7 @@ public class SortAndPage
                             throw new IllegalArgumentException("Comparator factory for sort by " + sortByClass + " not found");
                         }
 
-                        Comparator aComparator = comparatorFactory.getComparator(sorting.getField());
+                        Comparator aComparator = comparatorFactory.getComparator(sorting.getField(), sorting.getParameters(), criteria);
 
                         if (aComparator == null)
                         {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/tag/TagComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/tag/TagComparatorFactory.java
index 0ae8a397c2f..598231a9f07 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/tag/TagComparatorFactory.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/tag/TagComparatorFactory.java
@@ -17,7 +17,10 @@
 package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.tag;
 
 import java.util.Comparator;
+import java.util.Map;
 
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.Tag;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.fetchoptions.TagSortOptions;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.CodeComparator;
@@ -37,7 +40,7 @@ public class TagComparatorFactory extends ComparatorFactory
     }
 
     @Override
-    public Comparator<Tag> getComparator(String field)
+    public Comparator<Tag> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria)
     {
         if (TagSortOptions.CODE.equals(field))
         {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/vocabulary/VocabularyComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/vocabulary/VocabularyComparatorFactory.java
index a6740821d46..dab46dbd380 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/vocabulary/VocabularyComparatorFactory.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/vocabulary/VocabularyComparatorFactory.java
@@ -17,7 +17,10 @@
 package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.vocabulary;
 
 import java.util.Comparator;
+import java.util.Map;
 
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.Vocabulary;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.fetchoptions.VocabularySortOptions;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.CodeComparator;
@@ -37,7 +40,7 @@ public class VocabularyComparatorFactory extends ComparatorFactory
     }
 
     @Override
-    public Comparator<Vocabulary> getComparator(String field)
+    public Comparator<Vocabulary> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria)
     {
         if (VocabularySortOptions.CODE.equals(field))
         {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/vocabulary/VocabularyTermComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/vocabulary/VocabularyTermComparatorFactory.java
index 7d4fb30ccc8..35bdb6d11d9 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/vocabulary/VocabularyTermComparatorFactory.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/vocabulary/VocabularyTermComparatorFactory.java
@@ -17,7 +17,10 @@
 package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.vocabulary;
 
 import java.util.Comparator;
+import java.util.Map;
 
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.VocabularyTerm;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.fetchoptions.VocabularyTermSortOptions;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.CodeComparator;
@@ -36,7 +39,7 @@ public class VocabularyTermComparatorFactory extends ComparatorFactory
     }
 
     @Override
-    public Comparator<VocabularyTerm> getComparator(String field)
+    public Comparator<VocabularyTerm> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria)
     {
         if (VocabularyTermSortOptions.CODE.equals(field))
         {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/sample/SampleTypeTranslator.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/sample/SampleTypeTranslator.java
index 5763f56f49b..03e40acf46d 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/sample/SampleTypeTranslator.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/sample/SampleTypeTranslator.java
@@ -105,7 +105,7 @@ public class SampleTypeTranslator extends AbstractCachingTranslator<Long, Sample
         {
             Collection<PropertyAssignment> assignments = relations.get(ISamplePropertyAssignmentTranslator.class, typeId);
             List<PropertyAssignment> propertyAssignments = new ArrayList<>(assignments);
-            result.setPropertyAssignments(new SortAndPage().sortAndPage(propertyAssignments, fetchOptions.withPropertyAssignments()));
+            result.setPropertyAssignments(new SortAndPage().sortAndPage(propertyAssignments, null, fetchOptions.withPropertyAssignments()));
         }
 
         if (fetchOptions.hasSemanticAnnotations())
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/SortAndPageTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/SortAndPageTest.java
index 45fc0ff733c..211a2290c29 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/SortAndPageTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/SortAndPageTest.java
@@ -16,17 +16,168 @@ import org.testng.annotations.Test;
 
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.Material;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.fetchoptions.MaterialFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.search.MaterialSearchCriteria;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.Person;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.Project;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.Sample;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.SampleType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.fetchoptions.SampleFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.search.SampleSearchCriteria;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.Space;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.Tag;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.SortAndPage;
 
 public class SortAndPageTest
 {
+	@Test
+    public void testFetchedFieldsScore_CodeScore()
+    {
+		SampleType sampleTypeA = new SampleType();
+		sampleTypeA.setCode("DUMMY_CODE_A");
+		
+		SampleType sampleTypeB = new SampleType();
+		sampleTypeB.setCode("DUMMY_CODE_B");
+		
+		String propertyCode = "DUMMY_PROPERTY";
+		
+		SampleSearchCriteria c = new SampleSearchCriteria();
+		c.withOrOperator();
+        c.withCode().thatEquals("S2");
+        
+		SampleFetchOptions fo = new SampleFetchOptions();
+		fo.withType();
+		fo.withProperties();
+		fo.sortBy().fetchedFieldsScore();
+		
+        Sample sample1 = new Sample();
+        sample1.setType(sampleTypeA);
+        sample1.setCode("S1");
+        sample1.setProperty(propertyCode, "DUMMY_S1");
+        sample1.setFetchOptions(fo);
+
+        Sample sample2 = new Sample();
+        sample2.setType(sampleTypeB);
+        sample2.setCode("S2");
+        sample2.setProperty(propertyCode, "DUMMY_S2");
+        sample2.setFetchOptions(fo);
+
+        Sample sample3 = new Sample();
+        sample3.setType(sampleTypeA);
+        sample3.setCode("S3");
+        sample3.setProperty(propertyCode, "DUMMY_S3");
+        sample3.setFetchOptions(fo);
+
+        List<Sample> samples = new ArrayList<Sample>();
+        samples.add(sample1);
+        samples.add(sample2);
+        samples.add(sample3);
+
+        Collection<Sample> results = new SortAndPage().sortAndPage(samples, c, fo);
+
+        assertEquals(results, list(sample2, sample1, sample3));
+    }
+	
+	@Test
+    public void testFetchedFieldsScore_PropertyScore()
+    {
+		SampleType sampleTypeA = new SampleType();
+		sampleTypeA.setCode("DUMMY_CODE_A");
+		
+		SampleType sampleTypeB = new SampleType();
+		sampleTypeB.setCode("DUMMY_CODE_B");
+		
+		String propertyCode = "DUMMY_PROPERTY";
+		
+		SampleSearchCriteria c = new SampleSearchCriteria();
+		c.withOrOperator();
+        c.withProperty(propertyCode).thatEquals("DUMMY_S3");
+        
+		SampleFetchOptions fo = new SampleFetchOptions();
+		fo.withType();
+		fo.withProperties();
+		fo.sortBy().fetchedFieldsScore();
+		
+        Sample sample1 = new Sample();
+        sample1.setType(sampleTypeA);
+        sample1.setCode("S1");
+        sample1.setProperty(propertyCode, "DUMMY_S1");
+        sample1.setFetchOptions(fo);
+
+        Sample sample2 = new Sample();
+        sample2.setType(sampleTypeB);
+        sample2.setCode("S2");
+        sample2.setProperty(propertyCode, "DUMMY_S2");
+        sample2.setFetchOptions(fo);
+
+        Sample sample3 = new Sample();
+        sample3.setType(sampleTypeA);
+        sample3.setCode("S3");
+        sample3.setProperty(propertyCode, "DUMMY_S3");
+        sample3.setFetchOptions(fo);
+
+        List<Sample> samples = new ArrayList<Sample>();
+        samples.add(sample1);
+        samples.add(sample2);
+        samples.add(sample3);
+
+        Collection<Sample> results = new SortAndPage().sortAndPage(samples, c, fo);
+
+        assertEquals(results, list(sample3, sample1, sample2));
+    }
+	
+	@Test
+    public void testFetchedFieldsScore_TypeScore()
+    {
+		SampleType sampleTypeA = new SampleType();
+		sampleTypeA.setCode("DUMMY_CODE_A");
+		
+		SampleType sampleTypeB = new SampleType();
+		sampleTypeB.setCode("DUMMY_CODE_B");
+		
+		String propertyCode = "DUMMY_PROPERTY";
+		
+		SampleSearchCriteria c = new SampleSearchCriteria();
+		c.withOrOperator();
+        c.withType().withCode().thatEquals(sampleTypeA.getCode());
+        
+		SampleFetchOptions fo = new SampleFetchOptions();
+		fo.withType();
+		fo.withProperties();
+		fo.sortBy().fetchedFieldsScore();
+		
+        Sample sample1 = new Sample();
+        sample1.setType(sampleTypeA);
+        sample1.setCode("S1");
+        sample1.setProperty(propertyCode, "DUMMY_S1");
+        sample1.setFetchOptions(fo);
+
+        Sample sample2 = new Sample();
+        sample2.setType(sampleTypeB);
+        sample2.setCode("S2");
+        sample2.setProperty(propertyCode, "DUMMY_S2");
+        sample2.setFetchOptions(fo);
+
+        Sample sample3 = new Sample();
+        sample3.setType(sampleTypeA);
+        sample3.setCode("S3");
+        sample3.setProperty(propertyCode, "DUMMY_S3");
+        sample3.setFetchOptions(fo);
+
+        List<Sample> samples = new ArrayList<Sample>();
+        samples.add(sample1);
+        samples.add(sample2);
+        samples.add(sample3);
+
+        Collection<Sample> results = new SortAndPage().sortAndPage(samples, c, fo);
+
+        assertEquals(results, list(sample1, sample3, sample2));
+    }
+	
     @Test
     public void testTopLevel()
     {
+    		MaterialSearchCriteria c = new MaterialSearchCriteria();
+    		
         MaterialFetchOptions fo = new MaterialFetchOptions();
         fo.sortBy().code().desc();
         fo.from(1).count(2);
@@ -48,7 +199,7 @@ public class SortAndPageTest
         materials.add(material2);
         materials.add(material3);
 
-        Collection<Material> results = new SortAndPage().sortAndPage(materials, fo);
+        Collection<Material> results = new SortAndPage().sortAndPage(materials, c, fo);
 
         assertEquals(results, list(material2, material1));
     }
@@ -56,6 +207,8 @@ public class SortAndPageTest
     @Test
     public void testSubLevel()
     {
+    		MaterialSearchCriteria c = new MaterialSearchCriteria();
+    	
         MaterialFetchOptions fo = new MaterialFetchOptions();
         fo.sortBy().code().desc();
         fo.withTags().from(1).count(1);
@@ -81,7 +234,7 @@ public class SortAndPageTest
         materials.add(material1);
         materials.add(material2);
 
-        List<Material> results = new SortAndPage().sortAndPage(materials, fo);
+        List<Material> results = new SortAndPage().sortAndPage(materials, c, fo);
 
         assertEquals(results, list(material2, material1));
         assertEquals(results.get(0).getTags(), set(tag3));
@@ -91,6 +244,8 @@ public class SortAndPageTest
     @Test
     public void testSubLevelThroughSingleRelation()
     {
+    		MaterialSearchCriteria c = new MaterialSearchCriteria();
+    	
         MaterialFetchOptions fo = new MaterialFetchOptions();
         fo.sortBy().code().desc();
         fo.withTags().from(1).count(1);
@@ -149,7 +304,7 @@ public class SortAndPageTest
         materials.add(material1);
         materials.add(material2);
 
-        List<Material> results = new SortAndPage().sortAndPage(materials, fo);
+        List<Material> results = new SortAndPage().sortAndPage(materials, c, fo);
 
         assertEquals(results, list(material2, material1));
 
@@ -168,6 +323,8 @@ public class SortAndPageTest
     @Test
     public void testSortByMultipleFields()
     {
+    		MaterialSearchCriteria c = new MaterialSearchCriteria();
+    	
         MaterialFetchOptions fo = new MaterialFetchOptions();
         fo.sortBy().code().desc();
         fo.sortBy().registrationDate().asc();
@@ -192,7 +349,7 @@ public class SortAndPageTest
         materials.add(material2);
         materials.add(material3);
 
-        List<Material> results = new SortAndPage().sortAndPage(materials, fo);
+        List<Material> results = new SortAndPage().sortAndPage(materials, c, fo);
 
         assertEquals(results.get(0), material3);
         assertEquals(results.get(1), material2);
@@ -202,6 +359,8 @@ public class SortAndPageTest
     @Test
     public void testSamePageMultipleTimes()
     {
+    		MaterialSearchCriteria c = new MaterialSearchCriteria();
+    	
         Tag tag1 = new Tag();
         tag1.setCode("T1");
         Tag tag2 = new Tag();
@@ -227,7 +386,7 @@ public class SortAndPageTest
         materials.add(material1);
         materials.add(material2);
 
-        List<Material> results = new SortAndPage().sortAndPage(materials, fo);
+        List<Material> results = new SortAndPage().sortAndPage(materials, c, fo);
 
         assertEquals(results, list(material2));
         assertEquals(results.get(0).getTags(), set(tag3));
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/EntityWithPropertiesSortOptions.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/EntityWithPropertiesSortOptions.java
index 8084b9e430a..7412b168f21 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/EntityWithPropertiesSortOptions.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/EntityWithPropertiesSortOptions.java
@@ -16,6 +16,9 @@
 
 package ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import com.fasterxml.jackson.annotation.JsonIgnore;
 
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.ICodeHolder;
@@ -34,13 +37,26 @@ public class EntityWithPropertiesSortOptions<OBJECT extends ICodeHolder & IPermI
 {
 
     private static final long serialVersionUID = 1L;
-
+    
+    @JsonIgnore
+    public static final String FETCHED_FIELDS_SCORE = "FETCHED_FIELDS_SCORE";
+    
     @JsonIgnore
     public static final String TYPE = "TYPE";
 
     @JsonIgnore
     public static final String PROPERTY = "PROPERTY";
-
+    
+    public SortOrder fetchedFieldsScore() {
+    		Map<SortParameter, String> parameters = new HashMap<>();
+    		parameters.put(SortParameter.FULL_CODE_BOOST, 	"1000000");
+    		parameters.put(SortParameter.PARTIAL_CODE_BOOST,  "100000");
+    		parameters.put(SortParameter.FULL_PROPERTY_BOOST,  "10000");
+    		parameters.put(SortParameter.FULL_TYPE_BOOST, 	   "1000");
+    		parameters.put(SortParameter.PARTIAL_PROPERTY_BOOST, "100");
+		return getOrCreateSorting(FETCHED_FIELDS_SCORE, parameters);
+    }
+    
     public SortOrder type()
     {
         return getOrCreateSorting(TYPE);
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/SortOptions.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/SortOptions.java
index 9859cfa1d08..c0d0ac4b248 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/SortOptions.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/SortOptions.java
@@ -20,6 +20,7 @@ import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.commons.lang.StringUtils;
 
@@ -37,12 +38,17 @@ public abstract class SortOptions<OBJECT> implements Serializable
     private List<Sorting> sortings = new LinkedList<>();
 
     protected SortOrder getOrCreateSorting(String field)
+    {
+    		return getOrCreateSorting(field, null);
+    }
+    
+    protected SortOrder getOrCreateSorting(String field, Map<SortParameter, String> parameters)
     {
         SortOrder order = getSorting(field);
         if (order == null)
         {
             order = new SortOrder();
-            sortings.add(new Sorting(field, order));
+            sortings.add(new Sorting(field, order, parameters));
         }
         return order;
     }
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/SortParameter.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/SortParameter.java
new file mode 100644
index 00000000000..232fb2678e6
--- /dev/null
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/SortParameter.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2015 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions;
+
+import ch.systemsx.cisd.base.annotation.JsonObject;
+
+/**
+ * @author juanf
+ */
+@JsonObject("as.dto.common.fetchoptions.SortParameter")
+public enum SortParameter
+{
+
+    FULL_CODE_BOOST, PARTIAL_CODE_BOOST, FULL_TYPE_BOOST, FULL_PROPERTY_BOOST, PARTIAL_PROPERTY_BOOST
+
+}
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/Sorting.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/Sorting.java
index 4f819b261ac..11b10ccff58 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/Sorting.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/Sorting.java
@@ -17,6 +17,7 @@
 package ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions;
 
 import java.io.Serializable;
+import java.util.Map;
 
 import ch.systemsx.cisd.base.annotation.JsonObject;
 
@@ -32,16 +33,24 @@ public class Sorting implements Serializable
     private String field;
 
     private SortOrder order;
-
+    
+    private Map<SortParameter, String> parameters;
+    
     @SuppressWarnings("unused")
     private Sorting()
     {
     }
 
     public Sorting(String field, SortOrder order)
+    {
+        this(field, order, null);
+    }
+    
+    public Sorting(String field, SortOrder order, Map<SortParameter, String> parameters)
     {
         this.field = field;
         this.order = order;
+        this.parameters = parameters;
     }
 
     public String getField()
@@ -53,6 +62,10 @@ public class Sorting implements Serializable
     {
         return order;
     }
+    
+    public Map<SortParameter, String> getParameters() {
+    		return parameters;
+    }
 
     @Override
     public String toString()
-- 
GitLab