From 0eed46b03020bf90a71bd1421bcb78f175c3d3ab Mon Sep 17 00:00:00 2001
From: pkupczyk <piotr.kupczyk@id.ethz.ch>
Date: Wed, 27 Mar 2024 12:44:22 +0100
Subject: [PATCH] SSDM-13578 : 2PT : Database and V3 Implementation - js facade

---
 api-openbis-javascript/src/v3/config.js       | 11 ++-
 api-openbis-javascript/src/v3/openbis.js      | 84 +++++++++++++++++--
 .../dto/OpenBISJavaScriptAFSFacade.java       | 71 ++++++++++++++--
 lib-transactional-file-system/build.gradle    |  3 +
 server-data-store/build.gradle                |  3 +
 test-api-openbis-javascript/build.gradle      |  2 +
 .../servers/common/afs-server/etc/log4j2.xml  | 13 +++
 .../etc/server-data-store-config.properties   | 26 ++++++
 .../openbis-v3-api-test/html/test/main.js     |  1 +
 .../openbis-v3-api-test/html/test/test-afs.ts | 63 ++++++++++++++
 .../html/test/types/openbis.esm.d.ts          | 76 ++++++++++++++++-
 .../servers/common/openBIS-server/etc/log.xml | 62 --------------
 .../common/openBIS-server/etc/log4j1.xml      | 19 +++++
 test-api-openbis-javascript/settings.gradle   |  2 +-
 .../suite/common/JsTestCommonSelenium.java    | 34 +++++++-
 15 files changed, 383 insertions(+), 87 deletions(-)
 create mode 100644 test-api-openbis-javascript/servers/common/afs-server/etc/log4j2.xml
 create mode 100755 test-api-openbis-javascript/servers/common/afs-server/etc/server-data-store-config.properties
 create mode 100644 test-api-openbis-javascript/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/test-afs.ts
 delete mode 100644 test-api-openbis-javascript/servers/common/openBIS-server/etc/log.xml
 create mode 100644 test-api-openbis-javascript/servers/common/openBIS-server/etc/log4j1.xml

