From 5e2028bcd01ffbcfe9a3693bbabaed82c98ecbd8 Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Tue, 5 Apr 2016 12:32:11 +0000
Subject: [PATCH] SSDM-3401: Refactoring: Extracting Matcher and subclasses out
 AbstractSearchObjectManuallyExecutor. Introducing
 AbstractIdSearchMeathodExecutor.

SVN: 36085
---
 .../AbstractSearchObjectManuallyExecutor.java | 88 +------------------
 .../asapi/v3/executor/common/CodeMatcher.java | 35 ++++++++
 .../asapi/v3/executor/common/Matcher.java     | 29 ++++++
 .../executor/common/SimpleFieldMatcher.java   | 46 ++++++++++
 .../executor/common/StringFieldMatcher.java   | 74 ++++++++++++++++
 .../AbstractIdSearchMethodExecutor.java       | 59 +++++++++++++
 .../SearchCustomASServiceMethodExecutor.java  |  6 +-
 .../SearchProjectSqlMethodExecutor.java       | 23 +----
 .../method/SearchSpaceSqlMethodExecutor.java  | 23 +----
 .../SearchVocabularyTermMethodExecutor.java   | 23 +----
 .../project/SearchProjectExecutor.java        | 25 ++----
 .../executor/space/SearchSpaceExecutor.java   | 20 ++---
 .../vocabulary/SearchVocabularyExecutor.java  | 21 ++---
 .../SearchVocabularyTermExecutor.java         | 25 ++----
 14 files changed, 288 insertions(+), 209 deletions(-)
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/CodeMatcher.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/Matcher.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/SimpleFieldMatcher.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/StringFieldMatcher.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/AbstractIdSearchMethodExecutor.java

diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/AbstractSearchObjectManuallyExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/AbstractSearchObjectManuallyExecutor.java
index a56c32f1aab..304b906cd72 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/AbstractSearchObjectManuallyExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/AbstractSearchObjectManuallyExecutor.java
@@ -26,15 +26,8 @@ import java.util.Set;
 import org.springframework.beans.factory.annotation.Autowired;
 
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.AbstractObjectSearchCriteria;
-import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.AbstractStringValue;
-import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.AnyStringValue;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.SearchOperator;
-import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.StringContainsValue;
-import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.StringEndsWithValue;
-import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.StringEqualToValue;
-import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.StringFieldSearchCriteria;
-import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.StringStartsWithValue;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
 
@@ -50,7 +43,7 @@ public abstract class AbstractSearchObjectManuallyExecutor<CRITERIA extends Abst
 
     protected abstract List<OBJECT> listAll();
 
-    protected abstract Matcher getMatcher(ISearchCriteria criteria);
+    protected abstract Matcher<OBJECT> getMatcher(ISearchCriteria criteria);
 
     @Override
     public List<OBJECT> search(IOperationContext context, CRITERIA criteria)
@@ -78,7 +71,7 @@ public abstract class AbstractSearchObjectManuallyExecutor<CRITERIA extends Abst
 
             for (ISearchCriteria subCriteria : criteria.getCriteria())
             {
-                Matcher matcher = getMatcher(subCriteria);
+                Matcher<OBJECT> matcher = getMatcher(subCriteria);
 
                 List<OBJECT> partialMatch = matcher.getMatching(context, objects, subCriteria);
                 if (partialMatch == null)
@@ -111,81 +104,4 @@ public abstract class AbstractSearchObjectManuallyExecutor<CRITERIA extends Abst
         }
     }
 
