From 7a4399b34187211243aadcbf752596ff07ed53bf Mon Sep 17 00:00:00 2001 From: alaskowski <alaskowski@ethz.ch> Date: Thu, 7 Dec 2023 16:25:42 +0100 Subject: [PATCH] BIS-713: removed old code --- .../imaging/1/as/initialize-master-data.py | 73 -- .../1/as/master-data/imaging-data-model.xls | Bin 23552 -> 0 bytes .../imaging_dataset_config_validation.py | 182 ---- .../imaging/lib/openBIS-premise-imaging.jar | Bin 44194 -> 0 bytes .../imaging/lib/premise-sources/build.gradle | 59 -- .../gradle/wrapper/gradle-wrapper.jar | Bin 55616 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - .../imaging/lib/premise-sources/gradlew | 188 ---- .../imaging/lib/premise-sources/gradlew.bat | 100 -- .../lib/premise-sources/javaproject.gradle | 412 -------- .../lib/premise-sources/repository.gradle | 6 - .../lib/premise-sources/settings.gradle | 21 - .../source/java/PingPongService.java | 45 - .../v3/dto/imaging/ImagingDataSetConfig.java | 153 --- .../v3/dto/imaging/ImagingDataSetControl.java | 192 ---- .../ImagingDataSetControlVisibility.java | 88 -- .../v3/dto/imaging/ImagingDataSetExport.java | 70 -- .../v3/dto/imaging/ImagingDataSetImage.java | 81 -- .../imaging/ImagingDataSetMultiExport.java | 97 -- .../v3/dto/imaging/ImagingDataSetPreview.java | 113 -- .../imaging/ImagingDataSetPropertyConfig.java | 62 -- .../dss/plugins/imaging/ImagingArchiver.java | 157 --- .../dss/plugins/imaging/ImagingService.java | 398 ------- .../imaging/ImagingServiceContext.java | 53 - .../server/dss/plugins/imaging/Util.java | 137 --- .../server/dss/plugins/imaging/Validator.java | 85 -- .../adaptor/ImagingDataSetExampleAdaptor.java | 70 -- .../adaptor/ImagingDataSetJythonAdaptor.java | 60 -- .../adaptor/ImagingDataSetPythonAdaptor.java | 92 -- .../imaging/adaptor/NanonisDatAdaptor.java | 75 -- .../imaging/adaptor/NanonisSxmAdaptor.java | 78 -- .../container/ImagingDataContainer.java | 58 -- .../container/ImagingExportContainer.java | 77 -- .../ImagingMultiExportContainer.java | 56 - .../container/ImagingPreviewContainer.java | 64 -- .../dss/dto/imaging/ImagingDataSetConfig.js | 91 -- .../dss/dto/imaging/ImagingDataSetControl.js | 112 -- .../ImagingDataSetControlVisibility.js | 51 - .../dss/dto/imaging/ImagingDataSetExport.js | 58 -- .../v3/dss/dto/imaging/ImagingDataSetImage.js | 37 - .../dss/dto/imaging/ImagingDataSetPreview.js | 58 -- .../imaging/ImagingDataSetPropertyConfig.js | 34 - .../source/python/imaging/__init__.py | 22 - .../source/python/imaging/imaging.py | 448 -------- .../source/python/tests/test_imaging.py | 119 --- .../plugins/imaging/ImagingServiceTest.java | 116 --- .../premise-sources/sourceTest/java/tests.xml | 12 - .../custom-services/imaging/nanonis_dat.py | 119 --- .../custom-services/imaging/nanonis_sxm.py | 100 -- .../custom-services/imaging/plugin.properties | 8 - .../custom-services/imaging/spmpy_terry.py | 970 ------------------ 51 files changed, 5762 deletions(-) delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/as/initialize-master-data.py delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/as/master-data/imaging-data-model.xls delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/as/master-data/scripts/imaging_dataset_config_validation.py delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/openBIS-premise-imaging.jar delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/build.gradle delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/gradle/wrapper/gradle-wrapper.jar delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/gradle/wrapper/gradle-wrapper.properties delete mode 100755 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/gradlew delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/gradlew.bat delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/javaproject.gradle delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/repository.gradle delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/settings.gradle delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/PingPongService.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetConfig.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControl.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControlVisibility.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetExport.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetImage.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetMultiExport.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetPreview.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetPropertyConfig.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingArchiver.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingService.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingServiceContext.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/Util.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/Validator.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetExampleAdaptor.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetJythonAdaptor.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetPythonAdaptor.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/NanonisDatAdaptor.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/NanonisSxmAdaptor.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingDataContainer.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingExportContainer.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingMultiExportContainer.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingPreviewContainer.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetConfig.js delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetControl.js delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetControlVisibility.js delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetExport.js delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetImage.js delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetPreview.js delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetPropertyConfig.js delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/python/imaging/__init__.py delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/python/imaging/imaging.py delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/python/tests/test_imaging.py delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/sourceTest/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingServiceTest.java delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/sourceTest/java/tests.xml delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_dat.py delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_sxm.py delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/plugin.properties delete mode 100644 core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/spmpy_terry.py diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/as/initialize-master-data.py b/core-plugin-openbis/dist/core-plugins/imaging/1/as/initialize-master-data.py deleted file mode 100644 index e1ed0ce1fa3..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/as/initialize-master-data.py +++ /dev/null @@ -1,73 +0,0 @@ -# -# Copyright 2014 ETH Zuerich, Scientific IT Services -# -# 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. -# -# MasterDataRegistrationTransaction Class -from ch.ethz.sis.openbis.generic.server.asapi.v3 import ApplicationServerApi -from ch.systemsx.cisd.openbis.generic.server import CommonServiceProvider -from ch.ethz.sis.openbis.generic.asapi.v3.dto.service.id import CustomASServiceCode -from ch.ethz.sis.openbis.generic.asapi.v3.dto.service import CustomASServiceExecutionOptions -from ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl import MasterDataRegistrationHelper -import sys - -helper = MasterDataRegistrationHelper(sys.path) -api = CommonServiceProvider.getApplicationContext().getBean(ApplicationServerApi.INTERNAL_SERVICE_NAME) -sessionToken = api.loginAsSystem() -props = CustomASServiceExecutionOptions().withParameter('xls', helper.listXlsByteArrays()) \ - .withParameter('method', 'import').withParameter('zip', False).withParameter('xls_name', 'IMAGING').withParameter('update_mode', 'UPDATE_IF_EXISTS') \ - .withParameter('scripts', helper.getAllScripts()) -result = api.executeCustomASService(sessionToken, CustomASServiceCode("xls-import"), props) -api.logout(sessionToken) -print("======================== imaging-master-data xls ingestion result ========================") -print(result) -print("======================== imaging-data xls ingestion result ========================") - - - -# from ch.ethz.sis.openbis.generic.server.asapi.v3 import ApplicationServerApi -# from ch.systemsx.cisd.openbis.generic.server import CommonServiceProvider -# from ch.ethz.sis.openbis.generic.asapi.v3.dto.service.id import CustomASServiceCode -# from ch.ethz.sis.openbis.generic.asapi.v3.dto.service import CustomASServiceExecutionOptions -# from ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl import MasterDataRegistrationHelper -# import sys -# -# from ch.systemsx.cisd.openbis.generic.server.hotfix import ELNFixes -# from ch.systemsx.cisd.openbis.generic.server.hotfix import ELNAnnotationsMigration -# from ch.systemsx.cisd.openbis.generic.server.hotfix import ELNCollectionTypeMigration -# -# api = CommonServiceProvider.getApplicationContext().getBean(ApplicationServerApi.INTERNAL_SERVICE_NAME) -# sessionToken = api.loginAsSystem() -# -# if ELNFixes.isELNInstalled(): -# ELNFixes.beforeUpgrade(sessionToken) -# ELNAnnotationsMigration.beforeUpgrade(sessionToken) -# ELNCollectionTypeMigration.beforeUpgrade(sessionToken) -# -# helper = MasterDataRegistrationHelper(sys.path) -# props = CustomASServiceExecutionOptions().withParameter('xls', helper.getByteArray("common-data-model.xls"))\ -# .withParameter('method', 'import').withParameter('zip', False).withParameter('xls_name', 'ELN-LIMS').withParameter('update_mode', 'UPDATE_IF_EXISTS')\ -# .withParameter('scripts', helper.getAllScripts()) -# result = api.executeCustomASService(sessionToken, CustomASServiceCode("xls-import"), props) -# -# if not ELNFixes.isMultiGroup(): -# props = CustomASServiceExecutionOptions().withParameter('xls', helper.getByteArray("single-group-data-model.xls"))\ -# .withParameter('method', 'import').withParameter('zip', False).withParameter('xls_name', 'ELN-LIMS').withParameter('update_mode', 'UPDATE_IF_EXISTS')\ -# .withParameter('scripts', helper.getAllScripts()) -# result = api.executeCustomASService(sessionToken, CustomASServiceCode("xls-import"), props) -# -# ELNCollectionTypeMigration.afterUpgrade() -# api.logout(sessionToken) -# print("======================== master-data xls ingestion result ========================") -# print(result) -# print("======================== master-data xls ingestion result ========================") diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/as/master-data/imaging-data-model.xls b/core-plugin-openbis/dist/core-plugins/imaging/1/as/master-data/imaging-data-model.xls deleted file mode 100644 index 8f88765f4618a3462bf4118c977d56eb9f621c5d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23552 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 L{QuSe>-PT#nLi{N diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/as/master-data/scripts/imaging_dataset_config_validation.py b/core-plugin-openbis/dist/core-plugins/imaging/1/as/master-data/scripts/imaging_dataset_config_validation.py deleted file mode 100644 index 6766c2ff211..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/as/master-data/scripts/imaging_dataset_config_validation.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright ETH 2023 Zürich, Scientific IT Services -# -# 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. -# - -import json - - -def assert_control(control_config): - if not control_config: - return True, '' - obligatory_tags = ['@type', 'label', 'type'] - for tag in obligatory_tags: - if tag not in control_config: - return False, tag+': is missing!' - if control_config[tag] is None: - return False, tag+': can not be empty!' - - list_tags = ['values', 'range', 'speeds', 'visibility'] - for list_tag in list_tags: - if list_tag in control_config and control_config[list_tag] is not None and not isinstance(control_config[list_tag], list): - return False, list_tag+': must be a list or null!' - - boolean_tags = ['playable', 'multiselect'] - for boolean_tag in boolean_tags: - if boolean_tag in control_config and control_config[boolean_tag] is not None and not isinstance(control_config[boolean_tag], bool): - return False, boolean_tag+': must be a boolean or empty!' - - if 'visibility' in control_config and control_config['visibility'] is not None: - visibility = control_config['visibility'] - for vis in visibility: - tags = ['label', 'values'] - all_tags = tags + ['range', 'unit'] - for tag in ['label', 'values']: - if tag not in vis: - return False, 'visibility->'+tag+': is missing!' - if vis[tag] is None: - return False, 'visibility->'+tag+': can not be empty!' - - for tag in ['values', 'range']: - if tag in vis and vis[tag] is not None and not isinstance(vis[tag], list): - return False, 'visibility->'+tag+': must be a list!' - - if 'metadata' in control_config and control_config['metadata'] is not None and not isinstance(control_config['metadata'], dict): - return False, '->metadata: must be a dictionary or null!' - - return True, '' - - -def assert_config(json_config): - if 'config' in json_config: - config = json_config['config'] - obligatory_tags = ['@type', 'adaptor', 'version', 'playable', 'exports', 'inputs'] - for tag in obligatory_tags: - if tag not in config: - return False, 'config->' + tag + ': is missing!' - if config[tag] is None: - return False, 'config->' + tag + ': can not be empty!' - - if config['adaptor'].strip() == '': - return False, 'config->adaptor: can not be blank!' - - list_tags = ['speeds', 'resolutions', 'exports', 'inputs'] - for list_tag in list_tags: - if list_tag in config and config[list_tag] is not None and not isinstance(config[list_tag], list): - return False, '\''+list_tag+'\' must be a list or null!' - - if not isinstance(config['playable'], bool): - return False, 'config->playable: must be a boolean!' - - for control in config['exports']: - result, err = assert_control(control) - if not result: - return result, 'config->exports->' + err - - for control in config['inputs']: - result, err = assert_control(control) - if not result: - return result, 'config->inputs->' + err - - if 'metadata' in config and config['metadata'] is not None and not isinstance(config['metadata'], dict): - return False, 'config->metadata: must be a dictionary or null!' - else: - return False, 'Missing \'config\' tag in configuration!' - return True, '' - - -def assert_preview(preview_config): - obligatory_tags = ['@type', 'format', 'show'] - for tag in obligatory_tags: - if tag not in config: - return False, tag + ': is missing!' - if config[tag] is None: - return False, tag + ': can not be empty!' - - if not isinstance(preview_config['show'], bool): - return False, 'show: must be boolean!' - - if not isinstance(preview_config['format'], str): - return False, 'format: must be string!' - - if 'bytes' in preview_config and preview_config['bytes'] is not None and not isinstance(preview_config['bytes'], str): - return False, 'bytes: must be a base64 encoded string or null!' - - if 'metadata' in preview_config and preview_config['metadata'] is not None and not isinstance(preview_config['metadata'], dict): - return False, 'metadata: must be a dictionary or null!' - - if 'config' in preview_config and preview_config['config'] is not None and not isinstance(preview_config['config'], dict): - return False, 'config: must be a dictionary or null!' - - return True, '' - - -def assert_images(json_config): - if 'images' in json_config: - images = json_config['images'] - if images is None: - return False, '\'images\' tag can not be null!' - if not isinstance(images, list): - return False, '\'images\' tag must be a list!' - - for image in images: - obligatory_tags = ['@type'] - for tag in obligatory_tags: - if tag not in image: - return False, 'images->' + tag + ': missing tag!' - if image[tag] is None: - return False, 'images->' + tag + ': can not be empty!' - - if 'metadata' in image and image['metadata'] is not None and not isinstance(image['metadata'], dict): - return False, 'images->metadata: must be a dictionary or null!' - - if 'previews' in image and image['previews'] is not None and not isinstance(image['previews'], list): - return False, 'images->previews: must be a list or null!' - - for preview in image['previews']: - res, err = assert_preview(preview) - if not res: - return result, 'images->previews->' + err - - else: - return False, 'Missing \'images\' tag in configuration!' - return True, '' - - -def get_rendered_property(entity, property): - properties = entity.externalDataPE().getProperties() - for prop in properties: - etpt = prop.getEntityTypePropertyType() - pt = etpt.getPropertyType() - code = pt.getCode() - if code == property: - return prop.tryGetUntypedValue() - return None - - -def validate(entity, is_new): - imaging_dataset_config = get_rendered_property(entity, "$IMAGING_DATA_CONFIG") - if imaging_dataset_config is None or imaging_dataset_config == "": - return "Imaging dataset config can not be empty!" - elif "test_validation_failure" in imaging_dataset_config: - return "Imaging dataset config validation failure!" - else: - - try: - config = json.loads(imaging_dataset_config) - except Exception as e: - return "Could not parse JSON: " + e - - result, err = assert_config(config) - if not result: - return err diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/openBIS-premise-imaging.jar b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/openBIS-premise-imaging.jar deleted file mode 100644 index 4b4684b9fca92f5c299aa0ac081570eae50770bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44194 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 EKMkZO0RR91 diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/build.gradle b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/build.gradle deleted file mode 100644 index 0f364e52211..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/build.gradle +++ /dev/null @@ -1,59 +0,0 @@ -apply from: 'javaproject.gradle' -apply from: 'repository.gradle' - -//evaluationDependsOn(':api-openbis-java') - -dependencies { - api project(':api-openbis-java'), - project(':server-original-data-store') - - implementation 'fasterxml:jackson-annotations:2.9.10', - 'fasterxml:jackson-core:2.9.10', - 'fasterxml:jackson-databind:2.9.10.8', - 'fasterxml:jackson-datatype-jsr310:2.9.10' - -// testImplementation 'testng:testng:6.8-CISD' -// project(':server-original-data-store') - - testImplementation 'junit:junit:4.10', - 'testng:testng:6.8-CISD' - - testRuntimeOnly 'hamcrest:hamcrest-core:1.3', - project(':server-original-data-store') -} - -sourceSets { - main { - resources { - srcDirs = ['source/java/*'] - } - } - test { - resources { - srcDirs = ['sourceTest/java'] - } - } -} - -//test { -// workingDir = '.' -//} - -def premiseArchiveName = 'openBIS-premise-imaging.jar' -jar { - dependsOn compileJava - archiveName premiseArchiveName - includeEmptyDirs false -} - - -task premiseImagingJar(type: Copy) { - dependsOn jar - from("${project.buildDir}/libs/${premiseArchiveName}") - into ".." - doLast { -// delete "${project.buildDir}/${premiseArchiveName}" -// delete "${project.buildDir}" -// delete - } -} \ No newline at end of file diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/gradle/wrapper/gradle-wrapper.jar b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 5c2d1cf016b3885f6930543d57b744ea8c220a1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55616 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 I5eVr20d63LbpQYW diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/gradle/wrapper/gradle-wrapper.properties b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 7745c4ec463..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://sissource.ethz.ch/openbis/openbis-public/openbis-ivy/-/raw/main/gradle/distribution/7.4/gradle-7.4-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/gradlew b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/gradlew deleted file mode 100755 index 83f2acfdc31..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/gradlew +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env sh - -# -# Copyright 2015 the original author or authors. -# -# 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 -# -# https://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. -# - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/gradlew.bat b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/gradlew.bat deleted file mode 100644 index 9618d8d9607..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/gradlew.bat +++ /dev/null @@ -1,100 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/javaproject.gradle b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/javaproject.gradle deleted file mode 100644 index 82beac14965..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/javaproject.gradle +++ /dev/null @@ -1,412 +0,0 @@ -apply plugin: 'java-library' -apply plugin: 'project-report' - -evaluationDependsOnChildren() - -configurations { - implementation { - canBeResolved = true - } - testImplementation { - canBeResolved = true - } - runtimeOnly { - canBeResolved = true - } - tests.extendsFrom testRuntimeOnly -} - -configurations { - ecj -} - -configurations.all { - resolutionStrategy.cacheDynamicVersionsFor 0, 'hours' - resolutionStrategy.cacheChangingModulesFor 0, 'hours' -} - -//task wrapper(type: Wrapper) { -// gradleVersion = '4.10.3' -// distributionUrl = "https://services.gradle.org/distributions/gradle-4.10.3-bin.zip" -//} -sourceCompatibility='11' -targetCompatibility='11' - -sourceSets { - main { - java { - srcDirs = ['source/java'] - } - } - test { - java { - srcDirs = ['sourceTest/java'] - } - resources { - srcDirs = ['sourceTest/java'] - } - } - examples { - java { - srcDirs = ['sourceExamples/java'] - } - } -} - -buildDir = 'targets/gradle' - -buildscript { - apply from: './repository.gradle' - - repositories repositoryConfig - - dependencies { - classpath 'cisd:cisd-ant-tasks:r29834' - } -} - -repositories repositoryConfig - -def execute(command, arguments) { - new ByteArrayOutputStream().withStream { os -> - print "execute: ${command}" - arguments.collect({print " ${it}"}) - println '' - def result = exec { - executable = command - args = arguments - standardOutput = os - } - return os.toString().split('\n') - } -} - -ext.executeFunction = { - command, arguments -> execute(command, arguments) -} - -def execute_working_dir(command, arguments, working_dir) { - new ByteArrayOutputStream().withStream { os -> - print "execute: ${command}" - arguments.collect({print " ${it}"}) - println '' - def result = exec { - executable = command - args = arguments - standardOutput = os - } - return os.toString().split('\n') - } -} - -ext.svnCommand = 'svn' - -def isSvnProject() { - return new java.io.File(projectDir, ".svn").isDirectory() || new java.io.File(projectDir, "../.svn").isDirectory() -} - -def isGitProject() { - return new java.io.File(projectDir, ".git").isDirectory() || new java.io.File(projectDir, "../.git").isDirectory() -} - -def executeSVN(arguments) { - arguments.add(0, '--non-interactive') - return execute(svnCommand, arguments) -} - -def calculateCleanFlag() { - return 'clean' - for (childProject in project.childProjects.values()) { - if (childProject.cleanFlag == 'dirty') { - return 'dirty' - } - } - def isSvn = isSvnProject() - if (isSvn) { - def output = executeSVN(['status', '../' + project.name]) - def lines = output.findAll({ (it.startsWith('?') || it.trim().isEmpty()) == false}) - return lines.isEmpty() ? 'clean' : 'dirty' - } else if (isGitProject()) { - def output = execute_working_dir('git', ['status', '--porcelain'], '../' + project.name) - return output.length == 0 ? 'clean' : 'dirty' - } else { - return 'dirty' - } -} - -def findMaximum(lines, key) { - return lines.findAll({ it.startsWith(key)}).collect({element -> element.split(':')[1].toInteger()}).max() -} - -def calculateBuildInfo() { - if (isSvnProject()) { - def output = executeSVN(['info', '-R', '../' + project.name]) - def maxRevisionNumber = findMaximum(output, 'Revision:') - project.ext.revisionNumber = findMaximum(output, 'Last Changed Rev:') - if (maxRevisionNumber < project.ext.revisionNumber) { - throw new GradleException("Maximum revision ($maxRevisionNumber) is less than the maximum " - + "last changed revision ($project.ext.revisionNumber).") - } - project.ext.versionNumber = 'SNAPSHOT' - def url = output.findAll({ it.startsWith('URL:')})[0].split('URL:')[1].trim() - if (url.contains('/trunk') == false) { - def pathElements = url.split('/') - project.ext.versionNumber = 'libraries' == pathElements[-2] ? pathElements[-3] : pathElements[-2] - } - } else if (isGitProject()) { - def gitlogoutput = execute_working_dir('git', ['log', '-1', '--format=%at'], '../' + project.name) - project.ext.revisionNumber = Integer.parseInt(gitlogoutput[0]) - def tag = 'git tag -l --points-at HEAD'.execute().text.trim() - if (tag == null || tag.isEmpty() || tag.contains('pybis')) { - project.ext.versionNumber = 'SNAPSHOT' - } else { - project.ext.versionNumber = tag - } - } else { - project.ext.revisionNumber = 1 - project.ext.versionNumber = 'SNAPSHOT' - } - - for (childProject in project.childProjects.values()) { - project.ext.revisionNumber = Math.max(project.ext.revisionNumber, childProject.revisionNumber) - if (project.ext.versionNumber != childProject.versionNumber) { - throw new GradleException("Inconsistent version numbers: " - + "${project.name} at version ${project.ext.versionNumber} but " - + "${childProject.name} at version ${childProject.versionNumber}.") - } - } - version = "${project.ext.versionNumber}-r${project.ext.revisionNumber}" - project.ext.revisionForPublication = project.ext.versionNumber.startsWith('SNAPSHOT') ? "r${project.ext.revisionNumber}" : project.ext.versionNumber - project.ext.cleanFlag = calculateCleanFlag() - - def buildInfo = "${project.ext.versionNumber}:${project.ext.revisionNumber}:${project.ext.cleanFlag}" - def buildInfoDev = "${project.ext.versionNumber}-dev:${project.ext.revisionNumber}:${project.ext.cleanFlag}" - - println "BUILD INFO for $project: $buildInfo" - - def targetsDistFolder = new File("${project.projectDir}/targets/dist") - targetsDistFolder.deleteDir() - targetsDistFolder.mkdirs() - - def targetDistBuildInfo = new File(targetsDistFolder, "BUILD-${project.name}.INFO") - targetDistBuildInfo << buildInfo - - def mainClassesFolder = new File("${project.projectDir}/targets/gradle/classes/java/main") - mainClassesFolder.mkdirs() - - def mainClassesBuildInfo = new File(mainClassesFolder, "BUILD-${project.name}.INFO") - mainClassesBuildInfo.delete() - mainClassesBuildInfo << buildInfoDev -} - -calculateBuildInfo() - -group='cisd' - -task checkRestrictions(type: Exec, dependsOn: [classes, testClasses]) { - doFirst { -/* - def cp = configurations.testImplementation.filter({ f -> f.name.startsWith('restrictionchecker') || f.name.startsWith('bcel')}).asPath - def cmd = ['java', '-cp', cp, 'ch.rinn.restrictions.RestrictionChecker', '-r', sourceSets.main.output.classesDirs.first()] - if (sourceSets.test.output.classesDirs.first().exists()) { - cmd.add(sourceSets.test.output.classesDirs.first()) - } - cmd.add('-cp') - cmd.add(sourceSets.main.output.classesDirs.first()) - if (sourceSets.test.output.classesDirs.first().exists()) { - cmd.add(sourceSets.test.output.classesDirs.first()) - } - cmd.add(configurations.testImplementation.asPath) - commandLine cmd -*/ - commandLine = ['pwd'] - } -} - -def deleteSymbolicLinksRecursively(file) { - def absolutePath = file.getAbsolutePath() - def canonicalPath = file.getCanonicalPath() - if (absolutePath.equals(canonicalPath) == false) { - file.delete(); - } else if (file.isDirectory()) { - File[] files = file.listFiles() - for (File child : files) { - deleteSymbolicLinksRecursively(child) - } - } -} - -task deleteSymLinks { - doFirst { - println "DELETE SYM LINKS in $buildDir" - deleteSymbolicLinksRecursively buildDir - } -} - -clean.dependsOn deleteSymLinks - -test { - useTestNG() - options.suites('sourceTest/java/tests.xml') - - systemProperty "ant.project.name", project.name - - maxHeapSize = "8192m" - jvmArgs '-Duser.timezone=Europe/Zurich', '-Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StrErrLog' - - testLogging.showStandardStreams = true - ignoreFailures = true -} -test.dependsOn checkRestrictions - -// Legacy Java 8 compiler from eclipse -dependencies { - ecj "eclipse:ecj:4.6.1" -} - -if(System.getProperty("java.version").startsWith("1.8.")) { - tasks.withType(JavaCompile) { - options.headerOutputDirectory.convention(null) - } -} - -compileJava { - options.encoding = 'utf-8' - options.fork = true - doFirst { - // Use the legacy Java 8 compiler from eclipse for Java 8 - if(System.getProperty("java.version").startsWith("1.8.")) { - options.forkOptions.with { - executable = 'java' - jvmArgs = createEclipseJDK8Args() - } - } else if(System.getProperty("java.version").startsWith("11.") || System.getProperty("java.version").startsWith("17.")) { - // Use modern openJDK 11 or 17 Compiler - } else { - throw new Exception("Unsupported Java version found: '" + System.getProperty("java.version") + "', please use JDK8, JDK11 or JDK17"); - } - } -} - -compileTestJava { - options.encoding = 'utf-8' - options.fork = true - doFirst { - // Use the legacy Java 8 compiler from eclipse for Java 8 - if(System.getProperty("java.version").startsWith("1.8.")) { - options.forkOptions.with { - executable = 'java' - jvmArgs = createEclipseJDK8Args() - } - } else if(System.getProperty("java.version").startsWith("11.") || System.getProperty("java.version").startsWith("17.")) { - // Use modern openJDK 11 or 17 Compiler - } else { - throw new Exception("Unsupported Java version found: '" + System.getProperty("java.version") + "', please use JDK8, JDK11 or JDK17"); - } - } -} - -def createEclipseJDK8Args() { - def args = ['-cp', configurations.ecj.asPath, 'org.eclipse.jdt.internal.compiler.batch.Main', '-nowarn'] - return args -} - -processTestResources { - fileMode=0666 -} - -apply plugin: 'eclipse' - -eclipse { - classpath { - downloadSources=true - defaultOutputDir = file('targets/classes') - } -} - -eclipse.classpath.file { - whenMerged{ classpath -> - def projectRefs = classpath.entries.findAll{entry -> entry.kind =='src' && entry.path.startsWith('/')} - classpath.entries.removeAll(projectRefs) - classpath.entries.addAll(projectRefs) - } -} - -task testJar(type: Jar, dependsOn: testClasses) { - baseName = "test-${project.archivesBaseName}" - from sourceSets.test.output -} - -task sourcesJar(type: Jar) { - duplicatesStrategy 'include' - classifier = 'sources' - from sourceSets.main.allSource -} - -compileJava.dependsOn sourcesJar - -artifacts { - tests testJar -} - -artifacts { - archives sourcesJar -} - -task compileDependencies(type: Copy) { - into "$buildDir/output/compile-dependencies" - from configurations.implementation -} - -task runtimeDependencies(type: Copy) { - into "$buildDir/output/runtime-dependencies" - from configurations.runtimeOnly -} - -task testCompileDependencies(type: Copy) { - into "$buildDir/output/testCompile-dependencies" - from configurations.testImplementation -} - -task testRuntimeDependencies(type: Copy) { - into "$buildDir/output/testRuntime-dependencies" - from configurations.testRuntimeOnly -} - -task checkDependencies(dependsOn: classes) { - doLast { - ant.taskdef(name: 'dependencychecker', classname: 'classycle.ant.DependencyCheckingTask', classpath: configurations.testRuntime.asPath) - ant.dependencychecker( - definitionFile: 'resource/dependency-structure.ddf', - failOnUnwantedDependencies: 'true', - mergeInnerClasses: 'true') { - fileset(dir: "${buildDir}", includes: "**/*.class") - } - } -} - -apply plugin: 'ivy-publish' -if (hasProperty('ivyRepository') == false || ''.equals(project.ivyRepository)) -{ - project.ext.ivyRepository = "${project.projectDir}/../ivy-repository" -} -publishing { - - repositories { - ivy { - ivyPattern "file://${project.ivyRepository}/[organisation]/[module]/[revision]/ivy.xml" - artifactPattern "file://${project.ivyRepository}/[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]" - } - } -} - -publish { - dependsOn build -} - -if (JavaVersion.current().isJava8Compatible()) { - tasks.withType(Javadoc) { - options.addStringOption('Xdoclint:none', '-quiet') - options.addStringOption('encoding', 'utf-8') - } -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/repository.gradle b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/repository.gradle deleted file mode 100644 index 1672a54cfb7..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/repository.gradle +++ /dev/null @@ -1,6 +0,0 @@ -ext.repositoryConfig = { - ivy { - ivyPattern "https://sissource.ethz.ch/openbis/openbis-public/openbis-ivy/-/raw/main/[organisation]/[module]/[revision]/ivy.xml" - artifactPattern "https://sissource.ethz.ch/openbis/openbis-public/openbis-ivy/-/raw/main/[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]" - } -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/settings.gradle b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/settings.gradle deleted file mode 100644 index 0abc667a666..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/settings.gradle +++ /dev/null @@ -1,21 +0,0 @@ -//includeFlat 'lib-commonbase', 'lib-common', 'api-openbis-java', 'lib-openbis-common', 'lib-authentication', 'lib-dbmigration', 'server-application-server', -// 'server-original-data-store', 'server-screening', 'server-external-data-store', -// 'ui-admin', 'lib-microservice-server', 'ui-eln-lims', 'api-openbis-javascript' -// -//def includes = ['lib-commonbase', 'lib-common', 'api-openbis-java', 'lib-openbis-common', 'api-openbis-javascript', -// 'lib-authentication', 'lib-dbmigration', 'server-application-server', 'server-original-data-store'] -// -//includes.forEach { name -> -// includeFlat(name) -// project(":${name}").projectDir = new File("../openbis/${name}") -//} - -def includes = ['lib-common', 'lib-commonbase', 'api-openbis-java', -'api-openbis-javascript', 'lib-openbis-common', 'lib-dbmigration', 'lib-authentication', -'server-original-data-store', 'server-application-server' -] - -includes.forEach { name -> - includeFlat(name) - project(":${name}").projectDir = new File("../../../../../../../../../../${name}") -} \ No newline at end of file diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/PingPongService.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/PingPongService.java deleted file mode 100644 index ae4934db548..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/PingPongService.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dss.plugins; - -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.service.CustomDSSServiceExecutionOptions; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.service.id.ICustomDSSServiceId; -import ch.ethz.sis.openbis.generic.dssapi.v3.plugin.service.ICustomDSSServiceExecutor; - -import java.io.Serializable; -import java.util.Map; -import java.util.Properties; - -public class PingPongService implements ICustomDSSServiceExecutor -{ - public PingPongService(Properties properties) - { - System.out.println("||> INIT PING PONG SERVICE"); - } - @Override - public Serializable executeService(String sessionToken, ICustomDSSServiceId serviceId, - CustomDSSServiceExecutionOptions options) - { - Map<String, Object> params = options.getParameters(); - if(params.containsKey("key") && params.get("key").toString().equalsIgnoreCase("PING")) - { - return "PONG"; - } - throw new IllegalArgumentException("Missing Ping parameter"); - } -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetConfig.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetConfig.java deleted file mode 100644 index 7ce7ed60b56..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetConfig.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dssapi.v3.dto.imaging; - -import ch.systemsx.cisd.base.annotation.JsonObject; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; - -@JsonObject("dss.dto.imaging.ImagingDataSetConfig") -public class ImagingDataSetConfig implements Serializable -{ - private static final long serialVersionUID = 1L; - - - @JsonProperty - private String adaptor; - - @JsonProperty - private Double version; - - @JsonProperty - private List<Integer> speeds; - - @JsonProperty - private List<String> resolutions; - - @JsonProperty - private boolean playable; - - @JsonProperty - private List<ImagingDataSetControl> exports; - - @JsonProperty - private List<ImagingDataSetControl> inputs; - - @JsonProperty - private Map<String, String> metaData; - - @JsonIgnore - public String getAdaptor() - { - return adaptor; - } - - public void setAdaptor(String adaptor) - { - this.adaptor = adaptor; - } - - @JsonIgnore - public Double getVersion() - { - return version; - } - - public void setVersion(Double version) - { - this.version = version; - } - - @JsonIgnore - public List<Integer> getSpeeds() - { - return speeds; - } - - public void setSpeeds(List<Integer> speeds) - { - this.speeds = speeds; - } - - @JsonIgnore - public List<String> getResolutions() - { - return resolutions; - } - - public void setResolutions(List<String> resolutions) - { - this.resolutions = resolutions; - } - - @JsonIgnore - public boolean isPlayable() - { - return playable; - } - - public void setPlayable(boolean playable) - { - this.playable = playable; - } - - @JsonIgnore - public List<ImagingDataSetControl> getExports() - { - return exports; - } - - public void setExports( - List<ImagingDataSetControl> exports) - { - this.exports = exports; - } - - @JsonIgnore - public List<ImagingDataSetControl> getInputs() - { - return inputs; - } - - public void setInputs( - List<ImagingDataSetControl> inputs) - { - this.inputs = inputs; - } - - @JsonIgnore - public Map<String, String> getMetaData() - { - return metaData; - } - - public void setMetaData(Map<String, String> metaData) - { - this.metaData = metaData; - } - - @Override - public String toString() - { - return "ImagingDataSetConfig: " + adaptor; - } -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControl.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControl.java deleted file mode 100644 index 7d5c27fe9ce..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControl.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dssapi.v3.dto.imaging; - -import ch.systemsx.cisd.base.annotation.JsonObject; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; - -@JsonObject("dss.dto.imaging.ImagingDataSetControl") -public class ImagingDataSetControl implements Serializable -{ - private static final long serialVersionUID = 1L; - - @JsonProperty - private String label; - - @JsonProperty - private String section; - - @JsonProperty - private String type; - - @JsonProperty - private List<String> values; - - @JsonProperty - private String unit; - - @JsonProperty - private List<String> range; - - @JsonProperty - private boolean multiselect; - - @JsonProperty - private Boolean playable; - - @JsonProperty - private List<Integer> speeds; - @JsonProperty - private List<ImagingDataSetControlVisibility> visibility; - - @JsonProperty - private Map<String, String> metaData; - - @JsonIgnore - public String getLabel() - { - return label; - } - - public void setLabel(String label) - { - this.label = label; - } - - @JsonIgnore - public String getSection() - { - return section; - } - - public void setSection(String section) - { - this.section = section; - } - - @JsonIgnore - public String getUnit() - { - return unit; - } - - public void setUnit(String unit) - { - this.unit = unit; - } - - @JsonIgnore - public String getType() - { - return type; - } - - public void setType(String type) - { - this.type = type; - } - - @JsonIgnore - public List<String> getValues() - { - return values; - } - - public void setValues(List<String> values) - { - this.values = values; - } - - @JsonIgnore - public boolean isMultiselect() - { - return multiselect; - } - - public void setMultiselect(boolean multiselect) - { - this.multiselect = multiselect; - } - - @JsonIgnore - public Boolean getPlayable() - { - return playable; - } - - public void setPlayable(Boolean playable) - { - this.playable = playable; - } - - @JsonIgnore - public List<Integer> getSpeeds() - { - return speeds; - } - - public void setSpeeds(List<Integer> speeds) - { - this.speeds = speeds; - } - - @JsonIgnore - public List<String> getRange() - { - return range; - } - - public void setRange(List<String> range) - { - this.range = range; - } - - @JsonIgnore - public List<ImagingDataSetControlVisibility> getVisibility() - { - return visibility; - } - - public void setVisibility( - List<ImagingDataSetControlVisibility> visibility) - { - this.visibility = visibility; - } - - @JsonIgnore - public Map<String, String> getMetaData() - { - return metaData; - } - - public void setMetaData(Map<String, String> metaData) - { - this.metaData = metaData; - } - - @Override - public String toString() - { - return "ImagingDataSetControl: " + label; - } -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControlVisibility.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControlVisibility.java deleted file mode 100644 index 2a364ad0745..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetControlVisibility.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dssapi.v3.dto.imaging; - -import ch.systemsx.cisd.base.annotation.JsonObject; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.io.Serializable; -import java.util.List; - -@JsonObject("dss.dto.imaging.ImagingDataSetControlVisibility") -public class ImagingDataSetControlVisibility implements Serializable -{ - private static final long serialVersionUID = 1L; - - @JsonProperty - private String label; - @JsonProperty - private List<String> values; - @JsonProperty - private List<String> range; - @JsonProperty - private String unit; - - @JsonIgnore - public String getLabel() - { - return label; - } - - public void setLabel(String label) - { - this.label = label; - } - @JsonIgnore - public List<String> getValues() - { - return values; - } - - public void setValues(List<String> values) - { - this.values = values; - } - @JsonIgnore - public List<String> getRange() - { - return range; - } - - public void setRange(List<String> range) - { - this.range = range; - } - - @JsonIgnore - public String getUnit() - { - return unit; - } - - public void setUnit(String unit) - { - this.unit = unit; - } - - @Override - public String toString() - { - return "ImagingDataSetControlVisibility: " + label; - } -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetExport.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetExport.java deleted file mode 100644 index 8d46949ea19..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetExport.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dssapi.v3.dto.imaging; - -import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.property.PropertiesDeserializer; -import ch.systemsx.cisd.base.annotation.JsonObject; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; - -import java.io.Serializable; -import java.util.Map; - -@JsonObject("dss.dto.imaging.ImagingDataSetExport") -public class ImagingDataSetExport implements Serializable -{ - private static final long serialVersionUID = 1L; - - @JsonProperty - @JsonDeserialize(contentUsing = PropertiesDeserializer.class) - private Map<String, Serializable> config; - - @JsonProperty - @JsonDeserialize(contentUsing = PropertiesDeserializer.class) - private Map<String, String> metaData; - - @JsonIgnore - public Map<String, Serializable> getConfig() - { - return config; - } - - public void setConfig(Map<String, Serializable> config) - { - this.config = config; - } - - @JsonIgnore - public Map<String, String> getMetaData() - { - return metaData; - } - - public void setMetaData(Map<String, String> metaData) - { - this.metaData = metaData; - } - - @Override - public String toString() - { - return "ImagingDataSetExport"; - } - -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetImage.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetImage.java deleted file mode 100644 index e726231d0e4..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetImage.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dssapi.v3.dto.imaging; - -import ch.systemsx.cisd.base.annotation.JsonObject; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; - -@JsonObject("dss.dto.imaging.ImagingDataSetImage") -public class ImagingDataSetImage implements Serializable -{ - private static final long serialVersionUID = 1L; - - @JsonProperty - private List<ImagingDataSetPreview> previews; - - @JsonProperty - private Map<String, Serializable> config; - - @JsonProperty - private Map<String, String> metaData; - - @JsonIgnore - public List<ImagingDataSetPreview> getPreviews() - { - return previews; - } - - public void setPreviews( - List<ImagingDataSetPreview> previews) - { - this.previews = previews; - } - - public Map<String, Serializable> getConfig() - { - return config; - } - - public void setConfig(Map<String, Serializable> config) - { - this.config = config; - } - - @JsonIgnore - public Map<String, String> getMetaData() - { - return metaData; - } - - public void setMetaData(Map<String, String> metaData) - { - this.metaData = metaData; - } - - @Override - public String toString() - { - return "ImagingDataSetImage:"; - } - -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetMultiExport.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetMultiExport.java deleted file mode 100644 index d46ced3b5a0..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetMultiExport.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dssapi.v3.dto.imaging; - - -import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.property.PropertiesDeserializer; -import ch.systemsx.cisd.base.annotation.JsonObject; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; - -@JsonObject("dss.dto.imaging.ImagingDataSetMultiExport") -public class ImagingDataSetMultiExport implements Serializable -{ - private static final long serialVersionUID = 1L; - - @JsonProperty - private String permId; - @JsonProperty - private int index; - - @JsonProperty - @JsonDeserialize(contentUsing = PropertiesDeserializer.class) - private Map<String, Serializable> config; - - @JsonProperty - @JsonDeserialize(contentUsing = PropertiesDeserializer.class) - private Map<String, String> metaData; - - @JsonIgnore - public String getPermId() - { - return permId; - } - - public void setPermId(String permId) { - this.permId = permId; - } - - @JsonIgnore - public int getIndex() - { - return index; - } - - public void setIndex(int index) { - this.index = index; - } - - @JsonIgnore - public Map<String, Serializable> getConfig() - { - return config; - } - - public void setConfig(Map<String, Serializable> config) - { - this.config = config; - } - - @JsonIgnore - public Map<String, String> getMetaData() - { - return metaData; - } - - public void setMetaData(Map<String, String> metaData) - { - this.metaData = metaData; - } - - @Override - public String toString() - { - return "ImagingDataSetMultiExport:" + permId; - } - -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetPreview.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetPreview.java deleted file mode 100644 index 39e85e507c7..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetPreview.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dssapi.v3.dto.imaging; - -import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.property.PropertiesDeserializer; -import ch.systemsx.cisd.base.annotation.JsonObject; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; - -@JsonObject("dss.dto.imaging.ImagingDataSetPreview") -public class ImagingDataSetPreview implements Serializable -{ - private static final long serialVersionUID = 1L; - - @JsonProperty - @JsonDeserialize(contentUsing = PropertiesDeserializer.class) - private Map<String, Serializable> config; - - @JsonProperty - private String format; - - @JsonProperty - private String bytes; - - @JsonProperty - private boolean show; - - @JsonProperty - private Map<String, String> metaData; - - - @JsonIgnore - public Map<String, Serializable> getConfig() - { - return config; - } - - public void setConfig(Map<String, Serializable> config) - { - this.config = config; - } - - @JsonIgnore - public String getFormat() - { - return format; - } - - public void setFormat(String format) - { - this.format = format; - } - - @JsonIgnore - public String getBytes() - { - return bytes; - } - - public void setBytes(String bytes) - { - this.bytes = bytes; - } - - @JsonIgnore - public boolean isShow() - { - return show; - } - - public void setShow(boolean show) - { - this.show = show; - } - - @JsonIgnore - public Map<String, String> getMetaData() - { - return metaData; - } - - public void setMetaData(Map<String, String> metaData) - { - this.metaData = metaData; - } - - @Override - public String toString() - { - return "ImagingDataSetPreview"; - } - -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetPropertyConfig.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetPropertyConfig.java deleted file mode 100644 index 7b9d9b71eb0..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/dssapi/v3/dto/imaging/ImagingDataSetPropertyConfig.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dssapi.v3.dto.imaging; - -import ch.systemsx.cisd.base.annotation.JsonObject; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.io.Serializable; -import java.util.List; - -@JsonObject("dss.dto.imaging.ImagingDataSetPropertyConfig") -public class ImagingDataSetPropertyConfig implements Serializable -{ - private static final long serialVersionUID = 1L; - - @JsonProperty - ImagingDataSetConfig config; - - @JsonProperty - List<ImagingDataSetImage> images; - - @JsonIgnore - public ImagingDataSetConfig getConfig() - { - return config; - } - - public void setConfig(ImagingDataSetConfig config) - { - this.config = config; - } - - @JsonIgnore - public List<ImagingDataSetImage> getImages() - { - return images; - } - - public void setImages( - List<ImagingDataSetImage> images) - { - this.images = images; - } - - -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingArchiver.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingArchiver.java deleted file mode 100644 index b550053a46c..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingArchiver.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dss.plugins.imaging; - -import ch.systemsx.cisd.common.exceptions.UserFailureException; -import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDataSetPackager; -import ch.systemsx.cisd.openbis.dss.generic.server.DataStoreServer; -import ch.systemsx.cisd.openbis.dss.generic.server.TarDataSetPackager; -import ch.systemsx.cisd.openbis.dss.generic.server.ZipDataSetPackager; -import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; -import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.ISessionWorkspaceProvider; -import org.apache.commons.io.FileUtils; - -import java.io.*; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.*; -import java.util.function.Function; - -class ImagingArchiver -{ - private final String sessionToken; - private final String exportDirName; - private final String exportArchiveName; - private final Function<InputStream, Long> checksumFunction; - private final AbstractDataSetPackager packager; - private final File archiveFile; - private boolean isFinished; - private final long archiveDate; - - private static final int DEFAULT_BUFFER_SIZE = (int) (10 * FileUtils.ONE_MB); - - ImagingArchiver(String sessionToken, String archiveFormat) throws IOException { - this.sessionToken = sessionToken; - isFinished = false; - - archiveDate = System.currentTimeMillis(); - exportDirName = "imaging_export_" + String.valueOf(archiveDate); - - ISessionWorkspaceProvider sessionWorkspaceProvider = getSessionWorkspaceProvider(sessionToken); - File rootDirectory = sessionWorkspaceProvider.getSessionWorkspace(); - - Path tempDir = Files.createDirectory( - Path.of(rootDirectory.getAbsolutePath(), exportDirName)); - - - if (archiveFormat.equalsIgnoreCase("zip")) - { - exportArchiveName = "export.zip"; - archiveFile = - Files.createFile(Path.of(tempDir.toAbsolutePath().toString(), exportArchiveName)) - .toFile(); - packager = new ZipDataSetPackager(archiveFile, true, null, null); - checksumFunction = Util::getCRC32Checksum; - } else if (archiveFormat.equalsIgnoreCase("tar")) - { - exportArchiveName = "export.tar.gz"; - archiveFile = - Files.createFile(Path.of(tempDir.toAbsolutePath().toString(), exportArchiveName)) - .toFile(); - packager = new TarDataSetPackager(archiveFile, null, null, DEFAULT_BUFFER_SIZE, - 5L * DEFAULT_BUFFER_SIZE); - checksumFunction = (x) -> 0L; - } else - { - throw new UserFailureException("Unknown archive format!"); - } - - - } - - void addToArchive(String folderName, String fileName, byte[] byteArray) { - assertNotFinished(); - long size = byteArray.length; - packager.addEntry(Paths.get(folderName, fileName).toString(), - archiveDate, - size, - checksumFunction.apply(new ByteArrayInputStream(byteArray)), - new ByteArrayInputStream(byteArray)); - } - - void addToArchive(String folderName, File fileOrDirectoryToArchive) { - assertNotFinished(); - - Deque<Map.Entry<String, File>> queue = new LinkedList<>(); - - queue.add(new AbstractMap.SimpleImmutableEntry<>(folderName, fileOrDirectoryToArchive)); - while (!queue.isEmpty()) - { - Map.Entry<String, File> element = queue.pollFirst(); - String prefixPath = element.getKey(); - File file = element.getValue(); - String path = Paths.get(prefixPath, file.getName()).toString(); - if (file.isDirectory()) - { - for (File f : file.listFiles()) - { - queue.add(new AbstractMap.SimpleImmutableEntry<>(path, f)); - } - packager.addDirectoryEntry(path); - } else - { - try - { - packager.addEntry(path, - file.lastModified(), - file.getTotalSpace(), - checksumFunction.apply(new FileInputStream(file)), - new FileInputStream(file)); - } catch (IOException exc) - { - throw new UserFailureException("Failed during export!", exc); - } - } - } - - } - - String build() { - if(!isFinished) { - isFinished = true; - packager.close(); - } - String url = DataStoreServer.getConfigParameters().getDownloadURL() + "/datastore_server/session_workspace_file_download?sessionID=" + sessionToken + "&filePath="; - return url + Path.of(exportDirName, exportArchiveName); - } - - private ISessionWorkspaceProvider getSessionWorkspaceProvider(String sessionToken) - { - return ServiceProvider.getDataStoreService().getSessionWorkspaceProvider(sessionToken); - } - - private void assertNotFinished() - { - if(isFinished){ - throw new UserFailureException("Archive file is already closed!"); - } - } - - -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingService.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingService.java deleted file mode 100644 index 6c1278fddd9..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingService.java +++ /dev/null @@ -1,398 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dss.plugins.imaging; - -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.dssapi.v3.IDataStoreServerApi; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging.ImagingDataSetImage; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging.ImagingDataSetMultiExport; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging.ImagingDataSetPreview; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging.ImagingDataSetPropertyConfig; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.service.CustomDSSServiceExecutionOptions; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.service.id.ICustomDSSServiceId; -import ch.ethz.sis.openbis.generic.server.dss.plugins.imaging.adaptor.IImagingDataSetAdaptor; -import ch.ethz.sis.openbis.generic.server.dss.plugins.imaging.container.ImagingDataContainer; -import ch.ethz.sis.openbis.generic.server.dss.plugins.imaging.container.ImagingExportContainer; -import ch.ethz.sis.openbis.generic.server.dss.plugins.imaging.container.ImagingMultiExportContainer; -import ch.ethz.sis.openbis.generic.server.dss.plugins.imaging.container.ImagingPreviewContainer; -import ch.ethz.sis.openbis.generic.dssapi.v3.plugin.service.ICustomDSSServiceExecutor; -import ch.systemsx.cisd.common.exceptions.UserFailureException; -import ch.systemsx.cisd.common.logging.LogCategory; -import ch.systemsx.cisd.common.reflection.ClassUtils; -import ch.systemsx.cisd.openbis.common.io.hierarchical_content.api.IHierarchicalContent; -import ch.systemsx.cisd.openbis.common.io.hierarchical_content.api.IHierarchicalContentNode; -import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDataSetPackager; -import ch.systemsx.cisd.openbis.dss.generic.server.DataStoreServer; -import ch.systemsx.cisd.openbis.dss.generic.server.TarDataSetPackager; -import ch.systemsx.cisd.openbis.dss.generic.server.ZipDataSetPackager; -import ch.systemsx.cisd.openbis.dss.generic.shared.IHierarchicalContentProvider; -import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; -import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.ISessionWorkspaceProvider; -import ch.systemsx.cisd.openbis.generic.shared.dto.OpenBISSessionHolder; -import ch.systemsx.cisd.common.logging.LogFactory; -import org.apache.commons.io.FileUtils; -import org.apache.log4j.Logger; - -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.*; -import java.util.function.Function; - -public class ImagingService implements ICustomDSSServiceExecutor -{ - - private final Properties properties; - - private IHierarchicalContentProvider contentProvider; - - private static final Logger - operationLog = LogFactory.getLogger(LogCategory.OPERATION, ImagingService.class); - - private static final int DEFAULT_BUFFER_SIZE = (int) (10 * FileUtils.ONE_MB); - - private static final String IMAGING_CONFIG_PROPERTY_NAME = "$IMAGING_DATA_CONFIG"; - - public ImagingService(Properties properties) - { - this.properties = properties; - } - - @Override - public Serializable executeService(String sessionToken, ICustomDSSServiceId serviceId, - CustomDSSServiceExecutionOptions options) - { - operationLog.info("Executing imaging service:" + serviceId); - ImagingDataContainer data = getDataFromParams(options.getParameters()); - try - { - if (data.getType().equalsIgnoreCase("preview")) - { - return processPreviewFlow(sessionToken, (ImagingPreviewContainer) data); - } else if (data.getType().equalsIgnoreCase("export")) - { - return processExportFlow(sessionToken, (ImagingExportContainer) data); - } else if (data.getType().equalsIgnoreCase("multi-export")) - { - return processMultiExportFlow(sessionToken, (ImagingMultiExportContainer) data); - } else - { - throw new UserFailureException("Unknown request type!"); - } - } catch (Exception e) - { - data.setError(e.toString()); - } - return data; - } - - private IImagingDataSetAdaptor getAdaptor(ImagingDataSetPropertyConfig config) - { - final String adaptorName = config.getConfig().getAdaptor(); - - if (adaptorName == null || adaptorName.isBlank()) - { - throw new UserFailureException("Adaptor name is missing from the config!"); - } - try - { - return ClassUtils.create(IImagingDataSetAdaptor.class, adaptorName, properties); - } catch (Exception e) - { - throw new UserFailureException("Could not load adapter: " + adaptorName, e); - } - } - - private File getRootFile(String sessionToken, DataSet dataSet) - { - IHierarchicalContent content = - getHierarchicalContentProvider(sessionToken).asContent( - dataSet.getPermId().getPermId()); - IHierarchicalContentNode root = content.getRootNode(); - return root.getFile(); - } - - private ImagingPreviewContainer processPreviewFlow(String sessionToken, - ImagingPreviewContainer data) - { - DataSet dataSet = getDataSet(sessionToken, data.getPermId()); - - ImagingDataSetPropertyConfig config = - Util.readConfig(dataSet.getJsonProperty("$IMAGING_DATA_CONFIG"), - ImagingDataSetPropertyConfig.class); - - IImagingDataSetAdaptor adaptor = getAdaptor(config); - File rootFile = getRootFile(sessionToken, dataSet); - Map<String, Serializable> previewParams = data.getPreview().getConfig(); - Map<String, String> meta = data.getPreview().getMetaData(); - String format = data.getPreview().getFormat(); - - int index = data.getIndex(); - if (config.getImages().size() <= index) - { - throw new UserFailureException("There is no image with index:" + index); - } - Map<String, Serializable> imageConfig = config.getImages().get(index).getConfig(); - - if (format == null || format.isBlank()) - { - throw new UserFailureException("Format can not be empty!"); - } - - ImagingServiceContext context = - new ImagingServiceContext(sessionToken, getApplicationServerApi(), - getDataStoreServerApi()); - - data.getPreview().setBytes( - adaptor.process(context, - rootFile, imageConfig, previewParams, meta, format).toString()); - return data; - } - - - - private Serializable processExportFlow(String sessionToken, ImagingExportContainer data) - { - // Get all parameters - final DataSet dataSet = getDataSet(sessionToken, data.getPermId()); - final ImagingDataSetPropertyConfig config = - Util.readConfig(dataSet.getJsonProperty(IMAGING_CONFIG_PROPERTY_NAME), - ImagingDataSetPropertyConfig.class); - - final File rootFile = getRootFile(sessionToken, dataSet); - final int index = data.getIndex(); - if (config.getImages().size() <= index) - { - throw new UserFailureException("There is no image with index:" + index); - } - - final ImagingDataSetImage image = config.getImages().get(index); - - // TODO: discuss image config as filtering for export - Map<String, Serializable> imageConfig = image.getConfig(); - - Map<String, Serializable> exportConfig = data.getExport().getConfig(); - Validator.validateExportConfig(exportConfig); - - Serializable[] exportTypes = (Serializable[]) exportConfig.get("include"); - - ImagingArchiver archiver; - - // Prepare archiver - try - { - archiver = new ImagingArchiver(sessionToken, exportConfig.get("archive-format").toString()); - } catch (IOException exception) - { - throw new UserFailureException("Could not export data!", exception); - } - - // For each export type, perform adequate action - for (Serializable exportType : exportTypes) - { - if (exportType.toString().equalsIgnoreCase("image")) - { - ImagingServiceContext context = - new ImagingServiceContext(sessionToken, getApplicationServerApi(), - getDataStoreServerApi()); - IImagingDataSetAdaptor adaptor = getAdaptor(config); - archiveImage(context, adaptor, image, index, exportConfig, rootFile, "", archiver); - } else if (exportType.toString().equalsIgnoreCase("raw data")) - { - archiveRawData(rootFile, "", archiver, dataSet); - } else - { - throw new UserFailureException("Unknown export type!"); - } - - } - - data.setUrl(archiver.build()); - return data; - } - - private Serializable processMultiExportFlow(String sessionToken, ImagingMultiExportContainer data) - { - // multi export case - final String archiveFormat = "zip"; - ImagingArchiver archiver; - try - { - archiver = new ImagingArchiver(sessionToken, archiveFormat); - } catch (IOException exception) - { - throw new UserFailureException("Could not export data!", exception); - } - - for (ImagingDataSetMultiExport export : data.getExports()) - { - DataSet dataSet = getDataSet(sessionToken, export.getPermId()); - ImagingDataSetPropertyConfig config = - Util.readConfig(dataSet.getJsonProperty(IMAGING_CONFIG_PROPERTY_NAME), - ImagingDataSetPropertyConfig.class); - - File rootFile = getRootFile(sessionToken, dataSet); - - final int index = export.getIndex(); - if (config.getImages().size() <= index) - { - throw new UserFailureException("There is no image with index:" + index); - } - - ImagingDataSetImage image = config.getImages().get(index); - - // TODO: discuss image config as filtering for export - Map<String, Serializable> imageConfig = image.getConfig(); - - Map<String, Serializable> exportConfig = export.getConfig(); - Validator.validateExportConfig(exportConfig); - - Serializable[] exportTypes = (Serializable[]) exportConfig.get("include"); - - // For each export type, perform adequate action - for (Serializable exportType : exportTypes) - { - if (exportType.toString().equalsIgnoreCase("image")) - { - ImagingServiceContext context = - new ImagingServiceContext(sessionToken, getApplicationServerApi(), - getDataStoreServerApi()); - IImagingDataSetAdaptor adaptor = getAdaptor(config); - archiveImage(context, adaptor, image, index, exportConfig, rootFile, export.getPermId(), archiver); - } else if (exportType.toString().equalsIgnoreCase("raw data")) - { - archiveRawData(rootFile, export.getPermId(), archiver, dataSet); - } else - { - throw new UserFailureException("Unknown export type!"); - } - - } - } - data.setUrl(archiver.build()); - return data; - } - - - private IHierarchicalContentProvider getHierarchicalContentProvider(String sessionToken) - { - if (contentProvider == null) - { - contentProvider = ServiceProvider.getHierarchicalContentProvider(); - } - OpenBISSessionHolder sessionTokenHolder = new OpenBISSessionHolder(); - sessionTokenHolder.setSessionToken(sessionToken); - return contentProvider.cloneFor(sessionTokenHolder); - } - - private IApplicationServerApi getApplicationServerApi() - { - return ServiceProvider.getV3ApplicationService(); - } - - private IDataStoreServerApi getDataStoreServerApi() - { - return ServiceProvider.getV3DataStoreService(); - } - - private DataSet getDataSet(String sessionToken, String permId) - { - DataSetFetchOptions fetchOptions = new DataSetFetchOptions(); - fetchOptions.withProperties(); - fetchOptions.withType(); - fetchOptions.withDataStore(); - fetchOptions.withPhysicalData(); - Map<IDataSetId, DataSet> result = getApplicationServerApi() - .getDataSets(sessionToken, List.of(new DataSetPermId(permId)), - fetchOptions); - if (result.isEmpty()) - { - throw new UserFailureException("Could not find Dataset:" + permId); - } - return result.get(new DataSetPermId(permId)); - } - - - - private ImagingDataContainer getDataFromParams(Map<String, Object> params) - { - Validator.validateInputParams(params); - - String type = (String) params.get("type"); - String json = Util.mapToJson(params); - - switch (type.toLowerCase()) - { - case "preview": - return Util.readConfig(json, ImagingPreviewContainer.class); - case "export": - return Util.readConfig(json, ImagingExportContainer.class); - case "multi-export": - return Util.readConfig(json, ImagingMultiExportContainer.class); - default: - throw new UserFailureException("Wrong type:" + type); - } - } - - private void archiveRawData(File rootFile, String rootFolderName, - ImagingArchiver archiver, DataSet dataSet) - { - //Add dataset files to archive - archiver.addToArchive(rootFolderName, rootFile); - //Add dataset properties to archive - Map<String, Serializable> properties = dataSet.getProperties(); - properties.remove(IMAGING_CONFIG_PROPERTY_NAME); - if(!properties.isEmpty()) { - byte[] json = Util.mapToJson(properties).getBytes(StandardCharsets.UTF_8); - archiver.addToArchive(rootFolderName, "properties.txt", json); - } - } - - - private void archiveImage(ImagingServiceContext context, IImagingDataSetAdaptor adaptor, - ImagingDataSetImage image, int imageIdx, Map<String, Serializable> exportConfig, - File rootFile, String rootFolderName, ImagingArchiver archiver) { - - String imageFormat = exportConfig.get("image-format").toString(); - int previewIdx = 0; - for(ImagingDataSetPreview preview : image.getPreviews()) - { - String format = imageFormat; - if(imageFormat.equalsIgnoreCase("original")) { - format = preview.getFormat(); - } - Map<String, Serializable> params = preview.getConfig(); - params.put("resolution", exportConfig.get("resolution")); - Serializable img = adaptor.process(context, - rootFile, image.getConfig(), params, image.getMetaData(), format); - String imgString = img.toString(); - byte[] decoded = Base64.getDecoder().decode(imgString); - String fileName = "image" + imageIdx +"_preview" + previewIdx + "." + format; - - archiver.addToArchive(rootFolderName, fileName, decoded); - previewIdx++; - } - } - -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingServiceContext.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingServiceContext.java deleted file mode 100644 index b6d33d169f6..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingServiceContext.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dss.plugins.imaging; - -import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi; -import ch.ethz.sis.openbis.generic.dssapi.v3.IDataStoreServerApi; - -import java.io.Serializable; - -public final class ImagingServiceContext implements Serializable -{ - - private final String sessionToken; - private final IApplicationServerApi asApi; - private final IDataStoreServerApi dssApi; - - - public ImagingServiceContext(String sessionToken, IApplicationServerApi asApi, IDataStoreServerApi dssApi) { - this.sessionToken = sessionToken; - this.asApi = asApi; - this.dssApi = dssApi; - } - - public String getSessionToken() - { - return sessionToken; - } - - public IApplicationServerApi getAsApi() - { - return asApi; - } - - public IDataStoreServerApi getDssApi() - { - return dssApi; - } -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/Util.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/Util.java deleted file mode 100644 index f39f10af48c..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/Util.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dss.plugins.imaging; - -import ch.systemsx.cisd.common.exceptions.UserFailureException; -import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDataSetPackager; -import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.nio.file.Paths; -import java.util.AbstractMap; -import java.util.Deque; -import java.util.LinkedList; -import java.util.Map; -import java.util.function.Function; -import java.util.zip.CRC32; - -class Util -{ - private Util() {} - - private static ObjectMapper getObjectMapper() - { - return ServiceProvider.getObjectMapperV3(); - } - - static long getCRC32Checksum(InputStream input) - { - if (input == null) - throw new UserFailureException("Can not compute crc32!"); - CRC32 crc = new CRC32(); - byte[] buffer = new byte[4096]; - try - { - while (true) - { - int length = input.read(buffer); - if (length == -1) - break; - crc.update(buffer, 0, length); - } - } catch (Exception ex) - { - try - { - input.close(); - } catch (Exception ignored) - { - } - } - return crc.getValue(); - } - - static <T> T readConfig(String val, Class<T> clazz) - { - try - { - ObjectMapper objectMapper = getObjectMapper(); - return objectMapper.readValue(new ByteArrayInputStream(val.getBytes()), - clazz); - } catch (JsonMappingException mappingException) - { - throw new UserFailureException(mappingException.toString(), mappingException); - } catch (Exception e) - { - throw new UserFailureException("Could not read the parameters!", e); - } - } - - static String mapToJson(Map<String, ?> map) - { - try - { - ObjectMapper objectMapper = getObjectMapper(); - return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(map); - } catch (Exception e) - { - throw new UserFailureException("Could not serialize the input parameters!", e); - } - } - - - - static void archiveFiles(AbstractDataSetPackager packager, File rootFile, String rootFolderName, - Function<InputStream, Long> checksumFunction) - { - Deque<Map.Entry<String, File>> queue = new LinkedList<>(); - - queue.add(new AbstractMap.SimpleImmutableEntry<>(rootFolderName, rootFile)); - while (!queue.isEmpty()) - { - Map.Entry<String, File> element = queue.pollFirst(); - String prefixPath = element.getKey(); - File file = element.getValue(); - String path = Paths.get(prefixPath, file.getName()).toString(); - if (file.isDirectory()) - { - for (File f : file.listFiles()) - { - queue.add(new AbstractMap.SimpleImmutableEntry<>(path, f)); - } - packager.addDirectoryEntry(path); - } else - { - try - { - FileInputStream fileStream = new FileInputStream(file); - packager.addEntry(path, file.lastModified(), file.getTotalSpace(), - checksumFunction.apply(fileStream), new FileInputStream(file)); - } catch (IOException exc) - { - throw new UserFailureException("Failed during export!", exc); - } - } - } - - } - -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/Validator.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/Validator.java deleted file mode 100644 index f9248caf9aa..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/Validator.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dss.plugins.imaging; - -import ch.systemsx.cisd.common.exceptions.UserFailureException; - -import java.io.Serializable; -import java.util.Map; - -class Validator -{ - private Validator() {} - - - static void validateInputParams(Map<String, Object> params) - { -// if (!params.containsKey("permId")) -// { -// throw new UserFailureException("Missing dataset permId!"); -// } - if (!params.containsKey("type")) - { - throw new UserFailureException("Missing type!"); - } -// if (!params.containsKey("index")) -// { -// throw new UserFailureException("Missing index!"); -// } - } - - - static void validateExportConfig(Map<String, Serializable> exportConfig) { - if(exportConfig == null) { - throw new UserFailureException("Export config can not be empty!"); - } - validateTag(exportConfig, "include", true); - validateTag(exportConfig, "image-format"); - validateTag(exportConfig, "archive-format"); - validateTag(exportConfig, "resolution"); - } - - private static void validateTag(Map<String, Serializable> config, String tagName) - { - validateTag(config, tagName, false); - } - - private static void validateTag(Map<String, Serializable> config, String tagName, boolean isMultiValue) - { - if(!config.containsKey(tagName)){ - throw new UserFailureException("Missing '"+tagName+"' in export config!"); - } - Serializable include = config.get(tagName); - if(include == null){ - throw new UserFailureException("'"+tagName+"' tag in export config can not be null!"); - } - if(isMultiValue) - { - if (!include.getClass().isArray()) - { - throw new UserFailureException("'include' tag in export config must be an array!"); - } - if (((Serializable[]) include).length == 0) - { - throw new UserFailureException("'include' tag in export config can not be empty!"); - } - } - } - - -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetExampleAdaptor.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetExampleAdaptor.java deleted file mode 100644 index 536f0837571..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetExampleAdaptor.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dss.plugins.imaging.adaptor; - -import ch.ethz.sis.openbis.generic.server.dss.plugins.imaging.ImagingServiceContext; - -import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.Serializable; -import java.util.Base64; -import java.util.Map; -import java.util.Properties; - -public final class ImagingDataSetExampleAdaptor implements IImagingDataSetAdaptor -{ - - private static final int WIDTH = 640; - private static final int HEIGHT = 640; - - public ImagingDataSetExampleAdaptor(Properties properties) { - } - - @Override - public Serializable process(ImagingServiceContext context, File rootFile, Map<String, Serializable> imageConfig, - Map<String, Serializable> previewConfig, Map<String, String> metaData, String format) - { - BufferedImage img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB); - for(int y=0;y<HEIGHT; y++) - { - for (int x = 0; x < WIDTH; x++) - { - int a = (int)(Math.random()*256); - int r = (int)(Math.random()*256); - int g = (int)(Math.random()*256); - int b = (int)(Math.random()*256); - - //pixel - int p = (a<<24) | (r<<16) | (g<<8) | b; - - img.setRGB(x, y, p); - } - } - try - { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - ImageIO.write(img, "png", byteArrayOutputStream); - byteArrayOutputStream.flush(); - return Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray()); - } catch (Exception e) { - throw new RuntimeException(e); - } - } -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetJythonAdaptor.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetJythonAdaptor.java deleted file mode 100644 index 1a53bcd5c64..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetJythonAdaptor.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dss.plugins.imaging.adaptor; - -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.service.CustomDSSServiceExecutionOptions; -import ch.ethz.sis.openbis.generic.server.dss.plugins.imaging.ImagingServiceContext; -import ch.ethz.sis.openbis.generic.server.dssapi.v3.helper.IDssServiceScriptRunner; -import ch.ethz.sis.openbis.generic.server.dssapi.v3.helper.ScriptRunnerFactory; -import ch.systemsx.cisd.common.exceptions.UserFailureException; - -import java.io.File; -import java.io.Serializable; -import java.util.Map; -import java.util.Properties; - -public class ImagingDataSetJythonAdaptor implements IImagingDataSetAdaptor -{ - private final String scriptPath; - - - public ImagingDataSetJythonAdaptor(Properties properties) { - this.scriptPath = properties.getProperty("script-path", ""); - if(scriptPath.isBlank()) { - throw new UserFailureException("There is no script defined for this adaptor!"); - } - } - @Override - public Serializable process(ImagingServiceContext context, File rootFile, Map<String, Serializable> imageConfig, - Map<String, Serializable> previewConfig, Map<String, String> metaData, String format) - { - CustomDSSServiceExecutionOptions options = new CustomDSSServiceExecutionOptions(); - options.withParameter("sessionToken", context.getSessionToken()); - options.withParameter("asApi", context.getAsApi()); - options.withParameter("dssApi", context.getDssApi()); - options.withParameter("file", rootFile); - options.withParameter("imageConfig", imageConfig); - options.withParameter("config", previewConfig); - options.withParameter("metaData", metaData); - IDssServiceScriptRunner - runner = new ScriptRunnerFactory(scriptPath, context.getAsApi(), - context.getDssApi()) - .createServiceRunner(context.getSessionToken()); - return runner.process(options); - } -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetPythonAdaptor.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetPythonAdaptor.java deleted file mode 100644 index b616666b257..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/ImagingDataSetPythonAdaptor.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dss.plugins.imaging.adaptor; - -import ch.ethz.sis.openbis.generic.server.dss.plugins.imaging.ImagingServiceContext; -import ch.ethz.sis.openbis.generic.server.sharedapi.v3.json.GenericObjectMapper; -import ch.systemsx.cisd.common.exceptions.UserFailureException; -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.io.File; -import java.io.IOException; -import java.io.Serializable; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; - -public abstract class ImagingDataSetPythonAdaptor implements IImagingDataSetAdaptor -{ - - protected String pythonPath; - - protected String scriptPath; - - @Override - public Serializable process(ImagingServiceContext context, File rootFile, Map<String, Serializable> imageConfig, - Map<String, Serializable> previewConfig, Map<String, String> metaData, String format) - { - - ProcessBuilder processBuilder = new ProcessBuilder(pythonPath, - scriptPath, rootFile.getAbsolutePath(), convertMapToJson(imageConfig), - convertMapToJson(previewConfig), convertMapToJson(metaData), format); - processBuilder.redirectErrorStream(false); - - String fullOutput; - try - { - Process process = processBuilder.start(); - fullOutput = - new String(process.getInputStream().readAllBytes(), StandardCharsets.UTF_8); - int exitCode = process.waitFor(); - if (exitCode != 0) - { - String error = - new String(process.getErrorStream().readAllBytes(), StandardCharsets.UTF_8); - throw new UserFailureException("Script evaluation failed: " + error); - } - } catch (IOException | InterruptedException e) - { - throw new RuntimeException(e); - } - - if (fullOutput.isBlank()) - { - throw new UserFailureException("Script produced no results!"); - } - - String[] resultSplit = fullOutput.split("\n"); - return resultSplit[resultSplit.length - 1]; - } - - private String convertMapToJson(Map<String, ?> map) - { - Map<String, ?> mapToConvert = map; - if(map == null) { - mapToConvert = new HashMap<>(); - } - try - { - ObjectMapper objectMapper = new GenericObjectMapper(); - return objectMapper.writeValueAsString(mapToConvert); - } catch (Exception e) - { - throw new UserFailureException("Couldn't convert map to string", e); - } - } - -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/NanonisDatAdaptor.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/NanonisDatAdaptor.java deleted file mode 100644 index 4b66f8cf576..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/NanonisDatAdaptor.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dss.plugins.imaging.adaptor; - -import ch.ethz.sis.openbis.generic.server.dss.plugins.imaging.ImagingServiceContext; -import ch.systemsx.cisd.common.exceptions.UserFailureException; - -import java.io.File; -import java.io.Serializable; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Map; -import java.util.Properties; - -public class NanonisDatAdaptor extends ImagingDataSetPythonAdaptor -{ - private final String DAT_SCRIPT_PROPERTY = "nanonis-dat"; - - - public NanonisDatAdaptor(Properties properties) - { - - String scriptProperty = properties.getProperty(DAT_SCRIPT_PROPERTY, ""); - if (scriptProperty.isBlank()) - { - throw new UserFailureException( - "There is no script path property called '" + DAT_SCRIPT_PROPERTY + "' defined for this adaptor!"); - } - Path script = Paths.get(scriptProperty); - if (!Files.exists(script)) - { - throw new UserFailureException("Script file " + script + " does not exists!"); - } - this.scriptPath = script.toString(); - this.pythonPath = properties.getProperty("python3-path", "python3"); - } - - @Override - public Serializable process( - ImagingServiceContext context, File rootFile, Map<String, Serializable> imageConfig, - Map<String, Serializable> previewConfig, Map<String, String> metaData, String format) - { - Serializable result = super.process(context, rootFile, imageConfig, previewConfig, metaData, format); - if (result == null) - { - return result; - } - String str = result.toString(); - if (str.length() > 3) - { - return str.substring(2, str.length() - 1); - } else - { - return ""; - } - - } - -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/NanonisSxmAdaptor.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/NanonisSxmAdaptor.java deleted file mode 100644 index 4f7601ec881..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/adaptor/NanonisSxmAdaptor.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dss.plugins.imaging.adaptor; - -import ch.systemsx.cisd.common.exceptions.UserFailureException; -import ch.ethz.sis.openbis.generic.server.dss.plugins.imaging.ImagingServiceContext; -import ch.ethz.sis.openbis.generic.server.sharedapi.v3.json.GenericObjectMapper; -import ch.systemsx.cisd.common.exceptions.UserFailureException; -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.io.File; -import java.io.IOException; -import java.io.Serializable; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Map; -import java.util.Properties; - -public final class NanonisSxmAdaptor extends ImagingDataSetPythonAdaptor -{ - private final String SXM_SCRIPT_PROPERTY = "nanonis-sxm"; - - public NanonisSxmAdaptor(Properties properties) - { - - String scriptProperty = properties.getProperty(SXM_SCRIPT_PROPERTY, ""); - if (scriptProperty.isBlank()) - { - throw new UserFailureException( - "There is no script path property called '" + SXM_SCRIPT_PROPERTY + "' defined for this adaptor!"); - } - Path script = Paths.get(scriptProperty); - if (!Files.exists(script)) - { - throw new UserFailureException("Script file " + script + " does not exists!"); - } - this.scriptPath = script.toString(); - this.pythonPath = properties.getProperty("python3-path", "python3"); - } - - @Override - public Serializable process(ImagingServiceContext context, File rootFile, Map<String, Serializable> imageConfig, - Map<String, Serializable> previewConfig, Map<String, String> metaData, String format) - { - Serializable result = super.process(context, rootFile, imageConfig, previewConfig, metaData, format); - if (result == null) - { - return result; - } - String str = result.toString(); - if (str.length() > 3) - { - return str.substring(2, str.length() - 1); - } else - { - return ""; - } - - } - -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingDataContainer.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingDataContainer.java deleted file mode 100644 index 7c07d1c0b91..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingDataContainer.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dss.plugins.imaging.container; - -import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.io.Serializable; - -public abstract class ImagingDataContainer implements Serializable -{ - - @JsonProperty - private String type; - - @JsonProperty - private String error; - - @JsonIgnore - public String getType() - { - return type; - } - - public void setType(String type) { - this.type = type; - } - - @JsonIgnore - public String getError() - { - return error; - } - - public void setError(String error) - { - this.error = error; - } - - - -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingExportContainer.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingExportContainer.java deleted file mode 100644 index c1e5fed445d..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingExportContainer.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dss.plugins.imaging.container; - -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging.ImagingDataSetExport; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; - -public final class ImagingExportContainer extends ImagingDataContainer -{ - - @JsonProperty - private String permId; - @JsonProperty - private int index; - @JsonProperty - private String url; - @JsonProperty - private ImagingDataSetExport export = null; - - @JsonIgnore - public String getPermId() - { - return permId; - } - - public void setPermId(String permId) { - this.permId = permId; - } - - @JsonIgnore - public int getIndex() - { - return index; - } - - public void setIndex(int index) { - this.index = index; - } - - @JsonIgnore - public String getUrl() - { - return url; - } - - public void setUrl(String url) - { - this.url = url; - } - - @JsonIgnore - public ImagingDataSetExport getExport() - { - return export; - } - - public void setExport(ImagingDataSetExport export) - { - this.export = export; - } -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingMultiExportContainer.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingMultiExportContainer.java deleted file mode 100644 index 183cb54dfd5..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingMultiExportContainer.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dss.plugins.imaging.container; - -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging.ImagingDataSetMultiExport; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; - -public class ImagingMultiExportContainer extends ImagingDataContainer -{ - - @JsonProperty - private String url; - - @JsonProperty - private List<ImagingDataSetMultiExport> exports = null; - - @JsonIgnore - public String getUrl() - { - return url; - } - - public void setUrl(String url) - { - this.url = url; - } - - @JsonIgnore - public List<ImagingDataSetMultiExport> getExports() - { - return exports; - } - - public void setExports(List<ImagingDataSetMultiExport> exports) - { - this.exports = exports; - } -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingPreviewContainer.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingPreviewContainer.java deleted file mode 100644 index d5d5e23973d..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/container/ImagingPreviewContainer.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dss.plugins.imaging.container; - -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.imaging.ImagingDataSetPreview; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; - -public final class ImagingPreviewContainer extends ImagingDataContainer -{ - - @JsonProperty - private String permId; - @JsonProperty - private int index; - @JsonProperty - private ImagingDataSetPreview preview = null; - - @JsonIgnore - public String getPermId() - { - return permId; - } - - public void setPermId(String permId) { - this.permId = permId; - } - - @JsonIgnore - public int getIndex() - { - return index; - } - - public void setIndex(int index) { - this.index = index; - } - - @JsonIgnore - public ImagingDataSetPreview getPreview() - { - return preview; - } - - public void setPreview(ImagingDataSetPreview preview) - { - this.preview = preview; - } -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetConfig.js b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetConfig.js deleted file mode 100644 index c44fe0fac0f..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetConfig.js +++ /dev/null @@ -1,91 +0,0 @@ -define([ "stjs", "util/Exceptions" ], function(stjs, exceptions) { - var ImagingDataSetConfig = function() { - }; - stjs.extend(ImagingDataSetConfig, null, [], function(constructor, prototype) { - prototype['@type'] = 'dss.dto.imaging.ImagingDataSetConfig'; - constructor.serialVersionUID = 1; - prototype.adaptor = null; - prototype.version = null; - prototype.speeds = null; - prototype.resolutions = null; - prototype.playable = null; - prototype.exports = null; - prototype.inputs = null; - prototype.metaData = null; - - prototype.getAdaptor = function() { - return this.adaptor; - }; - prototype.setAdaptor = function(adaptor) { - this.adaptor = adaptor; - }; - prototype.getVersion = function() { - return this.version; - }; - prototype.setVersion = function(version) { - this.version = version; - }; - prototype.getSpeeds = function() { - return this.speeds; - }; - prototype.setSpeeds = function(speeds) { - this.speeds = speeds; - }; - prototype.getResolutions = function() { - return this.resolutions; - }; - prototype.setResolutions = function(resolutions) { - this.resolutions = resolutions; - }; - prototype.getPlayable = function() { - return this.playable; - }; - prototype.setPlayable = function(playable) { - this.playable = playable; - }; - prototype.getExports = function() { - return this.exports; - }; - prototype.setExports = function(exports) { - this.exports = exports; - }; - prototype.getInputs = function() { - return this.inputs; - }; - prototype.setInputs = function(inputs) { - this.inputs = inputs; - }; - prototype.getMetaData = function() { - return this.metaData; - }; - prototype.setMetaData = function(metaData) { - this.metaData = metaData; - }; - prototype.toString = function() { - return "ImagingDataSetConfig: " + this.adaptor; - }; - - }, { - resolutions : { - name : "List", - arguments : [ "String"] - }, - speeds : { - name : "List", - arguments : [ "Integer"] - }, - exports : { - name : "List", - arguments : [ "ImagingDataSetControl"] - }, - inputs : { - name : "List", - arguments : [ "ImagingDataSetControl"] - }, - metaData : { - name : "Map", - arguments : [ "String", "String" ] - } - }); - return ImagingDataSetConfig; -}) \ No newline at end of file diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetControl.js b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetControl.js deleted file mode 100644 index 30c9b6c9a38..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetControl.js +++ /dev/null @@ -1,112 +0,0 @@ -define([ "stjs", "util/Exceptions" ], function(stjs, exceptions) { - var ImagingDataSetControl = function() { - }; - stjs.extend(ImagingDataSetControl, null, [], function(constructor, prototype) { - prototype['@type'] = 'dss.dto.imaging.ImagingDataSetControl'; - constructor.serialVersionUID = 1; - prototype.label = null; - prototype.section = null; - prototype.type = null; - prototype.values = null; - prototype.unit = null; - prototype.range = null; - prototype.multiselect = null; - prototype.playable = null; - prototype.speeds = null; - prototype.visibility = null; - prototype.metaData = null; - - prototype.getLabel = function() { - return this.label; - }; - prototype.setLabel = function(label) { - this.label = label; - }; - prototype.getSection = function() { - return this.section; - }; - prototype.setSection = function(section) { - this.section = section; - }; - prototype.getType = function() { - return this.type; - }; - prototype.setType = function(type) { - this.type = type; - }; - prototype.getValues = function() { - return this.values; - }; - prototype.setValues = function(values) { - this.values = values; - }; - prototype.getUnit = function() { - return this.unit; - }; - prototype.setUnit = function(unit) { - this.unit = unit; - }; - prototype.getRange = function() { - return this.range; - }; - prototype.setRange = function(range) { - this.range = range; - }; - prototype.getMultiselect = function() { - return this.multiselect; - }; - prototype.setMultiselect = function(multiselect) { - this.multiselect = multiselect; - }; - prototype.getPlayable = function() { - return this.playable; - }; - prototype.setPlayable = function(playable) { - this.playable = playable; - }; - prototype.getSpeeds = function() { - return this.speeds; - }; - prototype.setSpeeds = function(speeds) { - this.speeds = speeds; - }; - prototype.getVisibility = function() { - return this.visibility; - }; - prototype.setVisibility = function(visibility) { - this.visibility = visibility; - }; - prototype.getMetaData = function() { - return this.metaData; - }; - prototype.setMetaData = function(metaData) { - this.metaData = metaData; - }; - prototype.toString = function() { - return "ImagingDataSetControl: " + this.label; - }; - - }, { - values : { - name : "List", - arguments : [ "String"] - }, - visibility: { - name : "List", - arguments : [ "ImagingDataSetControlVisibility"] - } - range : { - name : "List", - arguments : [ "String"] - }, - speeds : { - name : "List", - arguments : [ "Integer"] - }, - metaData : { - name : "Map", - arguments : [ "String", "String" ] - } - }); - return ImagingDataSetControl; -}) \ No newline at end of file diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetControlVisibility.js b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetControlVisibility.js deleted file mode 100644 index 5a0b2fc7711..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetControlVisibility.js +++ /dev/null @@ -1,51 +0,0 @@ -define([ "stjs", "util/Exceptions" ], function(stjs, exceptions) { - var ImagingDataSetControlVisibility = function() { - }; - stjs.extend(ImagingDataSetControlVisibility, null, [], function(constructor, prototype) { - prototype['@type'] = 'dss.dto.imaging.ImagingDataSetControlVisibility'; - constructor.serialVersionUID = 1; - prototype.label = null; - prototype.values = null; - prototype.range = null; - prototype.unit = null; - - prototype.getLabel = function() { - return this.label; - }; - prototype.setLabel = function(label) { - this.label = label; - }; - prototype.getValues = function() { - return this.values; - }; - prototype.setValues = function(values) { - this.values = values; - }; - prototype.getUnit = function() { - return this.unit; - }; - prototype.setUnit = function(unit) { - this.unit = unit; - }; - prototype.getRange = function() { - return this.range; - }; - prototype.setRange = function(range) { - this.range = range; - }; - prototype.toString = function() { - return "ImagingDataSetControlVisibility: " + this.label; - }; - - }, { - values : { - name : "List", - arguments : [ "String"] - }, - range : { - name : "List", - arguments : [ "String"] - } - }); - return ImagingDataSetControlVisibility; -}) \ No newline at end of file diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetExport.js b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetExport.js deleted file mode 100644 index a478e50fcc6..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetExport.js +++ /dev/null @@ -1,58 +0,0 @@ -define([ "stjs", "util/Exceptions" ], function(stjs, exceptions) { - var ImagingDataSetExport = function() { - }; - stjs.extend(ImagingDataSetExport, null, [], function(constructor, prototype) { - prototype['@type'] = 'dss.dto.imaging.ImagingDataSetExport'; - constructor.serialVersionUID = 1; - prototype.config = null; - prototype.format = null; - prototype.bytes = null; - prototype.show = null; - prototype.metaData = null; - - prototype.getConfig = function() { - return this.config; - }; - prototype.setConfig = function(config) { - this.config = config; - }; - prototype.getFormat = function() { - return this.format; - }; - prototype.setFormat = function(format) { - this.format = format; - }; - prototype.getBytes = function() { - return this.bytes; - }; - prototype.setBytes = function(bytes) { - this.bytes = bytes; - }; - prototype.isShow = function() { - return this.show; - }; - prototype.setShow = function(show) { - this.show = show; - }; - prototype.getMetaData = function() { - return this.metaData; - }; - prototype.setMetaData = function(metaData) { - this.metaData = metaData; - }; - prototype.toString = function() { - return "ImagingDataSetExport: " + this.config; - }; - - }, { - config : { - name : "Map", - arguments : [ "String", "Serializable" ] - }, - metaData : { - name : "Map", - arguments : [ "String", "String" ] - } - }); - return ImagingDataSetExport; -}) \ No newline at end of file diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetImage.js b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetImage.js deleted file mode 100644 index cabcef4beca..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetImage.js +++ /dev/null @@ -1,37 +0,0 @@ -define([ "stjs", "util/Exceptions" ], function(stjs, exceptions) { - var ImagingDataSetImage = function() { - }; - stjs.extend(ImagingDataSetImage, null, [], function(constructor, prototype) { - prototype['@type'] = 'dss.dto.imaging.ImagingDataSetImage'; - constructor.serialVersionUID = 1; - prototype.previews = null; - prototype.metaData = null; - - prototype.getPreviews = function() { - return this.previews; - }; - prototype.setPreviews = function(previews) { - this.previews = previews; - }; - prototype.getMetaData = function() { - return this.metaData; - }; - prototype.setMetaData = function(metaData) { - this.metaData = metaData; - }; - prototype.toString = function() { - return "ImagingDataSetImage: " + this.previews; - }; - - }, { - previews : { - name : "List", - arguments : [ "ImagingDataSetPreview"] - }, - metaData : { - name : "Map", - arguments : [ "String", "String" ] - } - }); - return ImagingDataSetImage; -}) \ No newline at end of file diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetPreview.js b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetPreview.js deleted file mode 100644 index f119f0c2e32..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetPreview.js +++ /dev/null @@ -1,58 +0,0 @@ -define([ "stjs", "util/Exceptions" ], function(stjs, exceptions) { - var ImagingDataSetPreview = function() { - }; - stjs.extend(ImagingDataSetPreview, null, [], function(constructor, prototype) { - prototype['@type'] = 'dss.dto.imaging.ImagingDataSetPreview'; - constructor.serialVersionUID = 1; - prototype.config = null; - prototype.format = null; - prototype.bytes = null; - prototype.show = null; - prototype.metaData = null; - - prototype.getConfig = function() { - return this.config; - }; - prototype.setConfig = function(config) { - this.config = config; - }; - prototype.getFormat = function() { - return this.format; - }; - prototype.setFormat = function(format) { - this.format = format; - }; - prototype.getBytes = function() { - return this.bytes; - }; - prototype.setBytes = function(bytes) { - this.bytes = bytes; - }; - prototype.isShow = function() { - return this.show; - }; - prototype.setShow = function(show) { - this.show = show; - }; - prototype.getMetaData = function() { - return this.metaData; - }; - prototype.setMetaData = function(metaData) { - this.metaData = metaData; - }; - prototype.toString = function() { - return "ImagingDataSetPreview: " + this.config; - }; - - }, { - config : { - name : "Map", - arguments : [ "String", "Serializable" ] - }, - metaData : { - name : "Map", - arguments : [ "String", "String" ] - } - }); - return ImagingDataSetPreview; -}) \ No newline at end of file diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetPropertyConfig.js b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetPropertyConfig.js deleted file mode 100644 index 3b0b820e8cc..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/js/src/v3/dss/dto/imaging/ImagingDataSetPropertyConfig.js +++ /dev/null @@ -1,34 +0,0 @@ -define([ "stjs", "util/Exceptions" ], function(stjs, exceptions) { - var ImagingDataSetPropertyConfig = function() { - }; - stjs.extend(ImagingDataSetPropertyConfig, null, [], function(constructor, prototype) { - prototype['@type'] = 'dss.dto.imaging.ImagingDataSetPropertyConfig'; - constructor.serialVersionUID = 1; - prototype.config = null; - prototype.images = null; - - prototype.getConfig = function() { - return this.config; - }; - prototype.setConfig = function(config) { - this.config = config; - }; - prototype.getImages = function() { - return this.images; - }; - prototype.setSection = function(images) { - this.images = images; - }; - - prototype.toString = function() { - return "ImagingDataSetPropertyConfig: " + this.label; - }; - - }, { - images : { - name : "List", - arguments : [ "ImagingDataSetImage"] - } - }); - return ImagingDataSetPropertyConfig; -}) \ No newline at end of file diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/python/imaging/__init__.py b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/python/imaging/__init__.py deleted file mode 100644 index ea4523e5b12..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/python/imaging/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright ETH 2023 Zürich, Scientific IT Services -# -# 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. -# -from . import imaging - -name = "imaging" -__author__ = "ID SIS • ETH Zürich" -__email__ = "openbis-support@id.ethz.ch" -__version__ = "0.0.0" - - diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/python/imaging/imaging.py b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/python/imaging/imaging.py deleted file mode 100644 index fccc9d84387..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/python/imaging/imaging.py +++ /dev/null @@ -1,448 +0,0 @@ -# Copyright ETH 2023 Zürich, Scientific IT Services -# -# 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. -# - -from pybis import Openbis -import abc -import json -import base64 -import requests -import os -from urllib.parse import urljoin - - -DEFAULT_SERVICE_NAME = "imaging" -IMAGING_CONFIG_PROP_NAME = "$IMAGING_DATA_CONFIG".lower() - - -def get_instance(url="http://localhost:8888/openbis"): - base_url = url - # base_url = "http://localhost:8888/openbis" - # base_url = "https://alaskowski:8443/openbis" - # base_url = "https://openbis-sis-ci-sprint.ethz.ch/" - openbis_instance = Openbis( - url=base_url, - verify_certificates=False, - allow_http_but_do_not_use_this_in_production_and_only_within_safe_networks=True - ) - token = openbis_instance.login('admin', 'changeit') - print(f'Connected to {base_url} -> token: {token}') - return openbis_instance - - -class AbstractImagingClass(metaclass=abc.ABCMeta): - def to_json(self): - return json.dumps(self, default=lambda x: x.__dict__, sort_keys=True, indent=4) - - def __str__(self): - return json.dumps(self.__dict__, default=lambda x: x.__dict__) - - def __repr__(self): - return json.dumps(self.__dict__, default=lambda x: x.__dict__) - - -class AbstractImagingRequest(AbstractImagingClass, metaclass=abc.ABCMeta): - @abc.abstractmethod - def _validate_data(self): - return - - -class ImagingDataSetPreview(AbstractImagingRequest): - config: dict - format: str - bytes: str | None - show: bool - metadata: dict - - def __init__(self, config, preview_format, metadata=None): - self.__dict__["@type"] = "dss.dto.imaging.ImagingDataSetPreview" - self.bytes = None - self.format = preview_format - self.config = config if config is not None else dict() - self.metadata = metadata if metadata is not None else dict() - self._validate_data() - - def _validate_data(self): - assert self.format is not None, "Format can not be null" - - def save_to_file(self, file_path): - assert self.bytes is not None, "There is no image information!" - img_data = bytearray(self.bytes, encoding='utf-8') - with open(file_path, "wb") as fh: - fh.write(base64.decodebytes(img_data)) - - @classmethod - def from_dict(cls, data): - if data is None: - return None - preview = cls(None, None, None) - for prop in cls.__annotations__.keys(): - attribute = data.get(prop) - preview.__dict__[prop] = attribute - return preview - - -class ImagingDataSetExport(AbstractImagingRequest): - config: dict - metadata: dict - - def __init__(self, config, metadata=None): - self.__dict__["@type"] = "dss.dto.imaging.ImagingDataSetExport" - self.config = config if config is not None else dict() - self.metadata = metadata if metadata is not None else dict() - self._validate_data() - - def _validate_data(self): - assert self.config is not None, "Config can not be null" - required_keys = {"include", "archive-format", "image-format", "resolution"} - for key in required_keys: - assert key in self.config and self.config[key] is not None, \ - f"export->config->{key}: Must not be None!" - - -class ImagingDataSetMultiExport(AbstractImagingRequest): - permId: str - index: int - config: dict - metadata: dict - - def __init__(self, permId, index, config, metadata=None): - self.__dict__["@type"] = "dss.dto.imaging.ImagingDataSetMultiExport" - self.permId = permId - self.index = index - self.config = config - self.metadata = metadata if metadata is not None else dict() - self._validate_data() - - def _validate_data(self): - assert self.permId is not None, "PermId can not be null" - assert self.index is not None, "Index can not be null" - assert self.config is not None, "Config can not be null" - required_keys = {"include", "archive-format", "image-format", "resolution"} - for key in required_keys: - assert key in self.config and self.config[key] is not None, \ - f"export->config->{key}: Must not be None!" - - -class ImagingDataSetControlVisibility(AbstractImagingClass): - label: str - values: list[str] - range: list[str] - unit: str - - def __init__(self, label: str, values: list[str], values_range: list[str], unit: str = None): - self.__dict__["@type"] = "dss.dto.imaging.ImagingDataSetControlVisibility" - self.label = label - self.values = values - self.range = values_range - self.unit = unit - - @classmethod - def from_dict(cls, data): - if data is None: - return None - control = cls(None, None, None, None) - for prop in cls.__annotations__.keys(): - attribute = data.get(prop) - control.__dict__[prop] = attribute - return control - - -class ImagingDataSetControl(AbstractImagingClass): - label: str - section: str - type: str - values: list[str] - unit: str - range: list[str] - multiselect: bool - playable: bool - speeds: list[int] - visibility: list[ImagingDataSetControlVisibility] - metaData: dict - - def __init__(self, label: str, control_type: str, values: list[str] = None, - values_range: list[str] = None, multiselect: bool = None): - self.__dict__["@type"] = "dss.dto.imaging.ImagingDataSetControl" - self.label = label - self.type = control_type - if control_type.lower() in ["slider", "range"]: - self.range = values_range - elif control_type.lower() == "dropdown": - self.values = values - self.multiselect = multiselect - - @classmethod - def from_dict(cls, data): - if data is None: - return None - control = cls(None, "", None, None) - for prop in cls.__annotations__.keys(): - attribute = data.get(prop) - if prop == 'visibility' and attribute is not None: - attribute = [ImagingDataSetControlVisibility.from_dict(visibility) for visibility in attribute] - control.__dict__[prop] = attribute - return control - - -class ImagingDataSetConfig(AbstractImagingClass): - adaptor: str - version: float - speeds: list[int] - resolutions: list[str] - playable: bool - exports: list[ImagingDataSetControl] - inputs: list[ImagingDataSetControl] - metadata: dict - - def __init__(self, adaptor: str, version: float, resolutions: list[str], playable: bool, - speeds: list[int] = None, exports: list[ImagingDataSetControl] = None, - inputs: list[ImagingDataSetControl] = None, metadata: dict = None): - self.__dict__["@type"] = "dss.dto.imaging.ImagingDataSetConfig" - self.adaptor = adaptor - self.version = version - self.resolutions = resolutions - self.playable = playable - if playable: - self.speeds = speeds - self.exports = exports - self.inputs = inputs - self.metadata = metadata - - @classmethod - def from_dict(cls, data): - if data is None: - return None - config = cls(None, None, None, None) - for prop in cls.__annotations__.keys(): - attribute = data.get(prop) - if prop in ['exports', 'inputs'] and attribute is not None: - attribute = [ImagingDataSetControl.from_dict(control) for control in attribute] - config.__dict__[prop] = attribute - return config - - -class ImagingDataSetImage(AbstractImagingClass): - previews: list[ImagingDataSetPreview] - config: dict - metadata: dict - - def __init__(self, config=None, previews=None, metadata=None): - self.__dict__["@type"] = "dss.dto.imaging.ImagingDataSetImage" - self.config = config if config is not None else dict() - self.previews = previews if previews is not None else [] - self.metadata = metadata if metadata is not None else dict() - - def add_preview(self, preview): - self.previews += [preview] - - @classmethod - def from_dict(cls, data): - if data is None: - return None - image = cls(None, None, None) - for prop in cls.__annotations__.keys(): - attribute = data.get(prop) - if prop == 'images' and attribute is not None: - attribute = [ImagingDataSetPreview.from_dict(image) for image in attribute] - image.__dict__[prop] = attribute - return image - - -class ImagingDataSetPropertyConfig(AbstractImagingClass): - config: ImagingDataSetConfig - images: list[ImagingDataSetImage] - - def __init__(self, config: ImagingDataSetConfig, images: list[ImagingDataSetImage]): - assert config is not None, "Config must not be None!" - self.__dict__["@type"] = "dss.dto.imaging.ImagingDataSetPropertyConfig" - self.config = config - self.images = images if images is not None else [] - - @classmethod - def from_dict(cls, data: dict): - assert data is not None and any(data), "There is no property config found!" - config = ImagingDataSetConfig.from_dict(data.get('config')) - attr = data.get('images') - images = [ImagingDataSetImage.from_dict(image) for image in attr] if attr is not None else None - return cls(config, images) - - def add_image(self, image: ImagingDataSetImage): - if self.images is None: - self.images = [] - self.images += [image] - - -class ImagingControl: - - def __init__(self, openbis_instance, service_name=DEFAULT_SERVICE_NAME): - self._openbis = openbis_instance - self._service_name = service_name - - def _execute_custom_dss_service(self, parameters): - service_id = { - "@type": "dss.dto.service.id.CustomDssServiceCode", - "permId": self._service_name - } - options = { - "@type": "dss.dto.service.CustomDSSServiceExecutionOptions", - "parameters": parameters - } - request = { - "method": "executeCustomDSSService", - "params": [ - self._openbis.token, - service_id, - options - ], - } - full_url = urljoin(self._openbis._get_dss_url(), self._openbis.dss_v3) - return self._openbis._post_request_full_url(full_url, request) - - def make_preview(self, perm_id: str, index: int, preview: ImagingDataSetPreview) -> ImagingDataSetPreview: - parameters = { - "type": "preview", - "permId": perm_id, - "index": index, - "error": None, - "preview": preview.__dict__ - } - service_response = self._execute_custom_dss_service(parameters) - if service_response['error'] is None: - preview.__dict__ = service_response["preview"] - return preview - else: - raise ValueError(service_response['error']) - - def get_export_url(self, perm_id: str, export: ImagingDataSetExport, image_index: int = 0) -> str: - parameters = { - "type": "export", - "permId": perm_id, - "index": image_index, - "error": None, - "url": None, - "export": export.__dict__ - } - service_response = self._execute_custom_dss_service(parameters) - if service_response['error'] is None: - return service_response['url'] - else: - raise ValueError(service_response['error']) - - def get_multi_export_url(self, exports: list[ImagingDataSetMultiExport]) -> str: - parameters = { - "type": "multi-export", - "error": None, - "url": None, - "exports": [export.__dict__ for export in exports] - } - service_response = self._execute_custom_dss_service(parameters) - if service_response['error'] is None: - return service_response['url'] - else: - raise ValueError(service_response['error']) - - def single_export_download(self, perm_id: str, export: ImagingDataSetExport, image_index: int = 0, directory_path=""): - export_url = self.get_export_url(perm_id, export, image_index) - self._download(export_url, directory_path) - - def multi_export_download(self, exports: list[ImagingDataSetMultiExport], directory_path=""): - export_url = self.get_multi_export_url(exports) - self._download(export_url, directory_path) - - def _download(self, url, directory_path=""): - get_response = requests.get(url, stream=True) - file_name = url.split("/")[-1] - with open(os.path.join(directory_path, file_name), 'wb') as f: - for chunk in get_response.iter_content(chunk_size=1024): - if chunk: - f.write(chunk) - - def get_property_config(self, perm_id: str) -> ImagingDataSetPropertyConfig: - dataset = self._openbis.get_dataset(perm_id) - imaging_property = json.loads(dataset.props[IMAGING_CONFIG_PROP_NAME]) - return ImagingDataSetPropertyConfig.from_dict(imaging_property) - - def update_property_config(self, perm_id: str, config: ImagingDataSetPropertyConfig): - dataset = self._openbis.get_dataset(perm_id) - dataset.props[IMAGING_CONFIG_PROP_NAME] = config.to_json() - dataset.save() - - -# o = get_instance() -# -# -# # imaging_preview = ImagingDataSetPreview(preview_format="png", config=config_sxm) -# # response = get_preview('20231110130838616-26', 0, imaging_preview) -# # print(response) -# -# config_export = { -# "include": ['image', 'raw data'], -# "image-format": 'original', -# "archive-format": "zip", -# "resolution": "original" -# } -# # imaging_export = ImagingDataSetExport(config_export) -# # export_response = get_export('20231110130838616-26', 0, imaging_export) -# # print(export_response) -# -# -# # imaging_export1 = ImagingDataSetMultiExport('20231110130838616-26', 0, config_export) -# # imaging_export2 = ImagingDataSetMultiExport('20231110134813653-27', 0, config_export) -# # multi_export_response = get_multi_export([imaging_export1, imaging_export2]) -# # print(multi_export_response) -# -# -# # imaging_property_config = get_property_config('20231110134813653-27') -# # print(imaging_property_config.to_json()) -# -# ic = ImagingControl(o) -# perm_id = '20231110130838616-26' -# pc = ic.get_property_config(perm_id) -# -# -# -# config_sxm_preview = { -# "channel": "z", # usually one of these: ['z', 'I', 'dIdV', 'dIdV_Y'] -# "x-axis": [1.2, 3.0], # file dependent -# "y-axis": [1.2, 3.0], # file dependent -# "color-scale": [-700.0, 700.0], # file dependend -# "colormap": "gray", # [gray, YlOrBr, viridis, cividis, inferno, rainbow, Spectral, RdBu, RdGy] -# "scaling": "linear", # ['linear', 'logarithmic'] -# # "mode": 3 # uncomment this if you want to generate random pixel image generation -# } -# -# # imaging_preview = ImagingDataSetPreview(preview_format="png", config=config_sxm_preview) -# # -# # preview = ic.make_preview(perm_id, 0, imaging_preview) -# # pc.images[0].add_preview(preview) -# # ic.update_property_config(perm_id, pc) -# # -# # print(ic.get_property_config(perm_id)) -# -# -# -# config_export = { -# "include": ['image', 'raw data'], -# "image-format": 'original', -# "archive-format": "zip", -# "resolution": "original" -# } -# imaging_export = ImagingDataSetExport(config_export) -# ic.single_export_download(perm_id, imaging_export, 0, '/home/alaskowski/PREMISE') - - - - - diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/python/tests/test_imaging.py b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/python/tests/test_imaging.py deleted file mode 100644 index 05b18b5f834..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/source/python/tests/test_imaging.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright ETH 2023 Zürich, Scientific IT Services -# -# 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. -# - -import unittest -import imaging.imaging as imaging -from unittest.mock import MagicMock -import json - -IMAGING_CONFIG_PROP_NAME = "$IMAGING_DATA_CONFIG".lower() - -PROPER_CONFIG = { - "config": { - "adaptor": "some.adaptor.class.MyAdaptorClass", - "version": 1.0, - "speeds": [1, 2, 5], - "resolutions": ["150dpi", "300dpi"], - "playable": True, - "exports": [{ - "label": "Archive", - "type": "Dropdown", - "values": ["zip", "tar.gz"], - "multiselect": False, - "metaData": {} - }], - "inputs": [{ - "label": "Option 1", - "section": "section", - "type": "Dropdown", - "values": ["a", "b", "c"], - "multiselect": True, - "playable": False, - "metaData": {} - }, { - "label": "Option 2", - "section": "section", - "type": "Slider", - "unit": "cm", - "range": ["1", "2", "0.1"], - "multiselect": False, - "playable": True, - "speeds": [1, 2, 5], - "metaData": {} - }, { - "label": "Option 2", - "section": "section", - "type": "Range", - "multiselect": False, - "playable": False, - "visibility": [{ - "label": "Option 1", - "values": ["a", "b"], - "range": ["1", "2", "0.1"], - "unit": "mm" - }, { - "label": "Option 1", - "values": ["c"], - "range": ["0", "100", "1"], - "unit": "px" - }], - "metaData": {} - }], - "metadata": {} - }, - "images": [{ - "previews": [{ - "config": {}, - "format": "png", - "bytes": "base64_encoded_bytes", - "show": False, - "metadata": {} - }], - "config": {}, - "metadata": {} - }] -} - - -class ImagingTestCase(unittest.TestCase): - - def setUp(self): - self.dataset_mock = MagicMock() - self.set_dataset_config(PROPER_CONFIG) - - self.openbis_mock = MagicMock() - self.openbis_mock.get_dataset.return_value = self.dataset_mock - - self.imaging_control = imaging.ImagingControl(self.openbis_mock) - - def set_dataset_config(self, config): - json_config = json.dumps(config) - self.dataset_mock.props = {IMAGING_CONFIG_PROP_NAME: json_config} - - def test_get_proper_config(self): - config = self.imaging_control.get_property_config('some_perm_id') - assert len(config.images) == 1 - assert len(config.images[0].previews) == 1 - - def test_get_empty_config(self): - self.set_dataset_config(None) - self.assertRaises(AssertionError, self.imaging_control.get_property_config, 'some_perm_id') - - #TODO expand tests - - - -if __name__ == '__main__': - unittest.main() diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/sourceTest/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingServiceTest.java b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/sourceTest/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingServiceTest.java deleted file mode 100644 index 9327e229c57..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/sourceTest/java/ch/ethz/sis/openbis/generic/server/dss/plugins/imaging/ImagingServiceTest.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright ETH 2023 Zürich, Scientific IT Services - * - * 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.dss.plugins.imaging; - -import static org.junit.Assert.fail; - -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.delete.DataSetDeletionOptions; -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.service.CustomDSSServiceExecutionOptions; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.service.id.CustomDssServiceCode; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.service.id.ICustomDSSServiceId; -import ch.ethz.sis.openbis.generic.server.dss.plugins.imaging.container.ImagingPreviewContainer; -import org.testng.annotations.Test; -import org.junit.Assert.*; - -import java.util.*; - - -public class ImagingServiceTest //extends AbstractFileTest -{ - - - @Test - public void testImagingService() throws Exception - { -// fail(); -// String sessionToken = as.login(TEST_USER, PASSWORD); -// -// DataSetPermId dataSetPermId = new DataSetPermId("TEST-IMAGING-" + UUID.randomUUID().toString()); -// createDirectories(workingDirectory, new HashSet<>(List.of("dss-root", "dss-root/store", "dss-root/store/1", -// "dss-root/store/1/" + dataSetPermId.getPermId()))); -// createFiles(workingDirectory, List.of("dss-root/store/1/" + dataSetPermId.getPermId() + "/file1.txt")); -// -// try -// { -// PhysicalDataCreation physicalCreation = new PhysicalDataCreation(); -// physicalCreation.setLocation(dataSetPermId.getPermId()); -// physicalCreation.setFileFormatTypeId(new FileFormatTypePermId("TIFF")); -// physicalCreation.setLocatorTypeId(new RelativeLocationLocatorTypePermId()); -// physicalCreation.setStorageFormatId(new ProprietaryStorageFormatPermId()); -// -// DataSetCreation creation = new DataSetCreation(); -// creation.setCode(dataSetPermId.getPermId()); -// creation.setDataSetKind(DataSetKind.PHYSICAL); -// creation.setTypeId(new EntityTypePermId("IMAGING_DATA")); -// creation.setExperimentId(new ExperimentIdentifier("/TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST")); -// creation.setDataStoreId(new DataStorePermId("STANDARD")); -// creation.setPhysicalData(physicalCreation); -// creation.setProperty("$IMAGING_DATA_CONFIG", "{\"config\" : { \"@type\" : \"dss.dto.imaging.ImagingDataSetConfig\", \"adaptor\" : \"ch.ethz.sis.openbis.generic.server.dss.plugins.imaging.adaptor.ImagingDataSetExampleAdaptor\" } }"); -// -// -// List<DataSetPermId> ds = as.createDataSets(sessionToken, Arrays.asList(creation)); -// DataSetPermId pds = ds.get(0); -// -// ICustomDSSServiceId serviceId = new CustomDssServiceCode("imaging"); -// -// Map<String, Object> map = Map.of("@type", "dss.dto.imaging.ImagingDataSetPreview", -// "config", Map.of("Dimension 1", new Integer[] {1,2})); -// -// CustomDSSServiceExecutionOptions options = new CustomDSSServiceExecutionOptions(); -// options.withParameter("type", "preview"); -// options.withParameter("permId", pds.getPermId()); -// options.withParameter("index", 0); -// options.withParameter("preview", map); -// Object executionResult = dss.executeCustomDSSService(sessionToken, serviceId, options); -// -//// assertTrue(executionResult instanceof ImagingPreviewContainer); -//// ImagingPreviewContainer result = (ImagingPreviewContainer) executionResult; -//// -//// assertNotNull(result.getPreview().getBytes()); -// } -// finally -// { -// DataSetDeletionOptions options = new DataSetDeletionOptions(); -// options.setReason("cleanup"); -// as.deleteDataSets(sessionToken, Arrays.asList(dataSetPermId), options); -// as.logout(sessionToken); -// } - } - - - - - - - - - - - - -} diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/sourceTest/java/tests.xml b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/sourceTest/java/tests.xml deleted file mode 100644 index adca2f5bb61..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/lib/premise-sources/sourceTest/java/tests.xml +++ /dev/null @@ -1,12 +0,0 @@ -<suite name="All" verbose="2"> - <test name="All" annotations="JDK"> - <groups> - <run> - <exclude name="broken" /> - </run> - </groups> - <packages> - <package name="ch.ethz.sis.openbis.generic.server.dss.plugins.imaging.*" /> - </packages> - </test> -</suite> diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_dat.py b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_dat.py deleted file mode 100644 index 6b1c598587a..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_dat.py +++ /dev/null @@ -1,119 +0,0 @@ -import numpy -from PIL import Image -import io -import base64 -import sys -import json -import os -import sys -from spmpy_terry import spm # <--- class spm defines objects of type spm with their attributes and class functions -import spmpy_terry as spmpy # <--- spmpy has other methods -from datetime import datetime - -import matplotlib.pyplot as plt -# %matplotlib inline - - -def load_image(path): - return spm(path) - - -def get_lock_in(img): - param_name = 'lock-in>lock-in status' - param = img.get_param(param_name) - return param - - -def get_channel(img, channel_name = 'z'): - # channel_name = 'z' - channel = img.get_channel(channel_name) - return channel - - -file = sys.argv[1] -image_params = json.loads(sys.argv[2]) -params = json.loads(sys.argv[3]) -meta_data = json.loads(sys.argv[4]) -format = sys.argv[5] - - -folder_dir = os.path.join(file, 'original') -file_path = os.path.join(folder_dir, os.listdir(folder_dir)[0]) -# print(file_path) - - -def generate_random_image(height, width): - imarray = numpy.random.rand(height,width,3) * 255 - im = Image.fromarray(imarray.astype('uint8')).convert('RGBA') - img_byte_arr = io.BytesIO() - im.save(img_byte_arr, format=format) - img_byte_arr = img_byte_arr.getvalue() - encoded = base64.b64encode(img_byte_arr) - return encoded - - -def get_dat_image(channel_x, channel_y, x_axis, y_axis, colormap, scaling, grouping, print_legend): - specs = spmpy.importall(folder_dir, '', 'spec') - - for spec in specs: - date_time = spec.get_param('Saved Date') - spec.date_time = datetime.strptime(date_time, "%d.%m.%Y %H:%M:%S") - - # sort measurements according to date - specs.sort(key=lambda d: d.date_time) - specs_sub = list(filter(lambda spec:spec.name in grouping, specs)) - - print_legend = print_legend - show = False - fig = spmpy.specs_plot(specs_sub, channelx=channel_x, channely=channel_y, direction='forward', - print_legend=print_legend, show=show, colormap=colormap, scaling=scaling, - x_axis=x_axis, y_axis=y_axis) - - img_byte_arr = io.BytesIO() - plt.savefig(img_byte_arr, format=format) - img_byte_arr = img_byte_arr.getvalue() - encoded = base64.b64encode(img_byte_arr) - return encoded - - - - - -print(params) -if 'mode' in params: - if params['mode'] == '1': - print(generate_random_image(640, 640)) - elif params['mode'] == '2': - parameters = dict( - channel_x=params['channel x'], - channel_y=params['channel y'], - x_axis=[float(x) for x in params['x-axis']], - y_axis=[float(x) for x in params['y-axis']], - colormap=params['colormap'], - scaling=params['scaling'], - grouping=params['grouping'] - ) - if "color" in params: - parameters['color'] = params['color'] - if "print_legend" in params: - parameters['print_legend'] = params['print_legend'].upper() == "TRUE" - else: - parameters['print_legend'] = True - print(get_dat_image(**parameters)) -else: - parameters = dict( - channel_x=params['channel x'], - channel_y=params['channel y'], - x_axis=[float(x) for x in params['x-axis']], - y_axis=[float(x) for x in params['y-axis']], - colormap=params['colormap'], - scaling=params['scaling'], - grouping=params['grouping'] - ) - if "color" in params: - parameters['color'] = params['color'] - if "print_legend" in params: - parameters['print_legend'] = params['print_legend'].upper() == "TRUE" - else: - parameters['print_legend'] = True - print(get_dat_image(**parameters)) diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_sxm.py b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_sxm.py deleted file mode 100644 index 476d27f5a0a..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/nanonis_sxm.py +++ /dev/null @@ -1,100 +0,0 @@ -import numpy -from PIL import Image -import io -import base64 -import sys -import json -import os -import sys -from spmpy_terry import spm # <--- class spm defines objects of type spm with their attributes and class functions -import spmpy_terry as spmpy # <--- spmpy has other methods - -import matplotlib.pyplot as plt -# %matplotlib inline - - -class NumpyEncoder(json.JSONEncoder): - def default(self, obj): - if isinstance(obj, numpy.ndarray): - return obj.tolist() - return json.JSONEncoder.default(self, obj) - -def load_image(path): - return spm(path) - - -def get_lock_in(img): - param_name = 'lock-in>lock-in status' - param = img.get_param(param_name) - return param - - -def get_channel(img, channel_name = 'z'): - # channel_name = 'z' - channel = img.get_channel(channel_name) - return channel - -print("SYS.ARGV:" + str(sys.argv)) -file = sys.argv[1] -image_params = json.loads(sys.argv[2]) -params = json.loads(sys.argv[3]) -meta_data = json.loads(sys.argv[4]) -format = sys.argv[5] - - -folder_dir = os.path.join(file, 'original') -file_path = os.path.join(folder_dir, os.listdir(folder_dir)[0]) - - -def generate_random_image(height, width): - imarray = numpy.random.rand(height,width,3) * 255 - im = Image.fromarray(imarray.astype('uint8')).convert('RGBA') - img_byte_arr = io.BytesIO() - im.save(img_byte_arr, format='PNG') - img_byte_arr = img_byte_arr.getvalue() - encoded = base64.b64encode(img_byte_arr) - return encoded - - -def get_sxm_image(channel_name, x_axis, y_axis, scaling, color_scale, colormap, colormap_scaling): - img = load_image(file_path) - img_byte_arr = io.BytesIO() - - log = False - if scaling == 'logarithmic': - log = True - fig = img.plot(show=False, show_params=False, channel=channel_name, log=log, cmap=colormap, - color_scale=color_scale, x_axis=x_axis, y_axis=y_axis, colormap_scaling=colormap_scaling) - plt.savefig(img_byte_arr, format=format) - - img_byte_arr = img_byte_arr.getvalue() - encoded = base64.b64encode(img_byte_arr) - print_params = img.print_params(show=False).split('\n') - print_params = {x: y for x, y in (s.split(':') for s in print_params)} - print_params = json.dumps(print_params) - print(f'PARAMS={print_params}') - header = json.dumps(img.header, cls=NumpyEncoder) - print(f'HEADER={header}') - - return encoded - -def sxm_mode(parameters): - channel = parameters['channel'] - x_axis = [float(x) for x in parameters['x-axis']] - y_axis = [float(x) for x in parameters['y-axis']] - color_scale = [float(x) for x in parameters['color-scale']] - colormap = parameters['colormap'] - scaling = parameters['scaling'] - colormap_scaling = False - if "colormap_scaling" in parameters: - colormap_scaling = parameters['colormap_scaling'].upper() == "TRUE" - print(f'{get_sxm_image(channel, x_axis, y_axis, scaling, color_scale, colormap, colormap_scaling)}') - -print(params) -if 'mode' in params: - if params['mode'] == '3': - print(f'{generate_random_image(256, 256)}') - elif params['mode'] == '5': - sxm_mode(params) -else: - sxm_mode(params) \ No newline at end of file diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/plugin.properties b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/plugin.properties deleted file mode 100644 index a669c47e3ac..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/plugin.properties +++ /dev/null @@ -1,8 +0,0 @@ -label = PremiseImagingService - -class2 = ch.ethz.sis.openbis.generic.server.dss.plugins.PingPongService -class = ch.ethz.sis.openbis.generic.server.dss.plugins.imaging.ImagingService - -python3-path = /home/alaskowski/virtualenv_python/bin/python3 -nanonis-sxm = nanonis_sxm.py -nanonis-dat = nanonis_dat.py diff --git a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/spmpy_terry.py b/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/spmpy_terry.py deleted file mode 100644 index 57702f4aef4..00000000000 --- a/core-plugin-openbis/dist/core-plugins/imaging/1/dss/custom-services/imaging/spmpy_terry.py +++ /dev/null @@ -1,970 +0,0 @@ - # -*- coding: utf-8 -*- -""" -Created on Tue Jan 3 15:13:13 2017 - -@author: Bruno Schuler -""" - -############################################## -# spm_matrix class -############################################## - -# This module provides functions to load and display Nanonis files - -# requires packages: -# pip install numpy -# pip install six -# pip install nanonispy -# pip install spiepy - -import os as os -import numpy as np -import nanonispy as nap -import spiepy -import warnings -import matplotlib.pyplot as plt -import matplotlib.pylab as pl - -class spm: - - #Dictionary Channels - ChannelName = ['LI_Demod_1_X','LI_Demod_1_Y','Z','Current','Bias','Frequency_Shift','Amplitude','Excitation','Temperature_1', - 'Bias (V)','Bias calc (V)', 'Bias [bwd] (V)', 'Current (A)','Current [bwd] (A)','Amplitude (m)', - 'Amplitude [bwd] (m)', 'Excitation (V)', 'Excitation [bwd] (V)', 'Frequency Shift (Hz)', 'Frequency Shift [bwd] (Hz)', - 'LI Demod 1 X (A)','LI Demod 1 X (A) [bwd] (A)','PMT (V)','Counter 1 (Hz)','Counter_1', 'Z rel (m)', 'Z (m)','Time (s)', - 'Delay Sampling (s)','LI Demod 0 X (V)','LI Demod 0 Y (V)','LI Demod 3 X (A)','LI Demod 3 Y (A)', - 'Position Phase1 (m)','Rotation1 (deg)','Rotation2 (deg)','Rotation (deg)','Index'] - ChannelNickname = ['dIdV','dIdV_Y','z','I','V','df','A','exc','T1', - 'V', 'V', 'V_bw' ,'I','I_bw','A', - 'A_bw', 'exc','exc_bw','df','df_bw', - 'dIdV','dIdV_bw','PMT','counter','counter', 'zrel','zspec','t', - 'Delay','EOS','EOS_Y','I_THz','I_THz_Y', - 'Phase','Rot1','Rot2','Rot','Index'] - ChanneliScaling = [10**12,10**12,10**9,10**12,1,1,10**9,1,1, - 1,1,1,10**12,10**12,10**9, - 10**9,1,1,1,1,1, - 1,1,1,1,10**12,10**9,1, - 10**12,1,1,10**12,10**12, - 10**3,1,1,1,1] - ChannelUnit = ['pS','pS','nm','pA','V','Hz','nm','V','K', - 'V','V','V','pA','pA','nm', - 'nm','V','V','Hz','Hz','a.u.', - 'a.u.','V','Hz','Hz','pm','nm','s', - 'ps','V','V','pA','pA', - 'mm','deg','deg','deg','N'] - - global SignalsListReference - SignalsListReference = [] - - for (chName,chNickname,chScaling,chUnit) in zip(ChannelName,ChannelNickname,ChanneliScaling,ChannelUnit): - SignalsListReference.append({'ChannelName': chName, 'ChannelNickname': chNickname , 'ChannelScaling': chScaling, 'ChannelUnit': chUnit}) - - del ChannelName,ChanneliScaling,ChannelUnit - del chName,chNickname,chScaling,chUnit - - #Dictionary Parameters - ParamName = ['X (m)','Y (m)','Z (m)','bias','z-controller>setpoint','scan_angle','Comments','Comment01', - 'Lock-in>Amplitude','Lock-in>Reference phase D1 (deg)','Lock-in>Frequency (Hz)','Temperature 2>Temperature 2 (K)', - 'Current>Current (A)','Bias>Bias (V)','z-controller>tiplift (m)', - 'Parameter>Delay Sampling (s)','Parameter>Delay PP1 (s)','Parameter>Delay PP2 (s)','Parameter>Angle Rot1 (deg)','Parameter>Angle Rot2 (deg)','Parameter>Position Phase1 (m)','Parameter>Position_Phase1 (m)'] - ParamNickname = ['x','y','z','V','setpoint','angle','comment','comment_spec', - 'lockin_amplitude','lockin_phase','lockin_frequency','temperature', - 'setpoint_spec','V_spec','z_offset', - 'Sampling','PP1','PP2','Rot1','Rot2','Phase','Phase_depricated'] - ParamScaling = [10**9,10**9,10**9,1,10**12,1,'na','na', - 10**3,1,1,1, - 10**12,1,10**9, - 10**12,10**12,10**12,1,1,10**3,10**3] # na if not a numeric value - ParamUnit = ['nm','nm','nm','V','pA','°','','', - 'mV','°','Hz','K', - 'pA','V','nm', - 'ps','ps','ps','deg','deg','mm','mm'] - - - global ParamListReference - ParamListReference = [] - - for (paName,paNickname,paScaling,paUnit) in zip(ParamName,ParamNickname,ParamScaling,ParamUnit): - ParamListReference.append({'ParamName': paName, 'ParamNickname': paNickname, 'ParamScaling': paScaling, 'ParamUnit': paUnit}) - - del ParamName,ParamScaling,ParamUnit - del paName,paNickname,paScaling,paUnit - - # constructor - def __init__(self,path): - #import os as os - #import numpy as np - #import nanonispy as nap - - - # self.path = path.replace('//', '/') - abspath = os.path.abspath(path) - self.path = '/'.join(abspath.split('\\')[-4:]) - self.name = self.path.split('/')[-1] - file_extension = os.path.splitext(path)[1] - - if file_extension == '.sxm': - self.napImport = nap.read.Scan(path) - self.type = 'scan' - elif file_extension == '.dat': - self.napImport = nap.read.Spec(path) - self.type = 'spec' - else: - print('Datatype not supported.') - return; - - ch = [] - for key in self.napImport.signals: - try: - ch.append([d['ChannelName'] for d in SignalsListReference].index(key)) - except: - pass; - - self.SignalsList = [SignalsListReference[i] for i in ch] #List of all recorded channels - self.channels = [c['ChannelNickname'] for c in self.SignalsList] - self.header = self.napImport.header - - - def __repr__(self): - return self.path - - #get channel - def get_channel(self,channel,direction = 'forward', flatten = False, offset = False,zero = False): - - #import spiepy - #import numpy as np - - if self.type == 'scan': - chNum = [d['ChannelNickname'] for d in self.SignalsList].index(channel) - im = self.napImport.signals[self.SignalsList[chNum]['ChannelName']][direction] - im = im *self.SignalsList[chNum]['ChannelScaling'] - - if flatten: - if ~np.isnan(np.sum(im)): - im, _ = spiepy.flatten_xy(im) - else: - m,n = np.shape(im) - i = np.argwhere(np.isnan(im))[0,0] - im_cut = im[:i-1,:] - im, _ = spiepy.flatten_xy(im_cut) - empty = np.full((m-i,n),np.nan) - im = np.vstack((im,empty)) - - warnings.warn('NaN values in image') - #im-np.nanmean(im) - - if offset: - im = im-np.mean(im) - if zero: - im = im+abs(np.min(im)) - - unit = self.SignalsList[chNum]['ChannelUnit'] - - return (im,unit) - - elif self.type == 'spec': - - if direction == 'backward': - channel = channel + '_bw'; - #print(channel) - - chNum = [d['ChannelNickname'] for d in self.SignalsList].index(channel) - data = self.napImport.signals[self.SignalsList[chNum]['ChannelName']] - data = data*self.SignalsList[chNum]['ChannelScaling'] - unit = self.SignalsList[chNum]['ChannelUnit'] - - return (data,unit) - - return - - #get parameter - def get_param(self,param): - - if any(d['ParamNickname'] == param for d in ParamListReference): - paNum = [d['ParamNickname'] for d in ParamListReference].index(param) - - if ParamListReference[paNum]['ParamScaling'] == 'na': - return self.napImport.header[ParamListReference[paNum]['ParamName']] - else: - return (float(self.napImport.header[ParamListReference[paNum]['ParamName']])*ParamListReference[paNum]['ParamScaling'],ParamListReference[paNum]['ParamUnit']) - - - elif param == 'width' or param == 'height': - # height, width = self.get_param('scan_range') - # height, width = [height*10**9, width*10**9] - scanfield = self.get_param('scan>scanfield') - width, height = float(scanfield.split(';')[2])*10**9, float(scanfield.split(';')[3])*10**9 - - return (eval(param),'nm') - - - else: - if param in self.napImport.header.keys(): - return self.napImport.header[param] - else: - return - - - - # print essential parameters for plotting - def print_params(self, show = True): - - # import numpy as np - - label = [] - - if self.type == 'scan': - fb_enable = self.get_param('z-controller>controller status') - fb_ctrl = self.get_param('z-controller>controller name') - bias = self.get_param('V') - set_point = self.get_param('setpoint') - height = self.get_param('height') - width = self.get_param('width') - angle = self.get_param('angle') - z_offset = self.get_param('z_offset') - comment = self.get_param('comments') - - - - if fb_enable == 'OFF': - label.append('constant height') - label.append('z-offset: %.3f%s' % z_offset) - - if np.abs(bias[0])<0.1: - bias = list(bias) - bias[0] = bias[0]*1000 - bias[1] = 'mV' - bias = tuple(bias) - - label.append('I: %.0f%s' % set_point) - label.append('bias: %.2f%s' % bias) - label.append('size: %.1f%s x %.1f%s (%.0f%s)' % (width+height+angle)) - label.append('comment: %s' % comment) - - - elif self.type == 'spec': - - fb_enable = self.get_param('Z-Ctrl hold') - set_point = self.get_param('setpoint_spec') - bias = self.get_param('V_spec') - #lockin_status = self.get_param('Lock-in>Lock-in status') - lockin_amplitude = self.get_param('lockin_amplitude') - lockin_phase= self.get_param('lockin_phase') - lockin_frequency= self.get_param('lockin_frequency') - comment = self.get_param('comment_spec') - - - #if lockin_status == 'ON': - label.append('lockin: A = %.0f%s (θ = %.0f%s, f = %.0f%s)' % (lockin_amplitude+lockin_phase+lockin_frequency)) - - - if fb_enable == 'FALSE': - label.append('feedback: on') - - elif fb_enable == 'TRUE': - label.append('feedback: off') - - - label.append('setpoint: I = %.0f%s, V = %.1f%s' % (set_point+bias)) - - label.append('comment: %s' % comment) - - label.append('path: %s' % self.path) - label = '\n'.join(label) - - if show: - print(label) - - return label - - - - # plot - def plot(self, **params): - import numpy as np - #import matplotlib as ml - import matplotlib.pyplot as plt - from matplotlib.colors import LogNorm - - #cmaps = sorted(m for m in plt.cm.datad) - # ['Accent', 'Accent_r', 'Blues', 'Blues_r', 'BrBG', 'BrBG_r', 'BuGn', 'BuGn_r', 'BuPu', 'BuPu_r', 'CMRmap', 'CMRmap_r', 'Dark2', 'Dark2_r', 'GnBu', 'GnBu_r', 'Greens', 'Greens_r', 'Greys', 'Greys_r', 'OrRd', 'OrRd_r', 'Oranges', 'Oranges_r', 'PRGn', 'PRGn_r', 'Paired', 'Paired_r', 'Pastel1', 'Pastel1_r', 'Pastel2', 'Pastel2_r', 'PiYG', 'PiYG_r', 'PuBu', 'PuBuGn', 'PuBuGn_r', 'PuBu_r', 'PuOr', 'PuOr_r', 'PuRd', 'PuRd_r', 'Purples', 'Purples_r', 'RdBu', 'RdBu_r', 'RdGy', 'RdGy_r', 'RdPu', 'RdPu_r', 'RdYlBu', 'RdYlBu_r', 'RdYlGn', 'RdYlGn_r', 'Reds', 'Reds_r', 'Set1', 'Set1_r', 'Set2', 'Set2_r', 'Set3', 'Set3_r', 'Spectral', 'Spectral_r', 'Wistia', 'Wistia_r', 'YlGn', 'YlGnBu', 'YlGnBu_r', 'YlGn_r', 'YlOrBr', 'YlOrBr_r', 'YlOrRd', 'YlOrRd_r', 'afmhot', 'afmhot_r', 'autumn', 'autumn_r', 'binary', 'binary_r', 'bone', 'bone_r', 'brg', 'brg_r', 'bwr', 'bwr_r', 'cool', 'cool_r', 'coolwarm', 'coolwarm_r', 'copper', 'copper_r', 'cubehelix', 'cubehelix_r', 'flag', 'flag_r', 'gist_earth', 'gist_earth_r', 'gist_gray', 'gist_gray_r', 'gist_heat', 'gist_heat_r', 'gist_ncar', 'gist_ncar_r', 'gist_rainbow', 'gist_rainbow_r', 'gist_stern', 'gist_stern_r', 'gist_yarg', 'gist_yarg_r', 'gnuplot', 'gnuplot2', 'gnuplot2_r', 'gnuplot_r', 'gray', 'gray_r', 'hot', 'hot_r', 'hsv', 'hsv_r', 'jet', 'jet_r', 'nipy_spectral', 'nipy_spectral_r', 'ocean', 'ocean_r', 'pink', 'pink_r', 'prism', 'prism_r', 'rainbow', 'rainbow_r', 'seismic', 'seismic_r', 'spectral', 'spectral_r', 'spring', 'spring_r', 'summer', 'summer_r', 'terrain', 'terrain_r', 'winter', 'winter_r'] - - #ml.interactive(0) - - if self.type == 'scan': - - if 'channel' in params: - channel = params['channel'] - else: - channel = self.channels[0] - - if 'direction' in params: - direction = params['direction'] - else: - direction = 'forward' - - if 'flatten' in params: - flatten = params['flatten'] - else: - flatten = False - - if 'offset' in params: - offset = params['offset'] - else: - offset = False - - if 'cmap' in params: - cmap = params['cmap'] - else: - cmap = 'gray' - - if 'clim' in params: - clim = params['clim'] - else: - clim = False - - if 'log' in params: - log = params['log'] - else: - log = False - - if 'show_params' in params: - show_params = params['show_params'] - else: - show_params = False - - if 'show' in params: - show = params['show'] - else: - show = True - - # PREMISE - specific params - - if 'hide' in params: - hide = params['hide'] - else: - hide = False - - if 'color_scale' in params: - color_scale = params['color_scale'] - else: - color_scale = False - - if 'x_axis' in params: - x_axis = params['x_axis'] - else: - x_axis = False - - if 'y_axis' in params: - y_axis = params['y_axis'] - else: - y_axis = False - - if 'colormap_scaling' in params: - colormap_scaling = params['colormap_scaling'] - else: - colormap_scaling = False - - - - (chData,chUnit) = self.get_channel(channel, direction = direction, flatten=flatten, offset=offset); - - if direction == 'backward': - chData = np.fliplr(chData) - - width = self.get_param('width') - height = self.get_param('height') - pix_y,pix_x = np.shape(chData) - - # fig = plt.figure(figsize=(6, 4)) - fig = plt.figure()#figsize=(6,4)) - - - ImgOrigin = 'lower' - if self.get_param('scan_dir') == 'down': - ImgOrigin = 'upper' - - if color_scale: - chData = np.clip(chData, color_scale[0], color_scale[1]) - - if x_axis and y_axis: - plt.ylim(y_axis[0], y_axis[1]) - plt.xlim(x_axis[0], x_axis[1]) - # plt.axis([x_axis[0], x_axis[1], y_axis[0], y_axis[1]]) - - plot_params = dict( - X = np.abs(chData) if log else chData, - aspect = 'equal', - extent = [0,width[0],0,height[0]], - cmap = cmap, - origin = ImgOrigin, - interpolation = 'none' - ) - if log: - plot_params['norm'] = LogNorm() - - if colormap_scaling: - min_x = x_axis[0] - max_x = x_axis[1] - min_y = y_axis[0] - max_y = y_axis[1] - - shape = chData.shape - minx = int(np.floor(shape[0] * min_x / width[0])) - maxx = int(np.ceil(shape[0] * max_x / width[0])) - miny = int(np.floor(shape[1] * min_y / height[0])) - maxy = int(np.ceil(shape[1] * max_y / height[0])) - - mini = np.min(chData[minx:maxx, miny:maxy]) - maxi = np.max(chData[minx:maxx, miny:maxy]) - - mini = int(mini*100)/100 - maxi = int(maxi*100)/100 - plot_params['vmin'] = mini - plot_params['vmax'] = maxi - - im = plt.imshow(**plot_params) - - # if log: - # im = plt.imshow(np.abs(chData), aspect = 'equal', extent = [0,width[0],0,height[0]], cmap = cmap, norm=LogNorm(), origin = ImgOrigin) - # else: - # im = plt.imshow(chData, aspect = 'equal',extent = [0,width[0],0,height[0]], cmap = cmap, origin = ImgOrigin) - - - if clim: - plt.clim(clim) - - - # im.axes.set_xticks([0,width[0]]) - # im.axes.set_xticklabels([0,np.round(width[0],2)]) - # im.axes.set_yticks([0,height[0]]) - # im.axes.set_yticklabels([0,np.round(height[0],2)]) - - if show_params: - title = self.print_params(show = False); - else: - title = self.path - - if not hide: - # plt.title(title + '\n', loc='left') - plt.xlabel('x (%s)' % width[1]) - plt.ylabel('y (%s)' % height[1]) - print(f'AXES={im.axes}') - cbar = plt.colorbar(im)#,fraction=0.046, pad=0.02, format='%.2g',shrink = 0.5,aspect=10) - cbar.set_label('channel:%s (%s)' % (channel,chUnit)) - - if show: - plt.show() - # else: - # plt.close(fig) - - return fig - - - - elif self.type == 'spec': - - - if 'channelx' in params: - channelx = params['channelx'] - else: - channelx = self.channels[0] - - if 'channely' in params: - channely = params['channely'] - else: - channely = self.channels[1] - - if 'direction' in params: - direction = params['direction'] - else: - direction = direction = 'forward' - - if 'log' in params: - log = params['log'] - else: - log = False - - if 'loglog' in params: - loglog = params['loglog'] - else: - loglog = False - - - if 'show_params' in params: - show_params = params['show_params'] - else: - show_params = False - - if 'show' in params: - show = params['show'] - else: - show = True - - - (x_data,x_unit) = self.get_channel(channelx,direction=direction) - (y_data,y_unit) = self.get_channel(channely,direction=direction) - - - fig = plt.figure(figsize=(6,4)) - - if log: - plt.semilogy(x_data,np.abs(y_data)) - - elif loglog: - plt.loglog(np.abs(x_data),np.abs(y_data)) - - else: - plt.plot(x_data,y_data) - - - if show_params: - title = self.print_params(show = False); - else: - title = self.path - - plt.title(title + '\n', loc='left') - - plt.xlabel('%s (%s)' % (channelx,x_unit)) - plt.ylabel('%s (%s)' % (channely,y_unit)) - - if show: - plt.show() - else: - plt.close(fig) - - return fig - - - - - -############################################## -# functions for spm class -############################################## - - -# import all files in folder as list of spm objects -def importall(FilePath,FilePrefix = '',ImportOnly = '' ): - - from os import walk - - files = [] - NumSpec = 0 - NumScan = 0 - - - for root, dirs, filenames in walk(FilePath): - for file in filenames: - if file.endswith(".sxm") and file.startswith(FilePrefix): - if not(ImportOnly == 'spec'): - files.append(spm(root + '/' + file)) - NumScan = NumScan + 1 - elif file.endswith(".dat") and file.startswith(FilePrefix): - if not(ImportOnly == 'scan'): - files.append(spm(root + '/' + file)) - NumSpec = NumSpec + 1 - - print(str(len(files)) + ' files imported; ' + str(NumScan) + ' scan(s) and ' + str(NumSpec) + ' spectra') - - return files - -# def importspecific(FilePath,FileList,FilePrefix = '',ImportOnly = '' ): - -# from os import walk - -# files = [] -# NumSpec = 0 -# NumScan = 0 - - -# for root, dirs, filenames in walk(FilePath): -# for file in filenames: -# if (file in FileList): -# if file.endswith(".sxm") and file.startswith(FilePrefix): -# if not(ImportOnly == 'spec'): -# files.append(spm(root + '/' + file)) -# NumScan = NumScan + 1 -# elif file.endswith(".dat") and file.startswith(FilePrefix): -# if not(ImportOnly == 'scan'): -# files.append(spm(root + '/' + file)) -# NumSpec = NumSpec + 1 - -# print(str(len(files)) + ' files imported; ' + str(NumScan) + ' scan(s) and ' + str(NumSpec) + ' spectra') - -# return files - - - - -def specs_plot(specs,**params): -# plot spectra in list - - #import matplotlib.pyplot as plt - - if 'channelx' in params: - channelx = params['channelx'] - else: - channelx = specs[0].channels[0] - - if 'channely' in params: - channely = params['channely'] - else: - channely = specs[0].channels[1] - - if 'direction' in params: - direction = params['direction'] - else: - direction = list(specs[0].data.keys())[0] - - if 'color' in params: - color = params['color'] - else: - color = pl.cm.rainbow(np.linspace(0,1,len(specs))) - if 'print_legend' in params: - print_legend = params['print_legend'] - else: - print_legend = False - if 'offset' in params: - offset = params['offset'] - else: - offset = 0 - - # PREMISE specific - if 'show' in params: - show = params['show'] - else: - show = True - - if 'colormap' in params: - colormap = params['colormap'] - cmap = plt.get_cmap(colormap) - color = cmap(np.linspace(0,1,len(specs))) - else: - colormap = False - - if 'scaling' in params: - scaling = params['scaling'] - else: - scaling = False - - if 'x_axis' in params: - x_axis = params['x_axis'] - else: - x_axis = False - - if 'y_axis' in params: - y_axis = params['y_axis'] - else: - y_axis = False - ####### - - fig = plt.figure(figsize=(6,4)) - - counter = 0 - for (s, c) in zip(specs, color): - - (x_data, x_unit) = s.get_channel(channelx, direction=direction) - if x_axis: - x_data = np.clip(x_data, x_axis[0], x_axis[1]) - - (y_data, y_unit) = s.get_channel(channely, direction=direction) - if y_axis: - y_data = np.clip(y_data, y_axis[0], y_axis[1]) - - if scaling: - if scaling == 'lin-lin': - plt.plot(x_data, y_data, color=c, label=s.name) - elif scaling == "lin-log": - plt.semilogy(x_data, np.abs(y_data), color=c, label=s.name) - elif scaling == 'log-lin': - plt.semilogx(np.abs(x_data), y_data, color=c, label=s.name) - elif scaling == 'log-log': - plt.loglog(np.abs(x_data), np.abs(y_data), color=c, label=s.name) - else: - plt.plot(x_data, y_data, color=c, label=s.name) - else: - plt.plot(x_data,y_data+counter*offset,color = c,label = s.name) - counter = counter + 1 - - plt.xlabel('%s (%s)' % (channelx,x_unit)) - plt.ylabel('%s (%s)' % (channely,y_unit)) - - if print_legend: - plt.legend() - - if show: - plt.show() - - return fig - - -def relative_position(img,spec,**params): - - #width = ref.get_param('width') - #height = ref.get_param('height') - #[px_x,px_y] = ref.get_param('scan_pixels') - - [o_x,o_y] = img.get_param('scan_offset') - width = img.get_param('width')[0] - height = img.get_param('height')[0] - [o_x,o_y] = [o_x*10**9,o_y*10**9] - - angle = float(img.get_param('scan_angle'))*-1* np.pi/180 - - - x_spec = spec.get_param('x')[0] - y_spec = spec.get_param('y')[0] - - if angle != 0: - #Transforming to relative coordinates with angle - x_rel = (x_spec-o_x)*np.cos(angle) + (y_spec-o_y)*np.sin(angle)+width/2 - y_rel = -(x_spec-o_x)*np.sin(angle) + (y_spec-o_y)*np.cos(angle)+height/2 - else: - x_rel = x_spec-o_x+width/2 - y_rel = y_spec-o_y+height/2 - return [x_rel,y_rel] - - - -def ref_spec_plotting(ref_file,spec_files,fname_ref,fname_specs,**params): - """ - Plots sxm reference image with spectra locations and multiple dat spectra - - Input: - ref_file: filename of reference sxm image - spec_files: list of filenames of dat spectra - fname_ref: filename of saved reference image - fname_specs: filename of saved spectra image - - Optional input: - channelx_plot: channel to plot on x-axis of dat spectra (default: V) - channely_plot: channel to plot on y-axis of dat spectra (default: dIdV) - offset: offset between spectra (default: 0) - annotate_spec: annotate spectra with numbers - - Output: - specs_fig: figure of spectra - """ - - - # Load modules - import os - - # Optional input - if 'channelx_plot' in params: - channelx_plot = params['channelx_plot'] - else: - channelx_plot = 'V' - - if 'channely_plot' in params: - channely_plot = params['channely_plot'] - else: - channely_plot = 'dIdV' - - if 'print_legend' not in params: - params['print_legend'] = True - - if 'annotate_spec' in params: - annotate_spec = params['annotate_spec'] - else: - annotate_spec = False - - - ## Import - # Importing reference image - ref = spm(ref_file) - - # Importing spec - sp = [] - for s in spec_files: - sp.append(spm(s)) - - # Defining color scale - col = pl.cm.rainbow(np.linspace(0,1,len(sp))) - - ## Plotting reference image with spec locations - ref.plot(show_params = True, offset = False, show = False,channel = 'z',close_fig = False); - - # plot circle for each location - for (s,c) in zip(sp,col): - (x,y) = relative_position(ref,s) - plt.plot(x,y,'o',color = c) - if annotate_spec: - plt.annotate(s.name, (x,y)) - - plt.xlabel('x (nm)') - plt.ylabel('y (nm)') - - figDir = os.path.abspath(os.path.join(fname_ref, os.pardir)) - if not os.path.exists(figDir): - os.makedirs(figDir) - - - plt.savefig(fname_ref+'.png', dpi=500) - plt.savefig(fname_ref+'.svg', dpi=500) - - # Plotting specs - specs_fig = specs_plot(sp,channelx=channelx_plot,channely=channely_plot, direction = 'forward', color = col,**params); - - figDir = os.path.abspath(os.path.join(fname_specs, os.pardir)) - if not os.path.exists(figDir): - os.makedirs(figDir) - - specs_fig.savefig(fname_specs+'.png', dpi=500) - specs_fig.savefig(fname_specs+'.svg', dpi=500) - - plt.show() - - return specs_fig - - - -# returns dict list of fitted kpfm parabolas for list of spm objects -def kpfm(files,**params): - - if 'range' in params: - range = params['range']; - else: - range = [0,len(files[0].get_channel('V')[0])-1] - - import numpy as np - #sys.path.append('../') - #import analyze as an - - data = {'V': [], 'df': [], 'V_max': [], 'df_max': [], 'p_fit': [], 'err_p': [], 'V_fit': [], 'df_fit': [], 'err_V_max': [], 'err_df_max': [], 'position': []} - - for f in files: - if f.type == 'spec': - if any(d['ChannelNickname'] == 'df' for d in f.SignalsList): - - data['V'].append(f.get_channel('V')[0]) - data['df'].append(f.get_channel('df')[0]) - - if any(d['ChannelNickname'] == 'df_bw' for d in f.SignalsList): - - if not('df_bw' in data.keys()): - data['V_bw'] = []; - data['df_bw'] = []; - - else: - data['V_bw'].append(f.get_channel('V_bw')[0]) - data['df_bw'].append(f.get_channel('df_bw')[0]) - - x = f.get_param('x')[0] - y = f.get_param('y')[0] - - data['position'].append([x,y]) - - - (p_fit,err_p,df_fit,V_max,err_V_max,df_max,err_df_max) = fit_parabola(np.array(data['V'])[:,range[0]:range[1]].tolist(),np.array(data['df'])[:,range[0]:range[1]].tolist(),single_spectrum=False,fitMin=False,fitMax=False) - - data['p_fit'] = p_fit; - data['err_p'] = err_p; - data['V_fit'] = np.array(data['V'])[:,range[0]:range[1]].tolist(); - data['df_fit'] = df_fit; - data['V_max'] = V_max; - data['err_V_max'] = err_V_max; - data['df_max'] = df_max; - data['err_df_max'] = err_df_max; - - if 'df_bw' in data.keys(): - - (p_fit_bw,err_p_bw,df_fit_bw,V_max_bw,err_V_max_bw,df_max_bw,err_df_max_bw) = fit_parabola(np.array(data['V_bw'])[:,range[0]:range[1]].tolist(),np.array(data['df_bw'])[:,range[0]:range[1]].tolist(),single_spectrum=False,fitMin=False,fitMax=False) - - data['p_fit_bw'] = p_fit_bw; - data['err_p_bw'] = err_p_bw; - data['V_fit_bw'] = np.array(data['V_bw'])[:,range[0]:range[1]].tolist() - data['df_fit_bw'] = df_fit_bw; - data['V_max_bw'] = V_max_bw; - data['err_V_max_bw'] = err_V_max_bw; - data['df_max_bw'] = df_max_bw; - data['err_df_max_bw'] = err_df_max_bw; - - return data - - - - - -############################################## -# help functions -############################################## - -def fit_parabola( - bias, - df, - single_spectrum=False, - fitMin=False, - fitMax=False, - ): - - #import numpy as np - - if single_spectrum: - bias = np.array([bias]) - df = np.array([df]) - p_fit = np.zeros((len(bias), 3)) - df_fit = np.zeros((len(bias), len(bias[0]))) - err_p = np.zeros((len(bias), 3)) - bias_max = np.zeros(len(bias)) - err_bias_max = np.zeros(len(bias)) - df_max = np.zeros(len(bias)) - err_df_max = np.zeros(len(bias)) - - for i in range(len(bias)): - if not fitMin and not fitMax: - (p, cov) = np.polyfit(bias[i], df[i], 2, cov=True) - elif fitMin and not fitMax: - - fit_i = np.where(bias[i] > fitMin[i])[0] - (p, cov) = np.polyfit(bias[i, fit_i], df[i, fit_i], 2, - cov=True) - p_fit[i] = p - err1 = np.sqrt(abs(cov)) - err_p[i] = np.array([err1[0, 0], err1[1, 1], err1[2, 2]]) - - df_fit[i] = np.polyval(p, bias[i]) - - bias_max[i] = -p[1] / (2 * p[0]) - - # if errors independent - - #err_bias_max[i] = abs(bias_max[i]) * np.sqrt((err1[1, 1] - # / p[1]) ** 2 + (err1[0, 0] / p[0]) ** 2) - err_bias_max[i] = np.sqrt((err1[1, 1]/ (2*p[0]))** 2 + (err1[0, 0]*p[1] /(2*p[0]**2)) ** 2) - - # maximum error in any case (John Tayler Error analysis book) - - #err_bias_max[i] = abs(bias_max[i]) * (err1[1, 1] + err1[0, 0]) - - df_max[i] = np.polyval(p, bias_max[i]) - err_df_max[i] = p[0] * bias_max[i] ** 2 * (err1[0, 0] + 2 - * err_bias_max[i] / abs(bias_max[i])) + p[1] \ - * bias_max[i] * (err1[1, 1] + err_bias_max[i] - / abs(bias_max[i])) + p[2] * err1[2, 2] - return ( - p_fit, - err_p, - df_fit, - bias_max, - err_bias_max, - df_max, - err_df_max, - ) - -# this function returns a rgb color code according to standard matlab colors -def matlab_color(num): - if num > 6: - num = np.mod(num,7) - - colors = [[0,0.4470,0.7410], - [0.8500,0.3250,0.0980], - [0.9290,0.6940,0.1250], - [0.4940,0.1840,0.5560], - [0.4660,0.6740,0.1880], - [0.3010,0.7450,0.9330], - [0.6350,0.0780,0.1840]] - - return colors[np.round(num)] - -- GitLab