diff --git a/samples/sample-databases/cloudbeaver-sample.conf b/samples/sample-databases/cloudbeaver-sample.conf index 22e77caac6..3d31f4d448 100644 --- a/samples/sample-databases/cloudbeaver-sample.conf +++ b/samples/sample-databases/cloudbeaver-sample.conf @@ -5,4 +5,6 @@ WorkspaceLocation = workspace ContentRoot = web DriversLocation = drivers +ProductConfiguration = conf/product.js + DevelMode = false diff --git a/samples/sample-databases/product.js b/samples/sample-databases/product.js new file mode 100644 index 0000000000..b63b61a437 --- /dev/null +++ b/samples/sample-databases/product.js @@ -0,0 +1,16 @@ +{ + // Global properties + core: { + // User defaults + user: { + defaultTheme: "light", + defaultLanguage: "en" + } + }, + // Log viewer config + logViewer: { + refreshTimeout: 3000, + logBatchSize: 1000, + maxLogRecords: 2000, + } +} diff --git a/server/bundles/io.cloudbeaver.server/schema/schema.graphqls b/server/bundles/io.cloudbeaver.server/schema/schema.graphqls index 9267d38c3c..1243adfce5 100644 --- a/server/bundles/io.cloudbeaver.server/schema/schema.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/schema.graphqls @@ -61,6 +61,7 @@ type ServerConfig { supportsWorkspaces: Boolean supportedLanguages: [ ServerLanguage ] services: [ WebServiceConfig ] + productConfiguration: Object! } type SessionInfo { diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CloudbeaverApplication.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CloudbeaverApplication.java index 86b6e15632..01c6671902 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CloudbeaverApplication.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CloudbeaverApplication.java @@ -16,6 +16,7 @@ */ package io.cloudbeaver.server; +import com.google.gson.GsonBuilder; import io.cloudbeaver.server.jetty.CloudbeaverJettyServer; import org.eclipse.core.runtime.Platform; import org.eclipse.equinox.app.IApplicationContext; @@ -24,6 +25,7 @@ import org.jkiss.code.NotNull; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.ModelPreferences; import org.jkiss.dbeaver.model.app.DBPApplication; +import org.jkiss.dbeaver.model.data.json.JSONUtils; import org.jkiss.dbeaver.registry.BaseApplicationImpl; import org.jkiss.dbeaver.runtime.DBWorkbench; import org.jkiss.dbeaver.utils.GeneralUtils; @@ -32,11 +34,11 @@ import org.jkiss.dbeaver.utils.SystemVariablesResolver; 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.io.*; import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; import java.util.Properties; /** @@ -57,6 +59,8 @@ public class CloudbeaverApplication extends BaseApplicationImpl { private String workspaceLocation = CloudbeaverConstants.DEFAULT_WORKSPACE_LOCATION; private String driversLocation = CloudbeaverConstants.DEFAULT_DRIVERS_LOCATION; + private Map productConfiguration = new HashMap<>(); + private long maxSessionIdleTime = CloudbeaverConstants.MAX_SESSION_IDLE_TIME; private boolean develMode = false; @@ -101,6 +105,10 @@ public class CloudbeaverApplication extends BaseApplicationImpl { return (CloudbeaverApplication) BaseApplicationImpl.getInstance(); } + public Map getProductConfiguration() { + return productConfiguration; + } + @Override public boolean isHeadlessMode() { return true; @@ -169,14 +177,14 @@ public class CloudbeaverApplication extends BaseApplicationImpl { File configFile = new File(configPath); if (!configFile.exists()) { - log.debug("Configuration file " + configPath + " doesn't exist. Use defaults."); + log.error("Configuration file " + configFile.getAbsolutePath() + " doesn't exist. Use defaults."); } else { Properties props = new Properties(); try (InputStream is = new FileInputStream(configFile)) { props.load(is); parseConfiguration(props); } catch (IOException e) { - log.debug("Error reading config file", e); + log.error("Error reading config file", e); } } // Set default preferences @@ -203,6 +211,25 @@ public class CloudbeaverApplication extends BaseApplicationImpl { maxSessionIdleTime = getConfigParameter(props, CloudbeaverConstants.PARAM_SESSION_EXPIRE_PERIOD, CloudbeaverConstants.MAX_SESSION_IDLE_TIME); develMode = CommonUtils.toBoolean(getConfigParameter(props, CloudbeaverConstants.PARAM_DEVEL_MODE, "false")); + + String productConfigPath = this.getRelativePath(getConfigParameter(props, CloudbeaverConstants.PARAM_PRODUCT_CONFIGURATION, CloudbeaverConstants.DEFAULT_PRODUCT_CONFIGURATION), homeFolder); + if (!CommonUtils.isEmpty(productConfigPath)) { + File productConfigFile = new File(productConfigPath); + if (!productConfigFile.exists()) { + log.error("Product configuration file not found (" + productConfigFile.getAbsolutePath() + "'"); + } else { + log.debug("Load product configuration from '" + productConfigFile.getAbsolutePath() + "'"); + try (Reader reader = new InputStreamReader(new FileInputStream(productConfigFile), StandardCharsets.UTF_8)) { + + GsonBuilder gsonBuilder = new GsonBuilder().setLenient(); + //gsonBuilder.registerTypeAdapter(Object.class, new JSONBestNumberObjectDeserializer()); + + productConfiguration = JSONUtils.parseMap(gsonBuilder.create(), reader); + } catch (Exception e) { + log.error("Error reading product configuration", e); + } + } + } } private String getRelativePath(String path, String curDir) { diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CloudbeaverConstants.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CloudbeaverConstants.java index f80ed9c08b..b4114587e8 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CloudbeaverConstants.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CloudbeaverConstants.java @@ -39,6 +39,7 @@ public class CloudbeaverConstants { public static final String PARAM_SERVICES_URI = "ServiceURI"; public static final String PARAM_DRIVERS_LOCATION = "DriversLocation"; public static final String PARAM_WORKSPACE_LOCATION = "WorkspaceLocation"; + public static final String PARAM_PRODUCT_CONFIGURATION = "ProductConfiguration"; public static final String PARAM_SESSION_EXPIRE_PERIOD = "ExpireSessionAfterPeriod"; @@ -53,6 +54,7 @@ public class CloudbeaverConstants { public static final String DEFAULT_DEPLOY_LOCATION = "/opt/cloudbeaver"; public static final String DEFAULT_DRIVERS_LOCATION = DEFAULT_DEPLOY_LOCATION + "/drivers"; public static final String DEFAULT_WORKSPACE_LOCATION = DEFAULT_DEPLOY_LOCATION + "/workspace"; + public static final String DEFAULT_PRODUCT_CONFIGURATION = "conf/product.js"; // Default max idle time (10 minutes) public static final long MAX_SESSION_IDLE_TIME = 10 * 60 * 1000; diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/model/WebServerConfig.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/model/WebServerConfig.java index aef4c58e99..e920fb9fe8 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/model/WebServerConfig.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/model/WebServerConfig.java @@ -16,6 +16,7 @@ */ package io.cloudbeaver.server.model; +import io.cloudbeaver.server.CloudbeaverPlatform; import io.cloudbeaver.server.registry.WebServiceDescriptor; import io.cloudbeaver.server.registry.WebServiceRegistry; import org.jkiss.dbeaver.model.meta.Property; @@ -25,6 +26,7 @@ import org.jkiss.dbeaver.registry.language.PlatformLanguageRegistry; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * Web server configuration @@ -116,4 +118,9 @@ public class WebServerConfig { return services.toArray(new WebServiceConfig[0]); } + @RuntimeAction + public Map getProductConfiguration() { + return CloudbeaverPlatform.getInstance().getApplication().getProductConfiguration(); + } + }