From 91fb69bbece6570eec36a150b8a729fafa07f82a Mon Sep 17 00:00:00 2001 From: felmer <felmer> Date: Tue, 15 Sep 2015 11:44:09 +0000 Subject: [PATCH] SSDM-2318: MapSampletechIdByIdExecutor replacing MapSampleByIdExecutor in MapSampleSqlMethodExecutor. SVN: 34647 --- .../common/TechIdStringIdentifierRecord.java | 28 ++++ .../method/MapSampleSqlMethodExecutor.java | 28 +--- .../sample/IMapSampleTechIdByIdExecutor.java | 30 ++++ .../sample/ListSampleTechIdByIdentifier.java | 158 ++++++++++++++++++ .../sample/ListSampleTechIdByPermId.java | 70 ++++++++ .../sample/MapSampleTechIdByIdExecutor.java | 48 ++++++ .../api/v3/executor/sample/SampleQuery.java | 61 +++++++ .../systemtest/api/v3/MapSampleTest.java | 24 ++- 8 files changed, 413 insertions(+), 34 deletions(-) create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/common/TechIdStringIdentifierRecord.java create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/IMapSampleTechIdByIdExecutor.java create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByIdentifier.java create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByPermId.java create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/MapSampleTechIdByIdExecutor.java create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/SampleQuery.java diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/common/TechIdStringIdentifierRecord.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/common/TechIdStringIdentifierRecord.java new file mode 100644 index 00000000000..f23e48b0a22 --- /dev/null +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/common/TechIdStringIdentifierRecord.java @@ -0,0 +1,28 @@ +/* + * Copyright 2015 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.api.v3.executor.common; + +/** + * + * + * @author Franz-Josef Elmer + */ +public class TechIdStringIdentifierRecord +{ + public Long id; + public String identifier; +} diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/method/MapSampleSqlMethodExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/method/MapSampleSqlMethodExecutor.java index 8f701009469..d769bb9c49e 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/method/MapSampleSqlMethodExecutor.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/method/MapSampleSqlMethodExecutor.java @@ -16,22 +16,16 @@ package ch.ethz.sis.openbis.generic.server.api.v3.executor.method; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.Map; - 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.IMapObjectByIdExecutor; -import ch.ethz.sis.openbis.generic.server.api.v3.executor.sample.IMapSampleByIdExecutor; +import ch.ethz.sis.openbis.generic.server.api.v3.executor.sample.IMapSampleTechIdByIdExecutor; import ch.ethz.sis.openbis.generic.server.api.v3.translator.ITranslator; import ch.ethz.sis.openbis.generic.server.api.v3.translator.entity.sample.sql.ISampleSqlTranslator; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.sample.Sample; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.fetchoptions.sample.SampleFetchOptions; import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.ISampleId; -import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE; /** * @author pkupczyk @@ -42,7 +36,7 @@ public class MapSampleSqlMethodExecutor extends AbstractMapMethodExecutor<ISampl { @Autowired - private IMapSampleByIdExecutor mapExecutor; + private IMapSampleTechIdByIdExecutor mapExecutor; @Autowired private ISampleSqlTranslator translator; @@ -50,23 +44,7 @@ public class MapSampleSqlMethodExecutor extends AbstractMapMethodExecutor<ISampl @Override protected IMapObjectByIdExecutor<ISampleId, Long> getMapExecutor() { - // TODO replace with ISampleId -> Long mapExecutor once there is one - return new IMapObjectByIdExecutor<ISampleId, Long>() - { - @Override - public Map<ISampleId, Long> map(IOperationContext context, Collection<? extends ISampleId> ids) - { - Map<ISampleId, SamplePE> peMap = mapExecutor.map(context, ids); - Map<ISampleId, Long> idMap = new LinkedHashMap<ISampleId, Long>(); - - for (Map.Entry<ISampleId, SamplePE> peEntry : peMap.entrySet()) - { - idMap.put(peEntry.getKey(), peEntry.getValue().getId()); - } - - return idMap; - } - }; + return mapExecutor; } @Override diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/IMapSampleTechIdByIdExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/IMapSampleTechIdByIdExecutor.java new file mode 100644 index 00000000000..21f5be72d9d --- /dev/null +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/IMapSampleTechIdByIdExecutor.java @@ -0,0 +1,30 @@ +/* + * Copyright 2015 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.api.v3.executor.sample; + +import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.IMapObjectByIdExecutor; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.ISampleId; + +/** + * + * + * @author Franz-Josef Elmer + */ +public interface IMapSampleTechIdByIdExecutor extends IMapObjectByIdExecutor<ISampleId, Long> +{ + +} diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByIdentifier.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByIdentifier.java new file mode 100644 index 00000000000..dc4c7ef7ac3 --- /dev/null +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByIdentifier.java @@ -0,0 +1,158 @@ +/* + * Copyright 2015 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.api.v3.executor.sample; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import net.lemnik.eodsql.QueryTool; + +import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.TechIdStringIdentifierRecord; +import ch.ethz.sis.openbis.generic.server.api.v3.helper.common.IListObjectById; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.SampleIdentifier; +import ch.systemsx.cisd.openbis.generic.shared.basic.CodeConverter; +import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory; + +/** + * + * + * @author Franz-Josef Elmer + */ +public class ListSampleTechIdByIdentifier implements IListObjectById<SampleIdentifier, Long> +{ + private Map<Long, SampleIdentifier> identifiersByTechIds = new HashMap<Long, SampleIdentifier>(); + + @Override + public Class<SampleIdentifier> getIdClass() + { + return SampleIdentifier.class; + } + + @Override + public SampleIdentifier createId(Long techId) + { + return identifiersByTechIds.get(techId); + } + + @Override + public List<Long> listByIds(List<SampleIdentifier> ids) + { + Map<Key, Map<String, SampleIdentifier>> groupedIdentifiers = new HashMap<>(); + for (SampleIdentifier sampleIdentifier : ids) + { + ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier sampleIdentifier2 + = SampleIdentifierFactory.parse(sampleIdentifier.getIdentifier()); + String spaceCode = null; + if (sampleIdentifier2.isSpaceLevel()) + { + spaceCode = CodeConverter.tryToDatabase(sampleIdentifier2.getSpaceLevel().getSpaceCode()); + } + String sampleSubCode = CodeConverter.tryToDatabase(sampleIdentifier2.getSampleSubCode()); + String containerCode = CodeConverter.tryToDatabase(sampleIdentifier2.tryGetContainerCode()); + Key key = new Key(spaceCode, containerCode); + Map<String, SampleIdentifier> identifiersByCode = groupedIdentifiers.get(key); + if (identifiersByCode == null) + { + identifiersByCode = new HashMap<>(); + groupedIdentifiers.put(key, identifiersByCode); + } + identifiersByCode.put(sampleSubCode, sampleIdentifier); + } + SampleQuery query = QueryTool.getManagedQuery(SampleQuery.class); + for (Entry<Key, Map<String, SampleIdentifier>> entry : groupedIdentifiers.entrySet()) + { + Key key = entry.getKey(); + Map<String, SampleIdentifier> identifiersByCode = entry.getValue(); + List<TechIdStringIdentifierRecord> records = list(query, key, identifiersByCode.keySet()); + for (TechIdStringIdentifierRecord record : records) + { + String sampleCode = record.identifier; + identifiersByTechIds.put(record.id, identifiersByCode.get(sampleCode)); + } + } + return new ArrayList<>(identifiersByTechIds.keySet()); + } + + private List<TechIdStringIdentifierRecord> list(SampleQuery query, Key key, Collection<String> codes) + { + String[] codesArray = codes.toArray(new String[codes.size()]); + String spaceCode = key.spaceCodeOrNull; + String containerCode = key.containerCodeOrNull; + if (spaceCode == null) + { + if (containerCode == null) + { + return query.listSharedSampleTechIdsByCodes(codesArray); + } + return query.listSharedSampleTechIdsByContainerCodeAndCodes(containerCode, codesArray); + } + if (containerCode == null) + { + return query.listSpaceSampleTechIdsByCodes(spaceCode, codesArray); + } + return query.listSpaceSampleTechIdsByContainerCodeAndCodes(spaceCode, containerCode, codesArray); + } + + private static final class Key + { + private String spaceCodeOrNull; + private String containerCodeOrNull; + + Key(String spaceCodeOrNull, String containerCodeOrNull) + { + this.spaceCodeOrNull = spaceCodeOrNull; + this.containerCodeOrNull = containerCodeOrNull; + } + + @Override + public boolean equals(Object obj) + { + if (obj == this) + { + return true; + } + if (obj instanceof Key == false) + { + return false; + } + Key key = (Key) obj; + return isEqual(spaceCodeOrNull, key.spaceCodeOrNull) + && isEqual(containerCodeOrNull, key.containerCodeOrNull); + } + + private boolean isEqual(String str1, String str2) + { + return str1 == null ? str1 == str2 : str1.equals(str2); + } + + @Override + public int hashCode() + { + return 37 * calcHashCode(spaceCodeOrNull) + calcHashCode(containerCodeOrNull); + } + + private int calcHashCode(String str) + { + return str == null ? 0 : str.hashCode(); + } + } + +} diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByPermId.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByPermId.java new file mode 100644 index 00000000000..6905e21ba1e --- /dev/null +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByPermId.java @@ -0,0 +1,70 @@ +/* + * Copyright 2015 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.api.v3.executor.sample; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.lemnik.eodsql.QueryTool; + +import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.TechIdStringIdentifierRecord; +import ch.ethz.sis.openbis.generic.server.api.v3.helper.common.IListObjectById; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.SamplePermId; + +/** + * + * + * @author Franz-Josef Elmer + */ +public class ListSampleTechIdByPermId implements IListObjectById<SamplePermId, Long> +{ + private Map<Long, SamplePermId> permIdsByTechIds = new HashMap<Long, SamplePermId>(); + + @Override + public Class<SamplePermId> getIdClass() + { + return SamplePermId.class; + } + + @Override + public SamplePermId createId(Long techId) + { + return permIdsByTechIds.get(techId); + } + + @Override + public List<Long> listByIds(List<SamplePermId> ids) + { + SampleQuery query = QueryTool.getManagedQuery(SampleQuery.class); + + List<String> permIds = new ArrayList<>(ids.size()); + for (SamplePermId permId : ids) + { + permIds.add(permId.getPermId()); + } + List<Long> techIds = new ArrayList<>(); + for (TechIdStringIdentifierRecord record : query.listSampleTechIdsByPermIds(permIds.toArray(new String[permIds.size()]))) + { + techIds.add(record.id); + permIdsByTechIds.put(record.id, new SamplePermId(record.identifier)); + } + return techIds; + } + +} diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/MapSampleTechIdByIdExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/MapSampleTechIdByIdExecutor.java new file mode 100644 index 00000000000..fc3a6962209 --- /dev/null +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/MapSampleTechIdByIdExecutor.java @@ -0,0 +1,48 @@ +/* + * Copyright 2015 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.api.v3.executor.sample; + +import java.util.LinkedList; +import java.util.List; + +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.AbstractMapObjectByIdExecutor; +import ch.ethz.sis.openbis.generic.server.api.v3.helper.common.IListObjectById; +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.ISampleId; + +/** + * + * + * @author Franz-Josef Elmer + */ +@Component +public class MapSampleTechIdByIdExecutor extends AbstractMapObjectByIdExecutor<ISampleId, Long> implements IMapSampleTechIdByIdExecutor +{ + + @Override + protected List<IListObjectById<? extends ISampleId, Long>> createListers(IOperationContext context) + { + List<IListObjectById<? extends ISampleId, Long>> listers = + new LinkedList<IListObjectById<? extends ISampleId, Long>>(); + listers.add(new ListSampleTechIdByPermId()); + listers.add(new ListSampleTechIdByIdentifier()); + return listers; + } + +} diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/SampleQuery.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/SampleQuery.java new file mode 100644 index 00000000000..d3033ac0e63 --- /dev/null +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/SampleQuery.java @@ -0,0 +1,61 @@ +/* + * Copyright 2015 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.api.v3.executor.sample; + +import java.util.List; + +import net.lemnik.eodsql.Select; +import net.lemnik.eodsql.TypeMapper; + +import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.TechIdStringIdentifierRecord; +import ch.ethz.sis.openbis.generic.server.api.v3.translator.entity.common.sql.ObjectQuery; +import ch.systemsx.cisd.common.db.mapper.StringArrayMapper; + +/** + * + * + * @author Franz-Josef Elmer + */ +public interface SampleQuery extends ObjectQuery +{ + @Select(sql = "select id, perm_id as identifier from samples where perm_id = any(?{1})", parameterBindings = + { StringArrayMapper.class }, fetchSize = FETCH_SIZE) + public List<TechIdStringIdentifierRecord> listSampleTechIdsByPermIds(String[] permIds); + + @Select(sql = "select id, code as identifier from samples " + + "where space_id is null and samp_id_part_of is null and code = any(?{1})", parameterBindings = + { StringArrayMapper.class }, fetchSize = FETCH_SIZE) + public List<TechIdStringIdentifierRecord> listSharedSampleTechIdsByCodes(String[] codes); + + @Select(sql = "select s.id, s.code as identifier from samples s join samples cs on s.samp_id_part_of = cs.id " + + "where s.space_id is null and cs.code = ?{1} and s.code = any(?{2})", parameterBindings = + { TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE) + public List<TechIdStringIdentifierRecord> listSharedSampleTechIdsByContainerCodeAndCodes(String containerCode, + String[] codes); + + @Select(sql = "select s.id, s.code as identifier from samples s join spaces sp on s.space_id = sp.id " + + "where sp.code = ?{1} and samp_id_part_of is null and s.code = any(?{2})", parameterBindings = + { TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE) + public List<TechIdStringIdentifierRecord> listSpaceSampleTechIdsByCodes(String spaceCode, String[] codes); + + @Select(sql = "select s.id, s.code as identifier from samples s join spaces sp on s.space_id = sp.id " + + "join samples cs on s.samp_id_part_of = cs.id " + + "where sp.code = ?{1} and cs.code = ?{2} and s.code = any(?{3})", parameterBindings = + { TypeMapper.class, TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE) + public List<TechIdStringIdentifierRecord> listSpaceSampleTechIdsByContainerCodeAndCodes(String spaceCode, + String containerCode, String[] codes); +} diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/MapSampleTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/MapSampleTest.java index 6b3c0960734..936facf86f4 100644 --- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/MapSampleTest.java +++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/MapSampleTest.java @@ -102,19 +102,25 @@ public class MapSampleTest extends AbstractSampleTest SampleIdentifier identifier1 = new SampleIdentifier("/CISD/CP-TEST-1"); SampleIdentifier identifier2 = new SampleIdentifier("/TEST-SPACE/CP-TEST-4"); SampleIdentifier identifier3 = new SampleIdentifier("/CISD/3VCP8"); + SampleIdentifier identifier4 = new SampleIdentifier("/MP"); + SampleIdentifier identifier5 = new SampleIdentifier("/MP:A03"); + SampleIdentifier identifier6 = new SampleIdentifier("/CISD/CL1:A03"); - Map<ISampleId, Sample> map = v3api.mapSamples(sessionToken, Arrays.asList(identifier1, identifier2, identifier3), new SampleFetchOptions()); + List<SampleIdentifier> identifiers = Arrays.asList(identifier1, identifier2, identifier3, identifier4, + identifier5, identifier6); + Map<ISampleId, Sample> map = v3api.mapSamples(sessionToken, identifiers, new SampleFetchOptions()); - assertEquals(3, map.size()); + assertEquals(map.size(), identifiers.size()); Iterator<Sample> iter = map.values().iterator(); - assertEquals(iter.next().getIdentifier(), identifier1); - assertEquals(iter.next().getIdentifier(), identifier2); - assertEquals(iter.next().getIdentifier(), identifier3); - - assertEquals(map.get(identifier1).getIdentifier(), identifier1); - assertEquals(map.get(identifier2).getIdentifier(), identifier2); - assertEquals(map.get(identifier3).getIdentifier(), identifier3); + for (SampleIdentifier identifier : identifiers) + { + assertEquals(iter.next().getIdentifier(), identifier); + } + for (SampleIdentifier identifier : identifiers) + { + assertEquals(map.get(identifier).getIdentifier(), identifier); + } v3api.logout(sessionToken); } -- GitLab