diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/FullSampleIdentifier.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/FullSampleIdentifier.java new file mode 100644 index 0000000000000000000000000000000000000000..bd76b7ea549a452086ea8ebee0c18c5c69124e8c --- /dev/null +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/FullSampleIdentifier.java @@ -0,0 +1,92 @@ +/* + * 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 org.apache.commons.lang.StringUtils; + +import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.SampleIdentifier; + +/** + * Helper class which parses a sample identifier string. + * + * @author Franz-Josef Elmer + */ +class FullSampleIdentifier +{ + private SampleIdentifierParts sampleIdentifierParts; + private String sampleCode; + + FullSampleIdentifier(String sampleIdentifier) + { + if (StringUtils.isBlank(sampleIdentifier)) + { + throw new IllegalArgumentException("Unspecified sample identifier."); + } + if (sampleIdentifier.startsWith("/") == false) + { + throw new IllegalArgumentException("Sample identifier has to start with a '/': " + sampleIdentifier); + } + String[] parts = sampleIdentifier.split("/"); + String spaceCode = null; + String projectCode = null; + if (parts.length > 4) + { + throw new IllegalArgumentException("Sample identifier can not contain more than three '/': " + sampleIdentifier); + } else if (parts.length == 3) + { + spaceCode = parts[1]; + } else if (parts.length == 4) + { + spaceCode = parts[1]; + projectCode = parts[2]; + } + String code = parts[parts.length - 1]; + String[] splittedCode = code.split(":"); + String containerCode = null; + String plainSampleCode = code; + if (splittedCode.length > 2) + { + throw new IllegalArgumentException("Sample code can not contain more than one ':': " + sampleIdentifier); + } else if (splittedCode.length == 2) + { + containerCode = splittedCode[0]; + plainSampleCode = splittedCode[1]; + } + sampleCode = plainSampleCode; + sampleIdentifierParts = new SampleIdentifierParts(spaceCode, projectCode, containerCode); + + } + + SampleIdentifierParts getParts() + { + return sampleIdentifierParts; + } + + String getSampleCode() + { + return sampleCode; + } + + @Override + public String toString() + { + return new SampleIdentifier(sampleIdentifierParts.getSpaceCodeOrNull(), + sampleIdentifierParts.getProjectCodeOrNull(), sampleIdentifierParts.getContainerCodeOrNull(), + sampleCode).toString(); + } + +} 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 index 730b9dc28e9568caa979adf02097afa66e7dd260..366cf9f11f03d5bd502d6870bac01be42b0fc8ff 100644 --- 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 @@ -49,11 +49,11 @@ public class ListSampleTechIdByIdentifier extends AbstractListTechIdById<SampleI { return SampleIdentifier.class; } - + @Override protected Map<Long, SampleIdentifier> createIdsByTechIdsMap(List<SampleIdentifier> ids) { - Map<Key, Map<String, SampleIdentifier>> groupedIdentifiers = new HashMap<>(); + Map<SampleIdentifierParts, Map<String, SampleIdentifier>> groupedIdentifiers = new HashMap<>(); for (SampleIdentifier sampleIdentifier : ids) { ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier sampleIdentifier2 @@ -75,7 +75,7 @@ public class ListSampleTechIdByIdentifier extends AbstractListTechIdById<SampleI } String sampleSubCode = CodeConverter.tryToDatabase(sampleIdentifier2.getSampleSubCode()); String containerCode = CodeConverter.tryToDatabase(sampleIdentifier2.tryGetContainerCode()); - Key key = new Key(spaceCode, containerCode); + SampleIdentifierParts key = new SampleIdentifierParts(spaceCode, null, containerCode); Map<String, SampleIdentifier> identifiersByCode = groupedIdentifiers.get(key); if (identifiersByCode == null) { @@ -87,9 +87,9 @@ public class ListSampleTechIdByIdentifier extends AbstractListTechIdById<SampleI Map<Long, SampleIdentifier> result = new HashMap<>(); SampleQuery query = QueryTool.getManagedQuery(SampleQuery.class); - for (Entry<Key, Map<String, SampleIdentifier>> entry : groupedIdentifiers.entrySet()) + for (Entry<SampleIdentifierParts, Map<String, SampleIdentifier>> entry : groupedIdentifiers.entrySet()) { - Key key = entry.getKey(); + SampleIdentifierParts key = entry.getKey(); Map<String, SampleIdentifier> identifiersByCode = entry.getValue(); List<TechIdStringIdentifierRecord> records = list(query, key, identifiersByCode.keySet()); for (TechIdStringIdentifierRecord record : records) @@ -101,11 +101,11 @@ public class ListSampleTechIdByIdentifier extends AbstractListTechIdById<SampleI return result; } - private List<TechIdStringIdentifierRecord> list(SampleQuery query, Key key, Collection<String> codes) + private List<TechIdStringIdentifierRecord> list(SampleQuery query, SampleIdentifierParts key, Collection<String> codes) { String[] codesArray = codes.toArray(new String[codes.size()]); - String spaceCode = key.spaceCodeOrNull; - String containerCode = key.containerCodeOrNull; + String spaceCode = key.getSpaceCodeOrNull(); + String containerCode = key.getContainerCodeOrNull(); if (spaceCode == null) { if (containerCode == null) @@ -121,48 +121,4 @@ public class ListSampleTechIdByIdentifier extends AbstractListTechIdById<SampleI 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/SampleIdentifierParts.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/SampleIdentifierParts.java new file mode 100644 index 0000000000000000000000000000000000000000..61302519b06e6ba661900518a0ddad2ac413fd82 --- /dev/null +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/SampleIdentifierParts.java @@ -0,0 +1,87 @@ +/* + * 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; + +final class SampleIdentifierParts +{ + private String spaceCodeOrNull; + private String projectCodeOrNull; + private String containerCodeOrNull; + + SampleIdentifierParts(String spaceCodeOrNull, String projectCodeOrNull, String containerCodeOrNull) + { + this.spaceCodeOrNull = spaceCodeOrNull; + this.projectCodeOrNull = projectCodeOrNull; + this.containerCodeOrNull = containerCodeOrNull; + } + + public String getSpaceCodeOrNull() + { + return spaceCodeOrNull; + } + + public String getProjectCodeOrNull() + { + return projectCodeOrNull; + } + + public String getContainerCodeOrNull() + { + return containerCodeOrNull; + } + + @Override + public boolean equals(Object obj) + { + if (obj == this) + { + return true; + } + if (obj instanceof SampleIdentifierParts == false) + { + return false; + } + SampleIdentifierParts key = (SampleIdentifierParts) obj; + return isEqual(spaceCodeOrNull, key.spaceCodeOrNull) + && isEqual(projectCodeOrNull, key.projectCodeOrNull) + && 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 * (37 * calcHashCode(spaceCodeOrNull) + calcHashCode(projectCodeOrNull)) + + calcHashCode(containerCodeOrNull); + } + + @Override + public String toString() + { + // TODO Auto-generated method stub + return super.toString(); + } + + private int calcHashCode(String str) + { + return str == null ? 0 : str.hashCode(); + } +} \ No newline at end of file diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/entity/sample/SampleBaseRecord.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/entity/sample/SampleBaseRecord.java index 2760bddbb3ca3522b74f06e34a458fae5e9bc4e8..49fa50b50122fbaecf03dc021c3481e5ce3a0c8f 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/entity/sample/SampleBaseRecord.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/entity/sample/SampleBaseRecord.java @@ -30,6 +30,8 @@ public class SampleBaseRecord extends ObjectBaseRecord public String spaceCode; + public String projectCode; + public String containerCode; public String permId; diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/entity/sample/SampleQuery.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/entity/sample/SampleQuery.java index 798f6198f3260e2cd2d0f109a2a760d2acc16b5b..bd87d642c458c6664b5f8985b98d7e837c5176ef 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/entity/sample/SampleQuery.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/entity/sample/SampleQuery.java @@ -41,8 +41,11 @@ public interface SampleQuery extends ObjectQuery + "where s.id = any(?{1})", parameterBindings = { LongSetMapper.class }, fetchSize = FETCH_SIZE) public List<SampleAuthorizationRecord> getAuthorizations(LongSet sampleIds); - @Select(sql = "select s.id, s.code, s.perm_id as permId, sp.code as spaceCode, sc.code as containerCode, s.registration_timestamp as registrationDate, s.modification_timestamp as modificationDate " + @Select(sql = "select s.id, s.code, s.perm_id as permId, sp.code as spaceCode, p.code as projectCode, " + + "sc.code as containerCode, s.registration_timestamp as registrationDate, " + + "s.modification_timestamp as modificationDate " + "from samples s left join spaces sp on s.space_id = sp.id " + + "left join projects p on s.proj_id = p.id " + "left join samples sc on s.samp_id_part_of = sc.id " + "where s.id = any(?{1})", parameterBindings = { LongSetMapper.class }, fetchSize = FETCH_SIZE) public List<SampleBaseRecord> getSamples(LongSet sampleIds); diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/entity/sample/SampleTranslator.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/entity/sample/SampleTranslator.java index 888af5f9247fbddd9a9d550813d190785e831518..33e0ea3ae6df187795f8928bf624aade9662100b 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/entity/sample/SampleTranslator.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/entity/sample/SampleTranslator.java @@ -208,7 +208,8 @@ public class SampleTranslator extends AbstractCachingTranslator<Long, Sample, Sa result.setPermId(new SamplePermId(baseRecord.permId)); result.setCode(baseRecord.code); - result.setIdentifier(new SampleIdentifier(baseRecord.spaceCode, baseRecord.containerCode, baseRecord.code)); + result.setIdentifier(new SampleIdentifier(baseRecord.spaceCode, baseRecord.projectCode, + baseRecord.containerCode, baseRecord.code)); result.setModificationDate(baseRecord.modificationDate); result.setRegistrationDate(baseRecord.registrationDate); diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/FullSampleIdentifierTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/FullSampleIdentifierTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4feb0e8aefa4aed8fabc72bb9b8482b40f70daa5 --- /dev/null +++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/FullSampleIdentifierTest.java @@ -0,0 +1,69 @@ +/* + * 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 static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.fail; + +import org.testng.annotations.Test; + +/** + * + * + * @author Franz-Josef Elmer + */ +public class FullSampleIdentifierTest +{ + + @Test + public void testHappyCases() + { + assertSampId("/S1"); + assertSampId("/SPACE1/S2"); + assertSampId("/SPACE1/S2:A02"); + assertSampId("/SPACE1/PROJECT1/S1"); + assertSampId("/SPACE1/PROJECT1/S1:A02"); + } + + @Test + public void testFailingCases() + { + assertInvalidSampId("Unspecified sample identifier.", null); + assertInvalidSampId("Unspecified sample identifier.", ""); + assertInvalidSampId("Sample identifier has to start with a '/': A/BC", "A/BC"); + assertInvalidSampId("Sample identifier can not contain more than three '/': /A/B/C/D", "/A/B/C/D"); + assertInvalidSampId("Sample code can not contain more than one ':': /A/B:C:D", "/A/B:C:D"); + } + + private void assertInvalidSampId(String expectedErrorMsg, String identifier) + { + try + { + new FullSampleIdentifier(identifier); + fail("IllegalArgumentException expected"); + } catch (IllegalArgumentException ex) + { + assertEquals(expectedErrorMsg, ex.getMessage()); + } + } + + private void assertSampId(String identifier) + { + assertEquals(new FullSampleIdentifier(identifier).toString(), identifier); + } + +} diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/ProjectSampleTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/ProjectSampleTest.java index a4e75b18e9ff0a8e2bc9192ae25d726f79cfacf1..0a8f05a6754429136cff918ade6cca0f97792fdd 100644 --- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/ProjectSampleTest.java +++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/ProjectSampleTest.java @@ -367,7 +367,7 @@ public class ProjectSampleTest extends AbstractTest SearchResult<Sample> result = v3api.searchSamples(systemSessionToken, searchCriteria, fetchOptions); - assertEquals(result.getObjects().get(0).getIdentifier().getIdentifier(), "/CISD/3VCP5"); + assertEquals(result.getObjects().get(0).getIdentifier().getIdentifier(), "/CISD/NEMO/3VCP5"); assertEquals(result.getObjects().get(0).getProject().getIdentifier().getIdentifier(), "/CISD/NEMO"); assertEquals(result.getTotalCount(), 1); } @@ -383,7 +383,7 @@ public class ProjectSampleTest extends AbstractTest SearchResult<Sample> result = v3api.searchSamples(systemSessionToken, searchCriteria, fetchOptions); - assertEquals(result.getObjects().get(0).getIdentifier().getIdentifier(), "/CISD/3VCP5"); + assertEquals(result.getObjects().get(0).getIdentifier().getIdentifier(), "/CISD/NEMO/3VCP5"); assertEquals(result.getObjects().get(0).getProject().getIdentifier().getIdentifier(), "/CISD/NEMO"); assertEquals(result.getTotalCount(), 1); } @@ -398,7 +398,7 @@ public class ProjectSampleTest extends AbstractTest SearchResult<Sample> result = v3api.searchSamples(systemSessionToken, searchCriteria, fetchOptions); - assertEquals(result.getObjects().get(0).getIdentifier().getIdentifier(), "/CISD/3VCP5"); + assertEquals(result.getObjects().get(0).getIdentifier().getIdentifier(), "/CISD/NEMO/3VCP5"); assertEquals(result.getObjects().get(0).getProject().getIdentifier().getIdentifier(), "/CISD/NEMO"); assertEquals(result.getTotalCount(), 1); } @@ -413,7 +413,7 @@ public class ProjectSampleTest extends AbstractTest SearchResult<Sample> result = v3api.searchSamples(systemSessionToken, searchCriteria, fetchOptions); - assertEquals(result.getObjects().get(0).getIdentifier().getIdentifier(), "/CISD/3VCP5"); + assertEquals(result.getObjects().get(0).getIdentifier().getIdentifier(), "/CISD/NEMO/3VCP5"); assertEquals(result.getObjects().get(0).getProject().getIdentifier().getIdentifier(), "/CISD/NEMO"); assertEquals(result.getTotalCount(), 1); } diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/sample/SampleIdentifier.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/sample/SampleIdentifier.java index 90fe47d68de6c23c272fc5effcbbdc05cc0ec283..e029e57e7f8832695e1f378b4f8a1dcacbde01db 100644 --- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/sample/SampleIdentifier.java +++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/sample/SampleIdentifier.java @@ -40,14 +40,31 @@ public class SampleIdentifier extends ObjectIdentifier implements ISampleId public SampleIdentifier(String spaceCodeOrNull, String containerCodeOrNull, String sampleCode) { - this(createIdentifier(spaceCodeOrNull, containerCodeOrNull, sampleCode)); + this(spaceCodeOrNull, null, containerCodeOrNull, sampleCode); } - private static String createIdentifier(String spaceCodeOrNull, String containerCodeOrNull, String sampleCode) + public SampleIdentifier(String spaceCodeOrNull, String projectCodeOrNull, String containerCodeOrNull, String sampleCode) { - String spaceCode = spaceCodeOrNull != null ? "/" + spaceCodeOrNull : ""; - String containerCode = containerCodeOrNull != null ? containerCodeOrNull + ":" : ""; - return spaceCode + "/" + containerCode + sampleCode; + this(createIdentifier(spaceCodeOrNull, projectCodeOrNull, containerCodeOrNull, sampleCode)); + } + + private static String createIdentifier(String spaceCodeOrNull, String projectCodeOrNull, + String containerCodeOrNull, String sampleCode) + { + StringBuilder builder = new StringBuilder("/"); + if (spaceCodeOrNull != null) + { + builder.append(spaceCodeOrNull).append("/"); + } + if (projectCodeOrNull != null) + { + builder.append(projectCodeOrNull).append("/"); + } + if (containerCodeOrNull != null) + { + builder.append(containerCodeOrNull).append(":"); + } + return builder.append(sampleCode).toString(); } //