From 58fc9cb9b1395836f29da3bb3194a0b36b459ce1 Mon Sep 17 00:00:00 2001 From: Aleksandr Skoblikov Date: Mon, 23 Sep 2024 16:29:25 +0400 Subject: [PATCH 1/4] CB-5390 wip --- .gitignore | 3 + .../BaseServerConfigurationController.java | 59 +++++++++++++++++++ .../model/app/BaseWebApplication.java | 6 ++ .../model/app/WebServerConfiguration.java | 7 +++ .../app/WebServerConfigurationController.java | 3 + .../cloudbeaver/server/BaseGQLPlatform.java | 3 +- .../server/WebGlobalWorkspace.java | 19 +++--- .../io/cloudbeaver/server/CBApplication.java | 5 -- .../CBServerConfigurationController.java | 52 ++++++++-------- ...ServerConfigurationControllerEmbedded.java | 2 - 10 files changed, 116 insertions(+), 43 deletions(-) diff --git a/.gitignore b/.gitignore index 8906c71da1..93b1d9e73b 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,9 @@ server/test/io.cloudbeaver.test.platform/workspace/.data/ .classpath .settings/ +## Eclipse PDE +*.product.launch + workspace-dev-ce/ deploy/cloudbeaver server/**/target diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java index 516ef29e2a..7b4bc227f2 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java @@ -19,12 +19,29 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import org.jkiss.code.NotNull; +import org.jkiss.dbeaver.DBException; +import org.jkiss.dbeaver.Log; +import org.jkiss.dbeaver.registry.fs.FileSystemProviderRegistry; + +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; /** * Abstract class that contains methods for loading configuration with gson. */ public abstract class BaseServerConfigurationController implements WebServerConfigurationController { + private static final Log log = Log.getLog(BaseServerConfigurationController.class); + @NotNull + private final Path homeDirectory; + + private Path workspacePath; + + protected BaseServerConfigurationController(@NotNull Path homeDirectory) { + this.homeDirectory = homeDirectory; + } @NotNull public Gson getGson() { @@ -34,4 +51,46 @@ public Gson getGson() { protected abstract GsonBuilder getGsonBuilder(); public abstract T getServerConfiguration(); + + + @NotNull + protected synchronized Path initWorkspacePath() throws DBException { + if (workspacePath != null) { + log.warn("Workspace directory already initialized: " + workspacePath); + return workspacePath; + } + String workspaceLocation = getServerConfiguration().getWorkspaceLocation(); + URI workspaceUri = URI.create(workspaceLocation); + if (workspaceUri.getScheme() == null) { + // default filesystem + return getHomeDirectory().resolve(workspaceLocation); + } + + var externalFsProvider = + FileSystemProviderRegistry.getInstance().getFileSystemProviderBySchema(workspaceUri.getScheme()); + if (externalFsProvider == null) { + throw new DBException("File system not found for scheme: " + workspaceUri.getScheme()); + } + ClassLoader fsClassloader = externalFsProvider.getInstance().getClass().getClassLoader(); + try (FileSystem externalFileSystem = FileSystems.newFileSystem(workspaceUri, System.getenv(), fsClassloader);) { + this.workspacePath = externalFileSystem.provider().getPath(workspaceUri); + return workspacePath; + } catch (Exception e) { + throw new DBException("Failed to initialize workspace path: " + workspaceUri, e); + } + } + + @NotNull + protected Path getHomeDirectory() { + return homeDirectory; + } + + @NotNull + @Override + public Path getWorkspacePath() { + if (workspacePath == null) { + throw new RuntimeException("Workspace path not initialized"); + } + return workspacePath; + } } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebApplication.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebApplication.java index 0517fef9b1..7489bd3089 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebApplication.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebApplication.java @@ -251,6 +251,12 @@ public String getWorkspaceIdProperty() throws DBException { return BaseWorkspaceImpl.readWorkspaceIdProperty(); } + @Override + public Path getWorkspaceDirectory() { + return getServerConfigurationController().getWorkspacePath(); + } + + public String getApplicationId() { try { return getApplicationInstanceId(); diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebServerConfiguration.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebServerConfiguration.java index 1c8fa96c2c..b3238e25fb 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebServerConfiguration.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebServerConfiguration.java @@ -16,6 +16,8 @@ */ package io.cloudbeaver.model.app; +import org.jkiss.code.NotNull; + /** * Web server configuration. * Contains only server configuration properties. @@ -27,4 +29,9 @@ default String getRootURI() { return ""; } + @NotNull + default String getWorkspaceLocation() { + return "workspace"; + } + } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebServerConfigurationController.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebServerConfigurationController.java index c06f137b70..4756c74a9c 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebServerConfigurationController.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebServerConfigurationController.java @@ -39,6 +39,9 @@ default Map getOriginalConfigurationProperties() { return Map.of(); } + @NotNull + Path getWorkspacePath(); + @NotNull Gson getGson(); } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/BaseGQLPlatform.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/BaseGQLPlatform.java index ca5d26fd6a..41b1a60e25 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/BaseGQLPlatform.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/BaseGQLPlatform.java @@ -17,6 +17,7 @@ package io.cloudbeaver.server; import io.cloudbeaver.DBWConstants; +import io.cloudbeaver.model.app.WebApplication; import org.eclipse.core.runtime.Plugin; import org.jkiss.code.NotNull; import org.jkiss.dbeaver.Log; @@ -55,7 +56,7 @@ protected synchronized void initialize() { SecurityProviderUtils.registerSecurityProvider(); // Register properties adapter - this.workspace = new WebGlobalWorkspace(this); + this.workspace = new WebGlobalWorkspace(this, (WebApplication) getApplication()); this.workspace.initializeProjects(); QMUtils.initApplication(this); diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/WebGlobalWorkspace.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/WebGlobalWorkspace.java index 02a3b4e53d..44d13c5667 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/WebGlobalWorkspace.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/WebGlobalWorkspace.java @@ -17,6 +17,7 @@ package io.cloudbeaver.server; import io.cloudbeaver.WebProjectImpl; +import io.cloudbeaver.model.app.WebApplication; import io.cloudbeaver.utils.WebAppUtils; import org.eclipse.core.runtime.Platform; import org.jkiss.code.NotNull; @@ -47,18 +48,14 @@ public class WebGlobalWorkspace extends BaseWorkspaceImpl { protected final Map projects = new LinkedHashMap<>(); private WebGlobalProject globalProject; - public WebGlobalWorkspace(DBPPlatform platform) { - super(platform, Path.of(getWorkspaceURI())); - } + private final WebApplication application; - @NotNull - private static URI getWorkspaceURI() { - String workspacePath = Platform.getInstanceLocation().getURL().toString(); - try { - return new URI(workspacePath); - } catch (URISyntaxException e) { - throw new IllegalStateException("Workspace path is invalid: " + workspacePath, e); - } + public WebGlobalWorkspace( + @NotNull DBPPlatform platform, + @NotNull WebApplication application + ) { + super(platform, application.getWorkspaceDirectory()); + this.application = application; } @Override diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java index 2027832a9d..ddc06571eb 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java @@ -439,11 +439,6 @@ public Path getDataDirectory(boolean create) { return dataDir.toPath(); } - @Override - public Path getWorkspaceDirectory() { - return Path.of(getServerConfiguration().getWorkspaceLocation()); - } - private void initializeSecurityController() throws DBException { securityController = createGlobalSecurityController(); } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java index 7acde3722b..29529d78d8 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java @@ -68,6 +68,7 @@ public abstract class CBServerConfigurationController private final Map originalConfigurationProperties = new LinkedHashMap<>(); protected CBServerConfigurationController(@NotNull T serverConfiguration, @NotNull Path homeDirectory) { + super(homeDirectory); this.serverConfiguration = serverConfiguration; this.homeDirectory = homeDirectory; } @@ -91,6 +92,8 @@ public void loadServerConfiguration(Path configPath) throws DBException { loadConfiguration(configPath); } + initWorkspacePath(); + // Try to load configuration from runtime app config file Path runtimeConfigPath = getRuntimeAppConfigPath(); if (Files.exists(runtimeConfigPath)) { @@ -102,6 +105,7 @@ public void loadServerConfiguration(Path configPath) throws DBException { PrefUtils.setDefaultPreferenceValue(DBWorkbench.getPlatform().getPreferenceStore(), ModelPreferences.UI_DRIVERS_HOME, getServerConfiguration().getDriversLocation()); + CBPlatform.getInstance().refreshApplicableDrivers(); } public void loadConfiguration(Path configPath) throws DBException { @@ -169,7 +173,6 @@ public T parseServerConfiguration() { config.setContentRoot(WebAppUtils.getRelativePath(config.getContentRoot(), homeDirectory)); config.setRootURI(readRootUri(config.getRootURI())); config.setDriversLocation(WebAppUtils.getRelativePath(config.getDriversLocation(), homeDirectory)); - config.setWorkspaceLocation(WebAppUtils.getRelativePath(config.getWorkspaceLocation(), homeDirectory)); String staticContentsFile = config.getStaticContent(); if (!CommonUtils.isEmpty(staticContentsFile)) { @@ -248,21 +251,21 @@ protected void readProductConfiguration(Map serverConfig, Gson g } } - // Add product config from runtime - File rtConfig = getRuntimeProductConfigFilePath().toFile(); - if (rtConfig.exists()) { - log.debug("Load product runtime configuration from '" + rtConfig.getAbsolutePath() + "'"); - try (Reader reader = new InputStreamReader(new FileInputStream(rtConfig), StandardCharsets.UTF_8)) { - var runtimeProductSettings = JSONUtils.parseMap(gson, reader); - var productSettings = serverConfiguration.getProductSettings(); - runtimeProductSettings.putAll(productSettings); - Map flattenConfig = WebAppUtils.flattenMap(runtimeProductSettings); - productSettings.clear(); - productSettings.putAll(flattenConfig); - } catch (Exception e) { - throw new DBException("Error reading product runtime configuration", e); - } - } +// // Add product config from runtime +// File rtConfig = getRuntimeProductConfigFilePath().toFile(); +// if (rtConfig.exists()) { +// log.debug("Load product runtime configuration from '" + rtConfig.getAbsolutePath() + "'"); +// try (Reader reader = new InputStreamReader(new FileInputStream(rtConfig), StandardCharsets.UTF_8)) { +// var runtimeProductSettings = JSONUtils.parseMap(gson, reader); +// var productSettings = serverConfiguration.getProductSettings(); +// runtimeProductSettings.putAll(productSettings); +// Map flattenConfig = WebAppUtils.flattenMap(runtimeProductSettings); +// productSettings.clear(); +// productSettings.putAll(flattenConfig); +// } catch (Exception e) { +// throw new DBException("Error reading product runtime configuration", e); +// } +// } } protected Map readConnectionsPermissionsConfiguration(Path parentPath) { @@ -307,7 +310,7 @@ protected Map readConfiguration(Path configPath) throws DBExcept } public Map readConfigurationFile(Path path) throws DBException { - try (Reader reader = new InputStreamReader(new FileInputStream(path.toFile()), StandardCharsets.UTF_8)) { + try (Reader reader = new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8)) { return JSONUtils.parseMap(getGson(), reader); } catch (Exception e) { throw new DBException("Error parsing server configuration", e); @@ -358,8 +361,7 @@ private synchronized void writeRuntimeConfig(Path runtimeConfigPath, Map productConfiguration) throws DBException { diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationControllerEmbedded.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationControllerEmbedded.java index 7031b941a6..d51c1f7cbd 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationControllerEmbedded.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationControllerEmbedded.java @@ -100,6 +100,4 @@ protected GsonBuilder getGsonBuilder() { return gsonBuilder .registerTypeAdapter(WebDatabaseConfig.class, dbConfigCreator); } - - } From f8f2778f60c5e316bc3f8e691e52a6530d1fc112 Mon Sep 17 00:00:00 2001 From: Aleksandr Skoblikov Date: Fri, 27 Sep 2024 13:12:46 +0400 Subject: [PATCH 2/4] CB-5390 wip --- .../BaseServerConfigurationController.java | 39 +++++++++++-------- .../model/app/WebServerConfiguration.java | 7 ---- .../rm/local/LocalResourceController.java | 4 +- .../model/rm/lock/RMFileLockController.java | 16 +++++--- .../cloudbeaver/server/BaseGQLPlatform.java | 13 +++---- .../server/WebPlatformActivator.java | 2 - .../io/cloudbeaver/server/CBApplication.java | 25 ++++++++---- .../CBServerConfigurationController.java | 13 +++---- 8 files changed, 62 insertions(+), 57 deletions(-) diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java index 7b4bc227f2..2d5ecdca5c 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java @@ -54,32 +54,37 @@ public Gson getGson() { @NotNull - protected synchronized Path initWorkspacePath() throws DBException { + protected synchronized void initWorkspacePath() throws DBException { if (workspacePath != null) { log.warn("Workspace directory already initialized: " + workspacePath); - return workspacePath; + return; } - String workspaceLocation = getServerConfiguration().getWorkspaceLocation(); + String workspaceLocation = getWorkspaceLocation(); URI workspaceUri = URI.create(workspaceLocation); if (workspaceUri.getScheme() == null) { // default filesystem - return getHomeDirectory().resolve(workspaceLocation); - } - - var externalFsProvider = - FileSystemProviderRegistry.getInstance().getFileSystemProviderBySchema(workspaceUri.getScheme()); - if (externalFsProvider == null) { - throw new DBException("File system not found for scheme: " + workspaceUri.getScheme()); - } - ClassLoader fsClassloader = externalFsProvider.getInstance().getClass().getClassLoader(); - try (FileSystem externalFileSystem = FileSystems.newFileSystem(workspaceUri, System.getenv(), fsClassloader);) { - this.workspacePath = externalFileSystem.provider().getPath(workspaceUri); - return workspacePath; - } catch (Exception e) { - throw new DBException("Failed to initialize workspace path: " + workspaceUri, e); + this.workspacePath = getHomeDirectory().resolve(workspaceLocation); + } else { + var externalFsProvider = + FileSystemProviderRegistry.getInstance().getFileSystemProviderBySchema(workspaceUri.getScheme()); + if (externalFsProvider == null) { + throw new DBException("File system not found for scheme: " + workspaceUri.getScheme()); + } + ClassLoader fsClassloader = externalFsProvider.getInstance().getClass().getClassLoader(); + try (FileSystem externalFileSystem = FileSystems.newFileSystem(workspaceUri, + System.getenv(), + fsClassloader);) { + this.workspacePath = externalFileSystem.provider().getPath(workspaceUri); + } catch (Exception e) { + throw new DBException("Failed to initialize workspace path: " + workspaceUri, e); + } } + log.info("Workspace path initialized: " + workspacePath); } + @NotNull + protected abstract String getWorkspaceLocation(); + @NotNull protected Path getHomeDirectory() { return homeDirectory; diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebServerConfiguration.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebServerConfiguration.java index b3238e25fb..1c8fa96c2c 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebServerConfiguration.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebServerConfiguration.java @@ -16,8 +16,6 @@ */ package io.cloudbeaver.model.app; -import org.jkiss.code.NotNull; - /** * Web server configuration. * Contains only server configuration properties. @@ -29,9 +27,4 @@ default String getRootURI() { return ""; } - @NotNull - default String getWorkspaceLocation() { - return "workspace"; - } - } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/local/LocalResourceController.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/local/LocalResourceController.java index 4718c448c2..0948919976 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/local/LocalResourceController.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/local/LocalResourceController.java @@ -625,7 +625,7 @@ public String moveResource( throw new DBException("Resource '" + oldTargetPath + "' doesn't exists"); } Path newTargetPath = getTargetPath(projectId, normalizedNewResourcePath); - validateResourcePath(newTargetPath.toString()); + validateResourcePath(rootPath.relativize(newTargetPath).toString()); if (Files.exists(newTargetPath)) { throw new DBException("Resource with name %s already exists".formatted(newTargetPath.getFileName())); } @@ -881,7 +881,7 @@ private Path getTargetPath(@NotNull String projectId, @NotNull String resourcePa if (!targetPath.startsWith(projectPath)) { throw new DBException("Invalid resource path"); } - return WebAppUtils.getWebApplication().getHomeDirectory().relativize(targetPath); + return targetPath; } catch (InvalidPathException e) { throw new DBException("Resource path contains invalid characters"); } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/lock/RMFileLockController.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/lock/RMFileLockController.java index bf966ea748..9c9190bddf 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/lock/RMFileLockController.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/lock/RMFileLockController.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.io.Reader; import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.UUID; @@ -73,18 +74,23 @@ public RMFileLockController(WebApplication application, int maxLockTime) throws * @return - lock */ @NotNull - public RMLock lockProject(@NotNull String projectId,@NotNull String operationName) throws DBException { + public RMLock lockProject(@NotNull String projectId, @NotNull String operationName) throws DBException { synchronized (RMFileLockController.class) { try { - createLockFolderIfNeeded(); - createProjectFolder(projectId); - Path projectLockFile = getProjectLockFilePath(projectId); - RMLockInfo lockInfo = new RMLockInfo.Builder(projectId, UUID.randomUUID().toString()) .setApplicationId(applicationId) .setOperationName(operationName) .setOperationStartTime(System.currentTimeMillis()) .build(); + Path projectLockFile = getProjectLockFilePath(projectId); + + if (!lockFolderPath.getFileSystem().equals(FileSystems.getDefault())) { + // fake lock for external file system? + return new RMLock(projectLockFile); + } + createLockFolderIfNeeded(); + createProjectFolder(projectId); + createLockFile(projectLockFile, lockInfo); return new RMLock(projectLockFile); } catch (Exception e) { diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/BaseGQLPlatform.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/BaseGQLPlatform.java index 41b1a60e25..57ebd2dd56 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/BaseGQLPlatform.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/BaseGQLPlatform.java @@ -96,14 +96,8 @@ public Path getTempFolder(@NotNull DBRProgressMonitor monitor, @NotNull String n if (tempFolder == null) { // Make temp folder monitor.subTask("Create temp folder"); - tempFolder = workspace.getAbsolutePath().resolve(DBWConstants.WORK_DATA_FOLDER_NAME); - } - if (!Files.exists(tempFolder)) { - try { - Files.createDirectories(tempFolder); - } catch (IOException e) { - log.error("Can't create temp directory " + tempFolder, e); - } + //we do not use workspace because it can be in external file system + tempFolder = getApplication().getHomeDirectory().resolve(DBWConstants.WORK_DATA_FOLDER_NAME); } Path folder = tempFolder.resolve(name); if (!Files.exists(folder)) { @@ -116,6 +110,9 @@ public Path getTempFolder(@NotNull DBRProgressMonitor monitor, @NotNull String n return folder; } + @NotNull + public abstract WebApplication getApplication(); + @Override public synchronized void dispose() { super.dispose(); diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/WebPlatformActivator.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/WebPlatformActivator.java index 94652dd478..d13eb03bcf 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/WebPlatformActivator.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/WebPlatformActivator.java @@ -23,7 +23,6 @@ import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; -import java.io.File; import java.io.PrintStream; /** @@ -33,7 +32,6 @@ public class WebPlatformActivator extends Plugin { // The shared instance private static WebPlatformActivator instance; - private static File configDir; private PrintStream debugWriter; private DBPPreferenceStore preferences; diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java index ddc06571eb..007af2d51e 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java @@ -37,6 +37,7 @@ import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; +import org.jkiss.dbeaver.ModelPreferences; import org.jkiss.dbeaver.model.DBPDataSourceContainer; import org.jkiss.dbeaver.model.app.DBPPlatform; import org.jkiss.dbeaver.model.auth.AuthInfo; @@ -53,19 +54,20 @@ import org.jkiss.dbeaver.runtime.DBWorkbench; import org.jkiss.dbeaver.runtime.ui.DBPPlatformUI; import org.jkiss.dbeaver.utils.GeneralUtils; +import org.jkiss.dbeaver.utils.PrefUtils; import org.jkiss.dbeaver.utils.SystemVariablesResolver; import org.jkiss.utils.ArrayUtils; import org.jkiss.utils.CommonUtils; import org.jkiss.utils.StandardConstants; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.URL; import java.net.UnknownHostException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -201,6 +203,7 @@ protected void startServer() { if (!loadServerConfiguration()) { return; } + if (CommonUtils.isEmpty(this.getAppConfiguration().getDefaultUserTeam())) { throw new DBException("Default user team must be specified"); } @@ -208,6 +211,12 @@ protected void startServer() { log.error(e); return; } + // Set default preferences + PrefUtils.setDefaultPreferenceValue(DBWorkbench.getPlatform().getPreferenceStore(), + ModelPreferences.UI_DRIVERS_HOME, + getServerConfiguration().getDriversLocation()); + CBPlatform.getInstance().refreshApplicableDrivers(); + refreshDisabledDriversConfig(); configurationMode = CommonUtils.isEmpty(getServerConfiguration().getServerName()); @@ -303,7 +312,7 @@ protected void startServer() { if (configurationMode) { // Try to configure automatically - performAutoConfiguration(getMainConfigurationFilePath().toFile().getParentFile()); + performAutoConfiguration(getMainConfigurationFilePath().getParent()); } else if (!isMultiNode()) { var appConfiguration = getServerConfigurationController().getAppConfiguration(); if (appConfiguration.isGrantConnectionsAccessToAnonymousTeam()) { @@ -331,7 +340,7 @@ protected void initializeAdditionalConfiguration() { * * @param configPath */ - protected void performAutoConfiguration(File configPath) { + protected void performAutoConfiguration(Path configPath) { String autoServerName = System.getenv(CBConstants.VAR_AUTO_CB_SERVER_NAME); String autoServerURL = System.getenv(CBConstants.VAR_AUTO_CB_SERVER_URL); String autoAdminName = System.getenv(CBConstants.VAR_AUTO_CB_ADMIN_NAME); @@ -340,11 +349,11 @@ protected void performAutoConfiguration(File configPath) { if (CommonUtils.isEmpty(autoServerName) || CommonUtils.isEmpty(autoAdminName) || CommonUtils.isEmpty( autoAdminPassword)) { // Try to load from auto config file - if (configPath.exists()) { - File autoConfigFile = new File(configPath, CBConstants.AUTO_CONFIG_FILE_NAME); - if (autoConfigFile.exists()) { + if (Files.exists(configPath)) { + Path autoConfigFile = configPath.resolve(CBConstants.AUTO_CONFIG_FILE_NAME); + if (Files.exists(autoConfigFile)) { Properties autoProps = new Properties(); - try (InputStream is = new FileInputStream(autoConfigFile)) { + try (InputStream is = Files.newInputStream(autoConfigFile)) { autoProps.load(is); autoServerName = autoProps.getProperty(CBConstants.VAR_AUTO_CB_SERVER_NAME); @@ -352,7 +361,7 @@ protected void performAutoConfiguration(File configPath) { autoAdminName = autoProps.getProperty(CBConstants.VAR_AUTO_CB_ADMIN_NAME); autoAdminPassword = autoProps.getProperty(CBConstants.VAR_AUTO_CB_ADMIN_PASSWORD); } catch (IOException e) { - log.error("Error loading auto configuration file '" + autoConfigFile.getAbsolutePath() + "'", + log.error("Error loading auto configuration file '" + autoConfigFile + "'", e); } } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java index 29529d78d8..02fffb7224 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java @@ -30,16 +30,13 @@ import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; -import org.jkiss.dbeaver.ModelPreferences; import org.jkiss.dbeaver.model.auth.SMCredentialsProvider; import org.jkiss.dbeaver.model.data.json.JSONUtils; import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings; import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration; import org.jkiss.dbeaver.registry.DataSourceNavigatorSettings; -import org.jkiss.dbeaver.runtime.DBWorkbench; import org.jkiss.dbeaver.runtime.IVariableResolver; import org.jkiss.dbeaver.utils.ContentUtils; -import org.jkiss.dbeaver.utils.PrefUtils; import org.jkiss.dbeaver.utils.SystemVariablesResolver; import org.jkiss.utils.CommonUtils; @@ -100,12 +97,12 @@ public void loadServerConfiguration(Path configPath) throws DBException { log.debug("Runtime configuration [" + runtimeConfigPath.toAbsolutePath() + "]"); loadConfiguration(runtimeConfigPath); } + } - // Set default preferences - PrefUtils.setDefaultPreferenceValue(DBWorkbench.getPlatform().getPreferenceStore(), - ModelPreferences.UI_DRIVERS_HOME, - getServerConfiguration().getDriversLocation()); - CBPlatform.getInstance().refreshApplicableDrivers(); + @NotNull + @Override + protected String getWorkspaceLocation() { + return getServerConfiguration().getWorkspaceLocation(); } public void loadConfiguration(Path configPath) throws DBException { From a745192cd85f1ce21eb4f1a48d4c6458c43e7c80 Mon Sep 17 00:00:00 2001 From: Aleksandr Skoblikov Date: Mon, 30 Sep 2024 15:59:16 +0400 Subject: [PATCH 3/4] CB-5390 review fixes --- .../BaseServerConfigurationController.java | 2 +- .../app/WebServerConfigurationController.java | 2 + .../model/rm/lock/RMFileLockController.java | 4 +- .../cloudbeaver/server/BaseGQLPlatform.java | 26 ++++++++-- .../io/cloudbeaver/server/CBApplication.java | 7 --- .../CBServerConfigurationController.java | 51 ++++++++++++------- 6 files changed, 60 insertions(+), 32 deletions(-) diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java index 2d5ecdca5c..01169931f7 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java @@ -37,7 +37,7 @@ public abstract class BaseServerConfigurationController getOriginalConfigurationProperties() { @NotNull Gson getGson(); + + void validateFinalServerConfiguration() throws DBException; } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/lock/RMFileLockController.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/lock/RMFileLockController.java index 9c9190bddf..b87526cd92 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/lock/RMFileLockController.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/lock/RMFileLockController.java @@ -23,11 +23,11 @@ import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.app.DBPWorkspace; +import org.jkiss.utils.IOUtils; import java.io.IOException; import java.io.Reader; import java.nio.charset.StandardCharsets; -import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.UUID; @@ -84,7 +84,7 @@ public RMLock lockProject(@NotNull String projectId, @NotNull String operationNa .build(); Path projectLockFile = getProjectLockFilePath(projectId); - if (!lockFolderPath.getFileSystem().equals(FileSystems.getDefault())) { + if (!IOUtils.isFileFromDefaultFS(lockFolderPath)) { // fake lock for external file system? return new RMLock(projectLockFile); } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/BaseGQLPlatform.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/BaseGQLPlatform.java index 57ebd2dd56..a2ae8040a2 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/BaseGQLPlatform.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/BaseGQLPlatform.java @@ -34,6 +34,8 @@ import org.jkiss.dbeaver.runtime.qm.QMLogFileWriter; import org.jkiss.dbeaver.runtime.qm.QMRegistryImpl; import org.jkiss.dbeaver.utils.ContentUtils; +import org.jkiss.utils.CommonUtils; +import org.jkiss.utils.StandardConstants; import java.io.IOException; import java.nio.file.Files; @@ -41,7 +43,7 @@ public abstract class BaseGQLPlatform extends BasePlatformImpl { private static final Log log = Log.getLog(BaseGQLPlatform.class); - public static final String WORK_DATA_FOLDER_NAME = ".work-data"; + public static final String BASE_TEMP_DIR = "dbeaver"; private Path tempFolder; @@ -93,11 +95,13 @@ public DBPWorkspace getWorkspace() { @NotNull public Path getTempFolder(@NotNull DBRProgressMonitor monitor, @NotNull String name) { + if (tempFolder == null) { - // Make temp folder - monitor.subTask("Create temp folder"); - //we do not use workspace because it can be in external file system - tempFolder = getApplication().getHomeDirectory().resolve(DBWConstants.WORK_DATA_FOLDER_NAME); + synchronized (this) { + if (tempFolder == null) { + initTempFolder(monitor); + } + } } Path folder = tempFolder.resolve(name); if (!Files.exists(folder)) { @@ -110,6 +114,18 @@ public Path getTempFolder(@NotNull DBRProgressMonitor monitor, @NotNull String n return folder; } + private void initTempFolder(@NotNull DBRProgressMonitor monitor) { + // Make temp folder + monitor.subTask("Create temp folder"); + String sysTempFolder = System.getProperty(StandardConstants.ENV_TMP_DIR); + if (CommonUtils.isNotEmpty(sysTempFolder)) { + tempFolder = Path.of(sysTempFolder).resolve(BASE_TEMP_DIR).resolve(DBWConstants.WORK_DATA_FOLDER_NAME); + } else { + //we do not use workspace because it can be in external file system + tempFolder = getApplication().getHomeDirectory().resolve(DBWConstants.WORK_DATA_FOLDER_NAME); + } + } + @NotNull public abstract WebApplication getApplication(); diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java index 007af2d51e..38c295f8e3 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java @@ -37,7 +37,6 @@ import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; -import org.jkiss.dbeaver.ModelPreferences; import org.jkiss.dbeaver.model.DBPDataSourceContainer; import org.jkiss.dbeaver.model.app.DBPPlatform; import org.jkiss.dbeaver.model.auth.AuthInfo; @@ -54,7 +53,6 @@ import org.jkiss.dbeaver.runtime.DBWorkbench; import org.jkiss.dbeaver.runtime.ui.DBPPlatformUI; import org.jkiss.dbeaver.utils.GeneralUtils; -import org.jkiss.dbeaver.utils.PrefUtils; import org.jkiss.dbeaver.utils.SystemVariablesResolver; import org.jkiss.utils.ArrayUtils; import org.jkiss.utils.CommonUtils; @@ -211,11 +209,6 @@ protected void startServer() { log.error(e); return; } - // Set default preferences - PrefUtils.setDefaultPreferenceValue(DBWorkbench.getPlatform().getPreferenceStore(), - ModelPreferences.UI_DRIVERS_HOME, - getServerConfiguration().getDriversLocation()); - CBPlatform.getInstance().refreshApplicableDrivers(); refreshDisabledDriversConfig(); diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java index 02fffb7224..883e326314 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBServerConfigurationController.java @@ -30,15 +30,19 @@ import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; +import org.jkiss.dbeaver.ModelPreferences; import org.jkiss.dbeaver.model.auth.SMCredentialsProvider; import org.jkiss.dbeaver.model.data.json.JSONUtils; import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings; import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration; import org.jkiss.dbeaver.registry.DataSourceNavigatorSettings; +import org.jkiss.dbeaver.runtime.DBWorkbench; import org.jkiss.dbeaver.runtime.IVariableResolver; import org.jkiss.dbeaver.utils.ContentUtils; +import org.jkiss.dbeaver.utils.PrefUtils; import org.jkiss.dbeaver.utils.SystemVariablesResolver; import org.jkiss.utils.CommonUtils; +import org.jkiss.utils.IOUtils; import java.io.*; import java.net.InetAddress; @@ -97,6 +101,11 @@ public void loadServerConfiguration(Path configPath) throws DBException { log.debug("Runtime configuration [" + runtimeConfigPath.toAbsolutePath() + "]"); loadConfiguration(runtimeConfigPath); } + // Set default preferences + PrefUtils.setDefaultPreferenceValue(DBWorkbench.getPlatform().getPreferenceStore(), + ModelPreferences.UI_DRIVERS_HOME, + getServerConfiguration().getDriversLocation()); + validateFinalServerConfiguration(); } @NotNull @@ -147,7 +156,7 @@ protected void parseConfiguration(Map configProps) throws DBExce ); // App config Map appConfig = JSONUtils.getObject(configProps, "app"); - validateConfiguration(appConfig); + preValidateAppConfiguration(appConfig); gson.fromJson(gson.toJson(appConfig), CBAppConfig.class); readProductConfiguration(serverConfig, gson); } @@ -182,10 +191,11 @@ public T parseServerConfiguration() { return config; } - protected void validateConfiguration(Map appConfig) throws DBException { + protected void preValidateAppConfiguration(Map appConfig) throws DBException { } + private void readExternalProperties(Map serverConfig) { String externalPropertiesFile = JSONUtils.getString(serverConfig, CBConstants.PARAM_EXTERNAL_PROPERTIES); if (!CommonUtils.isEmpty(externalPropertiesFile)) { @@ -248,21 +258,23 @@ protected void readProductConfiguration(Map serverConfig, Gson g } } -// // Add product config from runtime -// File rtConfig = getRuntimeProductConfigFilePath().toFile(); -// if (rtConfig.exists()) { -// log.debug("Load product runtime configuration from '" + rtConfig.getAbsolutePath() + "'"); -// try (Reader reader = new InputStreamReader(new FileInputStream(rtConfig), StandardCharsets.UTF_8)) { -// var runtimeProductSettings = JSONUtils.parseMap(gson, reader); -// var productSettings = serverConfiguration.getProductSettings(); -// runtimeProductSettings.putAll(productSettings); -// Map flattenConfig = WebAppUtils.flattenMap(runtimeProductSettings); -// productSettings.clear(); -// productSettings.putAll(flattenConfig); -// } catch (Exception e) { -// throw new DBException("Error reading product runtime configuration", e); -// } -// } + if (workspacePath != null && IOUtils.isFileFromDefaultFS(getWorkspacePath())) { + // Add product config from runtime + Path rtConfig = getRuntimeProductConfigFilePath(); + if (Files.exists(rtConfig)) { + log.debug("Load product runtime configuration from '" + rtConfig + "'"); + try (Reader reader = new InputStreamReader(Files.newInputStream(rtConfig), StandardCharsets.UTF_8)) { + var runtimeProductSettings = JSONUtils.parseMap(gson, reader); + var productSettings = serverConfiguration.getProductSettings(); + runtimeProductSettings.putAll(productSettings); + Map flattenConfig = WebAppUtils.flattenMap(runtimeProductSettings); + productSettings.clear(); + productSettings.putAll(flattenConfig); + } catch (Exception e) { + throw new DBException("Error reading product runtime configuration", e); + } + } + } } protected Map readConnectionsPermissionsConfiguration(Path parentPath) { @@ -634,4 +646,9 @@ private String readRootUri(String uri) { public Map getOriginalConfigurationProperties() { return originalConfigurationProperties; } + + @Override + public void validateFinalServerConfiguration() throws DBException { + + } } \ No newline at end of file From d5a822f76a56a21e6b0f58235248987be437f00b Mon Sep 17 00:00:00 2001 From: Aleksandr Skoblikov Date: Wed, 2 Oct 2024 14:41:02 +0400 Subject: [PATCH 4/4] CB-5390 fix conflicts --- .../model/app/BaseServerConfigurationController.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java index 01169931f7..e9d3887df0 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServerConfigurationController.java @@ -22,6 +22,7 @@ import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.registry.fs.FileSystemProviderRegistry; +import org.jkiss.utils.IOUtils; import java.net.URI; import java.nio.file.FileSystem; @@ -41,6 +42,8 @@ public abstract class BaseServerConfigurationController