diff --git a/api-openbis-javascript/src/v3/config.js b/api-openbis-javascript/src/v3/config.js
index 0453c2d6d4c..2ed17fde603 100644
--- a/api-openbis-javascript/src/v3/config.js
+++ b/api-openbis-javascript/src/v3/config.js
@@ -29,7 +29,7 @@ var require = (function() {
 			"bootstrap" : "../../lib/bootstrap/js/bootstrap.min",
 			"bootstrap-slider" : "../../lib/bootstrap-slider/js/bootstrap-slider.min",
 			"afs" : "afs/server-data-store-facade",
-			"afs-md5" : "afs/md5"
+			"afsMd5" : "afs/md5"
 		},
 		shim : {
 			"stjs" : {
@@ -49,9 +49,12 @@ var require = (function() {
 				exports : "openbis"
 			},
 			"afs" : {
-				deps : [ "afs-md5" ],
-				exports : "DataStoreServer"
-			}
+				deps : [ "afsMd5" ],
+				exports : "DataStoreServer",
+				init : function(afsMd5){
+				    this.md5 = afsMd5
+				}
+			},
 		}
 	}
 
diff --git a/api-openbis-javascript/src/v3/openbis.js b/api-openbis-javascript/src/v3/openbis.js
index f9c7525030f..589df6c5a33 100644
--- a/api-openbis-javascript/src/v3/openbis.js
+++ b/api-openbis-javascript/src/v3/openbis.js
@@ -441,32 +441,100 @@ define([ 'jquery', 'util/Json', 'as/dto/datastore/search/DataStoreSearchCriteria
         this.afsServer.useSession(asFacade._private.sessionToken)
 
 		this.list = function(owner, source, recursively) {
-		    return this.afsServer.list(owner, source, recursively);
+            return handleAfsResponse(this.afsServer.list(owner, source, recursively)).then(function(result){
+                var files = []
+                if(Array.isArray(result)){
+                    result.forEach(function(item){
+                        if(Array.isArray(item) && item.length === 2){
+                            files.push(new File(item[1]));
+                        }
+                    });
+                }
+                return files;
+            });
 		}
 
 		this.read = function(owner, source, offset, limit){
-		    return this.afsServer.read(owner, source, offset, limit);
+		    return handleAfsResponse(this.afsServer.read(owner, source, offset, limit));
 		}
 
 		this.write = function(owner, source, offset, data){
-		    return this.afsServer.write(owner, source, offset, data);
+		    return handleAfsResponse(this.afsServer.write(owner, source, offset, data));
 		}
 
 		this.delete = function(owner, source){
-		    return this.afsServer.delete(owner, source)
+		    return handleAfsResponse(this.afsServer.delete(owner, source));
 		}
 
 		this.copy = function(sourceOwner, source, targetOwner, target){
-		    return this.afsServer.copy(sourceOwner, source, targetOwner, target);
+		    return handleAfsResponse(this.afsServer.copy(sourceOwner, source, targetOwner, target));
 		}
 
 		this.move = function(sourceOwner, source, targetOwner, target){
-		    return this.afsServer.move(sourceOwner, source, targetOwner, target);
+		    return handleAfsResponse(this.afsServer.move(sourceOwner, source, targetOwner, target));
 		}
 
 		this.create = function(owner, source, directory){
-		    return this.afsServer.create(owner, source, directory);
-		}
+		    return handleAfsResponse(this.afsServer.create(owner, source, directory));
+		}
+
+        var File = function(fileObject){
+            this.owner = fileObject.owner;
+            this.path = fileObject.path;
+            this.name = fileObject.name;
+            this.directory = fileObject.directory;
+            this.size = fileObject.size;
+            this.lastModifiedTime = fileObject.lastModifiedTime;
+            this.creationTime = fileObject.creationTime;
+            this.lastAccessTime = fileObject.lastAccessTime;
+
+            this.getOwner = function(){
+                return this.owner;
+            }
+            this.getPath = function(){
+                return this.path;
+            }
+            this.getName = function(){
+                return this.name;
+            }
+            this.getDirectory = function(){
+                return this.directory;
+            }
+            this.getSize = function(){
+                return this.size;
+            }
+            this.getLastModifiedTime = function(){
+                return this.lastModifiedTime;
+            }
+            this.getCreationTime = function(){
+                return this.creationTime;
+            }
+            this.getLastAccessTime = function(){
+                return this.lastAccessTime;
+            }
+        }
+
+        var handleAfsResponse = function(responsePromise){
+            return new Promise(function(resolve, reject){
+                return responsePromise.then(function(response){
+                    if(response.error){
+                        if(Array.isArray(response.error) && response.error.length === 2){
+                            reject(response.error[1])
+                        }else{
+                            reject(response.error)
+                        }
+                    }else{
+                        if(Array.isArray(response.result) && response.result.length === 2){
+                            resolve(response.result[1])
+                        }else{
+                            resolve(response.result)
+                        }
+                    }
+                }, function(error){
+                    reject(error)
+                })
+            });
+        }
 
 	}
 
diff --git a/api-openbis-typescript/source/java/ch/ethz/sis/openbis/generic/typescript/dto/OpenBISJavaScriptAFSFacade.java b/api-openbis-typescript/source/java/ch/ethz/sis/openbis/generic/typescript/dto/OpenBISJavaScriptAFSFacade.java
index 94f4d92b57d..4cde6e8b222 100644
--- a/api-openbis-typescript/source/java/ch/ethz/sis/openbis/generic/typescript/dto/OpenBISJavaScriptAFSFacade.java
+++ b/api-openbis-typescript/source/java/ch/ethz/sis/openbis/generic/typescript/dto/OpenBISJavaScriptAFSFacade.java
@@ -1,8 +1,8 @@
 package ch.ethz.sis.openbis.generic.typescript.dto;
 
+import java.time.OffsetDateTime;
 import java.util.List;
 
-import ch.ethz.sis.afsapi.dto.File;
 import ch.ethz.sis.openbis.generic.typescript.TypeScriptMethod;
 import ch.ethz.sis.openbis.generic.typescript.TypeScriptObject;
 
@@ -15,45 +15,100 @@ public class OpenBISJavaScriptAFSFacade
     }
 
     @TypeScriptMethod(sessionToken = false)
