From ef3c3822f065f8815c17d51d0598879e0807b210 Mon Sep 17 00:00:00 2001
From: Timm Fitschen <t.fitschen@indiscale.com>
Date: Wed, 14 Dec 2022 22:10:49 +0100
Subject: [PATCH] WIP: file system: import

---
 .../java/org/caosdb/server/entity/Entity.java | 20 ++++++++++++++-----
 .../server/filesystem/FSODescriptor.java      | 10 ++++++++++
 .../filesystem/FileStorageInterface.java      |  6 ++++--
 .../caosdb/server/filesystem/FileSystem.java  |  9 +++++++--
 .../server/filesystem/LocalFileStorage.java   | 17 +++++++++++++++-
 .../server/filesystem/SharedFileStorage.java  |  2 +-
 .../VirtualFSODescriptorInterface.java        |  2 ++
 .../consistency/ConsistencyCheck.java         |  2 +-
 .../java/org/caosdb/server/jobs/FilesJob.java | 17 +++++++++++++++-
 .../jobs/core/CheckTargetPathValid.java       | 10 ++++++++++
 .../caosdb/server/utils/ServerMessages.java   |  6 ++++++
 11 files changed, 88 insertions(+), 13 deletions(-)

diff --git a/src/main/java/org/caosdb/server/entity/Entity.java b/src/main/java/org/caosdb/server/entity/Entity.java
index 04237c31..61a287e6 100644
--- a/src/main/java/org/caosdb/server/entity/Entity.java
+++ b/src/main/java/org/caosdb/server/entity/Entity.java
@@ -816,21 +816,31 @@ public abstract class Entity extends AbstractObservable implements EntityInterfa
       linkTarget = Integer.parseInt(element.getAttributeValue("linktarget"));
     }
 
+    // Parse IMPORT
+    boolean isImport = false;
+    if (element.getAttribute("import") != null
+        && element.getAttributeValue("import").equals("true")) {
+      isImport = true;
+    }
+
     // Store PATH, HASH, SIZE, TMPIDENTIFYER
     if (tmpIdentifier != null || checksum != null || path != null || size != null) {
       // legacy clients (which use this api) always use sha512.
       Hash hash = Hash.create(checksum, 0, Hasher.Default);
+      FSODescriptor fso;
       if (getRole() == Role.Directory) {
-        setFSODescriptor(FSODescriptor.createDir(FileSystem.DEFAULT_BACKEND, new Path(path)));
+        fso = FSODescriptor.createDir(FileSystem.DEFAULT_BACKEND, new Path(path));
       } else if (getRole() == Role.Link) {
-        setFSODescriptor(
+        fso =
             FSODescriptor.createLink(
-                FileSystem.DEFAULT_BACKEND, new Path(path), new EntityID(linkTarget)));
+                FileSystem.DEFAULT_BACKEND, new Path(path), new EntityID(linkTarget));
       } else {
-        setFSODescriptor(
+        fso =
             new FSODescriptor(
-                FileSystem.DEFAULT_BACKEND, null, hash, new Path(path), size, tmpIdentifier));
+                FileSystem.DEFAULT_BACKEND, null, hash, new Path(path), size, tmpIdentifier);
       }
+      fso.setImport(isImport);
+      setFSODescriptor(fso);
     }
 
     // Parse flags
