Repository: apache/streampipes
Pull request #2968 (2024-06-27 19:07:02)

chore: Cleanup persistence layer
<!--
  ~ Licensed to the Apache Software Foundation (ASF) under one or more
  ~ contributor license agreements.  See the NOTICE file distributed with
  ~ this work for additional information regarding copyright ownership.
  ~ The ASF licenses this file to You 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.
  ~
  -->

  <!--
Thanks for contributing! Here are some tips you can follow to help us incorporate your contribution quickly and easily:
1. If this is your first time, please read our contributor guidelines:
    - https://streampipes.apache.org/community/get-involved/
    - https://cwiki.apache.org/confluence/display/STREAMPIPES/Getting+Started
2. Make sure the PR title is formatted like: `[#<GitHub issue id>] PR title ...`
3. If the PR is unfinished, add '[WIP]' in your PR title, e.g., `[WIP][#<GitHub issue id>] PR title ...`.
4. Please write your PR title to summarize what this PR proposes/fixes.
5. Link the PR to the corresponding GitHub issue (if present) in the `Development` section in the right menu bar.
6. Be sure to keep the PR description updated to reflect all changes.
7. If possible, provide a concise example to reproduce the issue for a faster review.
8. Make sure tests pass via `mvn clean install`.
9. (Optional) If the contribution is large, please file an Apache ICLA
    - http://apache.org/licenses/icla.pdf
-->

### Purpose
<!--
Please clarify what changes you are proposing and describe how those changes will address the issue.
Furthermore, describe potential consequences the changes might have.
-->

Do some more cleanup to reduce persistence layer complexity.

### Remarks
<!--
Is there anything left we need to pay attention on?
Are there some references that might be important? E.g. links to Confluence, or discussions
on the mailing list or GitHub.
-->
PR introduces (a) breaking change(s): no

PR introduces (a) deprecation(s): no



