diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/DBWFeatureSet.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/DBWFeatureSet.java index f270b84d31..af07462401 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/DBWFeatureSet.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/DBWFeatureSet.java @@ -36,4 +36,6 @@ public interface DBWFeatureSet { boolean isEnabled(); + boolean isEnabledByDefault(); + } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebAppConfiguration.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebAppConfiguration.java index d16277e757..1f4bf33835 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebAppConfiguration.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseWebAppConfiguration.java @@ -36,6 +36,7 @@ public abstract class BaseWebAppConfiguration implements ServletAppConfiguration protected boolean secretManagerEnabled; protected boolean showReadOnlyConnectionInfo; protected String[] enabledFeatures; + protected String[] disabledFeatures; protected String[] disabledBetaFeatures; @@ -43,6 +44,7 @@ public abstract class BaseWebAppConfiguration implements ServletAppConfiguration this.plugins = new LinkedHashMap<>(); this.resourceManagerEnabled = true; this.enabledFeatures = null; + this.disabledFeatures = new String[0]; this.disabledBetaFeatures = new String[0]; this.showReadOnlyConnectionInfo = false; this.secretManagerEnabled = false; @@ -53,6 +55,7 @@ public abstract class BaseWebAppConfiguration implements ServletAppConfiguration this.defaultUserTeam = src.defaultUserTeam; this.resourceManagerEnabled = src.resourceManagerEnabled; this.enabledFeatures = src.enabledFeatures; + this.disabledFeatures = src.disabledFeatures; this.disabledBetaFeatures = src.disabledBetaFeatures; this.showReadOnlyConnectionInfo = src.showReadOnlyConnectionInfo; this.secretManagerEnabled = src.secretManagerEnabled; @@ -122,6 +125,16 @@ public abstract class BaseWebAppConfiguration implements ServletAppConfiguration this.enabledFeatures = enabledFeatures; } + @NotNull + @Override + public String[] getDisabledFeatures() { + return disabledFeatures; + } + + public void setDisabledFeatures(@NotNull String[] disabledFeatures) { + this.disabledFeatures = disabledFeatures; + } + public boolean isShowReadOnlyConnectionInfo() { return showReadOnlyConnectionInfo; } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/ServletAppConfiguration.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/ServletAppConfiguration.java index 04bae47333..e3afd69125 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/ServletAppConfiguration.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/ServletAppConfiguration.java @@ -51,6 +51,16 @@ public interface ServletAppConfiguration { return new String[0]; } + /** + * Returns disabled features. + * + * @return array of disabled feature IDs + */ + @NotNull + default String[] getDisabledFeatures() { + return new String[0]; + } + default boolean isSupportsCustomConnections() { return true; } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebFeatureDescriptor.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebFeatureDescriptor.java index 5526cd1cba..03c014b825 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebFeatureDescriptor.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebFeatureDescriptor.java @@ -23,6 +23,7 @@ import org.eclipse.core.runtime.IConfigurationElement; import org.jkiss.code.NotNull; import org.jkiss.dbeaver.model.DBPImage; import org.jkiss.dbeaver.model.impl.AbstractContextDescriptor; +import org.jkiss.utils.CommonUtils; /** * WebFeatureDescriptor @@ -35,6 +36,7 @@ public class WebFeatureDescriptor extends AbstractContextDescriptor implements D private final String label; private final String description; private final DBPImage icon; + private final boolean enabledByDefault; public WebFeatureDescriptor(IConfigurationElement config) { @@ -43,6 +45,7 @@ public class WebFeatureDescriptor extends AbstractContextDescriptor implements D this.label = config.getAttribute("label"); this.description = config.getAttribute("description"); this.icon = iconToImage(config.getAttribute("icon")); + this.enabledByDefault = CommonUtils.getBoolean(config.getAttribute("enabledByDefault"), false); } @NotNull @@ -69,4 +72,9 @@ public class WebFeatureDescriptor extends AbstractContextDescriptor implements D return ServletAppUtils.getServletApplication().getAppConfiguration().isFeatureEnabled(this.id); } + @Override + public boolean isEnabledByDefault() { + return enabledByDefault; + } + } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebServerFeatureDescriptor.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebServerFeatureDescriptor.java index 49cf2e0241..d89bf19429 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebServerFeatureDescriptor.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebServerFeatureDescriptor.java @@ -68,4 +68,9 @@ public class WebServerFeatureDescriptor extends AbstractContextDescriptor implem return true; } + @Override + public boolean isEnabledByDefault() { + return false; + } + } diff --git a/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/CBApplication.java b/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/CBApplication.java index aa2f70690f..29076afb9b 100644 --- a/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/CBApplication.java +++ b/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/CBApplication.java @@ -27,6 +27,7 @@ import io.cloudbeaver.model.app.ServletSystemInformationCollector; import io.cloudbeaver.model.config.CBAppConfig; import io.cloudbeaver.model.config.CBServerConfig; import io.cloudbeaver.registry.WebDriverRegistry; +import io.cloudbeaver.registry.WebFeatureRegistry; import io.cloudbeaver.registry.WebServiceRegistry; import io.cloudbeaver.server.jetty.CBJettyServer; import io.cloudbeaver.service.ConnectionController; @@ -214,7 +215,12 @@ public abstract class CBApplication configurationMode = CommonUtils.isEmpty(getServerConfiguration().getServerName()); - refreshDisabledDriversConfig(); + try { + refreshServerConfiguration(); + } catch (DBException e) { + log.error("Error refreshing server configuration", e); + return; + } eventController.setForceSkipEvents(isConfigurationMode()); // do not send events if configuration mode is on @@ -331,6 +337,25 @@ public abstract class CBApplication log.debug("Shutdown"); } + private void refreshServerConfiguration() throws DBException { + refreshDisabledDriversConfig(); + refreshEnabledFeatures(); + if (!isConfigurationMode()) { + flushConfiguration(); + } + } + + private void refreshEnabledFeatures() { + Set enabledFeatures = new LinkedHashSet<>(Arrays.asList(getAppConfiguration().getEnabledFeatures())); + Set disabledFeatures = new LinkedHashSet<>(Arrays.asList(getAppConfiguration().getDisabledFeatures())); + + WebFeatureRegistry.getInstance().getWebFeatures().stream() + .filter(f -> f.isEnabledByDefault() && !disabledFeatures.contains(f.getId())) + .forEach(f -> enabledFeatures.add(f.getId())); + + getAppConfiguration().setEnabledFeatures(enabledFeatures.toArray(new String[0])); + } + protected ServletSystemInformationCollector createSystemInformationCollector() { return new ServletSystemInformationCollector<>(this); } diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java index 4d3e35b7f6..afff09478b 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java @@ -584,7 +584,7 @@ public class WebServiceAdmin implements DBWServiceAdmin { appConfig.setSupportsCustomConnections(config.isCustomConnectionsEnabled()); appConfig.setPublicCredentialsSaveEnabled(config.isPublicCredentialsSaveEnabled()); appConfig.setAdminCredentialsSaveEnabled(config.isAdminCredentialsSaveEnabled()); - appConfig.setEnabledFeatures(config.getEnabledFeatures().toArray(new String[0])); + updateDisabledFeaturesConfig(appConfig, config.getEnabledFeatures()); // custom logic for enabling embedded drivers updateDisabledDriversConfig(appConfig, config.getDisabledDrivers()); appConfig.setResourceManagerEnabled(config.isResourceManagerEnabled()); @@ -674,6 +674,15 @@ public class WebServiceAdmin implements DBWServiceAdmin { return true; } + private void updateDisabledFeaturesConfig(CBAppConfig appConfig, List enabledFeatures) { + Set enabledIds = new LinkedHashSet<>(enabledFeatures); + appConfig.setEnabledFeatures(enabledFeatures.toArray(new String[0])); + String[] disabledFeatures = WebFeatureRegistry.getInstance().getWebFeatures().stream().map(DBWFeatureSet::getId) + .filter(id -> !enabledIds.contains(id)) + .toArray(String[]::new); + appConfig.setDisabledFeatures(disabledFeatures); + } + // we disable embedded drivers by default and enable it in enabled drivers list // that's why we need so complicated logic for disabling drivers private void updateDisabledDriversConfig(CBAppConfig appConfig, String[] disabledDriversConfig) {