diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java index abf03fa9c840de7ebec7f372664f5bfaced69ff4..6d18fbab78a1db932af9100d75972bca7c81e8c0 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java @@ -16,19 +16,30 @@ package ch.systemsx.cisd.openbis.generic.server.api.v1; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import java.util.Map; import javax.annotation.Resource; +import javax.servlet.http.HttpSession; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import ch.rinn.restrictions.Private; import ch.systemsx.cisd.common.exceptions.InvalidSessionException; +import ch.systemsx.cisd.common.exceptions.UserFailureException; +import ch.systemsx.cisd.common.servlet.IRequestContextProvider; import ch.systemsx.cisd.openbis.common.spring.IInvocationLoggerContext; +import ch.systemsx.cisd.openbis.common.spring.IUncheckedMultipartFile; +import ch.systemsx.cisd.openbis.generic.client.web.server.UploadedFilesBean; +import ch.systemsx.cisd.openbis.generic.client.web.server.translator.UserFailureExceptionTranslator; import ch.systemsx.cisd.openbis.generic.server.AbstractServer; import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.RolesAllowed; import ch.systemsx.cisd.openbis.generic.server.business.IPropertiesBatchManager; import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory; +import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.exception.SampleUniqueCodeViolationExceptionAbstract; import ch.systemsx.cisd.openbis.generic.shared.DatabaseCreateOrDeleteModification; import ch.systemsx.cisd.openbis.generic.shared.ICommonServer; import ch.systemsx.cisd.openbis.generic.shared.IOpenBisSessionManager; @@ -38,12 +49,20 @@ import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.NewVocabularyTerm; import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.WebAppSettings; import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.id.metaproject.IMetaprojectId; import ch.systemsx.cisd.openbis.generic.shared.basic.TechId; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BatchOperationKind; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseModificationKind.ObjectKind; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Metaproject; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewEntitiesWithTypes; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy; import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE; import ch.systemsx.cisd.openbis.generic.shared.dto.Session; +import ch.systemsx.cisd.openbis.generic.shared.parser.NamedInputStream; +import ch.systemsx.cisd.openbis.generic.shared.parser.SampleUploadSectionsParser; +import ch.systemsx.cisd.openbis.generic.shared.parser.SampleUploadSectionsParser.BatchSamplesOperation; +import ch.systemsx.cisd.openbis.generic.shared.parser.SampleUploadSectionsParser.SampleCodeGenerator; import ch.systemsx.cisd.openbis.generic.shared.util.EntityHelper; +import ch.systemsx.cisd.openbis.plugin.generic.shared.IGenericServer; /** * @author Franz-Josef Elmer @@ -53,7 +72,7 @@ public class GeneralInformationChangingService extends AbstractServer<IGeneralInformationChangingService> implements IGeneralInformationChangingService { - public static final int MINOR_VERSION = 3; + public static final int MINOR_VERSION = 4; @Resource(name = ch.systemsx.cisd.openbis.generic.shared.ResourceNames.COMMON_SERVER) private ICommonServer server; @@ -206,4 +225,181 @@ public class GeneralInformationChangingService extends return MINOR_VERSION; } + // + // <TEST IMPLEMENTATION For registerSamples> + // + @Resource(name = ch.systemsx.cisd.openbis.plugin.generic.shared.ResourceNames.GENERIC_PLUGIN_SERVER) + private IGenericServer genericServer; + + @Resource(name = "request-context-provider") + @Private + public IRequestContextProvider requestContextProvider; + + @Override + @Transactional(readOnly = false) + @RolesAllowed(RoleWithHierarchy.INSTANCE_OBSERVER) + public final boolean registerSamples( + final String sessionToken, + final String sampleTypeCode, + final String sessionKey, + final String defaultGroupIdentifier) + { + List<ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType> sampleTypes = server.listSampleTypes(sessionToken); + ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType sampleType = null; + for (ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType auxSampleType : sampleTypes) + { + if (auxSampleType.getCode().equals(sampleTypeCode)) + { + sampleType = auxSampleType; + break; + } + } + + boolean isAutogenerateCodes = defaultGroupIdentifier != null; + + BatchOperationKind operationKind = BatchOperationKind.REGISTRATION; + BatchSamplesOperation info = + parseSamples(sessionToken, sampleType, sessionKey, defaultGroupIdentifier, isAutogenerateCodes, true, null, operationKind); + try + { + genericServer.registerOrUpdateSamples(sessionToken, info.getSamples()); + return true; // info.getResultList(); + } catch (final ch.systemsx.cisd.common.exceptions.UserFailureException e) + { + if (e.getCause() instanceof SampleUniqueCodeViolationExceptionAbstract) + { + SampleUniqueCodeViolationExceptionAbstract codeException = (SampleUniqueCodeViolationExceptionAbstract) e.getCause(); + + if (isAutogenerateCodes) + { + throw new UserFailureException( + String.format( + "Import failed because the autogenerated codes are no longer unique. Somebody has created a sample (code: %s) that matched one of the autogenerated codes. Please run the import once again.", + codeException.getSampleCode())); + } else + { + throw new UserFailureException(String.format( + "Import failed because sample (code: %s) already exists.", + codeException.getSampleCode())); + } + } else + { + throw UserFailureExceptionTranslator.translate(e); + } + } + } + + private BatchSamplesOperation parseSamples( + final String sessionToken, + final ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType sampleType, + final String sessionKey, + String defaultGroupIdentifier, + final boolean isAutoGenerateCodes, + final boolean allowExperiments, + String excelSheetName, + BatchOperationKind operationKind) + { + HttpSession httpSession = getHttpSession(); + UploadedFilesBean uploadedFiles = null; + try + { + uploadedFiles = getUploadedFiles(sessionKey, httpSession); + return parseSamples(sessionToken, sampleType, httpSession, uploadedFiles, defaultGroupIdentifier, + isAutoGenerateCodes, allowExperiments, excelSheetName, operationKind); + } finally + { + cleanUploadedFiles(sessionKey, httpSession, uploadedFiles); + } + } + + private BatchSamplesOperation parseSamples( + final String sessionToken, + final ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType sampleType, + HttpSession httpSession, + UploadedFilesBean uploadedFiles, + String defaultGroupIdentifier, + final boolean isAutoGenerateCodes, + final boolean allowExperiments, + String excelSheetName, + BatchOperationKind operationKind) + { + boolean updateExisting = (operationKind == BatchOperationKind.UPDATE); + SampleCodeGenerator sampleCodeGeneratorOrNull = + tryGetSampleCodeGenerator(sessionToken, isAutoGenerateCodes, sampleType.getGeneratedCodePrefix()); + Collection<NamedInputStream> files = new ArrayList<NamedInputStream>(uploadedFiles.size()); + for (IUncheckedMultipartFile f : uploadedFiles.iterable()) + { + files.add(new NamedInputStream(f.getInputStream(), f.getOriginalFilename())); + } + BatchSamplesOperation batchSamplesOperation = + SampleUploadSectionsParser.prepareSamples(sampleType, files, + defaultGroupIdentifier, sampleCodeGeneratorOrNull, allowExperiments, + excelSheetName, operationKind); + setUpdatePossibility(batchSamplesOperation.getSamples(), updateExisting); + return batchSamplesOperation; + + } + + protected static UploadedFilesBean getUploadedFiles(String sessionKey, HttpSession session) + { + if (session.getAttribute(sessionKey) == null + || session.getAttribute(sessionKey) instanceof UploadedFilesBean == false) + { + throw new IllegalStateException(String.format( + "No UploadedFilesBean object as session attribute '%s' found.", sessionKey)); + } + return (UploadedFilesBean) session.getAttribute(sessionKey); + } + + protected static void cleanUploadedFiles(final String sessionKey, HttpSession session, + UploadedFilesBean uploadedFiles) + { + if (uploadedFiles != null) + { + uploadedFiles.deleteTransferredFiles(); + } + if (session != null) + { + session.removeAttribute(sessionKey); + } + } + + private SampleCodeGenerator tryGetSampleCodeGenerator(final String sessionToken, boolean isAutoGenerateCodes, + final String codePrefix) + { + if (isAutoGenerateCodes) + { + return new SampleCodeGenerator() + { + @Override + public List<String> generateCodes(int size) + { + return genericServer.generateCodes(sessionToken, codePrefix, + EntityKind.SAMPLE, size); + } + }; + } else + { + return null; + } + } + + private static void setUpdatePossibility( + List<? extends NewEntitiesWithTypes<?, ?>> batchOperation, boolean updateExisting) + { + for (NewEntitiesWithTypes<?, ?> entitiesWithTypes : batchOperation) + { + entitiesWithTypes.setAllowUpdateIfExist(updateExisting); + } + } + + protected final HttpSession getHttpSession() + { + return getOrCreateHttpSession(false); + } + + private final HttpSession getOrCreateHttpSession(final boolean create) + { + return requestContextProvider.getHttpServletRequest().getSession(create); + } } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingServiceLogger.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingServiceLogger.java index 611dab06bf1b09f718097ccac33dcac727486a20..19d7dc24a6adacac818eda75241840c1ede92bba 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingServiceLogger.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingServiceLogger.java @@ -132,6 +132,18 @@ class GeneralInformationChangingServiceLogger extends AbstractServerLogger imple abbreviate(assignments.getMaterials())); } + @Override + public boolean registerSamples(String sessionToken, String sampleTypeCode, String sessionKey, String defaultGroupIdentifier) + { + logAccess(sessionToken, "registerSamples", + "sampleTypeCode(%s), sessionKey(%s), defaultGroupIdentifier(%s)", + sampleTypeCode, + sessionKey, + defaultGroupIdentifier); + + return false; + } + @Override public int getMajorVersion() { diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/js/openbis.js b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/js/openbis.js index f5476a74d56f0f72713d4c678d306fa0f8405326..c6af848a4478c1027cf2d4b273228827648f9a28 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/js/openbis.js +++ b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/js/openbis.js @@ -1035,6 +1035,22 @@ openbis.prototype.listAttachmentsForSample = function(sampleId, allVersions, act * ========================================================================================== */ +/** + * @see IGeneralInformationChangingService.registerSamples(String, String, String, String) + * @method + */ +openbis.prototype.registerSamples = function(sampleTypeCode, sessionKey, defaultGroupIdentifier, action) { + this._internal.ajaxRequest({ + url: this._internal.generalInfoChangingServiceUrl, + data: { "method" : "registerSamples", + "params" : [ this.getSession(), + sampleTypeCode, + sessionKey, + defaultGroupIdentifier] }, + success: action + }); +} + /** * @see IGeneralInformationChangingService.updateSampleProperties(String, long, Map<String,String>) * @method diff --git a/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/IGeneralInformationChangingService.java b/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/IGeneralInformationChangingService.java index c626ee7847329b5ef04526414a36f5b262b01970..255360a46b0751fda896370c4f3d02262f3d914d 100644 --- a/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/IGeneralInformationChangingService.java +++ b/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/IGeneralInformationChangingService.java @@ -138,4 +138,17 @@ public interface IGeneralInformationChangingService extends IRpcService public void removeFromMetaproject(String sessionToken, IMetaprojectId metaprojectId, MetaprojectAssignmentsIds assignmentsToRemove); + /** + * Registers samples parsing a file stored on the HTTP Session. + * + * @param sampleTypeCode Sample type to parse + * @param sessionKey key of the file stored on the HTTP Session + * @param defaultGroupIdentifier key of the file stored on the HTTP Session + * @since 1.4 + */ + public boolean registerSamples( + final String sessionToken, + final String sampleTypeCode, + final String sessionKey, + final String defaultGroupIdentifier); }