-    public List<File> list(final String owner, final String source, final Boolean recursively)
+    public List<File> list(final String owner, final String source, final boolean recursively)
     {
         return null;
     }
 
     @TypeScriptMethod(sessionToken = false)
-    public byte[] read(final String source, final long offset, final int limit)
+    public byte[] read(final String owner, final String source, final long offset, final int limit)
     {
         return null;
     }
 
     @TypeScriptMethod(sessionToken = false)
-    public boolean write(final String source, final long offset, final byte[] data)
+    public boolean write(final String owner, final String source, final long offset, final byte[] data)
     {
         return false;
     }
 
     @TypeScriptMethod(sessionToken = false)
-    public boolean delete(final String source)
+    public boolean delete(final String owner, final String source)
     {
         return false;
     }
 
     @TypeScriptMethod(sessionToken = false)
-    public boolean copy(final String source, final String target)
+    public boolean copy(final String sourceOwner, final String source, final String targetOwner, final String target)
     {
         return false;
     }
 
     @TypeScriptMethod(sessionToken = false)
-    public boolean move(final String source, final String target)
+    public boolean move(final String sourceOwner, final String source, final String targetOwner, final String target)
     {
         return false;
     }
 
     @TypeScriptMethod(sessionToken = false)
-    public boolean create(final String source, final boolean directory)
+    public boolean create(final String owner, final String source, final boolean directory)
     {
         return false;
     }
 
+    @TypeScriptObject
+    public static class File
+    {
+        private String owner;
+
+        private String path;
+
+        private String name;
+
+        private Boolean directory;
+
+        private Long size;
+
+        private OffsetDateTime lastModifiedTime;
+
+        private OffsetDateTime creationTime;
+
+        private OffsetDateTime lastAccessTime;
+
+        public String getOwner()
+        {
+            return owner;
+        }
+
+        public String getPath()
+        {
+            return path;
+        }
+
+        public String getName()
+        {
+            return name;
+        }
+
+        public Boolean getDirectory()
+        {
+            return directory;
+        }
+
+        public OffsetDateTime getLastModifiedTime()
+        {
+            return lastModifiedTime;
+        }
+
+        public OffsetDateTime getCreationTime()
+        {
+            return creationTime;
+        }
+
+        public OffsetDateTime getLastAccessTime()
+        {
+            return lastAccessTime;
+        }
+    }
+
 }
diff --git a/lib-transactional-file-system/build.gradle b/lib-transactional-file-system/build.gradle
index d64c65cbecf..e9ac75f7fd3 100644
--- a/lib-transactional-file-system/build.gradle
+++ b/lib-transactional-file-system/build.gradle
@@ -5,6 +5,9 @@ compileJava {
     options.compilerArgs << '-parameters'
 }
 
