mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-10-16 14:50:15 +08:00
Compare commits
107
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6670cc81ae | ||
|
|
f8a107256b | ||
|
|
4f796e5f9c | ||
|
|
fb6f3c8246 | ||
|
|
f3eaed955f | ||
|
|
339f19ff24 | ||
|
|
0229ed1327 | ||
|
|
6a6c29f38e | ||
|
|
c3054c1f26 | ||
|
|
20b129d5a2 | ||
|
|
a08b9c2f2b | ||
|
|
3a250e2e7a | ||
|
|
951b51b403 | ||
|
|
72fcd7bfe2 | ||
|
|
9ea3de9edf | ||
|
|
729d47fda1 | ||
|
|
ebda152b6b | ||
|
|
430ae8e5cc | ||
|
|
97c12d026b | ||
|
|
ea0997d3b0 | ||
|
|
04a2eed596 | ||
|
|
10d8741403 | ||
|
|
ded139584c | ||
|
|
04b3bd9e2b | ||
|
|
9303f4dacf | ||
|
|
7b258d7ba6 | ||
|
|
76c2d4b7fe | ||
|
|
61d0c43bd2 | ||
|
|
0c07a5cd09 | ||
|
|
3dcae7063c | ||
|
|
635d2f8d7f | ||
|
|
cea06eecae | ||
|
|
0e402cd27d | ||
|
|
d79054a5d8 | ||
|
|
0903025942 | ||
|
|
b36b11008f | ||
|
|
f8acdb58af | ||
|
|
4e4292376e | ||
|
|
d5860dc9e8 | ||
|
|
5301adaed4 | ||
|
|
fc9ef33e1d | ||
|
|
2a8f34682f | ||
|
|
9c6f301fa9 | ||
|
|
a2ccd0b0f7 | ||
|
|
acc3e42f1c | ||
|
|
075fa916f0 | ||
|
|
f7b96db2de | ||
|
|
dff9adaf34 | ||
|
|
86c50a1557 | ||
|
|
7d6c05f50c | ||
|
|
022778f95c | ||
|
|
d752d8ac26 | ||
|
|
e1a029b238 | ||
|
|
644dc2a136 | ||
|
|
768fe00f6a | ||
|
|
1e1f684379 | ||
|
|
ac3ce9e085 | ||
|
|
3cc9c3ce86 | ||
|
|
1660e62391 | ||
|
|
c27fca442b | ||
|
|
318100300f | ||
|
|
9c9e8e4496 | ||
|
|
4789acb76a | ||
|
|
39ad4568d0 | ||
|
|
860b8e2e16 | ||
|
|
4b9ba00663 | ||
|
|
897dd994ba | ||
|
|
e81a150287 | ||
|
|
0d17208be4 | ||
|
|
9c1678c256 | ||
|
|
321d45bd48 | ||
|
|
0f33fb5514 | ||
|
|
e7648b1b4c | ||
|
|
45cfded51f | ||
|
|
9822147d68 | ||
|
|
3b0f52f3ed | ||
|
|
3b032a275d | ||
|
|
a11ca992fe | ||
|
|
5138c73ae5 | ||
|
|
ea36247797 | ||
|
|
a6a1916299 | ||
|
|
b8699e6bcb | ||
|
|
8cff50b0cf | ||
|
|
b06a96dc31 | ||
|
|
446bd81e08 | ||
|
|
09863ea260 | ||
|
|
34b4556773 | ||
|
|
9b4c874e51 | ||
|
|
ddbc9789e7 | ||
|
|
810d0215cb | ||
|
|
3dadc17ff1 | ||
|
|
8c69985083 | ||
|
|
1d5b475482 | ||
|
|
b779b9d855 | ||
|
|
df676913a0 | ||
|
|
fab9d1dd43 | ||
|
|
36dfdc8b33 | ||
|
|
8b0a20cfd7 | ||
|
|
9553c30ee5 | ||
|
|
9c36651aa0 | ||
|
|
24a251cd5b | ||
|
|
a44ba89cd9 | ||
|
|
44077ad27a | ||
|
|
3ae74763ff | ||
|
|
45a63f70ee | ||
|
|
1bafe29e99 | ||
|
|
10ad601f8b |
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vscode-java-configs",
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"packageManager": "yarn@4.14.1",
|
||||
"devDependencies": {
|
||||
"typescript": "^5.8.3"
|
||||
}
|
||||
|
||||
@@ -25,6 +25,101 @@ You can see a live demo of CloudBeaver here: https://demo.cloudbeaver.io
|
||||
|
||||
## Changelog
|
||||
|
||||
### 26.0.4 2026-05-04
|
||||
|
||||
- Data Editor:
|
||||
- Added the ability to copy-paste multiple cells at once. Pasted values will be distributed across separate cells, not put in a single cell.
|
||||
- Data Editor started to keep the state of column configurations, such as filters, sorting, and ordering, after the reconnect, page refresh, and re-login.
|
||||
- SQL Editor:
|
||||
- Updated the SQL Editor to use real tab characters for indentation. The application displayed tabs as four-space gaps with a distinct visual marker.
|
||||
- Added the ability to view and edit scripts without connecting to the database.
|
||||
- Added more settings to the Generated SQL window, including the ability to select fully qualified names for query or use compact SQL formatting.
|
||||
- Added the ability to open in the SQL Editor generated queries right from the Generate SQL window.
|
||||
- Accessibility:
|
||||
- Fixed contrast for elements across different application parts in the light and dark themes to meet WCAG requirements.
|
||||
- General:
|
||||
- Removed the "Folders" setting from the available settings for the Navigator Tree.
|
||||
- Databases:
|
||||
- DuckDB: Fixed map rendering for GEOMETRY types with CRS parameters.
|
||||
- Firebird: Expanded database-specific SQL dialect coverage for the SQL Editor. Added more keywords, built-in functions, and SQL generators.
|
||||
- MySQL: Fixed query boundaries recognition in the SQL Editor for scripts with the DELIMITER keyword.
|
||||
- SQL Server: Fixed DDL generation for external tables.
|
||||
- Security:
|
||||
- Updated session handling to prompt the application to generate a new session identifier for each login.
|
||||
- Fixed the high vulnerability (CVE-2026-3505) in the bcpg-jdk18on library. The library was updated to version 1.84.0.
|
||||
|
||||
### 26.0.3 2026-04-20
|
||||
|
||||
- Data Editor:
|
||||
- Added key column mark for tables with unique keys in the data grid.
|
||||
- Added the ability to paste a copied cell into multiple cells and to set multiple cells to NULL.
|
||||
- Fixed the ability to calculate row count for non-standard SELECT statements. (thanks to @fdcastel)
|
||||
- Navigator Tree:
|
||||
- Reorganized the context menu on the connection level to make it more compact.
|
||||
- Added support for special symbols (pipe, comma, and asterisk) for the search field.
|
||||
- Accessibility:
|
||||
- Added the Skip to content option for quick keyboard access to the Navigator Tree, editors, and shortcuts to improve application accessibility.
|
||||
- General:
|
||||
- SQL Editor: Fixed keyword autocompletion for partially typed keywords. There are no extra letters for them after completion.
|
||||
- Added support for custom startup arguments when running CloudBeaver in a container. Administrators can specify configuration file locations to adapt the application to their environment. (thanks to @MalteHei)
|
||||
- Fixed custom driver properties display for the connection page.
|
||||
- Fixed data export in SQL format for values containing single quotes.
|
||||
- Databases:
|
||||
- ClickHouse: Fixed the display of Array(JSON) types in the data grid.
|
||||
- Added support for the "prompt=false" connection property for DB2 for IBM i to turn off interactive prompts and prevent related errors.
|
||||
- Security:
|
||||
- Fixed the critical vulnerability (CVE-2025-62718) in the axios library. The library was updated to version 1.15.0.
|
||||
- Fixed the high vulnerability (CVE-2026-4800) in the lodash library. The library was updated to version 4.18.0.
|
||||
- Fixed the high vulnerability (CVE-2026-39363) in the vite library. The library was updated to version 7.3.2.
|
||||
|
||||
### 26.0.2 2026-04-06
|
||||
|
||||
- UI improvements:
|
||||
- Marked icons for non-saved (temporary) scripts with the hourglass symbol to add visual distinction from the saved ones.
|
||||
- Added the tooltip about quoting rules for the Bind variables parameters dialog.
|
||||
- Improved keyboard navigation for context menu and buttons for Data Editor, SQL Editor, and Navigator tree.
|
||||
- Authentication:
|
||||
- Fixed the bug with the authentication form. Now the same password is required for the password change operation.
|
||||
- Fixed the display of authentication fields for SQL Server with Active Directory - MSI. The unnecessary Password field was removed.
|
||||
- Databases and drivers:
|
||||
- DuckDB: Fixed geometry type display for database versions > 1.5. (thanks @EastLord).
|
||||
- H2 database:
|
||||
- Added new embedded driver version 2.4.2.
|
||||
- Updated server driver to the version 2.4.2.
|
||||
- Security:
|
||||
- Fixed the high vulnerability (CVE-2026-33671) in the picomatch library. The library was updated to version 2.3.2.
|
||||
- Fixed the high vulnerability (CVE-2026-33943) in the happy-dom library. The library was updated to version 20.8.8.
|
||||
- Fixed the high vulnerability (CVE-2026-33228) in the flatted library. The library was updated to version 3.4.2.
|
||||
|
||||
### 26.0.1 2026-03-23
|
||||
|
||||
- Data Editor:
|
||||
- Added the Find and Replace functionality for the Data Editor with the ability to find data by matching case, whole word, or using regular expressions.
|
||||
- Added support for adding, duplicating, deleting, or setting values to NULL in multiple highlighted rows via the Data Editor context menu.
|
||||
- SQL query generation in the Data Editor is now available for columns containing large object data.
|
||||
- Improved column drag-and-drop behavior in the Data Editor. Users could drag columns from any area within the header and drop them onto any part of the target column or table body.
|
||||
- SQL Editor:
|
||||
- Added fuzzy search to SQL Editor auto-completion for object names. The feature allowed users to find tables and containers even with typos or incorrect letter ordering by matching strings that start with, contain, or resemble the input.
|
||||
- Fixed data editing for SQL scripts with variables.
|
||||
- General:
|
||||
- Added a close button to the right tab when it is the only open tab (ex. Scripts). Users no longer needed to use the main menu to close a single tab.
|
||||
- Replaced the generic "Something went wrong" message with a specific network error notification when the application cannot connect to the server.
|
||||
- Null or empty values can now be assigned to the Driver properties for all drivers.
|
||||
- Fixed an issue where re-selecting an existing SSH key file during connection edits caused problems.
|
||||
- Fixed the ability to switch tabs in the Data editor using the keyboard.
|
||||
- Fixed error notification spelling. Thanks to @Malcolm-B-Breaks.
|
||||
- ClickHouse:
|
||||
- Updated driver version to 0.9.7.
|
||||
- Fixed IP address display in the Data Editor by removing the leading slash.
|
||||
- PostgreSQL: Fixed an error when connecting via URL if the database name contains a hyphen.
|
||||
- Security:
|
||||
- Fixed the high vulnerability (CVE-2025-45141) in the tar library. The library was updated to version 7.5.11.
|
||||
- Fixed the high vulnerability (CVE-2026-27148) in the storybook library. The library was updated to version 10.2.10.
|
||||
- Fixed the high vulnerability (CVE-2026-27606) in the rollup library. The library was updated to version 4.59.0.
|
||||
- Fixed the high vulnerability (CVE-2026-27904) in the minimatch library. The library was updated to version 3.1.3.
|
||||
- Fixed the high vulnerability (CVE-2026-27959) in the koa library. The library was updated to version 2.16.4.
|
||||
- Fixed the high vulnerability (CVE-2026-32141) in the flatted library. The library was updated to version 4.4.0.
|
||||
|
||||
### 26.0.0 2026-03-02
|
||||
|
||||
### Changes since 25.3.0:
|
||||
|
||||
@@ -13,7 +13,7 @@ if [ "$(id -u)" -eq 0 ]; then
|
||||
|
||||
chown -R $DBEAVER_UID:$DBEAVER_GID $PWD/workspace
|
||||
# Execute run-cloudbeaver-server.sh as the dbeaver user with the JAVA_HOME and PATH environment variables
|
||||
exec su "$TARGET_USER" -c "JAVA_HOME=$JAVA_HOME PATH=$PATH ./run-cloudbeaver-server.sh"
|
||||
exec su "$TARGET_USER" -c "JAVA_HOME=$JAVA_HOME PATH=$PATH ./run-cloudbeaver-server.sh $*"
|
||||
else
|
||||
exec ./run-cloudbeaver-server.sh
|
||||
fi
|
||||
exec ./run-cloudbeaver-server.sh "$@"
|
||||
fi
|
||||
|
||||
@@ -35,7 +35,7 @@ exec java ${JAVA_OPTS} \
|
||||
--add-opens=java.sql/java.sql=ALL-UNNAMED \
|
||||
-jar ${launcherJar} \
|
||||
-product io.cloudbeaver.product.ce.product \
|
||||
-web-config conf/cloudbeaver.conf \
|
||||
"$@" \
|
||||
-web-config conf/cloudbeaver.conf \
|
||||
-nl en \
|
||||
-registryMultiLanguage
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Model
|
||||
Bundle-SymbolicName: io.cloudbeaver.model.cli;singleton:=true
|
||||
Bundle-Version: 1.0.7.qualifier
|
||||
Bundle-Release-Date: 20260406
|
||||
Bundle-Version: 1.0.10.qualifier
|
||||
Bundle-Release-Date: 20260518
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: org.jkiss.dbeaver.model.cli;visibility:=reexport
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.model.cli</artifactId>
|
||||
<version>1.0.7-SNAPSHOT</version>
|
||||
<version>1.0.10-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
+6
-2
@@ -22,8 +22,11 @@ import org.jkiss.dbeaver.model.cli.ApplicationCommandLine;
|
||||
import org.jkiss.dbeaver.model.cli.ApplicationInstanceController;
|
||||
import org.jkiss.dbeaver.model.cli.CLIContextImpl;
|
||||
import org.jkiss.dbeaver.model.cli.CLIRunMeta;
|
||||
import org.jkiss.dbeaver.model.cli.registry.CLICommandDescriptor;
|
||||
import picocli.CommandLine;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CloudBeaverCommandLine extends ApplicationCommandLine<ApplicationInstanceController> {
|
||||
private final CloudBeaverMixin mixin;
|
||||
|
||||
@@ -53,9 +56,10 @@ public class CloudBeaverCommandLine extends ApplicationCommandLine<ApplicationIn
|
||||
protected CommandLine initCommandLine(
|
||||
@Nullable ApplicationInstanceController applicationInstanceController,
|
||||
@NotNull CLIContextImpl context,
|
||||
@NotNull CLIRunMeta runMeta
|
||||
@NotNull CLIRunMeta runMeta,
|
||||
@NotNull List<CLICommandDescriptor> commandsToExecute
|
||||
) {
|
||||
var cmd = super.initCommandLine(applicationInstanceController, context, runMeta);
|
||||
var cmd = super.initCommandLine(applicationInstanceController, context, runMeta, commandsToExecute);
|
||||
cmd.addMixin("cloudbeaver", mixin);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Model
|
||||
Bundle-SymbolicName: io.cloudbeaver.model;singleton:=true
|
||||
Bundle-Version: 1.0.98.qualifier
|
||||
Bundle-Release-Date: 20260406
|
||||
Bundle-Version: 1.0.101.qualifier
|
||||
Bundle-Release-Date: 20260518
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: org.jkiss.dbeaver.data.gis;visibility:=reexport,
|
||||
@@ -17,7 +17,6 @@ Require-Bundle: org.jkiss.dbeaver.data.gis;visibility:=reexport,
|
||||
org.jkiss.bundle.logback;visibility:=reexport,
|
||||
org.jkiss.bundle.graphql;visibility:=reexport,
|
||||
org.jkiss.bundle.apache.dbcp,
|
||||
com.google.gson;visibility:=reexport,
|
||||
jakarta.servlet-api;bundle-version:="6.0.0";visibility:=reexport
|
||||
Export-Package: io.cloudbeaver,
|
||||
io.cloudbeaver.auth,
|
||||
@@ -29,6 +28,11 @@ Export-Package: io.cloudbeaver,
|
||||
io.cloudbeaver.websocket.event.client,
|
||||
io.cloudbeaver.websocket.event.task,
|
||||
io.cloudbeaver.model,
|
||||
io.cloudbeaver.model.api.annotation,
|
||||
io.cloudbeaver.model.api.annotation.enums,
|
||||
io.cloudbeaver.model.api.annotation.media,
|
||||
io.cloudbeaver.model.api.annotation.responses,
|
||||
io.cloudbeaver.model.api.annotation.tags,
|
||||
io.cloudbeaver.model.app,
|
||||
io.cloudbeaver.model.config,
|
||||
io.cloudbeaver.model.apilog,
|
||||
|
||||
@@ -25,6 +25,11 @@
|
||||
label="Default secret controller" description="Default void secret controller"/>
|
||||
</extension>
|
||||
|
||||
<extension point="io.cloudbeaver.feature">
|
||||
<feature id="ssh" label="SSH tunnels for databases" description="Enables SSH tunnels for secure database connections, allowing access to remote databases through encrypted channels" enabledByDefault="true"/>
|
||||
</extension>
|
||||
|
||||
|
||||
<extension point="org.jkiss.dbeaver.ws.event">
|
||||
<event topicId="cb_session_task" id="cb_session_task_info_updated"
|
||||
class="io.cloudbeaver.websocket.event.task.WSSessionTaskInfoEvent"/>
|
||||
@@ -46,6 +51,8 @@
|
||||
class="io.cloudbeaver.websocket.event.client.WSSessionTaskConfirmationEvent"/>
|
||||
<clientEvent id="cb_client_session_task_with_parameters_confirmation"
|
||||
class="io.cloudbeaver.websocket.event.client.WSSessionTaskWithParametersConfirmationEvent"/>
|
||||
<clientEvent id="cb_client_cancel_action"
|
||||
class="io.cloudbeaver.websocket.event.client.WSSessionCancelActionClientEvent"/>
|
||||
</extension>
|
||||
|
||||
</plugin>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.model</artifactId>
|
||||
<version>1.0.98-SNAPSHOT</version>
|
||||
<version>1.0.101-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
+5
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,6 +27,7 @@ import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
|
||||
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
|
||||
import org.jkiss.dbeaver.model.connection.DBPDriver;
|
||||
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
|
||||
import org.jkiss.dbeaver.registry.DataSourcePreferenceStore;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
public class WebConnectionConfigInputHandler<T extends WebConnectionConfig, C extends DataSourceDescriptor> {
|
||||
@@ -93,6 +94,9 @@ public class WebConnectionConfigInputHandler<T extends WebConnectionConfig, C ex
|
||||
input.isSharedCredentials()
|
||||
);
|
||||
dataSource.setConnectionReadOnly(input.isReadOnly());
|
||||
DataSourcePreferenceStore preferenceStore = dataSource.getPreferenceStore();
|
||||
preferenceStore.clear();
|
||||
preferenceStore.setProperties(input.getDefaultUserPreferences());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -407,12 +407,12 @@ public class WebGlobalProjectRegistryProxy implements DBPDataSourceRegistry, Dat
|
||||
}
|
||||
|
||||
@Override
|
||||
public void persistSecrets(DBSSecretController secretController) throws DBException {
|
||||
public void persistSecrets(@NotNull DBSSecretController secretController) throws DBException {
|
||||
dataSourceRegistry.persistSecrets(secretController);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolveSecrets(DBSSecretController secretController) throws DBException {
|
||||
public void resolveSecrets(@NotNull DBSSecretController secretController) throws DBException {
|
||||
dataSourceRegistry.resolveSecrets(secretController);
|
||||
}
|
||||
|
||||
|
||||
+15
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,6 +23,7 @@ import org.jkiss.dbeaver.model.data.json.JSONUtils;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -64,6 +65,8 @@ public class WebConnectionConfig {
|
||||
private Boolean defaultAutoCommit;
|
||||
private String defaultCatalogName;
|
||||
private String defaultSchemaName;
|
||||
@NotNull
|
||||
private Map<String, String> defaultUserPreferences = new LinkedHashMap<>();
|
||||
|
||||
public WebConnectionConfig() {
|
||||
}
|
||||
@@ -111,6 +114,8 @@ public class WebConnectionConfig {
|
||||
String configType = JSONUtils.getString(params, "configurationType");
|
||||
configurationType = configType == null ? null : DBPDriverConfigurationType.valueOf(configType);
|
||||
|
||||
Map<String, Object> stringObjectUserPrefMap = JSONUtils.getObject(params, "defaultUserPreferences");
|
||||
stringObjectUserPrefMap.forEach((key, value) -> defaultUserPreferences.put(key, value.toString()));
|
||||
networkHandlersConfig = new ArrayList<>();
|
||||
for (Map<String, Object> nhc : JSONUtils.getObjectList(params, "networkHandlersConfig")) {
|
||||
networkHandlersConfig.add(new WebNetworkHandlerConfigInput(nhc));
|
||||
@@ -367,4 +372,13 @@ public class WebConnectionConfig {
|
||||
public void setDefaultSchemaName(String defaultSchemaName) {
|
||||
this.defaultSchemaName = defaultSchemaName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<String, String> getDefaultUserPreferences() {
|
||||
return defaultUserPreferences;
|
||||
}
|
||||
|
||||
public void setDefaultUserPreferences(@NotNull Map<String, String> defaultUserPreferences) {
|
||||
this.defaultUserPreferences = defaultUserPreferences;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,11 +40,13 @@ import org.jkiss.dbeaver.model.impl.auth.AuthModelDatabaseNative;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings;
|
||||
import org.jkiss.dbeaver.model.navigator.DBNDataSource;
|
||||
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
|
||||
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
|
||||
import org.jkiss.dbeaver.model.preferences.DBPPropertySource;
|
||||
import org.jkiss.dbeaver.model.rm.RMConstants;
|
||||
import org.jkiss.dbeaver.model.rm.RMProjectPermission;
|
||||
import org.jkiss.dbeaver.model.runtime.DBRRunnableParametrized;
|
||||
import org.jkiss.dbeaver.registry.DataSourcePreferenceStore;
|
||||
import org.jkiss.dbeaver.registry.network.NetworkHandlerDescriptor;
|
||||
import org.jkiss.dbeaver.registry.network.NetworkHandlerRegistry;
|
||||
import org.jkiss.dbeaver.runtime.DBWorkbench;
|
||||
@@ -293,6 +295,16 @@ public class WebConnectionInfo {
|
||||
return dataSourceContainer.getNavigatorSettings().getOriginalSettings();
|
||||
}
|
||||
|
||||
@Property
|
||||
@NotNull
|
||||
public Map<String, String> getDefaultUserPreferences() {
|
||||
DBPPreferenceStore preferenceStore = dataSourceContainer.getPreferenceStore();
|
||||
if (preferenceStore instanceof DataSourcePreferenceStore dataSourcePreferenceStore) {
|
||||
return dataSourcePreferenceStore.getProperties();
|
||||
}
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@Property
|
||||
@NotNull
|
||||
public List<WebDataFormat> getSupportedDataFormats() {
|
||||
@@ -578,4 +590,5 @@ public class WebConnectionInfo {
|
||||
public void setCredentialsSavedInSession(@Nullable Boolean credentialsSavedInSession) {
|
||||
this.credentialsSavedInSession = credentialsSavedInSession;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-2
@@ -16,6 +16,8 @@
|
||||
*/
|
||||
package io.cloudbeaver.model;
|
||||
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.model.data.json.JSONUtils;
|
||||
import org.jkiss.dbeaver.model.net.DBWHandlerType;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
@@ -28,12 +30,14 @@ import java.util.Map;
|
||||
*/
|
||||
public class WebNetworkHandlerConfigInput {
|
||||
|
||||
@NotNull
|
||||
private final Map<String, Object> cfg;
|
||||
|
||||
public WebNetworkHandlerConfigInput(Map<String, Object> cfg) {
|
||||
public WebNetworkHandlerConfigInput(@NotNull Map<String, Object> cfg) {
|
||||
this.cfg = cfg;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public DBWHandlerType getType() {
|
||||
return CommonUtils.valueOf(DBWHandlerType.class, JSONUtils.getString(cfg, "type"), null);
|
||||
}
|
||||
@@ -42,6 +46,7 @@ public class WebNetworkHandlerConfigInput {
|
||||
return JSONUtils.getString(cfg, "id");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Boolean isEnabled() {
|
||||
if (cfg.containsKey("enabled")) {
|
||||
return JSONUtils.getBoolean(cfg, "enabled");
|
||||
@@ -62,11 +67,13 @@ public class WebNetworkHandlerConfigInput {
|
||||
return JSONUtils.getString(cfg, "password");
|
||||
}
|
||||
|
||||
@Deprecated // use secured properties
|
||||
// Deprecated. Use secured properties
|
||||
@Nullable
|
||||
public String getKey() {
|
||||
return JSONUtils.getString(cfg, "key");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Boolean isSavePassword() {
|
||||
if (cfg.containsKey("savePassword")) {
|
||||
return JSONUtils.getBoolean(cfg, "savePassword");
|
||||
@@ -75,10 +82,12 @@ public class WebNetworkHandlerConfigInput {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Map<String, Object> getProperties() {
|
||||
return JSONUtils.getObjectOrNull(cfg, "properties");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Map<String, String> getSecureProperties() {
|
||||
var secureProperties = JSONUtils.getObjectOrNull(cfg, "secureProperties");
|
||||
if (secureProperties == null) {
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed 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 io.cloudbeaver.model.api.annotation;
|
||||
|
||||
import io.cloudbeaver.model.api.annotation.responses.ApiResponse;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Operation {
|
||||
|
||||
String summary() default "";
|
||||
|
||||
String description() default "";
|
||||
|
||||
String operationId() default "";
|
||||
|
||||
String method() default "";
|
||||
|
||||
Parameter[] parameters() default {};
|
||||
|
||||
ApiResponse[] responses() default {};
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed 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 io.cloudbeaver.model.api.annotation;
|
||||
|
||||
import io.cloudbeaver.model.api.annotation.enums.Explode;
|
||||
import io.cloudbeaver.model.api.annotation.enums.ParameterIn;
|
||||
import io.cloudbeaver.model.api.annotation.enums.ParameterStyle;
|
||||
import io.cloudbeaver.model.api.annotation.media.ArraySchema;
|
||||
import io.cloudbeaver.model.api.annotation.media.Schema;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Repeatable(Parameters.class)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
|
||||
public @interface Parameter {
|
||||
|
||||
String name() default "";
|
||||
|
||||
String description() default "";
|
||||
|
||||
boolean required() default false;
|
||||
|
||||
String example() default "";
|
||||
|
||||
ParameterIn in() default ParameterIn.DEFAULT;
|
||||
|
||||
Schema schema() default @Schema;
|
||||
|
||||
ArraySchema array() default @ArraySchema;
|
||||
|
||||
ParameterStyle style() default ParameterStyle.DEFAULT;
|
||||
|
||||
Explode explode() default Explode.DEFAULT;
|
||||
|
||||
boolean hidden() default false;
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed 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 io.cloudbeaver.model.api.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
|
||||
public @interface Parameters {
|
||||
|
||||
Parameter[] value();
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed 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 io.cloudbeaver.model.api.annotation.enums;
|
||||
|
||||
public enum Explode {
|
||||
TRUE("true"),
|
||||
FALSE("false"),
|
||||
DEFAULT("default");
|
||||
|
||||
private final String value;
|
||||
|
||||
Explode(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed 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 io.cloudbeaver.model.api.annotation.enums;
|
||||
|
||||
public enum ParameterIn {
|
||||
DEFAULT("default"),
|
||||
QUERY("query"),
|
||||
HEADER("header"),
|
||||
PATH("path"),
|
||||
COOKIE("cookie");
|
||||
|
||||
private final String value;
|
||||
|
||||
ParameterIn(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed 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 io.cloudbeaver.model.api.annotation.enums;
|
||||
|
||||
public enum ParameterStyle {
|
||||
MATRIX("matrix"),
|
||||
LABEL("label"),
|
||||
FORM("form"),
|
||||
SIMPLE("simple"),
|
||||
SPACEDELIMITED("spaceDelimited"),
|
||||
PIPEDELIMITED("pipeDelimited"),
|
||||
DEEPOBJECT("deepObject"),
|
||||
DEFAULT("default");
|
||||
|
||||
private final String value;
|
||||
|
||||
ParameterStyle(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed 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 io.cloudbeaver.model.api.annotation.media;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
|
||||
public @interface ArraySchema {
|
||||
|
||||
Schema schema() default @Schema;
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed 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 io.cloudbeaver.model.api.annotation.media;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
public @interface Content {
|
||||
|
||||
Schema schema() default @Schema;
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed 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 io.cloudbeaver.model.api.annotation.media;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
|
||||
public @interface Schema {
|
||||
|
||||
String description() default "";
|
||||
|
||||
String example() default "";
|
||||
|
||||
String type() default "";
|
||||
|
||||
Class<?> implementation() default Void.class;
|
||||
|
||||
boolean required() default false;
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed 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 io.cloudbeaver.model.api.annotation.responses;
|
||||
|
||||
import io.cloudbeaver.model.api.annotation.media.Content;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
public @interface ApiResponse {
|
||||
|
||||
String responseCode() default "default";
|
||||
|
||||
String description() default "";
|
||||
|
||||
Content[] content() default {};
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed 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 io.cloudbeaver.model.api.annotation.tags;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface Tag {
|
||||
|
||||
String name() default "";
|
||||
|
||||
String description() default "";
|
||||
}
|
||||
+18
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,10 +25,13 @@ import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.DBFileController;
|
||||
import org.jkiss.dbeaver.model.app.DBPLockManagerProvider;
|
||||
import org.jkiss.dbeaver.model.app.DBPWorkspace;
|
||||
import org.jkiss.dbeaver.model.auth.SMCredentialsProvider;
|
||||
import org.jkiss.dbeaver.model.auth.SMSessionContext;
|
||||
import org.jkiss.dbeaver.model.data.json.JSONUtils;
|
||||
import org.jkiss.dbeaver.model.fs.lock.LockManager;
|
||||
import org.jkiss.dbeaver.model.fs.lock.shared.SharedFileLockManager;
|
||||
import org.jkiss.dbeaver.model.impl.app.ApplicationRegistry;
|
||||
import org.jkiss.dbeaver.model.impl.app.BaseApplicationImpl;
|
||||
import org.jkiss.dbeaver.model.impl.app.BaseWorkspaceImpl;
|
||||
@@ -48,7 +51,7 @@ import java.util.Map;
|
||||
/**
|
||||
* Servlet application
|
||||
*/
|
||||
public abstract class BaseServletApplication extends BaseApplicationImpl implements ServletApplication {
|
||||
public abstract class BaseServletApplication extends BaseApplicationImpl implements ServletApplication, DBPLockManagerProvider {
|
||||
|
||||
public static final String DEFAULT_CONFIG_FILE_PATH = "/etc/cloudbeaver.conf";
|
||||
public static final String CUSTOM_CONFIG_FOLDER = "custom";
|
||||
@@ -59,6 +62,7 @@ public abstract class BaseServletApplication extends BaseApplicationImpl impleme
|
||||
|
||||
private String instanceId;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public RMController createResourceController(
|
||||
@NotNull SMCredentialsProvider credentialsProvider,
|
||||
@@ -73,6 +77,18 @@ public abstract class BaseServletApplication extends BaseApplicationImpl impleme
|
||||
throw new IllegalStateException("File controller is not supported by " + getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public LockManager createLockManager(@NotNull String applicationId, @NotNull Path metadataFolder) throws DBException {
|
||||
return new SharedFileLockManager(applicationId, metadataFolder);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public LockManager createLockManager() throws DBException {
|
||||
return new SharedFileLockManager(getApplicationInstanceId());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Path getDefaultWorkingFolder() {
|
||||
|
||||
+10
-8
@@ -26,7 +26,9 @@ import org.jkiss.dbeaver.model.DBPDataSourceFolder;
|
||||
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
|
||||
import org.jkiss.dbeaver.model.app.DBPProject;
|
||||
import org.jkiss.dbeaver.model.app.DBPWorkspace;
|
||||
import org.jkiss.dbeaver.model.fs.lock.FileLockController;
|
||||
import org.jkiss.dbeaver.model.fs.lock.LockManager;
|
||||
import org.jkiss.dbeaver.model.fs.lock.LockOptions;
|
||||
import org.jkiss.dbeaver.model.fs.lock.LockTarget;
|
||||
import org.jkiss.dbeaver.model.rm.RMController;
|
||||
import org.jkiss.dbeaver.model.rm.RMEvent;
|
||||
import org.jkiss.dbeaver.model.rm.RMEventManager;
|
||||
@@ -53,11 +55,11 @@ public abstract class BaseLocalResourceController implements RMController {
|
||||
@NotNull
|
||||
protected final DBPWorkspace workspace;
|
||||
@NotNull
|
||||
protected final FileLockController lockController;
|
||||
protected final LockManager lockController;
|
||||
|
||||
protected BaseLocalResourceController(
|
||||
@NotNull DBPWorkspace workspace,
|
||||
@NotNull FileLockController lockController
|
||||
@NotNull LockManager lockController
|
||||
) {
|
||||
this.workspace = workspace;
|
||||
this.lockController = lockController;
|
||||
@@ -157,7 +159,7 @@ public abstract class BaseLocalResourceController implements RMController {
|
||||
@NotNull String configuration,
|
||||
@Nullable List<String> dataSourceIds
|
||||
) throws DBException {
|
||||
try (var ignoredLock = lockController.lock(projectId, "updateProjectDataSources")) {
|
||||
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("updateProjectDataSources"))) {
|
||||
DBPProject project = getWebProject(projectId, false);
|
||||
return doFileWriteOperation(
|
||||
projectId, project.getMetadataFolder(false),
|
||||
@@ -188,7 +190,7 @@ public abstract class BaseLocalResourceController implements RMController {
|
||||
@NotNull String projectId,
|
||||
@NotNull String[] dataSourceIds
|
||||
) throws DBException {
|
||||
try (var ignoredLock = lockController.lock(projectId, "deleteDataSources")) {
|
||||
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("deleteDataSources"))) {
|
||||
DBPProject project = getWebProject(projectId, false);
|
||||
doFileWriteOperation(projectId, project.getMetadataFolder(false), () -> {
|
||||
DBPDataSourceRegistry registry = project.getDataSourceRegistry();
|
||||
@@ -213,7 +215,7 @@ public abstract class BaseLocalResourceController implements RMController {
|
||||
@NotNull String projectId,
|
||||
@NotNull String folderPath
|
||||
) throws DBException {
|
||||
try (var ignoredLock = lockController.lock(projectId, "createDatasourceFolder")) {
|
||||
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("createDatasourceFolder"))) {
|
||||
DBPProject project = getWebProject(projectId, false);
|
||||
log.debug("Creating data source folder '" + folderPath + "' in project '" + projectId + "'");
|
||||
doFileWriteOperation(projectId, project.getMetadataFolder(false),
|
||||
@@ -241,7 +243,7 @@ public abstract class BaseLocalResourceController implements RMController {
|
||||
@NotNull String[] folderPaths,
|
||||
boolean dropContents
|
||||
) throws DBException {
|
||||
try (var ignoredLock = lockController.lock(projectId, "createDatasourceFolder")) {
|
||||
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("createDatasourceFolder"))) {
|
||||
DBPProject project = getWebProject(projectId, false);
|
||||
doFileWriteOperation(projectId, project.getMetadataFolder(false),
|
||||
() -> {
|
||||
@@ -267,7 +269,7 @@ public abstract class BaseLocalResourceController implements RMController {
|
||||
@NotNull String oldPath,
|
||||
@NotNull String newPath
|
||||
) throws DBException {
|
||||
try (var ignoredLock = lockController.lock(projectId, "createDatasourceFolder")) {
|
||||
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("createDatasourceFolder"))) {
|
||||
DBPProject project = getWebProject(projectId, false);
|
||||
log.debug("Moving data source folder from '" + oldPath + "' to '" + newPath + "' in project '" + projectId + "'");
|
||||
doFileWriteOperation(projectId, project.getMetadataFolder(false),
|
||||
|
||||
+44
-23
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -33,7 +33,9 @@ import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
|
||||
import org.jkiss.dbeaver.model.app.DBPWorkspace;
|
||||
import org.jkiss.dbeaver.model.auth.SMCredentials;
|
||||
import org.jkiss.dbeaver.model.auth.SMCredentialsProvider;
|
||||
import org.jkiss.dbeaver.model.fs.lock.FileLockController;
|
||||
import org.jkiss.dbeaver.model.fs.lock.LockManager;
|
||||
import org.jkiss.dbeaver.model.fs.lock.LockOptions;
|
||||
import org.jkiss.dbeaver.model.fs.lock.LockTarget;
|
||||
import org.jkiss.dbeaver.model.impl.app.BaseProjectImpl;
|
||||
import org.jkiss.dbeaver.model.impl.auth.SessionContextImpl;
|
||||
import org.jkiss.dbeaver.model.navigator.DBNLocalFolder;
|
||||
@@ -90,9 +92,10 @@ public class LocalResourceController extends BaseLocalResourceController {
|
||||
@NotNull Path rootPath,
|
||||
@NotNull Path userProjectsPath,
|
||||
@NotNull Path sharedProjectsPath,
|
||||
@NotNull Supplier<SMAdminController> smControllerSupplier
|
||||
@NotNull Supplier<SMAdminController> smControllerSupplier,
|
||||
@NotNull LockManager lockController
|
||||
) throws DBException {
|
||||
super(workspace, new FileLockController(ServletAppUtils.getServletApplication().getApplicationInstanceId()));
|
||||
super(workspace, lockController);
|
||||
this.credentialsProvider = credentialsProvider;
|
||||
this.rootPath = rootPath;
|
||||
this.userProjectsPath = userProjectsPath;
|
||||
@@ -101,7 +104,7 @@ public class LocalResourceController extends BaseLocalResourceController {
|
||||
|
||||
this.globalProjectName = DBWorkbench.getPlatform().getApplication().getDefaultProjectName();
|
||||
this.fileHandlers = RMFileOperationHandlersRegistry.getInstance().getFileHandlers();
|
||||
this.sharedProjectsMetadataInfo = new ProjectsMetadataInfo(sharedProjectsPath);
|
||||
this.sharedProjectsMetadataInfo = new ProjectsMetadataInfo(sharedProjectsPath, lockController);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -303,7 +306,7 @@ public class LocalResourceController extends BaseLocalResourceController {
|
||||
@Override
|
||||
public RMProject updateProject(@NotNull String projectId, @NotNull RMProjectInfo projectInfo) throws DBException {
|
||||
validateProjectName(projectId, projectInfo.getName());
|
||||
try (var ignoredLock = lockController.lock(projectId, "updateProject")) {
|
||||
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("updateProject"))) {
|
||||
RMLocalProject project = getWebProject(projectId, false);
|
||||
Path targetPath = getProjectPath(projectId);
|
||||
if (!Files.exists(targetPath)) {
|
||||
@@ -330,7 +333,7 @@ public class LocalResourceController extends BaseLocalResourceController {
|
||||
|
||||
@Override
|
||||
public void deleteProject(@NotNull String projectId) throws DBException {
|
||||
try (var ignoredLock = lockController.lock(projectId, "deleteProject")) {
|
||||
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("deleteProject"))) {
|
||||
Path targetPath = getProjectPath(projectId);
|
||||
if (!Files.exists(targetPath)) {
|
||||
log.error(MessageFormat.format("Project folder ''{0}'' is not found", projectId));
|
||||
@@ -699,7 +702,7 @@ public class LocalResourceController extends BaseLocalResourceController {
|
||||
@NotNull String resourcePath,
|
||||
boolean isFolder
|
||||
) throws DBException {
|
||||
try (var ignoredLock = lockController.lock(projectId, "createResource")) {
|
||||
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("createResource"))) {
|
||||
validateResourcePath(resourcePath);
|
||||
Path targetPath = getTargetPath(projectId, resourcePath);
|
||||
if (Files.exists(targetPath)) {
|
||||
@@ -731,7 +734,7 @@ public class LocalResourceController extends BaseLocalResourceController {
|
||||
@NotNull String oldResourcePath,
|
||||
@NotNull String newResourcePath
|
||||
) throws DBException {
|
||||
try (var ignoredLock = lockController.lock(projectId, "moveResource")) {
|
||||
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("moveResource"))) {
|
||||
var normalizedOldResourcePath = CommonUtils.normalizeResourcePath(oldResourcePath);
|
||||
var normalizedNewResourcePath = CommonUtils.normalizeResourcePath(newResourcePath);
|
||||
if (log.isDebugEnabled()) {
|
||||
@@ -803,7 +806,7 @@ public class LocalResourceController extends BaseLocalResourceController {
|
||||
|
||||
@Override
|
||||
public void deleteResource(@NotNull String projectId, @NotNull String resourcePath, boolean recursive) throws DBException {
|
||||
try (var ignoredLock = lockController.lock(projectId, "deleteResource")) {
|
||||
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("deleteResource"))) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Removing resource from '" + resourcePath + "' in project '" + projectId + "'" + (recursive ? " recursive" : ""));
|
||||
}
|
||||
@@ -891,7 +894,7 @@ public class LocalResourceController extends BaseLocalResourceController {
|
||||
@NotNull byte[] data,
|
||||
boolean forceOverwrite
|
||||
) throws DBException {
|
||||
try (var ignoredLock = lockController.lock(projectId, "setResourceContents")) {
|
||||
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("setResourceContents"))) {
|
||||
validateResourcePath(resourcePath);
|
||||
Number fileSizeLimit = ServletAppUtils.getServletApplication()
|
||||
.getAppConfiguration()
|
||||
@@ -936,7 +939,7 @@ public class LocalResourceController extends BaseLocalResourceController {
|
||||
@NotNull String propertyName,
|
||||
@Nullable Object propertyValue
|
||||
) throws DBException {
|
||||
try (var ignoredLock = lockController.lock(projectId, "resourcePropertyUpdate")) {
|
||||
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("resourcePropertyUpdate"))) {
|
||||
validateResourcePath(resourcePath);
|
||||
RMLocalProject webProject = getWebProject(projectId, false);
|
||||
doFileWriteOperation(projectId, webProject.getMetadataFilePath(),
|
||||
@@ -957,7 +960,7 @@ public class LocalResourceController extends BaseLocalResourceController {
|
||||
@NotNull String resourcePath,
|
||||
@NotNull Map<String, Object> properties
|
||||
) throws DBException {
|
||||
try (var ignoredLock = lockController.lock(projectId, "resourcePropertyUpdate")) {
|
||||
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("resourcePropertyUpdate"))) {
|
||||
validateResourcePath(resourcePath);
|
||||
RMLocalProject webProject = getWebProject(projectId, false);
|
||||
doFileWriteOperation(projectId, webProject.getMetadataFilePath(),
|
||||
@@ -1204,12 +1207,14 @@ public class LocalResourceController extends BaseLocalResourceController {
|
||||
return getProjectPath(projectId).toAbsolutePath().relativize(path).toString().replace('\\', IPath.SEPARATOR);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Builder builder(
|
||||
SMCredentialsProvider credentialsProvider,
|
||||
DBPWorkspace workspace,
|
||||
Supplier<SMAdminController> smControllerSupplier
|
||||
@NotNull SMCredentialsProvider credentialsProvider,
|
||||
@NotNull DBPWorkspace workspace,
|
||||
@NotNull LockManager lockController,
|
||||
@NotNull Supplier<SMAdminController> smControllerSupplier
|
||||
) {
|
||||
return new Builder(workspace, credentialsProvider, smControllerSupplier);
|
||||
return new Builder(workspace, credentialsProvider, lockController, smControllerSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1225,10 +1230,13 @@ public class LocalResourceController extends BaseLocalResourceController {
|
||||
protected Path rootPath;
|
||||
protected Path userProjectsPath;
|
||||
protected Path sharedProjectsPath;
|
||||
protected LockManager lockController;
|
||||
|
||||
protected Builder(
|
||||
DBPWorkspace workspace, SMCredentialsProvider credentialsProvider,
|
||||
Supplier<SMAdminController> smControllerSupplier
|
||||
@NotNull DBPWorkspace workspace,
|
||||
@NotNull SMCredentialsProvider credentialsProvider,
|
||||
@NotNull LockManager lockController,
|
||||
@NotNull Supplier<SMAdminController> smControllerSupplier
|
||||
) {
|
||||
this.workspace = workspace;
|
||||
this.credentialsProvider = credentialsProvider;
|
||||
@@ -1236,25 +1244,38 @@ public class LocalResourceController extends BaseLocalResourceController {
|
||||
this.rootPath = RMUtils.getRootPath();
|
||||
this.userProjectsPath = RMUtils.getUserProjectsPath();
|
||||
this.sharedProjectsPath = RMUtils.getSharedProjectsPath();
|
||||
this.lockController = lockController;
|
||||
}
|
||||
|
||||
public Builder setRootPath(Path rootPath) {
|
||||
@NotNull
|
||||
public Builder setRootPath(@NotNull Path rootPath) {
|
||||
this.rootPath = rootPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setUserProjectsPath(Path userProjectsPath) {
|
||||
@NotNull
|
||||
public Builder setUserProjectsPath(@NotNull Path userProjectsPath) {
|
||||
this.userProjectsPath = userProjectsPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setSharedProjectsPath(Path sharedProjectsPath) {
|
||||
@NotNull
|
||||
public Builder setSharedProjectsPath(@NotNull Path sharedProjectsPath) {
|
||||
this.sharedProjectsPath = sharedProjectsPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public LocalResourceController build() throws DBException {
|
||||
return new LocalResourceController(workspace, credentialsProvider, rootPath, userProjectsPath, sharedProjectsPath, smController);
|
||||
return new LocalResourceController(
|
||||
workspace,
|
||||
credentialsProvider,
|
||||
rootPath,
|
||||
userProjectsPath,
|
||||
sharedProjectsPath,
|
||||
smController,
|
||||
lockController
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-7
@@ -17,14 +17,15 @@
|
||||
package io.cloudbeaver.model.rm.local;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import io.cloudbeaver.utils.ServletAppUtils;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.app.DBPProject;
|
||||
import org.jkiss.dbeaver.model.data.json.JSONUtils;
|
||||
import org.jkiss.dbeaver.model.fs.lock.FileLockController;
|
||||
import org.jkiss.dbeaver.model.fs.lock.LockManager;
|
||||
import org.jkiss.dbeaver.model.fs.lock.LockOptions;
|
||||
import org.jkiss.dbeaver.model.fs.lock.LockTarget;
|
||||
import org.jkiss.dbeaver.model.impl.app.BaseProjectImpl;
|
||||
import org.jkiss.dbeaver.model.rm.RMProjectInfo;
|
||||
import org.jkiss.dbeaver.model.rm.RMProjectType;
|
||||
@@ -45,12 +46,12 @@ public class ProjectsMetadataInfo {
|
||||
|
||||
private final Map<String, RMProjectInfo> projectsInfo = new LinkedHashMap<>();
|
||||
private final Path projectsPath;
|
||||
private final FileLockController lockController;
|
||||
private final LockManager lockController;
|
||||
|
||||
|
||||
public ProjectsMetadataInfo(@NotNull Path projectsPath) throws DBException {
|
||||
public ProjectsMetadataInfo(@NotNull Path projectsPath, @NotNull LockManager lockController) throws DBException {
|
||||
this.projectsPath = projectsPath;
|
||||
this.lockController = new FileLockController(ServletAppUtils.getServletApplication().getApplicationInstanceId());
|
||||
this.lockController = lockController;
|
||||
readProjectInfos(projectsPath);
|
||||
}
|
||||
|
||||
@@ -139,7 +140,7 @@ public class ProjectsMetadataInfo {
|
||||
}
|
||||
|
||||
private void saveProjectsInfo() {
|
||||
try (var lock = lockController.lock(PROJECTS_INFO_FILE_NAME, "saveProjectsInfo")) {
|
||||
try (var lock = lockController.lock(LockTarget.of(PROJECTS_INFO_FILE_NAME), LockOptions.of("saveProjectsInfo"))) {
|
||||
log.info("Saving project information");
|
||||
Files.writeString(projectsPath.resolve(PROJECTS_INFO_FILE_NAME), JSONUtils.GSON.toJson(projectsInfo));
|
||||
} catch (IOException e) {
|
||||
@@ -148,4 +149,4 @@ public class ProjectsMetadataInfo {
|
||||
log.error("Error locking file " + PROJECTS_INFO_FILE_NAME + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-4
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -55,14 +55,21 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
|
||||
@NotNull
|
||||
protected final ServletApplication application;
|
||||
protected volatile long lastAccessTime;
|
||||
@NotNull
|
||||
private final SessionType sessionType;
|
||||
|
||||
private final List<CBWebSessionEventHandler> sessionEventHandlers = new CopyOnWriteArrayList<>();
|
||||
private WebSessionEventsFilter eventsFilter;
|
||||
private final WebSessionWorkspace workspace;
|
||||
|
||||
public BaseWebSession(@NotNull String id, @NotNull ServletApplication application) throws DBException {
|
||||
public BaseWebSession(
|
||||
@NotNull String id,
|
||||
@NotNull ServletApplication application,
|
||||
@NotNull SessionType sessionType
|
||||
) throws DBException {
|
||||
this.id = id;
|
||||
this.application = application;
|
||||
this.sessionType = sessionType;
|
||||
this.createTime = System.currentTimeMillis();
|
||||
this.lastAccessTime = this.createTime;
|
||||
this.workspace = createWebWorkspace();
|
||||
@@ -151,7 +158,7 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
|
||||
}
|
||||
|
||||
protected synchronized void clearSessionContext() {
|
||||
this.workspace.getAuthContext().clear();
|
||||
this.workspace.getAuthContext().clearContext(false);
|
||||
this.workspace.getAuthContext().addSession(this);
|
||||
}
|
||||
|
||||
@@ -176,6 +183,11 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
|
||||
return lastAccessTime;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public SessionType getSessionType() {
|
||||
return sessionType;
|
||||
}
|
||||
|
||||
public void touchSession() {
|
||||
this.lastAccessTime = System.currentTimeMillis();
|
||||
}
|
||||
@@ -187,12 +199,13 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
super.close();
|
||||
cleanUpSession(true);
|
||||
super.close();
|
||||
}
|
||||
|
||||
public void close(boolean clearTokens, boolean sendSessionExpiredEvent) {
|
||||
cleanUpSession(sendSessionExpiredEvent);
|
||||
super.close();
|
||||
}
|
||||
|
||||
private void cleanUpSession(boolean sendSessionExpiredEvent) {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed 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 io.cloudbeaver.model.session;
|
||||
|
||||
public enum SessionType {
|
||||
WEB,
|
||||
HEADLESS,
|
||||
API_TOKEN
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,7 +31,7 @@ public class WebHeadlessSession extends BaseWebSession {
|
||||
@NotNull String id,
|
||||
@NotNull ServletAuthApplication application
|
||||
) throws DBException {
|
||||
super(id, application);
|
||||
super(id, application, SessionType.HEADLESS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+25
-4
@@ -17,6 +17,7 @@
|
||||
package io.cloudbeaver.model.session;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.utils.HttpConstants;
|
||||
|
||||
@@ -31,12 +32,16 @@ public class WebHttpRequestInfo {
|
||||
private final String lastRemoteAddress;
|
||||
@Nullable
|
||||
private final String lastRemoteUserAgent;
|
||||
@NotNull
|
||||
private final SessionType sessionType;
|
||||
|
||||
public WebHttpRequestInfo(HttpServletRequest request) {
|
||||
this.id = request.getSession() == null ? null : request.getSession().getId();
|
||||
this.locale = request.getAttribute("locale");
|
||||
this.lastRemoteAddress = request.getRemoteAddr();
|
||||
this.lastRemoteUserAgent = request.getHeader(USER_AGENT);
|
||||
this(
|
||||
request.getSession() == null ? null : request.getSession().getId(),
|
||||
request.getAttribute("locale"),
|
||||
request.getRemoteAddr(),
|
||||
request.getHeader(USER_AGENT)
|
||||
);
|
||||
}
|
||||
|
||||
public WebHttpRequestInfo(
|
||||
@@ -44,11 +49,22 @@ public class WebHttpRequestInfo {
|
||||
@Nullable Object locale,
|
||||
@Nullable String lastRemoteAddress,
|
||||
@Nullable String lastRemoteUserAgent
|
||||
) {
|
||||
this(id, locale, lastRemoteAddress, lastRemoteUserAgent, SessionType.WEB);
|
||||
}
|
||||
|
||||
public WebHttpRequestInfo(
|
||||
@Nullable String id,
|
||||
@Nullable Object locale,
|
||||
@Nullable String lastRemoteAddress,
|
||||
@Nullable String lastRemoteUserAgent,
|
||||
@NotNull SessionType sessionType
|
||||
) {
|
||||
this.id = id;
|
||||
this.locale = locale;
|
||||
this.lastRemoteAddress = lastRemoteAddress;
|
||||
this.lastRemoteUserAgent = lastRemoteUserAgent;
|
||||
this.sessionType = sessionType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -70,4 +86,9 @@ public class WebHttpRequestInfo {
|
||||
public String getLastRemoteUserAgent() {
|
||||
return lastRemoteUserAgent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public SessionType getSessionType() {
|
||||
return sessionType;
|
||||
}
|
||||
}
|
||||
|
||||
+27
-6
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -116,7 +116,8 @@ public class WebSession extends BaseWebSession
|
||||
CommonUtils.toString(requestInfo.getLocale()),
|
||||
application,
|
||||
sessionHandlers,
|
||||
requestInfo.getLastRemoteAddress()
|
||||
requestInfo.getLastRemoteAddress(),
|
||||
requestInfo.getSessionType()
|
||||
);
|
||||
updateSessionParameters(requestInfo);
|
||||
}
|
||||
@@ -128,7 +129,18 @@ public class WebSession extends BaseWebSession
|
||||
@NotNull Map<String, DBWSessionHandler<WebSession>> sessionHandlers,
|
||||
@Nullable String remoteAddr
|
||||
) throws DBException {
|
||||
super(id, application);
|
||||
this(id, locale, application, sessionHandlers, remoteAddr, SessionType.WEB);
|
||||
}
|
||||
|
||||
protected WebSession(
|
||||
@NotNull String id,
|
||||
@Nullable String locale,
|
||||
@NotNull ServletApplication application,
|
||||
@NotNull Map<String, DBWSessionHandler<WebSession>> sessionHandlers,
|
||||
@Nullable String remoteAddr,
|
||||
@NotNull SessionType sessionType
|
||||
) throws DBException {
|
||||
super(id, application, sessionType);
|
||||
if (CommonUtils.isEmpty(remoteAddr)) {
|
||||
throw new DBException("Remote address cannot be empty");
|
||||
}
|
||||
@@ -492,7 +504,6 @@ public class WebSession extends BaseWebSession
|
||||
public void close() {
|
||||
try {
|
||||
resetNavigationModel();
|
||||
resetSessionCache();
|
||||
} catch (Throwable e) {
|
||||
log.error(e);
|
||||
}
|
||||
@@ -509,7 +520,6 @@ public class WebSession extends BaseWebSession
|
||||
public void close(boolean clearTokens, boolean sendSessionExpiredEvent) {
|
||||
try {
|
||||
resetNavigationModel();
|
||||
resetSessionCache();
|
||||
} catch (Throwable e) {
|
||||
log.error(e);
|
||||
}
|
||||
@@ -609,11 +619,13 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public WebAsyncTaskInfo createAndRunAsyncTask(@NotNull String taskName, @NotNull WebAsyncTaskProcessor<?> runnable) {
|
||||
WebAsyncTaskInfo asyncTask = createAsyncTask(taskName);
|
||||
return runAsyncTask(asyncTask, runnable);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public WebAsyncTaskInfo runAsyncTask(@NotNull WebAsyncTaskInfo asyncTask, @NotNull WebAsyncTaskProcessor<?> runnable) {
|
||||
AbstractJob job = new AbstractCancelableJob(asyncTask.getName()) {
|
||||
@NotNull
|
||||
@@ -1037,7 +1049,6 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void handleTaskConfirmationWithParameters(@NotNull String taskId, @NotNull Map<String, Object> parameters) {
|
||||
String attributeName = getTaskConfirmationAttributeName(taskId);
|
||||
CompletableFuture<Map<String, Object>> confirmationFuture = getAttribute(attributeName);
|
||||
@@ -1049,6 +1060,16 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
}
|
||||
|
||||
public void handleActionCancelledEvent(@NotNull String actionId) {
|
||||
Object attributeValue = getAttribute(actionId);
|
||||
if (!(attributeValue instanceof CompletableFuture<?> future)) {
|
||||
log.info("Action to be cancelled not found, skipping: " + actionId);
|
||||
return;
|
||||
}
|
||||
future.completeExceptionally(new DBWebException("Action cancelled by user: " + actionId));
|
||||
removeAttribute(actionId);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getTaskConfirmationAttributeName(@NotNull String taskId) {
|
||||
return WebSQLConstants.TASK_CONFIRMATION_ATTR_PREFIX + taskId;
|
||||
|
||||
+6
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@
|
||||
package io.cloudbeaver.model.session;
|
||||
|
||||
import io.cloudbeaver.WebSessionProjectImpl;
|
||||
import io.cloudbeaver.utils.ServletAppUtils;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
@@ -199,12 +200,15 @@ public class WebSessionWorkspace implements DBPWorkspace {
|
||||
|
||||
@Override
|
||||
public boolean hasRealmPermission(@NotNull String permission) {
|
||||
if (getWebSession() instanceof WebSession webSession) {
|
||||
return webSession.getSessionPermissions().contains(permission);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsRealmFeature(@NotNull String feature) {
|
||||
return false;
|
||||
return ServletAppUtils.getServletApplication().getAppConfiguration().isFeatureEnabled(feature);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,6 +31,8 @@ import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
|
||||
import org.jkiss.dbeaver.model.security.SMAuthCredentialsProfile;
|
||||
import org.jkiss.dbeaver.model.security.SMAuthProviderDescriptor;
|
||||
import org.jkiss.dbeaver.model.security.SMSubjectType;
|
||||
import org.jkiss.dbeaver.utils.GeneralUtils;
|
||||
import org.jkiss.dbeaver.utils.SystemVariablesResolver;
|
||||
import org.jkiss.utils.ArrayUtils;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
@@ -110,7 +112,9 @@ public class WebAuthProviderDescriptor extends AbstractDescriptor {
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return cfg.getAttribute(WebRegistryConstant.ATTR_DESCRIPTION);
|
||||
return GeneralUtils.replaceVariables(
|
||||
cfg.getAttribute(WebRegistryConstant.ATTR_DESCRIPTION), SystemVariablesResolver.INSTANCE
|
||||
);
|
||||
}
|
||||
|
||||
public DBPImage getIcon() {
|
||||
|
||||
+16
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,11 +20,14 @@ import io.cloudbeaver.WebProjectImpl;
|
||||
import io.cloudbeaver.model.app.ServletApplication;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.app.DBPPlatform;
|
||||
import org.jkiss.dbeaver.model.app.DBPProject;
|
||||
import org.jkiss.dbeaver.model.auth.SMSession;
|
||||
import org.jkiss.dbeaver.model.impl.app.BaseProjectImpl;
|
||||
import org.jkiss.dbeaver.model.impl.app.BaseWorkspaceImpl;
|
||||
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -55,8 +58,14 @@ public class ServerGlobalWorkspace extends BaseWorkspaceImpl {
|
||||
this.application = application;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public void initializeProjects() {
|
||||
protected SMSession acquireWorkspaceSession(@NotNull DBRProgressMonitor monitor) throws DBException {
|
||||
return new ServerGlobalWorkspaceSession(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeProjects() throws DBException {
|
||||
initializeWorkspaceSession();
|
||||
|
||||
// Load global project
|
||||
@@ -106,4 +115,9 @@ public class ServerGlobalWorkspace extends BaseWorkspaceImpl {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsRealmFeature(@NotNull String feature) {
|
||||
return application.getAppConfiguration().isFeatureEnabled(feature);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed 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 io.cloudbeaver.server;
|
||||
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.model.app.DBPWorkspace;
|
||||
import org.jkiss.dbeaver.model.impl.app.LocalWorkspaceSession;
|
||||
import org.jkiss.dbeaver.model.secret.DBSSecretController;
|
||||
|
||||
public class ServerGlobalWorkspaceSession extends LocalWorkspaceSession {
|
||||
|
||||
public ServerGlobalWorkspaceSession(@NotNull DBPWorkspace workspace) {
|
||||
super(workspace);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public DBSSecretController getSecretController() {
|
||||
return super.getSecretController();
|
||||
}
|
||||
}
|
||||
@@ -193,8 +193,12 @@ public class ServletAppUtils {
|
||||
@NotNull String origin
|
||||
) throws DBException {
|
||||
String finalOrigin = webAuthApplication.modifyOrigin(origin);
|
||||
StringBuilder authUriBuilder = new StringBuilder(removeSideSlashes(finalOrigin));
|
||||
String serviceUriSegment = removeSideSlashes(webAuthApplication.getAuthServiceUriSegment());
|
||||
String rootUri = removeSideSlashes(getServletApplication().getRootURI());
|
||||
if (finalOrigin.endsWith("/" + rootUri) && serviceUriSegment.startsWith(rootUri + "/")) {
|
||||
finalOrigin = finalOrigin.substring(0, finalOrigin.length() - rootUri.length());
|
||||
}
|
||||
StringBuilder authUriBuilder = new StringBuilder(removeSideSlashes(finalOrigin));
|
||||
if (CommonUtils.isNotEmpty(serviceUriSegment)) {
|
||||
authUriBuilder.append("/").append(serviceUriSegment);
|
||||
}
|
||||
@@ -305,12 +309,6 @@ public class ServletAppUtils {
|
||||
log.trace("X-Origin header: " + origin);
|
||||
}
|
||||
}
|
||||
if (CommonUtils.isEmpty(origin)) {
|
||||
origin = request.getHeader(HEADER_REFERER);
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Referer header: " + origin);
|
||||
}
|
||||
}
|
||||
String forwardedScheme = request.getHeader(HEADER_FORWARDED_SCHEME);
|
||||
if (CommonUtils.isEmpty(forwardedScheme)) {
|
||||
forwardedScheme = request.getHeader(HEADER_FORWARDED_PROTO);
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed 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 io.cloudbeaver.websocket.event.client;
|
||||
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.websocket.WSConstants;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSClientEvent;
|
||||
|
||||
public class WSSessionCancelActionClientEvent extends WSClientEvent {
|
||||
public static final String ID = "cb_client_cancel_action";
|
||||
|
||||
@NotNull
|
||||
private final String actionId;
|
||||
|
||||
public WSSessionCancelActionClientEvent(
|
||||
@NotNull String actionId
|
||||
) {
|
||||
super(ID, WSConstants.TOPIC_SESSION_ACTION);
|
||||
this.actionId = actionId;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getActionId() {
|
||||
return actionId;
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Community Product
|
||||
Bundle-SymbolicName: io.cloudbeaver.product.ce;singleton:=true
|
||||
Bundle-Version: 26.0.2.qualifier
|
||||
Bundle-Release-Date: 20260406
|
||||
Bundle-Version: 26.0.5.qualifier
|
||||
Bundle-Release-Date: 20260518
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server.ce
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.product.ce</artifactId>
|
||||
<version>26.0.2-SNAPSHOT</version>
|
||||
<version>26.0.5-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -2,8 +2,8 @@ Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Cloudbeaver Base JDBC drivers
|
||||
Bundle-SymbolicName: io.cloudbeaver.resources.drivers.base;singleton:=true
|
||||
Bundle-Version: 1.0.143.qualifier
|
||||
Bundle-Release-Date: 20260406
|
||||
Bundle-Version: 1.0.146.qualifier
|
||||
Bundle-Release-Date: 20260518
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Automatic-Module-Name: io.cloudbeaver.resources.drivers.base
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<resource name="drivers/jaybird"/>
|
||||
<resource name="drivers/h2"/>
|
||||
<resource name="drivers/h2_v2"/>
|
||||
<resource name="drivers/h2_v3"/>
|
||||
<resource name="drivers/sqlite/xerial"/>
|
||||
<resource name="drivers/mssql/new"/>
|
||||
<resource name="drivers/trino"/>
|
||||
@@ -35,6 +36,7 @@
|
||||
<bundle id="drivers.firebird" label="Firebird drivers"/>
|
||||
<bundle id="drivers.h2" label="H2 drivers"/>
|
||||
<bundle id="drivers.h2_v2" label="H2 v2 drivers"/>
|
||||
<bundle id="drivers.h2_v3" label="H2 v3 drivers"/>
|
||||
<bundle id="drivers.sqlite.xerial" label="SQLite drivers"/>
|
||||
<bundle id="drivers.mssql.new" label="SQL Server drivers"/>
|
||||
<bundle id="drivers.trino" label="Trino drivers"/>
|
||||
@@ -55,6 +57,7 @@
|
||||
<driver id="clickhouse:com_clickhouse"/>
|
||||
<driver id="h2:h2_embedded"/>
|
||||
<driver id="h2:h2_embedded_v2"/>
|
||||
<driver id="h2:h2_embedded_v3"/>
|
||||
<driver id="sqlite:sqlite_jdbc"/>
|
||||
<driver id="sqlite:libsql_jdbc"/>
|
||||
<driver id="sqlserver:microsoft"/>
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.resources.drivers.base</artifactId>
|
||||
<version>1.0.143-SNAPSHOT</version>
|
||||
<version>1.0.146-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: CloudBeaver Community
|
||||
Bundle-SymbolicName: io.cloudbeaver.server.ce;singleton:=true
|
||||
Bundle-Version: 26.0.2.qualifier
|
||||
Bundle-Release-Date: 20260406
|
||||
Bundle-Version: 26.0.5.qualifier
|
||||
Bundle-Release-Date: 20260518
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-Activator: io.cloudbeaver.server.CBPlatformActivator
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.server.ce</artifactId>
|
||||
<version>26.0.2-SNAPSHOT</version>
|
||||
<version>26.0.5-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
+8
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package io.cloudbeaver.server;
|
||||
|
||||
import graphql.execution.instrumentation.Instrumentation;
|
||||
import io.cloudbeaver.WebServiceUtils;
|
||||
import io.cloudbeaver.auth.NoAuthCredentialsProvider;
|
||||
import io.cloudbeaver.model.CBWebServerConfig;
|
||||
@@ -29,6 +30,7 @@ import io.cloudbeaver.model.config.CBAppConfig;
|
||||
import io.cloudbeaver.model.config.CBServerConfig;
|
||||
import io.cloudbeaver.registry.WebDriverRegistry;
|
||||
import io.cloudbeaver.registry.WebServiceRegistry;
|
||||
import io.cloudbeaver.server.graphql.GraphQLEndpoint;
|
||||
import io.cloudbeaver.server.jetty.CBJettyServer;
|
||||
import io.cloudbeaver.service.DBWServiceInitializer;
|
||||
import io.cloudbeaver.service.DBWServiceServerConfigurator;
|
||||
@@ -685,6 +687,11 @@ public abstract class CBApplication<T extends CBServerConfig>
|
||||
return new CBSessionManager(this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public GraphQLEndpoint createGraphQLEndpoint(@NotNull Instrumentation instrumentation) {
|
||||
return new GraphQLEndpoint(instrumentation);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public WebDriverRegistry getDriverRegistry() {
|
||||
return WebDriverRegistry.getInstance();
|
||||
|
||||
+9
-6
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -75,13 +75,16 @@ public class CBApplicationCE extends CBApplication<CBServerConfig> {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public RMController createResourceController(@NotNull SMCredentialsProvider credentialsProvider,
|
||||
@NotNull DBPWorkspace workspace) throws DBException {
|
||||
return LocalResourceController.builder(credentialsProvider, workspace, this::getSecurityController).build();
|
||||
public RMController createResourceController(
|
||||
@NotNull SMCredentialsProvider credentialsProvider,
|
||||
@NotNull DBPWorkspace workspace
|
||||
) throws DBException {
|
||||
var lockManager = createLockManager();
|
||||
return LocalResourceController
|
||||
.builder(credentialsProvider, workspace, lockManager, this::getSecurityController)
|
||||
.build();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,6 +21,7 @@ import io.cloudbeaver.server.jobs.SessionStateJob;
|
||||
import io.cloudbeaver.server.jobs.WebDataSourceMonitorJob;
|
||||
import io.cloudbeaver.server.jobs.WebSessionMonitorJob;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.app.DBPRegistryListener;
|
||||
import org.jkiss.dbeaver.model.impl.app.BaseApplicationImpl;
|
||||
@@ -51,7 +52,7 @@ public class CBPlatform extends BaseWebPlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void initialize() {
|
||||
protected synchronized void initialize() throws DBException {
|
||||
long startTime = System.currentTimeMillis();
|
||||
log.info("Initialize web platform " + getClass().getSimpleName());
|
||||
this.preferenceStore = new WebServerPreferenceStore(WebPlatformActivator.getInstance().getPreferences());
|
||||
|
||||
+6
-2
@@ -24,6 +24,7 @@ import io.cloudbeaver.server.CBConstants;
|
||||
import io.cloudbeaver.server.filters.ServerConfigurationTimeLimitFilter;
|
||||
import io.cloudbeaver.server.graphql.GraphQLEndpoint;
|
||||
import io.cloudbeaver.server.servlets.CBImageServlet;
|
||||
import io.cloudbeaver.server.servlets.CBManifestServlet;
|
||||
import io.cloudbeaver.server.servlets.CBStaticServlet;
|
||||
import io.cloudbeaver.server.servlets.WebStatusServlet;
|
||||
import io.cloudbeaver.server.websockets.CBEventsLongPollingServlet;
|
||||
@@ -119,12 +120,15 @@ public class CBJettyServer {
|
||||
ServletHolder imagesServletHolder = new ServletHolder("images", new CBImageServlet());
|
||||
servletContextHandler.addServlet(imagesServletHolder, serverConfiguration.getServicesURI() + "images/*");
|
||||
|
||||
ServletHolder manifestServletHolder = new ServletHolder("manifest", new CBManifestServlet(contentRootPath));
|
||||
servletContextHandler.addServlet(manifestServletHolder, "/manifest.webmanifest");
|
||||
|
||||
servletContextHandler.addServlet(new ServletHolder("status", new WebStatusServlet()), "/status");
|
||||
|
||||
ServletHolder eventsServletHolder = new ServletHolder("events", new CBEventsLongPollingServlet());
|
||||
servletContextHandler.addServlet(eventsServletHolder, serverConfiguration.getServicesURI() + "events/*");
|
||||
|
||||
GraphQLEndpoint endpoint = new GraphQLEndpoint(new ServerConfigurationTimeLimitFilter(application));
|
||||
GraphQLEndpoint endpoint = application.createGraphQLEndpoint(new ServerConfigurationTimeLimitFilter(application));
|
||||
application.addApplicationContextValue(GraphQL.class.getName(), endpoint.getGraphQL());
|
||||
String gqlServletPath = serverConfiguration.getServicesURI() + "gql/*";
|
||||
servletContextHandler.addServlet(
|
||||
@@ -257,4 +261,4 @@ public class CBJettyServer {
|
||||
cbSessionHandler.setSecureCookies(application.getServerConfiguration().isForceHttps());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed 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 io.cloudbeaver.server.servlets;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import io.cloudbeaver.model.config.CBServerConfig;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.annotation.WebServlet;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.utils.MimeTypes;
|
||||
import org.jkiss.utils.IOUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@WebServlet(urlPatterns = "/manifest.webmanifest")
|
||||
public class CBManifestServlet extends HttpServlet {
|
||||
|
||||
private static final Log log = Log.getLog(CBManifestServlet.class);
|
||||
private static final String MANIFEST_FILE = "manifest.webmanifest";
|
||||
|
||||
// Fix: Create Gson instance with HTML escaping disabled to prevent \u003d escaping
|
||||
private static final Gson GSON = new GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.disableHtmlEscaping() // This prevents escaping = to \u003d
|
||||
.create();
|
||||
|
||||
@NotNull
|
||||
private final Path contentRoot;
|
||||
|
||||
public CBManifestServlet(@NotNull Path contentRoot) {
|
||||
this.contentRoot = contentRoot;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
Path manifestPath = contentRoot.resolve(MANIFEST_FILE).normalize();
|
||||
|
||||
if (!manifestPath.startsWith(contentRoot) || !Files.exists(manifestPath)) {
|
||||
log.error("Manifest file not found or path is invalid: " + manifestPath);
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Read the original manifest file
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (InputStream fis = Files.newInputStream(manifestPath)) {
|
||||
IOUtils.copyStream(fis, baos);
|
||||
}
|
||||
String manifestContent = baos.toString(StandardCharsets.UTF_8);
|
||||
|
||||
// Parse the JSON and update dynamic fields
|
||||
CBServerConfig serverConfig = CBApplication.getInstance().getServerConfiguration();
|
||||
String rootURI = serverConfig.getRootURI();
|
||||
|
||||
// Ensure rootURI ends with / for proper scope and path handling
|
||||
String normalizedRootURI = rootURI;
|
||||
if (!normalizedRootURI.endsWith("/")) {
|
||||
normalizedRootURI += "/";
|
||||
}
|
||||
|
||||
// Use JsonParser to parse the existing manifest
|
||||
JsonObject manifest = JsonParser.parseString(manifestContent).getAsJsonObject();
|
||||
|
||||
// Update scope to match the rootURI
|
||||
manifest.addProperty("scope", normalizedRootURI);
|
||||
|
||||
// Update start_url and id to match the rootURI
|
||||
String startUrl = normalizedRootURI + "?source=pwa";
|
||||
manifest.addProperty("start_url", startUrl);
|
||||
manifest.addProperty("id", startUrl);
|
||||
|
||||
// Convert back to JSON string using the Gson instance with HTML escaping disabled
|
||||
String updatedManifest = GSON.toJson(manifest);
|
||||
byte[] manifestBytes = updatedManifest.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
// Set appropriate headers
|
||||
response.setHeader(HttpHeader.CONTENT_TYPE.toString(), "application/manifest+json");
|
||||
response.setHeader(HttpHeader.CACHE_CONTROL.toString(), "no-cache, no-store, must-revalidate");
|
||||
response.setHeader(HttpHeader.EXPIRES.toString(), "0");
|
||||
response.setContentLength(manifestBytes.length);
|
||||
|
||||
// Write the response
|
||||
response.getOutputStream().write(manifestBytes);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Error processing manifest file", e);
|
||||
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
+59
-1
@@ -51,7 +51,7 @@ public class CBSessionManager implements WebAppSessionManager {
|
||||
private static final Log log = Log.getLog(CBSessionManager.class);
|
||||
|
||||
private final CBApplication<?> application;
|
||||
private final Map<String, BaseWebSession> sessionMap = new HashMap<>();
|
||||
protected final Map<String, BaseWebSession> sessionMap = new HashMap<>();
|
||||
|
||||
public CBSessionManager(CBApplication<?> application) {
|
||||
this.application = application;
|
||||
@@ -379,6 +379,63 @@ public class CBSessionManager implements WebAppSessionManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public WebSession getWebSession(
|
||||
@Nullable String smAccessToken,
|
||||
@NotNull WebHttpRequestInfo requestInfo,
|
||||
boolean create
|
||||
) throws DBException {
|
||||
if (CommonUtils.isEmpty(smAccessToken)) {
|
||||
return null;
|
||||
}
|
||||
synchronized (sessionMap) {
|
||||
var tempCredProvider = new SMTokenCredentialProvider(smAccessToken);
|
||||
SMAuthPermissions authPermissions = application.createSecurityController(tempCredProvider).getTokenPermissions();
|
||||
var sessionId = requestInfo.getId() != null ? requestInfo.getId()
|
||||
: authPermissions.getSessionId();
|
||||
|
||||
var existSession = sessionMap.get(sessionId);
|
||||
|
||||
if (existSession instanceof WebSession webSession) {
|
||||
var creds = webSession.getUserContext().getActiveUserCredentials();
|
||||
if (creds == null || !smAccessToken.equals(creds.getSmAccessToken())) {
|
||||
if (webSession.getUserContext().refresh(
|
||||
smAccessToken,
|
||||
null,
|
||||
authPermissions
|
||||
)) {
|
||||
webSession.refreshUserData();
|
||||
}
|
||||
}
|
||||
return webSession;
|
||||
}
|
||||
if (existSession != null) {
|
||||
//session exist but it not web session
|
||||
return null;
|
||||
}
|
||||
if (!create) {
|
||||
return null;
|
||||
}
|
||||
if (requestInfo.getId() == null) {
|
||||
requestInfo = new WebHttpRequestInfo(
|
||||
sessionId,
|
||||
requestInfo.getLocale(),
|
||||
requestInfo.getLastRemoteAddress(),
|
||||
requestInfo.getLastRemoteUserAgent()
|
||||
);
|
||||
}
|
||||
var webSession = createWebSessionImpl(requestInfo);
|
||||
webSession.getUserContext().refresh(
|
||||
smAccessToken,
|
||||
null,
|
||||
authPermissions
|
||||
);
|
||||
webSession.refreshUserData();
|
||||
sessionMap.put(sessionId, webSession);
|
||||
return webSession;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send session state with remaining alive time to all cached session
|
||||
*/
|
||||
@@ -470,4 +527,5 @@ public class CBSessionManager implements WebAppSessionManager {
|
||||
log.debug("> Expire session '" + session.getSessionId() + "'");
|
||||
session.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,17 +3,13 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Server
|
||||
Bundle-SymbolicName: io.cloudbeaver.server;singleton:=true
|
||||
Bundle-Version: 26.0.2.qualifier
|
||||
Bundle-Release-Date: 20260406
|
||||
Bundle-Version: 26.0.5.qualifier
|
||||
Bundle-Release-Date: 20260518
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: org.eclipse.core.runtime;visibility:=reexport,
|
||||
org.apache.commons.jexl,
|
||||
org.jkiss.utils;visibility:=reexport,
|
||||
org.jkiss.dbeaver.model.sql;visibility:=reexport,
|
||||
Require-Bundle: org.jkiss.dbeaver.model.sql;visibility:=reexport,
|
||||
org.jkiss.dbeaver.data.gis,
|
||||
org.jkiss.bundle.jetty.server;visibility:=reexport,
|
||||
com.google.gson;visibility:=reexport,
|
||||
org.jkiss.bundle.graphql;visibility:=reexport,
|
||||
org.jkiss.bundle.apache.dbcp,
|
||||
org.jkiss.dbeaver.net.ssh,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.server</artifactId>
|
||||
<version>26.0.2-SNAPSHOT</version>
|
||||
<version>26.0.5-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -565,6 +565,8 @@ type ConnectionInfo {
|
||||
requiredAuth: String
|
||||
defaultCatalogName: String @since(version: "25.0.5")
|
||||
defaultSchemaName: String @since(version: "25.0.5")
|
||||
"Default user settings for connection"
|
||||
defaultUserPreferences: Object @since(version: "26.0.2")
|
||||
|
||||
"List of tools that can be used with this connection. Returns empty list if no tools are available"
|
||||
tools: [String!]! @since(version: "24.1.3")
|
||||
@@ -741,6 +743,8 @@ input ConnectionConfig {
|
||||
defaultCatalogName: String @since(version: "25.0.5") @deprecated(reason: "25.2.1 use expertPropertyValues instead")
|
||||
"Sets schema name for the connection"
|
||||
defaultSchemaName: String @since(version: "25.0.5") @deprecated(reason: "25.2.1 use expertPropertyValues instead")
|
||||
"Default user settings for connection"
|
||||
defaultUserPreferences: Object @since(version: "26.0.2")
|
||||
}
|
||||
|
||||
####################################################
|
||||
@@ -846,6 +850,7 @@ extend type Mutation {
|
||||
"Sets to default navigator settings for connection. Resets all user navigator settings for this connection."
|
||||
clearConnectionNavigatorSettings(projectId: ID!, id: ID!): ConnectionInfo! @since(version: "25.3.2")
|
||||
|
||||
setObjectSettingsForDatasource(id: ID!, projectId:ID, settings: Object!): Object! @since(version: "25.3.5")
|
||||
#### Generic async functions
|
||||
|
||||
"Cancel async task by ID"
|
||||
|
||||
@@ -38,7 +38,8 @@ enum CBClientEventId {
|
||||
cb_client_topic_subscribe,
|
||||
cb_client_topic_unsubscribe,
|
||||
cb_client_projects_active,
|
||||
cb_client_session_ping
|
||||
cb_client_session_ping,
|
||||
cb_client_cancel_action @since(version: "26.0.2")
|
||||
}
|
||||
|
||||
"Client subscribes on topic to receive only related events"
|
||||
@@ -136,6 +137,13 @@ type CBProjectsActiveEvent implements CBClientEvent {
|
||||
projectIds: [String!]!
|
||||
}
|
||||
|
||||
"Action cancelled by user"
|
||||
type CBActionCancelledEvent implements CBClientEvent @since(version: "26.0.2") {
|
||||
id: CBClientEventId!
|
||||
topicId: CBEventTopic
|
||||
actionId: String!
|
||||
}
|
||||
|
||||
"Async task info status event"
|
||||
type WSAsyncTaskInfo @since(version: "24.3.1") {
|
||||
id: CBServerEventId!
|
||||
@@ -167,6 +175,7 @@ type WSOpenUrlEvent implements CBServerEvent @since(version: "25.3.1") {
|
||||
topicId: CBEventTopic!
|
||||
timestamp: Int!
|
||||
url: String!
|
||||
actionId: String!
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
|
||||
@@ -228,6 +228,10 @@ type DataTypeLogicalOperation {
|
||||
type SQLExecutionPlan {
|
||||
query: String!
|
||||
nodes: [SQLExecutionPlanNode!]!
|
||||
hasCost: Boolean! @since(version: "26.0.3")
|
||||
hasRows: Boolean! @since(version: "26.0.3")
|
||||
hasDuration: Boolean! @since(version: "26.0.3")
|
||||
durationMeasure: String @since(version: "26.0.3")
|
||||
}
|
||||
|
||||
type SQLExecutionPlanNode {
|
||||
@@ -240,6 +244,10 @@ type SQLExecutionPlanNode {
|
||||
condition: String
|
||||
description: String
|
||||
properties: [ObjectPropertyInfo!]!
|
||||
cost: Float @since(version: "26.0.3")
|
||||
rowCount: Float @since(version: "26.0.3")
|
||||
duration: Float @since(version: "26.0.3")
|
||||
percent: Float @since(version: "26.0.3")
|
||||
}
|
||||
|
||||
####################################################
|
||||
@@ -254,6 +262,11 @@ type SQLQueryGenerator {
|
||||
multiObject: Boolean!
|
||||
}
|
||||
|
||||
input SQLQueryGeneratorOptions {
|
||||
useFullyQualifiedNames: Boolean!
|
||||
compactSql: Boolean!
|
||||
}
|
||||
|
||||
####################################################
|
||||
# SQL Query info
|
||||
####################################################
|
||||
@@ -338,19 +351,12 @@ extend type Query {
|
||||
|
||||
"""
|
||||
Generates SQL query for the specified entity query generator.
|
||||
Available options:
|
||||
fullyQualifiedNames - Use fully qualified names for entities
|
||||
compactSQL - Use compact SQL format
|
||||
showComments - Show comments in generated SQL
|
||||
showPermissions - Show permissions in generated SQL
|
||||
showFullDdl - Show full DDL in generated SQL
|
||||
excludeAutoGeneratedColumn - Exclude auto-generated columns in generated SQL
|
||||
useCustomDataFormat - Use custom data format for generated SQL
|
||||
"""
|
||||
sqlGenerateEntityQuery(
|
||||
generatorId: String!,
|
||||
options: Object!,
|
||||
nodePathList: [String!]!
|
||||
options: Object @deprecated(reason: "use generatorOptions (26.0.3)")
|
||||
nodePathList: [String!]!,
|
||||
generatorOptions: SQLQueryGeneratorOptions
|
||||
): String!
|
||||
|
||||
"""
|
||||
@@ -364,6 +370,7 @@ extend type Query {
|
||||
generatorId: SQLResultSetGeneratorId!,
|
||||
resultsId: ID!,
|
||||
selectedRows: [SQLResultRow!]!,
|
||||
generatorOptions: SQLQueryGeneratorOptions
|
||||
): String!
|
||||
|
||||
"Parses SQL script and returns script info with queries start and end positions"
|
||||
|
||||
+2
-13
@@ -20,10 +20,7 @@ import io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.WebServiceUtils;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.utils.WebCommonUtils;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.DBConstants;
|
||||
import org.jkiss.dbeaver.model.connection.DBPAuthModelDescriptor;
|
||||
import org.jkiss.dbeaver.model.impl.auth.AuthModelDatabaseNative;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
|
||||
import org.jkiss.dbeaver.model.preferences.DBPPropertySource;
|
||||
@@ -77,6 +74,7 @@ public class WebDatabaseAuthModel {
|
||||
|
||||
@Property
|
||||
public WebPropertyInfo[] getProperties() throws DBWebException {
|
||||
|
||||
DBPPropertySource credentialsSource = model.createCredentialsSource(null, null);
|
||||
Predicate<DBPPropertyDescriptor> predicate = CommonUtils.isEmpty(getRequiredAuth())
|
||||
? p -> true
|
||||
@@ -84,18 +82,9 @@ public class WebDatabaseAuthModel {
|
||||
|
||||
return Arrays.stream(credentialsSource.getProperties())
|
||||
.filter(predicate)
|
||||
.filter(p -> !isPassword(p) || isPasswordApplicable())
|
||||
.filter(p -> !p.isDesktop())
|
||||
.map(p -> new WebPropertyInfo(webSession, p, credentialsSource))
|
||||
.toArray(WebPropertyInfo[]::new);
|
||||
.map(p -> new WebPropertyInfo(webSession, p, credentialsSource)).toArray(WebPropertyInfo[]::new);
|
||||
}
|
||||
|
||||
private boolean isPassword(@NotNull DBPPropertyDescriptor property) {
|
||||
return property.hasFeature(DBConstants.PROP_FEATURE_PASSWORD);
|
||||
}
|
||||
|
||||
private boolean isPasswordApplicable() {
|
||||
return model.getInstance() instanceof AuthModelDatabaseNative<?> nativeModel &&
|
||||
nativeModel.isUserPasswordApplicable();
|
||||
}
|
||||
}
|
||||
|
||||
+19
@@ -23,6 +23,7 @@ import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.DBConstants;
|
||||
import org.jkiss.dbeaver.model.connection.*;
|
||||
import org.jkiss.dbeaver.model.impl.PropertyDescriptor;
|
||||
import org.jkiss.dbeaver.model.impl.auth.AuthModelDatabaseNative;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
|
||||
@@ -186,10 +187,28 @@ public class WebDatabaseDriverInfo {
|
||||
cfg.setDatabaseName(driver.getDefaultDatabase());
|
||||
cfg.setUrl(driver.getConnectionURL(cfg));
|
||||
DBPPropertyDescriptor[] properties = driver.getDataSourceProvider().getConnectionProperties(webSession.getProgressMonitor(), driver, cfg);
|
||||
Map<String, Object> connectionProperties = driver.getConnectionProperties();
|
||||
for (Map.Entry<String, Object> connProp : connectionProperties.entrySet()) {
|
||||
String propName = connProp.getKey();
|
||||
Object propValue = connProp.getValue();
|
||||
DBPPropertyDescriptor dbpPropertyDescriptor = new PropertyDescriptor(
|
||||
null,
|
||||
propName,
|
||||
propName,
|
||||
null,
|
||||
false,
|
||||
String.class,
|
||||
propValue,
|
||||
null
|
||||
);
|
||||
properties = ArrayUtils.add(DBPPropertyDescriptor.class, properties, dbpPropertyDescriptor);
|
||||
cfg.setProperty(propName, (String) propValue);
|
||||
}
|
||||
if (properties == null) {
|
||||
return new WebPropertyInfo[0];
|
||||
}
|
||||
|
||||
|
||||
PropertySourceCustom propertySource = new PropertySourceCustom(
|
||||
properties,
|
||||
cfg.getProperties());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,6 +19,7 @@ package io.cloudbeaver.server;
|
||||
import io.cloudbeaver.server.websockets.WebSocketPingPongJob;
|
||||
import org.eclipse.core.runtime.Plugin;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.model.DBConstants;
|
||||
import org.jkiss.dbeaver.model.app.DBACertificateStorage;
|
||||
import org.jkiss.dbeaver.model.app.DBPWorkspace;
|
||||
@@ -35,7 +36,7 @@ public abstract class BaseWebPlatform extends BaseServletPlatform {
|
||||
private ServerGlobalWorkspace workspace;
|
||||
|
||||
@Override
|
||||
protected synchronized void initialize() {
|
||||
protected synchronized void initialize() throws DBException {
|
||||
// Register BC security provider
|
||||
SecurityProviderUtils.registerSecurityProvider();
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
+53
-16
@@ -239,6 +239,14 @@ public class GraphQLEndpoint extends HttpServlet {
|
||||
@Nullable Map<String, Object> variables,
|
||||
@Nullable String operationName
|
||||
) throws IOException {
|
||||
|
||||
String userId = GraphQLLoggerUtil.getUserId(request);
|
||||
LocalDateTime startTime = LocalDateTime.now();
|
||||
|
||||
if (isQueryHandledBeforeExecution(request, response, variables, operationName, userId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> mapOfContext =
|
||||
Map.of(
|
||||
"request", request,
|
||||
@@ -254,8 +262,6 @@ public class GraphQLEndpoint extends HttpServlet {
|
||||
if (operationName != null) {
|
||||
contextBuilder.operationName(operationName);
|
||||
}
|
||||
String userId = GraphQLLoggerUtil.getUserId(request);
|
||||
LocalDateTime startTime = LocalDateTime.now();
|
||||
ExecutionInput executionInput = contextBuilder.build();
|
||||
ExecutionResult executionResult = null;
|
||||
Exception executionException = null;
|
||||
@@ -271,23 +277,54 @@ public class GraphQLEndpoint extends HttpServlet {
|
||||
} else if (executionException != null) {
|
||||
errorMessage = executionException.getMessage();
|
||||
}
|
||||
if (WebAppUtils.getWebApplication() instanceof ApiCallInterceptor apiCallInterceptor) {
|
||||
apiCallInterceptor.onApiCallEvent(
|
||||
request,
|
||||
variables,
|
||||
CommonUtils.notEmpty(operationName), userId, startTime,
|
||||
errorMessage,
|
||||
API_PROTOCOL
|
||||
);
|
||||
}
|
||||
notifyApiCallInterceptor(request, variables, operationName, userId, startTime, errorMessage);
|
||||
}
|
||||
|
||||
if (executionResult != null) {
|
||||
Map<String, Object> resJSON = executionResult.toSpecification();
|
||||
String resString = gson.toJson(resJSON);
|
||||
setDevelHeaders(request, response);
|
||||
response.setContentType(GraphQLConstants.CONTENT_TYPE_JSON_UTF8);
|
||||
response.getWriter().print(resString);
|
||||
writeExecutionResult(request, response, executionResult);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isQueryHandledBeforeExecution(
|
||||
@NotNull HttpServletRequest request,
|
||||
@NotNull HttpServletResponse response,
|
||||
@Nullable Map<String, Object> variables,
|
||||
@Nullable String operationName,
|
||||
@Nullable String userId
|
||||
) throws IOException {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void writeExecutionResult(
|
||||
@NotNull HttpServletRequest request,
|
||||
@NotNull HttpServletResponse response,
|
||||
@NotNull ExecutionResult executionResult
|
||||
) throws IOException {
|
||||
Map<String, Object> resJSON = executionResult.toSpecification();
|
||||
String resString = gson.toJson(resJSON);
|
||||
setDevelHeaders(request, response);
|
||||
response.setContentType(GraphQLConstants.CONTENT_TYPE_JSON_UTF8);
|
||||
response.getWriter().print(resString);
|
||||
}
|
||||
|
||||
protected void notifyApiCallInterceptor(
|
||||
@NotNull HttpServletRequest request,
|
||||
@Nullable Map<String, Object> variables,
|
||||
@Nullable String operationName,
|
||||
@Nullable String userId,
|
||||
@NotNull LocalDateTime startTime,
|
||||
@Nullable String errorMessage
|
||||
) {
|
||||
if (WebAppUtils.getWebApplication() instanceof ApiCallInterceptor apiCallInterceptor) {
|
||||
apiCallInterceptor.onApiCallEvent(
|
||||
request,
|
||||
variables,
|
||||
CommonUtils.notEmpty(operationName),
|
||||
userId,
|
||||
startTime,
|
||||
errorMessage,
|
||||
API_PROTOCOL
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,6 +27,7 @@ import jakarta.servlet.ServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.model.navigator.DBNNode;
|
||||
import org.jkiss.dbeaver.model.qm.QMConstants;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
@@ -122,6 +123,9 @@ public class GraphQLLoggerUtil {
|
||||
if (value instanceof String sv && CommonUtils.isEmpty(sv)) {
|
||||
continue;
|
||||
}
|
||||
if (value instanceof DBNNode node) {
|
||||
value = node.getNodeUri();
|
||||
}
|
||||
|
||||
if (value != null && !isSimple(value.getClass())) {
|
||||
String stringValue;
|
||||
|
||||
+21
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,6 +25,8 @@ import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.websocket.WSUtils;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSClientEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.registry.WSClientEventDescriptor;
|
||||
import org.jkiss.dbeaver.model.websocket.registry.WSEventRegistry;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
public class CBClientEventProcessor {
|
||||
@@ -50,6 +52,17 @@ public class CBClientEventProcessor {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle with custom handlers
|
||||
WSClientEventDescriptor ced = WSEventRegistry.getInstance().getClientEvent(clientEvent.getId());
|
||||
if (ced != null && ced.getHandler() != null) {
|
||||
try {
|
||||
ced.getHandler().handleEvent(webSession, clientEvent);
|
||||
} catch (Exception e) {
|
||||
log.error("Error handling event '" + clientEvent.getId() + "'", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (clientEvent.getId()) {
|
||||
case WSSubscribeOnTopicClientEvent.ID: {
|
||||
webSession.getEventsFilter().subscribeOnEventTopic(clientEvent.getTopicId());
|
||||
@@ -91,6 +104,13 @@ public class CBClientEventProcessor {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WSSessionCancelActionClientEvent.ID: {
|
||||
if (webSession instanceof WebSession session) {
|
||||
var cancelActionEvent = (WSSessionCancelActionClientEvent) clientEvent;
|
||||
session.handleActionCancelledEvent(cancelActionEvent.getActionId());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
var e = new DBWebException("Unknown client event: " + clientEvent.getId());
|
||||
log.error(e.getMessage(), e);
|
||||
|
||||
+3
-4
@@ -24,7 +24,6 @@ import jakarta.websocket.HandshakeResponse;
|
||||
import jakarta.websocket.server.HandshakeRequest;
|
||||
import jakarta.websocket.server.ServerEndpointConfig;
|
||||
import org.eclipse.jetty.ee11.websocket.jakarta.server.internal.JakartaWebSocketCreator;
|
||||
import org.eclipse.jetty.http.BadMessageException;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
@@ -89,7 +88,7 @@ public class CBWebSocketServerConfigurator extends ServerEndpointConfig.Configur
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
if (sec.getUserProperties().get(PROP_WEB_SESSION) == null) {
|
||||
throw new BadMessageException("No web session found for websocket request");
|
||||
throw new RuntimeException("No web session found for websocket request");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,8 +96,8 @@ public class CBWebSocketServerConfigurator extends ServerEndpointConfig.Configur
|
||||
private String getSessionId(@NotNull HandshakeRequest request) {
|
||||
// complex auth uses bearer authentication
|
||||
List<String> authHeaders = WSClientUtils.getHeaders(request.getHeaders(), HttpConstants.HEADER_AUTHORIZATION);
|
||||
if (!CommonUtils.isEmpty(authHeaders) && authHeaders.get(0).startsWith("Bearer ")) {
|
||||
return authHeaders.get(0).substring(7);
|
||||
if (!CommonUtils.isEmpty(authHeaders) && authHeaders.getFirst().startsWith(HttpConstants.BEARER_PREFIX)) {
|
||||
return authHeaders.getFirst().substring(7);
|
||||
}
|
||||
return request.getHttpSession() instanceof HttpSession httpSession ? httpSession.getId() : null;
|
||||
}
|
||||
|
||||
+8
-8
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -108,11 +108,7 @@ public abstract class WebServiceBindingBase<API_TYPE extends DBWService> impleme
|
||||
}
|
||||
|
||||
protected static WebSession getWebSession(DataFetchingEnvironment env) throws DBWebException {
|
||||
if (env.getGraphQlContext().getBoolean(CloudbeaverCliConstants.CLI_MODE)) {
|
||||
return getSessionFromContextOrThrow(env);
|
||||
}
|
||||
return WebAppUtils.getWebApplication().getSessionManager().getWebSession(
|
||||
GraphQLEndpoint.getServletRequestOrThrow(env), getServletResponse(env));
|
||||
return getWebSession(env, true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -353,9 +349,13 @@ public abstract class WebServiceBindingBase<API_TYPE extends DBWService> impleme
|
||||
}
|
||||
String sessionId = GraphQLLoggerUtil.getSmSessionId(request);
|
||||
String userId = GraphQLLoggerUtil.getUserId(request);
|
||||
String loggerMessage = GraphQLLoggerUtil.buildLoggerMessage(sessionId, userId, method, args);
|
||||
try {
|
||||
String loggerMessage = GraphQLLoggerUtil.buildLoggerMessage(sessionId, userId, method, args);
|
||||
|
||||
log.debug("API > " + method.getName() + loggerMessage);
|
||||
log.debug("API > " + method.getName() + loggerMessage);
|
||||
} catch (Throwable e) {
|
||||
log.error("Logging error", e);
|
||||
}
|
||||
|
||||
setLogContext(method, args);
|
||||
}
|
||||
|
||||
+10
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.model.rm.RMConstants;
|
||||
import org.jkiss.dbeaver.registry.DataSourceNavigatorSettings;
|
||||
import org.jkiss.dbeaver.registry.settings.ProductSettingDescriptor;
|
||||
@@ -218,6 +219,14 @@ public interface DBWServiceCore extends DBWService {
|
||||
@NotNull String id
|
||||
) throws DBWebException;
|
||||
|
||||
@NotNull
|
||||
Map<String, String> setObjectSettingsForDatasource(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull String projectId,
|
||||
@NotNull String objectId,
|
||||
@NotNull Map<String, String> settings
|
||||
) throws DBException;
|
||||
|
||||
///////////////////////////////////////////
|
||||
// Async tasks
|
||||
|
||||
|
||||
+6
@@ -163,6 +163,12 @@ public class WebServiceBindingCore extends WebServiceBindingBase<DBWServiceCore>
|
||||
getArgumentVal(env, "id")
|
||||
)
|
||||
)
|
||||
.dataFetcher("setObjectSettingsForDatasource", env -> getService(env).setObjectSettingsForDatasource(
|
||||
getWebSession(env),
|
||||
getProjectReference(env),
|
||||
getArgumentVal(env, "id"),
|
||||
getArgumentVal(env, "settings")
|
||||
))
|
||||
|
||||
.dataFetcher("asyncTaskInfo", env -> getService(env).getAsyncTaskInfo(
|
||||
getWebSession(env),
|
||||
|
||||
+22
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -58,12 +58,14 @@ import org.jkiss.dbeaver.model.rm.RMProjectType;
|
||||
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
|
||||
import org.jkiss.dbeaver.model.secret.DBSSecretController;
|
||||
import org.jkiss.dbeaver.model.secret.DBSSecretValue;
|
||||
import org.jkiss.dbeaver.model.security.SMObjectType;
|
||||
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
|
||||
import org.jkiss.dbeaver.registry.DataSourceNavigatorSettings;
|
||||
import org.jkiss.dbeaver.registry.DataSourceNavigatorSettingsUtils;
|
||||
import org.jkiss.dbeaver.registry.DataSourceProviderRegistry;
|
||||
import org.jkiss.dbeaver.registry.network.NetworkHandlerDescriptor;
|
||||
import org.jkiss.dbeaver.registry.network.NetworkHandlerRegistry;
|
||||
import org.jkiss.dbeaver.registry.project.BaseProjectSettings;
|
||||
import org.jkiss.dbeaver.registry.settings.ProductSettingDescriptor;
|
||||
import org.jkiss.dbeaver.registry.settings.ProductSettingsRegistry;
|
||||
import org.jkiss.dbeaver.runtime.DBWorkbench;
|
||||
@@ -795,6 +797,25 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
return connectionInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Map<String, String> setObjectSettingsForDatasource(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull String projectId,
|
||||
@NotNull String objectId,
|
||||
@NotNull Map<String, String> settings
|
||||
) throws DBException {
|
||||
|
||||
WebSessionProjectImpl projectById = webSession.getProjectById(projectId);
|
||||
if (projectById == null) {
|
||||
throw new DBWebException("Project '" + projectId + "' not found");
|
||||
}
|
||||
BaseProjectSettings projectSettings = projectById.getProjectSettings();
|
||||
projectSettings.setObjectSettings(SMObjectType.datasource, objectId, settings);
|
||||
Map<String, String> objectSettings = projectSettings.getObjectSettings(SMObjectType.datasource, objectId);
|
||||
return objectSettings == null ? new HashMap<>() : objectSettings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebAsyncTaskInfo getAsyncTaskInfo(WebSession webSession, String taskId, Boolean removeOnFinish)
|
||||
throws DBWebException {
|
||||
|
||||
+6
-5
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -63,11 +63,12 @@ public interface DBWServiceNavigator extends DBWService {
|
||||
@Nullable Boolean recursive) throws DBWebException;
|
||||
|
||||
@WebAction
|
||||
@NotNull
|
||||
WebStructContainers getStructContainers(
|
||||
String projectId,
|
||||
WebConnectionInfo connectionInfo,
|
||||
String contextId,
|
||||
String catalog) throws DBWebException;
|
||||
@NotNull String projectId,
|
||||
@NotNull WebConnectionInfo connectionInfo,
|
||||
@NotNull String contextId,
|
||||
@Nullable String catalog) throws DBWebException;
|
||||
|
||||
@WebAction
|
||||
String renameNode(
|
||||
|
||||
+52
-31
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -60,7 +60,6 @@ import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Web service implementation
|
||||
@@ -314,12 +313,13 @@ public class WebServiceNavigator implements DBWServiceNavigator {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public WebStructContainers getStructContainers(
|
||||
String projectId,
|
||||
WebConnectionInfo connection,
|
||||
String contextId,
|
||||
String catalog
|
||||
@NotNull String projectId,
|
||||
@NotNull WebConnectionInfo connection,
|
||||
@NotNull String contextId,
|
||||
@Nullable String catalog
|
||||
) throws DBWebException {
|
||||
DBPDataSource dataSource = connection.getDataSource();
|
||||
DBCExecutionContext executionContext = DBUtils.getDefaultContext(connection.getDataSource(), false);
|
||||
@@ -344,9 +344,9 @@ public class WebServiceNavigator implements DBWServiceNavigator {
|
||||
|
||||
DBRProgressMonitor monitor = connection.getSession().getProgressMonitor();
|
||||
List<? extends DBSObject> dbsObjects = this.getCatalogs(
|
||||
monitor,
|
||||
connection.getDataSourceContainer().getDataSource(),
|
||||
contextDefaults);
|
||||
monitor,
|
||||
connection.getDataSourceContainer().getDataSource(),
|
||||
contextDefaults);
|
||||
|
||||
for (DBSObject dbsObject : dbsObjects) {
|
||||
if (!dataSource.getContainer().getNavigatorSettings().isShowSystemObjects()
|
||||
@@ -404,26 +404,36 @@ public class WebServiceNavigator implements DBWServiceNavigator {
|
||||
return structContainers;
|
||||
}
|
||||
|
||||
protected List<? extends DBSObject> getCatalogs(DBRProgressMonitor monitor, DBSObject rootObject, DBCExecutionContextDefaults<?, ?> contextDefaults) throws DBWebException {
|
||||
if (rootObject instanceof DBSObjectContainer) {
|
||||
@NotNull
|
||||
protected List<? extends DBSObject> getCatalogs(
|
||||
@NotNull DBRProgressMonitor monitor,
|
||||
@NotNull DBSObject rootObject,
|
||||
@Nullable DBCExecutionContextDefaults<?, ?> contextDefaults
|
||||
) throws DBWebException {
|
||||
if (rootObject instanceof DBSObjectContainer objectContainer) {
|
||||
try {
|
||||
Collection<? extends DBSObject> objectsCollection;
|
||||
if (rootObject instanceof DBSCatalog && contextDefaults != null && !contextDefaults.supportsCatalogChange()) {
|
||||
objectsCollection = Collections.singletonList(contextDefaults.getDefaultCatalog());
|
||||
} else {
|
||||
objectsCollection = ((DBSObjectContainer) rootObject).getChildren(monitor);
|
||||
objectsCollection = objectContainer.getChildren(monitor);
|
||||
}
|
||||
if (objectsCollection == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return new ArrayList<>(objectsCollection);
|
||||
} catch (DBException e) {
|
||||
throw new DBWebException("Error reading context defaults", e);
|
||||
// return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected WebNavigatorNodeInfo getNodeFromObject(WebSession session, DBSObject object) throws DBWebException {
|
||||
protected WebNavigatorNodeInfo getNodeFromObject(
|
||||
@NotNull WebSession session,
|
||||
@NotNull DBSObject object
|
||||
) throws DBWebException {
|
||||
DBRProgressMonitor monitor = session.getProgressMonitor();
|
||||
DBNNode node = session.getNavigatorModelOrThrow().getNodeByObject(monitor, object, false);
|
||||
|
||||
@@ -454,10 +464,10 @@ public class WebServiceNavigator implements DBWServiceNavigator {
|
||||
}
|
||||
return node.getNodeItemPath();
|
||||
}
|
||||
if (node instanceof DBNDatabaseNode) {
|
||||
if (node instanceof DBNDatabaseNode dbNode) {
|
||||
return renameDatabaseObject(
|
||||
session,
|
||||
(DBNDatabaseNode) node,
|
||||
dbNode,
|
||||
CommonUtils.trim(CommonUtils.notEmpty(newName)));
|
||||
}
|
||||
throw new DBException("Rename is not supported");
|
||||
@@ -466,7 +476,11 @@ public class WebServiceNavigator implements DBWServiceNavigator {
|
||||
}
|
||||
}
|
||||
|
||||
private void renameConnectionFolder(@NotNull WebSession session, DBNNode node, @NotNull String newName) throws DBException {
|
||||
private void renameConnectionFolder(
|
||||
@NotNull WebSession session,
|
||||
DBNNode node,
|
||||
@NotNull String newName
|
||||
) throws DBException {
|
||||
WebConnectionFolderUtils.validateConnectionFolder(newName);
|
||||
DBNNode[] children = ((DBNLocalFolder) node).getLogicalParent().getChildren(session.getProgressMonitor());
|
||||
if (children != null) {
|
||||
@@ -480,7 +494,11 @@ public class WebServiceNavigator implements DBWServiceNavigator {
|
||||
node.rename(session.getProgressMonitor(), newName);
|
||||
}
|
||||
|
||||
private void renameRmResourceNode(@NotNull WebSession session, DBNNode node, @NotNull String newName) throws DBException {
|
||||
private void renameRmResourceNode(
|
||||
@NotNull WebSession session,
|
||||
DBNNode node,
|
||||
@NotNull String newName
|
||||
) throws DBException {
|
||||
if (newName.contains("/") || newName.contains("\\")) {
|
||||
throw new DBWebException("New node name has prohibited symbols: \\ /");
|
||||
}
|
||||
@@ -496,9 +514,9 @@ public class WebServiceNavigator implements DBWServiceNavigator {
|
||||
|
||||
private void addRmMoveEvent(
|
||||
@NotNull WebSession session,
|
||||
String projectId,
|
||||
String oldResourcePath,
|
||||
String newResourcePath
|
||||
@NotNull String projectId,
|
||||
@NotNull String oldResourcePath,
|
||||
@NotNull String newResourcePath
|
||||
) {
|
||||
WebEventUtils.addRmResourceUpdatedEvent(
|
||||
projectId,
|
||||
@@ -566,8 +584,7 @@ public class WebServiceNavigator implements DBWServiceNavigator {
|
||||
}
|
||||
} else if (node instanceof DBNLocalFolder) {
|
||||
node.getOwnerProject().getDataSourceRegistry().removeFolder(((DBNLocalFolder) node).getFolder(), false);
|
||||
} else if (node instanceof DBNResourceManagerResource) {
|
||||
DBNResourceManagerResource rmResource = ((DBNResourceManagerResource) node);
|
||||
} else if (node instanceof DBNResourceManagerResource rmResource) {
|
||||
String resourceProjectId = rmResource.getResourceProject().getId();
|
||||
String resourcePath = rmResource.getResourceFolder();
|
||||
session.getRmController().deleteResource(resourceProjectId, resourcePath, true);
|
||||
@@ -589,14 +606,18 @@ public class WebServiceNavigator implements DBWServiceNavigator {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkProjectEditAccess(DBNNode node, WebSession session) throws DBException {
|
||||
private void checkProjectEditAccess(@NotNull DBNNode node, @NotNull WebSession session) throws DBException {
|
||||
BaseWebProjectImpl project = (BaseWebProjectImpl) node.getOwnerProject();
|
||||
if (project == null || !hasNodeEditPermission(session, node, project.getRMProject())) {
|
||||
throw new DBException("Access denied");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasNodeEditPermission(WebSession session, DBNNode node, RMProject rmProject) {
|
||||
private boolean hasNodeEditPermission(
|
||||
@NotNull WebSession session,
|
||||
@NotNull DBNNode node,
|
||||
@NotNull RMProject rmProject
|
||||
) {
|
||||
if (node instanceof DBNDataSource || node instanceof DBNLocalFolder) {
|
||||
return SMUtils.hasProjectPermission(session, rmProject, RMProjectPermission.DATA_SOURCES_EDIT);
|
||||
} else if (node instanceof DBNAbstractResourceManagerNode) {
|
||||
@@ -644,7 +665,7 @@ public class WebServiceNavigator implements DBWServiceNavigator {
|
||||
if (parentFolder != null) {
|
||||
List<String> siblings = Arrays.stream(parentFolder.getChildren())
|
||||
.map(DBPDataSourceFolder::getName)
|
||||
.collect(Collectors.toList());
|
||||
.toList();
|
||||
if (siblings.contains(node.getName())) {
|
||||
throw new DBWebException("Node " + folderNodePath + " contains folder with name '" + node.getName() + "'");
|
||||
}
|
||||
@@ -655,9 +676,8 @@ public class WebServiceNavigator implements DBWServiceNavigator {
|
||||
);
|
||||
node.getOwnerProject().getDataSourceRegistry().checkForErrors();
|
||||
WebServiceUtils.refreshDatabases(session, node.getOwnerProject().getId());
|
||||
} else if (node instanceof DBNResourceManagerResource) {
|
||||
} else if (node instanceof DBNResourceManagerResource rmOldNode) {
|
||||
boolean rmNewNode = folderNode instanceof DBNAbstractResourceManagerNode;
|
||||
DBNResourceManagerResource rmOldNode = (DBNResourceManagerResource) node;
|
||||
if (!rmNewNode) {
|
||||
throw new DBWebException("Navigator node '" + folderNodePath + "' is not a resource manager node");
|
||||
}
|
||||
@@ -665,8 +685,8 @@ public class WebServiceNavigator implements DBWServiceNavigator {
|
||||
String projectId = rmOldNode.getResourceProject().getId();
|
||||
// Get paths from nodes
|
||||
String newPath = rmOldNode.getResource().getName();
|
||||
if (folderNode instanceof DBNResourceManagerResource) {
|
||||
newPath = ((DBNResourceManagerResource) folderNode).getResourceFolder() + "/" + newPath;
|
||||
if (folderNode instanceof DBNResourceManagerResource rmr) {
|
||||
newPath = rmr.getResourceFolder() + "/" + newPath;
|
||||
}
|
||||
String resourcePath = rmOldNode.getResourceFolder();
|
||||
session.getRmController().moveResource(projectId, resourcePath, newPath);
|
||||
@@ -710,7 +730,8 @@ public class WebServiceNavigator implements DBWServiceNavigator {
|
||||
throw new DBException("Node " + node.getNodeUri() + " rename is not supported");
|
||||
}
|
||||
|
||||
public DBCExecutionContext getCommandExecutionContext(DBSObject object) {
|
||||
@Nullable
|
||||
public DBCExecutionContext getCommandExecutionContext(@NotNull DBSObject object) {
|
||||
DBCExecutionContext executionContext = DBUtils.getDefaultContext(object, true);
|
||||
if (executionContext == null) {
|
||||
// It may happen in case of lazy context initialization
|
||||
|
||||
+7
-3
@@ -72,20 +72,24 @@ public interface DBWServiceSQL extends DBWService {
|
||||
@NotNull WebSession session,
|
||||
@NotNull List<String> nodePathList) throws DBWebException;
|
||||
|
||||
@NotNull
|
||||
@WebAction
|
||||
String generateEntityQuery(
|
||||
@NotNull WebSession session,
|
||||
@NotNull String generatorId,
|
||||
@NotNull Map<String, Object> options,
|
||||
@NotNull List<String> nodePathList) throws DBWebException;
|
||||
@NotNull List<String> nodePathList,
|
||||
@NotNull WebSQLGeneratorOptions options
|
||||
) throws DBWebException;
|
||||
|
||||
@NotNull
|
||||
@WebAction
|
||||
String sqlGenerateResultSetQuery(
|
||||
@NotNull WebSession session,
|
||||
@NotNull WebSQLContextInfo sqlContext,
|
||||
@NotNull String generatorId,
|
||||
@NotNull String resultsId,
|
||||
@NotNull List<WebSQLResultsRow> selectedRows
|
||||
@NotNull List<WebSQLResultsRow> selectedRows,
|
||||
@NotNull WebSQLGeneratorOptions options
|
||||
) throws DBWebException;
|
||||
|
||||
@WebAction
|
||||
|
||||
+32
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,9 +17,12 @@
|
||||
package io.cloudbeaver.service.sql;
|
||||
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.exec.plan.DBCPlan;
|
||||
import org.jkiss.dbeaver.model.exec.plan.DBCPlanCostNode;
|
||||
import org.jkiss.dbeaver.model.exec.plan.DBCPlanNode;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -30,18 +33,45 @@ public class WebSQLExecutionPlan {
|
||||
|
||||
private static final Log log = Log.getLog(WebSQLExecutionPlan.class);
|
||||
|
||||
@NotNull
|
||||
private final WebSession webSession;
|
||||
@NotNull
|
||||
private final DBCPlan plan;
|
||||
|
||||
public WebSQLExecutionPlan(WebSession webSession, DBCPlan plan) {
|
||||
public WebSQLExecutionPlan(@NotNull WebSession webSession, @NotNull DBCPlan plan) {
|
||||
this.webSession = webSession;
|
||||
this.plan = plan;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DBCPlan getPlan() {
|
||||
return plan;
|
||||
}
|
||||
|
||||
public String getQuery() {
|
||||
return plan.getQueryString();
|
||||
}
|
||||
|
||||
public boolean isHasCost() {
|
||||
return CommonUtils.toBoolean(plan.getPlanFeature(DBCPlanCostNode.FEATURE_PLAN_COST));
|
||||
}
|
||||
|
||||
public boolean isHasRows() {
|
||||
return CommonUtils.toBoolean(plan.getPlanFeature(DBCPlanCostNode.FEATURE_PLAN_ROWS));
|
||||
}
|
||||
|
||||
public boolean isHasDuration() {
|
||||
return CommonUtils.toBoolean(plan.getPlanFeature(DBCPlanCostNode.FEATURE_PLAN_DURATION));
|
||||
}
|
||||
|
||||
public String getDurationMeasure() {
|
||||
if (!isHasDuration()) {
|
||||
return null;
|
||||
}
|
||||
Object value = plan.getPlanFeature(DBCPlanCostNode.PLAN_DURATION_MEASURE);
|
||||
return value == null ? null : String.valueOf(value);
|
||||
}
|
||||
|
||||
public WebSQLExecutionPlanNode[] getNodes() {
|
||||
Map<String, Object> options = new LinkedHashMap<>();
|
||||
Map<DBCPlanNode, String> idMap = new IdentityHashMap<>();
|
||||
|
||||
+24
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,7 +19,9 @@ package io.cloudbeaver.service.sql;
|
||||
import io.cloudbeaver.model.WebPropertyInfo;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.exec.plan.DBCPlanCostNode;
|
||||
import org.jkiss.dbeaver.model.exec.plan.DBCPlanNode;
|
||||
import org.jkiss.dbeaver.runtime.properties.ObjectPropertyDescriptor;
|
||||
import org.jkiss.dbeaver.runtime.properties.PropertyCollector;
|
||||
@@ -73,12 +75,32 @@ public class WebSQLExecutionPlanNode {
|
||||
return node.getNodeDescription();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getCost() {
|
||||
return node instanceof DBCPlanCostNode cn && cn.getNodeCost() != null ? cn.getNodeCost().doubleValue() : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Number getRowCount() {
|
||||
return node instanceof DBCPlanCostNode cn ? cn.getNodeRowCount() : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getDuration() {
|
||||
return node instanceof DBCPlanCostNode cn && cn.getNodeDuration() != null ? cn.getNodeDuration().doubleValue() : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getPercent() {
|
||||
return node instanceof DBCPlanCostNode cn && cn.getNodePercent() != null ? cn.getNodePercent().doubleValue() : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public WebPropertyInfo[] getProperties() {
|
||||
PropertyCollector propertyCollector = new PropertyCollector(node, false);
|
||||
propertyCollector.collectProperties();
|
||||
return Arrays.stream(propertyCollector.getProperties())
|
||||
.filter(p -> !(p instanceof ObjectPropertyDescriptor && ((ObjectPropertyDescriptor) p).isHidden()))
|
||||
.filter(p -> !(p instanceof ObjectPropertyDescriptor && p.isHidden()))
|
||||
.map(p -> new WebPropertyInfo(webSession, p, propertyCollector)).toArray(WebPropertyInfo[]::new);
|
||||
}
|
||||
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed 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 io.cloudbeaver.service.sql;
|
||||
|
||||
public record WebSQLGeneratorOptions(
|
||||
boolean useFullyQualifiedNames,
|
||||
boolean compactSql
|
||||
) {
|
||||
}
|
||||
+17
-3
@@ -90,8 +90,9 @@ public class WebServiceBindingSQL extends WebServiceBindingBase<DBWServiceSQL>
|
||||
getService(env).generateEntityQuery(
|
||||
getWebSession(env),
|
||||
getArgumentVal(env, "generatorId"),
|
||||
getArgumentVal(env, "options"),
|
||||
getArgumentVal(env, "nodePathList"))
|
||||
getArgumentVal(env, "nodePathList"),
|
||||
getGeneratorOptions(env)
|
||||
)
|
||||
)
|
||||
.dataFetcher("sqlGenerateResultSetQuery", env ->
|
||||
getService(env).sqlGenerateResultSetQuery(
|
||||
@@ -99,7 +100,8 @@ public class WebServiceBindingSQL extends WebServiceBindingBase<DBWServiceSQL>
|
||||
getSQLContext(env),
|
||||
getArgumentVal(env, "generatorId"),
|
||||
getArgumentVal(env, "resultsId"),
|
||||
getResultsRow(env, "selectedRows")
|
||||
getResultsRow(env, "selectedRows"),
|
||||
getGeneratorOptions(env)
|
||||
)
|
||||
)
|
||||
.dataFetcher("sqlParseScript", env ->
|
||||
@@ -415,4 +417,16 @@ public class WebServiceBindingSQL extends WebServiceBindingBase<DBWServiceSQL>
|
||||
return mapList.stream().map(WebSQLResultsRow::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static WebSQLGeneratorOptions getGeneratorOptions(@NotNull DataFetchingEnvironment env) {
|
||||
Map<String, Object> optionsMap = getArgument(env, "generatorOptions");
|
||||
if (optionsMap == null) {
|
||||
return new WebSQLGeneratorOptions(true, false);
|
||||
}
|
||||
return new WebSQLGeneratorOptions(
|
||||
CommonUtils.toBoolean(optionsMap.get("useFullyQualifiedNames")),
|
||||
CommonUtils.toBoolean(optionsMap.get("compactSql"))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-7
@@ -25,12 +25,10 @@ import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.model.DBPDataSource;
|
||||
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
|
||||
import org.jkiss.dbeaver.model.DBUtils;
|
||||
import org.jkiss.dbeaver.model.data.DBDAttributeBinding;
|
||||
import org.jkiss.dbeaver.model.data.DBDResultSetDataProvider;
|
||||
import org.jkiss.dbeaver.model.data.DBDRowIdentifier;
|
||||
import org.jkiss.dbeaver.model.data.DBDValueRow;
|
||||
import org.jkiss.dbeaver.model.data.*;
|
||||
import org.jkiss.dbeaver.model.data.hints.DBDValueHintContext;
|
||||
import org.jkiss.dbeaver.model.exec.DBCExecutionContext;
|
||||
import org.jkiss.dbeaver.model.impl.data.ResultSetHintContext;
|
||||
import org.jkiss.dbeaver.model.struct.DBSEntity;
|
||||
import org.jkiss.dbeaver.model.struct.DBSObject;
|
||||
|
||||
@@ -43,6 +41,7 @@ public class WebDBDResultSetDataProvider implements DBDResultSetDataProvider, DB
|
||||
private final String resultsId;
|
||||
private final WebSQLContextInfo contextInfo;
|
||||
private final List<WebSQLResultsRow> selectedRows;
|
||||
private final DBDValueHintContext hintContext;
|
||||
|
||||
WebDBDResultSetDataProvider(
|
||||
@NotNull String resultsId,
|
||||
@@ -52,6 +51,7 @@ public class WebDBDResultSetDataProvider implements DBDResultSetDataProvider, DB
|
||||
this.resultsId = resultsId;
|
||||
this.contextInfo = contextInfo;
|
||||
this.selectedRows = selectedRows;
|
||||
this.hintContext = new ResultSetHintContext(() -> null, () -> null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -122,15 +122,20 @@ public class WebDBDResultSetDataProvider implements DBDResultSetDataProvider, DB
|
||||
@NotNull DBDAttributeBinding attribute,
|
||||
@NotNull DBDValueRow row,
|
||||
@Nullable int[] rowIndexes,
|
||||
@Nullable ResultSetValuePath valuePath,
|
||||
boolean retrieveDeepestCollectionElement
|
||||
) throws DBWebException {
|
||||
return DBUtils.getAttributeValue(attribute, getAttributes(), row.getValues());
|
||||
if (valuePath != null) {
|
||||
return DBUtils.getRowValueByPath(row, valuePath);
|
||||
} else {
|
||||
return DBUtils.getAttributeValue(attribute, getAttributes(), row.getValues());
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
@Override
|
||||
public DBDValueHintContext getHintContext() {
|
||||
return null;
|
||||
return hintContext;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
+24
-5
@@ -243,23 +243,37 @@ public class WebServiceSQL implements DBWServiceSQL {
|
||||
return SQLGeneratorConfigurationRegistry.getInstance().getApplicableGenerators(objectList, session).toArray(new SQLGeneratorDescriptor[0]);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String generateEntityQuery(@NotNull WebSession session, @NotNull String generatorId, @NotNull Map<String, Object> options, @NotNull List<String> nodePathList) throws DBWebException {
|
||||
public String generateEntityQuery(
|
||||
@NotNull WebSession session,
|
||||
@NotNull String generatorId,
|
||||
@NotNull List<String> nodePathList,
|
||||
@NotNull WebSQLGeneratorOptions options
|
||||
) throws DBWebException {
|
||||
List<DBSObject> objectList = getObjectListFromNodeIds(session, nodePathList);
|
||||
return createAndRunGenerator(session, generatorId, objectList);
|
||||
return createAndRunGenerator(
|
||||
session, generatorId, objectList,
|
||||
options.useFullyQualifiedNames(), options.compactSql()
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String sqlGenerateResultSetQuery(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull WebSQLContextInfo sqlContext,
|
||||
@NotNull String generatorId,
|
||||
@NotNull String resultsId,
|
||||
@NotNull List<WebSQLResultsRow> selectedRows
|
||||
@NotNull List<WebSQLResultsRow> selectedRows,
|
||||
@NotNull WebSQLGeneratorOptions options
|
||||
) throws DBWebException {
|
||||
checkAndFillTruncatedData(sqlContext, resultsId, selectedRows);
|
||||
WebDBDResultSetDataProvider dataProvider = new WebDBDResultSetDataProvider(resultsId, sqlContext, selectedRows);
|
||||
return createAndRunGenerator(webSession, generatorId, Collections.singletonList(dataProvider));
|
||||
return createAndRunGenerator(
|
||||
webSession, generatorId, Collections.singletonList(dataProvider),
|
||||
options.useFullyQualifiedNames(), options.compactSql()
|
||||
);
|
||||
}
|
||||
|
||||
private void checkAndFillTruncatedData(
|
||||
@@ -289,10 +303,13 @@ public class WebServiceSQL implements DBWServiceSQL {
|
||||
dataKind.equals(DBPDataKind.BINARY);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String createAndRunGenerator(
|
||||
@NotNull WebSession session,
|
||||
@NotNull String generatorId,
|
||||
@NotNull List<DBSObject> objectList
|
||||
@NotNull List<DBSObject> objectList,
|
||||
boolean useFullyQualifiedNames,
|
||||
boolean compactSql
|
||||
) throws DBWebException {
|
||||
SQLGeneratorDescriptor generator = SQLGeneratorConfigurationRegistry.getInstance().getGenerator(generatorId);
|
||||
if (generator == null) {
|
||||
@@ -300,6 +317,8 @@ public class WebServiceSQL implements DBWServiceSQL {
|
||||
}
|
||||
try {
|
||||
SQLGenerator<DBSObject> generatorInstance = generator.createGenerator(objectList);
|
||||
generatorInstance.setFullyQualifiedNames(useFullyQualifiedNames);
|
||||
generatorInstance.setCompactSQL(compactSql);
|
||||
generatorInstance.run(session.getProgressMonitor());
|
||||
return generatorInstance.getResult();
|
||||
} catch (DBException e) {
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Service - Administration
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.admin;singleton:=true
|
||||
Bundle-Version: 1.0.142.qualifier
|
||||
Bundle-Release-Date: 20260406
|
||||
Bundle-Version: 1.0.145.qualifier
|
||||
Bundle-Release-Date: 20260518
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server.ce,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.admin</artifactId>
|
||||
<version>1.0.142-SNAPSHOT</version>
|
||||
<version>1.0.145-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Service - Authentication
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.auth;singleton:=true
|
||||
Bundle-Version: 1.0.142.qualifier
|
||||
Bundle-Release-Date: 20260406
|
||||
Bundle-Version: 1.0.145.qualifier
|
||||
Bundle-Release-Date: 20260518
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server.ce
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.auth</artifactId>
|
||||
<version>1.0.142-SNAPSHOT</version>
|
||||
<version>1.0.145-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Service - Data Transfer
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.data.transfer;singleton:=true
|
||||
Bundle-Version: 1.0.143.qualifier
|
||||
Bundle-Release-Date: 20260406
|
||||
Bundle-Version: 1.0.146.qualifier
|
||||
Bundle-Release-Date: 20260518
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server.ce,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.data.transfer</artifactId>
|
||||
<version>1.0.143-SNAPSHOT</version>
|
||||
<version>1.0.146-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Service - File System
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.fs;singleton:=true
|
||||
Bundle-Version: 1.0.60.qualifier
|
||||
Bundle-Release-Date: 20260406
|
||||
Bundle-Version: 1.0.63.qualifier
|
||||
Bundle-Release-Date: 20260518
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server.ce,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.fs</artifactId>
|
||||
<version>1.0.60-SNAPSHOT</version>
|
||||
<version>1.0.63-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
+3
@@ -35,6 +35,7 @@ import org.jkiss.dbeaver.runtime.DBWorkbench;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
@@ -213,6 +214,8 @@ public class WebServiceFS implements DBWServiceFS {
|
||||
oldParentNode.removeChildResource(oldNode.getPath());
|
||||
parentNode.addChildResource(to);
|
||||
return new FSFile(parentNode.getChild(to));
|
||||
} catch (NoSuchFileException e) {
|
||||
throw new DBWebException("File not found. Please refresh the catalog and check if file exists.");
|
||||
} catch (Exception e) {
|
||||
throw new DBWebException("Failed to move file: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Cloudbeaver Web Service - LDAP
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.ldap.auth;singleton:=true
|
||||
Bundle-Version: 1.0.25.qualifier
|
||||
Bundle-Release-Date: 20260406
|
||||
Bundle-Version: 1.0.28.qualifier
|
||||
Bundle-Release-Date: 20260518
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: org.jkiss.dbeaver.model;visibility:=reexport,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.ldap.auth</artifactId>
|
||||
<version>1.0.25-SNAPSHOT</version>
|
||||
<version>1.0.28-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Service - Metadata
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.metadata;singleton:=true
|
||||
Bundle-Version: 1.0.146.qualifier
|
||||
Bundle-Release-Date: 20260406
|
||||
Bundle-Version: 1.0.149.qualifier
|
||||
Bundle-Release-Date: 20260518
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.metadata</artifactId>
|
||||
<version>1.0.146-SNAPSHOT</version>
|
||||
<version>1.0.149-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Resource manager NIO implementation
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.rm.nio;singleton:=true
|
||||
Bundle-Version: 1.0.60.qualifier
|
||||
Bundle-Release-Date: 20260406
|
||||
Bundle-Version: 1.0.63.qualifier
|
||||
Bundle-Release-Date: 20260518
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.model,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.rm.nio</artifactId>
|
||||
<version>1.0.60-SNAPSHOT</version>
|
||||
<version>1.0.63-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Service - Resource manager
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.rm;singleton:=true
|
||||
Bundle-Version: 1.0.95.qualifier
|
||||
Bundle-Release-Date: 20260406
|
||||
Bundle-Version: 1.0.98.qualifier
|
||||
Bundle-Release-Date: 20260518
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.rm</artifactId>
|
||||
<version>1.0.95-SNAPSHOT</version>
|
||||
<version>1.0.98-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Cloudbeaver Web Service - Security
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.security;singleton:=true
|
||||
Bundle-Version: 1.0.98.qualifier
|
||||
Bundle-Release-Date: 20260406
|
||||
Bundle-Version: 1.0.101.qualifier
|
||||
Bundle-Release-Date: 20260518
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: org.jkiss.dbeaver.model;visibility:=reexport,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.security</artifactId>
|
||||
<version>1.0.98-SNAPSHOT</version>
|
||||
<version>1.0.101-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
+20
-8
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,7 +32,6 @@ import io.cloudbeaver.service.security.bruteforce.UserLoginRecord;
|
||||
import io.cloudbeaver.service.security.db.CBDatabase;
|
||||
import io.cloudbeaver.service.security.internal.AuthAttemptSessionInfo;
|
||||
import io.cloudbeaver.service.security.internal.CBAuthSubjectRepo;
|
||||
import io.cloudbeaver.service.security.internal.SMTokenInfo;
|
||||
import io.cloudbeaver.utils.WebEventUtils;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
@@ -406,14 +405,24 @@ public class CBEmbeddedSecurityController<T extends ServletAuthApplication>
|
||||
|
||||
protected void importUsers(@NotNull Connection connection, @NotNull SMUserImportList userImportList)
|
||||
throws DBException, SQLException {
|
||||
List<SMUserProvisioning> users = userImportList.getUsers();
|
||||
Set<String> seen = new HashSet<>();
|
||||
outer:
|
||||
for (SMUserProvisioning user : userImportList.getUsers()) {
|
||||
String authRole = user.getAuthRole() == null ? userImportList.getAuthRole() : user.getAuthRole();
|
||||
String userId = user.getUserId();
|
||||
for (SMUserProvisioning user : users) {
|
||||
Map<String, String> metaParameters = user.getMetaParameters();
|
||||
String effectiveUserId = user.getUserId();
|
||||
if (CommonUtils.isNotEmpty(metaParameters.get(SMStandardMeta.META_USER_ID))) {
|
||||
userId = metaParameters.get(SMStandardMeta.META_USER_ID);
|
||||
effectiveUserId = metaParameters.get(SMStandardMeta.META_USER_ID);
|
||||
}
|
||||
String effectiveUserIdLowerCase = effectiveUserId.toLowerCase();
|
||||
if (seen.contains(effectiveUserIdLowerCase)) {
|
||||
log.warn("Skipping duplicate user (case-insensitive): " + effectiveUserId);
|
||||
continue;
|
||||
}
|
||||
seen.add(effectiveUserIdLowerCase);
|
||||
|
||||
String authRole = user.getAuthRole() == null ? userImportList.getAuthRole() : user.getAuthRole();
|
||||
String userId = effectiveUserId;
|
||||
for (String possibleUserId : List.of(userId, userId.toLowerCase())) {
|
||||
if (isSubjectExists(possibleUserId)) {
|
||||
if (getSubjectType(possibleUserId) == SMSubjectType.team) {
|
||||
@@ -2386,7 +2395,8 @@ public class CBEmbeddedSecurityController<T extends ServletAuthApplication>
|
||||
}
|
||||
}
|
||||
|
||||
private SMCredentials getCurrentUserCreds() throws SMException {
|
||||
@NotNull
|
||||
protected SMCredentials getCurrentUserCreds() throws SMException {
|
||||
var currentUserCreds = credentialsProvider.getActiveUserCredentials();
|
||||
if (currentUserCreds == null) {
|
||||
throw new SMException("Unauthorized");
|
||||
@@ -2437,7 +2447,9 @@ public class CBEmbeddedSecurityController<T extends ServletAuthApplication>
|
||||
}
|
||||
}
|
||||
|
||||
private SMTokenInfo readAccessTokenInfo(String smAccessToken) throws DBException {
|
||||
@NotNull
|
||||
@Override
|
||||
public SMTokenInfo readAccessTokenInfo(@NotNull String smAccessToken) throws DBException {
|
||||
try (Connection dbCon = database.openConnection();
|
||||
PreparedStatement dbStat = dbCon.prepareStatement(
|
||||
"""
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user