diff --git a/src/main/java/org/caosdb/server/filesystem/FSODescriptor.java b/src/main/java/org/caosdb/server/filesystem/FSODescriptor.java
index 19b1c829..ee99d816 100644
--- a/src/main/java/org/caosdb/server/filesystem/FSODescriptor.java
+++ b/src/main/java/org/caosdb/server/filesystem/FSODescriptor.java
@@ -43,6 +43,7 @@ public class FSODescriptor implements VirtualFSODescriptorInterface {
   protected List<VirtualFSODescriptorInterface> children;
   private RealFSODescriptorInterface twin;
   private EntityID linkTarget = null;
+  private boolean isImport = false;
 
   public FSODescriptor(
       final String fileStorageId,
@@ -283,4 +284,13 @@ public class FSODescriptor implements VirtualFSODescriptorInterface {
     result.type = ObjectType.LINK;
     return result;
   }
+
+  @Override
+  public boolean isImport() {
+    return isImport;
+  }
+
+  public void setImport(boolean isImport) {
+    this.isImport = isImport;
+  }
 }
diff --git a/src/main/java/org/caosdb/server/filesystem/FileStorageInterface.java b/src/main/java/org/caosdb/server/filesystem/FileStorageInterface.java
index e2bca5af..90f49e9a 100644
--- a/src/main/java/org/caosdb/server/filesystem/FileStorageInterface.java
+++ b/src/main/java/org/caosdb/server/filesystem/FileStorageInterface.java
@@ -48,8 +48,10 @@ public interface FileStorageInterface {
 
   public abstract Hash getHash(FSODescriptorInterface fso, String algorithm);
 
-  /** Return true iff an object with this key exists. */
-  public abstract boolean exists(String key);
+  /** Return true if this object exists. */
+  public abstract boolean exists(VirtualFSODescriptorInterface fso);
 
   public abstract Iterable<? extends RealFSODescriptorInterface> list(String prefix);
+
+  public abstract RealFSODescriptorInterface resolve(VirtualFSODescriptorInterface fso);
 }
diff --git a/src/main/java/org/caosdb/server/filesystem/FileSystem.java b/src/main/java/org/caosdb/server/filesystem/FileSystem.java
index 800a003b..dcd685fd 100644
--- a/src/main/java/org/caosdb/server/filesystem/FileSystem.java
+++ b/src/main/java/org/caosdb/server/filesystem/FileSystem.java
@@ -84,10 +84,10 @@ public class FileSystem implements FileSystemInterface {
   //    return false;
   //  }
 
-  public static Boolean exists(FSODescriptorInterface fso) {
+  public static Boolean exists(VirtualFSODescriptorInterface fso) {
     FileStorageInterface fileStorage = getInstance().getFileStorage(fso);
     if (fileStorage.getCapabilities().existence) {
-      return fileStorage.exists(fso.getKey());
+      return fileStorage.exists(fso);
     }
     return null;
   }
@@ -98,6 +98,11 @@ public class FileSystem implements FileSystemInterface {
     return fileStorage.move(fso, target);
   }
 
+  public RealFSODescriptorInterface resolve(VirtualFSODescriptorInterface fso) {
+    FileStorageInterface fileStorage = getInstance().getFileStorage(fso);
+    return fileStorage.resolve(fso);
+  }
+
   //  public static boolean resolve(FSODescriptorInterface fso) {
   //    FileStorageInterface fileStorage = getInstance().getFileStorage(fso);
   //    return fileStorage.resolve(fso);
diff --git a/src/main/java/org/caosdb/server/filesystem/LocalFileStorage.java b/src/main/java/org/caosdb/server/filesystem/LocalFileStorage.java
index 40836edb..bfc8fe12 100644
--- a/src/main/java/org/caosdb/server/filesystem/LocalFileStorage.java
+++ b/src/main/java/org/caosdb/server/filesystem/LocalFileStorage.java
@@ -284,6 +284,16 @@ public abstract class LocalFileStorage implements FileStorageInterface {
     return new LocalFSODescriptor(this, key);
   }
 
+  @Override
+  public RealFSODescriptorInterface resolve(VirtualFSODescriptorInterface fso) {
+    String key = fso.getKey();
+    if (key == null) {
+      key = fso.getPath().toString();
+      fso.setKey(key);
+    }
+    return resolve(key);
+  }
+
   @Override
   public Undoable move(final RealFSODescriptorInterface file, VirtualFSODescriptorInterface target)
       throws Message {
@@ -698,7 +708,12 @@ public abstract class LocalFileStorage implements FileStorageInterface {
   }
 
   @Override
-  public boolean exists(String key) {
+  public boolean exists(VirtualFSODescriptorInterface fso) {
+    String key = fso.getKey();
+    if (key == null) {
+      key = fso.getPath().toString();
+      fso.setKey(key);
+    }
     return !isFree(key);
   }
 
diff --git a/src/main/java/org/caosdb/server/filesystem/SharedFileStorage.java b/src/main/java/org/caosdb/server/filesystem/SharedFileStorage.java
index e66bf2b9..ac47dbd8 100644
--- a/src/main/java/org/caosdb/server/filesystem/SharedFileStorage.java
+++ b/src/main/java/org/caosdb/server/filesystem/SharedFileStorage.java
@@ -64,7 +64,7 @@ public class SharedFileStorage extends LocalFileStorage {
     }
 
     // known to this fs?
-    if (!exists(path)) {
+    if (!exists(getFile(path))) {
       return null;
     }
 
diff --git a/src/main/java/org/caosdb/server/filesystem/VirtualFSODescriptorInterface.java b/src/main/java/org/caosdb/server/filesystem/VirtualFSODescriptorInterface.java
index f76c997a..4e65b45b 100644
--- a/src/main/java/org/caosdb/server/filesystem/VirtualFSODescriptorInterface.java
+++ b/src/main/java/org/caosdb/server/filesystem/VirtualFSODescriptorInterface.java
@@ -126,4 +126,6 @@ public interface VirtualFSODescriptorInterface extends FSODescriptorInterface {
   public abstract Path getLinkTargetPath();
 
   public abstract void setLinkTargetPath(Path target);
+
+  public abstract boolean isImport();
 }
diff --git a/src/main/java/org/caosdb/server/filesystem/consistency/ConsistencyCheck.java b/src/main/java/org/caosdb/server/filesystem/consistency/ConsistencyCheck.java
index b5dd679f..71e1a2cd 100644
--- a/src/main/java/org/caosdb/server/filesystem/consistency/ConsistencyCheck.java
+++ b/src/main/java/org/caosdb/server/filesystem/consistency/ConsistencyCheck.java
@@ -244,7 +244,7 @@ class RunThroughInternalFileSystem extends ConsistencyCheckStrategy {
     return null;
   }
 
-  private RealFSODescriptorInterface resolve(FSODescriptorInterface fso) {
+  private RealFSODescriptorInterface resolve(VirtualFSODescriptorInterface fso) {
     RealFSODescriptorInterface result = null;
     result = FileSystem.getInstance().resolve(fso.getFileStorageId(), fso.getKey());
     Boolean exists = FileSystem.exists(fso);
diff --git a/src/main/java/org/caosdb/server/jobs/FilesJob.java b/src/main/java/org/caosdb/server/jobs/FilesJob.java
index f769481c..70b099ea 100644
--- a/src/main/java/org/caosdb/server/jobs/FilesJob.java
+++ b/src/main/java/org/caosdb/server/jobs/FilesJob.java
@@ -22,8 +22,11 @@
  */
 package org.caosdb.server.jobs;
 
+import org.caosdb.server.entity.Message;
+import org.caosdb.server.filesystem.FileSystem;
 import org.caosdb.server.filesystem.RealFSODescriptorInterface;
 import org.caosdb.server.filesystem.VirtualFSODescriptorInterface;
+import org.caosdb.server.utils.ServerMessages;
 
 public abstract class FilesJob extends EntityJob {
 
@@ -32,11 +35,23 @@ public abstract class FilesJob extends EntityJob {
    *
    * @param tmpFileId
    * @return
+   * @throws Message
    */
-  protected RealFSODescriptorInterface getRealFSODescriptor(VirtualFSODescriptorInterface fso) {
+  protected RealFSODescriptorInterface getRealFSODescriptor(VirtualFSODescriptorInterface fso)
+      throws Message {
     if (fso.getTwin() != null) {
       return fso.getTwin();
     }
+    if (fso.isImport()) {
+      if (FileSystem.exists(getEntity().getFSODescriptor())) {
+        RealFSODescriptorInterface twin =
+            FileSystem.getInstance().resolve(getEntity().getFSODescriptor());
+        getEntity().getFSODescriptor().setTwin(twin);
+        return twin;
+      } else if (getEntity().getFSODescriptor().isImport()) {
+        throw ServerMessages.FILE_IMPORT_FAILED_FILE_DOES_NOT_EXIST;
+      }
+    }
     return getContainer().getFiles().get(fso.getTmpIdentifier());
   }
 }
diff --git a/src/main/java/org/caosdb/server/jobs/core/CheckTargetPathValid.java b/src/main/java/org/caosdb/server/jobs/core/CheckTargetPathValid.java
index 6d381553..60e5ddd5 100644
--- a/src/main/java/org/caosdb/server/jobs/core/CheckTargetPathValid.java
+++ b/src/main/java/org/caosdb/server/jobs/core/CheckTargetPathValid.java
@@ -23,6 +23,7 @@
 package org.caosdb.server.jobs.core;
 
 import org.caosdb.server.database.backend.transaction.CheckTargetPath;
+import org.caosdb.server.filesystem.FileSystem;
 import org.caosdb.server.filesystem.VirtualFSODescriptorInterface;
 import org.caosdb.server.jobs.FilesJob;
 import org.caosdb.server.utils.EntityStatus;
@@ -51,6 +52,15 @@ public class CheckTargetPathValid extends FilesJob {
       // check that target path is not owned by another entity.
       final CheckTargetPath t = new CheckTargetPath(getEntity(), getContainer());
       execute(t);
+
+      // check if the fso exists in the file storage
+      if (FileSystem.exists(getEntity().getFSODescriptor())) {
+        if (getEntity().getFSODescriptor().isImport()) {
+          // ok?
+        } else {
+          // is update?
+        }
+      }
     }
   }
 }
diff --git a/src/main/java/org/caosdb/server/utils/ServerMessages.java b/src/main/java/org/caosdb/server/utils/ServerMessages.java
index ed048f3c..25d52bc0 100644
--- a/src/main/java/org/caosdb/server/utils/ServerMessages.java
+++ b/src/main/java/org/caosdb/server/utils/ServerMessages.java
@@ -168,6 +168,12 @@ public class ServerMessages {
           MessageCode.MESSAGE_CODE_FILE_HAS_NOT_BEEN_UPLOAED,
           "File has not been uploaded.");
 
+  public static final Message FILE_IMPORT_FAILED_FILE_DOES_NOT_EXIST =
+      new Message(
+          MessageType.Error,
+          MessageCode.MESSAGE_CODE_UNKNOWN,
+          "This file does not exist. It cannot be imported.");
+
   public static final Message CANNOT_MOVE_FILE_TO_TARGET_PATH =
       new Message(
           MessageType.Error,
-- 
GitLab