Patch:
diff --git a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataExplorerSchemaManagement.java b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataExplorerSchemaManagement.java
index d6cac01c7d..ef3db4c7d3 100644
--- a/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataExplorerSchemaManagement.java
+++ b/streampipes-data-explorer/src/main/java/org/apache/streampipes/dataexplorer/DataExplorerSchemaManagement.java
@@ -34,9 +34,9 @@ import java.util.stream.Stream;
 
 public class DataExplorerSchemaManagement implements IDataExplorerSchemaManagement {
 
-  CRUDStorage<String, DataLakeMeasure> dataLakeStorage;
+  CRUDStorage<DataLakeMeasure> dataLakeStorage;
 
-  public DataExplorerSchemaManagement(CRUDStorage<String, DataLakeMeasure> dataLakeStorage) {
+  public DataExplorerSchemaManagement(CRUDStorage<DataLakeMeasure> dataLakeStorage) {
     this.dataLakeStorage = dataLakeStorage;
   }
 
diff --git a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/FileResolver.java b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/FileResolver.java
index d30d66936a..ab0179d8f1 100644
--- a/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/FileResolver.java
+++ b/streampipes-data-export/src/main/java/org/apache/streampipes/export/resolver/FileResolver.java
@@ -28,7 +28,7 @@ public class FileResolver extends AbstractResolver<FileMetadata> {
 
   @Override
   public FileMetadata findDocument(String resourceId) {
-    return getNoSqlStore().getFileMetadataStorage().getMetadataById(resourceId);
+    return getNoSqlStore().getFileMetadataStorage().getElementById(resourceId);
   }
 
   @Override
@@ -49,7 +49,7 @@ public class FileResolver extends AbstractResolver<FileMetadata> {
 
   @Override
   public void writeDocument(String document) throws JsonProcessingException {
-    getNoSqlStore().getFileMetadataStorage().addFileMetadata(deserializeDocument(document));
+    getNoSqlStore().getFileMetadataStorage().persist(deserializeDocument(document));
   }
 
   @Override
diff --git a/streampipes-maven-plugin/pom.xml b/streampipes-maven-plugin/pom.xml
index 95cb99b4c1..f802fa0bc6 100644
--- a/streampipes-maven-plugin/pom.xml
+++ b/streampipes-maven-plugin/pom.xml
@@ -43,7 +43,7 @@
         <maven-jar-plugin.version>3.4.0</maven-jar-plugin.version>
         <maven-plugin-plugin.version>3.13.0</maven-plugin-plugin.version>
         <maven-resources-plugin.version>3.3.0</maven-resources-plugin.version>
-        <maven-surefire-plugin.version>3.2.5</maven-surefire-plugin.version>
+        <maven-surefire-plugin.version>3.3.0</maven-surefire-plugin.version>
     </properties>
 
     <dependencyManagement>
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/assetdashboard/AssetDashboardConfig.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/assetdashboard/AssetDashboardConfig.java
index d8956e577c..9d162c9595 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/assetdashboard/AssetDashboardConfig.java
+++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/assetdashboard/AssetDashboardConfig.java
@@ -17,12 +17,14 @@
  */
 package org.apache.streampipes.model.client.assetdashboard;
 
+import org.apache.streampipes.model.shared.api.Storable;
+
 import com.google.gson.annotations.SerializedName;
 
 import java.util.List;
 import java.util.Map;
 
-public class AssetDashboardConfig {
+public class AssetDashboardConfig implements Storable {
 
   private @SerializedName("_id") String dashboardId;
   private @SerializedName("_rev") String rev;
@@ -100,4 +102,14 @@ public class AssetDashboardConfig {
   public void setRev(String rev) {
     this.rev = rev;
   }
+
+  @Override
+  public String getElementId() {
+    return this.dashboardId;
+  }
+
+  @Override
+  public void setElementId(String elementId) {
+    this.dashboardId = elementId;
+  }
 }
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/AbstractMailToken.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/AbstractMailToken.java
index 372ad5de98..0434031dc0 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/AbstractMailToken.java
+++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/AbstractMailToken.java
@@ -17,9 +17,11 @@
  */
 package org.apache.streampipes.model.client.user;
 
+import org.apache.streampipes.model.shared.api.Storable;
+
 import com.google.gson.annotations.SerializedName;
 
-public abstract class AbstractMailToken {
+public abstract class AbstractMailToken implements Storable {
 
   protected @SerializedName("_id") String token;
   protected @SerializedName("_rev") String rev;
@@ -49,4 +51,14 @@ public abstract class AbstractMailToken {
   public void setUsername(String username) {
     this.username = username;
   }
+
+  @Override
+  public String getElementId() {
+    return this.token;
+  }
+
+  @Override
+  public void setElementId(String elementId) {
+    this.token = elementId;
+  }
 }
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Group.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Group.java
index 8829add8a3..063d901877 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Group.java
+++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Group.java
@@ -18,6 +18,7 @@
 package org.apache.streampipes.model.client.user;
 
 import org.apache.streampipes.model.shared.annotation.TsModel;
+import org.apache.streampipes.model.shared.api.Storable;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.google.gson.annotations.SerializedName;
@@ -26,15 +27,15 @@ import java.util.HashSet;
 import java.util.Set;
 
 @TsModel
-public class Group {
+public class Group implements Storable {
 
   protected @SerializedName("_id") String groupId;
   protected @SerializedName("_rev") String rev;
 
   // This field should be called $type since this is the identifier used in the CouchDB view
-  @SuppressWarnings("checkstyle:MemberName")
+  @SerializedName("$type")
   @JsonIgnore
-  private String $type = "group";
+  private String type = "group";
 
   private String groupName;
 
@@ -60,6 +61,16 @@ public class Group {
     this.rev = rev;
   }
 
+  @Override
+  public String getElementId() {
+    return this.groupId;
+  }
+
+  @Override
+  public void setElementId(String elementId) {
+    this.groupId = elementId;
+  }
+
   public String getGroupName() {
     return groupName;
   }
@@ -76,13 +87,11 @@ public class Group {
     this.roles = roles;
   }
 
-  @SuppressWarnings("checkstyle:MethodName")
-  public String get$type() {
-    return $type;
+  public String getType() {
+    return type;
   }
 
-  @SuppressWarnings({"checkstyle:MethodName", "checkstyle:ParameterName"})
-  public void set$type(String $type) {
-    this.$type = $type;
+  public void setType(String type) {
+    this.type = type;
   }
 }
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/PasswordRecoveryToken.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/PasswordRecoveryToken.java
index cb8ae692ea..8c0ea623e7 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/PasswordRecoveryToken.java
+++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/PasswordRecoveryToken.java
@@ -18,9 +18,12 @@
 package org.apache.streampipes.model.client.user;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.google.gson.annotations.SerializedName;
 
 public class PasswordRecoveryToken extends AbstractMailToken {
 
+  // This field should be called $type since this is the identifier used in the CouchDB view
+  @SerializedName("$type")
   @JsonIgnore
   private String type = "password-recovery";
 
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserActivationToken.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserActivationToken.java
index 1fe6ab0288..17d96c777e 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserActivationToken.java
+++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserActivationToken.java
@@ -18,9 +18,12 @@
 package org.apache.streampipes.model.client.user;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.google.gson.annotations.SerializedName;
 
 public class UserActivationToken extends AbstractMailToken {
 
+  // This field should be called $type since this is the identifier used in the CouchDB view
+  @SerializedName("$type")
   @JsonIgnore
   private String type = "user-activation";
 
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/api/Storable.java b/streampipes-model-shared/src/main/java/org/apache/streampipes/model/shared/api/Storable.java
similarity index 95%
rename from streampipes-model/src/main/java/org/apache/streampipes/model/api/Storable.java
rename to streampipes-model-shared/src/main/java/org/apache/streampipes/model/shared/api/Storable.java
index a9081f000d..1e7e4d4af1 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/api/Storable.java
+++ b/streampipes-model-shared/src/main/java/org/apache/streampipes/model/shared/api/Storable.java
@@ -16,7 +16,7 @@
  *
  */
 
-package org.apache.streampipes.model.api;
+package org.apache.streampipes.model.shared.api;
 
 public interface Storable {
 
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/base/NamedStreamPipesEntity.java b/streampipes-model/src/main/java/org/apache/streampipes/model/base/NamedStreamPipesEntity.java
index 46806a68a8..db57bf577e 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/base/NamedStreamPipesEntity.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/base/NamedStreamPipesEntity.java
@@ -20,10 +20,10 @@ package org.apache.streampipes.model.base;
 
 
 import org.apache.streampipes.model.SpDataStream;
-import org.apache.streampipes.model.api.Storable;
 import org.apache.streampipes.model.extensions.ExtensionAssetType;
 import org.apache.streampipes.model.extensions.ExtensionItemDescription;
 import org.apache.streampipes.model.shared.annotation.TsModel;
+import org.apache.streampipes.model.shared.api.Storable;
 import org.apache.streampipes.model.util.ServiceDefinitionUtil;
 
 import com.fasterxml.jackson.annotation.JsonAlias;
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardEntity.java b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardEntity.java
index 0b53f974a5..b2ec89845a 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardEntity.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardEntity.java
@@ -18,8 +18,8 @@
 
 package org.apache.streampipes.model.dashboard;
 
-import org.apache.streampipes.model.api.Storable;
 import org.apache.streampipes.model.datalake.DataExplorerWidgetModel;
+import org.apache.streampipes.model.shared.api.Storable;
 
 import com.fasterxml.jackson.annotation.JsonAlias;
 import com.fasterxml.jackson.annotation.JsonSubTypes;
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardModel.java b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardModel.java
index 9cd6e11365..6233b3f90c 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardModel.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/dashboard/DashboardModel.java
@@ -18,8 +18,8 @@
 
 package org.apache.streampipes.model.dashboard;
 
-import org.apache.streampipes.model.api.Storable;
 import org.apache.streampipes.model.shared.annotation.TsModel;
+import org.apache.streampipes.model.shared.api.Storable;
 
 import com.fasterxml.jackson.annotation.JsonAlias;
 import com.google.gson.annotations.SerializedName;
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/DataLakeMeasure.java b/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/DataLakeMeasure.java
index 92a3c881df..a7029fa520 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/DataLakeMeasure.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/datalake/DataLakeMeasure.java
@@ -18,10 +18,10 @@
 
 package org.apache.streampipes.model.datalake;
 
-import org.apache.streampipes.model.api.Storable;
 import org.apache.streampipes.model.schema.EventSchema;
 import org.apache.streampipes.model.shared.annotation.TsIgnore;
 import org.apache.streampipes.model.shared.annotation.TsModel;
+import org.apache.streampipes.model.shared.api.Storable;
 
 import com.fasterxml.jackson.annotation.JsonAlias;
 import com.fasterxml.jackson.annotation.JsonIgnore;
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/extensions/configuration/SpServiceConfiguration.java b/streampipes-model/src/main/java/org/apache/streampipes/model/extensions/configuration/SpServiceConfiguration.java
index 9cc4319d9a..268eb04cd9 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/extensions/configuration/SpServiceConfiguration.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/extensions/configuration/SpServiceConfiguration.java
@@ -19,13 +19,14 @@
 package org.apache.streampipes.model.extensions.configuration;
 
 import org.apache.streampipes.model.shared.annotation.TsModel;
+import org.apache.streampipes.model.shared.api.Storable;
 
 import com.google.gson.annotations.SerializedName;
 
 import java.util.List;
 
 @TsModel
-public class SpServiceConfiguration {
+public class SpServiceConfiguration implements Storable {
 
   protected @SerializedName("_rev") String rev;
   private @SerializedName("_id") String serviceGroup;
@@ -75,4 +76,14 @@ public class SpServiceConfiguration {
   public void setRev(String rev) {
     this.rev = rev;
   }
+
+  @Override
+  public String getElementId() {
+    return this.serviceGroup;
+  }
+
+  @Override
+  public void setElementId(String elementId) {
+    this.serviceGroup = elementId;
+  }
 }
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/extensions/svcdiscovery/SpServiceRegistration.java b/streampipes-model/src/main/java/org/apache/streampipes/model/extensions/svcdiscovery/SpServiceRegistration.java
index fc01712a8c..7fb9b8d1e3 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/extensions/svcdiscovery/SpServiceRegistration.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/extensions/svcdiscovery/SpServiceRegistration.java
@@ -19,13 +19,14 @@ package org.apache.streampipes.model.extensions.svcdiscovery;
 
 import org.apache.streampipes.model.extensions.ExtensionItemDescription;
 import org.apache.streampipes.model.shared.annotation.TsModel;
+import org.apache.streampipes.model.shared.api.Storable;
 
 import com.google.gson.annotations.SerializedName;
 
 import java.util.Set;
 
 @TsModel
-public class SpServiceRegistration {
+public class SpServiceRegistration implements Storable {
 
   private String svcType;
   private String svcGroup;
@@ -130,6 +131,16 @@ public class SpServiceRegistration {
     this.rev = rev;
   }
 
+  @Override
+  public String getElementId() {
+    return this.svcId;
+  }
+
+  @Override
+  public void setElementId(String elementId) {
+    this.svcId = elementId;
+  }
+
   public String getScheme() {
     return scheme;
   }
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/file/FileMetadata.java b/streampipes-model/src/main/java/org/apache/streampipes/model/file/FileMetadata.java
index 4696179903..d7193d0608 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/file/FileMetadata.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/file/FileMetadata.java
@@ -18,11 +18,12 @@
 package org.apache.streampipes.model.file;
 
 import org.apache.streampipes.model.shared.annotation.TsModel;
+import org.apache.streampipes.model.shared.api.Storable;
 
 import com.google.gson.annotations.SerializedName;
 
 @TsModel
-public class FileMetadata {
+public class FileMetadata implements Storable {
 
   private @SerializedName("_id") String fileId;
 
@@ -52,6 +53,16 @@ public class FileMetadata {
     this.rev = rev;
   }
 
+  @Override
+  public String getElementId() {
+    return this.fileId;
+  }
+
+  @Override
+  public void setElementId(String elementId) {
+    this.fileId = elementId;
+  }
+
   public String getFilename() {
     return filename;
   }
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/template/PipelineElementTemplate.java b/streampipes-model/src/main/java/org/apache/streampipes/model/template/PipelineElementTemplate.java
index f7ce37808c..d304b0f31e 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/template/PipelineElementTemplate.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/template/PipelineElementTemplate.java
@@ -17,8 +17,8 @@
  */
 package org.apache.streampipes.model.template;
 
-import org.apache.streampipes.model.api.Storable;
 import org.apache.streampipes.model.shared.annotation.TsModel;
+import org.apache.streampipes.model.shared.api.Storable;
 
 import com.fasterxml.jackson.annotation.JsonAlias;
 import com.google.gson.annotations.SerializedName;
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/file/FileManager.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/file/FileManager.java
index 84bb7f47b7..a5a515669c 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/file/FileManager.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/file/FileManager.java
@@ -20,7 +20,7 @@ package org.apache.streampipes.manager.file;
 import org.apache.streampipes.commons.file.FileHasher;
 import org.apache.streampipes.model.file.FileMetadata;
 import org.apache.streampipes.sdk.helpers.Filetypes;
-import org.apache.streampipes.storage.api.IFileMetadataStorage;
+import org.apache.streampipes.storage.api.CRUDStorage;
 import org.apache.streampipes.storage.management.StorageDispatcher;
 
 import org.apache.commons.io.input.BOMInputStream;
@@ -34,11 +34,11 @@ import java.util.stream.Collectors;
 
 public class FileManager {
 
-  private final IFileMetadataStorage fileMetadataStorage;
+  private final CRUDStorage<FileMetadata> fileMetadataStorage;
   private final FileHandler fileHandler;
   private final FileHasher fileHasher;
 
-  public FileManager(IFileMetadataStorage fileMetadataStorage,
+  public FileManager(CRUDStorage<FileMetadata> fileMetadataStorage,
                      FileHandler fileHandler,
                      FileHasher fileHasher) {
     this.fileMetadataStorage = fileMetadataStorage;
@@ -60,7 +60,7 @@ public class FileManager {
   }
 
   public List<FileMetadata> getAllFiles(String filetypes) {
-    List<FileMetadata> allFiles = fileMetadataStorage.getAllFileMetadataDescriptions();
+    List<FileMetadata> allFiles = fileMetadataStorage.findAll();
     return filetypes != null ? filterFiletypes(allFiles, filetypes) : allFiles;
   }
 
@@ -94,10 +94,10 @@ public class FileManager {
 
 
   public void deleteFile(String id) {
-    var fileMetadata = fileMetadataStorage.getMetadataById(id);
+    var fileMetadata = fileMetadataStorage.getElementById(id);
     if (fileMetadata != null) {
       fileHandler.deleteFile(fileMetadata.getFilename());
-      fileMetadataStorage.deleteFileMetadata(id);
+      fileMetadataStorage.deleteElementById(id);
     }
   }
 
@@ -168,7 +168,7 @@ public class FileManager {
   }
 
   private void storeFileMetadata(FileMetadata fileMetadata) {
-    fileMetadataStorage.addFileMetadata(fileMetadata);
+    fileMetadataStorage.persist(fileMetadata);
   }
 
 
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/health/ServiceRegistrationManager.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/health/ServiceRegistrationManager.java
index e4654c3710..b12cefa6d0 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/health/ServiceRegistrationManager.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/health/ServiceRegistrationManager.java
@@ -31,9 +31,9 @@ public class ServiceRegistrationManager {
 
   private static final Logger LOG = LoggerFactory.getLogger(ServiceRegistrationManager.class);
 
-  private final CRUDStorage<String, SpServiceRegistration> storage;
+  private final CRUDStorage<SpServiceRegistration> storage;
 
-  public ServiceRegistrationManager(CRUDStorage<String, SpServiceRegistration> storage) {
+  public ServiceRegistrationManager(CRUDStorage<SpServiceRegistration> storage) {
     this.storage = storage;
   }
 
diff --git a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractDashboardResourceManager.java b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractDashboardResourceManager.java
index 67a0b479ee..3c1a125b7d 100644
--- a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractDashboardResourceManager.java
+++ b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractDashboardResourceManager.java
@@ -25,9 +25,9 @@ import org.apache.streampipes.storage.api.CRUDStorage;
 import java.util.List;
 
 public abstract class AbstractDashboardResourceManager
-    extends AbstractResourceManager<CRUDStorage<String, DashboardModel>> {
+    extends AbstractResourceManager<CRUDStorage<DashboardModel>> {
 
-  public AbstractDashboardResourceManager(CRUDStorage<String, DashboardModel> db) {
+  public AbstractDashboardResourceManager(CRUDStorage<DashboardModel> db) {
     super(db);
   }
 
diff --git a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractPipelineElementResourceManager.java b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractPipelineElementResourceManager.java
index a36c00e4ce..a241230237 100644
--- a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractPipelineElementResourceManager.java
+++ b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/AbstractPipelineElementResourceManager.java
@@ -26,7 +26,7 @@ import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
-public abstract class AbstractPipelineElementResourceManager<T extends CRUDStorage<String, W>,
+public abstract class AbstractPipelineElementResourceManager<T extends CRUDStorage<W>,
     W extends NamedStreamPipesEntity, X> extends AbstractResourceManager<T> {
 
   public AbstractPipelineElementResourceManager(T db) {
diff --git a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/UserResourceManager.java b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/UserResourceManager.java
index 9c9661247b..e9e1630be9 100644
--- a/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/UserResourceManager.java
+++ b/streampipes-resource-management/src/main/java/org/apache/streampipes/resource/management/UserResourceManager.java
@@ -30,8 +30,7 @@ import org.apache.streampipes.model.client.user.Role;
 import org.apache.streampipes.model.client.user.UserAccount;
 import org.apache.streampipes.model.client.user.UserActivationToken;
 import org.apache.streampipes.model.client.user.UserRegistrationData;
-import org.apache.streampipes.storage.api.IPasswordRecoveryTokenStorage;
-import org.apache.streampipes.storage.api.IUserActivationTokenStorage;
+import org.apache.streampipes.storage.api.CRUDStorage;
 import org.apache.streampipes.storage.api.IUserStorage;
 import org.apache.streampipes.storage.couchdb.CouchDbStorageManager;
 import org.apache.streampipes.storage.management.StorageDispatcher;
@@ -157,7 +156,7 @@ public class UserResourceManager extends AbstractResourceManager<IUserStorage> {
   }
 
   public void checkPasswordRecoveryCode(String recoveryCode) {
-    IPasswordRecoveryTokenStorage tokenStorage = getPasswordRecoveryTokenStorage();
+    var tokenStorage = getPasswordRecoveryTokenStorage();
     PasswordRecoveryToken token = tokenStorage.getElementById(recoveryCode);
     if (token == null) {
       throw new IllegalArgumentException("Invalid recovery code");
@@ -182,11 +181,11 @@ public class UserResourceManager extends AbstractResourceManager<IUserStorage> {
     getPasswordRecoveryTokenStorage().persist(PasswordRecoveryToken.create(recoveryCode, username));
   }
 
-  private IPasswordRecoveryTokenStorage getPasswordRecoveryTokenStorage() {
+  private CRUDStorage<PasswordRecoveryToken> getPasswordRecoveryTokenStorage() {
     return StorageDispatcher.INSTANCE.getNoSqlStore().getPasswordRecoveryTokenStorage();
   }
 
-  private IUserActivationTokenStorage getUserActivationTokenStorage() {
+  private CRUDStorage<UserActivationToken> getUserActivationTokenStorage() {
     return StorageDispatcher.INSTANCE.getNoSqlStore().getUserActivationTokenStorage();
   }
 
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AccountActivationResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AccountActivationResource.java
index ee54e7bcc6..d53a4d662d 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AccountActivationResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AccountActivationResource.java
@@ -35,7 +35,6 @@ public class AccountActivationResource extends AbstractAuthGuardedRestResource {
 
   @GetMapping(
       path = "{recoveryCode}",
-      consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE)
   public ResponseEntity<Void> activateUserAccount(@PathVariable("recoveryCode") String recoveryCode) {
     try {
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AssetDashboardResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AssetDashboardResource.java
index 4687f7c962..ed64308423 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AssetDashboardResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/AssetDashboardResource.java
@@ -21,7 +21,7 @@ import org.apache.streampipes.manager.file.FileManager;
 import org.apache.streampipes.model.client.assetdashboard.AssetDashboardConfig;
 import org.apache.streampipes.rest.core.base.impl.AbstractRestResource;
 import org.apache.streampipes.rest.shared.exception.SpMessageException;
-import org.apache.streampipes.storage.api.IAssetDashboardStorage;
+import org.apache.streampipes.storage.api.CRUDStorage;
 import org.apache.streampipes.storage.management.StorageDispatcher;
 
 import org.apache.commons.io.FileUtils;
@@ -63,7 +63,7 @@ public class AssetDashboardResource extends AbstractRestResource {
   @GetMapping(path = "/{dashboardId}", produces = MediaType.APPLICATION_JSON_VALUE)
   public ResponseEntity<AssetDashboardConfig> getAssetDashboard(@PathVariable("dashboardId") String dashboardId) {
     return ok(getNoSqlStorage().getAssetDashboardStorage()
-                               .getAssetDashboard(dashboardId));
+                               .getElementById(dashboardId));
   }
 
   @PutMapping(
@@ -74,17 +74,17 @@ public class AssetDashboardResource extends AbstractRestResource {
       @PathVariable("dashboardId") String dashboardId,
       @RequestBody AssetDashboardConfig dashboardConfig
   ) {
-    AssetDashboardConfig dashboard = getAssetDashboardStorage().getAssetDashboard(dashboardId);
+    AssetDashboardConfig dashboard = getAssetDashboardStorage().getElementById(dashboardId);
     dashboardConfig.setRev(dashboard.getRev());
     getNoSqlStorage().getAssetDashboardStorage()
-                     .updateAssetDashboard(dashboardConfig);
+                     .updateElement(dashboardConfig);
     return ok();
   }
 
   @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
   public ResponseEntity<List<AssetDashboardConfig>> getAllDashboards() {
     return ok(getNoSqlStorage().getAssetDashboardStorage()
-                               .getAllAssetDashboards());
+                               .findAll());
   }
 
   @PostMapping(
@@ -92,14 +92,14 @@ public class AssetDashboardResource extends AbstractRestResource {
       consumes = MediaType.APPLICATION_JSON_VALUE)
   public ResponseEntity<Void> storeAssetDashboard(@RequestBody AssetDashboardConfig dashboardConfig) {
     getNoSqlStorage().getAssetDashboardStorage()
-                     .storeAssetDashboard(dashboardConfig);
+                     .persist(dashboardConfig);
     return ok();
   }
 
   @DeleteMapping(path = "/{dashboardId}")
   public ResponseEntity<Void> deleteAssetDashboard(@PathVariable("dashboardId") String dashboardId) {
     getNoSqlStorage().getAssetDashboardStorage()
-                     .deleteAssetDashboard(dashboardId);
+                     .deleteElementById(dashboardId);
     return ok();
   }
 
@@ -169,7 +169,7 @@ public class AssetDashboardResource extends AbstractRestResource {
     return getTargetDirectory() + File.separator + filename;
   }
 
-  private IAssetDashboardStorage getAssetDashboardStorage() {
+  private CRUDStorage<AssetDashboardConfig> getAssetDashboardStorage() {
     return StorageDispatcher.INSTANCE.getNoSqlStore()
                                      .getAssetDashboardStorage();
   }
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/MigrationResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/MigrationResource.java
index aa3a509b80..a940e9d9b0 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/MigrationResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/MigrationResource.java
@@ -61,7 +61,7 @@ public class MigrationResource extends AbstractAuthGuardedRestResource {
 
   private static final Logger LOG = LoggerFactory.getLogger(MigrationResource.class);
 
-  private final CRUDStorage<String, SpServiceRegistration> extensionsServiceStorage =
+  private final CRUDStorage<SpServiceRegistration> extensionsServiceStorage =
       getNoSqlStorage().getExtensionsServiceStorage();
   private final IAdapterStorage adapterStorage = getNoSqlStorage().getAdapterInstanceStorage();
 
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ServiceConfigurationResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ServiceConfigurationResource.java
index 6a15de5476..378bc4e668 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ServiceConfigurationResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ServiceConfigurationResource.java
@@ -44,7 +44,7 @@ import java.util.List;
 @PreAuthorize(AuthConstants.IS_ADMIN_ROLE)
 public class ServiceConfigurationResource extends AbstractAuthGuardedRestResource {
 
-  private final CRUDStorage<String, SpServiceConfiguration> extensionsServicesConfigStorage =
+  private final CRUDStorage<SpServiceConfiguration> extensionsServicesConfigStorage =
       getNoSqlStorage().getExtensionsServiceConfigurationStorage();
 
 
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ServiceRegistrationResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ServiceRegistrationResource.java
index c8cd157aa2..7b73776682 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ServiceRegistrationResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/ServiceRegistrationResource.java
@@ -45,7 +45,7 @@ import java.util.List;
 @PreAuthorize(AuthConstants.IS_ADMIN_ROLE)
 public class ServiceRegistrationResource extends AbstractAuthGuardedRestResource {
 
-  private final CRUDStorage<String, SpServiceRegistration> extensionsServiceStorage =
+  private final CRUDStorage<SpServiceRegistration> extensionsServiceStorage =
       getNoSqlStorage().getExtensionsServiceStorage();
 
   @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/UserGroupResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/UserGroupResource.java
index b5f1ad0bc5..3ceab35c1e 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/UserGroupResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/admin/UserGroupResource.java
@@ -22,7 +22,7 @@ import org.apache.streampipes.model.message.Notifications;
 import org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource;
 import org.apache.streampipes.rest.security.AuthConstants;
 import org.apache.streampipes.rest.shared.exception.SpMessageException;
-import org.apache.streampipes.storage.api.IUserGroupStorage;
+import org.apache.streampipes.storage.api.CRUDStorage;
 
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
@@ -89,7 +89,7 @@ public class UserGroupResource extends AbstractAuthGuardedRestResource {
     }
   }
 
-  private IUserGroupStorage getUserGroupStorage() {
+  private CRUDStorage<Group> getUserGroupStorage() {
     return getNoSqlStorage().getUserGroupStorage();
   }
 }
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DashboardWidget.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DashboardWidget.java
index 78eed04375..91687ee4d5 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DashboardWidget.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/dashboard/DashboardWidget.java
@@ -77,7 +77,7 @@ public class DashboardWidget extends AbstractRestResource {
     return ok(getDashboardWidgetStorage().getElementById(elementId));
   }
 
-  private CRUDStorage<String, DashboardWidgetModel> getDashboardWidgetStorage() {
+  private CRUDStorage<DashboardWidgetModel> getDashboardWidgetStorage() {
     return getNoSqlStorage().getDashboardWidgetStorage();
   }
 }
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeWidgetResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeWidgetResource.java
index 9324ff117c..ced1771899 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeWidgetResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeWidgetResource.java
@@ -79,7 +79,7 @@ public class DataLakeWidgetResource extends AbstractRestResource {
     return ok(getDataExplorerWidgetStorage().getElementById(elementId));
   }
 
-  private CRUDStorage<String, DataExplorerWidgetModel> getDataExplorerWidgetStorage() {
+  private CRUDStorage<DataExplorerWidgetModel> getDataExplorerWidgetStorage() {
     return getNoSqlStorage().getDataExplorerWidgetStorage();
   }
 
diff --git a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/v095/MergeFilenamesAndRenameDuplicatesMigration.java b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/v095/MergeFilenamesAndRenameDuplicatesMigration.java
index 1330a109ce..d8d2eed10c 100644
--- a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/v095/MergeFilenamesAndRenameDuplicatesMigration.java
+++ b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/migrations/v095/MergeFilenamesAndRenameDuplicatesMigration.java
@@ -21,7 +21,7 @@ package org.apache.streampipes.service.core.migrations.v095;
 import org.apache.streampipes.manager.file.FileHandler;
 import org.apache.streampipes.model.file.FileMetadata;
 import org.apache.streampipes.service.core.migrations.Migration;
-import org.apache.streampipes.storage.api.IFileMetadataStorage;
+import org.apache.streampipes.storage.api.CRUDStorage;
 import org.apache.streampipes.storage.couchdb.utils.Utils;
 import org.apache.streampipes.storage.management.StorageDispatcher;
 
@@ -46,12 +46,12 @@ public class MergeFilenamesAndRenameDuplicatesMigration implements Migration {
 
   private CouchDbClient couchDbClient;
 
-  private ObjectMapper mapper = new ObjectMapper();
+  private final ObjectMapper mapper = new ObjectMapper();
 
-  private IFileMetadataStorage fileMetadataStorage =
+  private final CRUDStorage<FileMetadata> fileMetadataStorage =
       StorageDispatcher.INSTANCE.getNoSqlStore().getFileMetadataStorage();
 
-  private FileHandler fileHandler = new FileHandler();
+  private final FileHandler fileHandler = new FileHandler();
 
   Logger logger = LoggerFactory.getLogger(MergeFilenamesAndRenameDuplicatesMigration.class);
 
@@ -89,14 +89,14 @@ public class MergeFilenamesAndRenameDuplicatesMigration implements Migration {
    */
   protected void getFileMetadataToUpdate(List<Map<String, Object>> couchDbRawFileMetadata) {
     couchDbRawFileMetadata.forEach(
-        rawFileMetadata -> checkDuplicateOriginalFilename(rawFileMetadata));
+        this::checkDuplicateOriginalFilename);
   }
 
   /**
    * Fetches all fileIds stored in CouchDB
    */
-  private List<String> getAllFileIds(IFileMetadataStorage fileMetadataStorage) {
-    return fileMetadataStorage.getAllFileMetadataDescriptions().stream().map(fileMetadata -> fileMetadata.getFileId())
+  private List<String> getAllFileIds(CRUDStorage<FileMetadata> fileMetadataStorage) {
+    return fileMetadataStorage.findAll().stream().map(FileMetadata::getFileId)
         .toList();
   }
 
@@ -143,7 +143,7 @@ public class MergeFilenamesAndRenameDuplicatesMigration implements Migration {
         fileMetadata.setFileId(rawFileMetadata.get(ID).toString());
         fileMetadata.setFiletype(rawFileMetadata.get(FILETYPE).toString());
       } else {
-        fileMetadata = fileMetadataStorage.getMetadataById(rawFileMetadata.get(ID).toString());
+        fileMetadata = fileMetadataStorage.getElementById(rawFileMetadata.get(ID).toString());
       }
       fileMetadataGroupedByOriginalName.get(originalFilename).add(fileMetadata);
     }
@@ -177,7 +177,7 @@ public class MergeFilenamesAndRenameDuplicatesMigration implements Migration {
   private void updateFileMetadata(FileMetadata fileMetadata, String filename, boolean isTesting) {
     fileMetadata.setFilename(filename);
     if (!isTesting) {
-      fileMetadataStorage.updateFileMetadata(fileMetadata);
+      fileMetadataStorage.updateElement(fileMetadata);
     }
   }
 
diff --git a/streampipes-service-discovery/src/main/java/org/apache/streampipes/svcdiscovery/SpServiceDiscoveryCore.java b/streampipes-service-discovery/src/main/java/org/apache/streampipes/svcdiscovery/SpServiceDiscoveryCore.java
index c096267c5f..f0823b4830 100644
--- a/streampipes-service-discovery/src/main/java/org/apache/streampipes/svcdiscovery/SpServiceDiscoveryCore.java
+++ b/streampipes-service-discovery/src/main/java/org/apache/streampipes/svcdiscovery/SpServiceDiscoveryCore.java
@@ -40,7 +40,7 @@ public class SpServiceDiscoveryCore implements ISpServiceDiscovery {
   private static final Logger LOG = LoggerFactory.getLogger(SpServiceDiscoveryCore.class);
   private static final int MAX_RETRIES = 3;
 
-  private final CRUDStorage<String, SpServiceRegistration> serviceStorage;
+  private final CRUDStorage<SpServiceRegistration> serviceStorage;
 
   public SpServiceDiscoveryCore() {
     this.serviceStorage = StorageDispatcher.INSTANCE.getNoSqlStore().getExtensionsServiceStorage();
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java
index a5539aa1e4..32e57df0af 100644
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java
+++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/CRUDStorage.java
@@ -21,19 +21,19 @@ import org.apache.streampipes.model.Tuple2;
 
 import java.util.List;
 
-public interface CRUDStorage<K, V> {
+public interface CRUDStorage<T> {
 
-  List<V> findAll();
+  List<T> findAll();
 
-  Tuple2<Boolean, String> persist(V element);
+  Tuple2<Boolean, String> persist(T element);
 
-  V getElementById(K id);
+  T getElementById(String id);
 
-  V updateElement(V element);
+  T updateElement(T element);
 
-  void deleteElement(V element);
+  void deleteElement(T element);
 
-  default void deleteElementById(K id) {
+  default void deleteElementById(String id) {
     var element = getElementById(id);
     deleteElement(element);
   }
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IAdapterStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IAdapterStorage.java
index 651d7274ba..f2011bbc0c 100644
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IAdapterStorage.java
+++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IAdapterStorage.java
@@ -22,7 +22,7 @@ import org.apache.streampipes.model.connect.adapter.AdapterDescription;
 
 import java.util.List;
 
-public interface IAdapterStorage extends CRUDStorage<String, AdapterDescription>{
+public interface IAdapterStorage extends CRUDStorage<AdapterDescription>{
 
   List<AdapterDescription> getAllAdapters();
 
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IAssetDashboardStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IAssetDashboardStorage.java
deleted file mode 100644
index 69d66271f6..0000000000
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IAssetDashboardStorage.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.streampipes.storage.api;
-
-import org.apache.streampipes.model.client.assetdashboard.AssetDashboardConfig;
-
-import java.util.List;
-
-public interface IAssetDashboardStorage {
-
-  List<AssetDashboardConfig> getAllAssetDashboards();
-
-  AssetDashboardConfig getAssetDashboard(String dashboardId);
-
-  void storeAssetDashboard(AssetDashboardConfig assetDashboardConfig);
-
-  void updateAssetDashboard(AssetDashboardConfig assetDashboardConfig);
-
-  void deleteAssetDashboard(String dashboardId);
-}
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataProcessorStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataProcessorStorage.java
index c9f4d6630c..e0b055f978 100644
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataProcessorStorage.java
+++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataProcessorStorage.java
@@ -21,7 +21,7 @@ import org.apache.streampipes.model.graph.DataProcessorDescription;
 
 import java.util.List;
 
-public interface IDataProcessorStorage extends CRUDStorage<String, DataProcessorDescription> {
+public interface IDataProcessorStorage extends CRUDStorage<DataProcessorDescription> {
 
   DataProcessorDescription getFirstDataProcessorByAppId(String appId);
 
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataSinkStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataSinkStorage.java
index e740816d70..d82c02ba6c 100644
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataSinkStorage.java
+++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataSinkStorage.java
@@ -21,7 +21,7 @@ import org.apache.streampipes.model.graph.DataSinkDescription;
 
 import java.util.List;
 
-public interface IDataSinkStorage extends CRUDStorage<String, DataSinkDescription> {
+public interface IDataSinkStorage extends CRUDStorage<DataSinkDescription> {
 
   DataSinkDescription getFirstDataSinkByAppId(String appId);
 
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataStreamStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataStreamStorage.java
index 651584b24e..f08bc6233b 100644
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataStreamStorage.java
+++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IDataStreamStorage.java
@@ -19,7 +19,7 @@ package org.apache.streampipes.storage.api;
 
 import org.apache.streampipes.model.SpDataStream;
 
-public interface IDataStreamStorage extends CRUDStorage<String, SpDataStream> {
+public interface IDataStreamStorage extends CRUDStorage<SpDataStream> {
 
   SpDataStream getDataStreamByAppId(String appId);
 }
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java
index 3169a61c69..2b8c0203d7 100644
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java
+++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/INoSqlStorage.java
@@ -17,12 +17,17 @@
  */
 package org.apache.streampipes.storage.api;
 
+import org.apache.streampipes.model.client.assetdashboard.AssetDashboardConfig;
+import org.apache.streampipes.model.client.user.Group;
+import org.apache.streampipes.model.client.user.PasswordRecoveryToken;
+import org.apache.streampipes.model.client.user.UserActivationToken;
 import org.apache.streampipes.model.dashboard.DashboardModel;
 import org.apache.streampipes.model.dashboard.DashboardWidgetModel;
 import org.apache.streampipes.model.datalake.DataExplorerWidgetModel;
 import org.apache.streampipes.model.datalake.DataLakeMeasure;
 import org.apache.streampipes.model.extensions.configuration.SpServiceConfiguration;
 import org.apache.streampipes.model.extensions.svcdiscovery.SpServiceRegistration;
+import org.apache.streampipes.model.file.FileMetadata;
 
 public interface INoSqlStorage {
 
@@ -34,7 +39,7 @@ public interface INoSqlStorage {
 
   IImageStorage getImageStorage();
 
-  IUserGroupStorage getUserGroupStorage();
+  CRUDStorage<Group> getUserGroupStorage();
 
   IPipelineStorage getPipelineStorageAPI();
 
@@ -44,19 +49,19 @@ public interface INoSqlStorage {
 
   INotificationStorage getNotificationStorageApi();
 
-  IAssetDashboardStorage getAssetDashboardStorage();
+  CRUDStorage<AssetDashboardConfig> getAssetDashboardStorage();
 
-  CRUDStorage<String, DataLakeMeasure> getDataLakeStorage();
+  CRUDStorage<DataLakeMeasure> getDataLakeStorage();
 
-  IFileMetadataStorage getFileMetadataStorage();
+  CRUDStorage<FileMetadata> getFileMetadataStorage();
 
-  CRUDStorage<String, DashboardModel> getDashboardStorage();
+  CRUDStorage<DashboardModel> getDashboardStorage();
 
-  CRUDStorage<String, DashboardModel> getDataExplorerDashboardStorage();
+  CRUDStorage<DashboardModel> getDataExplorerDashboardStorage();
 
-  CRUDStorage<String, DashboardWidgetModel> getDashboardWidgetStorage();
+  CRUDStorage<DashboardWidgetModel> getDashboardWidgetStorage();
 
-  CRUDStorage<String, DataExplorerWidgetModel> getDataExplorerWidgetStorage();
+  CRUDStorage<DataExplorerWidgetModel> getDataExplorerWidgetStorage();
 
   IPipelineElementTemplateStorage getPipelineElementTemplateStorage();
 
@@ -72,13 +77,13 @@ public interface INoSqlStorage {
 
   IDataStreamStorage getDataStreamStorage();
 
-  IPasswordRecoveryTokenStorage getPasswordRecoveryTokenStorage();
+  CRUDStorage<PasswordRecoveryToken> getPasswordRecoveryTokenStorage();
 
-  IUserActivationTokenStorage getUserActivationTokenStorage();
+  CRUDStorage<UserActivationToken> getUserActivationTokenStorage();
 
-  CRUDStorage<String, SpServiceRegistration> getExtensionsServiceStorage();
+  CRUDStorage<SpServiceRegistration> getExtensionsServiceStorage();
 
-  CRUDStorage<String, SpServiceConfiguration> getExtensionsServiceConfigurationStorage();
+  CRUDStorage<SpServiceConfiguration> getExtensionsServiceConfigurationStorage();
 
   ISpCoreConfigurationStorage getSpCoreConfigurationStorage();
 }
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPasswordRecoveryTokenStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPasswordRecoveryTokenStorage.java
deleted file mode 100644
index 43259e5edf..0000000000
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPasswordRecoveryTokenStorage.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.streampipes.storage.api;
-
-import org.apache.streampipes.model.client.user.PasswordRecoveryToken;
-
-public interface IPasswordRecoveryTokenStorage extends CRUDStorage<String, PasswordRecoveryToken> {
-
-
-}
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPipelineCanvasMetadataStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPipelineCanvasMetadataStorage.java
index fa7c64736a..57701ac23e 100644
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPipelineCanvasMetadataStorage.java
+++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPipelineCanvasMetadataStorage.java
@@ -19,7 +19,7 @@ package org.apache.streampipes.storage.api;
 
 import org.apache.streampipes.model.canvas.PipelineCanvasMetadata;
 
-public interface IPipelineCanvasMetadataStorage extends CRUDStorage<String, PipelineCanvasMetadata> {
+public interface IPipelineCanvasMetadataStorage extends CRUDStorage<PipelineCanvasMetadata> {
 
   PipelineCanvasMetadata getPipelineCanvasMetadataForPipeline(String pipelineId);
 }
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IUserActivationTokenStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IUserActivationTokenStorage.java
deleted file mode 100644
index a2311dc485..0000000000
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IUserActivationTokenStorage.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.streampipes.storage.api;
-
-import org.apache.streampipes.model.client.user.UserActivationToken;
-
-public interface IUserActivationTokenStorage extends CRUDStorage<String, UserActivationToken> {
-}
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IUserGroupStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IUserGroupStorage.java
deleted file mode 100644
index accd125c4f..0000000000
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IUserGroupStorage.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.streampipes.storage.api;
-
-import org.apache.streampipes.model.client.user.Group;
-
-public interface IUserGroupStorage extends CRUDStorage<String, Group> {
-}
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java
index dca2e03294..64e873a8aa 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/CouchDbStorageManager.java
@@ -17,24 +17,26 @@
  */
 package org.apache.streampipes.storage.couchdb;
 
+import org.apache.streampipes.model.client.assetdashboard.AssetDashboardConfig;
+import org.apache.streampipes.model.client.user.Group;
+import org.apache.streampipes.model.client.user.PasswordRecoveryToken;
+import org.apache.streampipes.model.client.user.UserActivationToken;
 import org.apache.streampipes.model.dashboard.DashboardModel;
 import org.apache.streampipes.model.dashboard.DashboardWidgetModel;
 import org.apache.streampipes.model.datalake.DataExplorerWidgetModel;
 import org.apache.streampipes.model.datalake.DataLakeMeasure;
 import org.apache.streampipes.model.extensions.configuration.SpServiceConfiguration;
 import org.apache.streampipes.model.extensions.svcdiscovery.SpServiceRegistration;
+import org.apache.streampipes.model.file.FileMetadata;
 import org.apache.streampipes.storage.api.CRUDStorage;
 import org.apache.streampipes.storage.api.IAdapterStorage;
-import org.apache.streampipes.storage.api.IAssetDashboardStorage;
 import org.apache.streampipes.storage.api.IDataProcessorStorage;
 import org.apache.streampipes.storage.api.IDataSinkStorage;
 import org.apache.streampipes.storage.api.IDataStreamStorage;
-import org.apache.streampipes.storage.api.IFileMetadataStorage;
 import org.apache.streampipes.storage.api.IGenericStorage;
 import org.apache.streampipes.storage.api.IImageStorage;
 import org.apache.streampipes.storage.api.INoSqlStorage;
 import org.apache.streampipes.storage.api.INotificationStorage;
-import org.apache.streampipes.storage.api.IPasswordRecoveryTokenStorage;
 import org.apache.streampipes.storage.api.IPermissionStorage;
 import org.apache.streampipes.storage.api.IPipelineCanvasMetadataStorage;
 import org.apache.streampipes.storage.api.IPipelineElementConnectionStorage;
@@ -42,32 +44,24 @@ import org.apache.streampipes.storage.api.IPipelineElementDescriptionStorage;
 import org.apache.streampipes.storage.api.IPipelineElementTemplateStorage;
 import org.apache.streampipes.storage.api.IPipelineStorage;
 import org.apache.streampipes.storage.api.ISpCoreConfigurationStorage;
-import org.apache.streampipes.storage.api.IUserActivationTokenStorage;
-import org.apache.streampipes.storage.api.IUserGroupStorage;
 import org.apache.streampipes.storage.api.IUserStorage;
 import org.apache.streampipes.storage.couchdb.impl.AdapterDescriptionStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.AdapterInstanceStorageImpl;
-import org.apache.streampipes.storage.couchdb.impl.AssetDashboardStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.ConnectionStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.CoreConfigurationStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.DataProcessorStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.DataSinkStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.DataStreamStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.DefaultCrudStorage;
-import org.apache.streampipes.storage.couchdb.impl.ExtensionsServiceConfigStorageImpl;
-import org.apache.streampipes.storage.couchdb.impl.ExtensionsServiceStorageImpl;
-import org.apache.streampipes.storage.couchdb.impl.FileMetadataStorageImpl;
+import org.apache.streampipes.storage.couchdb.impl.DefaultViewCrudStorage;
 import org.apache.streampipes.storage.couchdb.impl.GenericStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.ImageStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.NotificationStorageImpl;
-import org.apache.streampipes.storage.couchdb.impl.PasswordRecoveryTokenImpl;
 import org.apache.streampipes.storage.couchdb.impl.PermissionStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.PipelineCanvasMetadataStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.PipelineElementDescriptionStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.PipelineElementTemplateStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.PipelineStorageImpl;
-import org.apache.streampipes.storage.couchdb.impl.UserActivationTokenImpl;
-import org.apache.streampipes.storage.couchdb.impl.UserGroupStorageImpl;
 import org.apache.streampipes.storage.couchdb.impl.UserStorage;
 import org.apache.streampipes.storage.couchdb.utils.Utils;
 
@@ -96,8 +90,12 @@ public enum CouchDbStorageManager implements INoSqlStorage {
   }
 
   @Override
-  public IUserGroupStorage getUserGroupStorage() {
-    return new UserGroupStorageImpl();
+  public CRUDStorage<Group> getUserGroupStorage() {
+    return new DefaultViewCrudStorage<>(
+        Utils::getCouchDbUserClient,
+        Group.class,
+        "users/groups"
+    );
   }
 
   @Override
@@ -121,12 +119,15 @@ public enum CouchDbStorageManager implements INoSqlStorage {
   }
 
   @Override
-  public IAssetDashboardStorage getAssetDashboardStorage() {
-    return new AssetDashboardStorageImpl();
+  public CRUDStorage<AssetDashboardConfig> getAssetDashboardStorage() {
+    return new DefaultCrudStorage<>(
+        () -> Utils.getCouchDbGsonClient("assetdashboard"),
+        AssetDashboardConfig.class
+    );
   }
 
   @Override
-  public CRUDStorage<String, DataLakeMeasure> getDataLakeStorage() {
+  public CRUDStorage<DataLakeMeasure> getDataLakeStorage() {
     return new DefaultCrudStorage<>(
         () -> Utils.getCouchDbGsonClient("data-lake"),
         DataLakeMeasure.class
@@ -134,12 +135,15 @@ public enum CouchDbStorageManager implements INoSqlStorage {
   }
 
   @Override
-  public IFileMetadataStorage getFileMetadataStorage() {
-    return new FileMetadataStorageImpl();
+  public CRUDStorage<FileMetadata> getFileMetadataStorage() {
+    return new DefaultCrudStorage<>(
+        () -> Utils.getCouchDbGsonClient("filemetadata"),
+        FileMetadata.class
+    );
   }
 
   @Override
-  public CRUDStorage<String, DashboardModel> getDashboardStorage() {
+  public CRUDStorage<DashboardModel> getDashboardStorage() {
     return new DefaultCrudStorage<>(
         () -> Utils.getCouchDbGsonClient("dashboard"),
         DashboardModel.class
@@ -147,7 +151,7 @@ public enum CouchDbStorageManager implements INoSqlStorage {
   }
 
   @Override
-  public CRUDStorage<String, DashboardModel> getDataExplorerDashboardStorage() {
+  public CRUDStorage<DashboardModel> getDataExplorerDashboardStorage() {
     return new DefaultCrudStorage<>(
         () -> Utils.getCouchDbGsonClient("dataexplorerdashboard"),
         DashboardModel.class
@@ -155,7 +159,7 @@ public enum CouchDbStorageManager implements INoSqlStorage {
   }
 
   @Override
-  public CRUDStorage<String, DashboardWidgetModel> getDashboardWidgetStorage() {
+  public CRUDStorage<DashboardWidgetModel> getDashboardWidgetStorage() {
     return new DefaultCrudStorage<>(
         () -> Utils.getCouchDbGsonClient("dashboardwidget"),
         DashboardWidgetModel.class
@@ -163,7 +167,7 @@ public enum CouchDbStorageManager implements INoSqlStorage {
   }
 
   @Override
-  public CRUDStorage<String, DataExplorerWidgetModel> getDataExplorerWidgetStorage() {
+  public CRUDStorage<DataExplorerWidgetModel> getDataExplorerWidgetStorage() {
     return new DefaultCrudStorage<>(
         () -> Utils.getCouchDbGsonClient("dataexplorerwidget"),
         DataExplorerWidgetModel.class
@@ -206,29 +210,41 @@ public enum CouchDbStorageManager implements INoSqlStorage {
   }
 
   @Override
-  public IPasswordRecoveryTokenStorage getPasswordRecoveryTokenStorage() {
-    return new PasswordRecoveryTokenImpl();
+  public CRUDStorage<PasswordRecoveryToken> getPasswordRecoveryTokenStorage() {
+    return new DefaultViewCrudStorage<>(
+        Utils::getCouchDbUserClient,
+        PasswordRecoveryToken.class,
+        "users/password-recovery"
+    );
   }
 
   @Override
-  public IUserActivationTokenStorage getUserActivationTokenStorage() {
-    return new UserActivationTokenImpl();
+  public CRUDStorage<UserActivationToken> getUserActivationTokenStorage() {
+    return new DefaultViewCrudStorage<>(
+        Utils::getCouchDbUserClient,
+        UserActivationToken.class,
+        "users/user-activation"
+    );
   }
 
   @Override
-  public CRUDStorage<String, SpServiceRegistration> getExtensionsServiceStorage() {
-    return new ExtensionsServiceStorageImpl();
+  public CRUDStorage<SpServiceRegistration> getExtensionsServiceStorage() {
+    return new DefaultCrudStorage<>(
+        () -> Utils.getCouchDbGsonClient("extensions-services"),
+        SpServiceRegistration.class
+    );
   }
 
   @Override
-  public CRUDStorage<String, SpServiceConfiguration> getExtensionsServiceConfigurationStorage() {
-    return new ExtensionsServiceConfigStorageImpl();
+  public CRUDStorage<SpServiceConfiguration> getExtensionsServiceConfigurationStorage() {
+    return new DefaultCrudStorage<>(
+        () -> Utils.getCouchDbGsonClient("extensions-services-configurations"),
+        SpServiceConfiguration.class
+    );
   }
 
   @Override
   public ISpCoreConfigurationStorage getSpCoreConfigurationStorage() {
     return new CoreConfigurationStorageImpl();
   }
-
-
 }
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AssetDashboardStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AssetDashboardStorageImpl.java
deleted file mode 100644
index 665259c0bf..0000000000
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/AssetDashboardStorageImpl.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.streampipes.storage.couchdb.impl;
-
-import org.apache.streampipes.model.client.assetdashboard.AssetDashboardConfig;
-import org.apache.streampipes.storage.api.IAssetDashboardStorage;
-import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
-import org.apache.streampipes.storage.couchdb.utils.Utils;
-
-import java.util.List;
-
-public class AssetDashboardStorageImpl extends AbstractDao<AssetDashboardConfig> implements IAssetDashboardStorage {
-
-  public AssetDashboardStorageImpl() {
-    super(Utils::getCouchDbAssetDashboardClient, AssetDashboardConfig.class);
-  }
-
-  @Override
-  public List<AssetDashboardConfig> getAllAssetDashboards() {
-    return findAll();
-  }
-
-  @Override
-  public AssetDashboardConfig getAssetDashboard(String dashboardId) {
-    return findWithNullIfEmpty(dashboardId);
-  }
-
-  @Override
-  public void storeAssetDashboard(AssetDashboardConfig assetDashboardConfig) {
-    persist(assetDashboardConfig);
-  }
-
-  @Override
-  public void updateAssetDashboard(AssetDashboardConfig assetDashboardConfig) {
-    update(assetDashboardConfig);
-  }
-
-  @Override
-  public void deleteAssetDashboard(String dashboardId) {
-    delete(dashboardId);
-  }
-}
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DefaultCrudStorage.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DefaultCrudStorage.java
index 88e9f275a6..84c6b80dc8 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DefaultCrudStorage.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DefaultCrudStorage.java
@@ -18,7 +18,7 @@
 
 package org.apache.streampipes.storage.couchdb.impl;
 
-import org.apache.streampipes.model.api.Storable;
+import org.apache.streampipes.model.shared.api.Storable;
 import org.apache.streampipes.storage.api.CRUDStorage;
 import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
 
@@ -26,7 +26,7 @@ import org.lightcouch.CouchDbClient;
 
 import java.util.function.Supplier;
 
-public class DefaultCrudStorage<T extends Storable> extends AbstractDao<T> implements CRUDStorage<String, T> {
+public class DefaultCrudStorage<T extends Storable> extends AbstractDao<T> implements CRUDStorage<T> {
 
   public DefaultCrudStorage(Supplier<CouchDbClient> couchDbClientSupplier,
                             Class<T> clazz) {
@@ -35,7 +35,7 @@ public class DefaultCrudStorage<T extends Storable> extends AbstractDao<T> imple
 
   @Override
   public T getElementById(String id) {
-    return find(id).orElseThrow(IllegalArgumentException::new);
+    return findWithNullIfEmpty(id);
   }
 
   @Override
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IFileMetadataStorage.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DefaultViewCrudStorage.java
similarity index 56%
rename from streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IFileMetadataStorage.java
rename to streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DefaultViewCrudStorage.java
index 13eae66ed7..a28c70147f 100644
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IFileMetadataStorage.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/DefaultViewCrudStorage.java
@@ -15,23 +15,30 @@
  * limitations under the License.
  *
  */
-package org.apache.streampipes.storage.api;
 
-import org.apache.streampipes.model.file.FileMetadata;
+package org.apache.streampipes.storage.couchdb.impl;
 
-import java.util.List;
+import org.apache.streampipes.model.shared.api.Storable;
 
-public interface IFileMetadataStorage {
+import org.lightcouch.CouchDbClient;
 
-  FileMetadata getMetadataById(String id);
+import java.util.List;
+import java.util.function.Supplier;
 
-  List<FileMetadata> getAllFileMetadataDescriptions();
+public class DefaultViewCrudStorage<T extends Storable> extends DefaultCrudStorage<T> {
 
-  List<FileMetadata> getFilteredFileMetadataDescriptions(String filetype);
+  private final String viewName;
 
-  void deleteFileMetadata(String id);
+  public DefaultViewCrudStorage(Supplier<CouchDbClient> couchDbClientSupplier,
+                                Class<T> clazz,
+                                String viewName) {
+    super(couchDbClientSupplier, clazz);
+    this.viewName = viewName;
+  }
 
-  void addFileMetadata(FileMetadata fileMetadata);
+  @Override
+  public List<T> findAll() {
+    return findAll(viewName, clazz);
+  }
 
-  void updateFileMetadata(FileMetadata fileMetadata);
 }
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/ExtensionsServiceConfigStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/ExtensionsServiceConfigStorageImpl.java
deleted file mode 100644
index 554632ca80..0000000000
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/ExtensionsServiceConfigStorageImpl.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.streampipes.storage.couchdb.impl;
-
-import org.apache.streampipes.model.extensions.configuration.SpServiceConfiguration;
-import org.apache.streampipes.storage.api.CRUDStorage;
-import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
-import org.apache.streampipes.storage.couchdb.utils.Utils;
-
-public class ExtensionsServiceConfigStorageImpl extends AbstractDao<SpServiceConfiguration>
-    implements CRUDStorage<String, SpServiceConfiguration> {
-
-  public ExtensionsServiceConfigStorageImpl() {
-    super(Utils::getCouchDbServiceConfigStorage, SpServiceConfiguration.class);
-  }
-
-  @Override
-  public SpServiceConfiguration getElementById(String id) {
-    return findWithNullIfEmpty(id);
-  }
-
-  @Override
-  public SpServiceConfiguration updateElement(SpServiceConfiguration element) {
-    update(element);
-    return getElementById(element.getServiceName());
-  }
-
-  @Override
-  public void deleteElement(SpServiceConfiguration element) {
-    delete(element.getServiceName());
-  }
-}
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/ExtensionsServiceStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/ExtensionsServiceStorageImpl.java
deleted file mode 100644
index 230c7a3393..0000000000
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/ExtensionsServiceStorageImpl.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.streampipes.storage.couchdb.impl;
-
-import org.apache.streampipes.model.extensions.svcdiscovery.SpServiceRegistration;
-import org.apache.streampipes.storage.api.CRUDStorage;
-import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
-import org.apache.streampipes.storage.couchdb.utils.Utils;
-
-public class ExtensionsServiceStorageImpl extends AbstractDao<SpServiceRegistration>
-    implements CRUDStorage<String, SpServiceRegistration> {
-
-  public ExtensionsServiceStorageImpl() {
-    super(Utils::getCouchDbExtensionsStorage, SpServiceRegistration.class);
-  }
-
-  @Override
-  public SpServiceRegistration getElementById(String id) {
-    return findWithNullIfEmpty(id);
-  }
-
-  @Override
-  public SpServiceRegistration updateElement(SpServiceRegistration element) {
-    update(element);
-    return getElementById(element.getSvcId());
-  }
-
-  @Override
-  public void deleteElement(SpServiceRegistration element) {
-    delete(element.getSvcId());
-  }
-}
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/FileMetadataStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/FileMetadataStorageImpl.java
deleted file mode 100644
index 2f65f09912..0000000000
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/FileMetadataStorageImpl.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.streampipes.storage.couchdb.impl;
-
-import org.apache.streampipes.model.file.FileMetadata;
-import org.apache.streampipes.storage.api.IFileMetadataStorage;
-import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
-import org.apache.streampipes.storage.couchdb.utils.Utils;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-public class FileMetadataStorageImpl extends AbstractDao<FileMetadata> implements
-    IFileMetadataStorage {
-
-  public FileMetadataStorageImpl() {
-    super(Utils::getCouchDbFileMetadataClient, FileMetadata.class);
-  }
-
-  @Override
-  public FileMetadata getMetadataById(String id) {
-    return findWithNullIfEmpty(id);
-  }
-
-  @Override
-  public List<FileMetadata> getAllFileMetadataDescriptions() {
-    return findAll();
-  }
-
-  @Override
-  public List<FileMetadata> getFilteredFileMetadataDescriptions(String filetype) {
-    List<FileMetadata> allFiles = getAllFileMetadataDescriptions();
-    return allFiles
-        .stream()
-        .filter(f -> f.getFiletype().equals(filetype))
-        .collect(Collectors.toList());
-  }
-
-  @Override
-  public void deleteFileMetadata(String id) {
-    delete(id);
-  }
-
-  @Override
-  public void addFileMetadata(FileMetadata fileMetadata) {
-    persist(fileMetadata);
-  }
-
-  @Override
-  public void updateFileMetadata(FileMetadata fileMetadata) {
-    update(fileMetadata);
-  }
-}
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PasswordRecoveryTokenImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PasswordRecoveryTokenImpl.java
deleted file mode 100644
index 4a8b687658..0000000000
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PasswordRecoveryTokenImpl.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.streampipes.storage.couchdb.impl;
-
-import org.apache.streampipes.model.client.user.PasswordRecoveryToken;
-import org.apache.streampipes.storage.api.IPasswordRecoveryTokenStorage;
-import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
-import org.apache.streampipes.storage.couchdb.utils.Utils;
-
-import java.util.List;
-
-public class PasswordRecoveryTokenImpl extends AbstractDao<PasswordRecoveryToken>
-    implements IPasswordRecoveryTokenStorage {
-
-  private static final String viewName = "users/password-recovery";
-
-  public PasswordRecoveryTokenImpl() {
-    super(Utils::getCouchDbUserClient, PasswordRecoveryToken.class);
-  }
-
-
-  @Override
-  public List<PasswordRecoveryToken> findAll() {
-    return findAll(viewName, PasswordRecoveryToken.class);
-  }
-
-  @Override
-  public PasswordRecoveryToken getElementById(String s) {
-    return findWithNullIfEmpty(s, PasswordRecoveryToken.class);
-  }
-
-  @Override
-  public PasswordRecoveryToken updateElement(PasswordRecoveryToken element) {
-    update(element, PasswordRecoveryToken.class);
-    return getElementById(element.getToken());
-  }
-
-  @Override
-  public void deleteElement(PasswordRecoveryToken element) {
-    delete(element.getToken(), PasswordRecoveryToken.class);
-  }
-}
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserActivationTokenImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserActivationTokenImpl.java
deleted file mode 100644
index 79d5f93509..0000000000
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserActivationTokenImpl.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.streampipes.storage.couchdb.impl;
-
-import org.apache.streampipes.model.client.user.UserActivationToken;
-import org.apache.streampipes.storage.api.IUserActivationTokenStorage;
-import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
-import org.apache.streampipes.storage.couchdb.utils.Utils;
-
-import java.util.List;
-
-public class UserActivationTokenImpl extends AbstractDao<UserActivationToken> implements IUserActivationTokenStorage {
-
-  private static final String viewName = "users/user-activation";
-
-  public UserActivationTokenImpl() {
-    super(Utils::getCouchDbUserClient, UserActivationToken.class);
-  }
-
-  @Override
-  public List<UserActivationToken> findAll() {
-    return findAll(viewName, UserActivationToken.class);
-  }
-
-  @Override
-  public UserActivationToken getElementById(String s) {
-    return findWithNullIfEmpty(s, UserActivationToken.class);
-  }
-
-  @Override
-  public UserActivationToken updateElement(UserActivationToken element) {
-    update(element, UserActivationToken.class);
-    return getElementById(element.getToken());
-  }
-
-  @Override
-  public void deleteElement(UserActivationToken element) {
-    delete(element.getToken(), UserActivationToken.class);
-  }
-}
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserGroupStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserGroupStorageImpl.java
deleted file mode 100644
index e657e960a2..0000000000
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/UserGroupStorageImpl.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.streampipes.storage.couchdb.impl;
-
-import org.apache.streampipes.model.client.user.Group;
-import org.apache.streampipes.storage.api.IUserGroupStorage;
-import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
-import org.apache.streampipes.storage.couchdb.utils.Utils;
-
-import java.util.List;
-
-public class UserGroupStorageImpl extends AbstractDao<Group> implements IUserGroupStorage {
-
-  private static final String viewName = "users/groups";
-
-  public UserGroupStorageImpl() {
-    super(Utils::getCouchDbUserClient, Group.class);
-  }
-
-  @Override
-  public List<Group> findAll() {
-    return findAll(viewName, Group.class);
-  }
-
-  @Override
-  public Group getElementById(String s) {
-    return findWithNullIfEmpty(s, Group.class);
-  }
-
-  @Override
-  public Group updateElement(Group element) {
-    update(element, Group.class);
-    return getElementById(element.getGroupId());
-  }
-
-  @Override
-  public void deleteElement(Group element) {
-    delete(element.getGroupId(), Group.class);
-  }
-}
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java
index 7f9cfd15ff..a9e1be34f9 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/utils/Utils.java
@@ -66,10 +66,6 @@ public class Utils {
     return getCouchDbGsonClient("general-configuration");
   }
 
-  public static CouchDbClient getCouchDbServiceConfigStorage() {
-    return getCouchDbGsonClient("extensions-services-configurations");
-  }
-
   public static CouchDbClient getCouchDbExtensionsStorage() {
     return getCouchDbGsonClient("extensions-services");
   }
@@ -82,10 +78,6 @@ public class Utils {
     return getCouchDbGsonClient("filemetadata");
   }
 
-  public static CouchDbClient getCouchDbAssetDashboardClient() {
-    return getCouchDbGsonClient("assetdashboard");
-  }
-
   public static CouchDbClient getCouchDbAdapterInstanceClient() {
     return getCouchDbAdapterClient("adapterinstance");
   }


Test patch:
diff --git a/streampipes-data-explorer/src/test/java/org/apache/streampipes/dataexplorer/DataExplorerSchemaManagementTest.java b/streampipes-data-explorer/src/test/java/org/apache/streampipes/dataexplorer/DataExplorerSchemaManagementTest.java
index 6c76d31c40..4dc34531ce 100644
--- a/streampipes-data-explorer/src/test/java/org/apache/streampipes/dataexplorer/DataExplorerSchemaManagementTest.java
+++ b/streampipes-data-explorer/src/test/java/org/apache/streampipes/dataexplorer/DataExplorerSchemaManagementTest.java
@@ -46,7 +46,7 @@ public class DataExplorerSchemaManagementTest {
   public static final String NEW_PROPERTY = "newProperty";
   public static final String OLD_PROPERTY = "oldProperty";
 
-  private CRUDStorage<String, DataLakeMeasure> dataLakeStorageMock;
+  private CRUDStorage<DataLakeMeasure> dataLakeStorageMock;
 
   @BeforeEach
   public void setUp() {
diff --git a/streampipes-pipeline-management/src/test/java/org/apache/streampipes/manager/file/TestFileManager.java b/streampipes-pipeline-management/src/test/java/org/apache/streampipes/manager/file/TestFileManager.java
index da62437bc6..ec2e840da0 100644
--- a/streampipes-pipeline-management/src/test/java/org/apache/streampipes/manager/file/TestFileManager.java
+++ b/streampipes-pipeline-management/src/test/java/org/apache/streampipes/manager/file/TestFileManager.java
@@ -19,7 +19,7 @@ package org.apache.streampipes.manager.file;
 
 import org.apache.streampipes.commons.file.FileHasher;
 import org.apache.streampipes.model.file.FileMetadata;
-import org.apache.streampipes.storage.api.IFileMetadataStorage;
+import org.apache.streampipes.storage.api.CRUDStorage;
 
 import org.apache.commons.io.IOUtils;
 import org.junit.jupiter.api.BeforeEach;
@@ -50,7 +50,7 @@ import static org.mockito.Mockito.when;
 public class TestFileManager {
 
   private FileManager fileManager;
-  private IFileMetadataStorage fileMetadataStorage;
+  private CRUDStorage<FileMetadata> fileMetadataStorage;
   private FileHandler fileHandler;
   private FileHasher fileHasher;
 
@@ -59,7 +59,7 @@ public class TestFileManager {
 
   @BeforeEach
   public void setup() {
-    fileMetadataStorage = mock(IFileMetadataStorage.class);
+    fileMetadataStorage = mock(CRUDStorage.class);
     fileHandler = mock(FileHandler.class);
     fileHasher = mock(FileHasher.class);
     fileManager = new FileManager(fileMetadataStorage, fileHandler, fileHasher);
@@ -104,7 +104,7 @@ public class TestFileManager {
 
   private List<FileMetadata> prepareFileMetadataStorageWithTwoSampleFiles() {
     List<FileMetadata> allFiles = Arrays.asList(createFileMetadata("csv"), createFileMetadata("json"));
-    when(fileMetadataStorage.getAllFileMetadataDescriptions()).thenReturn(allFiles);
+    when(fileMetadataStorage.findAll()).thenReturn(allFiles);
 
     return allFiles;
   }
@@ -152,7 +152,7 @@ public class TestFileManager {
     assertEquals(filename, fileMetadata.getFilename());
     assertEquals("csv", fileMetadata.getFiletype());
     verify(fileHandler, times(1)).storeFile(eq(filename), any(InputStream.class));
-    verify(fileMetadataStorage, times(1)).addFileMetadata(any(FileMetadata.class));
+    verify(fileMetadataStorage, times(1)).persist(any(FileMetadata.class));
   }
 
   @Test
@@ -164,7 +164,7 @@ public class TestFileManager {
 
     assertEquals(expectedSanitizedFilename, fileMetadata.getFilename());
     verify(fileHandler, times(1)).storeFile(eq(expectedSanitizedFilename), any(InputStream.class));
-    verify(fileMetadataStorage, times(1)).addFileMetadata(any(FileMetadata.class));
+    verify(fileMetadataStorage, times(1)).persist(any(FileMetadata.class));
   }
 
   /**
@@ -197,24 +197,24 @@ public class TestFileManager {
     var fileMetadata = new FileMetadata();
     fileMetadata.setFilename("existingFile.txt");
 
-    when(fileMetadataStorage.getMetadataById(id)).thenReturn(fileMetadata);
+    when(fileMetadataStorage.getElementById(id)).thenReturn(fileMetadata);
 
     fileManager.deleteFile(id);
 
     verify(fileHandler, times(1)).deleteFile(fileMetadata.getFilename());
-    verify(fileMetadataStorage, times(1)).deleteFileMetadata(id);
+    verify(fileMetadataStorage, times(1)).deleteElementById(id);
   }
 
   @Test
   public void deleteFile_doesNothingForNonExistingFile() {
     var id = "nonExistingFileId";
 
-    when(fileMetadataStorage.getMetadataById(id)).thenReturn(null);
+    when(fileMetadataStorage.getElementById(id)).thenReturn(null);
 
     fileManager.deleteFile(id);
 
     verify(fileHandler, times(0)).deleteFile(anyString());
-    verify(fileMetadataStorage, times(0)).deleteFileMetadata(id);
+    verify(fileMetadataStorage, times(0)).deleteElementById(id);
   }
 
   @Test
@@ -335,4 +335,4 @@ public class TestFileManager {
     assertFalse(result);
   }
 
-}
\ No newline at end of file
+}
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPipelineElementTemplateStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPipelineElementTemplateStorage.java
index 7f3a326557..e8d8fe6684 100644
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPipelineElementTemplateStorage.java
+++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPipelineElementTemplateStorage.java
@@ -21,7 +21,7 @@ import org.apache.streampipes.model.template.PipelineElementTemplate;
 
 import java.util.List;
 
-public interface IPipelineElementTemplateStorage extends CRUDStorage<String, PipelineElementTemplate> {
+public interface IPipelineElementTemplateStorage extends CRUDStorage<PipelineElementTemplate> {
 
   List<PipelineElementTemplate> getPipelineElementTemplatesforAppId(String appId);
 }