diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/DataStoreServerApi.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/DataStoreServerApi.java index f92dea95b818c2ba16fbd5e2df28f877d6f9d903..e435744da7e2377f81cc836aed0399f4538fa1cc 100644 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/DataStoreServerApi.java +++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/DataStoreServerApi.java @@ -15,8 +15,6 @@ */ package ch.ethz.sis.openbis.generic.server.dssapi.v3; -import java.io.File; -import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; @@ -28,17 +26,14 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; import org.apache.commons.collections4.iterators.IteratorChain; import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.id.CreationId; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.ISearchCriteria; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.SearchOperator; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.SearchResult; @@ -49,13 +44,9 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId; import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.search.DataSetSearchCriteria; import ch.ethz.sis.openbis.generic.asapi.v3.dto.datastore.id.DataStorePermId; import ch.ethz.sis.openbis.generic.asapi.v3.dto.datastore.id.IDataStoreId; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.id.EntityTypePermId; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.id.IEntityTypeId; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.IExperimentId; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.ISampleId; -import ch.ethz.sis.openbis.generic.asapi.v3.exceptions.UnsupportedObjectIdException; import ch.ethz.sis.openbis.generic.dssapi.v3.IDataStoreServerApi; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.dataset.create.FullDataSetCreation; +import ch.ethz.sis.openbis.generic.dssapi.v3.dto.dataset.create.UploadedDataSetCreation; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.DataSetFile; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.create.DataSetFileCreation; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.download.DataSetFileDownloadOptions; @@ -64,14 +55,12 @@ import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.id.DataSetFilePermI import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.id.IDataSetFileId; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.search.DataSetFileSearchCriteria; import ch.ethz.sis.openbis.generic.server.dssapi.v3.download.DataSetFileDownloadInputStream; +import ch.ethz.sis.openbis.generic.server.dssapi.v3.executor.ICreateUploadedDataSetExecutor; import ch.ethz.sis.openbis.generic.server.dssapi.v3.pathinfo.PathInfoFeeder; import ch.systemsx.cisd.common.exceptions.Status; import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.common.filesystem.IFreeSpaceProvider; import ch.systemsx.cisd.common.filesystem.SimpleFreeSpaceProvider; -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.etlserver.path.IPathsInfoDAO; import ch.systemsx.cisd.openbis.common.io.hierarchical_content.api.IHierarchicalContent; import ch.systemsx.cisd.openbis.common.io.hierarchical_content.api.IHierarchicalContentNode; @@ -83,13 +72,7 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.IConfigProvider; import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; import ch.systemsx.cisd.openbis.dss.generic.shared.IHierarchicalContentProvider; import ch.systemsx.cisd.openbis.dss.generic.shared.IShareIdManager; -import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.authorization.DssSessionAuthorizationHolder; -import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssBuilder; -import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssDTO; -import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.NewDataSetDTO; -import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.NewDataSetDTO.DataSetOwner; -import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.NewDataSetDTO.DataSetOwnerType; import ch.systemsx.cisd.openbis.dss.generic.shared.utils.PathInfoDataSourceProvider; import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.RolesAllowed; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy; @@ -109,12 +92,6 @@ public class DataStoreServerApi extends AbstractDssServiceRpc<IDataStoreServerAp */ public static final String INTERNAL_SERVICE_NAME = "data-store-server_INTERNAL"; - /** - * Logger with {@link LogCategory#OPERATION} with name of the concrete class, needs to be static for our purpose. - */ - protected static Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, - DataStoreServerApi.class); - public String DSS_SERVICE_NAME = "DSS Service"; @Autowired @@ -123,6 +100,9 @@ public class DataStoreServerApi extends AbstractDssServiceRpc<IDataStoreServerAp @Autowired private IApplicationServerApi as; + @Autowired + private ICreateUploadedDataSetExecutor createUploadedDataSetExecutor; + /** * The designated constructor. */ @@ -138,8 +118,7 @@ public class DataStoreServerApi extends AbstractDssServiceRpc<IDataStoreServerAp IPluginTaskInfoProvider infoProvider, IFreeSpaceProvider freeSpaceProvider, IShareIdManager shareIdManager, IHierarchicalContentProvider contentProvider) { - this(openBISService, apiServer, infoProvider, null, freeSpaceProvider, shareIdManager, - contentProvider, new PutDataSetService(openBISService, operationLog)); + this(openBISService, apiServer, infoProvider, null, freeSpaceProvider, shareIdManager, contentProvider); } /** @@ -148,8 +127,7 @@ public class DataStoreServerApi extends AbstractDssServiceRpc<IDataStoreServerAp public DataStoreServerApi(IEncapsulatedOpenBISService openBISService, IQueryApiServer apiServer, IPluginTaskInfoProvider infoProvider, IStreamRepository streamRepository, IFreeSpaceProvider freeSpaceProvider, - IShareIdManager shareIdManager, IHierarchicalContentProvider contentProvider, - PutDataSetService service) + IShareIdManager shareIdManager, IHierarchicalContentProvider contentProvider) { super(openBISService, streamRepository, shareIdManager, contentProvider); // queryApiServer = apiServer; @@ -345,80 +323,24 @@ public class DataStoreServerApi extends AbstractDssServiceRpc<IDataStoreServerAp return new DataStoreServerApiLogger(context); } - private NewDataSetDTO getNewDataSet(FullDataSetCreation dataSetCreation, File temporaryIncomingDir) throws IOException - { - ISampleId sampleIdentifier = dataSetCreation.getMetadataCreation().getSampleId(); - IExperimentId experimentIdentifier = dataSetCreation.getMetadataCreation().getExperimentId(); - DataSetOwnerType ownerType = DataSetOwnerType.SAMPLE; - DataSetOwner owner = null; - if (sampleIdentifier != null) - { - owner = new NewDataSetDTO.DataSetOwner(ownerType, sampleIdentifier.toString()); - } else if (experimentIdentifier != null) - { - ownerType = DataSetOwnerType.EXPERIMENT; - owner = new NewDataSetDTO.DataSetOwner(ownerType, experimentIdentifier.toString()); - } - if (owner == null) - { - throw new UserFailureException("A dataset needs either a Sample or Experiment as owner."); - } - IEntityTypeId typeId = dataSetCreation.getMetadataCreation().getTypeId(); - String typeCode = null; - - if (typeId != null) - { - if (typeId instanceof EntityTypePermId) - { - typeCode = ((EntityTypePermId) typeId).getPermId(); - } else - { - throw new UnsupportedObjectIdException(typeId); - } - } - - List<FileInfoDssDTO> fileInfos = FileInfoDssBuilder.getFileInfos(temporaryIncomingDir); - - NewDataSetDTO dataSet = new NewDataSetDTO(typeCode, owner, null, fileInfos); - return dataSet; - } - - private List<FullDataSetCreation> filterPhysicalDataSets(List<FullDataSetCreation> newDataSets) - { - return newDataSets - .stream() - .filter((dataSetCreation) -> dataSetCreation.getMetadataCreation().getPhysicalData() != null) - .collect(Collectors.toList()); - } - - private List<FullDataSetCreation> filterNonPhysicalDataSets(List<FullDataSetCreation> newDataSets) + @Override + @Transactional + @RolesAllowed({ RoleWithHierarchy.PROJECT_USER }) + public DataSetPermId createUploadedDataSet(String sessionToken, UploadedDataSetCreation creation) { - return newDataSets - .stream() - .filter((dataSetCreation) -> dataSetCreation.getMetadataCreation().getPhysicalData() == null) - .collect(Collectors.toList()); + return createUploadedDataSetExecutor.create(sessionToken, creation); } @Override @Transactional @RolesAllowed({ RoleWithHierarchy.INSTANCE_ADMIN }) public List<DataSetPermId> createDataSets(String sessionToken, List<FullDataSetCreation> newDataSets) - { - injectDataStoreIdAndCodesIfNeeded(newDataSets); - List<FullDataSetCreation> physicalDataSets = filterPhysicalDataSets(newDataSets); - createPhysicalDataSets(sessionToken, physicalDataSets); - - List<FullDataSetCreation> nonPhysicalDataSets = filterNonPhysicalDataSets(newDataSets); - return createNonPhysicalDataSets(sessionToken, nonPhysicalDataSets); - } - - private List<DataSetPermId> createNonPhysicalDataSets(String sessionToken, List<FullDataSetCreation> newDataSets) { if (PathInfoDataSourceProvider.isDataSourceDefined() == false) { throw new IllegalStateException("Pathinfo DB not configured - cannot store dataset file information"); } - + injectDataStoreIdAndCodesIfNeeded(newDataSets); IPathsInfoDAO dao = QueryTool.getQuery(PathInfoDataSourceProvider.getDataSource(), IPathsInfoDAO.class); for (int i = 0; i < newDataSets.size(); i++) @@ -453,42 +375,6 @@ public class DataStoreServerApi extends AbstractDssServiceRpc<IDataStoreServerAp return as.createDataSets(sessionToken, metadata); } - private void createPhysicalDataSets(String sessionToken, List<FullDataSetCreation> newDataSets) - { - for (FullDataSetCreation dataSetCreation : newDataSets) - { - PutDataSetService putService = - new PutDataSetService(ServiceProvider.getOpenBISService(), operationLog); - putService.setStoreDirectory(ServiceProvider.getConfigProvider().getStoreRoot()); - NewDataSetDTO newDataset; - try - { - DataSetCreation metadataCreation = dataSetCreation.getMetadataCreation(); - CreationId creationId = metadataCreation.getCreationId(); - String dataSetTypeCodeNull = null; - IEntityTypeId typeId = metadataCreation.getTypeId(); - if (null != typeId) - { - if (typeId instanceof EntityTypePermId) - { - dataSetTypeCodeNull = ((EntityTypePermId) typeId).getPermId(); - } else - { - throw new UnsupportedObjectIdException(typeId); - } - } - File temporaryIncomingDir = putService.getTemporaryIncomingDir(dataSetTypeCodeNull, creationId.toString()); - newDataset = getNewDataSet(dataSetCreation, temporaryIncomingDir); - String code = dataSetCreation.getMetadataCreation().getCode(); - putService.putDataSet(sessionToken, newDataset, creationId.toString(), code); - - } catch (IOException e) - { - operationLog.error(e.getMessage()); - } - } - } - private void injectDataStoreIdAndCodesIfNeeded(List<FullDataSetCreation> newDataSets) { String dataStoreCode = configProvider.getDataStoreCode(); diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/DataStoreServerApiJson.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/DataStoreServerApiJson.java index f4a3faa402a919bfb65fdbded09f114a93b4459f..7d6e3cc79130e3b9d05c76ea517d770b86cff50c 100644 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/DataStoreServerApiJson.java +++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/DataStoreServerApiJson.java @@ -27,6 +27,7 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.SearchResult; import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId; import ch.ethz.sis.openbis.generic.dssapi.v3.IDataStoreServerApi; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.dataset.create.FullDataSetCreation; +import ch.ethz.sis.openbis.generic.dssapi.v3.dto.dataset.create.UploadedDataSetCreation; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.DataSetFile; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.download.DataSetFileDownloadOptions; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.fetchoptions.DataSetFileFetchOptions; @@ -59,6 +60,12 @@ public class DataStoreServerApiJson implements IDataStoreServerApi throw new UnsupportedOperationException("This method is not supported in JSON API"); } + @Override + public DataSetPermId createUploadedDataSet(String sessionToken, UploadedDataSetCreation newDataSet) + { + return api.createUploadedDataSet(sessionToken, newDataSet); + } + @Override public List<DataSetPermId> createDataSets(String sessionToken, List<FullDataSetCreation> newDataSets) { diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/DataStoreServerApiLogger.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/DataStoreServerApiLogger.java index dbb7dae12d37d7410c3259d4dd785b591ec8df82..ec7f3ccbe8d6190b4675a49b08eb17700debee4d 100644 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/DataStoreServerApiLogger.java +++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/DataStoreServerApiLogger.java @@ -7,6 +7,7 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.SearchResult; import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId; import ch.ethz.sis.openbis.generic.dssapi.v3.IDataStoreServerApi; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.dataset.create.FullDataSetCreation; +import ch.ethz.sis.openbis.generic.dssapi.v3.dto.dataset.create.UploadedDataSetCreation; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.DataSetFile; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.download.DataSetFileDownloadOptions; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.fetchoptions.DataSetFileFetchOptions; @@ -50,6 +51,13 @@ public class DataStoreServerApiLogger extends AbstractServerLogger implements return null; } + @Override + public DataSetPermId createUploadedDataSet(String sessionToken, UploadedDataSetCreation newDataSet) + { + logAccess(sessionToken, "create-uploaded-data-sets", "DATA_SETS:\n%s", newDataSet); + return null; + } + @Override public List<DataSetPermId> createDataSets(String sessionToken, List<FullDataSetCreation> newDataSets) { 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 new file mode 100644 index 0000000000000000000000000000000000000000..ae944447b24b1800d8e6c30226871c88166192f5 --- /dev/null +++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/executor/CreateUploadedDataSetExecutor.java @@ -0,0 +1,224 @@ +/* + * 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.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; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.SearchResult; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSet; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSetType; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.fetchoptions.DataSetFetchOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.fetchoptions.DataSetTypeFetchOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.search.DataSetTypeSearchCriteria; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.Experiment; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.fetchoptions.ExperimentFetchOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.IExperimentId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.Sample; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.fetchoptions.SampleFetchOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.ISampleId; +import ch.ethz.sis.openbis.generic.asapi.v3.exceptions.ObjectNotFoundException; +import ch.ethz.sis.openbis.generic.dssapi.v3.dto.dataset.create.UploadedDataSetCreation; +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; +import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssDTO; +import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.NewDataSetDTO; +import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.NewDataSetDTO.DataSetOwner; +import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.NewDataSetDTO.DataSetOwnerType; +import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; + +/** + * @author pkupczyk + */ +@Component +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) + { + try + { + getOpenBIService().checkSession(sessionToken); + + NewDataSetDTO newDataset = getNewDataSet(sessionToken, creation); + + List<DataSetInformation> dataSetInfos = getPutService().putDataSet(sessionToken, newDataset, creation.getUploadId()); + + if (dataSetInfos != null && false == dataSetInfos.isEmpty()) + { + return new DataSetPermId(dataSetInfos.get(0).getDataSetCode()); + } else + { + return null; + } + } catch (IOException e) + { + throw ExceptionUtils.create(new OperationContext(null), e); + } + } + + private NewDataSetDTO getNewDataSet(String sessionToken, UploadedDataSetCreation creation) throws IOException + { + DataSetOwnerType ownerType; + DataSetOwner owner; + String typeCode; + List<String> parentCodes = new ArrayList<String>(); + + // type + + if (creation.getTypeId() != null) + { + DataSetTypeSearchCriteria criteria = new DataSetTypeSearchCriteria(); + criteria.withId().thatEquals(creation.getTypeId()); + + SearchResult<DataSetType> searchResult = + getApplicationServerApi().searchDataSetTypes(sessionToken, criteria, new DataSetTypeFetchOptions()); + + if (searchResult.getObjects() != null && false == searchResult.getObjects().isEmpty()) + { + DataSetType type = searchResult.getObjects().get(0); + typeCode = type.getCode(); + } else + { + throw new ObjectNotFoundException(creation.getTypeId()); + } + } else + { + throw new UserFailureException("A dataset needs a type."); + } + + // owner + + if (creation.getSampleId() != null) + { + Map<ISampleId, Sample> samples = + getApplicationServerApi().getSamples(sessionToken, Arrays.asList(creation.getSampleId()), new SampleFetchOptions()); + Sample sample = samples.get(creation.getSampleId()); + + if (sample == null) + { + throw new ObjectNotFoundException(creation.getSampleId()); + } + + ownerType = DataSetOwnerType.SAMPLE; + owner = new NewDataSetDTO.DataSetOwner(ownerType, sample.getIdentifier().getIdentifier()); + } else if (creation.getExperimentId() != null) + { + Map<IExperimentId, Experiment> experiments = + getApplicationServerApi().getExperiments(sessionToken, Arrays.asList(creation.getExperimentId()), new ExperimentFetchOptions()); + Experiment experiment = experiments.get(creation.getExperimentId()); + + if (experiment == null) + { + throw new ObjectNotFoundException(creation.getExperimentId()); + } + + ownerType = DataSetOwnerType.EXPERIMENT; + owner = new NewDataSetDTO.DataSetOwner(ownerType, experiment.getIdentifier().getIdentifier()); + } else + { + throw new UserFailureException("A dataset needs either a sample or an experiment as an owner."); + } + + // parents + + if (creation.getParentIds() != null && false == creation.getParentIds().isEmpty()) + { + Map<IDataSetId, DataSet> parents = + getApplicationServerApi().getDataSets(sessionToken, creation.getParentIds(), new DataSetFetchOptions()); + + for (IDataSetId parentId : creation.getParentIds()) + { + DataSet parent = parents.get(parentId); + if (parent == null) + { + throw new ObjectNotFoundException(parentId); + } + parentCodes.add(parent.getCode()); + } + } + + // 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); + return newDataSet; + } + + private IApplicationServerApi getApplicationServerApi() + { + return ServiceProvider.getV3ApplicationService(); + } + + private IEncapsulatedOpenBISService getOpenBIService() + { + return ServiceProvider.getOpenBISService(); + } + + private synchronized PutDataSetService getPutService() + { + if (putService == null) + { + putService = new PutDataSetService(ServiceProvider.getOpenBISService(), operationLog); + putService.setStoreDirectory(ServiceProvider.getConfigProvider().getStoreRoot()); + } + + return putService; + } +} diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/executor/ICreateUploadedDataSetExecutor.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/executor/ICreateUploadedDataSetExecutor.java new file mode 100644 index 0000000000000000000000000000000000000000..995215e6cbab5a122902a9e69346389d2e41a665 --- /dev/null +++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dssapi/v3/executor/ICreateUploadedDataSetExecutor.java @@ -0,0 +1,30 @@ +/* + * 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.ethz.sis.openbis.generic.server.dssapi.v3.executor; + +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId; +import ch.ethz.sis.openbis.generic.dssapi.v3.dto.dataset.create.UploadedDataSetCreation; + +/** + * @author pkupczyk + */ +public interface ICreateUploadedDataSetExecutor +{ + + DataSetPermId create(String sessionToken, UploadedDataSetCreation creation); + +} 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 4730bf93a4b5710504a3c1aa2e0ab79c0898f811..e40df8eeb44a5fb311da1d059dedbd6e299243bb 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 @@ -29,20 +29,14 @@ import org.apache.commons.fileupload.FileItemIterator; import org.apache.commons.fileupload.FileItemStream; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; -import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import com.marathon.util.spring.StreamSupportingHttpInvokerServiceExporter; - -import ch.ethz.sis.openbis.generic.dssapi.v3.IDataStoreServerApi; -import ch.ethz.sis.openbis.generic.server.dssapi.v3.DataStoreServerApiJsonServer; import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel; +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; @@ -50,21 +44,23 @@ import ch.systemsx.cisd.openbis.dss.generic.server.Utils; import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; /** - * - * * @author Ganime Betul Akin */ @RestController -@RequestMapping({"store_share_file_upload", "/datastore_server/store_share_file_upload"}) +@RequestMapping({ "store_share_file_upload", "/datastore_server/store_share_file_upload" }) public class StoreShareFileUploadServlet extends HttpServlet { private static final long serialVersionUID = 1L; - - @SuppressWarnings("hiding") + protected static Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, StoreShareFileUploadServlet.class); + public static final String SESSION_ID_PARAM = Utils.SESSION_ID_PARAM; + public static final String DATA_SET_TYPE_PARAM = "dataSetType"; + + public static final String IGNORE_FILE_PATH_PARAM = "ignoreFilePath"; + public static final String UPLOAD_ID_PARAM = "uploadID"; private PutDataSetService putService; @@ -73,27 +69,27 @@ public class StoreShareFileUploadServlet extends HttpServlet public final void init(final ServletConfig servletConfig) throws ServletException { super.init(servletConfig); - this.putService = - new PutDataSetService(ServiceProvider.getOpenBISService(), operationLog); + this.putService = new PutDataSetService(ServiceProvider.getOpenBISService(), operationLog); putService.setStoreDirectory(ServiceProvider.getConfigProvider().getStoreRoot()); - } + @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - StoreShareFileUploadRequest uploadRequest = - new StoreShareFileUploadRequest(request); + StoreShareFileUploadRequest uploadRequest = new StoreShareFileUploadRequest(request); uploadRequest.validate(); - - String dataSetTypeCodeOrNull = uploadRequest.getDataSetType(); - String uploadId = uploadRequest.getUploadId(); try { FileItemIterator iterator = uploadRequest.getFiles(); + if (false == iterator.hasNext()) + { + throw new UserFailureException("Please upload at least one file"); + } + while (iterator.hasNext()) { FileItemStream file = null; @@ -103,23 +99,30 @@ public class StoreShareFileUploadServlet extends HttpServlet { file = iterator.next(); stream = file.openStream(); - putService.putFileToStoreShare(uploadRequest.getSessionId(), file.getName(), dataSetTypeCodeOrNull, uploadId, stream); - } - catch (Exception e) { - operationLog.error(e.getMessage()); - } - finally + + /* + * Most browsers send only base file names for files which were uploaded via a regular html form. Still, there are some browsers + * (e.g. Opera) that are known to send file paths as well. To handle all browsers consistently by default we ignore file paths + * even if they are given. We only use the file paths if it has been explicitly requested via <code>IGNORE_FILE_PATH_PARAM</code> + * request parameter. This may be handy in contexts where we have a full control over what gets sent to the servlet (e.g. from a + * Python script that makes http requests to the servlet). + */ + String filePath = uploadRequest.isIgnoreFilePath() ? FilenameUtils.getName(file.getName()) : file.getName(); + + putService.putFileToStoreShare(uploadRequest.getSessionId(), filePath, uploadRequest.getDataSetType(), + uploadRequest.getUploadId(), stream); + } finally { IOUtils.closeQuietly(stream); } } - - } catch (FileUploadException e) + } catch (Exception e) { + operationLog.error(e.getMessage()); throw CheckedExceptionTunnel.wrapIfNecessary(e); } } - + private class StoreShareFileUploadRequest { @@ -132,8 +135,9 @@ public class StoreShareFileUploadServlet extends HttpServlet public String getSessionId() { - return request.getParameter(Utils.SESSION_ID_PARAM); + return request.getParameter(SESSION_ID_PARAM); } + public String getDataSetType() { return request.getParameter(DATA_SET_TYPE_PARAM); @@ -144,6 +148,19 @@ public class StoreShareFileUploadServlet extends HttpServlet return request.getParameter(UPLOAD_ID_PARAM); } + public boolean isIgnoreFilePath() + { + String str = request.getParameter(IGNORE_FILE_PATH_PARAM); + + if (str == null || str.isEmpty()) + { + return true; + } else + { + return Boolean.valueOf(str); + } + } + public FileItemIterator getFiles() throws FileUploadException, IOException { ServletFileUpload upload = new ServletFileUpload(); @@ -154,18 +171,7 @@ public class StoreShareFileUploadServlet extends HttpServlet { if (ServletFileUpload.isMultipartContent(request) == false) { - throw new IllegalArgumentException( - "The session workspace form upload accepts only multipart requests"); - } - if (getSessionId() == null) - { - throw new IllegalArgumentException(Utils.SESSION_ID_PARAM - + " parameter cannot be null"); - } - - if (getUploadId() == null) - { - throw new IllegalArgumentException(UPLOAD_ID_PARAM + " parameter cannot be null"); + throw new UserFailureException("The file upload accepts only multipart requests"); } } diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetExecutor.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetExecutor.java index 8ca00943510e01c3d2801b1bb9fa3fec08161551..0b2fd226dd604209bc4a3269523e886ccdcc8977 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetExecutor.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetExecutor.java @@ -135,7 +135,7 @@ class PutDataSetExecutor implements IDataSetHandlerRpc } PutDataSetExecutor(PutDataSetService service, IETLServerPlugin plugin, String sessionToken, - NewDataSetDTO newDataSet, File temporaryIncomingDir) + NewDataSetDTO newDataSet, File temporaryIncomingDir, File dataSet) { this.service = service; this.plugin = plugin; @@ -144,17 +144,7 @@ class PutDataSetExecutor implements IDataSetHandlerRpc this.inputStream = null; this.copier = FastRecursiveHardLinkMaker.tryCreate(RSyncConfig.getInstance().getAdditionalCommandLineOptions()); this.temporaryIncomingDir = temporaryIncomingDir; - this.dataSetDir = new File(temporaryIncomingDir, newDataSet.getDataSetFolderName()); - if (dataSetDir.exists()) - { - deleteDataSetDir(); - } - if (false == this.dataSetDir.mkdir()) - { - throw new EnvironmentFailureException("Could not create directory for data set " - + newDataSet.getDataSetFolderName()); - } - + this.dataSetDir = dataSet; overridingTypeExtractor = new OverridingTypeExtractor(); handler = plugin.getDataSetHandler(this, service.getOpenBisService()); } 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 c5e75e0e6f6faa4670e4ed8c85c0d3236573f544..f1e8fe136846c1aa27fd28d3c9e10ec557ccb478 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 @@ -65,6 +65,9 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseInstance; */ public class PutDataSetService { + + private static final String MULTIPLE_FILES_UPLOAD_DIR = "upload"; + private final IEncapsulatedOpenBISService openBisService; private final Logger operationLog; @@ -258,8 +261,8 @@ public class PutDataSetService } } } - - public String putDataSet(String sessionToken, NewDataSetDTO newDataSet, String uploadId, String dataSetCode) + + public List<DataSetInformation> putDataSet(String sessionToken, NewDataSetDTO newDataSet, String uploadId) throws IOExceptionUnchecked, IllegalArgumentException { if (false == isInitialized) @@ -267,101 +270,111 @@ public class PutDataSetService doInitialization(); } - try + String dataSetTypeOrNull = newDataSet.tryDataSetType(); + ITopLevelDataSetRegistrator registrator = registratorMap.getRegistratorForType(dataSetTypeOrNull); + + File uploadDir = new File(getTemporaryIncomingRoot(dataSetTypeOrNull), uploadId); + File multipleFilesUploadDir = new File(uploadDir, MULTIPLE_FILES_UPLOAD_DIR); + File[] uploadedFiles = multipleFilesUploadDir.listFiles(); + File dataSet = null; + + if (uploadedFiles != null && uploadedFiles.length == 1) { - String dataSetTypeOrNull = newDataSet.tryDataSetType(); - ITopLevelDataSetRegistrator registrator = - registratorMap.getRegistratorForType(dataSetTypeOrNull); + dataSet = uploadedFiles[0]; + } else + { + dataSet = multipleFilesUploadDir; + } - File uploadedDataSetDir = - new File(getTemporaryIncomingRoot(dataSetTypeOrNull), uploadId); + if (registrator instanceof PutDataSetServerPluginHolder) + { + return new PutDataSetExecutor(this, ((PutDataSetServerPluginHolder) registrator).getPlugin(), sessionToken, newDataSet, uploadDir, + dataSet).executeWithoutWriting(); + } else + { + return new PutDataSetTopLevelDataSetHandler(this, registrator, sessionToken, newDataSet, uploadDir, dataSet).executeWithoutWriting(); + } + } - File temporaryDataSetDir = - new File(getTemporaryIncomingRoot(dataSetTypeOrNull), dataSetCode); - - if(false == uploadedDataSetDir.renameTo(temporaryDataSetDir)) { - throw new ConfigurationFailureException("Could not rename : " - + uploadedDataSetDir + " to " + temporaryDataSetDir); + public void putFileToStoreShare(String sessionToken, String filePath, String dataSetType, String uploadId, InputStream inputStream) + { + if (false == isInitialized) + { + doInitialization(); + } - } + File file = null; + OutputStream outputStream = null; - final List<DataSetInformation> infos; - // Branch -- use the old logic for the ETLServerPlugins - if (registrator instanceof PutDataSetServerPluginHolder) + try + { + if (StringUtils.isBlank(sessionToken)) { - infos = - new PutDataSetExecutor(this, - ((PutDataSetServerPluginHolder) registrator).getPlugin(), - sessionToken, newDataSet, temporaryDataSetDir).executeWithoutWriting(); - } else + throw new UserFailureException("Session token cannot be null or empty"); + } + if (StringUtils.isBlank(filePath)) { - infos = - new PutDataSetTopLevelDataSetHandler(this, registrator, sessionToken, - newDataSet, temporaryDataSetDir).executeWithoutWriting(); + throw new UserFailureException("File path cannot be null or empty"); } - StringBuilder sb = new StringBuilder(); - for (DataSetInformation info : infos) + if (filePath.contains("../")) { - sb.append(info.getDataSetCode()); - sb.append(","); + throw new UserFailureException("File path must not contain '../'"); + } + if (StringUtils.isBlank(dataSetType)) + { + throw new UserFailureException("Data set type cannot be null or empty"); + } + 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 '/'"); + } + if (inputStream == null) + { + throw new UserFailureException("Input stream cannot be null"); } - // Remove the trailing comma - if (sb.length() > 0) + ServiceProvider.getOpenBISService().checkSession(sessionToken); + + File uploadDir = new File(getTemporaryIncomingRoot(dataSetType), uploadId); + if (false == uploadDir.exists()) { - sb.deleteCharAt(sb.length() - 1); + uploadDir.mkdir(); } - return sb.toString(); - } catch (UserFailureException e) - { - throw new IllegalArgumentException(e); - } - } - public String putFileToStoreShare(String sessionToken, String filePath, String dataSetTypeCodeOrNull, String uploadId, InputStream inputStream) { - { - if (false == isInitialized) + + File uploadSubDir = new File(uploadDir, MULTIPLE_FILES_UPLOAD_DIR); + if (false == uploadSubDir.exists()) { - doInitialization(); + uploadSubDir.mkdir(); } + 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); + + } catch (IOException ioe) + { + IOUtils.closeQuietly(outputStream); + try { - ServiceProvider.getOpenBISService().checkSession(sessionToken); - if (filePath.contains("../")) - { - throw new IOExceptionUnchecked("filePath must not contain '../'"); - } - String uniqueFolderName = uploadId; - File temporaryDataSetDir = - new File(getTemporaryIncomingRoot(dataSetTypeCodeOrNull), uniqueFolderName); - if(false == temporaryDataSetDir.exists()) { - temporaryDataSetDir.mkdir(); - } - final String subDir = FilenameUtils.getFullPath(filePath); - final String filename = FilenameUtils.getName(filePath); - final File dir = new File(temporaryDataSetDir, subDir); - dir.mkdirs(); - final File file = new File(dir, filename); - OutputStream ostream = null; - try - { - ostream = new FileOutputStream(file); - long size = IOUtils.copyLarge(inputStream, ostream); - ostream.close(); - return uniqueFolderName; - } catch (IOException ex) - { - file.delete(); - throw CheckedExceptionTunnel.wrapIfNecessary(ex); - } finally - { - IOUtils.closeQuietly(ostream); - } - } - catch (UserFailureException e) + file.delete(); + } catch (Exception e) { - throw new IllegalArgumentException(e); - } + } + + throw CheckedExceptionTunnel.wrapIfNecessary(ioe); + + } finally + { + IOUtils.closeQuietly(outputStream); } } @@ -491,28 +504,7 @@ public class PutDataSetService return temporaryIncomingDir; } - private File getTemporaryIncomingRoot(String dataSetTypeCodeOrNull) - { - TopLevelDataSetRegistratorGlobalState globalState = - getThreadGlobalState(dataSetTypeCodeOrNull); - File storeRoot = globalState.getStoreRootDir(); - if (false == StringUtils.isBlank(globalState.getShareId())) - { - File shareRoot = new File(storeRoot, globalState.getShareId()); - if (shareRoot.isDirectory()) - { - File incomingDir = new File(shareRoot, "rpc-incoming"); - incomingDir.mkdir(); - if (incomingDir.isDirectory()) - { - return incomingDir; - } - } - } - return storeRoot; - } - - public File getTemporaryIncomingDir(String dataSetTypeCodeOrNull, String creationId) + public File getTemporaryIncomingRoot(String dataSetTypeCodeOrNull) { if (false == isInitialized) { @@ -528,15 +520,18 @@ public class PutDataSetService if (shareRoot.isDirectory()) { File incomingDir = new File(shareRoot, "rpc-incoming"); - File tempDir = new File(incomingDir, creationId); - if(false == tempDir.exists()) { - throw new UserFailureException("The folder for the creation Id " + creationId + " could not be found. Have you uploaded the file first?" ); + incomingDir.mkdir(); + if (incomingDir.isDirectory()) + { + return incomingDir; } } } return storeRoot; } + } + /** * Helper class to simplify initializing the final fields of the {@link PutDataSetService}. * diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetTopLevelDataSetHandler.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetTopLevelDataSetHandler.java index abc85f9fb6e4117f3b628b2b39a1652661c390ef..8722cbba53ddb2d616154f5e6ca8609e369b609d 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetTopLevelDataSetHandler.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetTopLevelDataSetHandler.java @@ -98,39 +98,16 @@ class PutDataSetTopLevelDataSetHandler private final File dataSet; PutDataSetTopLevelDataSetHandler(PutDataSetService service, - ITopLevelDataSetRegistrator registrator, String sessionToken, NewDataSetDTO newDataSet, File temporaryIncomingDir) + ITopLevelDataSetRegistrator registrator, String sessionToken, NewDataSetDTO newDataSet, File temporaryIncomingDir, File dataSet) { this.service = service; this.registrator = registrator; this.sessionToken = sessionToken; this.newDataSet = newDataSet; this.temporaryIncomingDir = temporaryIncomingDir; + this.dataSet = dataSet; this.inputStream = null; - String dataSetFolderName = newDataSet.getDataSetFolderName(); - boolean dataSetIsASingleFile = - NewDataSetDTO.DEFAULT_DATA_SET_FOLDER_NAME.equals(dataSetFolderName) - && newDataSet.getFileInfos().size() == 1; - if (dataSetIsASingleFile) - { - dataSetDir = temporaryIncomingDir; - dataSet = - new File(temporaryIncomingDir, newDataSet.getFileInfos().get(0) - .getPathInDataSet()); - } else - { - this.dataSetDir = new File(temporaryIncomingDir, dataSetFolderName); - dataSet = dataSetDir; - } - if (dataSetDir.exists()) - { - deleteDataSetDir(); - } - if (false == this.dataSetDir.mkdir()) - { - throw new EnvironmentFailureException("Could not create directory for data set " - + dataSet.getName()); - } - + this.dataSetDir = null; } PutDataSetTopLevelDataSetHandler(PutDataSetService service, 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 new file mode 100644 index 0000000000000000000000000000000000000000..53f8ef2a2d9bc8f5479cfb95e161680c7994f55b --- /dev/null +++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/CreateUploadedDataSetsTest.java @@ -0,0 +1,916 @@ +/* + * Copyright 2017 ETH Zuerich, SIS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.ethz.sis.openbis.generic.dss.systemtest.api.v3; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.exception.ExceptionUtils; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.util.MultiPartContentProvider; +import org.eclipse.jetty.client.util.StringContentProvider; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpStatus; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSet; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.fetchoptions.DataSetFetchOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.id.EntityTypePermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.ExperimentIdentifier; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.ExperimentPermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.SampleIdentifier; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.SamplePermId; +import ch.ethz.sis.openbis.generic.dssapi.v3.dto.dataset.create.UploadedDataSetCreation; +import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.DataSetFile; +import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.download.DataSetFileDownload; +import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.download.DataSetFileDownloadOptions; +import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.download.DataSetFileDownloadReader; +import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.id.DataSetFilePermId; +import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.id.IDataSetFileId; +import ch.ethz.sis.openbis.generic.server.dssapi.v3.upload.StoreShareFileUploadServlet; +import ch.systemsx.cisd.common.exceptions.UserFailureException; +import ch.systemsx.cisd.common.http.JettyHttpClientFactory; +import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; +import ch.systemsx.cisd.openbis.generic.shared.util.TestInstanceHostUtils; +import ch.systemsx.cisd.openbis.systemtest.authorization.ProjectAuthorizationUser; + +/** + * @author Ganime Betul Akin + */ +public class CreateUploadedDataSetsTest extends AbstractFileTest +{ + private static final String SERVICE_URL = TestInstanceHostUtils.getDSSUrl() + "/datastore_server/store_share_file_upload"; + + private IApplicationServerApi as; + + @Override + @BeforeClass + protected void beforeClass() throws Exception + { + super.beforeClass(); + as = ServiceProvider.getV3ApplicationService(); + } + + @Test + public void testUploadWithInvalidSession() throws Exception + { + ContentResponse response = + uploadFiles("admin-180211214633760xF769DD44CAFFAF7B50FBEADF00DBEE1F", UUID.randomUUID().toString(), "UNKNOWN", true, + new FileToUpload()); + assertResponseError(response); + assertTrue(response.getContentAsString(), response.getContentAsString().contains("user is not logged in")); + } + + @Test + public void testUploadWithoutSession() throws Exception + { + ContentResponse response = uploadFiles(null, UUID.randomUUID().toString(), "UNKNOWN", true, new FileToUpload()); + assertResponseError(response); + assertTrue(response.getContentAsString(), response.getContentAsString().contains("Session token cannot be null or empty")); + } + + @Test + public void testUploadWithoutType() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + ContentResponse response = uploadFiles(sessionToken, UUID.randomUUID().toString(), null, true, new FileToUpload()); + assertResponseError(response); + assertTrue(response.getContentAsString(), response.getContentAsString().contains("Data set type cannot be null or empty")); + } + + @Test + public void testUploadWithoutUploadId() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + ContentResponse response = uploadFiles(sessionToken, null, "UNKNOWN", true, new FileToUpload()); + assertResponseError(response); + assertTrue(response.getContentAsString(), response.getContentAsString().contains("Upload id cannot be null or empty")); + } + + @Test + public void testUploadWithUploadIdThatContainsSlash() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + ContentResponse response = uploadFiles(sessionToken, "iam/incorrect", "UNKNOWN", true, new FileToUpload()); + assertResponseError(response); + assertTrue(response.getContentAsString(), response.getContentAsString().contains("Upload id must not contain '/'")); + } + + @Test + public void testUploadWithoutFile() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + ContentResponse response = uploadFiles(sessionToken, UUID.randomUUID().toString(), "UNKNOWN", true); + assertResponseError(response); + assertTrue(response.getContentAsString(), response.getContentAsString().contains("Please upload at least one file")); + } + + @Test + public void testUploadWithFileWithFolderUpPath() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + ContentResponse response = + uploadFiles(sessionToken, UUID.randomUUID().toString(), "UNKNOWN", false, new FileToUpload("name", "iam/../incorrect", "content")); + assertResponseError(response); + assertTrue(response.getContentAsString(), response.getContentAsString().contains("File path must not contain '../'")); + } + + @Test + public void testUploadWithFileWithoutPath() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + ContentResponse response = + uploadFiles(sessionToken, UUID.randomUUID().toString(), "UNKNOWN", false, new FileToUpload("name", null, "content")); + assertResponseError(response); + assertTrue(response.getContentAsString(), response.getContentAsString().contains("File path cannot be null or empty")); + } + + @Test + public void testCreateWithInvalidSession() throws Exception + { + try + { + getCreateAndGetDataSet("admin-180211214633760xF769DD44CAFFAF7B50FBEADF00DBEE1F", null); + } catch (UserFailureException e) + { + assertTrue(e.getMessage(), e.getMessage().contains("user is not logged in")); + } + } + + @Test + public void testCreateWithoutType() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "UNKNOWN"; + String sampleIdentifier = "/CISD/CP-TEST-1"; + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setSampleId(new SampleIdentifier(sampleIdentifier)); + creation.setUploadId(uploadId); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + assertResponseOK(response); + + try + { + getCreateAndGetDataSet(sessionToken, creation); + fail(); + } catch (UserFailureException e) + { + assertTrue(e.getMessage(), e.getMessage().contains("A dataset needs a type")); + } + } + + @Test + public void testCreateWithTypeNonexistent() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "IDONTEXIST"; + String sampleIdentifier = "/CISD/CP-TEST-1"; + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setSampleId(new SampleIdentifier(sampleIdentifier)); + creation.setUploadId(uploadId); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + assertResponseOK(response); + + try + { + getCreateAndGetDataSet(sessionToken, creation); + fail(); + } catch (UserFailureException e) + { + assertTrue(e.getMessage(), e.getMessage().contains("Object with EntityTypePermId = [IDONTEXIST, null] has not been found")); + } + } + + @Test + public void testCreateWithoutOwner() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "UNKNOWN"; + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setUploadId(uploadId); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + assertResponseOK(response); + + try + { + getCreateAndGetDataSet(sessionToken, creation); + fail(); + } catch (UserFailureException e) + { + assertTrue(e.getMessage(), e.getMessage().contains("A dataset needs either a sample or an experiment as an owner")); + } + } + + @Test + public void testCreateWithSampleNonexistent() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "UNKNOWN"; + String sampleIdentifier = "/IDONTEXIST/IDONTEXIST"; + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setSampleId(new SampleIdentifier(sampleIdentifier)); + creation.setUploadId(uploadId); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + assertResponseOK(response); + + try + { + getCreateAndGetDataSet(sessionToken, creation); + fail(); + } catch (UserFailureException e) + { + assertTrue(e.getMessage(), e.getMessage().contains("Object with SampleIdentifier = [/IDONTEXIST/IDONTEXIST] has not been found")); + } + } + + @Test + public void testCreateWithSampleIdentifier() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "UNKNOWN"; + String sampleIdentifier = "/CISD/CP-TEST-1"; + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setSampleId(new SampleIdentifier(sampleIdentifier)); + creation.setUploadId(uploadId); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + assertResponseOK(response); + + DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); + + assertEquals(dataSetType, dataSet.getType().getCode()); + assertEquals(sampleIdentifier, dataSet.getSample().getIdentifier().getIdentifier()); + } + + @Test + public void testCreateWithSamplePermId() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "UNKNOWN"; + String samplePermId = "200902091219327-1025"; + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setSampleId(new SamplePermId(samplePermId)); + creation.setUploadId(uploadId); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + assertResponseOK(response); + + DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); + + assertEquals(dataSetType, dataSet.getType().getCode()); + assertEquals(samplePermId, dataSet.getSample().getPermId().getPermId()); + } + + @Test + public void testCreateWithExperimentNonexistent() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "UNKNOWN"; + String experimentIdentifier = "/IDONTEXIST/IDONTEXIST/IDONTEXIST"; + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); + creation.setUploadId(uploadId); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + assertResponseOK(response); + + try + { + getCreateAndGetDataSet(sessionToken, creation); + fail(); + } catch (UserFailureException e) + { + assertTrue(e.getMessage(), + e.getMessage().contains("Object with ExperimentIdentifier = [/IDONTEXIST/IDONTEXIST/IDONTEXIST] has not been found")); + } + } + + @Test + public void testCreateWithExperimentIdentifier() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "UNKNOWN"; + String experimentIdentifier = "/CISD/NEMO/EXP1"; + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); + creation.setUploadId(uploadId); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + assertResponseOK(response); + + DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); + + assertEquals(dataSetType, dataSet.getType().getCode()); + assertEquals(experimentIdentifier, dataSet.getExperiment().getIdentifier().getIdentifier()); + } + + @Test + public void testCreateWithExperimentPermId() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "UNKNOWN"; + String experimentPermId = "200811050951882-1028"; + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setExperimentId(new ExperimentPermId(experimentPermId)); + creation.setUploadId(uploadId); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + assertResponseOK(response); + + DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); + + assertEquals(dataSetType, dataSet.getType().getCode()); + assertEquals(experimentPermId, dataSet.getExperiment().getPermId().getPermId()); + } + + @Test + public void testCreateWithProperties() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "HCS_IMAGE"; + String experimentIdentifier = "/CISD/NEMO/EXP1"; + + Map<String, String> properties = new HashMap<String, String>(); + properties.put("COMMENT", "test comment"); + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); + creation.setUploadId(uploadId); + creation.setProperties(properties); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + assertResponseOK(response); + + DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); + + assertEquals(dataSetType, dataSet.getType().getCode()); + assertEquals(experimentIdentifier, dataSet.getExperiment().getIdentifier().getIdentifier()); + assertEquals("test comment", dataSet.getProperty("COMMENT")); + } + + @Test + public void testCreateWithParentIds() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "UNKNOWN"; + String experimentIdentifier = "/CISD/NEMO/EXP1"; + IDataSetId parentId = new DataSetPermId("20081105092159111-1"); + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); + creation.setParentIds(Arrays.asList(parentId)); + creation.setUploadId(uploadId); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, new FileToUpload()); + assertResponseOK(response); + + DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); + + assertEquals(dataSetType, dataSet.getType().getCode()); + assertEquals(experimentIdentifier, dataSet.getExperiment().getIdentifier().getIdentifier()); + assertEquals(1, dataSet.getParents().size()); + assertEquals(parentId, dataSet.getParents().get(0).getPermId()); + } + + @Test + public void testCreateWithoutUploadId() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String dataSetType = "UNKNOWN"; + String experimentIdentifier = "/CISD/NEMO/EXP1"; + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); + + try + { + getCreateAndGetDataSet(sessionToken, creation); + fail(); + } catch (UserFailureException e) + { + assertTrue(e.getMessage(), e.getMessage().contains("Upload id cannot be null")); + } + } + + @Test + public void testCreateWithUploadIdThatContainsSlash() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String dataSetType = "UNKNOWN"; + String experimentIdentifier = "/CISD/NEMO/EXP1"; + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); + creation.setUploadId("iam/incorrect"); + + try + { + getCreateAndGetDataSet(sessionToken, creation); + fail(); + } catch (UserFailureException e) + { + assertTrue(e.getMessage(), e.getMessage().contains("Upload id must not contain '/'")); + } + } + + @Test + public void testCreateWithoutUpload() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "UNKNOWN"; + String experimentIdentifier = "/CISD/NEMO/EXP1"; + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); + creation.setUploadId(uploadId); + + try + { + getCreateAndGetDataSet(sessionToken, creation); + 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?")); + } + } + + @Test + public void testCreateWithSingleFile() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "UNKNOWN"; + String experimentIdentifier = "/CISD/NEMO/EXP1"; + + FileToUpload file = new FileToUpload("file", "test.txt", "test content"); + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); + creation.setUploadId(uploadId); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, false, file); + assertResponseOK(response); + + DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); + + assertEquals(dataSetType, dataSet.getType().getCode()); + assertEquals(experimentIdentifier, dataSet.getExperiment().getIdentifier().getIdentifier()); + + List<DownloadedFile> files = downloadFiles(sessionToken, dataSet.getPermId()); + assertEquals(3, files.size()); + + assertDirectory(files.get(0), ""); + assertDirectory(files.get(1), "original"); + assertFile(files.get(2), "original/test.txt", file.content); + } + + @Test + public void testCreateWithMultipleFiles() 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", "test1.txt", "test1 content"); + FileToUpload file2 = new FileToUpload("file2", "test2.txt", "test2 content"); + FileToUpload file3 = new FileToUpload("file3", "folder/test3.txt", "test3 content"); + FileToUpload file4 = new FileToUpload("file4", "folder/test4.txt", "test4 content"); + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); + creation.setUploadId(uploadId); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, false, file1, file2, file3, file4); + assertResponseOK(response); + + DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); + + assertEquals(dataSetType, dataSet.getType().getCode()); + assertEquals(experimentIdentifier, dataSet.getExperiment().getIdentifier().getIdentifier()); + + List<DownloadedFile> files = downloadFiles(sessionToken, dataSet.getPermId()); + assertEquals(8, files.size()); + + assertDirectory(files.get(0), ""); + assertDirectory(files.get(1), "original"); + assertDirectory(files.get(2), "original/upload"); + assertDirectory(files.get(3), "original/upload/folder"); + assertFile(files.get(4), "original/upload/folder/test3.txt", file3.content); + assertFile(files.get(5), "original/upload/folder/test4.txt", file4.content); + assertFile(files.get(6), "original/upload/test1.txt", file1.content); + assertFile(files.get(7), "original/upload/test2.txt", file2.content); + } + + @Test + public void testCreateWithIgnoreFilePathDefault() 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", "test1.txt", "test1 content"); + FileToUpload file2 = new FileToUpload("file2", "folder/test2.txt", "test2 content"); + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); + creation.setUploadId(uploadId); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, null, file1, file2); + assertResponseOK(response); + + DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); + + assertEquals(dataSetType, dataSet.getType().getCode()); + assertEquals(experimentIdentifier, dataSet.getExperiment().getIdentifier().getIdentifier()); + + List<DownloadedFile> files = downloadFiles(sessionToken, dataSet.getPermId()); + assertEquals(5, files.size()); + + assertDirectory(files.get(0), ""); + assertDirectory(files.get(1), "original"); + assertDirectory(files.get(2), "original/upload"); + assertFile(files.get(3), "original/upload/test1.txt", file1.content); + assertFile(files.get(4), "original/upload/test2.txt", file2.content); + } + + @Test + public void testCreateWithIgnoreFilePathSetToFalse() 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", "test1.txt", "test1 content"); + FileToUpload file2 = new FileToUpload("file2", "folder/test2.txt", "test2 content"); + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); + creation.setUploadId(uploadId); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, false, file1, file2); + assertResponseOK(response); + + DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); + + assertEquals(dataSetType, dataSet.getType().getCode()); + assertEquals(experimentIdentifier, dataSet.getExperiment().getIdentifier().getIdentifier()); + + List<DownloadedFile> files = downloadFiles(sessionToken, dataSet.getPermId()); + assertEquals(6, files.size()); + + assertDirectory(files.get(0), ""); + assertDirectory(files.get(1), "original"); + assertDirectory(files.get(2), "original/upload"); + assertDirectory(files.get(3), "original/upload/folder"); + assertFile(files.get(4), "original/upload/folder/test2.txt", file2.content); + assertFile(files.get(5), "original/upload/test1.txt", file1.content); + } + + @Test + public void testCreateWithMultipleAttempts() throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "UNKNOWN"; + String experimentIdentifier = "/CISD/NEMO/EXP1"; + + Map<String, String> properties = new HashMap<String, String>(); + properties.put("IDONTEXIST", "test value"); + + FileToUpload file = new FileToUpload("file", "test.txt", "test content"); + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); + creation.setProperties(properties); + creation.setUploadId(uploadId); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, file); + assertResponseOK(response); + + // first attempt + try + { + getCreateAndGetDataSet(sessionToken, creation); + fail("Creation should have failed because of nonexistent 'IDONTEXIST' property"); + } catch (Exception e) + { + String fullStackTrace = ExceptionUtils.getFullStackTrace(e); + assertTrue(fullStackTrace, fullStackTrace.contains("Property type with code 'IDONTEXIST' does not exist!")); + } + + // second attempt + try + { + getCreateAndGetDataSet(sessionToken, creation); + fail("Creation should have failed as uploaded file should have been removed during the first attempt"); + } catch (Exception e) + { + String fullStackTrace = ExceptionUtils.getFullStackTrace(e); + assertTrue(fullStackTrace, fullStackTrace.contains("The folder for the upload id " + uploadId + " could not be found")); + } + } + + @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER) + public void testCreateWithProjectAuthorization(ProjectAuthorizationUser user) throws Exception + { + String sessionToken = as.login(user.getUserId(), PASSWORD); + + String uploadId = UUID.randomUUID().toString(); + String dataSetType = "UNKNOWN"; + String experimentIdentifier = "/TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST"; + + FileToUpload file = new FileToUpload("file", "test.txt", "test content"); + + UploadedDataSetCreation creation = new UploadedDataSetCreation(); + creation.setTypeId(new EntityTypePermId(dataSetType)); + creation.setExperimentId(new ExperimentIdentifier(experimentIdentifier)); + creation.setUploadId(uploadId); + + ContentResponse response = uploadFiles(sessionToken, uploadId, dataSetType, true, file); + assertResponseOK(response); + + if (user.isDisabledProjectUser()) + { + try + { + getCreateAndGetDataSet(sessionToken, creation); + } catch (UserFailureException e) + { + assertTrue(e.getMessage(), e.getMessage().contains( + "None of method roles '[PROJECT_OBSERVER, PROJECT_USER, PROJECT_POWER_USER, PROJECT_ADMIN, SPACE_ADMIN, INSTANCE_ADMIN, SPACE_POWER_USER, SPACE_USER, SPACE_OBSERVER, INSTANCE_OBSERVER, SPACE_ETL_SERVER, INSTANCE_ETL_SERVER]' could be found in roles of user")); + } + } else if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser()) + { + DataSet dataSet = getCreateAndGetDataSet(sessionToken, creation); + + assertEquals(dataSetType, dataSet.getType().getCode()); + assertEquals(experimentIdentifier, dataSet.getExperiment().getIdentifier().getIdentifier()); + + List<DownloadedFile> files = downloadFiles(sessionToken, dataSet.getPermId()); + assertEquals(3, files.size()); + + assertDirectory(files.get(0), ""); + assertDirectory(files.get(1), "original"); + assertFile(files.get(2), "original/test.txt", file.content); + } else + { + try + { + getCreateAndGetDataSet(sessionToken, creation); + } catch (UserFailureException e) + { + assertTrue(e.getMessage(), + e.getMessage().contains("Object with ExperimentIdentifier = [/TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST] has not been found")); + } + } + } + + private ContentResponse uploadFiles(String sessionToken, String uploadId, String dataSetType, Boolean ignoreFilePath, + FileToUpload... filesToUpload) + throws InterruptedException, TimeoutException, ExecutionException + { + HttpClient client = JettyHttpClientFactory.getHttpClient(); + MultiPartContentProvider multiPart = new MultiPartContentProvider(); + + for (FileToUpload fileToUpload : filesToUpload) + { + multiPart.addFilePart(fileToUpload.fieldName, fileToUpload.fileName, new StringContentProvider(fileToUpload.content), null); + } + + multiPart.close(); + + Request request = client.newRequest(SERVICE_URL).method(HttpMethod.POST); + + if (sessionToken != null) + { + request.param(StoreShareFileUploadServlet.SESSION_ID_PARAM, sessionToken); + } + if (uploadId != null) + { + request.param(StoreShareFileUploadServlet.UPLOAD_ID_PARAM, uploadId); + } + if (ignoreFilePath != null) + { + request.param(StoreShareFileUploadServlet.IGNORE_FILE_PATH_PARAM, String.valueOf(ignoreFilePath)); + } + if (dataSetType != null) + { + request.param(StoreShareFileUploadServlet.DATA_SET_TYPE_PARAM, dataSetType); + } + request.content(multiPart); + return request.send(); + } + + private DataSet getCreateAndGetDataSet(String sessionToken, UploadedDataSetCreation creation) + { + DataSetPermId permId = dss.createUploadedDataSet(sessionToken, creation); + assertNotNull(permId); + + DataSetFetchOptions fo = new DataSetFetchOptions(); + fo.withType(); + fo.withExperiment(); + fo.withSample(); + fo.withProperties(); + fo.withParents(); + + Map<IDataSetId, DataSet> dataSets = as.getDataSets(sessionToken, Arrays.asList(permId), fo); + DataSet dataSet = dataSets.get(permId); + assertNotNull(dataSet); + + return dataSet; + } + + private List<DownloadedFile> downloadFiles(String sessionToken, IDataSetId dataSetId) throws IOException + { + DataSetFileDownloadOptions options = new DataSetFileDownloadOptions(); + options.setRecursive(true); + + IDataSetFileId fileId = new DataSetFilePermId(dataSetId, ""); + + InputStream stream = dss.downloadFiles(sessionToken, Arrays.asList(fileId), options); + DataSetFileDownloadReader reader = new DataSetFileDownloadReader(stream); + + List<DownloadedFile> files = new ArrayList<DownloadedFile>(); + DataSetFileDownload download = null; + + while ((download = reader.read()) != null) + { + DownloadedFile file = new DownloadedFile(download.getDataSetFile(), IOUtils.toString(download.getInputStream())); + files.add(file); + } + + return files; + } + + private void assertDirectory(DownloadedFile actual, String expectedPath) + { + assertEquals(expectedPath, actual.file.getPath()); + assertEquals(true, actual.file.isDirectory()); + assertEquals(0, actual.file.getFileLength()); + assertEquals("", actual.content); + } + + private void assertFile(DownloadedFile actual, String expectedPath, String expectedFileContent) + { + assertEquals(expectedPath, actual.file.getPath()); + assertEquals(false, actual.file.isDirectory()); + assertEquals(expectedFileContent.length(), actual.file.getFileLength()); + assertEquals(expectedFileContent, actual.content); + } + + private void assertResponseOK(ContentResponse response) + { + int statusCode = response.getStatus(); + if (statusCode != HttpStatus.Code.OK.getCode()) + { + throw new RuntimeException("Status Code was " + statusCode + " instead of " + HttpStatus.Code.OK.getCode()); + } + } + + private void assertResponseError(ContentResponse response) + { + int statusCode = response.getStatus(); + if (statusCode != HttpStatus.Code.INTERNAL_SERVER_ERROR.getCode()) + { + throw new RuntimeException("Status Code was " + statusCode + " instead of " + HttpStatus.Code.INTERNAL_SERVER_ERROR.getCode()); + } + } + + private class FileToUpload + { + private String fieldName; + + private String fileName; + + private String content; + + public FileToUpload() + { + this("testFieldName", "testFileName", "testContent"); + } + + public FileToUpload(String fieldName, String fileName, String content) + { + this.fieldName = fieldName; + this.fileName = fileName; + this.content = content; + } + } + + private class DownloadedFile + { + private DataSetFile file; + + private String content; + + public DownloadedFile(DataSetFile file, String content) + { + this.file = file; + this.content = content; + } + + } + +} diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UploadAndCreateDataSetsTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UploadAndCreateDataSetsTest.java deleted file mode 100644 index 6cce8c6c82eeee7180f860e56b048402cb2f7fc8..0000000000000000000000000000000000000000 --- a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UploadAndCreateDataSetsTest.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2017 ETH Zuerich, SIS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ch.ethz.sis.openbis.generic.dss.systemtest.api.v3; - -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.net.MalformedURLException; -import java.util.Arrays; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.api.ContentProvider; -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.client.api.Request; -import org.eclipse.jetty.client.util.StringContentProvider; -import org.eclipse.jetty.http.HttpStatus; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.id.CreationId; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSetKind; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.create.DataSetCreation; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.create.PhysicalDataCreation; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.FileFormatTypePermId; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.ProprietaryStorageFormatPermId; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.RelativeLocationLocatorTypePermId; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.datastore.id.DataStorePermId; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.id.EntityTypePermId; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.ExperimentIdentifier; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.dataset.create.FullDataSetCreation; -import ch.ethz.sis.openbis.generic.server.dssapi.v3.upload.StoreShareFileUploadServlet; -import ch.systemsx.cisd.common.filesystem.FileUtilities; -import ch.systemsx.cisd.common.http.JettyHttpClientFactory; -import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; -import ch.systemsx.cisd.openbis.generic.shared.util.TestInstanceHostUtils; - -/** - * @author Ganime Betul Akin - */ -public class UploadAndCreateDataSetsTest extends AbstractFileTest -{ - private static final String SERVICE_URL = TestInstanceHostUtils.getDSSUrl() + "/datastore_server/" - + "store_share_file_upload"; - - protected StoreShareFileUploadServlet servlet; - - protected String sessionToken; - - protected static final String UNIT_TEST_WORKING_DIRECTORY = "unit-test-wd"; - - protected static final String TARGETS_DIRECTORY = "targets"; - - protected static final File UNIT_TEST_ROOT_DIRECTORY = new File(TARGETS_DIRECTORY - + File.separator + UNIT_TEST_WORKING_DIRECTORY); - - /** - * Create a dummy file of size <code>length</code> bytes. - */ - private File createDummyFile(File dir, String name, int length) throws IOException - { - File dummyFile = new File(dir, name); - dummyFile.createNewFile(); - PrintWriter out = new PrintWriter(dummyFile); - for (int i = 0; i < length; ++i) - { - out.append('a'); - } - out.flush(); - out.close(); - - return dummyFile; - } - - @Test - public void testFileUpload() - { - HttpClient client = JettyHttpClientFactory.getHttpClient(); - Request requestEntity = client.newRequest(SERVICE_URL).method("POST"); - - String sessionToken = gis.tryToAuthenticateForAllServices(TEST_USER, PASSWORD); - - String uploadId = "1357"; - requestEntity.param("uploadID", uploadId); - String dataSetType = "UNKNOWN"; - requestEntity.param("dataSetType", dataSetType); - requestEntity.param("sessionID", sessionToken); - - final String CRLF = "\r\n"; - final String BOUNDARY = "MMMMM___MP_BOUNDARY___MMMMM"; - final String FILE_PART_NAME = "fastaFile"; - - File fileToUpload; - try - { - fileToUpload = createDummyFile(workingDirectory, "to-upload.txt", 80); - String fileContent = FileUtilities.loadToString(fileToUpload); - ContentProvider content = new StringContentProvider("--" + BOUNDARY + CRLF - + "Content-Disposition: form-data; name=\"" + FILE_PART_NAME + "\"; filename=\"" - + fileToUpload.getName() + "\"" + CRLF - + "Content-Type: application/octet-stream" + CRLF + CRLF - + fileContent + CRLF + "--" + BOUNDARY + "--" + CRLF); - requestEntity.content(content, "multipart/form-data; boundary=" + BOUNDARY); - - ContentResponse contentResponse; - contentResponse = requestEntity.send(); - int statusCode = contentResponse.getStatus(); - - if (statusCode != HttpStatus.Code.OK.getCode()) - { - throw new RuntimeException("Status Code was " + statusCode + " instead of " + HttpStatus.Code.OK.getCode()); - } - - DataSetCreation metadataCreation = new DataSetCreation(); - metadataCreation.setTypeId(new EntityTypePermId(dataSetType)); - metadataCreation.setDataSetKind(DataSetKind.PHYSICAL);; - metadataCreation.setAutoGeneratedCode(true); - metadataCreation.setExperimentId(new ExperimentIdentifier("/CISD/NEMO/EXP1")); - metadataCreation.setDataStoreId(new DataStorePermId("STANDARD")); - metadataCreation.setCreationId(new CreationId(uploadId)); - - String code = UUID.randomUUID().toString(); - PhysicalDataCreation physicalCreation = new PhysicalDataCreation(); - physicalCreation.setLocation("test/location/" + code); - physicalCreation.setFileFormatTypeId(new FileFormatTypePermId("TIFF")); - physicalCreation.setLocatorTypeId(new RelativeLocationLocatorTypePermId()); - physicalCreation.setStorageFormatId(new ProprietaryStorageFormatPermId()); - - metadataCreation.setPhysicalData(physicalCreation); - FullDataSetCreation newDataSet = new FullDataSetCreation(); - - newDataSet.setMetadataCreation(metadataCreation); - List<DataSetPermId> createDataSets = dss.createDataSets(sessionToken, Arrays.asList(newDataSet)); - } catch (InterruptedException | TimeoutException | ExecutionException | IOException e) - { - e.printStackTrace(); - } - } - - @BeforeMethod - public void beforeMethod() throws MalformedURLException - { - } -} diff --git a/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/common.js b/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/common.js index dfb0e81c8e69168b0bd20b052a08a13b28cc1e10..64a1bfc7b32d847c222ab0f2ada9240bd79a53b2 100644 --- a/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/common.js +++ b/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/common.js @@ -39,6 +39,7 @@ define([ 'jquery', 'openbis', 'underscore', 'test/dtos' ], function($, defaultOp this.SemanticAnnotationCreation = dtos.SemanticAnnotationCreation; this.DataSetCreation = dtos.DataSetCreation; this.FullDataSetCreation = dtos.FullDataSetCreation; + this.UploadedDataSetCreation = dtos.UploadedDataSetCreation; this.DataSetFileCreation = dtos.DataSetFileCreation; this.LinkedDataCreation = dtos.LinkedDataCreation; this.ContentCopyCreation = dtos.ContentCopyCreation; @@ -294,7 +295,7 @@ define([ 'jquery', 'openbis', 'underscore', 'test/dtos' ], function($, defaultOp this.getDtos = function() { return dtos; } - + this.getId = function(entity) { if (typeof entity["getPermId"] === 'function') { return entity.getPermId(); @@ -389,6 +390,33 @@ define([ 'jquery', 'openbis', 'underscore', 'test/dtos' ], function($, defaultOp }); }.bind(this); + this.waitUntilIndexed = function(facade, dataSetCode, timeout) { + var c = this; + var dfd = $.Deferred(); + var start = new Date().getTime(); + + var searchAndWait = function() { + var criteria = new c.DataSetSearchCriteria(); + criteria.withPermId().thatEquals(dataSetCode); + + facade.searchDataSets(criteria, c.createDataSetFetchOptions()).then(function(result) { + if (result.getTotalCount() == 0) { + var now = new Date().getTime(); + if (now - start > timeout) { + c.fail("Data set " + dataSetCode + " not indexed after " + timeout + " msec."); + dfd.reject(); + } else { + setTimeout(searchAndWait, 1000); + } + } else { + dfd.resolve(); + } + }); + }; + searchAndWait(); + return dfd.promise(); + }.bind(this); + this.getResponseFromJSTestAggregationService = function(facade, params, callback) { var c = this; return $.ajax({ @@ -454,7 +482,7 @@ define([ 'jquery', 'openbis', 'underscore', 'test/dtos' ], function($, defaultOp return permIds[0]; }); }.bind(this); - + this.createExternalDms = function(facade) { var c = this; var creation = new dtos.ExternalDmsCreation(); @@ -491,12 +519,12 @@ define([ 'jquery', 'openbis', 'underscore', 'test/dtos' ], function($, defaultOp var c = this; var creation = new dtos.AuthorizationGroupCreation(); creation.setCode(c.generateId("AUTHORIZATION_GROUP")); - creation.setUserIds([new c.PersonPermId("power_user")]); + creation.setUserIds([ new c.PersonPermId("power_user") ]); return facade.createAuthorizationGroups([ creation ]).then(function(permIds) { return permIds[0]; }); }.bind(this); - + this.createRoleAssignment = function(facade, isUser) { var c = this; return c.createSpace(facade).then(function(spaceId) { @@ -513,7 +541,7 @@ define([ 'jquery', 'openbis', 'underscore', 'test/dtos' ], function($, defaultOp }); }); }.bind(this); - + this.createPerson = function(facade) { var c = this; var creation = new dtos.PersonCreation(); @@ -522,7 +550,7 @@ define([ 'jquery', 'openbis', 'underscore', 'test/dtos' ], function($, defaultOp return permIds[0]; }); }.bind(this); - + this.createSemanticAnnotation = function(facade) { var c = this; var creation = new dtos.SemanticAnnotationCreation(); @@ -662,14 +690,14 @@ define([ 'jquery', 'openbis', 'underscore', 'test/dtos' ], function($, defaultOp return groups[id]; }); }.bind(this); - + this.findRoleAssignment = function(facade, id) { var c = this; return facade.getRoleAssignments([ id ], c.createRoleAssignmentFetchOptions()).then(function(assignments) { return assignments[id]; }); }.bind(this); - + this.findPerson = function(facade, id) { var c = this; return facade.getPersons([ id ], c.createPersonFetchOptions()).then(function(persons) { @@ -767,7 +795,7 @@ define([ 'jquery', 'openbis', 'underscore', 'test/dtos' ], function($, defaultOp options.setReason("test reason"); return facade.deleteVocabularyTerms([ id ], options); }.bind(this); - + this.replaceVocabularyTerm = function(facade, id) { var c = this; var options = new dtos.VocabularyTermDeletionOptions(); @@ -789,14 +817,14 @@ define([ 'jquery', 'openbis', 'underscore', 'test/dtos' ], function($, defaultOp options.setReason("test reason"); return facade.deleteAuthorizationGroups([ id ], options); }.bind(this); - + this.deleteRoleAssignment = function(facade, id) { var c = this; var options = new dtos.RoleAssignmentDeletionOptions(); options.setReason("test reason"); return facade.deleteRoleAssignments([ id ], options); }.bind(this); - + this.deleteOperationExecution = function(facade, id) { var c = this; var options = new dtos.OperationExecutionDeletionOptions(); @@ -1009,7 +1037,7 @@ define([ 'jquery', 'openbis', 'underscore', 'test/dtos' ], function($, defaultOp rafo.withProject().withSpace(); return fo; }; - + this.createRoleAssignmentFetchOptions = function() { var fo = new dtos.RoleAssignmentFetchOptions(); fo.withProject(); @@ -1019,7 +1047,7 @@ define([ 'jquery', 'openbis', 'underscore', 'test/dtos' ], function($, defaultOp fo.withRegistrator(); return fo; }; - + this.createPersonFetchOptions = function() { var fo = new dtos.PersonFetchOptions(); fo.withSpace(); @@ -1027,7 +1055,7 @@ define([ 'jquery', 'openbis', 'underscore', 'test/dtos' ], function($, defaultOp fo.withRegistrator(); return fo; }; - + this.createPropertyTypeFetchOptions = function() { var fo = new dtos.PropertyTypeFetchOptions(); fo.withVocabulary(); diff --git a/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/dtos.js b/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/dtos.js index 808675c41aba52a2a539becd4b13a2a1d361619a..d4988a8c7eb68330c80975c02b400d20e731f437 100644 --- a/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/dtos.js +++ b/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/dtos.js @@ -656,6 +656,7 @@ var sources = [ 'as/dto/operation/SynchronousOperationExecutionResults', 'dss/dto/dataset/create/FullDataSetCreation', + 'dss/dto/dataset/create/UploadedDataSetCreation', 'dss/dto/datasetfile/DataSetFile', 'dss/dto/datasetfile/create/DataSetFileCreation', 'dss/dto/datasetfile/fetchoptions/DataSetFileSortOptions', 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 7c6298b5f4dbc8fa7531a925899dfa31120f4b0a..fb9a6faa84a93f856b8830718fa9156412608f1a 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 @@ -295,23 +295,6 @@ define([ 'jquery', 'underscore', 'openbis', 'test/openbis-execute-operations', ' }); } - var waitUntilIndexed = function(facade, dataSetCode, timeout, action) { - if (timeout < 0) { - c.fail("Data set " + dataSetCode + " after " + timeout + " msec."); - } - setTimeout(function() { - var criteria = new c.DataSetSearchCriteria(); - criteria.withPermId().thatEquals(dataSetCode); - facade.searchDataSets(criteria, c.createDataSetFetchOptions()).then(function(result) { - if (result.getTotalCount() == 0) { - waitUntilIndexed(facade, dataSetCode, timeout - 1000, action); - } else { - action(); - } - }); - }, 1000) - }; - var fCheck = function(dataSet, facade) { c.assertEqual(dataSet.getType().getCode(), "LINK_TYPE", "Data set type"); var contentCopies = dataSet.getLinkedData().getContentCopies(); @@ -321,7 +304,7 @@ define([ 'jquery', 'underscore', 'openbis', 'test/openbis-execute-operations', ' c.assertEqual(contentCopy.getPath(), "/my/path", "Content copy path"); var dfd = $.Deferred() var dataSetCode = dataSet.getCode(); - waitUntilIndexed(facade, dataSetCode, 10000, function() { + c.waitUntilIndexed(facade, dataSetCode, 10000).then(function() { var criteria = new c.DataSetFileSearchCriteria(); criteria.withDataSet().withCode().thatEquals(dataSet.getCode()); facade.getDataStoreFacade("DSS1").searchFiles(criteria, c.createDataSetFileFetchOptions()).then(function(result) { @@ -506,7 +489,7 @@ define([ 'jquery', 'underscore', 'openbis', 'test/openbis-execute-operations', ' vocabularyCreation.setUrlTemplate("https://www.ethz.ch"); var termCreation = new c.VocabularyTermCreation(); termCreation.setCode("alpha"); - vocabularyCreation.setTerms([termCreation]); + vocabularyCreation.setTerms([ termCreation ]); return facade.createVocabularies([ vocabularyCreation ]); } @@ -525,7 +508,7 @@ define([ 'jquery', 'underscore', 'openbis', 'test/openbis-execute-operations', ' QUnit.test("createVocabularyTerms()", function(assert) { var c = new common(assert, openbis); var code = c.generateId("VOCABULARY_TERM"); - + var fCreate = function(facade) { var termCreation = new c.VocabularyTermCreation(); termCreation.setVocabularyId(new c.VocabularyPermId("TEST-VOCABULARY")); @@ -536,7 +519,7 @@ define([ 'jquery', 'underscore', 'openbis', 'test/openbis-execute-operations', ' termCreation.setPreviousTermId(new c.VocabularyTermPermId("TEST-TERM-1", "TEST-VOCABULARY")) return facade.createVocabularyTerms([ termCreation ]); } - + var fCheck = function(term) { c.assertEqual(term.getCode(), code, "Term code"); c.assertEqual(term.getVocabulary().getCode(), "TEST-VOCABULARY", "Term vocabulary code"); @@ -545,10 +528,10 @@ define([ 'jquery', 'underscore', 'openbis', 'test/openbis-execute-operations', ' c.assertEqual(term.isOfficial(), true, "Term official"); c.assertEqual(term.getOrdinal(), 2, "Term ordinal"); } - + testCreate(c, fCreate, c.findVocabularyTerm, fCheck); }); - + QUnit.test("createExternalDataManagementSystem()", function(assert) { var c = new common(assert, openbis); var code = c.generateId("EDMS"); @@ -598,15 +581,15 @@ define([ 'jquery', 'underscore', 'openbis', 'test/openbis-execute-operations', ' var c = new common(assert, openbis); var code = c.generateId("AUTHORIZATION_GROUP"); var description = "Description of " + code; - + var fCreate = function(facade) { var creation = new c.AuthorizationGroupCreation(); creation.setCode(code); creation.setDescription(description); - creation.setUserIds([new c.PersonPermId("power_user")]); + creation.setUserIds([ new c.PersonPermId("power_user") ]); return facade.createAuthorizationGroups([ creation ]); } - + var fCheck = function(group) { c.assertEqual(group.getCode(), code, "Code"); c.assertEqual(group.getDescription(), description, "Description"); @@ -616,54 +599,54 @@ define([ 'jquery', 'underscore', 'openbis', 'test/openbis-execute-operations', ' users.sort(); c.assertEqual(users.toString(), "power_user", "Users"); } - + testCreate(c, fCreate, c.findAuthorizationGroup, fCheck); }); - + QUnit.test("createRoleAssignments() for space user", function(assert) { var c = new common(assert, openbis); - + var fCreate = function(facade) { return c.createSpace(facade).then(function(spaceId) { var creation = new c.RoleAssignmentCreation(); creation.setRole(c.Role.POWER_USER); creation.setUserId(new c.PersonPermId("power_user")); creation.setSpaceId(spaceId); - return facade.createRoleAssignments([creation]); + return facade.createRoleAssignments([ creation ]); }); } - + var fCheck = function(roleAssignment) { c.assertEqual(roleAssignment.getUser().getUserId(), "power_user", "User"); c.assertEqual(roleAssignment.getRole(), c.Role.POWER_USER, "Role"); c.assertEqual(roleAssignment.getRoleLevel(), c.RoleLevel.SPACE, "Role level"); c.assertEqual(roleAssignment.getRegistrator().getUserId(), "openbis_test_js", "Registrator"); } - + testCreate(c, fCreate, c.findRoleAssignment, fCheck); }); - + QUnit.test("createPersons()", function(assert) { var c = new common(assert, openbis); var userId = c.generateId("user"); - + var fCreate = function(facade) { var personCreation = new c.PersonCreation(); personCreation.setUserId(userId); personCreation.setHomeSpaceId(new c.SpacePermId("TEST")) return facade.createPersons([ personCreation ]); } - + var fCheck = function(person) { c.assertEqual(person.getUserId(), userId, "User id"); c.assertEqual(person.getRegistrator().getUserId(), "openbis_test_js", "Registrator"); c.assertEqual(person.isActive(), true, "User active"); c.assertEqual(person.getSpace().getCode(), "TEST", "Home space"); } - + testCreate(c, fCreate, c.findPerson, fCheck); }); - + var createSemanticAnnotationCreation = function(c) { var creation = new c.SemanticAnnotationCreation(); creation.setPredicateOntologyId("jsPredicateOntologyId"); @@ -737,6 +720,71 @@ define([ 'jquery', 'underscore', 'openbis', 'test/openbis-execute-operations', ' testCreate(c, fCreate, c.findSemanticAnnotation, fCheck); }); + QUnit.test("createUploadedDataSet()", function(assert) { + var c = new common(assert, openbis); + + var fCreate = function(facade) { + + // unfortunately old Firefox that is used together with our + // 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" + + "------WebKitFormBoundary7MA4YWxkTrZu0gW--"; + + var dataStoreFacade = facade.getDataStoreFacade("DSS1"); + + return dataStoreFacade.createDataSetUpload("UNKNOWN").then(function(upload) { + return $.ajax({ + url : upload.url, + type : "POST", + processData : false, + contentType : "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW", + data : formData + }).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.setExperimentId(experimentPermId); + creation.setProperty("DESCRIPTION", "test description"); + creation.setParentIds([ new c.DataSetPermId("20130424111751432-431") ]); + return dataStoreFacade.createUploadedDataSet(creation).then(function(permId) { + return [ permId ]; + }) + }); + }); + }); + } + + var fCheck = function(dataSet, facade) { + return c.waitUntilIndexed(facade, dataSet.getCode(), 10000).then(function() { + var dataStoreFacade = facade.getDataStoreFacade("DSS1"); + + var criteria = new c.DataSetFileSearchCriteria(); + criteria.withDataSet().withCode().thatEquals(dataSet.getCode()); + + return dataStoreFacade.searchFiles(criteria, c.createDataSetFileFetchOptions()).then(function(result) { + var files = result.getObjects(); + c.assertEqual(files.length, 5, "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(dataSet.getType().getCode(), "UNKNOWN", "Type code"); + c.assertEqual(dataSet.getProperty("DESCRIPTION"), "test description", "'DESCRIPTION' property value"); + c.assertEqual(dataSet.getParents().length, 1, "Number of parents"); + c.assertEqual(dataSet.getParents()[0].getCode(), "20130424111751432-431", "Parent code"); + }); + }); + } + + testCreate(c, fCreate, c.findDataSet, fCheck); + }); + } return function() { diff --git a/js-test/servers/common/datastore_server/etc/service.properties b/js-test/servers/common/datastore_server/etc/service.properties index ce0ee81e53d5bf8feb58240e47f3f55c5d4ab83d..a4f556253edf350dcab9eb055c264f4528829979 100644 --- a/js-test/servers/common/datastore_server/etc/service.properties +++ b/js-test/servers/common/datastore_server/etc/service.properties @@ -148,7 +148,7 @@ default-dropbox.incoming-data-completeness-condition = auto-detection default-dropbox.top-level-data-set-handler = ch.systemsx.cisd.etlserver.registrator.api.v2.JavaTopLevelDataSetHandlerV2 default-dropbox.program-class = ch.systemsx.cisd.etlserver.registrator.DefaultDropbox default-dropbox.storage-processor = ch.systemsx.cisd.etlserver.DefaultStorageProcessor -default-dropbox.validation-script-path = ../core-plugins/default/default-validation-script.py +#default-dropbox.validation-script-path = ../core-plugins/default/default-validation-script.py # --------------------------------------------------------------------------- # Archiver configuration (optional) diff --git a/microservice-server/build.gradle b/microservice-server/build.gradle index 646dd1cdbfecdca95918ae4d6ebe6eea19cdf337..31097d3b24565f8e6900b88d4099481782a3e39d 100644 --- a/microservice-server/build.gradle +++ b/microservice-server/build.gradle @@ -6,7 +6,6 @@ task wrapper(type: Wrapper) { } repositories { - mavenCentral() ivy { ivyPattern "http://svnsis.ethz.ch/repos/cisd/ivy-repository/trunk/[organisation]/[module]/[revision]/ivy.xml" artifactPattern "http://svnsis.ethz.ch/repos/cisd/ivy-repository/trunk/[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]" diff --git a/microservice-server/gradle/wrapper/gradle-wrapper.properties b/microservice-server/gradle/wrapper/gradle-wrapper.properties index 3bde4b663e7fae0d3df1cddeb38898f41709b1b6..2df108562a21e0116bc037aeae24a5aa9efda179 100644 --- a/microservice-server/gradle/wrapper/gradle-wrapper.properties +++ b/microservice-server/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.5-bin.zip +distributionUrl=http\://svnsis.ethz.ch/repos/cisd/ivy-repository/trunk/gradle/distribution/4.5/gradle-4.5-bin.zip diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServiceForDataStoreServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServiceForDataStoreServer.java index 8f7c73228d5ee8a78a0052220d4db3333be6dcbb..58fa9e048e41f97db15ed61357a321d8b4d6e5cd 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServiceForDataStoreServer.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServiceForDataStoreServer.java @@ -17,6 +17,7 @@ package ch.systemsx.cisd.openbis.generic.server; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -34,8 +35,11 @@ import javax.servlet.http.HttpServletRequest; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.operation.IOperationResult; import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.Complete; import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSetKind; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.create.CreateDataSetsOperation; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.create.CreateDataSetsOperationResult; import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.create.DataSetCreation; import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.create.LinkedDataCreation; import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.create.PhysicalDataCreation; @@ -54,7 +58,7 @@ import ch.ethz.sis.openbis.generic.server.asapi.v3.context.IProgressListener; import ch.ethz.sis.openbis.generic.server.asapi.v3.context.IProgressStack; import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext; import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.OperationContext; -import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.dataset.ICreateDataSetExecutor; +import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.operation.IOperationsExecutor; import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sample.ListSampleTechIdByIdentifier; import ch.ethz.sis.openbis.generic.server.asapi.v3.utils.ExceptionUtils; import ch.rinn.restrictions.Private; @@ -334,7 +338,7 @@ public class ServiceForDataStoreServer extends AbstractCommonServer<IServiceForD private IManagedPropertyEvaluatorFactory managedPropertyEvaluatorFactory; @Autowired - private ICreateDataSetExecutor createDataSetExecutor; + private IOperationsExecutor operationsExecutor; private long timeout = 5; // minutes @@ -372,7 +376,7 @@ public class ServiceForDataStoreServer extends AbstractCommonServer<IServiceForD IDataStoreServiceRegistrator dataStoreServiceRegistrator, IDataStoreDataSourceManager dataSourceManager, ISessionManager<Session> sessionManagerForEntityOperation, - IManagedPropertyEvaluatorFactory managedPropertyEvaluatorFactory, ICreateDataSetExecutor createDataSetExecutor) + IManagedPropertyEvaluatorFactory managedPropertyEvaluatorFactory, IOperationsExecutor operationsExecutor) { super(authenticationService, sessionManager, daoFactory, propertiesBatchManager, boFactory); this.daoFactory = daoFactory; @@ -383,7 +387,7 @@ public class ServiceForDataStoreServer extends AbstractCommonServer<IServiceForD this.dataSourceManager = dataSourceManager; this.sessionManagerForEntityOperation = sessionManagerForEntityOperation; this.managedPropertyEvaluatorFactory = managedPropertyEvaluatorFactory; - this.createDataSetExecutor = createDataSetExecutor; + this.operationsExecutor = operationsExecutor; } @Override @@ -2676,9 +2680,9 @@ public class ServiceForDataStoreServer extends AbstractCommonServer<IServiceForD try { - List<DataSetPermId> ids = createDataSetExecutor.create(context, creations); - daoFactory.getSessionFactory().getCurrentSession().flush(); - return ids.size(); + CreateDataSetsOperation operation = new CreateDataSetsOperation(creations); + List<IOperationResult> results = operationsExecutor.execute(context, Arrays.asList(operation)); + return ((CreateDataSetsOperationResult) results.get(0)).getObjectIds().size(); } catch (Throwable t) { throw ExceptionUtils.create(context, t); diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/dss/dto/dataset/create/UploadedDataSetCreation.js b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/dss/dto/dataset/create/UploadedDataSetCreation.js new file mode 100644 index 0000000000000000000000000000000000000000..1ac569d45a7b85661b110af5160558d154ced8ba --- /dev/null +++ b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/dss/dto/dataset/create/UploadedDataSetCreation.js @@ -0,0 +1,71 @@ +define([ "stjs" ], function(stjs) { + var UploadedDataSetCreation = function() { + this.properties = {}; + }; + stjs.extend(UploadedDataSetCreation, null, [], function(constructor, prototype) { + prototype['@type'] = 'dss.dto.dataset.create.UploadedDataSetCreation'; + constructor.serialVersionUID = 1; + prototype.typeId = null; + prototype.experimentId = null; + prototype.sampleId = null; + prototype.properties = null; + prototype.parentIds = null; + prototype.uploadId = null; + + prototype.getTypeId = function() { + return this.typeId; + }; + prototype.setTypeId = function(typeId) { + this.typeId = typeId; + }; + prototype.getExperimentId = function() { + return this.experimentId; + }; + prototype.setExperimentId = function(experimentId) { + this.experimentId = experimentId; + }; + prototype.getSampleId = function() { + return this.sampleId; + }; + prototype.setSampleId = function(sampleId) { + this.sampleId = sampleId; + }; + prototype.getProperty = function(propertyName) { + return this.properties[propertyName]; + }; + prototype.setProperty = function(propertyName, propertyValue) { + this.properties[propertyName] = propertyValue; + }; + prototype.getProperties = function() { + return this.properties; + }; + prototype.setProperties = function(properties) { + this.properties = properties; + }; + prototype.getParentIds = function() { + return this.parentIds; + }; + prototype.setParentIds = function(parentIds) { + this.parentIds = parentIds; + }; + prototype.getUploadId = function() { + return this.uploadId; + }; + prototype.setUploadId = function(uploadId) { + this.uploadId = uploadId; + }; + }, { + typeId : "IEntityTypeId", + experimentId : "IExperimentId", + sampleId : "ISampleId", + properties : { + name : "Map", + arguments : [ null, null ] + }, + parentIds : { + name : "List", + arguments : [ "Object" ] + } + }); + return UploadedDataSetCreation; +}) \ 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 90b7be889102cb4846bc28632f6de54fccbf7fd0..58d75083fe395e7451e85d035c5f025c210f36d2 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 @@ -127,7 +127,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria }); } } - + this._createUrl = function(dataStore) { return dataStore.downloadUrl + "/datastore_server/rmi-data-store-server-v3.json"; } @@ -168,7 +168,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria }); }); } - + this.createDataSets = function(creations) { var thisFacade = this; var creationsByStore = {}; @@ -178,7 +178,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria if (dataStoreCode in creationsByStore) { creationsByStore[dataStoreCode].append(creation); } else { - creationsByStore[dataStoreCode] = [creation]; + creationsByStore[dataStoreCode] = [ creation ]; } } return this._getDataStores().then(function(dataStores) { @@ -210,6 +210,69 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria }); } + + this.createDataSetUpload = function(dataSetType) { + + var pad = function(value, length) { + var result = "" + value; + while (result.length < length) { + result = "0" + result; + } + return result; + } + + return this._getDataStores().then( + function(dataStores) { + var dfd = jquery.Deferred(); + + if (dataStores.length > 1) { + dfd.reject("Please specify exactly one data store"); + } else { + 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 + }); + } + + return dfd.promise(); + }); + } + + this.createUploadedDataSet = function(creation) { + var thisFacade = this; + return this._getDataStores().then(function(dataStores) { + if (dataStores.length > 1) { + var dfd = jquery.Deferred(); + dfd.reject("Please specify exactly one data store"); + return dfd.promise(); + } + + return facade._private.ajaxRequest({ + url : thisFacade._createUrl(dataStores[0]), + data : { + "method" : "createUploadedDataSet", + "params" : [ facade._private.sessionToken, creation ] + }, + returnType : { + name : "DataSetPermId" + } + }); + }); + } + } var facade = function(openbisUrl) { @@ -416,7 +479,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.createMaterials = function(creations) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -506,7 +569,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.createAuthorizationGroups = function(creations) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -521,7 +584,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.createRoleAssignments = function(creations) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -536,7 +599,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.createPersons = function(creations) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -551,7 +614,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.createSemanticAnnotations = function(creations) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -610,7 +673,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.updateSamples = function(updates) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -632,7 +695,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.updateDataSets = function(updates) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -654,7 +717,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.updateMaterials = function(updates) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -676,7 +739,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.updateExternalDataManagementSystems = function(updates) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -720,7 +783,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.updateAuthorizationGroups = function(updates) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -742,7 +805,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.updateOperationExecutions = function(updates) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -753,7 +816,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.updateSemanticAnnotations = function(updates) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -914,7 +977,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.getAuthorizationGroups = function(ids, fetchOptions) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -929,7 +992,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.getRoleAssignments = function(ids, fetchOptions) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -944,7 +1007,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.getPersons = function(ids, fetchOptions) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -959,7 +1022,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.getSemanticAnnotations = function(ids, fetchOptions) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -1148,7 +1211,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria returnType : "SearchResult" }); } - + this.searchVocabularyTerms = function(criteria, fetchOptions) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -1172,7 +1235,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria returnType : "SearchResult" }); } - + this.searchAuthorizationGroups = function(criteria, fetchOptions) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -1196,7 +1259,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria returnType : "SearchResult" }); } - + this.searchPersons = function(criteria, fetchOptions) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -1208,7 +1271,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria returnType : "SearchResult" }); } - + this.searchCustomASServices = function(criteria, fetchOptions) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -1268,7 +1331,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria returnType : "SearchResult" }); } - + this.searchPropertyTypes = function(criteria, fetchOptions) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -1417,7 +1480,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.deleteTags = function(ids, deletionOptions) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -1439,7 +1502,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.deleteRoleAssignments = function(ids, deletionOptions) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -1450,7 +1513,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.deleteOperationExecutions = function(ids, deletionOptions) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -1461,7 +1524,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.deleteSemanticAnnotations = function(ids, deletionOptions) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -1571,7 +1634,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria url : openbisUrl, data : { "method" : "setWebAppSettings", - "params" : [ thisFacade._private.sessionToken, webAppSettings] + "params" : [ thisFacade._private.sessionToken, webAppSettings ] } }); } @@ -1582,11 +1645,11 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria url : openbisUrl, data : { "method" : "getWebAppSettings", - "params" : [ thisFacade._private.sessionToken, webAppId] + "params" : [ thisFacade._private.sessionToken, webAppId ] } }); } - + this.createPermIdStrings = function(amount) { var thisFacade = this; return thisFacade._private.ajaxRequest({ @@ -1597,7 +1660,7 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria } }); } - + this.getDataStoreFacade = function() { var dataStoreCodes = []; for (var i = 0; i < arguments.length; i++) { diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/ETLServiceTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/ETLServiceTest.java index 0e024010f360f05ee3961eca2182d9d1665e1fbd..75b4b9d84928ed534455fedd0870c2e27ae932df 100644 --- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/ETLServiceTest.java +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/ETLServiceTest.java @@ -36,8 +36,9 @@ import org.jmock.Expectations; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.create.CreateDataSetsOperationResult; import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext; -import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.dataset.ICreateDataSetExecutor; +import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.operation.IOperationsExecutor; import ch.rinn.restrictions.Friend; import ch.systemsx.cisd.authentication.ISessionManager; import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; @@ -184,7 +185,7 @@ public class ETLServiceTest extends AbstractServerTestCase private IManagedPropertyEvaluatorFactory managedPropertyEvaluatorFactory; - private ICreateDataSetExecutor createDataSetExecutor; + private IOperationsExecutor operationsExecutor; private PersonPE sessionPerson; @@ -209,7 +210,7 @@ public class ETLServiceTest extends AbstractServerTestCase sessionPerson = new PersonPE(); session.setPerson(sessionPerson); managedPropertyEvaluatorFactory = new ManagedPropertyEvaluatorFactory(null, new TestJythonEvaluatorPool()); - createDataSetExecutor = context.mock(ICreateDataSetExecutor.class); + operationsExecutor = context.mock(IOperationsExecutor.class); prepareDataSetRegistrationCache(); } @@ -1074,8 +1075,7 @@ public class ETLServiceTest extends AbstractServerTestCase final DataSetBatchUpdatesDTO dataSetUpdate = new DataSetBatchUpdatesDTO(); dataSetUpdate.setDatasetId(CommonTestUtils.TECH_ID); dataSetUpdate.setFileFormatTypeCode("new-file-format"); - dataSetUpdate.setModifiedContainedDatasetCodesOrNull(new String[] - { "c1", "c2" }); + dataSetUpdate.setModifiedContainedDatasetCodesOrNull(new String[] { "c1", "c2" }); final MetaprojectPE metaprojectPE = new MetaprojectPE(); @@ -1271,7 +1271,8 @@ public class ETLServiceTest extends AbstractServerTestCase allowing(entityOperationChecker).assertInstanceSampleCreationAllowed(with(any(IAuthSession.class)), with(any(List.class))); allowing(entityOperationChecker).assertInstanceSampleUpdateAllowed(with(any(IAuthSession.class)), with(any(List.class))); - one(createDataSetExecutor).create(with(any(IOperationContext.class)), with(any(List.class))); + one(operationsExecutor).execute(with(any(IOperationContext.class)), with(any(List.class))); + will(returnValue(Collections.singletonList(new CreateDataSetsOperationResult(Collections.emptyList())))); } }); @@ -1319,8 +1320,7 @@ public class ETLServiceTest extends AbstractServerTestCase final DataSetBatchUpdatesDTO dataSetUpdate = new DataSetBatchUpdatesDTO(); dataSetUpdate.setDatasetId(CommonTestUtils.TECH_ID); dataSetUpdate.setFileFormatTypeCode("new-file-format"); - dataSetUpdate.setModifiedContainedDatasetCodesOrNull(new String[] - { "c1", "c2" }); + dataSetUpdate.setModifiedContainedDatasetCodesOrNull(new String[] { "c1", "c2" }); final MetaprojectPE metaprojectPE = new MetaprojectPE(); metaprojectPE.setOwner(CommonTestUtils.createPersonFromPrincipal(PRINCIPAL)); @@ -1540,7 +1540,7 @@ public class ETLServiceTest extends AbstractServerTestCase new ServiceForDataStoreServer(authenticationService, sessionManager, daoFactory, propertiesBatchManager, boFactory, dssfactory, null, entityOperationChecker, dataStoreServiceRegistrator, dataSourceManager, - sessionManagerForEntityOperations, managedPropertyEvaluatorFactory, createDataSetExecutor); + sessionManagerForEntityOperations, managedPropertyEvaluatorFactory, operationsExecutor); etlService.setConversationClient(conversationClient); etlService.setConversationServer(conversationServer); etlService.setDisplaySettingsProvider(new DisplaySettingsProvider()); @@ -1596,8 +1596,7 @@ public class ETLServiceTest extends AbstractServerTestCase DataStoreServiceKind serviceKind, String key) { // unknown data set type codes should be silently discarded - return new DatastoreServiceDescription(key, key, new String[] - { DATA_SET_TYPE_CODE, UNKNOWN_DATA_SET_TYPE_CODE }, key, serviceKind); + return new DatastoreServiceDescription(key, key, new String[] { DATA_SET_TYPE_CODE, UNKNOWN_DATA_SET_TYPE_CODE }, key, serviceKind); } @SuppressWarnings("deprecation") @@ -1605,8 +1604,7 @@ public class ETLServiceTest extends AbstractServerTestCase DataStoreServiceKind serviceKind, String key, String regex) { // wildcards should be handled correctly - return new DatastoreServiceDescription(key, key, new String[] - { regex }, key, serviceKind); + return new DatastoreServiceDescription(key, key, new String[] { regex }, key, serviceKind); } private void assignRoles(PersonPE person) diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/authorization/ProjectAuthorizationUser.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/authorization/ProjectAuthorizationUser.java index 7b3c1fe83fc63abd017c798994c2ef37cc9b15f8..300ff6ebef92861fe81b0848e7faf91789a594f4 100644 --- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/authorization/ProjectAuthorizationUser.java +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/authorization/ProjectAuthorizationUser.java @@ -38,6 +38,8 @@ public class ProjectAuthorizationUser public static final String TEST_PROJECT_PA_OFF = "test_project_pa_off"; + public static final String TEST_GROUP = "admin"; + public static final String ETL_SERVER = "etlserver"; public static final String TEST_SPACE_ETL_SERVER = "test_space_etl_server"; @@ -182,7 +184,7 @@ public class ProjectAuthorizationUser testProjectPAOn.setTestProjectUser(true); testProjectPAOn.setPAEnabled(true); - ProjectAuthorizationUser testGroup = new ProjectAuthorizationUser("admin"); + ProjectAuthorizationUser testGroup = new ProjectAuthorizationUser(TEST_GROUP); testGroup.setTestGroupUser(true); return new Object[][] { diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/IDataStoreServerApi.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/IDataStoreServerApi.java index cdabfb18ec05f0f8900a57f16a7db79717ef471d..ecf8ed13000c7891e1e7b08154e08708e6d84dfe 100644 --- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/IDataStoreServerApi.java +++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/IDataStoreServerApi.java @@ -22,6 +22,7 @@ import java.util.List; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.SearchResult; import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.dataset.create.FullDataSetCreation; +import ch.ethz.sis.openbis.generic.dssapi.v3.dto.dataset.create.UploadedDataSetCreation; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.DataSetFile; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.download.DataSetFileDownloadOptions; import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.fetchoptions.DataSetFileFetchOptions; @@ -52,6 +53,8 @@ public interface IDataStoreServerApi extends IRpcService public InputStream downloadFiles(String sessionToken, List<? extends IDataSetFileId> fileIds, DataSetFileDownloadOptions downloadOptions); + public DataSetPermId createUploadedDataSet(String sessionToken, UploadedDataSetCreation newDataSet); + @TechPreview public List<DataSetPermId> createDataSets(String sessionToken, List<FullDataSetCreation> newDataSets); diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/dataset/create/UploadedDataSetCreation.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/dataset/create/UploadedDataSetCreation.java new file mode 100644 index 0000000000000000000000000000000000000000..09a96a34885be24dbb07041a18ef9c2818f6a690 --- /dev/null +++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/dataset/create/UploadedDataSetCreation.java @@ -0,0 +1,102 @@ +package ch.ethz.sis.openbis.generic.dssapi.v3.dto.dataset.create; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.create.ICreation; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.id.IEntityTypeId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.IExperimentId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.ISampleId; +import ch.systemsx.cisd.base.annotation.JsonObject; + +/** + * @author pkupczyk + */ +@JsonObject("dss.dto.dataset.create.UploadedDataSetCreation") +public class UploadedDataSetCreation implements ICreation +{ + private static final long serialVersionUID = 1L; + + @JsonProperty + private IEntityTypeId typeId; + + @JsonProperty + private IExperimentId experimentId; + + @JsonProperty + private ISampleId sampleId; + + @JsonProperty + private Map<String, String> properties = new HashMap<String, String>(); + + @JsonProperty + private List<? extends IDataSetId> parentIds; + + @JsonProperty + private String uploadId; + + public IEntityTypeId getTypeId() + { + return typeId; + } + + public void setTypeId(IEntityTypeId typeId) + { + this.typeId = typeId; + } + + public IExperimentId getExperimentId() + { + return experimentId; + } + + public void setExperimentId(IExperimentId experimentId) + { + this.experimentId = experimentId; + } + + public ISampleId getSampleId() + { + return sampleId; + } + + public void setSampleId(ISampleId sampleId) + { + this.sampleId = sampleId; + } + + public Map<String, String> getProperties() + { + return properties; + } + + public void setProperties(Map<String, String> properties) + { + this.properties = properties; + } + + public List<? extends IDataSetId> getParentIds() + { + return parentIds; + } + + public void setParentIds(List<? extends IDataSetId> parentIds) + { + this.parentIds = parentIds; + } + + public String getUploadId() + { + return uploadId; + } + + public void setUploadId(String uploadId) + { + this.uploadId = uploadId; + } + +} diff --git a/openbis_api/sourceTest/java/ch/ethz/sis/openbis/generic/sharedapi/v3/dictionary.txt b/openbis_api/sourceTest/java/ch/ethz/sis/openbis/generic/sharedapi/v3/dictionary.txt index 4b236e9ae5ce08a1a26dc762ce19fcfacd10a77f..0c8316e02dc915b1f67b29d981fd64428b960a00 100644 --- a/openbis_api/sourceTest/java/ch/ethz/sis/openbis/generic/sharedapi/v3/dictionary.txt +++ b/openbis_api/sourceTest/java/ch/ethz/sis/openbis/generic/sharedapi/v3/dictionary.txt @@ -1882,3 +1882,8 @@ set Material Type Id get Property Types Get Property Types Operation Get Property Types Operation Result + +create Uploaded Data Set +get Upload Id +set Upload Id +Uploaded Data Set Creation \ No newline at end of file