From 23f55de3856e3bcee07dbc21a76f9eb7e83939a4 Mon Sep 17 00:00:00 2001 From: pkupczyk <pkupczyk> Date: Fri, 27 Mar 2015 16:03:18 +0000 Subject: [PATCH] SSDM-1677 : V3 AS API - finish up projects and materials - searchProjects SVN: 33759 --- .../server/api/v3/ApplicationServerApi.java | 67 ++++-- .../api/v3/ApplicationServerApiLogger.java | 8 + .../AbstractSearchObjectManuallyExecutor.java | 191 ++++++++++++++++++ .../project/ISearchProjectExecutor.java | 29 +++ .../project/SearchProjectExecutor.java | 149 ++++++++++++++ .../executor/space/SearchSpaceExecutor.java | 136 +++---------- .../systemtest/api/v3/SearchProjectTest.java | 163 +++++++++++++++ .../systemtest/api/v3/SearchSpaceTest.java | 8 +- .../shared/api/v3/IApplicationServerApi.java | 3 + .../v3/dto/search/ProjectSearchCriterion.java | 10 + 10 files changed, 634 insertions(+), 130 deletions(-) create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/common/AbstractSearchObjectManuallyExecutor.java create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/ISearchProjectExecutor.java create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/SearchProjectExecutor.java create mode 100644 openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/SearchProjectTest.java diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApi.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApi.java index bfc052c454a..c3dacc5ec38 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApi.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApi.java @@ -45,6 +45,7 @@ import ch.ethz.sis.openbis.generic.server.api.v3.executor.material.IMapMaterialB import ch.ethz.sis.openbis.generic.server.api.v3.executor.material.IUpdateMaterialExecutor; import ch.ethz.sis.openbis.generic.server.api.v3.executor.project.ICreateProjectExecutor; import ch.ethz.sis.openbis.generic.server.api.v3.executor.project.IMapProjectByIdExecutor; +import ch.ethz.sis.openbis.generic.server.api.v3.executor.project.ISearchProjectExecutor; import ch.ethz.sis.openbis.generic.server.api.v3.executor.project.IUpdateProjectExecutor; import ch.ethz.sis.openbis.generic.server.api.v3.executor.sample.ICreateSampleExecutor; import ch.ethz.sis.openbis.generic.server.api.v3.executor.sample.IDeleteSampleExecutor; @@ -114,6 +115,7 @@ import ch.ethz.sis.openbis.generic.shared.api.v3.dto.operation.IOperation; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.operation.IOperationResult; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.DataSetSearchCriterion; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ExperimentSearchCriterion; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ProjectSearchCriterion; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.SampleSearchCriterion; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.SpaceSearchCriterion; import ch.systemsx.cisd.openbis.common.spring.IInvocationLoggerContext; @@ -162,6 +164,9 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> @Autowired private ICreateSampleExecutor createSampleExecutor; + @Autowired + private ICreateMaterialExecutor createMaterialExecutor; + @Autowired private IUpdateSpaceExecutor updateSpaceExecutor; @@ -175,10 +180,10 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> private IUpdateSampleExecutor updateSampleExecutor; @Autowired - private IUpdateMaterialExecutor updateMaterialExecutor; + private IUpdateDataSetExecutor updateDataSetExecutor; @Autowired - private IUpdateDataSetExecutor updateDataSetExecutor; + private IUpdateMaterialExecutor updateMaterialExecutor; @Autowired private IMapSpaceByIdExecutor mapSpaceByIdExecutor; @@ -189,9 +194,6 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> @Autowired private IMapExperimentByIdExecutor mapExperimentByIdExecutor; - @Autowired - private IDeleteDataSetExecutor deleteDataSetExecutor; - @Autowired private IMapSampleByIdExecutor mapSampleByIdExecutor; @@ -201,14 +203,11 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> @Autowired private IMapMaterialByIdExecutor mapMaterialByIdExecutor; - @Autowired - private ICreateMaterialExecutor createMaterialExecutor; - @Autowired private ISearchSpaceExecutor searchSpaceExecutor; @Autowired - private IDeleteMaterialExecutor deleteMaterialExecutor; + private ISearchProjectExecutor searchProjectExecutor; @Autowired private ISearchExperimentExecutor searchExperimentExecutor; @@ -228,6 +227,12 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> @Autowired private IDeleteSampleExecutor deleteSampleExecutor; + @Autowired + private IDeleteDataSetExecutor deleteDataSetExecutor; + + @Autowired + private IDeleteMaterialExecutor deleteMaterialExecutor; + @Autowired private IListDeletionExecutor listDeletionExecutor; @@ -298,6 +303,10 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> } @Override + @Transactional + @RolesAllowed({ RoleWithHierarchy.INSTANCE_ADMIN, RoleWithHierarchy.SPACE_ETL_SERVER }) + @Capability("WRITE_MATERIAL") + @DatabaseCreateOrDeleteModification(value = ObjectKind.MATERIAL) public List<MaterialPermId> createMaterials(String sessionToken, List<MaterialCreation> newMaterials) { Session session = getSession(sessionToken); @@ -315,6 +324,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> @Transactional @RolesAllowed({ RoleWithHierarchy.SPACE_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER }) @Capability("REGISTER_PROJECT") + @DatabaseCreateOrDeleteModification(value = ObjectKind.PROJECT) public List<ProjectPermId> createProjects(String sessionToken, List<ProjectCreation> creations) { Session session = getSession(sessionToken); @@ -331,8 +341,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> @Override @Transactional - @RolesAllowed( - { RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER }) + @RolesAllowed({ RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER }) @Capability("WRITE_EXPERIMENT") @DatabaseCreateOrDeleteModification(value = ObjectKind.EXPERIMENT) public List<ExperimentPermId> createExperiments(String sessionToken, @@ -355,8 +364,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> @Override @Transactional - @RolesAllowed( - { RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER }) + @RolesAllowed({ RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER }) @Capability("WRITE_SAMPLE") @DatabaseCreateOrDeleteModification(value = ObjectKind.SAMPLE) public List<SamplePermId> createSamples(String sessionToken, @@ -401,6 +409,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> @Transactional @RolesAllowed({ RoleWithHierarchy.SPACE_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER }) @Capability("WRITE_PROJECT") + @DatabaseUpdateModification(value = ObjectKind.PROJECT) public void updateProjects(String sessionToken, List<ProjectUpdate> projectUpdates) { Session session = getSession(sessionToken); @@ -417,8 +426,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> @Override @Transactional - @RolesAllowed( - { RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER }) + @RolesAllowed({ RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER }) @Capability("WRITE_EXPERIMENT") @DatabaseUpdateModification(value = ObjectKind.EXPERIMENT) public void updateExperiments(String sessionToken, List<ExperimentUpdate> experimentUpdates) @@ -441,8 +449,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> @Override @Transactional - @RolesAllowed( - { RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER }) + @RolesAllowed({ RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER }) @Capability("WRITE_SAMPLE") @DatabaseUpdateModification(value = ObjectKind.SAMPLE) public void updateSamples(String sessionToken, List<SampleUpdate> updates) @@ -465,8 +472,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> @Override @Transactional - @RolesAllowed( - { RoleWithHierarchy.INSTANCE_ADMIN, RoleWithHierarchy.INSTANCE_ETL_SERVER }) + @RolesAllowed({ RoleWithHierarchy.INSTANCE_ADMIN, RoleWithHierarchy.INSTANCE_ETL_SERVER }) @Capability("UPDATE_MATERIAL") @DatabaseUpdateModification(value = ObjectKind.MATERIAL) public void updateMaterials(String sessionToken, List<MaterialUpdate> updates) @@ -580,6 +586,8 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> } @Override + @Transactional(readOnly = true) + @RolesAllowed({ RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER }) public Map<IMaterialId, Material> mapMaterials(String sessionToken, List<? extends IMaterialId> materialIds, MaterialFetchOptions fetchOptions) { Session session = getSession(sessionToken); @@ -613,6 +621,27 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> } } + @Override + @Transactional(readOnly = true) + @RolesAllowed({ RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER }) + public List<Project> searchProjects(String sessionToken, ProjectSearchCriterion searchCriterion, ProjectFetchOptions fetchOptions) + { + Session session = getSession(sessionToken); + OperationContext context = new OperationContext(session); + + try + { + List<ProjectPE> projects = searchProjectExecutor.search(context, searchCriterion); + + Map<ProjectPE, Project> translatedMap = + new ProjectTranslator(new TranslationContext(session, managedPropertyEvaluatorFactory), fetchOptions).translate(projects); + return new ArrayList<Project>(translatedMap.values()); + } catch (Throwable t) + { + throw ExceptionUtils.create(context, t); + } + } + @Override @Transactional(readOnly = true) @RolesAllowed({ RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER }) diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApiLogger.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApiLogger.java index 0c63b8d938b..cbb7e4e4783 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApiLogger.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApiLogger.java @@ -66,6 +66,7 @@ import ch.ethz.sis.openbis.generic.shared.api.v3.dto.operation.IOperation; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.operation.IOperationResult; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.DataSetSearchCriterion; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ExperimentSearchCriterion; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ProjectSearchCriterion; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.SampleSearchCriterion; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.SpaceSearchCriterion; import ch.systemsx.cisd.authentication.ISessionManager; @@ -238,6 +239,13 @@ public class ApplicationServerApiLogger extends AbstractServerLogger implements return null; } + @Override + public List<Project> searchProjects(String sessionToken, ProjectSearchCriterion searchCriterion, ProjectFetchOptions fetchOptions) + { + logAccess(sessionToken, "search-for-projects", "SEARCH_CRITERION:\n%s\nFETCH_OPTIONS:\n%s\n", searchCriterion, fetchOptions); + return null; + } + @Override public List<Experiment> searchExperiments(String sessionToken, ExperimentSearchCriterion searchCriterion, ExperimentFetchOptions fetchOptions) { diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/common/AbstractSearchObjectManuallyExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/common/AbstractSearchObjectManuallyExecutor.java new file mode 100644 index 00000000000..0805c380266 --- /dev/null +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/common/AbstractSearchObjectManuallyExecutor.java @@ -0,0 +1,191 @@ +/* + * 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.server.api.v3.executor.common; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; + +import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.AbstractObjectSearchCriterion; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.AbstractStringValue; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.AnyStringValue; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ISearchCriterion; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.SearchOperator; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.StringContainsValue; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.StringEndsWithValue; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.StringEqualToValue; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.StringFieldSearchCriterion; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.StringStartsWithValue; +import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory; + +/** + * @author pkupczyk + */ +public abstract class AbstractSearchObjectManuallyExecutor<CRITERION extends AbstractObjectSearchCriterion<?>, OBJECT> implements + ISearchObjectExecutor<CRITERION, OBJECT> +{ + + @Autowired + protected IDAOFactory daoFactory; + + protected abstract List<OBJECT> listAll(); + + protected abstract Matcher getMatcher(ISearchCriterion criterion); + + @Override + public List<OBJECT> search(IOperationContext context, CRITERION criterion) + { + if (context == null) + { + throw new IllegalArgumentException("Context cannot be null"); + } + if (criterion == null) + { + throw new IllegalArgumentException("Criterion cannot be null"); + } + + return getMatching(context, listAll(), criterion); + } + + private List<OBJECT> getMatching(IOperationContext context, List<OBJECT> objects, CRITERION criterion) + { + if (criterion.getCriteria() == null || criterion.getCriteria().isEmpty()) + { + return objects; + } else + { + List<List<OBJECT>> partialMatches = new LinkedList<List<OBJECT>>(); + + for (ISearchCriterion subCriterion : criterion.getCriteria()) + { + Matcher matcher = getMatcher(subCriterion); + + List<OBJECT> partialMatch = matcher.getMatching(context, objects, subCriterion); + if (partialMatch == null) + { + partialMatch = Collections.emptyList(); + } + partialMatches.add(partialMatch); + } + + if (SearchOperator.AND.equals(criterion.getOperator())) + { + Set<OBJECT> matches = new HashSet<OBJECT>(partialMatches.get(0)); + for (List<OBJECT> partialMatch : partialMatches) + { + matches.retainAll(partialMatch); + } + return new ArrayList<OBJECT>(matches); + } else if (SearchOperator.OR.equals(criterion.getOperator())) + { + Set<OBJECT> matches = new HashSet<OBJECT>(); + for (List<OBJECT> partialMatch : partialMatches) + { + matches.addAll(partialMatch); + } + return new ArrayList<OBJECT>(matches); + } else + { + throw new IllegalArgumentException("Unknown search operator: " + criterion.getOperator()); + } + } + } + + protected abstract class Matcher + { + + public abstract List<OBJECT> getMatching(IOperationContext context, List<OBJECT> objects, ISearchCriterion criterion); + + } + + protected abstract class SimpleFieldMatcher extends Matcher + { + + @Override + public List<OBJECT> getMatching(IOperationContext context, List<OBJECT> objects, ISearchCriterion criterion) + { + List<OBJECT> matches = new ArrayList<OBJECT>(); + + for (OBJECT object : objects) + { + if (isMatching(context, object, criterion)) + { + matches.add(object); + } + } + + return matches; + } + + protected abstract boolean isMatching(IOperationContext context, OBJECT object, ISearchCriterion criterion); + + } + + protected abstract class StringFieldMatcher extends SimpleFieldMatcher + { + + @Override + protected boolean isMatching(IOperationContext context, OBJECT object, ISearchCriterion criterion) + { + AbstractStringValue fieldValue = ((StringFieldSearchCriterion) criterion).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: " + criterion.getClass()); + } + } + + protected abstract String getFieldValue(OBJECT object); + + } + +} diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/ISearchProjectExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/ISearchProjectExecutor.java new file mode 100644 index 00000000000..84aa8393db7 --- /dev/null +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/ISearchProjectExecutor.java @@ -0,0 +1,29 @@ +/* + * Copyright 2014 ETH Zuerich, Scientific IT Services + * + * 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.api.v3.executor.project; + +import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.ISearchObjectExecutor; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ProjectSearchCriterion; +import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE; + +/** + * @author pkupczyk + */ +public interface ISearchProjectExecutor extends ISearchObjectExecutor<ProjectSearchCriterion, ProjectPE> +{ + +} diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/SearchProjectExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/SearchProjectExecutor.java new file mode 100644 index 00000000000..0d48b706d34 --- /dev/null +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/SearchProjectExecutor.java @@ -0,0 +1,149 @@ +/* + * 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.server.api.v3.executor.project; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext; +import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.AbstractSearchObjectManuallyExecutor; +import ch.ethz.sis.openbis.generic.server.api.v3.executor.space.ISearchSpaceExecutor; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.project.ProjectIdentifier; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.project.ProjectPermId; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.CodeSearchCriterion; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ISearchCriterion; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.IdSearchCriterion; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.PermIdSearchCriterion; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ProjectSearchCriterion; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.SpaceSearchCriterion; +import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE; +import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE; + +/** + * @author pkupczyk + */ +@Component +public class SearchProjectExecutor extends AbstractSearchObjectManuallyExecutor<ProjectSearchCriterion, ProjectPE> implements ISearchProjectExecutor +{ + + @Autowired + private ISearchSpaceExecutor searchSpaceExecutor; + + @Override + protected List<ProjectPE> listAll() + { + return daoFactory.getProjectDAO().listAllEntities(); + } + + @Override + protected Matcher getMatcher(ISearchCriterion criterion) + { + if (criterion instanceof IdSearchCriterion<?>) + { + return new IdMatcher(); + } else if (criterion instanceof CodeSearchCriterion) + { + return new CodeMatcher(); + } else if (criterion instanceof PermIdSearchCriterion) + { + return new PermIdMatcher(); + } else if (criterion instanceof SpaceSearchCriterion) + { + return new SpaceMatcher(); + } else + { + throw new IllegalArgumentException("Unknown search criterion: " + criterion.getClass()); + } + } + + private class IdMatcher extends SimpleFieldMatcher + { + + @Override + protected boolean isMatching(IOperationContext context, ProjectPE object, ISearchCriterion criterion) + { + Object id = ((IdSearchCriterion<?>) criterion).getId(); + + if (id == null) + { + return true; + } else if (id instanceof ProjectPermId) + { + return object.getPermId().equals(((ProjectPermId) id).getPermId()); + } else if (id instanceof ProjectIdentifier) + { + return object.getIdentifier().equals(((ProjectIdentifier) id).getIdentifier()); + } else + { + throw new IllegalArgumentException("Unknown id: " + criterion.getClass()); + } + } + + } + + private class CodeMatcher extends StringFieldMatcher + { + + @Override + protected String getFieldValue(ProjectPE object) + { + return object.getCode(); + } + + } + + private class PermIdMatcher extends StringFieldMatcher + { + + @Override + protected String getFieldValue(ProjectPE object) + { + return object.getPermId(); + } + + } + + private class SpaceMatcher extends Matcher + { + + @Override + public List<ProjectPE> getMatching(IOperationContext context, List<ProjectPE> objects, ISearchCriterion criterion) + { + List<SpacePE> spaceList = searchSpaceExecutor.search(context, (SpaceSearchCriterion) criterion); + Set<SpacePE> spaceSet = new HashSet<SpacePE>(spaceList); + + List<ProjectPE> matches = new ArrayList<ProjectPE>(); + + for (ProjectPE object : objects) + { + if (spaceSet.contains(object.getSpace())) + { + matches.add(object); + } + } + + return matches; + } + + } + +} diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/space/SearchSpaceExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/space/SearchSpaceExecutor.java index ca7e9de1c59..d308e4eaa69 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/space/SearchSpaceExecutor.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/space/SearchSpaceExecutor.java @@ -16,157 +16,79 @@ package ch.ethz.sis.openbis.generic.server.api.v3.executor.space; -import java.util.ArrayList; import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext; +import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.AbstractSearchObjectManuallyExecutor; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.space.SpacePermId; -import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.AbstractStringValue; -import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.AnyStringValue; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.CodeSearchCriterion; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ISearchCriterion; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.IdSearchCriterion; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.PermIdSearchCriterion; -import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.SearchOperator; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.SpaceSearchCriterion; -import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.StringContainsValue; -import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.StringEndsWithValue; -import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.StringEqualToValue; -import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.StringFieldSearchCriterion; -import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.StringStartsWithValue; -import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory; import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE; /** * @author pkupczyk */ @Component -public class SearchSpaceExecutor implements ISearchSpaceExecutor +public class SearchSpaceExecutor extends AbstractSearchObjectManuallyExecutor<SpaceSearchCriterion, SpacePE> implements ISearchSpaceExecutor { - @Autowired - protected IDAOFactory daoFactory; + @Override + protected List<SpacePE> listAll() + { + return daoFactory.getSpaceDAO().listAllEntities(); + } @Override - public List<SpacePE> search(IOperationContext context, SpaceSearchCriterion criterion) + protected Matcher getMatcher(ISearchCriterion criterion) { - if (context == null) + if (criterion instanceof IdSearchCriterion<?>) { - throw new IllegalArgumentException("Context cannot be null"); - } - if (criterion == null) + return new IdMatcher(); + } else if (criterion instanceof PermIdSearchCriterion || criterion instanceof CodeSearchCriterion) { - throw new IllegalArgumentException("Criterion cannot be null"); - } - - List<SpacePE> allSpaces = daoFactory.getSpaceDAO().listAllEntities(); - List<SpacePE> matchingSpaces = new ArrayList<SpacePE>(); - - for (SpacePE space : allSpaces) + return new CodeMatcher(); + } else { - if (isMatching(space, criterion)) - { - matchingSpaces.add(space); - } + throw new IllegalArgumentException("Unknown search criterion: " + criterion.getClass()); } - - return matchingSpaces; } - private boolean isMatching(SpacePE space, SpaceSearchCriterion criterion) + private class IdMatcher extends SimpleFieldMatcher { - if (criterion.getCriteria() == null || criterion.getCriteria().isEmpty()) - { - return true; - } else - { - boolean matchingAll = true; - boolean matchingAny = false; - for (ISearchCriterion subCriterion : criterion.getCriteria()) - { - boolean matching = isMatching(space, subCriterion); - - matchingAll = matchingAll && matching; - matchingAny = matchingAny || matching; - } + @Override + protected boolean isMatching(IOperationContext context, SpacePE object, ISearchCriterion criterion) + { + Object id = ((IdSearchCriterion<?>) criterion).getId(); - if (SearchOperator.AND.equals(criterion.getOperator())) + if (id == null) { - return matchingAll; - } else if (SearchOperator.OR.equals(criterion.getOperator())) + return true; + } else if (id instanceof SpacePermId) { - return matchingAny; + return object.getCode().equals(((SpacePermId) id).getPermId()); } else { - throw new IllegalArgumentException("Unknown search operator: " + criterion.getOperator()); + throw new IllegalArgumentException("Unknown id: " + id.getClass()); } } - } - - private boolean isMatching(SpacePE space, ISearchCriterion criterion) - { - if (criterion == null) - { - return true; - } else if (criterion instanceof IdSearchCriterion<?>) - { - return isMatchingId(space, (IdSearchCriterion<?>) criterion); - } else if (criterion instanceof PermIdSearchCriterion || criterion instanceof CodeSearchCriterion) - { - return isMatchingCode(space, (StringFieldSearchCriterion) criterion); - } else - { - throw new IllegalArgumentException("Unknown search criterion: " + criterion.getClass()); - } - } - private boolean isMatchingId(SpacePE space, IdSearchCriterion<?> criterion) - { - Object id = criterion.getId(); - - if (id == null) - { - return true; - } else if (id instanceof SpacePermId) - { - return space.getCode().equals(((SpacePermId) id).getPermId()); - } else - { - throw new IllegalArgumentException("Unknown search criterion: " + criterion.getClass()); - } } - private boolean isMatchingCode(SpacePE space, StringFieldSearchCriterion criterion) + private class CodeMatcher extends StringFieldMatcher { - AbstractStringValue fieldValue = criterion.getFieldValue(); - if (fieldValue == null || fieldValue.getValue() == null || fieldValue instanceof AnyStringValue) + @Override + protected String getFieldValue(SpacePE object) { - return true; + return object.getCode(); } - String code = space.getCode().toLowerCase(); - String value = fieldValue.getValue().toLowerCase(); - - if (fieldValue instanceof StringEqualToValue) - { - return code.equals(value); - } else if (fieldValue instanceof StringContainsValue) - { - return code.contains(value); - } else if (fieldValue instanceof StringStartsWithValue) - { - return code.startsWith(value); - } else if (fieldValue instanceof StringEndsWithValue) - { - return code.endsWith(value); - } else - { - throw new IllegalArgumentException("Unknown search criterion: " + criterion.getClass()); - } } + } diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/SearchProjectTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/SearchProjectTest.java new file mode 100644 index 00000000000..b6d2cf528ba --- /dev/null +++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/SearchProjectTest.java @@ -0,0 +1,163 @@ +/* + * Copyright 2014 ETH Zuerich, Scientific IT Services + * + * 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.systemtest.api.v3; + +import java.util.List; + +import org.testng.annotations.Test; + +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.project.Project; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.fetchoptions.project.ProjectFetchOptions; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.project.ProjectIdentifier; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.project.ProjectPermId; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.space.SpacePermId; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ProjectSearchCriterion; + +/** + * @author pkupczyk + */ +public class SearchProjectTest extends AbstractTest +{ + + @Test + public void testSearchWithIdSetToPermId() + { + ProjectSearchCriterion criterion = new ProjectSearchCriterion(); + criterion.withId().thatEquals(new ProjectPermId("20120814110011738-105")); + testSearch(TEST_USER, criterion, "/TEST-SPACE/TEST-PROJECT"); + } + + @Test + public void testSearchWithIdSetToIdentifier() + { + ProjectSearchCriterion criterion = new ProjectSearchCriterion(); + criterion.withId().thatEquals(new ProjectIdentifier("/TEST-SPACE/TEST-PROJECT")); + testSearch(TEST_USER, criterion, "/TEST-SPACE/TEST-PROJECT"); + } + + @Test + public void testSearchWithIdSetToNonexistentPermId() + { + ProjectSearchCriterion criterion = new ProjectSearchCriterion(); + criterion.withId().thatEquals(new ProjectPermId("IDONTEXIST")); + testSearch(TEST_USER, criterion); + } + + @Test + public void testSearchWithIdSetToNonexistentIdentifier() + { + ProjectSearchCriterion criterion = new ProjectSearchCriterion(); + criterion.withId().thatEquals(new ProjectIdentifier("/IDONT/EXIST")); + testSearch(TEST_USER, criterion); + } + + @Test + public void testSearchWithPermIdThatEquals() + { + ProjectSearchCriterion criterion = new ProjectSearchCriterion(); + criterion.withPermId().thatEquals("20120814110011738-105"); + testSearch(TEST_USER, criterion, "/TEST-SPACE/TEST-PROJECT"); + } + + @Test + public void testSearchWithCodeThatEquals() + { + ProjectSearchCriterion criterion = new ProjectSearchCriterion(); + criterion.withCode().thatEquals("test-PROJECT"); + testSearch(TEST_USER, criterion, "/TEST-SPACE/TEST-PROJECT"); + } + + @Test + public void testSearchWithCodeThatContains() + { + ProjectSearchCriterion criterion = new ProjectSearchCriterion(); + criterion.withCode().thatContains("pRoJ"); + testSearch(TEST_USER, criterion, "/TESTGROUP/TESTPROJ", "/TEST-SPACE/TEST-PROJECT", "/TEST-SPACE/PROJECT-TO-DELETE"); + } + + @Test + public void testSearchWithCodeThatStartsWith() + { + ProjectSearchCriterion criterion = new ProjectSearchCriterion(); + criterion.withCode().thatStartsWith("n"); + testSearch(TEST_USER, criterion, "/CISD/NEMO", "/CISD/NOE", "/TEST-SPACE/NOE"); + } + + @Test + public void testSearchWithCodeThatEndsWith() + { + ProjectSearchCriterion criterion = new ProjectSearchCriterion(); + criterion.withCode().thatEndsWith("t"); + testSearch(TEST_USER, criterion, "/CISD/DEFAULT", "/TEST-SPACE/TEST-PROJECT"); + } + + @Test + public void testSearchWithSpaceWithIdThatEquals() + { + ProjectSearchCriterion criterion = new ProjectSearchCriterion(); + criterion.withSpace().withId().thatEquals(new SpacePermId("CISD")); + testSearch(TEST_USER, criterion, "/CISD/DEFAULT", "/CISD/NEMO", "/CISD/NOE"); + } + + @Test + public void testSearchWithSpaceWithCodeThatStartsWith() + { + ProjectSearchCriterion criterion = new ProjectSearchCriterion(); + criterion.withSpace().withCode().thatStartsWith("TEST"); + testSearch(TEST_USER, criterion, "/TESTGROUP/TESTPROJ", "/TEST-SPACE/TEST-PROJECT", "/TEST-SPACE/NOE", "/TEST-SPACE/PROJECT-TO-DELETE"); + } + + @Test + public void testSearchWithAndOperator() + { + ProjectSearchCriterion criterion = new ProjectSearchCriterion(); + criterion.withAndOperator(); + criterion.withCode().thatContains("TEST"); + criterion.withCode().thatContains("PROJECT"); + testSearch(TEST_USER, criterion, "/TEST-SPACE/TEST-PROJECT"); + } + + @Test + public void testSearchWithOrOperator() + { + ProjectSearchCriterion criterion = new ProjectSearchCriterion(); + criterion.withOrOperator(); + criterion.withPermId().thatEquals("20120814110011738-101"); + criterion.withPermId().thatEquals("20120814110011738-105"); + testSearch(TEST_USER, criterion, "/CISD/DEFAULT", "/TEST-SPACE/TEST-PROJECT"); + } + + @Test + public void testSearchWithProjectUnauthorized() + { + ProjectSearchCriterion criterion = new ProjectSearchCriterion(); + criterion.withId().thatEquals(new ProjectIdentifier("/CISD/DEFAULT")); + testSearch(TEST_USER, criterion, "/CISD/DEFAULT"); + testSearch(TEST_SPACE_USER, criterion); + } + + private void testSearch(String user, ProjectSearchCriterion criterion, String... expectedIdentifiers) + { + String sessionToken = v3api.login(user, PASSWORD); + + List<Project> projects = v3api.searchProjects(sessionToken, criterion, new ProjectFetchOptions()); + + assertProjectIdentifiers(projects, expectedIdentifiers); + v3api.logout(sessionToken); + } + +} diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/SearchSpaceTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/SearchSpaceTest.java index 362c981e622..d15cdb8d8d0 100644 --- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/SearchSpaceTest.java +++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/SearchSpaceTest.java @@ -83,7 +83,7 @@ public class SearchSpaceTest extends AbstractTest public void testSearchWithCodeThatEquals() { SpaceSearchCriterion criterion = new SpaceSearchCriterion(); - criterion.withPermId().thatEquals("test-SPACE"); + criterion.withCode().thatEquals("test-SPACE"); testSearch(TEST_USER, criterion, "TEST-SPACE"); } @@ -91,7 +91,7 @@ public class SearchSpaceTest extends AbstractTest public void testSearchWithCodeThatContains() { SpaceSearchCriterion criterion = new SpaceSearchCriterion(); - criterion.withPermId().thatContains("ST-sPa"); + criterion.withCode().thatContains("ST-sPa"); testSearch(TEST_USER, criterion, "TEST-SPACE"); } @@ -99,7 +99,7 @@ public class SearchSpaceTest extends AbstractTest public void testSearchWithCodeThatStartsWith() { SpaceSearchCriterion criterion = new SpaceSearchCriterion(); - criterion.withPermId().thatStartsWith("c"); + criterion.withCode().thatStartsWith("c"); testSearch(TEST_USER, criterion, "CISD"); } @@ -107,7 +107,7 @@ public class SearchSpaceTest extends AbstractTest public void testSearchWithCodeThatEndsWith() { SpaceSearchCriterion criterion = new SpaceSearchCriterion(); - criterion.withPermId().thatEndsWith("e"); + criterion.withCode().thatEndsWith("e"); testSearch(TEST_USER, criterion, "TEST-SPACE"); } diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/IApplicationServerApi.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/IApplicationServerApi.java index ad7e9c0775a..05716d0c42b 100644 --- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/IApplicationServerApi.java +++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/IApplicationServerApi.java @@ -65,6 +65,7 @@ import ch.ethz.sis.openbis.generic.shared.api.v3.dto.operation.IOperation; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.operation.IOperationResult; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.DataSetSearchCriterion; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ExperimentSearchCriterion; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ProjectSearchCriterion; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.SampleSearchCriterion; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.SpaceSearchCriterion; import ch.systemsx.cisd.common.api.IRpcService; @@ -165,6 +166,8 @@ public interface IApplicationServerApi extends IRpcService public List<Space> searchSpaces(String sessionToken, SpaceSearchCriterion searchCriterion, SpaceFetchOptions fetchOptions); + public List<Project> searchProjects(String sessionToken, ProjectSearchCriterion searchCriterion, ProjectFetchOptions fetchOptions); + // REPLACES: // - ServiceForDataStoreServer.listExperimentsForProjects(List<ProjectIdentifier>, ExperimentFetchOptions) // - ServiceForDataStoreServer.listExperiments(ProjectIdentifier) diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/ProjectSearchCriterion.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/ProjectSearchCriterion.java index 1d659494c93..758bd9aaf82 100644 --- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/ProjectSearchCriterion.java +++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/ProjectSearchCriterion.java @@ -47,6 +47,16 @@ public class ProjectSearchCriterion extends AbstractObjectSearchCriterion<IProje return with(new SpaceSearchCriterion()); } + public ProjectSearchCriterion withOrOperator() + { + return (ProjectSearchCriterion) withOperator(SearchOperator.OR); + } + + public ProjectSearchCriterion withAndOperator() + { + return (ProjectSearchCriterion) withOperator(SearchOperator.AND); + } + @Override protected SearchCriterionToStringBuilder createBuilder() { -- GitLab