diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/executor/CreateUploadedDataSetExecutor.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/executor/CreateUploadedDataSetExecutor.java index ae944447b24b1800d8e6c30226871c88166192f5..20b81a77c8ae6f88d7be1e2d8e04f42af2091b56 100644 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/executor/CreateUploadedDataSetExecutor.java +++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/executor/CreateUploadedDataSetExecutor.java @@ -16,14 +16,12 @@ package ch.ethz.sis.openbis.generic.server.dssapi.v3.executor; -import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; -import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi; @@ -46,8 +44,6 @@ import ch.ethz.sis.openbis.generic.dssapi.v3.dto.dataset.create.UploadedDataSetC import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.OperationContext; import ch.ethz.sis.openbis.generic.server.asapi.v3.utils.ExceptionUtils; import ch.systemsx.cisd.common.exceptions.UserFailureException; -import ch.systemsx.cisd.common.logging.LogCategory; -import ch.systemsx.cisd.common.logging.LogFactory; import ch.systemsx.cisd.etlserver.api.v1.PutDataSetService; import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; @@ -64,10 +60,6 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; public class CreateUploadedDataSetExecutor implements ICreateUploadedDataSetExecutor { - private static Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, CreateUploadedDataSetExecutor.class); - - private PutDataSetService putService; - @Override public DataSetPermId create(String sessionToken, UploadedDataSetCreation creation) { @@ -173,28 +165,6 @@ public class CreateUploadedDataSetExecutor implements ICreateUploadedDataSetExec } } - // upload id - - if (creation.getUploadId() != null) - { - if (creation.getUploadId().contains("/")) - { - throw new UserFailureException("Upload id must not contain '/'"); - } - - File temporaryIncomingRoot = getPutService().getTemporaryIncomingRoot(typeCode); - File temporaryIncomingDir = new File(temporaryIncomingRoot, creation.getUploadId()); - - if (false == temporaryIncomingDir.exists()) - { - throw new UserFailureException( - "The folder for the upload id " + creation.getUploadId() + " could not be found. Have you uploaded the file(s) first?"); - } - } else - { - throw new UserFailureException("Upload id cannot be null."); - } - NewDataSetDTO newDataSet = new NewDataSetDTO(typeCode, owner, null, new ArrayList<FileInfoDssDTO>()); newDataSet.setProperties(creation.getProperties()); newDataSet.setParentDataSetCodes(parentCodes); @@ -211,14 +181,8 @@ public class CreateUploadedDataSetExecutor implements ICreateUploadedDataSetExec return ServiceProvider.getOpenBISService(); } - private synchronized PutDataSetService getPutService() + private PutDataSetService getPutService() { - if (putService == null) - { - putService = new PutDataSetService(ServiceProvider.getOpenBISService(), operationLog); - putService.setStoreDirectory(ServiceProvider.getConfigProvider().getStoreRoot()); - } - - return putService; + return (PutDataSetService) ServiceProvider.getDataStoreService().getPutDataSetService(); } } diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/upload/StoreShareFileUploadServlet.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/upload/StoreShareFileUploadServlet.java index e40df8eeb44a5fb311da1d059dedbd6e299243bb..242a2203b6a03f3325eb97d7234624d8090522db 100644 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/upload/StoreShareFileUploadServlet.java +++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/upload/StoreShareFileUploadServlet.java @@ -19,7 +19,6 @@ package ch.ethz.sis.openbis.generic.server.dssapi.v3.upload; import java.io.IOException; import java.io.InputStream; -import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -61,17 +60,9 @@ public class StoreShareFileUploadServlet extends HttpServlet public static final String IGNORE_FILE_PATH_PARAM = "ignoreFilePath"; - public static final String UPLOAD_ID_PARAM = "uploadID"; - - private PutDataSetService putService; + public static final String FOLDER_PATH_PARAM = "folderPath"; - @Override - public final void init(final ServletConfig servletConfig) throws ServletException - { - super.init(servletConfig); - this.putService = new PutDataSetService(ServiceProvider.getOpenBISService(), operationLog); - putService.setStoreDirectory(ServiceProvider.getConfigProvider().getStoreRoot()); - } + public static final String UPLOAD_ID_PARAM = "uploadID"; @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) @@ -90,6 +81,8 @@ public class StoreShareFileUploadServlet extends HttpServlet throw new UserFailureException("Please upload at least one file"); } + PutDataSetService putService = (PutDataSetService) ServiceProvider.getDataStoreService().getPutDataSetService(); + while (iterator.hasNext()) { FileItemStream file = null; @@ -109,8 +102,12 @@ public class StoreShareFileUploadServlet extends HttpServlet */ String filePath = uploadRequest.isIgnoreFilePath() ? FilenameUtils.getName(file.getName()) : file.getName(); - putService.putFileToStoreShare(uploadRequest.getSessionId(), filePath, uploadRequest.getDataSetType(), - uploadRequest.getUploadId(), stream); + operationLog.info("Received file '" + filePath + "' for upload id '" + uploadRequest.getUploadId() + "' and data set type '" + + uploadRequest.getDataSetType() + "'"); + + putService.putFileToStoreShare(uploadRequest.getSessionId(), uploadRequest.getFolderPath(), filePath, + uploadRequest.getDataSetType(), uploadRequest.getUploadId(), stream); + } finally { IOUtils.closeQuietly(stream); @@ -161,6 +158,11 @@ public class StoreShareFileUploadServlet extends HttpServlet } } + public String getFolderPath() + { + return request.getParameter(FOLDER_PATH_PARAM); + } + public FileItemIterator getFiles() throws FileUploadException, IOException { ServletFileUpload upload = new ServletFileUpload(); diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/DataSetTypeToRegistratorMapper.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/DataSetTypeToRegistratorMapper.java index 70c28293ea6292d024d8fc99f02eb1d4744cfa0c..6843a06f304fbd9b3fa0f67f39d86367514d9723 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/DataSetTypeToRegistratorMapper.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/DataSetTypeToRegistratorMapper.java @@ -17,6 +17,8 @@ package ch.systemsx.cisd.etlserver.api.v1; import java.io.File; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.Properties; @@ -100,8 +102,7 @@ class DataSetTypeToRegistratorMapper + dropboxName + " = " + dropboxName); return defaultHandler; - } - else + } else { return plugin; } @@ -117,6 +118,14 @@ class DataSetTypeToRegistratorMapper return (null == plugin) ? defaultHandler : plugin; } + public Collection<ITopLevelDataSetRegistrator> getRegistrators() + { + Collection<ITopLevelDataSetRegistrator> registrators = new ArrayList<ITopLevelDataSetRegistrator>(); + registrators.add(defaultHandler); + registrators.addAll(handlerMap.values()); + return registrators; + } + public void initializeStoreRootDirectory(File storeDirectory) { initializeStoreRootDirectory(storeDirectory, defaultHandler); diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetService.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetService.java index f1e8fe136846c1aa27fd28d3c9e10ec557ccb478..8bd0b279faae8c11c174584a31200a3f803cb62c 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetService.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetService.java @@ -21,6 +21,8 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Properties; @@ -36,6 +38,7 @@ import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel; import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked; import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; import ch.systemsx.cisd.common.exceptions.UserFailureException; +import ch.systemsx.cisd.common.filesystem.QueueingPathRemoverService; import ch.systemsx.cisd.common.mail.IMailClient; import ch.systemsx.cisd.common.mail.MailClient; import ch.systemsx.cisd.etlserver.DataStrategyStore; @@ -48,6 +51,7 @@ import ch.systemsx.cisd.openbis.common.io.ByteArrayBasedContentNode; import ch.systemsx.cisd.openbis.common.io.ConcatenatedContentInputStream; import ch.systemsx.cisd.openbis.dss.generic.shared.Constants; import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; +import ch.systemsx.cisd.openbis.dss.generic.shared.IPutDataSetService; import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssDTO; import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.NewDataSetDTO; @@ -63,7 +67,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseInstance; * * @author Chandrasekhar Ramakrishnan */ -public class PutDataSetService +public class PutDataSetService implements IPutDataSetService { private static final String MULTIPLE_FILES_UPLOAD_DIR = "upload"; @@ -270,15 +274,48 @@ public class PutDataSetService doInitialization(); } - String dataSetTypeOrNull = newDataSet.tryDataSetType(); - ITopLevelDataSetRegistrator registrator = registratorMap.getRegistratorForType(dataSetTypeOrNull); + if (StringUtils.isBlank(sessionToken)) + { + throw new UserFailureException("Session token cannot be null or empty"); + } + if (sessionToken.contains("/")) + { + throw new UserFailureException("Session token must not contain '/'"); + } + if (newDataSet == null) + { + throw new UserFailureException("New data set cannot be null"); + } + if (StringUtils.isBlank(uploadId)) + { + throw new UserFailureException("Upload id cannot be null or empty"); + } + if (uploadId.contains("/")) + { + throw new UserFailureException("Upload id must not contain '/'"); + } + + ServiceProvider.getOpenBISService().checkSession(sessionToken); + + String dataSetType = newDataSet.tryDataSetType(); + ITopLevelDataSetRegistrator registrator = registratorMap.getRegistratorForType(dataSetType); - File uploadDir = new File(getTemporaryIncomingRoot(dataSetTypeOrNull), uploadId); - File multipleFilesUploadDir = new File(uploadDir, MULTIPLE_FILES_UPLOAD_DIR); - File[] uploadedFiles = multipleFilesUploadDir.listFiles(); + File sessionUploadDir = new File(getTemporaryIncomingRoot(dataSetType), sessionToken); + File uploadIdDir = new File(sessionUploadDir, uploadId); + File multipleFilesUploadDir = new File(uploadIdDir, MULTIPLE_FILES_UPLOAD_DIR); + + File[] uploadedFiles = null; File dataSet = null; - if (uploadedFiles != null && uploadedFiles.length == 1) + if (multipleFilesUploadDir.exists() && multipleFilesUploadDir.isDirectory()) + { + uploadedFiles = multipleFilesUploadDir.listFiles(); + } + + if (uploadedFiles == null || uploadedFiles.length == 0) + { + throw new UserFailureException("No uploaded files found for upload id '" + uploadId + "'"); + } else if (uploadedFiles.length == 1) { dataSet = uploadedFiles[0]; } else @@ -288,15 +325,16 @@ public class PutDataSetService if (registrator instanceof PutDataSetServerPluginHolder) { - return new PutDataSetExecutor(this, ((PutDataSetServerPluginHolder) registrator).getPlugin(), sessionToken, newDataSet, uploadDir, + return new PutDataSetExecutor(this, ((PutDataSetServerPluginHolder) registrator).getPlugin(), sessionToken, newDataSet, uploadIdDir, dataSet).executeWithoutWriting(); } else { - return new PutDataSetTopLevelDataSetHandler(this, registrator, sessionToken, newDataSet, uploadDir, dataSet).executeWithoutWriting(); + return new PutDataSetTopLevelDataSetHandler(this, registrator, sessionToken, newDataSet, uploadIdDir, dataSet).executeWithoutWriting(); } } - public void putFileToStoreShare(String sessionToken, String filePath, String dataSetType, String uploadId, InputStream inputStream) + public void putFileToStoreShare(String sessionToken, String folderPathOrNull, String filePath, String dataSetType, String uploadId, + InputStream inputStream) { if (false == isInitialized) { @@ -312,10 +350,18 @@ public class PutDataSetService { throw new UserFailureException("Session token cannot be null or empty"); } + if (sessionToken.contains("/")) + { + throw new UserFailureException("Session token must not contain '/'"); + } if (StringUtils.isBlank(filePath)) { throw new UserFailureException("File path cannot be null or empty"); } + if (false == StringUtils.isBlank(folderPathOrNull) && folderPathOrNull.contains("../")) + { + throw new UserFailureException("Folder path must not contain '../'"); + } if (filePath.contains("../")) { throw new UserFailureException("File path must not contain '../'"); @@ -339,26 +385,30 @@ public class PutDataSetService ServiceProvider.getOpenBISService().checkSession(sessionToken); - File uploadDir = new File(getTemporaryIncomingRoot(dataSetType), uploadId); - if (false == uploadDir.exists()) + File sessionUploadDir = new File(getTemporaryIncomingRoot(dataSetType), sessionToken); + File uploadIdDir = new File(sessionUploadDir, uploadId); + File multipleFilesUploadDir = new File(uploadIdDir, MULTIPLE_FILES_UPLOAD_DIR); + + File filePathDir = null; + if (StringUtils.isBlank(folderPathOrNull)) { - uploadDir.mkdir(); + filePathDir = new File(multipleFilesUploadDir, FilenameUtils.getPath(filePath)); + } else + { + filePathDir = new File(multipleFilesUploadDir, FilenameUtils.getPath(folderPathOrNull + "/" + filePath)); } - File uploadSubDir = new File(uploadDir, MULTIPLE_FILES_UPLOAD_DIR); - if (false == uploadSubDir.exists()) + if (false == filePathDir.exists()) { - uploadSubDir.mkdir(); + filePathDir.mkdirs(); } - File filePathDir = new File(uploadSubDir, FilenameUtils.getPath(filePath)); - filePathDir.mkdirs(); - file = new File(filePathDir, FilenameUtils.getName(filePath)); outputStream = new FileOutputStream(file); - IOUtils.copyLarge(inputStream, outputStream); + operationLog.info("File '" + filePath + "' with upload id: '" + uploadId + "' has been stored as '" + file.getCanonicalPath() + "'"); + } catch (IOException ioe) { IOUtils.closeQuietly(outputStream); @@ -455,6 +505,22 @@ public class PutDataSetService return registratorMap.getRegistratorForType(dataSetTypeOrNull).getGlobalState(); } + private Collection<TopLevelDataSetRegistratorGlobalState> getThreadGlobalStates() + { + Collection<TopLevelDataSetRegistratorGlobalState> states = new ArrayList<TopLevelDataSetRegistratorGlobalState>(); + Collection<ITopLevelDataSetRegistrator> registrators = registratorMap.getRegistrators(); + + for (ITopLevelDataSetRegistrator registrator : registrators) + { + if (registrator != null && registrator.getGlobalState() != null) + { + states.add(registrator.getGlobalState()); + } + } + + return states; + } + Logger getOperationLog() { return operationLog; @@ -513,6 +579,16 @@ public class PutDataSetService TopLevelDataSetRegistratorGlobalState globalState = getThreadGlobalState(dataSetTypeCodeOrNull); + return getTemporaryIncomingRoot(globalState); + } + + private File getTemporaryIncomingRoot(TopLevelDataSetRegistratorGlobalState globalState) + { + if (false == isInitialized) + { + doInitialization(); + } + File storeRoot = globalState.getStoreRootDir(); if (false == StringUtils.isBlank(globalState.getShareId())) { @@ -530,6 +606,46 @@ public class PutDataSetService return storeRoot; } + public void cleanupSession(String sessionToken) + { + if (false == isInitialized) + { + doInitialization(); + } + + if (StringUtils.isBlank(sessionToken)) + { + throw new IllegalArgumentException("Session token cannot be null or empty"); + } + if (sessionToken.contains("/")) + { + throw new UserFailureException("Session token must not contain '/'"); + } + + Collection<TopLevelDataSetRegistratorGlobalState> states = getThreadGlobalStates(); + + for (TopLevelDataSetRegistratorGlobalState state : states) + { + File sessionUploadDir = null; + + try + { + sessionUploadDir = new File(getTemporaryIncomingRoot(state), sessionToken); + + if (sessionUploadDir.exists()) + { + operationLog.info("Cleaning up a user session upload folder '" + sessionUploadDir.getAbsolutePath() + "'"); + QueueingPathRemoverService.removeRecursively(sessionUploadDir); + } + } catch (Exception e) + { + operationLog.warn( + "Could not clean up a user session upload folder '" + sessionUploadDir.getAbsolutePath() + "' together with the user session", + e); + } + } + } + } /** diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java index 15bfac52dd8cbd05ae3c5886e77f365123ff52b3..13697bc6c9a8e113896dc0ccf56a9cbc6167105c 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java @@ -511,6 +511,8 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic { QueueingPathRemoverService.removeRecursively(sessionWorkspace); } + + getPutDataSetService().cleanupSession(userSessionToken); } @Override @@ -587,7 +589,8 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic return availableService; } - private PutDataSetService getPutDataSetService() + @Override + public PutDataSetService getPutDataSetService() { if (putService == null) { diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IDataStoreServiceInternal.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IDataStoreServiceInternal.java index 8f88f2a3d3cbeb4ef5a2808a519473e5c95c49ff..4b186e7cd728867a720f4b6139ff76b09f921d2e 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IDataStoreServiceInternal.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IDataStoreServiceInternal.java @@ -72,4 +72,9 @@ public interface IDataStoreServiceInternal extends IInitializable, IDataStoreSer public void scheduleTask(String taskKey, IProcessingPluginTask task, Map<String, String> parameterBindings, List<DatasetDescription> datasets, String userId, String userEmailOrNull, String userSessionToken); + + /** + * Returns the put data set service. + */ + IPutDataSetService getPutDataSetService(); } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IPutDataSetService.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IPutDataSetService.java new file mode 100644 index 0000000000000000000000000000000000000000..9fcb7e099a60b3e7e19c29e33d45194d7c17f68c --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IPutDataSetService.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 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.systemsx.cisd.openbis.dss.generic.shared; + +/** + * @author pkupczyk + */ +public interface IPutDataSetService +{ + +} diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/CreateUploadedDataSetsTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/CreateUploadedDataSetsTest.java index 53f8ef2a2d9bc8f5479cfb95e161680c7994f55b..07eb6409ecb6923c36732bff7041ca785d5a3ce4 100644 --- a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/CreateUploadedDataSetsTest.java +++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/CreateUploadedDataSetsTest.java @@ -16,6 +16,8 @@ package ch.ethz.sis.openbis.generic.dss.systemtest.api.v3; +import java.io.File; +import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -84,7 +86,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest public void testUploadWithInvalidSession() throws Exception { ContentResponse response = - uploadFiles("admin-180211214633760xF769DD44CAFFAF7B50FBEADF00DBEE1F", UUID.randomUUID().toString(), "UNKNOWN", true, + uploadFiles("admin-180211214633760xF769DD44CAFFAF7B50FBEADF00DBEE1F", UUID.randomUUID().toString(), "UNKNOWN", true, null, new FileToUpload()); assertResponseError(response); assertTrue(response.getContentAsString(), response.getContentAsString().contains("user is not logged in")); @@ -93,7 +95,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest @Test public void testUploadWithoutSession() throws Exception { - ContentResponse response = uploadFiles(null, UUID.randomUUID().toString(), "UNKNOWN", true, new FileToUpload()); + ContentResponse response = uploadFiles(null, UUID.randomUUID().toString(), "UNKNOWN", true, null, new FileToUpload()); assertResponseError(response); assertTrue(response.getContentAsString(), response.getContentAsString().contains("Session token cannot be null or empty")); } @@ -103,7 +105,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest { String sessionToken = as.login(TEST_USER, PASSWORD); - ContentResponse response = uploadFiles(sessionToken, UUID.randomUUID().toString(), null, true, new FileToUpload()); + ContentResponse response = uploadFiles(sessionToken, UUID.randomUUID().toString(), null, true, null, new FileToUpload()); assertResponseError(response); assertTrue(response.getContentAsString(), response.getContentAsString().contains("Data set type cannot be null or empty")); } @@ -113,7 +115,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest { String sessionToken = as.login(TEST_USER, PASSWORD); - ContentResponse response = uploadFiles(sessionToken, null, "UNKNOWN", true, new FileToUpload()); + ContentResponse response = uploadFiles(sessionToken, null, "UNKNOWN", true, null, new FileToUpload()); assertResponseError(response); assertTrue(response.getContentAsString(), response.getContentAsString().contains("Upload id cannot be null or empty")); } @@ -123,7 +125,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest { String sessionToken = as.login(TEST_USER, PASSWORD); - ContentResponse response = uploadFiles(sessionToken, "iam/incorrect", "UNKNOWN", true, new FileToUpload()); + ContentResponse response = uploadFiles(sessionToken, "iam/incorrect", "UNKNOWN", true, null, new FileToUpload()); assertResponseError(response); assertTrue(response.getContentAsString(), response.getContentAsString().contains("Upload id must not contain '/'")); } @@ -133,7 +135,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest { String sessionToken = as.login(TEST_USER, PASSWORD); - ContentResponse response = uploadFiles(sessionToken, UUID.randomUUID().toString(), "UNKNOWN", true); + ContentResponse response = uploadFiles(sessionToken, UUID.randomUUID().toString(), "UNKNOWN", true, null); assertResponseError(response); assertTrue(response.getContentAsString(), response.getContentAsString().contains("Please upload at least one file")); } @@ -144,7 +146,8 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest String sessionToken = as.login(TEST_USER, PASSWORD); ContentResponse response = - uploadFiles(sessionToken, UUID.randomUUID().toString(), "UNKNOWN", false, new FileToUpload("name", "iam/../incorrect", "content")); + uploadFiles(sessionToken, UUID.randomUUID().toString(), "UNKNOWN", false, null, + new FileToUpload("name", "iam/../incorrect", "content")); assertResponseError(response); assertTrue(response.getContentAsString(), response.getContentAsString().contains("File path must not contain '../'")); } @@ -155,11 +158,68 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest String sessionToken = as.login(TEST_USER, PASSWORD); ContentResponse response = - uploadFiles(sessionToken, UUID.randomUUID().toString(), "UNKNOWN", false, new FileToUpload("name", null, "content")); + uploadFiles(sessionToken, UUID.randomUUID().toString(), "UNKNOWN", false, null, new FileToUpload("name", null, "content")); assertResponseError(response); assertTrue(response.getContentAsString(), response.getContentAsString().contains("File path cannot be null or empty")); } + @Test + public void testUploadWithFolderPathWithFolderUp() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + ContentResponse response = + uploadFiles(sessionToken, UUID.randomUUID().toString(), "UNKNOWN", false, "iam/../incorrect", new FileToUpload()); + assertResponseError(response); + assertTrue(response.getContentAsString(), response.getContentAsString().contains("Folder path must not contain '../'")); + } + + @Test + public void testUploadWithFilesCleanedAfterLogout() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "UNKNOWN"; + + FileToUpload file = new FileToUpload("file", "test.txt", "test content"); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, false, null, file); + assertResponseOK(response); + + FilenameFilter sessionUploadDirFilter = new FilenameFilter() + { + @Override + public boolean accept(File dir, String name) + { + return sessionToken.equals(name); + } + }; + + File rpcIncomingDir = new File(store, "1/rpc-incoming"); + + File[] listFiles = rpcIncomingDir.listFiles(sessionUploadDirFilter); + assertEquals(1, listFiles.length); + + as.logout(sessionToken); + + // clean up of the session and the upload folder is done asynchronously therefore we have to wait + + long timeoutMillis = System.currentTimeMillis() + 5000; + while (System.currentTimeMillis() < timeoutMillis) + { + listFiles = rpcIncomingDir.listFiles(sessionUploadDirFilter); + if (listFiles.length == 0) + { + return; + } else + { + Thread.sleep(100); + } + } + fail("Session upload folder hasn't been removed after the logout"); + } + @Test public void testCreateWithInvalidSession() throws Exception { @@ -185,7 +245,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest creation.setSampleId(new SampleIdentifier(sampleIdentifier)); creation.setUploadId(uploadId); - ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, null, new FileToUpload()); assertResponseOK(response); try @@ -212,7 +272,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest creation.setSampleId(new SampleIdentifier(sampleIdentifier)); creation.setUploadId(uploadId); - ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, null, new FileToUpload()); assertResponseOK(response); try @@ -237,7 +297,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest creation.setTypeId(new EntityTypePermId(dataSetType)); creation.setUploadId(uploadId); - ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, null, new FileToUpload()); assertResponseOK(response); try @@ -264,7 +324,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest creation.setSampleId(new SampleIdentifier(sampleIdentifier)); creation.setUploadId(uploadId); - ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, null, new FileToUpload()); assertResponseOK(response); try @@ -291,7 +351,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest creation.setSampleId(new SampleIdentifier(sampleIdentifier)); creation.setUploadId(uploadId); - ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, null, new FileToUpload()); assertResponseOK(response); DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); @@ -314,7 +374,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest creation.setSampleId(new SamplePermId(samplePermId)); creation.setUploadId(uploadId); - ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, null, new FileToUpload()); assertResponseOK(response); DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); @@ -337,7 +397,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); creation.setUploadId(uploadId); - ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, null, new FileToUpload()); assertResponseOK(response); try @@ -365,7 +425,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); creation.setUploadId(uploadId); - ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, null, new FileToUpload()); assertResponseOK(response); DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); @@ -388,7 +448,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest creation.setExperimentId(new ExperimentPermId(experimentPermId)); creation.setUploadId(uploadId); - ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, null, new FileToUpload()); assertResponseOK(response); DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); @@ -415,7 +475,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest creation.setUploadId(uploadId); creation.setProperties(properties); - ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, null, new FileToUpload()); assertResponseOK(response); DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); @@ -441,7 +501,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest creation.setParentIds(Arrays.asList(parentId)); creation.setUploadId(uploadId); - ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, null, new FileToUpload()); assertResponseOK(response); DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); @@ -517,9 +577,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest fail(); } catch (UserFailureException e) { - assertTrue(e.getMessage(), - e.getMessage() - .contains("The folder for the upload id " + uploadId + " could not be found. Have you uploaded the file(s) first?")); + assertTrue(e.getMessage(), e.getMessage().contains("No uploaded files found for upload id '" + uploadId + "'")); } } @@ -539,7 +597,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); creation.setUploadId(uploadId); - ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, false, file); + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, false, null, file); assertResponseOK(response); DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); @@ -574,7 +632,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); creation.setUploadId(uploadId); - ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, false, file1, file2, file3, file4); + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, false, null, file1, file2, file3, file4); assertResponseOK(response); DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); @@ -612,7 +670,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); creation.setUploadId(uploadId); - ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, null, file1, file2); + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, null, null, file1, file2); assertResponseOK(response); DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); @@ -647,7 +705,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); creation.setUploadId(uploadId); - ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, false, file1, file2); + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, false, null, file1, file2); assertResponseOK(response); DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); @@ -666,6 +724,100 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest assertFile(files.get(5), "original/upload/test1.txt", file1.content); } + @Test + public void testCreateWithOneFolderPath() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "UNKNOWN"; + String experimentIdentifier = "/CISD/NEMO/EXP1"; + + FileToUpload file1 = new FileToUpload("file1", "path/to/ignore/test1.txt", "test1 content"); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, "folderPath", file1); + assertResponseOK(response); + + FileToUpload file2 = new FileToUpload("file2", "filePath/test2.txt", "test2 content"); + + response = uploadFiles(sessionToken, uploadId, dataSetType, false, "/folderPath", file2); + assertResponseOK(response); + + FileToUpload file3 = new FileToUpload("file3", "/filePath/test3.txt", "test3 content"); + + response = uploadFiles(sessionToken, uploadId, dataSetType, false, "/folderPath/", file3); + assertResponseOK(response); + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); + creation.setUploadId(uploadId); + + DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); + + assertEquals(dataSetType, dataSet.getType().getCode()); + assertEquals(experimentIdentifier, dataSet.getExperiment().getIdentifier().getIdentifier()); + + List<DownloadedFile> files = downloadFiles(sessionToken, dataSet.getPermId()); + assertEquals(7, files.size()); + + assertDirectory(files.get(0), ""); + assertDirectory(files.get(1), "original"); + assertDirectory(files.get(2), "original/folderPath"); + assertDirectory(files.get(3), "original/folderPath/filePath"); + assertFile(files.get(4), "original/folderPath/filePath/test2.txt", file2.content); + assertFile(files.get(5), "original/folderPath/filePath/test3.txt", file3.content); + assertFile(files.get(6), "original/folderPath/test1.txt", file1.content); + } + + @Test + public void testCreateWithMultipleFolderPaths() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "UNKNOWN"; + String experimentIdentifier = "/CISD/NEMO/EXP1"; + + FileToUpload file1 = new FileToUpload("file1", "path/to/ignore/test1.txt", "test1 content"); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, "folderPathA", file1); + assertResponseOK(response); + + FileToUpload file2 = new FileToUpload("file2", "filePath/test2.txt", "test2 content"); + + response = uploadFiles(sessionToken, uploadId, dataSetType, false, "/folderPathB", file2); + assertResponseOK(response); + + FileToUpload file3 = new FileToUpload("file3", "/filePath/test3.txt", "test3 content"); + + response = uploadFiles(sessionToken, uploadId, dataSetType, false, "/folderPathB/", file3); + assertResponseOK(response); + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); + creation.setUploadId(uploadId); + + DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); + + assertEquals(dataSetType, dataSet.getType().getCode()); + assertEquals(experimentIdentifier, dataSet.getExperiment().getIdentifier().getIdentifier()); + + List<DownloadedFile> files = downloadFiles(sessionToken, dataSet.getPermId()); + assertEquals(9, files.size()); + + assertDirectory(files.get(0), ""); + assertDirectory(files.get(1), "original"); + assertDirectory(files.get(2), "original/upload"); + assertDirectory(files.get(3), "original/upload/folderPathA"); + assertFile(files.get(4), "original/upload/folderPathA/test1.txt", file1.content); + assertDirectory(files.get(5), "original/upload/folderPathB"); + assertDirectory(files.get(6), "original/upload/folderPathB/filePath"); + assertFile(files.get(7), "original/upload/folderPathB/filePath/test2.txt", file2.content); + assertFile(files.get(8), "original/upload/folderPathB/filePath/test3.txt", file3.content); + } + @Test public void testCreateWithMultipleAttempts() throws Exception { @@ -686,7 +838,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest creation.setProperties(properties); creation.setUploadId(uploadId); - ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, file); + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, null, file); assertResponseOK(response); // first attempt @@ -708,7 +860,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest } catch (Exception e) { String fullStackTrace = ExceptionUtils.getFullStackTrace(e); - assertTrue(fullStackTrace, fullStackTrace.contains("The folder for the upload id " + uploadId + " could not be found")); + assertTrue(fullStackTrace, fullStackTrace.contains("No uploaded files found for upload id '" + uploadId + "'")); } } @@ -728,7 +880,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); creation.setUploadId(uploadId); - ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, file); + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, null, file); assertResponseOK(response); if (user.isDisabledProjectUser()) @@ -767,7 +919,7 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest } } - private ContentResponse uploadFiles(String sessionToken, String uploadId, String dataSetType, Boolean ignoreFilePath, + private ContentResponse uploadFiles(String sessionToken, String uploadId, String dataSetType, Boolean ignoreFilePath, String folderPath, FileToUpload... filesToUpload) throws InterruptedException, TimeoutException, ExecutionException { @@ -795,6 +947,10 @@ public class CreateUploadedDataSetsTest extends AbstractFileTest { request.param(StoreShareFileUploadServlet.IGNORE_FILE_PATH_PARAM, String.valueOf(ignoreFilePath)); } + if (folderPath != null) + { + request.param(StoreShareFileUploadServlet.FOLDER_PATH_PARAM, String.valueOf(folderPath)); + } if (dataSetType != null) { request.param(StoreShareFileUploadServlet.DATA_SET_TYPE_PARAM, dataSetType); diff --git a/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/test-create.js b/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/test-create.js index 8ed2989b2e1144976e6cc5d38f585b2db9edd368..95925de5c24e5ff84e9c0996c1ed8f5a6d0edeb6 100644 --- a/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/test-create.js +++ b/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/test-create.js @@ -756,15 +756,15 @@ define([ 'jquery', 'underscore', 'openbis', 'test/openbis-execute-operations', ' // Selenium tests does not allow to use FormData class which // would make constructing form data much easier - var formData = "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"file\"; filename=\"file1.txt\"\r\nContent-Type: text/plain\r\n\r\n\r\ncontent1\r\n" - + "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"file\"; filename=\"file2.txt\"\r\nContent-Type: text/plain\r\n\r\n\r\ncontent2\r\n" + var formData = "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"file\"; filename=\"filePath/file1.txt\"\r\nContent-Type: text/plain\r\n\r\n\r\ncontent1\r\n" + + "------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"file\"; filename=\"filePath/file2.txt\"\r\nContent-Type: text/plain\r\n\r\n\r\ncontent2\r\n" + "------WebKitFormBoundary7MA4YWxkTrZu0gW--"; var dataStoreFacade = facade.getDataStoreFacade("DSS1"); return dataStoreFacade.createDataSetUpload("UNKNOWN").then(function(upload) { return $.ajax({ - url : upload.url, + url : upload.getUrl("testFolder", false), type : "POST", processData : false, contentType : "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW", @@ -772,8 +772,8 @@ define([ 'jquery', 'underscore', 'openbis', 'test/openbis-execute-operations', ' }).then(function() { return c.createExperiment(facade).then(function(experimentPermId) { var creation = new c.UploadedDataSetCreation(); - creation.setUploadId(upload.id); - creation.setTypeId(new c.EntityTypePermId(upload.dataSetType)); + creation.setUploadId(upload.getId()); + creation.setTypeId(new c.EntityTypePermId(upload.getDataSetType())); creation.setExperimentId(experimentPermId); creation.setProperty("DESCRIPTION", "test description"); creation.setParentIds([ new c.DataSetPermId("20130424111751432-431") ]); @@ -794,12 +794,13 @@ define([ 'jquery', 'underscore', 'openbis', 'test/openbis-execute-operations', ' return dataStoreFacade.searchFiles(criteria, c.createDataSetFileFetchOptions()).then(function(result) { var files = result.getObjects(); - c.assertEqual(files.length, 5, "Number of files"); + c.assertEqual(files.length, 6, "Number of files"); c.assertEqual(files[0].path, "", "Path 0"); c.assertEqual(files[1].path, "original", "Path 1"); - c.assertEqual(files[2].path, "original/upload", "Path 2"); - c.assertEqual(files[3].path, "original/upload/file1.txt", "Path 3"); - c.assertEqual(files[4].path, "original/upload/file2.txt", "Path 4"); + c.assertEqual(files[2].path, "original/testFolder", "Path 2"); + c.assertEqual(files[3].path, "original/testFolder/filePath", "Path 3"); + c.assertEqual(files[4].path, "original/testFolder/filePath/file1.txt", "Path 4"); + c.assertEqual(files[5].path, "original/testFolder/filePath/file2.txt", "Path 5"); c.assertEqual(dataSet.getType().getCode(), "UNKNOWN", "Type code"); c.assertEqual(dataSet.getProperty("DESCRIPTION"), "test description", "'DESCRIPTION' property value"); diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/get/AbstractGetObjectsOperationExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/get/AbstractGetObjectsOperationExecutor.java index 00c85047085d96909289eb6217b711cf72b6852f..2ced14b81ed9eed9d5bde3b2f2afe72f2be1e367 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/get/AbstractGetObjectsOperationExecutor.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/get/AbstractGetObjectsOperationExecutor.java @@ -67,7 +67,7 @@ public abstract class AbstractGetObjectsOperationExecutor<OBJECT_ID extends IObj // sort and page the objects internal collections - ignore the top level changes // (we want to maintain all the results and keep them in order of the passed ids) - new SortAndPage().sortAndPage(idToObjectMap.values(), operation.getFetchOptions()); + new SortAndPage().sortAndPage(idToObjectMap.values(), null, operation.getFetchOptions()); return getOperationResult(idToObjectMap); } diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/search/AbstractSearchObjectsOperationExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/search/AbstractSearchObjectsOperationExecutor.java index 8abc1cce9a98236f9da569b064b0b75bf848c20a..fe8b92e6a27c171687e1eaa6c55c16b93d834f17 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/search/AbstractSearchObjectsOperationExecutor.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/search/AbstractSearchObjectsOperationExecutor.java @@ -77,7 +77,7 @@ public abstract class AbstractSearchObjectsOperationExecutor<OBJECT, OBJECT_PE, } Collection<OBJECT> allResults = searchAndTranslate(context, criteria, fetchOptions); - List<OBJECT> sortedAndPaged = sortAndPage(context, allResults, fetchOptions); + List<OBJECT> sortedAndPaged = sortAndPage(context, allResults, criteria, fetchOptions); SearchResult<OBJECT> searchResult = new SearchResult<OBJECT>(sortedAndPaged, allResults.size()); return getOperationResult(searchResult); @@ -119,7 +119,7 @@ public abstract class AbstractSearchObjectsOperationExecutor<OBJECT, OBJECT_PE, return objects; } - private List<OBJECT> sortAndPage(IOperationContext context, Collection<OBJECT> results, FETCH_OPTIONS fetchOptions) + private List<OBJECT> sortAndPage(IOperationContext context, Collection<OBJECT> results, CRITERIA criteria, FETCH_OPTIONS fetchOptions) { if (results == null || results.isEmpty()) { @@ -127,7 +127,7 @@ public abstract class AbstractSearchObjectsOperationExecutor<OBJECT, OBJECT_PE, } SortAndPage sap = new SortAndPage(); - Collection<OBJECT> objects = sap.sortAndPage(results, fetchOptions); + Collection<OBJECT> objects = sap.sortAndPage(results, criteria, fetchOptions); operationLog.info("Return " + objects.size() + " object(s) after sorting and paging."); diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/authorizationgroup/AuthorizationGroupComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/authorizationgroup/AuthorizationGroupComparatorFactory.java index ab031cbce349128caf9e51e454fd4de75981cebd..67a721fe9ff5e8424c949b31ed8f92d4e418f2e5 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/authorizationgroup/AuthorizationGroupComparatorFactory.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/authorizationgroup/AuthorizationGroupComparatorFactory.java @@ -17,9 +17,12 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.authorizationgroup; import java.util.Comparator; +import java.util.Map; import ch.ethz.sis.openbis.generic.asapi.v3.dto.authorizationgroup.AuthorizationGroup; import ch.ethz.sis.openbis.generic.asapi.v3.dto.authorizationgroup.fetchoptions.AuthorizationGroupSortOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria; import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.CodeComparator; import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.ComparatorFactory; @@ -38,7 +41,7 @@ public class AuthorizationGroupComparatorFactory extends ComparatorFactory } @Override - public Comparator<AuthorizationGroup> getComparator(String field) + public Comparator<AuthorizationGroup> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria) { if (AuthorizationGroupSortOptions.CODE.equals(field)) { diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/experiment/ExperimentComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/experiment/ExperimentComparatorFactory.java index f63b3cfb13dcac2a429e5982effde3d11db5fce9..5ef251a313681ed659e72476d5f15702a8119fcb 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/experiment/ExperimentComparatorFactory.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/experiment/ExperimentComparatorFactory.java @@ -17,7 +17,10 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.experiment; import java.util.Comparator; +import java.util.Map; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria; import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.Experiment; import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.fetchoptions.ExperimentSortOptions; import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.EntityWithPropertiesComparatorFactory; @@ -36,13 +39,13 @@ public class ExperimentComparatorFactory extends EntityWithPropertiesComparatorF } @Override - public Comparator<Experiment> getComparator(String field) + public Comparator<Experiment> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria) { if (ExperimentSortOptions.IDENTIFIER.equals(field)) { return new IdentifierComparator<Experiment>(); } - return super.getComparator(field); + return super.getComparator(field, parameters, criteria); } } diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/globalsearch/GlobalSearchObjectComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/globalsearch/GlobalSearchObjectComparatorFactory.java index ee861127a9479ed7ad9fe272f3b10267c223b56c..51d0e92d3478a1655c5569ae1789733fbd6c726d 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/globalsearch/GlobalSearchObjectComparatorFactory.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/globalsearch/GlobalSearchObjectComparatorFactory.java @@ -18,7 +18,10 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.globalsearch; import java.util.Collections; import java.util.Comparator; +import java.util.Map; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria; import ch.ethz.sis.openbis.generic.asapi.v3.dto.global.GlobalSearchObject; import ch.ethz.sis.openbis.generic.asapi.v3.dto.global.fetchoptions.GlobalSearchObjectSortOptions; import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.ComparatorFactory; @@ -37,7 +40,7 @@ public class GlobalSearchObjectComparatorFactory extends ComparatorFactory } @Override - public Comparator<GlobalSearchObject> getComparator(String field) + public Comparator<GlobalSearchObject> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria) { if (GlobalSearchObjectSortOptions.SCORE.equals(field)) { diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/plugin/PluginComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/plugin/PluginComparatorFactory.java index 808276fd3e228dd9da12e7ffc9a9e87a47440622..7e53021ebf677de23a8d0ad1d32b2cd75aaeceba 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/plugin/PluginComparatorFactory.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/plugin/PluginComparatorFactory.java @@ -17,7 +17,10 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.plugin; import java.util.Comparator; +import java.util.Map; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria; import ch.ethz.sis.openbis.generic.asapi.v3.dto.plugin.Plugin; import ch.ethz.sis.openbis.generic.asapi.v3.dto.plugin.fetchoptions.PluginSortOptions; import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.AbstractStringComparator; @@ -44,7 +47,7 @@ public class PluginComparatorFactory extends ComparatorFactory } @Override - public Comparator<Plugin> getComparator(String field) + public Comparator<Plugin> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria) { if (PluginSortOptions.NAME.equals(field)) { diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/project/ProjectComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/project/ProjectComparatorFactory.java index ed573d531597e6c4878586dd40d82b4b30dbca57..b469076fd30d10b3198d8a428f18010eda805888 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/project/ProjectComparatorFactory.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/project/ProjectComparatorFactory.java @@ -17,7 +17,10 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.project; import java.util.Comparator; +import java.util.Map; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria; import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.Project; import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.fetchoptions.ProjectSortOptions; import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.EntityComparatorFactory; @@ -36,13 +39,13 @@ public class ProjectComparatorFactory extends EntityComparatorFactory<Project> } @Override - public Comparator<Project> getComparator(String field) + public Comparator<Project> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria) { if (ProjectSortOptions.IDENTIFIER.equals(field)) { return new IdentifierComparator<Project>(); } - return super.getComparator(field); + return super.getComparator(field, parameters, criteria); } } diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/property/PropertyAssignmentComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/property/PropertyAssignmentComparatorFactory.java index 251b1e47e6ce9f6e24d2712d3194a33341a6c80f..93b07657b74121a7b1661b68ac6a50b1a01f279f 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/property/PropertyAssignmentComparatorFactory.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/property/PropertyAssignmentComparatorFactory.java @@ -20,6 +20,8 @@ import java.util.Comparator; import java.util.HashMap; import java.util.Map; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria; import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.PropertyAssignment; import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.PropertyType; import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.fetchoptions.PropertyAssignmentSortOptions; @@ -69,7 +71,7 @@ public class PropertyAssignmentComparatorFactory extends ComparatorFactory } @Override - public Comparator<?> getComparator(String field) + public Comparator<?> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria) { return COMPARATORS_BY_FIELD.get(field); } @@ -77,7 +79,7 @@ public class PropertyAssignmentComparatorFactory extends ComparatorFactory @Override public Comparator<?> getDefaultComparator() { - return getComparator(PropertyAssignmentSortOptions.ORDINAL); + return getComparator(PropertyAssignmentSortOptions.ORDINAL, null, null); } private abstract static class AbstractPropertyAssignmentComparator extends AbstractStringComparator<PropertyAssignment> diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/property/PropertyTypeComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/property/PropertyTypeComparatorFactory.java index ef68061cd5891c649d89942ebe5f7949aa52b019..f8c044fa6956b20ee6e015144637a0a3b52b10aa 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/property/PropertyTypeComparatorFactory.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/property/PropertyTypeComparatorFactory.java @@ -17,7 +17,10 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.property; import java.util.Comparator; +import java.util.Map; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria; import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.PropertyType; import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.fetchoptions.PropertyTypeSortOptions; import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.fetchoptions.VocabularySortOptions; @@ -38,7 +41,7 @@ public class PropertyTypeComparatorFactory extends ComparatorFactory } @Override - public Comparator<PropertyType> getComparator(String field) + public Comparator<PropertyType> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria) { if (VocabularySortOptions.CODE.equals(field)) { diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sample/SampleComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sample/SampleComparatorFactory.java index 4218ac4f930ce5bdd693a38c79dde335ef794b4c..8a1c3ddb2d2c19e2d8a0c32568fc2a557438b771 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sample/SampleComparatorFactory.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sample/SampleComparatorFactory.java @@ -17,7 +17,10 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sample; import java.util.Comparator; +import java.util.Map; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria; import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.Sample; import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.fetchoptions.SampleSortOptions; import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.EntityWithPropertiesComparatorFactory; @@ -36,13 +39,13 @@ public class SampleComparatorFactory extends EntityWithPropertiesComparatorFacto } @Override - public Comparator<Sample> getComparator(String field) + public Comparator<Sample> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria) { if (SampleSortOptions.IDENTIFIER.equals(field)) { return new IdentifierComparator<Sample>(); } - return super.getComparator(field); + return super.getComparator(field, parameters, criteria); } } diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/ComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/ComparatorFactory.java index cfa927e6528b38826028c43e2bf1917312200d88..16e7ff12ed63c71d547e4e63c20328f185c7457d 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/ComparatorFactory.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/ComparatorFactory.java @@ -19,7 +19,10 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort; import java.util.Comparator; import java.util.LinkedList; import java.util.List; +import java.util.Map; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria; import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.authorizationgroup.AuthorizationGroupComparatorFactory; import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.dataset.DataSetComparatorFactory; import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.experiment.ExperimentComparatorFactory; @@ -64,7 +67,7 @@ public abstract class ComparatorFactory public abstract boolean accepts(Class<?> sortOptionsClass); - public abstract Comparator getComparator(String field); + public abstract Comparator getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria); public abstract Comparator getDefaultComparator(); diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/EntityComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/EntityComparatorFactory.java index 88deff478fa9755fa49d8bd693a0cde6784363c9..213a197831c0dde96a9e2651166fc5221f49f3d5 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/EntityComparatorFactory.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/EntityComparatorFactory.java @@ -17,12 +17,15 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort; import java.util.Comparator; +import java.util.Map; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.EntitySortOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.ICodeHolder; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IModificationDateHolder; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IPermIdHolder; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IRegistrationDateHolder; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria; /** * @author pkupczyk @@ -38,7 +41,7 @@ public class EntityComparatorFactory<OBJECT extends ICodeHolder & IPermIdHolder } @Override - public Comparator<OBJECT> getComparator(String field) + public Comparator<OBJECT> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria) { if (EntitySortOptions.CODE.equals(field)) { diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/EntityWithPropertiesComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/EntityWithPropertiesComparatorFactory.java index 0ba498077cf6387dc6e502ca08d367b5e4d9ae22..e57c58e1198c839afe649fc9fcd1bec7028da1ad 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/EntityWithPropertiesComparatorFactory.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/EntityWithPropertiesComparatorFactory.java @@ -17,14 +17,17 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort; import java.util.Comparator; +import java.util.Map; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.EntityWithPropertiesSortOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.ICodeHolder; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IEntityTypeHolder; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IModificationDateHolder; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IPermIdHolder; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IPropertiesHolder; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IRegistrationDateHolder; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria; /** * @author pkupczyk @@ -40,9 +43,12 @@ public class EntityWithPropertiesComparatorFactory<OBJECT extends ICodeHolder & } @Override - public Comparator<OBJECT> getComparator(String field) + public Comparator<OBJECT> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria) { - if (field.equals(EntityWithPropertiesSortOptions.TYPE)) + if (field.equals(EntityWithPropertiesSortOptions.FETCHED_FIELDS_SCORE)) + { + return new FetchedFieldsScoreComparator<OBJECT>(parameters, criteria); + } if (field.equals(EntityWithPropertiesSortOptions.TYPE)) { return new TypeComparator<OBJECT>(); } else if (field.startsWith(EntityWithPropertiesSortOptions.PROPERTY)) @@ -50,7 +56,7 @@ public class EntityWithPropertiesComparatorFactory<OBJECT extends ICodeHolder & return new PropertyComparator<OBJECT>(field.substring(EntityWithPropertiesSortOptions.PROPERTY.length())); } else { - return super.getComparator(field); + return super.getComparator(field, parameters, criteria); } } diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/FetchedFieldsScoreComparator.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/FetchedFieldsScoreComparator.java new file mode 100644 index 0000000000000000000000000000000000000000..c02894de135373f3eb7d0ad30aab2b035979a69d --- /dev/null +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/FetchedFieldsScoreComparator.java @@ -0,0 +1,381 @@ +/* + * Copyright 2016 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IEntityTypeHolder; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IPermIdHolder; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IPropertiesHolder; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.AbstractEntitySearchCriteria; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.CodeSearchCriteria; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.StringPropertySearchCriteria; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSet; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.search.DataSetTypeSearchCriteria; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.search.AbstractEntityTypeSearchCriteria; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.Experiment; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.search.ExperimentTypeSearchCriteria; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.Material; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.search.MaterialTypeSearchCriteria; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.Sample; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.search.SampleTypeSearchCriteria; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.ICodeHolder; + + +/** + * @author juanf + */ +public class FetchedFieldsScoreComparator<OBJECT extends IEntityTypeHolder & IPropertiesHolder & ICodeHolder & IPermIdHolder> extends AbstractComparator<OBJECT, Integer> +{ + + private Map<SortParameter, String> parameters; + private AbstractEntitySearchCriteria criteria; + private List<Pattern> partialMatchTerms = new ArrayList<Pattern>(); + private List<String> exactMatchTerms = new ArrayList<String>(); + private List<Boost> boosts = new ArrayList<Boost>(); + private Map<OBJECT, Integer> scoreCache = new HashMap<>(); + + private Integer fullCodeBoost = 0; + private Integer partialCodeBoost = 0; + private Integer fullPropertyBoost = 0; + private Integer fullTypeBoost = 0; + private Integer partialPropertyBoost = 0; + + public FetchedFieldsScoreComparator(Map<SortParameter, String> parameters, ISearchCriteria criteria) + { + if (criteria == null || (criteria instanceof AbstractEntitySearchCriteria) == false) + { + throw new IllegalArgumentException("Missing criteria"); + } + + if (parameters == null) + { + throw new IllegalArgumentException("Missing score parameters"); + } else + { + if(parameters.containsKey(SortParameter.FULL_CODE_BOOST)) + { + fullCodeBoost = Integer.parseInt(parameters.get(SortParameter.FULL_CODE_BOOST)); + } + if(parameters.containsKey(SortParameter.PARTIAL_CODE_BOOST)) + { + partialCodeBoost = Integer.parseInt(parameters.get(SortParameter.PARTIAL_CODE_BOOST)); + } + if(parameters.containsKey(SortParameter.FULL_PROPERTY_BOOST)) + { + fullPropertyBoost = Integer.parseInt(parameters.get(SortParameter.FULL_PROPERTY_BOOST)); + } + if(parameters.containsKey(SortParameter.FULL_TYPE_BOOST)) + { + fullTypeBoost = Integer.parseInt(parameters.get(SortParameter.FULL_TYPE_BOOST)); + } + if(parameters.containsKey(SortParameter.PARTIAL_PROPERTY_BOOST)) + { + partialPropertyBoost = Integer.parseInt(parameters.get(SortParameter.PARTIAL_PROPERTY_BOOST)); + } + } + + this.parameters = parameters; + this.criteria = (AbstractEntitySearchCriteria) criteria; + + // Shared + this.partialMatchTerms = new ArrayList<Pattern>(); + this.exactMatchTerms = new ArrayList<String>(); + this.boosts = new ArrayList<Boost>(); + + for(ISearchCriteria subCriteria:this.criteria.getCriteria()) + { + ISearchCriteriaParser<ISearchCriteria> parser = criteriaParsers.get(subCriteria.getClass()); + + if(parser != null) + { + String value = parser.getValue(subCriteria); + + // Full Index + partialMatchTerms.add(getPartialMatchTerm(value)); + exactMatchTerms.add(getExactMatchTerm(value)); + boosts.add(parser.getBoost(subCriteria, 10)); + + // Split Index + String[] splitIndexes = value.replace("*", " ").replace("?", " ").replaceAll("\\s+", " ").trim().split(" "); + + for (String splitIndex : splitIndexes) + { + partialMatchTerms.add(getPartialMatchTerm(splitIndex)); + exactMatchTerms.add(getExactMatchTerm(splitIndex)); + boosts.add(parser.getBoost(subCriteria, 1)); + } + } + + } + + } + + @Override + public int compare(OBJECT o1, OBJECT o2) + { + return -1 * super.compare(o1, o2); // Higher scores first + } + + @Override + protected Integer getValue(OBJECT o) + { + Integer score = scoreCache.get(o); + if(score == null) { + score = calculateScore(o); + scoreCache.put(o, score); + } + return score; + } + + // + // V3 Helper Methods + // + + private static Map<Class, ISearchCriteriaParser> criteriaParsers = new HashMap<>(3); + + static { + criteriaParsers.put(CodeSearchCriteria.class, new CodeCriteriaParser()); + criteriaParsers.put(StringPropertySearchCriteria.class, new StringPropertySearchCriteriaParser()); + criteriaParsers.put(SampleTypeSearchCriteria.class, new AbstractEntityTypeSearchCriteriaParser()); + criteriaParsers.put(ExperimentTypeSearchCriteria.class, new AbstractEntityTypeSearchCriteriaParser()); + criteriaParsers.put(DataSetTypeSearchCriteria.class, new AbstractEntityTypeSearchCriteriaParser()); + criteriaParsers.put(MaterialTypeSearchCriteria.class, new AbstractEntityTypeSearchCriteriaParser()); + } + + private static interface ISearchCriteriaParser<ISearchCriteria> { + public String getValue(ISearchCriteria criteria); + public Boost getBoost(ISearchCriteria criteria, int boost); + } + + private static class CodeCriteriaParser implements ISearchCriteriaParser<CodeSearchCriteria> { + @Override + public String getValue(CodeSearchCriteria criteria) { + return criteria.getFieldValue().getValue(); + } + + @Override + public Boost getBoost(CodeSearchCriteria criteria, int boost) { + return new Boost(boost, 0, 0, 0, null); + } + } + + private static class StringPropertySearchCriteriaParser implements ISearchCriteriaParser<StringPropertySearchCriteria> { + @Override + public String getValue(StringPropertySearchCriteria criteria) { + return criteria.getFieldValue().getValue(); + } + + @Override + public Boost getBoost(StringPropertySearchCriteria criteria, int boost) { + return new Boost(0, 0, 0, boost, criteria.getFieldName()); + } + } + + private static class AbstractEntityTypeSearchCriteriaParser implements ISearchCriteriaParser<AbstractEntityTypeSearchCriteria> { + @Override + public String getValue(AbstractEntityTypeSearchCriteria criteria) { + for(ISearchCriteria subCriteria:criteria.getCriteria()) { + if(subCriteria instanceof CodeSearchCriteria) { + return criteriaParsers.get(subCriteria.getClass()).getValue(subCriteria); + } + } + return null; + } + + @Override + public Boost getBoost(AbstractEntityTypeSearchCriteria criteria, int boost) { + return new Boost(0, boost, 0, 0, null); + } + } + + // + // Scoring algorithm + // + + private boolean hasType(OBJECT o ) { + if(o instanceof Sample) { + return ((Sample)o).getFetchOptions().hasType(); + } else if(o instanceof Experiment) { + return ((Experiment)o).getFetchOptions().hasType(); + } if(o instanceof DataSet) { + return ((DataSet)o).getFetchOptions().hasType(); + } if(o instanceof Material) { + return ((Material)o).getFetchOptions().hasType(); + } else { + return false; + } + } + + private boolean hasProperties(OBJECT o ) { + if(o instanceof Sample) { + return ((Sample)o).getFetchOptions().hasProperties(); + } else if(o instanceof Experiment) { + return ((Experiment)o).getFetchOptions().hasProperties(); + } if(o instanceof DataSet) { + return ((DataSet)o).getFetchOptions().hasProperties(); + } if(o instanceof Material) { + return ((Material)o).getFetchOptions().hasProperties(); + } else { + return false; + } +} + + private Integer calculateScore(OBJECT o ) { + int score = 0; + String code = o.getCode(); + String typeCode = (hasType(o))?o.getType().getCode():null; + Map<String, String> properties = (hasProperties(o))?o.getProperties():null; + + for (int i = 0; i < exactMatchTerms.size(); i++) + { + Pattern partialTerm = partialMatchTerms.get(i); + String exactTerm = exactMatchTerms.get(i); + Boost boost = boosts.get(i); + + // 1. Code + if(code != null) { + if (isPartialMatch(code, partialTerm)) + { // If code matches partially + score += partialCodeBoost * boost.getCodeBoost(); + if (isExactMatch(code, exactTerm)) + { // If code matches exactly + score += fullCodeBoost * boost.getCodeBoost(); + } + } + } + + // 2. Entity type code + if(typeCode != null) + { + if (isExactMatch(typeCode, exactTerm)) + { // If type matches exactly + score += fullTypeBoost * boost.getTypeCodeBoost(); + } + } + + + // 3. Properties + if(properties != null) { + if (properties != null && properties.keySet() != null) + { + for (String propertykey : properties.keySet()) + { + String propertyValue = properties.get(propertykey); + if (isPartialMatch(propertyValue, partialTerm)) + { // If property matches partially + score += partialPropertyBoost * boost.getPropertyBoost(propertykey); + if (isExactMatch(propertyValue, exactTerm)) + { // If property matches exactly + score += fullPropertyBoost * boost.getPropertyBoost(propertykey); + } + } + } + } + } + } + + return score; + } + + // + // Helper Methods + // + + private static class Boost + { + private int codeBoost; + + private int typeCodeBoost; + + private int propertyBoost; + + private int propertyDefaultBoost; + + private String propertyName; + + public Boost(int codeBoost, int typeCodeBoost, int propertyDefaultBoost, int propertyBoost, String propertyName) + { + super(); + this.codeBoost = codeBoost; + this.typeCodeBoost = typeCodeBoost; + this.propertyDefaultBoost = propertyDefaultBoost; + this.propertyBoost = propertyBoost; + this.propertyName = propertyName; + } + + public int getCodeBoost() + { + return codeBoost; + } + + public int getTypeCodeBoost() + { + return typeCodeBoost; + } + + public int getPropertyBoost(String propertyNameToBoost) + { + if (this.propertyName != null && this.propertyName.equals(propertyNameToBoost)) + { + return propertyBoost; + } else + { + return propertyDefaultBoost; + } + } + + } + + private Pattern getPartialMatchTerm(String term) + { + return Pattern.compile(("*" + term + "*").replace("*", ".*").replace("?", ".?"), Pattern.CASE_INSENSITIVE); + } + + private String getExactMatchTerm(String term) + { + return term.replace("*", "").replace("?", ""); + } + + private boolean isExactMatch(String value, String term) + { + if (value != null && term != null) + { + return value.equalsIgnoreCase(term); + } else + { + return false; + } + } + + private boolean isPartialMatch(String value, Pattern pattern) + { + if (value != null && pattern != null) + { + return pattern.matcher(value).matches(); + } else + { + return false; + } + } +} diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/SortAndPage.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/SortAndPage.java index 63d9eba47c8a832aaf58eacbccf6945ac0090d39..80afc702f5a927b4b90e14365330e6f6e79ed41f 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/SortAndPage.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/SortAndPage.java @@ -37,6 +37,7 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.Sorting; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.view.AbstractCollectionView; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.view.ListView; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.view.SetView; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria; /** * @author pkupczyk @@ -49,7 +50,7 @@ public class SortAndPage private MethodsCache methodsCache = new MethodsCache(); - public <T, C extends Collection<T>> C sortAndPage(C objects, FetchOptions fo) + public <T, C extends Collection<T>> C sortAndPage(C objects, ISearchCriteria c, FetchOptions fo) { C newObjects = objects; @@ -58,21 +59,21 @@ public class SortAndPage newObjects = (C) ((AbstractCollectionView) objects).getOriginalCollection(); } - newObjects = (C) sort(newObjects, fo); + newObjects = (C) sort(newObjects, c, fo); newObjects = (C) page(newObjects, fo); - nest(newObjects, fo); + nest(newObjects, c, fo); return newObjects; } - - private Collection sort(Collection objects, FetchOptions fo) + + private Collection sort(Collection objects, ISearchCriteria c, FetchOptions fo) { if (objects == null || objects.isEmpty()) { return objects; } - Comparator comparator = getComparator(fo); + Comparator comparator = getComparator(c, fo); if (comparator != null) { @@ -135,7 +136,7 @@ public class SortAndPage } } - private void nest(Collection objects, FetchOptions fo) + private void nest(Collection objects, ISearchCriteria c, FetchOptions fo) { if (objects == null || objects.isEmpty()) { @@ -177,14 +178,14 @@ public class SortAndPage { if (value instanceof Collection) { - Collection newValue = sortAndPage((Collection) value, subFo); + Collection newValue = sortAndPage((Collection) value, c, subFo); setMethod.invoke(object, newValue); } else if (value instanceof Map) { - sortAndPage(((Map) value).values(), subFo); + sortAndPage(((Map) value).values(), c, subFo); } else { - Collection newValue = sortAndPage(Collections.singleton(value), subFo); + Collection newValue = sortAndPage(Collections.singleton(value), c, subFo); if (setMethod != null) { setMethod.invoke(object, newValue.iterator().next()); @@ -200,7 +201,7 @@ public class SortAndPage } } - protected Comparator getComparator(FetchOptions fetchOptions) + protected Comparator getComparator(ISearchCriteria criteria, FetchOptions fetchOptions) { if (fetchOptions == null) { @@ -240,7 +241,7 @@ public class SortAndPage throw new IllegalArgumentException("Comparator factory for sort by " + sortByClass + " not found"); } - Comparator aComparator = comparatorFactory.getComparator(sorting.getField()); + Comparator aComparator = comparatorFactory.getComparator(sorting.getField(), sorting.getParameters(), criteria); if (aComparator == null) { diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/tag/TagComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/tag/TagComparatorFactory.java index 0ae8a397c2f22dac8df5f4c86dc90d9b0e2e8e65..598231a9f07c14cc2f6cae2f2db2af44bfd92b25 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/tag/TagComparatorFactory.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/tag/TagComparatorFactory.java @@ -17,7 +17,10 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.tag; import java.util.Comparator; +import java.util.Map; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria; import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.Tag; import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.fetchoptions.TagSortOptions; import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.CodeComparator; @@ -37,7 +40,7 @@ public class TagComparatorFactory extends ComparatorFactory } @Override - public Comparator<Tag> getComparator(String field) + public Comparator<Tag> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria) { if (TagSortOptions.CODE.equals(field)) { diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/vocabulary/VocabularyComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/vocabulary/VocabularyComparatorFactory.java index a6740821d46a54076e9774439a2cbebe95b88f10..dab46dbd380183d7a2f5ae4c48c2074d0374499c 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/vocabulary/VocabularyComparatorFactory.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/vocabulary/VocabularyComparatorFactory.java @@ -17,7 +17,10 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.vocabulary; import java.util.Comparator; +import java.util.Map; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria; import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.Vocabulary; import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.fetchoptions.VocabularySortOptions; import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.CodeComparator; @@ -37,7 +40,7 @@ public class VocabularyComparatorFactory extends ComparatorFactory } @Override - public Comparator<Vocabulary> getComparator(String field) + public Comparator<Vocabulary> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria) { if (VocabularySortOptions.CODE.equals(field)) { diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/vocabulary/VocabularyTermComparatorFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/vocabulary/VocabularyTermComparatorFactory.java index 7d4fb30ccc8d5758753674bdaea8ad3b3c2d40c6..35bdb6d11d92c8c323e1ed42e861e2f7620e1780 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/vocabulary/VocabularyTermComparatorFactory.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/vocabulary/VocabularyTermComparatorFactory.java @@ -17,7 +17,10 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.helper.vocabulary; import java.util.Comparator; +import java.util.Map; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions.SortParameter; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria; import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.VocabularyTerm; import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.fetchoptions.VocabularyTermSortOptions; import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.CodeComparator; @@ -36,7 +39,7 @@ public class VocabularyTermComparatorFactory extends ComparatorFactory } @Override - public Comparator<VocabularyTerm> getComparator(String field) + public Comparator<VocabularyTerm> getComparator(String field, Map<SortParameter, String> parameters, ISearchCriteria criteria) { if (VocabularyTermSortOptions.CODE.equals(field)) { diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/sample/SampleTypeTranslator.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/sample/SampleTypeTranslator.java index 5763f56f49b6e009bdd368c5c2625f408b8268a5..03e40acf46d9f60659637643f7d2eefd59712ab5 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/sample/SampleTypeTranslator.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/sample/SampleTypeTranslator.java @@ -105,7 +105,7 @@ public class SampleTypeTranslator extends AbstractCachingTranslator<Long, Sample { Collection<PropertyAssignment> assignments = relations.get(ISamplePropertyAssignmentTranslator.class, typeId); List<PropertyAssignment> propertyAssignments = new ArrayList<>(assignments); - result.setPropertyAssignments(new SortAndPage().sortAndPage(propertyAssignments, fetchOptions.withPropertyAssignments())); + result.setPropertyAssignments(new SortAndPage().sortAndPage(propertyAssignments, null, fetchOptions.withPropertyAssignments())); } if (fetchOptions.hasSemanticAnnotations()) diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/common/fetchoptions/EntityWithPropertiesSortOptions.js b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/common/fetchoptions/EntityWithPropertiesSortOptions.js index a9b6cce007cc153b3f78df8ad64ab9e32e818a1c..e289ffceb3c4592a22071ab72daec7200c215fd9 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/common/fetchoptions/EntityWithPropertiesSortOptions.js +++ b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/common/fetchoptions/EntityWithPropertiesSortOptions.js @@ -1,17 +1,31 @@ -define([ "require", "stjs", "as/dto/common/fetchoptions/EntitySortOptions" ], function(require, stjs, EntitySortOptions) { +define([ "require", "stjs", "as/dto/common/fetchoptions/EntitySortOptions", "as/dto/common/fetchoptions/SortParameter" ], function(require, stjs, EntitySortOptions, SortParameter) { var EntityWithPropertiesSortOptions = function() { EntitySortOptions.call(this); }; var fields = { + FETCHED_FIELDS_SCORE : "FETCHED_FIELDS_SCORE", TYPE : "TYPE", PROPERTY : "PROPERTY" }; - + stjs.extend(EntityWithPropertiesSortOptions, EntitySortOptions, [ EntitySortOptions ], function(constructor, prototype) { prototype['@type'] = 'as.dto.common.fetchoptions.EntityWithPropertiesSortOptions'; constructor.serialVersionUID = 1; + prototype.fetchedFieldsScore = function() { + var parameters = {}; + parameters[SortParameter.FULL_CODE_BOOST] = "1000000"; + parameters[SortParameter.PARTIAL_CODE_BOOST] = "100000"; + parameters[SortParameter.FULL_PROPERTY_BOOST] = "10000"; + parameters[SortParameter.FULL_TYPE_BOOST] = "1000"; + parameters[SortParameter.PARTIAL_PROPERTY_BOOST] = "100"; + + return this.getOrCreateSortingWithParameters(fields.FETCHED_FIELDS_SCORE, parameters); + }; + prototype.getFetchedFieldsScore = function() { + return this.getSorting(fields.FETCHED_FIELDS_SCORE); + }; prototype.type = function() { return this.getOrCreateSorting(fields.TYPE); }; diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/common/fetchoptions/SortOptions.js b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/common/fetchoptions/SortOptions.js index d9dc882cef503ae2f1a601a223fc8bca35e6a283..588341e28fc49f4418a1f61716ad1a390e738c3e 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/common/fetchoptions/SortOptions.js +++ b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/common/fetchoptions/SortOptions.js @@ -6,14 +6,20 @@ define([ "require", "stjs", "as/dto/common/fetchoptions/SortOrder", "as/dto/comm stjs.extend(SortOptions, null, [], function(constructor, prototype) { prototype['@type'] = 'as.dto.common.fetchoptions.SortOptions'; constructor.serialVersionUID = 1; + prototype.getOrCreateSorting = function(field) { + return this.getOrCreateSortingWithParameters(field, null); + }; + + prototype.getOrCreateSortingWithParameters = function(field, parameters) { var order = this.getSorting(field); if (order == null) { order = new SortOrder(); - this.sortings.push(new Sorting(field, order)); + this.sortings.push(new Sorting(field, order, parameters)); } return order; }; + prototype.getSorting = function(field) { var order = null; this.sortings.forEach(function(sorting) { diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/common/fetchoptions/SortParameter.js b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/common/fetchoptions/SortParameter.js new file mode 100644 index 0000000000000000000000000000000000000000..fd223f6c74c9e0cfb6a0ee77d4f5c5543d188b2d --- /dev/null +++ b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/common/fetchoptions/SortParameter.js @@ -0,0 +1,12 @@ +/** + * @author juanf + */ + +define([ "stjs", "as/dto/common/Enum" ], function(stjs, Enum) { + var SortParameter = function() { + Enum.call(this, [ "FULL_CODE_BOOST", "PARTIAL_CODE_BOOST", "FULL_PROPERTY_BOOST", "FULL_TYPE_BOOST", "PARTIAL_PROPERTY_BOOST" ]); + }; + stjs.extend(SortParameter, Enum, [ Enum ], function(constructor, prototype) { + }, {}); + return new SortParameter(); +}) diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/common/fetchoptions/Sorting.js b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/common/fetchoptions/Sorting.js index 534db78593281c3681b2b8fbc8b1c64132f661c9..2cd97cffec8146c3b863aca403ccd27cd45cb715 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/common/fetchoptions/Sorting.js +++ b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/common/fetchoptions/Sorting.js @@ -1,7 +1,8 @@ define([ "require", "stjs" ], function(require, stjs) { - var Sorting = function(field, order) { + var Sorting = function(field, order, parameters) { this.field = field; this.order = order; + this.parameters = parameters; }; stjs.extend(Sorting, null, [], function(constructor, prototype) { @@ -13,6 +14,9 @@ define([ "require", "stjs" ], function(require, stjs) { prototype.getOrder = function() { return this.order; }; + prototype.getParameters = function() { + return this.parameters; + }; }, {}); return Sorting; }) \ No newline at end of file diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/openbis.js b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/openbis.js index 51cf65ac0aeace286b8af04b449f8c74078d4d2f..7147310bf3d1d24c26de27c3b058b9a854c7ee91 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/openbis.js +++ b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/openbis.js @@ -228,22 +228,35 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria if (dataStores.length > 1) { dfd.reject("Please specify exactly one data store"); } else { + var dataStore = dataStores[0]; var now = new Date(); var id = "upload-" + now.getFullYear() + pad(now.getMonth() + 1, 2) + pad(now.getDate(), 2) + pad(now.getHours(), 2) + pad(now.getMinutes(), 2) + pad(now.getSeconds(), 2) + "-" + pad(Math.round(Math.random() * 100000), 5); - var params = { - "sessionID" : facade._private.sessionToken, - "uploadID" : id, - "dataSetType" : dataSetType - }; - - var url = dataStores[0].downloadUrl + "/datastore_server/store_share_file_upload?" + jquery.param(params); - dfd.resolve({ - "id" : id, - "url" : url, - "dataSetType" : dataSetType + "getId" : function() { + return id; + }, + "getUrl" : function(folderPath, ignoreFilePath) { + var params = { + "sessionID" : facade._private.sessionToken, + "uploadID" : id, + "dataSetType" : dataSetType + }; + + if (folderPath != null) { + params["folderPath"] = folderPath; + } + + if (ignoreFilePath != null) { + params["ignoreFilePath"] = ignoreFilePath; + } + + return dataStore.downloadUrl + "/datastore_server/store_share_file_upload?" + jquery.param(params); + }, + "getDataSetType" : function() { + return dataSetType; + } }); } @@ -569,7 +582,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.createTags = function(creations) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -765,7 +778,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.updatePropertyTypes = function(updates) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -798,7 +811,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.updateVocabularyTerms = function(updates) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -809,7 +822,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.updateTags = function(updates) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -999,7 +1012,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.getVocabularyTerms = function(ids, fetchOptions) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -1511,7 +1524,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.deletePropertyTypes = function(ids, deletionOptions) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -1533,7 +1546,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.deleteVocabularyTerms = function(ids, deletionOptions) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -1544,7 +1557,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.deleteEntityTypes = function(ids, deletionOptions) { var thisFacade = this; return thisFacade._private.ajaxRequest({ diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/SortAndPageTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/SortAndPageTest.java index 45fc0ff733c529039b33f129baef5a799cad2dd0..211a2290c29b8e48ecb2060aa7142a0a18817b65 100644 --- a/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/SortAndPageTest.java +++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/sort/SortAndPageTest.java @@ -16,17 +16,168 @@ import org.testng.annotations.Test; import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.Material; import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.fetchoptions.MaterialFetchOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.search.MaterialSearchCriteria; import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.Person; import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.Project; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.Sample; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.SampleType; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.fetchoptions.SampleFetchOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.search.SampleSearchCriteria; import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.Space; import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.Tag; import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sort.SortAndPage; public class SortAndPageTest { + @Test + public void testFetchedFieldsScore_CodeScore() + { + SampleType sampleTypeA = new SampleType(); + sampleTypeA.setCode("DUMMY_CODE_A"); + + SampleType sampleTypeB = new SampleType(); + sampleTypeB.setCode("DUMMY_CODE_B"); + + String propertyCode = "DUMMY_PROPERTY"; + + SampleSearchCriteria c = new SampleSearchCriteria(); + c.withOrOperator(); + c.withCode().thatEquals("S2"); + + SampleFetchOptions fo = new SampleFetchOptions(); + fo.withType(); + fo.withProperties(); + fo.sortBy().fetchedFieldsScore(); + + Sample sample1 = new Sample(); + sample1.setType(sampleTypeA); + sample1.setCode("S1"); + sample1.setProperty(propertyCode, "DUMMY_S1"); + sample1.setFetchOptions(fo); + + Sample sample2 = new Sample(); + sample2.setType(sampleTypeB); + sample2.setCode("S2"); + sample2.setProperty(propertyCode, "DUMMY_S2"); + sample2.setFetchOptions(fo); + + Sample sample3 = new Sample(); + sample3.setType(sampleTypeA); + sample3.setCode("S3"); + sample3.setProperty(propertyCode, "DUMMY_S3"); + sample3.setFetchOptions(fo); + + List<Sample> samples = new ArrayList<Sample>(); + samples.add(sample1); + samples.add(sample2); + samples.add(sample3); + + Collection<Sample> results = new SortAndPage().sortAndPage(samples, c, fo); + + assertEquals(results, list(sample2, sample1, sample3)); + } + + @Test + public void testFetchedFieldsScore_PropertyScore() + { + SampleType sampleTypeA = new SampleType(); + sampleTypeA.setCode("DUMMY_CODE_A"); + + SampleType sampleTypeB = new SampleType(); + sampleTypeB.setCode("DUMMY_CODE_B"); + + String propertyCode = "DUMMY_PROPERTY"; + + SampleSearchCriteria c = new SampleSearchCriteria(); + c.withOrOperator(); + c.withProperty(propertyCode).thatEquals("DUMMY_S3"); + + SampleFetchOptions fo = new SampleFetchOptions(); + fo.withType(); + fo.withProperties(); + fo.sortBy().fetchedFieldsScore(); + + Sample sample1 = new Sample(); + sample1.setType(sampleTypeA); + sample1.setCode("S1"); + sample1.setProperty(propertyCode, "DUMMY_S1"); + sample1.setFetchOptions(fo); + + Sample sample2 = new Sample(); + sample2.setType(sampleTypeB); + sample2.setCode("S2"); + sample2.setProperty(propertyCode, "DUMMY_S2"); + sample2.setFetchOptions(fo); + + Sample sample3 = new Sample(); + sample3.setType(sampleTypeA); + sample3.setCode("S3"); + sample3.setProperty(propertyCode, "DUMMY_S3"); + sample3.setFetchOptions(fo); + + List<Sample> samples = new ArrayList<Sample>(); + samples.add(sample1); + samples.add(sample2); + samples.add(sample3); + + Collection<Sample> results = new SortAndPage().sortAndPage(samples, c, fo); + + assertEquals(results, list(sample3, sample1, sample2)); + } + + @Test + public void testFetchedFieldsScore_TypeScore() + { + SampleType sampleTypeA = new SampleType(); + sampleTypeA.setCode("DUMMY_CODE_A"); + + SampleType sampleTypeB = new SampleType(); + sampleTypeB.setCode("DUMMY_CODE_B"); + + String propertyCode = "DUMMY_PROPERTY"; + + SampleSearchCriteria c = new SampleSearchCriteria(); + c.withOrOperator(); + c.withType().withCode().thatEquals(sampleTypeA.getCode()); + + SampleFetchOptions fo = new SampleFetchOptions(); + fo.withType(); + fo.withProperties(); + fo.sortBy().fetchedFieldsScore(); + + Sample sample1 = new Sample(); + sample1.setType(sampleTypeA); + sample1.setCode("S1"); + sample1.setProperty(propertyCode, "DUMMY_S1"); + sample1.setFetchOptions(fo); + + Sample sample2 = new Sample(); + sample2.setType(sampleTypeB); + sample2.setCode("S2"); + sample2.setProperty(propertyCode, "DUMMY_S2"); + sample2.setFetchOptions(fo); + + Sample sample3 = new Sample(); + sample3.setType(sampleTypeA); + sample3.setCode("S3"); + sample3.setProperty(propertyCode, "DUMMY_S3"); + sample3.setFetchOptions(fo); + + List<Sample> samples = new ArrayList<Sample>(); + samples.add(sample1); + samples.add(sample2); + samples.add(sample3); + + Collection<Sample> results = new SortAndPage().sortAndPage(samples, c, fo); + + assertEquals(results, list(sample1, sample3, sample2)); + } + @Test public void testTopLevel() { + MaterialSearchCriteria c = new MaterialSearchCriteria(); + MaterialFetchOptions fo = new MaterialFetchOptions(); fo.sortBy().code().desc(); fo.from(1).count(2); @@ -48,7 +199,7 @@ public class SortAndPageTest materials.add(material2); materials.add(material3); - Collection<Material> results = new SortAndPage().sortAndPage(materials, fo); + Collection<Material> results = new SortAndPage().sortAndPage(materials, c, fo); assertEquals(results, list(material2, material1)); } @@ -56,6 +207,8 @@ public class SortAndPageTest @Test public void testSubLevel() { + MaterialSearchCriteria c = new MaterialSearchCriteria(); + MaterialFetchOptions fo = new MaterialFetchOptions(); fo.sortBy().code().desc(); fo.withTags().from(1).count(1); @@ -81,7 +234,7 @@ public class SortAndPageTest materials.add(material1); materials.add(material2); - List<Material> results = new SortAndPage().sortAndPage(materials, fo); + List<Material> results = new SortAndPage().sortAndPage(materials, c, fo); assertEquals(results, list(material2, material1)); assertEquals(results.get(0).getTags(), set(tag3)); @@ -91,6 +244,8 @@ public class SortAndPageTest @Test public void testSubLevelThroughSingleRelation() { + MaterialSearchCriteria c = new MaterialSearchCriteria(); + MaterialFetchOptions fo = new MaterialFetchOptions(); fo.sortBy().code().desc(); fo.withTags().from(1).count(1); @@ -149,7 +304,7 @@ public class SortAndPageTest materials.add(material1); materials.add(material2); - List<Material> results = new SortAndPage().sortAndPage(materials, fo); + List<Material> results = new SortAndPage().sortAndPage(materials, c, fo); assertEquals(results, list(material2, material1)); @@ -168,6 +323,8 @@ public class SortAndPageTest @Test public void testSortByMultipleFields() { + MaterialSearchCriteria c = new MaterialSearchCriteria(); + MaterialFetchOptions fo = new MaterialFetchOptions(); fo.sortBy().code().desc(); fo.sortBy().registrationDate().asc(); @@ -192,7 +349,7 @@ public class SortAndPageTest materials.add(material2); materials.add(material3); - List<Material> results = new SortAndPage().sortAndPage(materials, fo); + List<Material> results = new SortAndPage().sortAndPage(materials, c, fo); assertEquals(results.get(0), material3); assertEquals(results.get(1), material2); @@ -202,6 +359,8 @@ public class SortAndPageTest @Test public void testSamePageMultipleTimes() { + MaterialSearchCriteria c = new MaterialSearchCriteria(); + Tag tag1 = new Tag(); tag1.setCode("T1"); Tag tag2 = new Tag(); @@ -227,7 +386,7 @@ public class SortAndPageTest materials.add(material1); materials.add(material2); - List<Material> results = new SortAndPage().sortAndPage(materials, fo); + List<Material> results = new SortAndPage().sortAndPage(materials, c, fo); assertEquals(results, list(material2)); assertEquals(results.get(0).getTags(), set(tag3)); diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/EntityWithPropertiesSortOptions.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/EntityWithPropertiesSortOptions.java index 8084b9e430a493eca9d214b9ea94ca3a269c63b3..ba1a9d6fce9200223cf2c14e8f1438378cfc3b30 100644 --- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/EntityWithPropertiesSortOptions.java +++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/EntityWithPropertiesSortOptions.java @@ -16,6 +16,9 @@ package ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions; +import java.util.HashMap; +import java.util.Map; + import com.fasterxml.jackson.annotation.JsonIgnore; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.ICodeHolder; @@ -34,13 +37,31 @@ public class EntityWithPropertiesSortOptions<OBJECT extends ICodeHolder & IPermI { private static final long serialVersionUID = 1L; - + + @JsonIgnore + public static final String FETCHED_FIELDS_SCORE = "FETCHED_FIELDS_SCORE"; + @JsonIgnore public static final String TYPE = "TYPE"; @JsonIgnore public static final String PROPERTY = "PROPERTY"; - + + public SortOrder fetchedFieldsScore() { + Map<SortParameter, String> parameters = new HashMap<>(); + parameters.put(SortParameter.FULL_CODE_BOOST, "1000000"); + parameters.put(SortParameter.PARTIAL_CODE_BOOST, "100000"); + parameters.put(SortParameter.FULL_PROPERTY_BOOST, "10000"); + parameters.put(SortParameter.FULL_TYPE_BOOST, "1000"); + parameters.put(SortParameter.PARTIAL_PROPERTY_BOOST, "100"); + return getOrCreateSortingWithParameters(FETCHED_FIELDS_SCORE, parameters); + } + + public SortOrder getFetchedFieldsScore() + { + return getSorting(FETCHED_FIELDS_SCORE); + } + public SortOrder type() { return getOrCreateSorting(TYPE); diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/SortOptions.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/SortOptions.java index 9859cfa1d08140fdfeb14d6dcfa3eec6a16571f8..9c24777923d40bc8120a1ef2d767ede57012a776 100644 --- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/SortOptions.java +++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/SortOptions.java @@ -20,6 +20,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import java.util.Map; import org.apache.commons.lang.StringUtils; @@ -37,12 +38,17 @@ public abstract class SortOptions<OBJECT> implements Serializable private List<Sorting> sortings = new LinkedList<>(); protected SortOrder getOrCreateSorting(String field) + { + return getOrCreateSortingWithParameters(field, null); + } + + protected SortOrder getOrCreateSortingWithParameters(String field, Map<SortParameter, String> parameters) { SortOrder order = getSorting(field); if (order == null) { order = new SortOrder(); - sortings.add(new Sorting(field, order)); + sortings.add(new Sorting(field, order, parameters)); } return order; } diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/SortParameter.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/SortParameter.java new file mode 100644 index 0000000000000000000000000000000000000000..232fb2678e665aaa58036d85646fb7a7e2b5ced0 --- /dev/null +++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/SortParameter.java @@ -0,0 +1,30 @@ +/* + * Copyright 2015 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions; + +import ch.systemsx.cisd.base.annotation.JsonObject; + +/** + * @author juanf + */ +@JsonObject("as.dto.common.fetchoptions.SortParameter") +public enum SortParameter +{ + + FULL_CODE_BOOST, PARTIAL_CODE_BOOST, FULL_TYPE_BOOST, FULL_PROPERTY_BOOST, PARTIAL_PROPERTY_BOOST + +} diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/Sorting.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/Sorting.java index 4f819b261acb16fe341ddadf27bcf567392149cd..11b10ccff584584854bc8fd5ea82bb4c29281843 100644 --- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/Sorting.java +++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/common/fetchoptions/Sorting.java @@ -17,6 +17,7 @@ package ch.ethz.sis.openbis.generic.asapi.v3.dto.common.fetchoptions; import java.io.Serializable; +import java.util.Map; import ch.systemsx.cisd.base.annotation.JsonObject; @@ -32,16 +33,24 @@ public class Sorting implements Serializable private String field; private SortOrder order; - + + private Map<SortParameter, String> parameters; + @SuppressWarnings("unused") private Sorting() { } public Sorting(String field, SortOrder order) + { + this(field, order, null); + } + + public Sorting(String field, SortOrder order, Map<SortParameter, String> parameters) { this.field = field; this.order = order; + this.parameters = parameters; } public String getField() @@ -53,6 +62,10 @@ public class Sorting implements Serializable { return order; } + + public Map<SortParameter, String> getParameters() { + return parameters; + } @Override public String toString() diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/eln-lims-api/script.py b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/eln-lims-api/script.py index 23d486ee42c65a7da2523da9d92fdd9f306d9015..cb427d19f409c5b860b418b9ecbd6a382c138044 100644 --- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/eln-lims-api/script.py +++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/eln-lims-api/script.py @@ -362,9 +362,23 @@ def getFeaturesFromFeatureVector(tr, parameters, tableBuilder): def getDiskSpace(tr, parameters, tableBuilder): storerootDir = getConfigParameterAsString("storeroot-dir") - df = subprocess.check_output(["df", '-h', storerootDir]) - diskSpaceValues = extractDiskSpaceValues(df) - return getJsonForData([diskSpaceValues]) + diskSpaceValues = [] + diskSpaceValues.append(getDiskSpaceForDirectory(storerootDir)) + # The storeroot-dir might contain symlinks to different volumes. + # So we want to resolve them and show all relevant mount points. + findLinks = subprocess.check_output(["find", storerootDir, "-type", "l"]) + mountPoints = [] + for symlink in findLinks.splitlines(): + linkPath = os.path.realpath(symlink) + if os.path.exists(linkPath): + diskSpaceForDir = getDiskSpaceForDirectory(linkPath) + if diskSpaceForDir not in diskSpaceValues: + diskSpaceValues.append(diskSpaceForDir) + return getJsonForData(diskSpaceValues) + +def getDiskSpaceForDirectory(dir): + df = subprocess.check_output(["df", '-h', dir]) + return extractDiskSpaceValues(df) def extractDiskSpaceValues(df): values = {}