-    protected abstract class Matcher
-    {
-
-        public abstract List<OBJECT> getMatching(IOperationContext context, List<OBJECT> objects, ISearchCriteria criteria);
-
-    }
-
-    protected abstract class SimpleFieldMatcher extends Matcher
-    {
-
-        @Override
-        public List<OBJECT> getMatching(IOperationContext context, List<OBJECT> objects, ISearchCriteria criteria)
-        {
-            List<OBJECT> matches = new ArrayList<OBJECT>();
-
-            for (OBJECT object : objects)
-            {
-                if (isMatching(context, object, criteria))
-                {
-                    matches.add(object);
-                }
-            }
-
-            return matches;
-        }
-
-        protected abstract boolean isMatching(IOperationContext context, OBJECT object, ISearchCriteria criteria);
-
-    }
-
-    protected abstract class StringFieldMatcher extends SimpleFieldMatcher
-    {
-
-        @Override
-        protected boolean isMatching(IOperationContext context, OBJECT object, ISearchCriteria criteria)
-        {
-            AbstractStringValue fieldValue = ((StringFieldSearchCriteria) criteria).getFieldValue();
-
-            if (fieldValue == null || fieldValue.getValue() == null || fieldValue instanceof AnyStringValue)
-            {
-                return true;
-            }
-
-            String actualValue = getFieldValue(object);
-
-            if (actualValue == null)
-            {
-                actualValue = "";
-            } else
-            {
-                actualValue = actualValue.toLowerCase();
-            }
-
-            String searchedValue = fieldValue.getValue().toLowerCase();
-
-            if (fieldValue instanceof StringEqualToValue)
-            {
-                return actualValue.equals(searchedValue);
-            } else if (fieldValue instanceof StringContainsValue)
-            {
-                return actualValue.contains(searchedValue);
-            } else if (fieldValue instanceof StringStartsWithValue)
-            {
-                return actualValue.startsWith(searchedValue);
-            } else if (fieldValue instanceof StringEndsWithValue)
-            {
-                return actualValue.endsWith(searchedValue);
-            } else
-            {
-                throw new IllegalArgumentException("Unknown string value: " + criteria.getClass());
-            }
-        }
-
-        protected abstract String getFieldValue(OBJECT object);
-
-    }
-
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/CodeMatcher.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/CodeMatcher.java
new file mode 100644
index 00000000000..a5fde3d894b
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/CodeMatcher.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 ETH Zuerich, SIS
+ *
+ * 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.executor.common;
+
+import ch.systemsx.cisd.openbis.generic.shared.basic.ICodeHolder;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class CodeMatcher<OBJECT extends ICodeHolder> extends StringFieldMatcher<OBJECT>
+{
+
+    @Override
+    protected String getFieldValue(OBJECT object)
+    {
+        return object.getCode();
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/Matcher.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/Matcher.java
new file mode 100644
index 00000000000..fb6eedf7baf
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/Matcher.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 ETH Zuerich, SIS
+ *
+ * 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.executor.common;
+
+import java.util.List;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+
+public abstract class Matcher<OBJECT>
+{
+
+    public abstract List<OBJECT> getMatching(IOperationContext context, List<OBJECT> objects, ISearchCriteria criteria);
+
+}
\ No newline at end of file
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/SimpleFieldMatcher.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/SimpleFieldMatcher.java
new file mode 100644
index 00000000000..373ce37cfef
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/SimpleFieldMatcher.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016 ETH Zuerich, SIS
+ *
+ * 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.executor.common;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+
+public abstract class SimpleFieldMatcher<OBJECT> extends Matcher<OBJECT>
+{
+
+    @Override
+    public List<OBJECT> getMatching(IOperationContext context, List<OBJECT> objects, ISearchCriteria criteria)
+    {
+        List<OBJECT> matches = new ArrayList<OBJECT>();
+
+        for (OBJECT object : objects)
+        {
+            if (isMatching(context, object, criteria))
+            {
+                matches.add(object);
+            }
+        }
+
+        return matches;
+    }
+
+    protected abstract boolean isMatching(IOperationContext context, OBJECT object, ISearchCriteria criteria);
+
+}
\ No newline at end of file
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/StringFieldMatcher.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/StringFieldMatcher.java
new file mode 100644
index 00000000000..1a109b4a7e8
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/StringFieldMatcher.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 ETH Zuerich, SIS
+ *
+ * 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.executor.common;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.AbstractStringValue;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.AnyStringValue;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.StringContainsValue;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.StringEndsWithValue;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.StringEqualToValue;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.StringFieldSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.StringStartsWithValue;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+
+public abstract class StringFieldMatcher<OBJECT> extends SimpleFieldMatcher<OBJECT>
+{
+
+    @Override
+    protected boolean isMatching(IOperationContext context, OBJECT object, ISearchCriteria criteria)
+    {
+        AbstractStringValue fieldValue = ((StringFieldSearchCriteria) criteria).getFieldValue();
+
+        if (fieldValue == null || fieldValue.getValue() == null || fieldValue instanceof AnyStringValue)
+        {
+            return true;
+        }
+
+        String actualValue = getFieldValue(object);
+
+        if (actualValue == null)
+        {
+            actualValue = "";
+        } else
+        {
+            actualValue = actualValue.toLowerCase();
+        }
+
+        String searchedValue = fieldValue.getValue().toLowerCase();
+
+        if (fieldValue instanceof StringEqualToValue)
+        {
+            return actualValue.equals(searchedValue);
+        } else if (fieldValue instanceof StringContainsValue)
+        {
+            return actualValue.contains(searchedValue);
+        } else if (fieldValue instanceof StringStartsWithValue)
+        {
+            return actualValue.startsWith(searchedValue);
+        } else if (fieldValue instanceof StringEndsWithValue)
+        {
+            return actualValue.endsWith(searchedValue);
+        } else
+        {
+            throw new IllegalArgumentException("Unknown string value: " + criteria.getClass());
+        }
+    }
+
+    protected abstract String getFieldValue(OBJECT object);
+
+}
\ No newline at end of file
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/AbstractIdSearchMethodExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/AbstractIdSearchMethodExecutor.java
new file mode 100644
index 00000000000..8d13621c735
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/AbstractIdSearchMethodExecutor.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016 ETH Zuerich, SIS
+ *
+ * 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.executor.method;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.FetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.AbstractSearchCriteria;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.ISearchObjectExecutor;
+import ch.systemsx.cisd.openbis.generic.shared.basic.IIdHolder;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public abstract class AbstractIdSearchMethodExecutor<OBJECT, OBJECT_PE extends IIdHolder, 
+            CRITERIA extends AbstractSearchCriteria, FETCH_OPTIONS extends FetchOptions<OBJECT>>
+        extends AbstractSearchMethodExecutor<OBJECT, Long, CRITERIA, FETCH_OPTIONS>
+{
+
+    @Override
+    protected ISearchObjectExecutor<CRITERIA, Long> getSearchExecutor()
+    {
+        return new ISearchObjectExecutor<CRITERIA, Long>()
+            {
+                @Override
+                public List<Long> search(IOperationContext context, CRITERIA criteria)
+                {
+                    List<OBJECT_PE> objectPEs = searchPEs(context, criteria);
+                    List<Long> ids = new ArrayList<Long>();
+                    for (OBJECT_PE objectPE : objectPEs)
+                    {
+                        ids.add(objectPE.getId());
+                    }
+                    return ids;
+                }
+            };
+    }
+    
+    protected abstract List<OBJECT_PE> searchPEs(IOperationContext context, CRITERIA criteria);
+    
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/SearchCustomASServiceMethodExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/SearchCustomASServiceMethodExecutor.java
index 59ecd8da264..e233252cf30 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/SearchCustomASServiceMethodExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/SearchCustomASServiceMethodExecutor.java
@@ -32,6 +32,8 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.service.fetchoptions.CustomASSer
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.service.search.CustomASServiceSearchCriteria;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.OperationContext;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.AbstractSearchObjectManuallyExecutor;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.Matcher;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.StringFieldMatcher;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.SortAndPage;
 import ch.systemsx.cisd.openbis.generic.server.ComponentNames;
 import ch.systemsx.cisd.openbis.generic.shared.IOpenBisSessionManager;
@@ -64,7 +66,7 @@ public class SearchCustomASServiceMethodExecutor extends AbstractSearchObjectMan
     }
 
     @Override
-    protected Matcher getMatcher(ISearchCriteria criteria)
+    protected Matcher<CustomASService> getMatcher(ISearchCriteria criteria)
     {
         if (criteria instanceof CodeSearchCriteria)
         {
@@ -73,7 +75,7 @@ public class SearchCustomASServiceMethodExecutor extends AbstractSearchObjectMan
         throw new IllegalArgumentException("Unknown search criteria: " + criteria.getClass());
     }
 
-    private class CodeMatcher extends StringFieldMatcher
+    private class CodeMatcher extends StringFieldMatcher<CustomASService>
     {
 
         @Override
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/SearchProjectSqlMethodExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/SearchProjectSqlMethodExecutor.java
index fdff66cd937..c073b914176 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/SearchProjectSqlMethodExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/SearchProjectSqlMethodExecutor.java
@@ -16,7 +16,6 @@
 
 package ch.ethz.sis.openbis.generic.server.asapi.v3.executor.method;
 
-import java.util.ArrayList;
 import java.util.List;
 
 import org.springframework.beans.factory.annotation.Autowired;
@@ -26,7 +25,6 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.Project;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.fetchoptions.ProjectFetchOptions;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.search.ProjectSearchCriteria;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
-import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.ISearchObjectExecutor;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.project.ISearchProjectExecutor;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.ITranslator;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.entity.project.IProjectTranslator;
@@ -36,7 +34,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
  * @author pkupczyk
  */
 @Component
-public class SearchProjectSqlMethodExecutor extends AbstractSearchMethodExecutor<Project, Long, ProjectSearchCriteria, ProjectFetchOptions>
+public class SearchProjectSqlMethodExecutor extends AbstractIdSearchMethodExecutor<Project, ProjectPE, ProjectSearchCriteria, ProjectFetchOptions>
         implements ISearchProjectMethodExecutor
 {
 
@@ -47,24 +45,9 @@ public class SearchProjectSqlMethodExecutor extends AbstractSearchMethodExecutor
     private IProjectTranslator translator;
 
     @Override
-    protected ISearchObjectExecutor<ProjectSearchCriteria, Long> getSearchExecutor()
+    protected List<ProjectPE> searchPEs(IOperationContext context, ProjectSearchCriteria criteria)
     {
-        return new ISearchObjectExecutor<ProjectSearchCriteria, Long>()
-            {
-                @Override
-                public List<Long> search(IOperationContext context, ProjectSearchCriteria criteria)
-                {
-                    List<ProjectPE> projects = searchExecutor.search(context, criteria);
-                    List<Long> ids = new ArrayList<Long>();
-
-                    for (ProjectPE project : projects)
-                    {
-                        ids.add(project.getId());
-                    }
-
-                    return ids;
-                }
-            };
+        return searchExecutor.search(context, criteria);
     }
 
     @Override
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/SearchSpaceSqlMethodExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/SearchSpaceSqlMethodExecutor.java
index 2b7b6d1f665..a5605791b29 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/SearchSpaceSqlMethodExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/SearchSpaceSqlMethodExecutor.java
@@ -16,7 +16,6 @@
 
 package ch.ethz.sis.openbis.generic.server.asapi.v3.executor.method;
 
-import java.util.ArrayList;
 import java.util.List;
 
 import org.springframework.beans.factory.annotation.Autowired;
@@ -26,7 +25,6 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.Space;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.fetchoptions.SpaceFetchOptions;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.search.SpaceSearchCriteria;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
-import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.ISearchObjectExecutor;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.space.ISearchSpaceExecutor;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.ITranslator;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.entity.space.ISpaceTranslator;
@@ -36,7 +34,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
  * @author pkupczyk
  */
 @Component
-public class SearchSpaceSqlMethodExecutor extends AbstractSearchMethodExecutor<Space, Long, SpaceSearchCriteria, SpaceFetchOptions> implements
+public class SearchSpaceSqlMethodExecutor extends AbstractIdSearchMethodExecutor<Space, SpacePE, SpaceSearchCriteria, SpaceFetchOptions> implements
         ISearchSpaceMethodExecutor
 {
 
@@ -47,24 +45,9 @@ public class SearchSpaceSqlMethodExecutor extends AbstractSearchMethodExecutor<S
     private ISpaceTranslator translator;
 
     @Override
-    protected ISearchObjectExecutor<SpaceSearchCriteria, Long> getSearchExecutor()
+    protected List<SpacePE> searchPEs(IOperationContext context, SpaceSearchCriteria criteria)
     {
-        return new ISearchObjectExecutor<SpaceSearchCriteria, Long>()
-            {
-                @Override
-                public List<Long> search(IOperationContext context, SpaceSearchCriteria criteria)
-                {
-                    List<SpacePE> spaces = searchExecutor.search(context, criteria);
-                    List<Long> ids = new ArrayList<Long>();
-
-                    for (SpacePE space : spaces)
-                    {
-                        ids.add(space.getId());
-                    }
-
-                    return ids;
-                }
-            };
+        return searchExecutor.search(context, criteria);
     }
 
     @Override
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/SearchVocabularyTermMethodExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/SearchVocabularyTermMethodExecutor.java
index 901c1145807..986f3f7f0c0 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/SearchVocabularyTermMethodExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/method/SearchVocabularyTermMethodExecutor.java
@@ -16,7 +16,6 @@
 
 package ch.ethz.sis.openbis.generic.server.asapi.v3.executor.method;
 
-import java.util.ArrayList;
 import java.util.List;
 
 import org.springframework.beans.factory.annotation.Autowired;
@@ -26,7 +25,6 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.VocabularyTerm;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.fetchoptions.VocabularyTermFetchOptions;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.search.VocabularyTermSearchCriteria;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
-import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.ISearchObjectExecutor;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.vocabulary.ISearchVocabularyTermExecutor;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.ITranslator;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.entity.vocabulary.IVocabularyTermTranslator;
@@ -37,7 +35,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.VocabularyTermPE;
  */
 @Component
 public class SearchVocabularyTermMethodExecutor
-        extends AbstractSearchMethodExecutor<VocabularyTerm, Long, VocabularyTermSearchCriteria, VocabularyTermFetchOptions>
+        extends AbstractIdSearchMethodExecutor<VocabularyTerm, VocabularyTermPE, VocabularyTermSearchCriteria, VocabularyTermFetchOptions>
         implements ISearchVocabularyTermMethodExecutor
 {
 
@@ -48,24 +46,9 @@ public class SearchVocabularyTermMethodExecutor
     private IVocabularyTermTranslator translator;
 
     @Override
-    protected ISearchObjectExecutor<VocabularyTermSearchCriteria, Long> getSearchExecutor()
+    protected List<VocabularyTermPE> searchPEs(IOperationContext context, VocabularyTermSearchCriteria criteria)
     {
-        return new ISearchObjectExecutor<VocabularyTermSearchCriteria, Long>()
-            {
-                @Override
-                public List<Long> search(IOperationContext context, VocabularyTermSearchCriteria criteria)
-                {
-                    List<VocabularyTermPE> terms = searchExecutor.search(context, criteria);
-                    List<Long> ids = new ArrayList<Long>();
-
-                    for (VocabularyTermPE term : terms)
-                    {
-                        ids.add(term.getId());
-                    }
-
-                    return ids;
-                }
-            };
+        return searchExecutor.search(context, criteria);
     }
 
     @Override
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/project/SearchProjectExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/project/SearchProjectExecutor.java
index 90db1b64092..edfda9aac30 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/project/SearchProjectExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/project/SearchProjectExecutor.java
@@ -34,6 +34,10 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.search.ProjectSearchCrit
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.search.SpaceSearchCriteria;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.AbstractSearchObjectManuallyExecutor;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.CodeMatcher;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.Matcher;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.SimpleFieldMatcher;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.StringFieldMatcher;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.space.ISearchSpaceExecutor;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
@@ -55,14 +59,14 @@ public class SearchProjectExecutor extends AbstractSearchObjectManuallyExecutor<
     }
 
     @Override
-    protected Matcher getMatcher(ISearchCriteria criteria)
+    protected Matcher<ProjectPE> getMatcher(ISearchCriteria criteria)
     {
         if (criteria instanceof IdSearchCriteria<?>)
         {
             return new IdMatcher();
         } else if (criteria instanceof CodeSearchCriteria)
         {
-            return new CodeMatcher();
+            return new CodeMatcher<ProjectPE>();
         } else if (criteria instanceof PermIdSearchCriteria)
         {
             return new PermIdMatcher();
@@ -75,7 +79,7 @@ public class SearchProjectExecutor extends AbstractSearchObjectManuallyExecutor<
         }
     }
 
-    private class IdMatcher extends SimpleFieldMatcher
+    private class IdMatcher extends SimpleFieldMatcher<ProjectPE>
     {
 
         @Override
@@ -100,18 +104,7 @@ public class SearchProjectExecutor extends AbstractSearchObjectManuallyExecutor<
 
     }
 
-    private class CodeMatcher extends StringFieldMatcher
-    {
-
-        @Override
-        protected String getFieldValue(ProjectPE object)
-        {
-            return object.getCode();
-        }
-
-    }
-
-    private class PermIdMatcher extends StringFieldMatcher
+    private class PermIdMatcher extends StringFieldMatcher<ProjectPE>
     {
 
         @Override
@@ -122,7 +115,7 @@ public class SearchProjectExecutor extends AbstractSearchObjectManuallyExecutor<
 
     }
 
-    private class SpaceMatcher extends Matcher
+    private class SpaceMatcher extends Matcher<ProjectPE>
     {
 
         @Override
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/space/SearchSpaceExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/space/SearchSpaceExecutor.java
index d0cea4c104b..63f0a8c1658 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/space/SearchSpaceExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/space/SearchSpaceExecutor.java
@@ -28,6 +28,9 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.id.SpacePermId;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.search.SpaceSearchCriteria;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.AbstractSearchObjectManuallyExecutor;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.CodeMatcher;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.Matcher;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.SimpleFieldMatcher;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
 
 /**
@@ -44,21 +47,21 @@ public class SearchSpaceExecutor extends AbstractSearchObjectManuallyExecutor<Sp
     }
 
     @Override
-    protected Matcher getMatcher(ISearchCriteria criteria)
+    protected Matcher<SpacePE> getMatcher(ISearchCriteria criteria)
     {
         if (criteria instanceof IdSearchCriteria<?>)
         {
             return new IdMatcher();
         } else if (criteria instanceof PermIdSearchCriteria || criteria instanceof CodeSearchCriteria)
         {
-            return new CodeMatcher();
+            return new CodeMatcher<SpacePE>();
         } else
         {
             throw new IllegalArgumentException("Unknown search criteria: " + criteria.getClass());
         }
     }
 
-    private class IdMatcher extends SimpleFieldMatcher
+    private class IdMatcher extends SimpleFieldMatcher<SpacePE>
     {
 
         @Override
@@ -80,15 +83,4 @@ public class SearchSpaceExecutor extends AbstractSearchObjectManuallyExecutor<Sp
 
     }
 
-    private class CodeMatcher extends StringFieldMatcher
-    {
-
-        @Override
-        protected String getFieldValue(SpacePE object)
-        {
-            return object.getCode();
-        }
-
-    }
-
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/vocabulary/SearchVocabularyExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/vocabulary/SearchVocabularyExecutor.java
index 524ffc9e4d8..1e367d69ff0 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/vocabulary/SearchVocabularyExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/vocabulary/SearchVocabularyExecutor.java
@@ -28,6 +28,9 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.id.VocabularyPermId;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.search.VocabularySearchCriteria;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.AbstractSearchObjectManuallyExecutor;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.CodeMatcher;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.Matcher;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.SimpleFieldMatcher;
 import ch.systemsx.cisd.openbis.generic.shared.dto.VocabularyPE;
 
 /**
@@ -45,21 +48,21 @@ public class SearchVocabularyExecutor extends AbstractSearchObjectManuallyExecut
     }
 
     @Override
-    protected Matcher getMatcher(ISearchCriteria criteria)
+    protected Matcher<VocabularyPE> getMatcher(ISearchCriteria criteria)
     {
         if (criteria instanceof IdSearchCriteria<?>)
         {
             return new IdMatcher();
         } else if (criteria instanceof CodeSearchCriteria || criteria instanceof PermIdSearchCriteria)
         {
-            return new CodeMatcher();
+            return new CodeMatcher<VocabularyPE>();
         } else
         {
             throw new IllegalArgumentException("Unknown search criteria: " + criteria.getClass());
         }
     }
 
-    private class IdMatcher extends SimpleFieldMatcher
+    private class IdMatcher extends SimpleFieldMatcher<VocabularyPE>
     {
 
         @Override
@@ -81,16 +84,4 @@ public class SearchVocabularyExecutor extends AbstractSearchObjectManuallyExecut
         }
 
     }
-
-    private class CodeMatcher extends StringFieldMatcher
-    {
-
-        @Override
-        protected String getFieldValue(VocabularyPE object)
-        {
-            return object.getCode();
-        }
-
-    }
-
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/vocabulary/SearchVocabularyTermExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/vocabulary/SearchVocabularyTermExecutor.java
index f645daf111a..7e5c01dfaf0 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/vocabulary/SearchVocabularyTermExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/vocabulary/SearchVocabularyTermExecutor.java
@@ -33,6 +33,10 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.search.VocabularySear
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.search.VocabularyTermSearchCriteria;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.AbstractSearchObjectManuallyExecutor;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.CodeMatcher;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.Matcher;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.SimpleFieldMatcher;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.StringFieldMatcher;
 import ch.systemsx.cisd.openbis.generic.shared.dto.VocabularyPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.VocabularyTermPE;
 
@@ -54,7 +58,7 @@ public class SearchVocabularyTermExecutor extends AbstractSearchObjectManuallyEx
     }
 
     @Override
-    protected Matcher getMatcher(ISearchCriteria criteria)
+    protected Matcher<VocabularyTermPE> getMatcher(ISearchCriteria criteria)
     {
         if (criteria instanceof IdSearchCriteria<?>)
         {
@@ -64,7 +68,7 @@ public class SearchVocabularyTermExecutor extends AbstractSearchObjectManuallyEx
             return new PermIdMatcher();
         } else if (criteria instanceof CodeSearchCriteria)
         {
-            return new CodeMatcher();
+            return new CodeMatcher<VocabularyTermPE>();
         } else if (criteria instanceof VocabularySearchCriteria)
         {
             return new VocabularyMatcher();
@@ -74,7 +78,7 @@ public class SearchVocabularyTermExecutor extends AbstractSearchObjectManuallyEx
         }
     }
 
-    private class IdMatcher extends SimpleFieldMatcher
+    private class IdMatcher extends SimpleFieldMatcher<VocabularyTermPE>
     {
 
         @Override
@@ -97,7 +101,7 @@ public class SearchVocabularyTermExecutor extends AbstractSearchObjectManuallyEx
 
     }
 
-    private class PermIdMatcher extends StringFieldMatcher
+    private class PermIdMatcher extends StringFieldMatcher<VocabularyTermPE>
     {
 
         @Override
@@ -108,18 +112,7 @@ public class SearchVocabularyTermExecutor extends AbstractSearchObjectManuallyEx
 
     }
 
-    private class CodeMatcher extends StringFieldMatcher
-    {
-
-        @Override
-        protected String getFieldValue(VocabularyTermPE object)
-        {
-            return object.getCode();
-        }
-
-    }
-
-    private class VocabularyMatcher extends Matcher
+    private class VocabularyMatcher extends Matcher<VocabularyTermPE>
     {
 
         @Override
-- 
GitLab