+sourceCompatibility='11'
+targetCompatibility='11'
+
 repositories {
     ivy {
         ivyPattern "https://sissource.ethz.ch/openbis/openbis-public/openbis-ivy/-/raw/main/[organisation]/[module]/[revision]/ivy.xml"
diff --git a/server-data-store/build.gradle b/server-data-store/build.gradle
index b468482a876..45908299720 100644
--- a/server-data-store/build.gradle
+++ b/server-data-store/build.gradle
@@ -9,6 +9,9 @@ compileJava {
     options.compilerArgs << '-parameters'
 }
 
+sourceCompatibility='11'
+targetCompatibility='11'
+
 repositories {
     ivy {
         ivyPattern "https://sissource.ethz.ch/openbis/openbis-public/openbis-ivy/-/raw/main/[organisation]/[module]/[revision]/ivy.xml"
diff --git a/test-api-openbis-javascript/build.gradle b/test-api-openbis-javascript/build.gradle
index 518c7da5577..a36f70e7940 100644
--- a/test-api-openbis-javascript/build.gradle
+++ b/test-api-openbis-javascript/build.gradle
@@ -40,6 +40,8 @@ configurations.create('blast_tar')
 dependencies {
     api project(path: ':server-screening'),
             project(path: ':core-plugin-openbis'),
+            project(path: ':server-data-store'),
+            project(path: ':lib-transactional-file-system'),
             project(path: ':test-ui-core', configuration: 'tests'),
             'reflections:reflections:0.9.10',
             'fasterxml:jackson-core:2.9.10',
diff --git a/test-api-openbis-javascript/servers/common/afs-server/etc/log4j2.xml b/test-api-openbis-javascript/servers/common/afs-server/etc/log4j2.xml
new file mode 100644
index 00000000000..56e2b115e0c
--- /dev/null
+++ b/test-api-openbis-javascript/servers/common/afs-server/etc/log4j2.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="INFO">
+    <Appenders>
+        <Console name="Console" target="SYSTEM_OUT">
+            <PatternLayout pattern="[AFS] %d{yyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
+        </Console>
+    </Appenders>
+    <Loggers>
+        <Root>
+            <AppenderRef ref="Console" />
+        </Root>
+    </Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/test-api-openbis-javascript/servers/common/afs-server/etc/server-data-store-config.properties b/test-api-openbis-javascript/servers/common/afs-server/etc/server-data-store-config.properties
new file mode 100755
index 00000000000..683ef5b7972
--- /dev/null
+++ b/test-api-openbis-javascript/servers/common/afs-server/etc/server-data-store-config.properties
@@ -0,0 +1,26 @@
+logFactoryClass=ch.ethz.sis.shared.log.log4j2.Log4J2LogFactory
+logConfigFile=./../afs-server/etc/log4j2.xml
+
+jsonObjectMapperClass=ch.ethz.sis.afsjson.jackson.JacksonObjectMapper
+# Where all the transactions information is written until the prepare step
+# For performance reasons should be on the save volume as the configured storage
+writeAheadLogRoot=./../afs-server/transactions
+storageRoot=./../afs-server/storage
+
+httpServerClass=ch.ethz.sis.afsserver.http.impl.NettyHttpServer
+httpServerUri=/data-store-server
+httpServerPort=8085
+httpMaxContentLength=1024
+
+maxReadSizeInBytes=1048576
+authenticationInfoProviderClass=ch.ethz.sis.afsserver.worker.providers.impl.DummyAuthenticationInfoProvider
+authorizationInfoProviderClass=ch.ethz.sis.afsserver.worker.providers.impl.DummyAuthorizationInfoProvider
+poolSize=50
+connectionFactoryClass=ch.ethz.sis.afsserver.worker.ConnectionFactory
+workerFactoryClass=ch.ethz.sis.afsserver.worker.WorkerFactory
+publicApiInterface=ch.ethz.sis.afsapi.api.PublicAPI
+apiServerInteractiveSessionKey=test-interactive-session-key
+apiServerTransactionManagerKey=test-transaction-coordinator-key
+apiServerWorkerTimeout=3600000
+openBISUrl=
+openBISTimeout=30000
\ No newline at end of file
diff --git a/test-api-openbis-javascript/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/main.js b/test-api-openbis-javascript/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/main.js
index 8e1644af6b7..d6b0d9cd0ad 100644
--- a/test-api-openbis-javascript/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/main.js
+++ b/test-api-openbis-javascript/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/main.js
@@ -19,6 +19,7 @@ define([
     "test-compiled/test-archive-unarchive",
     "test-compiled/test-import-export",
     "test-compiled/test-typescript",
+    "test-compiled/test-afs",
 ], function () {
     var testSuites = arguments
     return async function () {
diff --git a/test-api-openbis-javascript/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/test-afs.ts b/test-api-openbis-javascript/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/test-afs.ts
new file mode 100644
index 00000000000..ee639ad3212
--- /dev/null
+++ b/test-api-openbis-javascript/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/test-afs.ts
@@ -0,0 +1,63 @@
+import jquery from "./types/jquery"
+import underscore from "./types/underscore"
+import common from "./types/common"
+import openbis from "./types/openbis.esm"
+
+exports.default = new Promise((resolve) => {
+    require(["jquery", "underscore", "openbis", "test/common", "test/dtos"], function (
+        $: jquery.JQueryStatic,
+        _: underscore.UnderscoreStatic,
+        openbisRequireJS,
+        common: common.CommonConstructor,
+        dtos
+    ) {
+        var executeModule = function (moduleName: string, facade: openbis.openbis, dtos: openbis.bundle) {
+            QUnit.module(moduleName)
+
+            function assertFileEquals(c: common.CommonClass, actualFile: openbis.File, expectedPath: string, expectedDirectory: boolean) {
+                c.assertEqual(actualFile.getPath(), expectedPath, "File path")
+                c.assertEqual(actualFile.getDirectory(), expectedDirectory, "File directory")
+            }
+
+            QUnit.test("list()", async function (assert) {
+                try {
+                    var c = new common(assert, dtos)
+                    c.start()
+
+                    await c.login(facade)
+
+                    await facade.getAfsServerFacade().write("test-owner", "test-file-1", 0, "test-content-1")
+                    await facade.getAfsServerFacade().write("test-owner/test-folder-1", "test-file-2", 0, "test-content-2")
+                    await facade.getAfsServerFacade().write("test-owner/test-folder-1", "test-file-3", 0, "test-content-3")
+                    await facade.getAfsServerFacade().write("test-owner/test-folder-2", "test-file-4", 0, "test-content-4")
+
+                    var list = await facade.getAfsServerFacade().list("test-owner", "", true)
+
+                    list.sort((file1, file2) => {
+                        return file1.getPath().localeCompare(file2.getPath())
+                    })
+
+                    c.assertEqual(list.length, 6, "Number of files")
+
+                    assertFileEquals(c, list[0], "/test-file-1", false)
+                    assertFileEquals(c, list[1], "/test-folder-1", true)
+                    assertFileEquals(c, list[2], "/test-folder-1/test-file-2", false)
+                    assertFileEquals(c, list[3], "/test-folder-1/test-file-3", false)
+                    assertFileEquals(c, list[4], "/test-folder-2", true)
+                    assertFileEquals(c, list[5], "/test-folder-2/test-file-4", false)
+
+                    c.finish()
+                } catch (error) {
+                    c.fail(error)
+                    c.finish()
+                }
+            })
+        }
+
+        resolve(function () {
+            executeModule("Afs tests (RequireJS)", new openbisRequireJS(), dtos)
+            executeModule("Afs tests (module VAR)", new window.openbis.openbis(), window.openbis)
+            executeModule("Afs tests (module ESM)", new window.openbisESM.openbis(), window.openbisESM)
+        })
+    })
+})
diff --git a/test-api-openbis-javascript/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/types/openbis.esm.d.ts b/test-api-openbis-javascript/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/types/openbis.esm.d.ts
index 75bf226c7e3..68bfe530f7c 100644
--- a/test-api-openbis-javascript/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/types/openbis.esm.d.ts
+++ b/test-api-openbis-javascript/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/types/openbis.esm.d.ts
@@ -1,6 +1,6 @@
 /* tslint:disable */
 /* eslint-disable */
-// Generated using typescript-generator version 3.2.1263 on 2024-01-29 16:21:05.
+// Generated using typescript-generator version 3.2.1263 on 2024-03-27 12:40:27.
 
 export default openbis;
 
@@ -9501,6 +9501,30 @@ export namespace openbis {
         new <T extends any>(): FieldUpdateValue<T>;
     }
 
+    interface File {
+
+        getCreationTime(): number;
+
+        getDirectory(): boolean;
+
+        getLastAccessTime(): number;
+
+        getLastModifiedTime(): number;
+
+        getName(): string;
+
+        getOwner(): string;
+
+        getPath(): string;
+    }
+
+    /**
+     */
+    interface FileConstructor {
+
+        new (): File;
+    }
+
     /**
      * @deprecated
      */
@@ -13638,6 +13662,23 @@ export namespace openbis {
         new (arg0: number): ObjectTechId;
     }
 
+    interface OpenBISJavaScriptAFSFacade {
+
+        copy(arg0: string, arg1: string, arg2: string, arg3: string): Promise<boolean>;
+
+        create(arg0: string, arg1: string, arg2: boolean): Promise<boolean>;
+
+        delete(arg0: string, arg1: string): Promise<boolean>;
+
+        list(arg0: string, arg1: string, arg2: boolean): Promise<File[]>;
+
+        move(arg0: string, arg1: string, arg2: string, arg3: string): Promise<boolean>;
+
+        read(arg0: string, arg1: string, arg2: number, arg3: number): Promise<string>;
+
+        write(arg0: string, arg1: string, arg2: number, arg3: string): Promise<boolean>;
+    }
+
     interface OpenBISJavaScriptDSSFacade {
 
         createDataSetUpload(arg0: string): Promise<CreateDataSetUploadResult>;
@@ -13775,6 +13816,8 @@ export namespace openbis {
 
         executeSql(arg1: string, arg2: SqlExecutionOptions): Promise<TableModel>;
 
+        getAfsServerFacade(): OpenBISJavaScriptAFSFacade;
+
         getAuthorizationGroups(arg1: IAuthorizationGroupId[], arg2: AuthorizationGroupFetchOptions): Promise<{ [index: string]: AuthorizationGroup }>;
 
         getDataSetTypes(arg1: IEntityTypeId[], arg2: DataSetTypeFetchOptions): Promise<{ [index: string]: DataSetType }>;
@@ -16701,6 +16744,10 @@ export namespace openbis {
 
         getMetaData(): { [index: string]: string };
 
+        getPattern(): string;
+
+        getPatternType(): string;
+
         getPermId(): PropertyTypePermId;
 
         getRegistrationDate(): number;
@@ -16743,6 +16790,10 @@ export namespace openbis {
 
         setMultiValue(arg0: boolean): void;
 
+        setPattern(arg0: string): void;
+
+        setPatternType(arg0: string): void;
+
         setPermId(arg0: PropertyTypePermId): void;
 
         setRegistrationDate(arg0: number): void;
@@ -16781,6 +16832,10 @@ export namespace openbis {
 
         getMetaData(): { [index: string]: string };
 
+        getPattern(): string;
+
+        getPatternType(): string;
+
         getSampleTypeId(): IEntityTypeId;
 
         getSchema(): string;
@@ -16813,6 +16868,10 @@ export namespace openbis {
 
         setMultiValue(arg0: boolean): void;
 
+        setPattern(arg0: string): void;
+
+        setPatternType(arg0: string): void;
+
         setSampleTypeId(arg0: IEntityTypeId): void;
 
         setSchema(arg0: string): void;
@@ -16975,6 +17034,10 @@ export namespace openbis {
 
         getObjectId(): IPropertyTypeId;
 
+        getPattern(): FieldUpdateValue<string>;
+
+        getPatternType(): FieldUpdateValue<string>;
+
         getSchema(): FieldUpdateValue<string>;
 
         getTransformation(): FieldUpdateValue<string>;
@@ -16987,6 +17050,10 @@ export namespace openbis {
 
         setMetaDataActions(arg0: ListUpdateAction<any>[]): void;
 
+        setPattern(arg0: string): void;
+
+        setPatternType(arg0: string): void;
+
         setSchema(arg0: string): void;
 
         setTransformation(arg0: string): void;
@@ -24948,6 +25015,7 @@ export namespace openbis {
         FastDownloadSessionOptions: FastDownloadSessionOptionsConstructor;
         FetchOptions: FetchOptionsConstructor;
         FieldUpdateValue: FieldUpdateValueConstructor;
+        File: FileConstructor;
         FileFormatType: FileFormatTypeConstructor;
         FileFormatTypeFetchOptions: FileFormatTypeFetchOptionsConstructor;
         FileFormatTypePermId: FileFormatTypePermIdConstructor;
@@ -27564,6 +27632,8 @@ SAMPLE : "SAMPLE"} as const
 
     export const FieldUpdateValue:FieldUpdateValueConstructor
 
+    export const File:FileConstructor
+
     export const FileFormatType:FileFormatTypeConstructor
 
     export const FileFormatTypeFetchOptions:FileFormatTypeFetchOptionsConstructor
@@ -30306,6 +30376,10 @@ SAMPLE : "SAMPLE"} as const
 
     type  = CreateDataSetUploadResult
 
+    type  = File
+
+    type  = OpenBISJavaScriptAFSFacade
+
     type  = OpenBISJavaScriptDSSFacade
 
     type ArchivingStatus = typeof ArchivingStatus[keyof typeof ArchivingStatus]
diff --git a/test-api-openbis-javascript/servers/common/openBIS-server/etc/log.xml b/test-api-openbis-javascript/servers/common/openBIS-server/etc/log.xml
deleted file mode 100644
index c437339ded6..00000000000
--- a/test-api-openbis-javascript/servers/common/openBIS-server/etc/log.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
-
-<!--
-  // This configuration file is suitable for testing purposes. 
--->
-<log4j:configuration debug="true" xmlns:log4j='http://jakarta.apache.org/log4j/'>
-
-  <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
-    <layout class="org.apache.log4j.PatternLayout">
-      <!--
-        // %d: outputs the date of the logging event.
-        // %-5p: priority (i.e. level) of the logging event should be left justified to
-        //       a width of five characters.
-        // %t: outputs the name of the thread that generated the logging event.
-        // %c: outputs the category of the logging event.
-        // %m: outputs the application supplied message associated with the logging event.
-        // %n: outputs the platform dependent line separator character or characters.
-        // %X: outputs the MDC (mapped diagnostic context) associated with the thread that generated the logging event.
-      -->
-      <param name="ConversionPattern"
-        value="%d %-5p [%t]%X{sessionInfo} %c - %m%n" />
-    </layout>
-  </appender>
-
-  <!--
-    // Defined but not used right now.
-  -->
-  <appender name="NULL" class="org.apache.log4j.varia.NullAppender" />
-
-  <!--
-    // Enable full wire (header and content) + context logging
-    // For more information look at http://jakarta.apache.org/commons/httpclient/logging.html.
-    // We do not need to set a level value here as loggers inherit their level from the root logger.
-  -->
-
-  <!-- 
-    // Do not use log level debug otherwise plain passwords are readable.
-  -->
-  <logger name="httpclient.wire">
-    <level value="ERROR" />
-  </logger>
-
-  <!--  
-    // Uncomment this for debugging value binding in Hibernate
-      <category name="org.hibernate.type">  
-        <priority value="TRACE"/>  
-      </category>
-  -->
-
-  <!--
-    <logger name="org.apache.commons.httpclient">
-    <level value="DEBUG" />
-    </logger>
-  -->
-
-  <root>
-    <priority value="info" />
-    <appender-ref ref="STDOUT" />
-  </root>
-
-</log4j:configuration>
diff --git a/test-api-openbis-javascript/servers/common/openBIS-server/etc/log4j1.xml b/test-api-openbis-javascript/servers/common/openBIS-server/etc/log4j1.xml
new file mode 100644
index 00000000000..20ec316ea66
--- /dev/null
+++ b/test-api-openbis-javascript/servers/common/openBIS-server/etc/log4j1.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
+
+  <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
+    <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="[AS] %d %-5p [%t] %c - %m%n"/>
+    </layout>
+  </appender>
+
+  <appender name="NULL" class="org.apache.log4j.varia.NullAppender" />
+
+  <root>
+    <priority value="info" />
+    <appender-ref ref="STDOUT" />
+  </root>
+
+</log4j:configuration>
diff --git a/test-api-openbis-javascript/settings.gradle b/test-api-openbis-javascript/settings.gradle
index 09200920db5..81cd6a673e7 100644
--- a/test-api-openbis-javascript/settings.gradle
+++ b/test-api-openbis-javascript/settings.gradle
@@ -1,3 +1,3 @@
 includeFlat 'lib-commonbase', 'lib-common', 'api-openbis-java', 'lib-openbis-common', 'lib-authentication',
-        'lib-dbmigration', 'server-application-server', 'server-original-data-store', 'server-screening',
+        'lib-dbmigration', 'lib-transactional-file-system', 'server-application-server', 'server-original-data-store', 'server-data-store', 'server-screening',
         'core-plugin-openbis', 'test-ui-core', 'api-openbis-javascript'
diff --git a/test-api-openbis-javascript/source/java/ch/systemsx/cisd/openbis/jstest/suite/common/JsTestCommonSelenium.java b/test-api-openbis-javascript/source/java/ch/systemsx/cisd/openbis/jstest/suite/common/JsTestCommonSelenium.java
index e02fe08d9f1..6693486214d 100644
--- a/test-api-openbis-javascript/source/java/ch/systemsx/cisd/openbis/jstest/suite/common/JsTestCommonSelenium.java
+++ b/test-api-openbis-javascript/source/java/ch/systemsx/cisd/openbis/jstest/suite/common/JsTestCommonSelenium.java
@@ -16,14 +16,20 @@
 package ch.systemsx.cisd.openbis.jstest.suite.common;
 
 import java.io.File;
+import java.util.List;
 
 import org.openqa.selenium.logging.LogEntries;
 import org.openqa.selenium.logging.LogEntry;
 import org.openqa.selenium.logging.LogType;
 import org.testng.annotations.AfterTest;
+import org.testng.annotations.BeforeSuite;
 import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
 
+import ch.ethz.sis.afsserver.server.Server;
+import ch.ethz.sis.afsserver.server.observer.impl.DummyServerObserver;
+import ch.ethz.sis.afsserver.startup.AtomicFileSystemServerParameter;
+import ch.ethz.sis.shared.startup.Configuration;
 import ch.systemsx.cisd.base.unix.Unix;
 import ch.systemsx.cisd.common.filesystem.FileUtilities;
 import ch.systemsx.cisd.openbis.jstest.layout.OpenbisJsWebappLocation;
@@ -39,13 +45,19 @@ import junit.framework.Assert;
 public class JsTestCommonSelenium extends SeleniumTest
 {
 
-    /** Duration of sleep in milliseconds before next check for JUnit report. */
+    /**
+     * Duration of sleep in milliseconds before next check for JUnit report.
+     */
     private static final int JUNIT_REPORT_SLEEP_DURATION = 2000;
 
-    /** Total duration in milliseconds for JUnit report. */
+    /**
+     * Total duration in milliseconds for JUnit report.
+     */
     private static final int JUNIT_REPORT_TOTAL_DURATION = 15 * 60 * 1000;
 
-    /** How many checks for report should be performed. */
+    /**
+     * How many checks for report should be performed.
+     */
     private static final int CHECKS_COUNT =
             JUNIT_REPORT_TOTAL_DURATION / JUNIT_REPORT_SLEEP_DURATION;
 
@@ -63,6 +75,14 @@ public class JsTestCommonSelenium extends SeleniumTest
         }
     }
 
+    @BeforeSuite @Override public void initialization() throws Exception
+    {
+        System.setProperty("log4j.configuration", "etc/log.xml");
+        System.setProperty("log4j.configurationFile", "etc/log.xml");
+        super.initialization();
+        startAfsServer();
+    }
+
     @Override
     protected String startApplicationServer() throws Exception
     {
@@ -89,6 +109,14 @@ public class JsTestCommonSelenium extends SeleniumTest
         return dss.start();
     }
 
+    protected void startAfsServer() throws Exception
+    {
+        Configuration configuration = new Configuration(List.of(AtomicFileSystemServerParameter.class),
+                "../afs-server/etc/server-data-store-config.properties");
+        DummyServerObserver dummyServerObserver = new DummyServerObserver();
+        new Server<>(configuration, dummyServerObserver, dummyServerObserver);
+    }
+
     @BeforeTest
     public void before()
     {
-- 
GitLab