mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-10-16 14:50:15 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1887714ab | ||
|
|
f5ac3cfe2a | ||
|
|
434a988919 | ||
|
|
3fbc227734 | ||
|
|
bb9a62da63 | ||
|
|
34c6e6c9be | ||
|
|
b35e3f83ed | ||
|
|
a42c7dc8de | ||
|
|
eb33e0e895 | ||
|
|
c3c15bf7cc | ||
|
|
6604b0887c | ||
|
|
735024b57b | ||
|
|
3118eac266 | ||
|
|
38445f3843 | ||
|
|
01d08fc3ce | ||
|
|
9bc6bd022e | ||
|
|
cf764f5807 | ||
|
|
0bf6783d00 | ||
|
|
0e3da49b23 | ||
|
|
f84bd6040f | ||
|
|
6339bee0dc | ||
|
|
8f54e759dd | ||
|
|
5f53e0ffa2 | ||
|
|
fe020f8f7d | ||
|
|
4b9e1c8b94 | ||
|
|
dc5592d052 | ||
|
|
1746d91072 | ||
|
|
d230275768 | ||
|
|
3b3bb147b7 | ||
|
|
6ad148850d | ||
|
|
a4130804bf | ||
|
|
37d06ecebd | ||
|
|
b869bddded | ||
|
|
efb42d33a7 | ||
|
|
90acaaf00e | ||
|
|
46309e9505 | ||
|
|
aebb2d47ef | ||
|
|
12e0107617 | ||
|
|
3c5aa6b7e8 | ||
|
|
4df7e01d19 | ||
|
|
801a55cd38 | ||
|
|
252ff71f03 | ||
|
|
461e251753 | ||
|
|
e54bfb3154 | ||
|
|
24ff77de47 | ||
|
|
5ce49faea0 |
@@ -1,17 +0,0 @@
|
||||
name: validation
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- devel
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- edited
|
||||
- ready_for_review
|
||||
- labeled
|
||||
|
||||
jobs:
|
||||
commit-message:
|
||||
uses: dbeaver/dbeaver/.github/workflows/reused-commit-msgs-validator.yml@devel
|
||||
Vendored
+53
-68
@@ -4,7 +4,7 @@
|
||||
{
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"name": "Chrome",
|
||||
"name": "CloudBeaver CE",
|
||||
"url": "http://localhost:8080",
|
||||
"webRoot": "${workspaceFolder}/..",
|
||||
"outFiles": [
|
||||
@@ -17,75 +17,60 @@
|
||||
},
|
||||
{
|
||||
"type": "java",
|
||||
"name": "CloudBeaver CE",
|
||||
"cwd": "${workspaceFolder}/workspace-dev-ce",
|
||||
"name": "CloudBeaver CE Server",
|
||||
"cwd": "${workspaceFolder}/../opt/cbce",
|
||||
"request": "launch",
|
||||
"mainClass": "org.jkiss.dbeaver.launcher.DBeaverLauncher",
|
||||
"windows": {
|
||||
"type": "java",
|
||||
"name": "CloudBeaver CE",
|
||||
"request": "launch",
|
||||
"mainClass": "org.jkiss.dbeaver.launcher.DBeaverLauncher",
|
||||
"args": [
|
||||
"-product",
|
||||
"io.cloudbeaver.product.ce.product",
|
||||
"-configuration",
|
||||
"file:${workspaceFolder}/../dbeaver-workspace/products/CloudbeaverServer.product/",
|
||||
"-dev",
|
||||
"file:${workspaceFolder}/../dbeaver-workspace/products/CloudbeaverServer.product/dev.properties",
|
||||
"-os",
|
||||
"win32",
|
||||
"-ws",
|
||||
"win32",
|
||||
"-arch",
|
||||
"x86_64",
|
||||
"-nl",
|
||||
"en",
|
||||
"-showsplash",
|
||||
"-web-config",
|
||||
"conf/cloudbeaver.conf"
|
||||
],
|
||||
"vmArgs": [
|
||||
"-XX:+IgnoreUnrecognizedVMOptions",
|
||||
"--add-modules=ALL-SYSTEM",
|
||||
"-Xms64m",
|
||||
"-Xmx1024m",
|
||||
"-Declipse.pde.launch=true"
|
||||
]
|
||||
},
|
||||
"osx": {
|
||||
"type": "java",
|
||||
"name": "CloudBeaver CE",
|
||||
"request": "launch",
|
||||
"mainClass": "org.jkiss.dbeaver.launcher.DBeaverLauncher",
|
||||
"args": [
|
||||
"-product",
|
||||
"io.cloudbeaver.product.ce.product",
|
||||
"-configuration",
|
||||
"file:${workspaceFolder}/../dbeaver-workspace/products/CloudbeaverServer.product/",
|
||||
"-dev",
|
||||
"file:${workspaceFolder}/../dbeaver-workspace/products/CloudbeaverServer.product/dev.properties",
|
||||
"-os",
|
||||
"macosx",
|
||||
"-ws",
|
||||
"cocoa",
|
||||
"-arch",
|
||||
"aarch64",
|
||||
"-nl",
|
||||
"en",
|
||||
"-showsplash",
|
||||
"-web-config",
|
||||
"conf/cloudbeaver.conf"
|
||||
],
|
||||
"vmArgs": [
|
||||
"-XX:+IgnoreUnrecognizedVMOptions",
|
||||
"--add-modules=ALL-SYSTEM",
|
||||
"-Xms64m",
|
||||
"-Xmx1024m",
|
||||
"-Declipse.pde.launch=true",
|
||||
"-XstartOnFirstThread"
|
||||
]
|
||||
}
|
||||
"args": [
|
||||
"-product",
|
||||
"io.cloudbeaver.product.ce.product",
|
||||
"-configuration",
|
||||
"file:${workspaceFolder}/../dbeaver-workspace/products/CloudbeaverServer.product/",
|
||||
"-dev",
|
||||
"file:${workspaceFolder}/../dbeaver-workspace/products/CloudbeaverServer.product/dev.properties",
|
||||
"-nl",
|
||||
"en",
|
||||
"-web-config",
|
||||
"conf/cloudbeaver.conf",
|
||||
"-registryMultiLanguage"
|
||||
],
|
||||
// "windows": {
|
||||
// "args": ["-os", "win32", "-ws", "win32", "-arch", "x86_64"]
|
||||
// },
|
||||
// "osx": {
|
||||
// "args": ["-os", "macosx", "-ws", "cocoa", "-arch", "aarch64"]
|
||||
// },
|
||||
|
||||
"vmArgs": [
|
||||
"-XX:+IgnoreUnrecognizedVMOptions",
|
||||
"-Xms64m",
|
||||
"-Xmx1024m",
|
||||
"-Declipse.pde.launch=true",
|
||||
"-XstartOnFirstThread",
|
||||
"-Dfile.encoding=UTF-8",
|
||||
"--add-modules=ALL-SYSTEM",
|
||||
"--add-opens=java.base/java.io=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.lang=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.lang.reflect=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.net=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.nio=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.nio.charset=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.text=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.time=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.util=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.util.concurrent=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED",
|
||||
"--add-opens=java.base/jdk.internal.vm=ALL-UNNAMED",
|
||||
"--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED",
|
||||
"--add-opens=java.base/sun.nio.ch=ALL-UNNAMED",
|
||||
"--add-opens=java.base/sun.security.ssl=ALL-UNNAMED",
|
||||
"--add-opens=java.base/sun.security.action=ALL-UNNAMED",
|
||||
"--add-opens=java.base/sun.security.util=ALL-UNNAMED",
|
||||
"--add-opens=java.security.jgss/sun.security.jgss=ALL-UNNAMED",
|
||||
"--add-opens=java.security.jgss/sun.security.krb5=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED",
|
||||
"--add-opens=java.sql/java.sql=ALL-UNNAMED"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
# CloudBeaver Community
|
||||
<img src="https://github.com/dbeaver/cloudbeaver/wiki/images/cloudbeaver-logo.png" align="right" width="250"/>
|
||||
|
||||
<img src="https://github.com/dbeaver/cloudbeaver/wiki/images/cloudbeaver-logo.png" width="250"/>
|
||||
# CloudBeaver Community
|
||||
|
||||
Cloud Database Manager - Community Edition.
|
||||
CloudBeaver is a web server that provides a rich web interface. The server itself is a Java application, and the web part is written in TypeScript and React.
|
||||
It is free to use and open-source (licensed under [Apache 2](https://github.com/dbeaver/cloudbeaver/blob/devel/LICENSE) license).
|
||||
See our [WIKI](https://github.com/dbeaver/cloudbeaver/wiki) for more details.
|
||||
|
||||

|
||||
<img src="https://github.com/dbeaver/cloudbeaver/wiki/images/connection-creation-demo.png" width="400"/>
|
||||
<img src="https://github.com/dbeaver/cloudbeaver/wiki/images/gis-demo.png" width="400"/>
|
||||
<img src="https://github.com/dbeaver/cloudbeaver/wiki/images/data-transfer-demo.png" width="400"/>
|
||||
<img src="https://github.com/dbeaver/cloudbeaver/wiki/images/sql-editor-demo.png" width="400"/>
|
||||
|
||||
## Run in Docker
|
||||
|
||||
@@ -22,6 +25,11 @@ You can see a live demo of CloudBeaver here: https://demo.cloudbeaver.io
|
||||
|
||||
## Changelog
|
||||
|
||||
### 24.2.1. 2024-09-23
|
||||
- Chinese localization has been improved (thanks to [cashlifei](https://github.com/cashlifei));
|
||||
- Environment variables configuration has been improved - now you can configure more variables on the initial stage of the Docker setup;
|
||||
- SQL Server driver has been updated to version 12.8.0.
|
||||
|
||||
### 24.2.0. 2024-09-02
|
||||
### Changes since 24.1.0:
|
||||
- General:
|
||||
@@ -54,6 +62,6 @@ You can see a live demo of CloudBeaver here: https://demo.cloudbeaver.io
|
||||
## Contribution
|
||||
As a community-driven open-source project, we warmly welcome contributions through GitHub pull requests.
|
||||
|
||||
[We are happy to reward](https://dbeaver.com/help-beaver/) our most active contributors every major sprint.
|
||||
[We are happy to reward](https://dbeaver.com/help-dbeaver/) our most active contributors every major sprint.
|
||||
The most significant contribution to our code for the major release 24.2.0 was made by:
|
||||
1. [matthieukhl](https://github.com/matthieukhl)
|
||||
|
||||
-2
@@ -21,9 +21,7 @@
|
||||
plugin.sql-editor.maxFileSize: 10240,
|
||||
plugin.log-viewer.disabled: false,
|
||||
plugin.log-viewer.logBatchSize: 1000,
|
||||
plugin.log-viewer.maxFailedRequests: 3,
|
||||
plugin.log-viewer.maxLogRecords: 2000,
|
||||
plugin.log-viewer.refreshTimeout: 3000,
|
||||
sql.proposals.insert.table.alias: PLAIN
|
||||
},
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
### Sample databases
|
||||
|
||||
Provides access to locally deployed SQLite sample database
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
{
|
||||
"folders": {},
|
||||
"connections": {
|
||||
"sqlite_xerial-sample-database": {
|
||||
"provider": "generic",
|
||||
"driver": "sqlite_jdbc",
|
||||
"name": "SQLite - Chinook (Sample)",
|
||||
"save-password": true,
|
||||
"navigator-show-only-entities": false,
|
||||
"navigator-hide-folders": false,
|
||||
"read-only": false,
|
||||
"template": false,
|
||||
"configuration": {
|
||||
"database": "${application.path}/../samples/db/Chinook.sqlitedb",
|
||||
"type": "dev",
|
||||
"auth-model": "native"
|
||||
}
|
||||
},
|
||||
"postgresql-template-1": {
|
||||
"provider": "postgresql",
|
||||
"driver": "postgres-jdbc",
|
||||
"name": "PostgreSQL (Template)",
|
||||
"save-password": false,
|
||||
"show-system-objects": false,
|
||||
"read-only": true,
|
||||
"template": true,
|
||||
"configuration": {
|
||||
"host": "localhost",
|
||||
"port": "5432",
|
||||
"database": "postgres",
|
||||
"url": "jdbc:postgresql://localhost:5432/postgres",
|
||||
"type": "dev",
|
||||
"provider-properties": {
|
||||
"@dbeaver-show-non-default-db@": "false"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"folders": {},
|
||||
"connections": {}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
{
|
||||
server: {
|
||||
serverPort: "${CLOUDBEAVER_SERVICE_PORT:8978}",
|
||||
|
||||
workspaceLocation: "${CLOUDBEAVER_WORKSPACE_LOCATION:workspace}",
|
||||
contentRoot: "web",
|
||||
driversLocation: "drivers",
|
||||
|
||||
rootURI: "${CLOUDBEAVER_ROOT_URI:/}",
|
||||
serviceURI: "/api/",
|
||||
|
||||
productSettings: {
|
||||
# Global properties
|
||||
core.theming.theme: 'light',
|
||||
core.localization.localization: 'en',
|
||||
plugin.sql-editor.autoSave: true,
|
||||
plugin.sql-editor.disabled: false,
|
||||
# max size of the file that can be uploaded to the editor (in kilobytes)
|
||||
plugin.sql-editor.maxFileSize: 10240,
|
||||
plugin.log-viewer.disabled: false,
|
||||
plugin.log-viewer.logBatchSize: 1000,
|
||||
plugin.log-viewer.maxFailedRequests: 3,
|
||||
plugin.log-viewer.maxLogRecords: 2000,
|
||||
plugin.log-viewer.refreshTimeout: 3000,
|
||||
sql.proposals.insert.table.alias: PLAIN
|
||||
},
|
||||
|
||||
expireSessionAfterPeriod: "${CLOUDBEAVER_EXPIRE_SESSION_AFTER_PERIOD:1800000}",
|
||||
|
||||
develMode: "${CLOUDBEAVER_DEVEL_MODE:false}",
|
||||
|
||||
enableSecurityManager: false,
|
||||
|
||||
database: {
|
||||
driver: "${CLOUDBEAVER_DB_DRIVER:h2_embedded_v2}",
|
||||
url: "${CLOUDBEAVER_DB_URL:jdbc:h2:${workspace}/.data/cb.h2v2.dat}",
|
||||
schema: "${CLOUDBEAVER_DB_SCHEMA:''}",
|
||||
user: "${CLOUDBEAVER_DB_USER:''}",
|
||||
password: "${CLOUDBEAVER_DB_PASSWORD:''}",
|
||||
initialDataConfiguration: "${CLOUDBEAVER_DB_INITIAL_DATA:conf/initial-data.conf}",
|
||||
pool: {
|
||||
minIdleConnections: "${CLOUDBEAVER_DB_MIN_IDLE_CONNECTIONS:4}",
|
||||
maxIdleConnections: "${CLOUDBEAVER_DB_MAX_IDLE_CONNECTIONS:10}",
|
||||
maxConnections: "${CLOUDBEAVER_DB_MAX_CONNECTIONS:100}",
|
||||
validationQuery: "${CLOUDBEAVER_DB_VALIDATION_QUERY:SELECT 1}"
|
||||
},
|
||||
backupEnabled: "${CLOUDBEAVER_DB_BACKUP_ENABLED:true}"
|
||||
},
|
||||
sm: {
|
||||
enableBruteForceProtection: "${CLOUDBEAVER_BRUTE_FORCE_PROTECTION_ENABLED:true}",
|
||||
maxFailedLogin: "${CLOUDBEAVER_MAX_FAILED_LOGINS:10}",
|
||||
minimumLoginTimeout: "${CLOUDBEAVER_MINIMUM_LOGIN_TIMEOUT:1}",
|
||||
blockLoginPeriod: "${CLOUDBEAVER_BLOCK_PERIOD:300}",
|
||||
passwordPolicy: {
|
||||
minLength: "${CLOUDBEAVER_POLICY_MIN_LENGTH:8}",
|
||||
requireMixedCase: "${CLOUDBEAVER_POLICY_REQUIRE_MIXED_CASE:true}",
|
||||
minNumberCount: "${CLOUDBEAVER_POLICY_MIN_NUMBER_COUNT:1}",
|
||||
minSymbolCount: "${CLOUDBEAVER_POLICY_MIN_SYMBOL_COUNT:0}"
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
app: {
|
||||
anonymousAccessEnabled: "${CLOUDBEAVER_APP_ANONYMOUS_ACCESS_ENABLED:true}",
|
||||
anonymousUserRole: user,
|
||||
grantConnectionsAccessToAnonymousTeam: "${CLOUDBEAVER_APP_GRANT_CONNECTIONS_ACCESS_TO_ANONYMOUS_TEAM:false}",
|
||||
supportsCustomConnections: "${CLOUDBEAVER_APP_SUPPORTS_CUSTOM_CONNECTIONS:false}",
|
||||
showReadOnlyConnectionInfo: "${CLOUDBEAVER_APP_READ_ONLY_CONNECTION_INFO:false}",
|
||||
systemVariablesResolvingEnabled: "${CLOUDBEAVER_SYSTEM_VARIABLES_RESOLVING_ENABLED:false}",
|
||||
|
||||
forwardProxy: "${CLOUDBEAVER_APP_FORWARD_PROXY:false}",
|
||||
|
||||
publicCredentialsSaveEnabled: "${CLOUDBEAVER_APP_PUBLIC_CREDENTIALS_SAVE_ENABLED:true}",
|
||||
adminCredentialsSaveEnabled: "${CLOUDBEAVER_APP_ADMIN_CREDENTIALS_SAVE_ENABLED:true}",
|
||||
|
||||
resourceManagerEnabled: "${CLOUDBEAVER_APP_RESOURCE_MANAGER_ENABLED:true}",
|
||||
|
||||
resourceQuotas: {
|
||||
dataExportFileSizeLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_DATA_EXPORT_FILE_SIZE_LIMIT:10000000}",
|
||||
resourceManagerFileSizeLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_RESOURCE_MANAGER_FILE_SIZE_LIMIT:500000}",
|
||||
sqlMaxRunningQueries: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_MAX_RUNNING_QUERIES:100}",
|
||||
sqlResultSetRowsLimit: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_RESULT_SET_ROWS_LIMIT:100000}",
|
||||
sqlTextPreviewMaxLength: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_TEXT_PREVIEW_MAX_LENGTH:4096}",
|
||||
sqlBinaryPreviewMaxLength: "${CLOUDBEAVER_RESOURCE_QUOTA_SQL_BINARY_PREVIEW_MAX_LENGTH:261120}"
|
||||
},
|
||||
enabledAuthProviders: [
|
||||
"local"
|
||||
],
|
||||
|
||||
disabledDrivers: [
|
||||
"h2:h2_embedded",
|
||||
"h2:h2_embedded_v2",
|
||||
"clickhouse:yandex_clickhouse"
|
||||
],
|
||||
disabledBetaFeatures: [
|
||||
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -1,6 +0,0 @@
|
||||
Chinook Database - Version 1.3
|
||||
Script: Chinook_Sqlite.sql
|
||||
Description: Creates and populates the Chinook database.
|
||||
DB Server: Sqlite
|
||||
Author: Luis Rocha
|
||||
License: http://www.codeplex.com/ChinookDatabase/license
|
||||
+1
-19
@@ -2,12 +2,6 @@
|
||||
set -Eeo pipefail
|
||||
set +u
|
||||
|
||||
# #command line arguments
|
||||
# CONFIGURATION_PATH=${1-"../config/sample-databases/DefaultConfiguration"}
|
||||
# SAMPLE_DATABASE_PATH=${2-""}
|
||||
|
||||
# echo $CONFIGURATION_PATH
|
||||
# echo $SAMPLE_DATABASE_PATH
|
||||
echo "Clone and build Cloudbeaver"
|
||||
|
||||
rm -rf ./drivers
|
||||
@@ -43,20 +37,8 @@ cp -rp ../server/product/web-server/target/products/io.cloudbeaver.product/all/a
|
||||
cp -p ./scripts/* ./cloudbeaver
|
||||
mkdir cloudbeaver/samples
|
||||
|
||||
if [[ -z $SAMPLE_DATABASE_PATH ]]; then
|
||||
SAMPLE_DATABASE_PATH=""
|
||||
else
|
||||
mkdir cloudbeaver/samples/db
|
||||
cp -rp "${SAMPLE_DATABASE_PATH}" cloudbeaver/samples/
|
||||
fi
|
||||
|
||||
if [[ -z "$CONFIGURATION_PATH" ]]; then
|
||||
CONFIGURATION_PATH="../config/sample-databases/DefaultConfiguration"
|
||||
fi
|
||||
|
||||
cp -rp ../config/core/* cloudbeaver/conf
|
||||
cp -rp "${CONFIGURATION_PATH}"/GlobalConfiguration/.dbeaver/data-sources.json cloudbeaver/conf/initial-data-sources.conf
|
||||
cp -p "${CONFIGURATION_PATH}"/*.conf cloudbeaver/conf/
|
||||
cp -rp ../config/GlobalConfiguration/.dbeaver/data-sources.json cloudbeaver/conf/initial-data-sources.conf
|
||||
mv drivers cloudbeaver
|
||||
|
||||
echo "End of backend build"
|
||||
@@ -1 +0,0 @@
|
||||
@call build.bat ..\config\sample-databases\SQLiteConfiguration ..\config\sample-databases\db
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
#command line arguments
|
||||
CONFIGURATION_PATH='../config/sample-databases/SQLiteConfiguration'
|
||||
SAMPLE_DATABASE_PATH='../config/sample-databases/db'
|
||||
|
||||
source build-backend.sh
|
||||
source build-frontend.sh
|
||||
+2
-11
@@ -1,11 +1,6 @@
|
||||
@echo off
|
||||
|
||||
rem command line arguments
|
||||
SET CONFIGURATION_PATH=%1
|
||||
SET SAMPLE_DATABASE_PATH=%2
|
||||
|
||||
IF "%CONFIGURATION_PATH%"=="" SET CONFIGURATION_PATH="..\config\sample-databases\DefaultConfiguration"
|
||||
echo "Configuration path=%CONFIGURATION_PATH%"
|
||||
|
||||
echo Clone and build Cloudbeaver
|
||||
|
||||
@@ -40,13 +35,9 @@ xcopy /E /Q ..\server\product\web-server\target\products\io.cloudbeaver.product\
|
||||
copy scripts\* cloudbeaver >NUL
|
||||
mkdir cloudbeaver\samples
|
||||
|
||||
IF NOT "%SAMPLE_DATABASE_PATH%"=="" (
|
||||
mkdir cloudbeaver\samples\db
|
||||
xcopy /E /Q %SAMPLE_DATABASE_PATH% cloudbeaver\samples\db >NUL
|
||||
)
|
||||
|
||||
copy ..\config\core\* cloudbeaver\conf >NUL
|
||||
copy %CONFIGURATION_PATH%\GlobalConfiguration\.dbeaver\data-sources.json cloudbeaver\conf\initial-data-sources.conf >NUL
|
||||
copy %CONFIGURATION_PATH%\*.conf cloudbeaver\conf >NUL
|
||||
copy ..\config\DefaultConfiguration\GlobalConfiguration\.dbeaver\data-sources.json cloudbeaver\conf\initial-data-sources.conf >NUL
|
||||
|
||||
move drivers cloudbeaver >NUL
|
||||
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
#!/bin/bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
#command line arguments
|
||||
CONFIGURATION_PATH="../config/sample-databases/DefaultConfiguration"
|
||||
SAMPLE_DATABASE_PATH=""
|
||||
|
||||
source build-backend.sh
|
||||
source build-frontend.sh
|
||||
@@ -1,4 +1,3 @@
|
||||
{
|
||||
"projects": ["../dbeaver-common", "../dbeaver", "../cloudbeaver/server"],
|
||||
"targetPlatform": "./org.jkiss.cloudbeaver.tp.target"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?pde version="3.8"?>
|
||||
<target name="org.jkiss.tp.cloudbeaver">
|
||||
<target name="org.jkiss.cloudbeaver.tp">
|
||||
<locations>
|
||||
<location path="../dbeaver-workspace/dependencies/plugins" type="Directory"/>
|
||||
</locations>
|
||||
|
||||
@@ -3,14 +3,13 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Model
|
||||
Bundle-SymbolicName: io.cloudbeaver.model;singleton:=true
|
||||
Bundle-Version: 1.0.61.qualifier
|
||||
Bundle-Release-Date: 20240923
|
||||
Bundle-Version: 1.0.62.qualifier
|
||||
Bundle-Release-Date: 20241007
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-17
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-ClassPath: .
|
||||
Require-Bundle: org.jkiss.dbeaver.data.gis;visibility:=reexport,
|
||||
org.jkiss.dbeaver.model;visibility:=reexport,
|
||||
org.jkiss.dbeaver.model.rcp;visibility:=reexport,
|
||||
org.jkiss.dbeaver.model.sm;visibility:=reexport,
|
||||
org.jkiss.dbeaver.model.event;visibility:=reexport,
|
||||
org.jkiss.dbeaver.model.nio;visibility:=reexport,
|
||||
@@ -29,7 +28,9 @@ Export-Package: io.cloudbeaver,
|
||||
io.cloudbeaver.websocket,
|
||||
io.cloudbeaver.model,
|
||||
io.cloudbeaver.model.app,
|
||||
io.cloudbeaver.model.config,
|
||||
io.cloudbeaver.model.fs,
|
||||
io.cloudbeaver.model.log,
|
||||
io.cloudbeaver.model.rm,
|
||||
io.cloudbeaver.model.rm.local,
|
||||
io.cloudbeaver.model.rm.lock,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.model</artifactId>
|
||||
<version>1.0.61-SNAPSHOT</version>
|
||||
<version>1.0.62-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -38,21 +38,18 @@ public abstract class BaseWebProjectImpl extends BaseProjectImpl implements RMCo
|
||||
@NotNull
|
||||
private final Path path;
|
||||
@NotNull
|
||||
protected final DataSourceFilter dataSourceFilter;
|
||||
private final RMController resourceController;
|
||||
|
||||
public BaseWebProjectImpl(
|
||||
@NotNull DBPWorkspace workspace,
|
||||
@NotNull RMController resourceController,
|
||||
@NotNull SMSessionContext sessionContext,
|
||||
@NotNull RMProject project,
|
||||
@NotNull DataSourceFilter dataSourceFilter
|
||||
@NotNull RMProject project
|
||||
) {
|
||||
super(workspace, sessionContext);
|
||||
this.resourceController = resourceController;
|
||||
this.path = RMUtils.getProjectPath(project);
|
||||
this.project = project;
|
||||
this.dataSourceFilter = dataSourceFilter;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -104,11 +101,6 @@ public abstract class BaseWebProjectImpl extends BaseProjectImpl implements RMCo
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public RMProject getRmProject() {
|
||||
return this.project;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for Bulk Update of resources properties paths
|
||||
*
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 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;
|
||||
|
||||
import io.cloudbeaver.model.session.WebHeadlessSession;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.rm.RMProject;
|
||||
|
||||
public class WebHeadlessSessionProjectImpl extends WebProjectImpl {
|
||||
public WebHeadlessSessionProjectImpl(
|
||||
@NotNull WebHeadlessSession session,
|
||||
@NotNull RMProject project
|
||||
) {
|
||||
super(
|
||||
session.getWorkspace(),
|
||||
session.getUserContext().getRmController(),
|
||||
session.getSessionContext(),
|
||||
project,
|
||||
session.getUserContext().getPreferenceStore()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -33,16 +33,15 @@ import org.jkiss.dbeaver.runtime.DBWorkbench;
|
||||
public abstract class WebProjectImpl extends BaseWebProjectImpl {
|
||||
private static final Log log = Log.getLog(WebProjectImpl.class);
|
||||
@NotNull
|
||||
private final DBPPreferenceStore preferenceStore;
|
||||
protected final DBPPreferenceStore preferenceStore;
|
||||
public WebProjectImpl(
|
||||
@NotNull DBPWorkspace workspace,
|
||||
@NotNull RMController resourceController,
|
||||
@NotNull SMSessionContext sessionContext,
|
||||
@NotNull RMProject project,
|
||||
@NotNull DataSourceFilter dataSourceFilter,
|
||||
@NotNull DBPPreferenceStore preferenceStore
|
||||
) {
|
||||
super(workspace, resourceController, sessionContext, project, dataSourceFilter);
|
||||
super(workspace, resourceController, sessionContext, project);
|
||||
this.preferenceStore = preferenceStore;
|
||||
}
|
||||
|
||||
@@ -82,8 +81,13 @@ public abstract class WebProjectImpl extends BaseWebProjectImpl {
|
||||
protected DBPDataSourceRegistry createDataSourceRegistry() {
|
||||
return new WebDataSourceRegistryProxy(
|
||||
new DataSourceRegistryRM(this, getResourceController(), preferenceStore),
|
||||
dataSourceFilter
|
||||
getDataSourceFilter()
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DataSourceFilter getDataSourceFilter() {
|
||||
return (ds) -> true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 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;
|
||||
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
|
||||
import org.jkiss.dbeaver.model.DBPEvent;
|
||||
import org.jkiss.dbeaver.model.rm.RMProject;
|
||||
import org.jkiss.dbeaver.model.security.SMObjectType;
|
||||
import org.jkiss.dbeaver.model.security.user.SMObjectPermissions;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Global project.
|
||||
* Connections there can be not accessible.
|
||||
*/
|
||||
public class WebSessionGlobalProjectImpl extends WebSessionProjectImpl {
|
||||
private static final Log log = Log.getLog(WebSessionGlobalProjectImpl.class);
|
||||
private Set<String> accessibleConnectionIds = Collections.emptySet();
|
||||
|
||||
public WebSessionGlobalProjectImpl(@NotNull WebSession webSession, @NotNull RMProject project) {
|
||||
super(webSession, project);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update info about accessible connections from a database.
|
||||
*/
|
||||
public synchronized void refreshAccessibleConnectionIds() {
|
||||
this.accessibleConnectionIds = readAccessibleConnectionIds();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Set<String> readAccessibleConnectionIds() {
|
||||
try {
|
||||
return webSession.getSecurityController()
|
||||
.getAllAvailableObjectsPermissions(SMObjectType.datasource)
|
||||
.stream()
|
||||
.map(SMObjectPermissions::getObjectId)
|
||||
.collect(Collectors.toSet());
|
||||
} catch (DBException e) {
|
||||
webSession.addSessionError(e);
|
||||
log.error("Error reading connection grants", e);
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if connection is accessible for current user.
|
||||
*/
|
||||
public boolean isDataSourceAccessible(@NotNull DBPDataSourceContainer dataSource) {
|
||||
return dataSource.isExternallyProvided() ||
|
||||
dataSource.isTemporary() ||
|
||||
webSession.hasPermission(DBWConstants.PERMISSION_ADMIN) ||
|
||||
accessibleConnectionIds.contains(dataSource.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a connection if it became accessible.
|
||||
* The method is processed when connection permissions were updated.
|
||||
*/
|
||||
public synchronized void addAccessibleConnectionToCache(@NotNull String dsId) {
|
||||
if (!getRMProject().isGlobal()) {
|
||||
return;
|
||||
}
|
||||
this.accessibleConnectionIds.add(dsId);
|
||||
var registry = getDataSourceRegistry();
|
||||
var dataSource = registry.getDataSource(dsId);
|
||||
if (dataSource != null) {
|
||||
addConnection(dataSource);
|
||||
// reflect changes is navigator model
|
||||
registry.notifyDataSourceListeners(new DBPEvent(DBPEvent.Action.OBJECT_ADD, dataSource, true));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a connection if it became not accessible.
|
||||
* The method is processed when connection permissions were updated.
|
||||
*/
|
||||
public synchronized void removeAccessibleConnectionFromCache(@NotNull String dsId) {
|
||||
if (!getRMProject().isGlobal()) {
|
||||
return;
|
||||
}
|
||||
var registry = getDataSourceRegistry();
|
||||
var dataSource = registry.getDataSource(dsId);
|
||||
if (dataSource != null) {
|
||||
this.accessibleConnectionIds.remove(dsId);
|
||||
removeConnection(dataSource);
|
||||
// reflect changes is navigator model
|
||||
registry.notifyDataSourceListeners(new DBPEvent(DBPEvent.Action.OBJECT_REMOVE, dataSource));
|
||||
dataSource.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DataSourceFilter getDataSourceFilter() {
|
||||
return this::isDataSourceAccessible;
|
||||
}
|
||||
}
|
||||
@@ -16,27 +16,39 @@
|
||||
*/
|
||||
package io.cloudbeaver;
|
||||
|
||||
import io.cloudbeaver.model.WebConnectionInfo;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.utils.WebDataSourceUtils;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
|
||||
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
|
||||
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistryCache;
|
||||
import org.jkiss.dbeaver.model.navigator.DBNModel;
|
||||
import org.jkiss.dbeaver.model.rm.RMProject;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEventType;
|
||||
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
|
||||
import org.jkiss.dbeaver.runtime.jobs.DisconnectJob;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class WebSessionProjectImpl extends WebProjectImpl {
|
||||
|
||||
private final WebSession webSession;
|
||||
private static final Log log = Log.getLog(WebSessionProjectImpl.class);
|
||||
protected final WebSession webSession;
|
||||
private final Map<String, WebConnectionInfo> connections = new HashMap<>();
|
||||
private boolean registryIsLoaded = false;
|
||||
|
||||
public WebSessionProjectImpl(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull RMProject project,
|
||||
@NotNull DataSourceFilter dataSourceFilter
|
||||
@NotNull RMProject project
|
||||
) {
|
||||
super(
|
||||
webSession.getWorkspace(),
|
||||
webSession.getRmController(),
|
||||
webSession.getSessionContext(),
|
||||
project,
|
||||
dataSourceFilter,
|
||||
webSession.getUserPreferenceStore()
|
||||
);
|
||||
this.webSession = webSession;
|
||||
@@ -47,4 +59,156 @@ public class WebSessionProjectImpl extends WebProjectImpl {
|
||||
public DBNModel getNavigatorModel() {
|
||||
return webSession.getNavigatorModel();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected DBPDataSourceRegistry createDataSourceRegistry() {
|
||||
DBPDataSourceRegistry dataSourceRegistry = super.createDataSourceRegistry();
|
||||
dataSourceRegistry.setAuthCredentialsProvider(webSession);
|
||||
return dataSourceRegistry;
|
||||
}
|
||||
|
||||
private synchronized void addDataSourcesToCache() {
|
||||
if (registryIsLoaded) {
|
||||
return;
|
||||
}
|
||||
getDataSourceRegistry().getDataSources().forEach(this::addConnection);
|
||||
Throwable lastError = getDataSourceRegistry().getLastError();
|
||||
if (lastError != null) {
|
||||
webSession.addSessionError(lastError);
|
||||
log.error("Error refreshing connections from project '" + getId() + "'", lastError);
|
||||
}
|
||||
registryIsLoaded = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
Map<String, WebConnectionInfo> conCopy;
|
||||
synchronized (this.connections) {
|
||||
conCopy = new HashMap<>(this.connections);
|
||||
this.connections.clear();
|
||||
}
|
||||
|
||||
for (WebConnectionInfo connectionInfo : conCopy.values()) {
|
||||
if (connectionInfo.isConnected()) {
|
||||
new DisconnectJob(connectionInfo.getDataSourceContainer()).schedule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns web connection info from cache (if exists).
|
||||
*/
|
||||
@Nullable
|
||||
public WebConnectionInfo findWebConnectionInfo(@NotNull String connectionId) {
|
||||
synchronized (connections) {
|
||||
return connections.get(connectionId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns web connection info from cache, adds it to cache if not present.
|
||||
* Throws exception if connection is not found.
|
||||
*/
|
||||
@NotNull
|
||||
public WebConnectionInfo getWebConnectionInfo(@NotNull String connectionId) throws DBWebException {
|
||||
WebConnectionInfo connectionInfo = findWebConnectionInfo(connectionId);
|
||||
if (connectionInfo != null) {
|
||||
return connectionInfo;
|
||||
}
|
||||
DBPDataSourceContainer dataSource = getDataSourceRegistry().getDataSource(connectionId);
|
||||
if (dataSource != null) {
|
||||
return addConnection(dataSource);
|
||||
}
|
||||
throw new DBWebException("Connection '%s' not found".formatted(connectionId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds connection to project cache.
|
||||
*/
|
||||
@NotNull
|
||||
public synchronized WebConnectionInfo addConnection(@NotNull DBPDataSourceContainer dataSourceContainer) {
|
||||
WebConnectionInfo connection = new WebConnectionInfo(webSession, dataSourceContainer);
|
||||
synchronized (connections) {
|
||||
connections.put(dataSourceContainer.getId(), connection);
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes connection from project cache.
|
||||
*/
|
||||
public void removeConnection(@NotNull DBPDataSourceContainer dataSourceContainer) {
|
||||
WebConnectionInfo webConnectionInfo = connections.get(dataSourceContainer.getId());
|
||||
if (webConnectionInfo != null) {
|
||||
webConnectionInfo.clearCache();
|
||||
synchronized (connections) {
|
||||
connections.remove(dataSourceContainer.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads connection from registry if they are not loaded.
|
||||
*
|
||||
* @return connections from cache.
|
||||
*/
|
||||
public List<WebConnectionInfo> getConnections() {
|
||||
if (!registryIsLoaded) {
|
||||
addDataSourcesToCache();
|
||||
registryIsLoaded = true;
|
||||
}
|
||||
synchronized (connections) {
|
||||
return new ArrayList<>(connections.values());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* updates data sources based on event in web session
|
||||
*
|
||||
* @param dataSourceIds list of updated connections
|
||||
* @param type type of event
|
||||
*/
|
||||
public synchronized boolean updateProjectDataSources(@NotNull List<String> dataSourceIds, @NotNull WSEventType type) {
|
||||
var sendDataSourceUpdatedEvent = false;
|
||||
DBPDataSourceRegistry registry = getDataSourceRegistry();
|
||||
// save old connections
|
||||
var oldDataSources = dataSourceIds.stream()
|
||||
.map(registry::getDataSource)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toMap(
|
||||
DBPDataSourceContainer::getId,
|
||||
ds -> new DataSourceDescriptor((DataSourceDescriptor) ds, ds.getRegistry())
|
||||
));
|
||||
if (type == WSEventType.DATASOURCE_CREATED || type == WSEventType.DATASOURCE_UPDATED) {
|
||||
registry.refreshConfig(dataSourceIds);
|
||||
}
|
||||
for (String dsId : dataSourceIds) {
|
||||
DataSourceDescriptor ds = (DataSourceDescriptor) registry.getDataSource(dsId);
|
||||
if (ds == null) {
|
||||
continue;
|
||||
}
|
||||
switch (type) {
|
||||
case DATASOURCE_CREATED -> {
|
||||
addConnection(ds);
|
||||
sendDataSourceUpdatedEvent = true;
|
||||
}
|
||||
case DATASOURCE_UPDATED -> // if settings were changed we need to send event
|
||||
sendDataSourceUpdatedEvent |= !ds.equalSettings(oldDataSources.get(dsId));
|
||||
case DATASOURCE_DELETED -> {
|
||||
WebDataSourceUtils.disconnectDataSource(webSession, ds);
|
||||
if (registry instanceof DBPDataSourceRegistryCache dsrc) {
|
||||
dsrc.removeDataSourceFromList(ds);
|
||||
}
|
||||
removeConnection(ds);
|
||||
sendDataSourceUpdatedEvent = true;
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
return sendDataSourceUpdatedEvent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,10 +445,10 @@ public class WebConnectionInfo {
|
||||
|
||||
private boolean hasProjectPermission(RMProjectPermission projectPermission) {
|
||||
DBPProject project = dataSourceContainer.getProject();
|
||||
if (!(project instanceof WebProjectImpl)) {
|
||||
if (!(project instanceof WebProjectImpl webProject)) {
|
||||
return false;
|
||||
}
|
||||
return SMUtils.hasProjectPermission(session, ((WebProjectImpl) project).getRmProject(), projectPermission);
|
||||
return SMUtils.hasProjectPermission(session, webProject.getRMProject(), projectPermission);
|
||||
}
|
||||
|
||||
private boolean canViewReadOnlyConnections() {
|
||||
|
||||
@@ -53,11 +53,13 @@ public class WebProjectInfo {
|
||||
}
|
||||
|
||||
@Property
|
||||
public boolean isGlobal() { return project.getRmProject().isGlobal(); }
|
||||
public boolean isGlobal() {
|
||||
return project.getRMProject().isGlobal();
|
||||
}
|
||||
|
||||
@Property
|
||||
public boolean isShared() {
|
||||
return project.getRmProject().isShared();
|
||||
return project.getRMProject().isShared();
|
||||
}
|
||||
|
||||
@Property
|
||||
@@ -72,7 +74,7 @@ public class WebProjectInfo {
|
||||
|
||||
@Property
|
||||
public boolean isCanEditDataSources() {
|
||||
if (project.getRmProject().getType() == RMProjectType.USER && !customPrivateConnectionsEnabled) {
|
||||
if (project.getRMProject().getType() == RMProjectType.USER && !customPrivateConnectionsEnabled) {
|
||||
return false;
|
||||
}
|
||||
return hasDataSourcePermission(RMProjectPermission.DATA_SOURCES_EDIT);
|
||||
@@ -94,12 +96,12 @@ public class WebProjectInfo {
|
||||
}
|
||||
|
||||
private boolean hasDataSourcePermission(RMProjectPermission permission) {
|
||||
return SMUtils.hasProjectPermission(session, project.getRmProject(), permission);
|
||||
return SMUtils.hasProjectPermission(session, project.getRMProject(), permission);
|
||||
}
|
||||
|
||||
@Property
|
||||
public RMResourceType[] getResourceTypes() {
|
||||
RMResourceType[] resourceTypes = project.getRmProject().getResourceTypes();
|
||||
RMResourceType[] resourceTypes = project.getRMProject().getResourceTypes();
|
||||
|
||||
if(resourceTypes == null) {
|
||||
return ArrayUtils.toArray(RMResourceType.class, new ArrayList<>());
|
||||
|
||||
-144
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 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.app;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import io.cloudbeaver.auth.provider.local.LocalAuthProviderConstants;
|
||||
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
|
||||
import io.cloudbeaver.registry.WebAuthProviderRegistry;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration;
|
||||
import org.jkiss.utils.ArrayUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public abstract class BaseAuthWebAppConfiguration extends BaseWebAppConfiguration implements WebAuthConfiguration {
|
||||
private String defaultAuthProvider;
|
||||
private String[] enabledAuthProviders;
|
||||
private final Set<SMAuthProviderCustomConfiguration> authConfigurations;
|
||||
// Legacy auth configs, left for backward compatibility
|
||||
@Expose(serialize = false)
|
||||
private final Map<String, SMAuthProviderCustomConfiguration> authConfiguration;
|
||||
|
||||
public BaseAuthWebAppConfiguration() {
|
||||
super();
|
||||
this.defaultAuthProvider = LocalAuthProviderConstants.PROVIDER_ID;
|
||||
this.enabledAuthProviders = null;
|
||||
this.authConfigurations = new LinkedHashSet<>();
|
||||
this.authConfiguration = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
public BaseAuthWebAppConfiguration(BaseAuthWebAppConfiguration src) {
|
||||
super(src);
|
||||
this.defaultAuthProvider = src.defaultAuthProvider;
|
||||
this.enabledAuthProviders = src.enabledAuthProviders;
|
||||
this.authConfigurations = new LinkedHashSet<>(src.authConfigurations);
|
||||
this.authConfiguration = new LinkedHashMap<>(src.authConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultAuthProvider() {
|
||||
return defaultAuthProvider;
|
||||
}
|
||||
|
||||
public void setDefaultAuthProvider(String defaultAuthProvider) {
|
||||
this.defaultAuthProvider = defaultAuthProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getEnabledAuthProviders() {
|
||||
if (enabledAuthProviders == null) {
|
||||
// No config - enable all providers (+backward compatibility)
|
||||
return WebAuthProviderRegistry.getInstance().getAuthProviders()
|
||||
.stream().map(WebAuthProviderDescriptor::getId).toArray(String[]::new);
|
||||
}
|
||||
return enabledAuthProviders;
|
||||
}
|
||||
|
||||
public void setEnabledAuthProviders(String[] enabledAuthProviders) {
|
||||
this.enabledAuthProviders = enabledAuthProviders;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isAuthProviderEnabled(String id) {
|
||||
var authProviderDescriptor = WebAuthProviderRegistry.getInstance().getAuthProvider(id);
|
||||
if (authProviderDescriptor == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ArrayUtils.contains(getEnabledAuthProviders(), id)) {
|
||||
return false;
|
||||
}
|
||||
if (!ArrayUtils.isEmpty(authProviderDescriptor.getRequiredFeatures())) {
|
||||
for (String rf : authProviderDescriptor.getRequiredFeatures()) {
|
||||
if (!isFeatureEnabled(rf)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Auth provider configs
|
||||
@Override
|
||||
public Set<SMAuthProviderCustomConfiguration> getAuthCustomConfigurations() {
|
||||
return authConfigurations;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public SMAuthProviderCustomConfiguration getAuthProviderConfiguration(@NotNull String id) {
|
||||
synchronized (authConfigurations) {
|
||||
return authConfigurations.stream().filter(c -> c.getId().equals(id)).findAny().orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void addAuthProviderConfiguration(@NotNull SMAuthProviderCustomConfiguration config) {
|
||||
synchronized (authConfigurations) {
|
||||
authConfigurations.removeIf(c -> c.getId().equals(config.getId()));
|
||||
authConfigurations.add(config);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAuthProvidersConfigurations(Collection<SMAuthProviderCustomConfiguration> authProviders) {
|
||||
synchronized (authConfigurations) {
|
||||
authConfigurations.clear();
|
||||
authConfigurations.addAll(authProviders);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean deleteAuthProviderConfiguration(@NotNull String id) {
|
||||
synchronized (authConfigurations) {
|
||||
return authConfigurations.removeIf(c -> c.getId().equals(id));
|
||||
}
|
||||
}
|
||||
|
||||
public void loadLegacyCustomConfigs() {
|
||||
// Convert legacy map of configs into list
|
||||
if (!authConfiguration.isEmpty()) {
|
||||
for (Map.Entry<String, SMAuthProviderCustomConfiguration> entry : authConfiguration.entrySet()) {
|
||||
entry.getValue().setId(entry.getKey());
|
||||
authConfigurations.add(entry.getValue());
|
||||
}
|
||||
authConfiguration.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
@@ -18,6 +18,7 @@ package io.cloudbeaver.model.app;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import org.jkiss.code.NotNull;
|
||||
|
||||
/**
|
||||
* Abstract class that contains methods for loading configuration with gson.
|
||||
@@ -25,6 +26,7 @@ import com.google.gson.GsonBuilder;
|
||||
public abstract class BaseServerConfigurationController<T extends WebServerConfiguration>
|
||||
implements WebServerConfigurationController<T> {
|
||||
|
||||
@NotNull
|
||||
public Gson getGson() {
|
||||
return getGsonBuilder().create();
|
||||
}
|
||||
|
||||
-19
@@ -16,11 +16,7 @@
|
||||
*/
|
||||
package io.cloudbeaver.model.app;
|
||||
|
||||
import io.cloudbeaver.DataSourceFilter;
|
||||
import io.cloudbeaver.WebProjectImpl;
|
||||
import io.cloudbeaver.WebSessionProjectImpl;
|
||||
import io.cloudbeaver.model.log.SLF4JLogHandler;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.equinox.app.IApplicationContext;
|
||||
import org.jkiss.code.NotNull;
|
||||
@@ -36,7 +32,6 @@ import org.jkiss.dbeaver.model.impl.app.ApplicationRegistry;
|
||||
import org.jkiss.dbeaver.model.impl.app.BaseApplicationImpl;
|
||||
import org.jkiss.dbeaver.model.impl.app.BaseWorkspaceImpl;
|
||||
import org.jkiss.dbeaver.model.rm.RMController;
|
||||
import org.jkiss.dbeaver.model.rm.RMProject;
|
||||
import org.jkiss.dbeaver.model.secret.DBSSecretController;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEventController;
|
||||
import org.jkiss.dbeaver.runtime.IVariableResolver;
|
||||
@@ -59,7 +54,6 @@ public abstract class BaseWebApplication extends BaseApplicationImpl implements
|
||||
public static final String CLI_PARAM_WEB_CONFIG = "-web-config";
|
||||
public static final String LOGBACK_FILE_NAME = "logback.xml";
|
||||
|
||||
|
||||
private static final Log log = Log.getLog(BaseWebApplication.class);
|
||||
|
||||
private String instanceId;
|
||||
@@ -161,19 +155,6 @@ public abstract class BaseWebApplication extends BaseApplicationImpl implements
|
||||
return Files.exists(customConfigPath) ? customConfigPath : configPath.resolve(fileName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebProjectImpl createProjectImpl(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull RMProject project,
|
||||
@NotNull DataSourceFilter dataSourceFilter
|
||||
) {
|
||||
return new WebSessionProjectImpl(
|
||||
webSession,
|
||||
project,
|
||||
dataSourceFilter
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* There is no secret controller in base web app.
|
||||
* Method returns VoidSecretController instance.
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
*/
|
||||
package io.cloudbeaver.model.app;
|
||||
|
||||
import io.cloudbeaver.DataSourceFilter;
|
||||
import io.cloudbeaver.WebProjectImpl;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.model.DBFileController;
|
||||
@@ -27,7 +24,6 @@ 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.rm.RMController;
|
||||
import org.jkiss.dbeaver.model.rm.RMProject;
|
||||
import org.jkiss.dbeaver.model.secret.DBSSecretController;
|
||||
import org.jkiss.dbeaver.model.security.SMAdminController;
|
||||
import org.jkiss.dbeaver.model.security.SMController;
|
||||
@@ -58,12 +54,6 @@ public interface WebApplication extends DBPApplication {
|
||||
|
||||
boolean isMultiNode();
|
||||
|
||||
WebProjectImpl createProjectImpl(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull RMProject project,
|
||||
@NotNull DataSourceFilter dataSourceFilter
|
||||
);
|
||||
|
||||
SMController createSecurityController(@NotNull SMCredentialsProvider credentialsProvider) throws DBException;
|
||||
|
||||
SMAdminController getAdminSecurityController(@NotNull SMCredentialsProvider credentialsProvider) throws DBException;
|
||||
|
||||
+114
-55
@@ -14,21 +14,19 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.cloudbeaver.server;
|
||||
package io.cloudbeaver.model.config;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.WebServiceUtils;
|
||||
import io.cloudbeaver.model.app.BaseAuthWebAppConfiguration;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import io.cloudbeaver.auth.provider.local.LocalAuthProviderConstants;
|
||||
import io.cloudbeaver.model.app.BaseWebAppConfiguration;
|
||||
import io.cloudbeaver.model.app.WebAuthConfiguration;
|
||||
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
|
||||
import io.cloudbeaver.registry.WebAuthProviderRegistry;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.connection.DBPDriver;
|
||||
import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings;
|
||||
import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration;
|
||||
import org.jkiss.dbeaver.registry.DataSourceNavigatorSettings;
|
||||
import org.jkiss.utils.ArrayUtils;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
@@ -38,11 +36,15 @@ import java.util.*;
|
||||
/**
|
||||
* Application configuration
|
||||
*/
|
||||
public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthConfiguration {
|
||||
public class CBAppConfig extends BaseWebAppConfiguration implements WebAuthConfiguration {
|
||||
private static final Log log = Log.getLog(CBAppConfig.class);
|
||||
public static final DataSourceNavigatorSettings.Preset PRESET_WEB = new DataSourceNavigatorSettings.Preset("web", "Web", "Default view");
|
||||
|
||||
public static final DataSourceNavigatorSettings DEFAULT_VIEW_SETTINGS = PRESET_WEB.getSettings();
|
||||
private final Set<SMAuthProviderCustomConfiguration> authConfigurations;
|
||||
// Legacy auth configs, left for backward compatibility
|
||||
@Expose(serialize = false)
|
||||
private final Map<String, SMAuthProviderCustomConfiguration> authConfiguration;
|
||||
|
||||
private boolean supportsCustomConnections;
|
||||
private boolean supportsConnectionBrowser;
|
||||
@@ -66,9 +68,14 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC
|
||||
private DataSourceNavigatorSettings defaultNavigatorSettings;
|
||||
|
||||
private final Map<String, Object> resourceQuotas;
|
||||
private String defaultAuthProvider;
|
||||
private String[] enabledAuthProviders;
|
||||
|
||||
public CBAppConfig() {
|
||||
super();
|
||||
this.defaultAuthProvider = LocalAuthProviderConstants.PROVIDER_ID;
|
||||
this.enabledAuthProviders = null;
|
||||
this.authConfigurations = new LinkedHashSet<>();
|
||||
this.authConfiguration = new LinkedHashMap<>();
|
||||
this.anonymousAccessEnabled = false;
|
||||
this.anonymousUserRole = DEFAULT_APP_ANONYMOUS_TEAM_NAME;
|
||||
this.anonymousUserTeam = DEFAULT_APP_ANONYMOUS_TEAM_NAME;
|
||||
@@ -91,6 +98,10 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC
|
||||
|
||||
public CBAppConfig(CBAppConfig src) {
|
||||
super(src);
|
||||
this.defaultAuthProvider = src.defaultAuthProvider;
|
||||
this.enabledAuthProviders = src.enabledAuthProviders;
|
||||
this.authConfigurations = new LinkedHashSet<>(src.authConfigurations);
|
||||
this.authConfiguration = new LinkedHashMap<>(src.authConfiguration);
|
||||
this.anonymousAccessEnabled = src.anonymousAccessEnabled;
|
||||
this.anonymousUserRole = src.anonymousUserRole;
|
||||
this.anonymousUserTeam = src.anonymousUserTeam;
|
||||
@@ -169,6 +180,10 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC
|
||||
return enabledDrivers;
|
||||
}
|
||||
|
||||
public void setEnabledDrivers(String[] enabledDrivers) {
|
||||
this.enabledDrivers = enabledDrivers;
|
||||
}
|
||||
|
||||
public String[] getDisabledDrivers() {
|
||||
return disabledDrivers;
|
||||
}
|
||||
@@ -204,19 +219,6 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC
|
||||
return getPluginConfig(pluginId, false);
|
||||
}
|
||||
|
||||
public <T> T getPluginOptions(@NotNull String pluginId, @NotNull String option, Class<T> theClass) throws DBException {
|
||||
Map<String, Object> iamSettingsMap = CBPlatform.getInstance().getApplication().getAppConfiguration().getPluginOption(
|
||||
pluginId, option);
|
||||
if (CommonUtils.isEmpty(iamSettingsMap)) {
|
||||
throw new DBException("Settings '" + option + "' not specified in plugin '" + pluginId + "' configuration");
|
||||
}
|
||||
|
||||
Gson gson = new GsonBuilder().create();
|
||||
return gson.fromJson(
|
||||
gson.toJsonTree(iamSettingsMap),
|
||||
theClass);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Quotas
|
||||
|
||||
@@ -264,38 +266,6 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC
|
||||
return grantConnectionsAccessToAnonymousTeam;
|
||||
}
|
||||
|
||||
|
||||
// we disable embedded drivers by default and enable it in enabled drivers list
|
||||
// that's why we need so complicated logic for disabling drivers
|
||||
|
||||
public void updateDisabledDriversConfig(String[] disabledDriversConfig) {
|
||||
Set<String> disabledIds = new LinkedHashSet<>(Arrays.asList(disabledDriversConfig));
|
||||
Set<String> enabledIds = new LinkedHashSet<>(Arrays.asList(this.enabledDrivers));
|
||||
|
||||
// remove all disabled embedded drivers from enabled drivers list
|
||||
enabledIds.removeAll(disabledIds);
|
||||
|
||||
// enable embedded driver if it is not in disabled drivers list
|
||||
for (String driverId : this.disabledDrivers) {
|
||||
if (disabledIds.contains(driverId)) {
|
||||
// driver is also disabled
|
||||
continue;
|
||||
}
|
||||
// driver is removed from disabled list
|
||||
// we need to enable if it is embedded
|
||||
try {
|
||||
DBPDriver driver = WebServiceUtils.getDriverById(driverId);
|
||||
if (driver.isEmbedded()) {
|
||||
enabledIds.add(driverId);
|
||||
}
|
||||
} catch (DBWebException e) {
|
||||
log.error("Failed to find driver by id", e);
|
||||
}
|
||||
}
|
||||
this.disabledDrivers = disabledDriversConfig;
|
||||
this.enabledDrivers = enabledIds.toArray(String[]::new);
|
||||
}
|
||||
|
||||
public boolean isDriverForceEnabled(@NotNull String driverId) {
|
||||
return ArrayUtils.containsIgnoreCase(getEnabledDrivers(), driverId);
|
||||
}
|
||||
@@ -303,4 +273,93 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC
|
||||
public boolean isSystemVariablesResolvingEnabled() {
|
||||
return systemVariablesResolvingEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultAuthProvider() {
|
||||
return defaultAuthProvider;
|
||||
}
|
||||
|
||||
public void setDefaultAuthProvider(String defaultAuthProvider) {
|
||||
this.defaultAuthProvider = defaultAuthProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getEnabledAuthProviders() {
|
||||
if (enabledAuthProviders == null) {
|
||||
// No config - enable all providers (+backward compatibility)
|
||||
return WebAuthProviderRegistry.getInstance().getAuthProviders()
|
||||
.stream().map(WebAuthProviderDescriptor::getId).toArray(String[]::new);
|
||||
}
|
||||
return enabledAuthProviders;
|
||||
}
|
||||
|
||||
public void setEnabledAuthProviders(String[] enabledAuthProviders) {
|
||||
this.enabledAuthProviders = enabledAuthProviders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthProviderEnabled(String id) {
|
||||
var authProviderDescriptor = WebAuthProviderRegistry.getInstance().getAuthProvider(id);
|
||||
if (authProviderDescriptor == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ArrayUtils.contains(getEnabledAuthProviders(), id)) {
|
||||
return false;
|
||||
}
|
||||
if (!ArrayUtils.isEmpty(authProviderDescriptor.getRequiredFeatures())) {
|
||||
for (String rf : authProviderDescriptor.getRequiredFeatures()) {
|
||||
if (!isFeatureEnabled(rf)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Auth provider configs
|
||||
@Override
|
||||
public Set<SMAuthProviderCustomConfiguration> getAuthCustomConfigurations() {
|
||||
return authConfigurations;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public SMAuthProviderCustomConfiguration getAuthProviderConfiguration(@NotNull String id) {
|
||||
synchronized (authConfigurations) {
|
||||
return authConfigurations.stream().filter(c -> c.getId().equals(id)).findAny().orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void addAuthProviderConfiguration(@NotNull SMAuthProviderCustomConfiguration config) {
|
||||
synchronized (authConfigurations) {
|
||||
authConfigurations.removeIf(c -> c.getId().equals(config.getId()));
|
||||
authConfigurations.add(config);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAuthProvidersConfigurations(Collection<SMAuthProviderCustomConfiguration> authProviders) {
|
||||
synchronized (authConfigurations) {
|
||||
authConfigurations.clear();
|
||||
authConfigurations.addAll(authProviders);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean deleteAuthProviderConfiguration(@NotNull String id) {
|
||||
synchronized (authConfigurations) {
|
||||
return authConfigurations.removeIf(c -> c.getId().equals(id));
|
||||
}
|
||||
}
|
||||
|
||||
public void loadLegacyCustomConfigs() {
|
||||
// Convert legacy map of configs into list
|
||||
if (!authConfiguration.isEmpty()) {
|
||||
for (Map.Entry<String, SMAuthProviderCustomConfiguration> entry : authConfiguration.entrySet()) {
|
||||
entry.getValue().setId(entry.getKey());
|
||||
authConfigurations.add(entry.getValue());
|
||||
}
|
||||
authConfiguration.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -14,13 +14,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.cloudbeaver.server;
|
||||
package io.cloudbeaver.model.config;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import io.cloudbeaver.auth.CBAuthConstants;
|
||||
import io.cloudbeaver.model.app.WebServerConfiguration;
|
||||
import io.cloudbeaver.service.security.SMControllerConfiguration;
|
||||
import io.cloudbeaver.service.security.db.WebDatabaseConfig;
|
||||
import io.cloudbeaver.server.CBConstants;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.cloudbeaver.service.security;
|
||||
package io.cloudbeaver.model.config;
|
||||
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.cloudbeaver.service.security;
|
||||
package io.cloudbeaver.model.config;
|
||||
|
||||
public class SMControllerConfiguration {
|
||||
//in minutes
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.cloudbeaver.service.security.db;
|
||||
package io.cloudbeaver.model.config;
|
||||
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.connection.InternalDatabaseConfig;
|
||||
+13
-15
@@ -20,7 +20,6 @@ package io.cloudbeaver.model.rm;
|
||||
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.DBIcon;
|
||||
import org.jkiss.dbeaver.model.DBPImage;
|
||||
import org.jkiss.dbeaver.model.DBPObject;
|
||||
@@ -37,7 +36,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DBNResourceManagerProject extends DBNAbstractResourceManagerNode {
|
||||
private static final Log log = Log.getLog(DBNResourceManagerProject.class);
|
||||
|
||||
private final RMProject project;
|
||||
|
||||
@@ -123,21 +121,15 @@ public class DBNResourceManagerProject extends DBNAbstractResourceManagerNode {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String toString() {
|
||||
return getNodeDisplayName();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DBPProject getOwnerProject() {
|
||||
public DBPProject getOwnerProjectOrNull() {
|
||||
List<? extends DBPProject> globalProjects = getModel().getModelProjects();
|
||||
if (globalProjects == null) {
|
||||
return null;
|
||||
}
|
||||
for (DBPProject modelProject : globalProjects) {
|
||||
if (CommonUtils.equalObjects(modelProject.getId(), project.getId())) {
|
||||
return modelProject;
|
||||
if (globalProjects != null) {
|
||||
for (DBPProject modelProject : globalProjects) {
|
||||
if (CommonUtils.equalObjects(modelProject.getId(), project.getId())) {
|
||||
return modelProject;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -148,4 +140,10 @@ public class DBNResourceManagerProject extends DBNAbstractResourceManagerNode {
|
||||
public DBPObject getObjectDetails(@NotNull DBRProgressMonitor monitor, @NotNull SMSessionContext sessionContext, @NotNull Object dataSource) throws DBException {
|
||||
return project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getNodeDisplayName();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-2
@@ -203,9 +203,10 @@ public class DBNResourceManagerResource extends DBNAbstractResourceManagerNode {
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public DBPProject getOwnerProject() {
|
||||
return getParentNode().getOwnerProject();
|
||||
public DBPProject getOwnerProjectOrNull() {
|
||||
return getParentNode().getOwnerProjectOrNull();
|
||||
}
|
||||
|
||||
public RMResource getResource() {
|
||||
|
||||
+1
-2
@@ -1291,8 +1291,7 @@ public class LocalResourceController implements RMController {
|
||||
LocalResourceController.this.workspace,
|
||||
LocalResourceController.this,
|
||||
sessionContext,
|
||||
rmProject,
|
||||
(container) -> true);
|
||||
rmProject);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+7
-3
@@ -51,14 +51,14 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
|
||||
@NotNull
|
||||
protected final WebUserContext userContext;
|
||||
@NotNull
|
||||
protected final WebAuthApplication application;
|
||||
protected final WebApplication application;
|
||||
protected volatile long lastAccessTime;
|
||||
|
||||
private final List<CBWebSessionEventHandler> sessionEventHandlers = new CopyOnWriteArrayList<>();
|
||||
private WebSessionEventsFilter eventsFilter = new WebSessionEventsFilter();
|
||||
private final WebSessionWorkspace workspace;
|
||||
|
||||
public BaseWebSession(@NotNull String id, @NotNull WebAuthApplication application) throws DBException {
|
||||
public BaseWebSession(@NotNull String id, @NotNull WebApplication application) throws DBException {
|
||||
this.id = id;
|
||||
this.application = application;
|
||||
this.createTime = System.currentTimeMillis();
|
||||
@@ -72,6 +72,7 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
|
||||
return new WebUserContext(this.application, this.workspace);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public WebSessionWorkspace getWorkspace() {
|
||||
return workspace;
|
||||
}
|
||||
@@ -232,6 +233,9 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
|
||||
|
||||
@Property
|
||||
public long getRemainingTime() {
|
||||
return application.getMaxSessionIdleTime() + lastAccessTime - System.currentTimeMillis();
|
||||
if (application instanceof WebAuthApplication authApplication) {
|
||||
return authApplication.getMaxSessionIdleTime() + lastAccessTime - System.currentTimeMillis();
|
||||
}
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
+71
-253
@@ -19,19 +19,17 @@ package io.cloudbeaver.model.session;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.InstanceCreator;
|
||||
import io.cloudbeaver.DBWConstants;
|
||||
import io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.DataSourceFilter;
|
||||
import io.cloudbeaver.WebProjectImpl;
|
||||
import com.google.gson.Strictness;
|
||||
import io.cloudbeaver.*;
|
||||
import io.cloudbeaver.model.WebAsyncTaskInfo;
|
||||
import io.cloudbeaver.model.WebConnectionInfo;
|
||||
import io.cloudbeaver.model.WebServerMessage;
|
||||
import io.cloudbeaver.model.app.WebApplication;
|
||||
import io.cloudbeaver.model.app.WebAuthApplication;
|
||||
import io.cloudbeaver.model.user.WebUser;
|
||||
import io.cloudbeaver.service.DBWSessionHandler;
|
||||
import io.cloudbeaver.service.sql.WebSQLConstants;
|
||||
import io.cloudbeaver.utils.CBModelConstants;
|
||||
import io.cloudbeaver.utils.WebAppUtils;
|
||||
import io.cloudbeaver.utils.WebDataSourceUtils;
|
||||
import org.eclipse.core.runtime.IAdaptable;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
@@ -42,12 +40,8 @@ import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.DBFileController;
|
||||
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
|
||||
import org.jkiss.dbeaver.model.DBPEvent;
|
||||
import org.jkiss.dbeaver.model.access.DBAAuthCredentials;
|
||||
import org.jkiss.dbeaver.model.access.DBACredentialsProvider;
|
||||
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
|
||||
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistryCache;
|
||||
import org.jkiss.dbeaver.model.app.DBPProject;
|
||||
import org.jkiss.dbeaver.model.auth.*;
|
||||
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
|
||||
import org.jkiss.dbeaver.model.exec.DBCException;
|
||||
@@ -67,15 +61,11 @@ import org.jkiss.dbeaver.model.runtime.ProxyProgressMonitor;
|
||||
import org.jkiss.dbeaver.model.security.SMAdminController;
|
||||
import org.jkiss.dbeaver.model.security.SMConstants;
|
||||
import org.jkiss.dbeaver.model.security.SMController;
|
||||
import org.jkiss.dbeaver.model.security.SMObjectType;
|
||||
import org.jkiss.dbeaver.model.security.user.SMObjectPermissions;
|
||||
import org.jkiss.dbeaver.model.sql.DBQuotaException;
|
||||
import org.jkiss.dbeaver.model.websocket.event.MessageType;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEventType;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSSessionLogUpdatedEvent;
|
||||
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
|
||||
import org.jkiss.dbeaver.runtime.DBWorkbench;
|
||||
import org.jkiss.dbeaver.runtime.jobs.DisconnectJob;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@@ -88,6 +78,7 @@ import java.util.stream.Collectors;
|
||||
* Web session.
|
||||
* Is the main source of data in web application
|
||||
*/
|
||||
//TODO: split to authenticated and non authenticated context
|
||||
public class WebSession extends BaseWebSession
|
||||
implements SMSessionWithAuth, SMCredentialsProvider, DBACredentialsProvider, IAdaptable {
|
||||
|
||||
@@ -104,12 +95,10 @@ public class WebSession extends BaseWebSession
|
||||
private String lastRemoteAddr;
|
||||
private String lastRemoteUserAgent;
|
||||
|
||||
private Set<String> accessibleConnectionIds = Collections.emptySet();
|
||||
|
||||
private String locale;
|
||||
private boolean cacheExpired;
|
||||
|
||||
private final Map<String, WebConnectionInfo> connections = new HashMap<>();
|
||||
protected WebSessionGlobalProjectImpl globalProject;
|
||||
private final List<WebServerMessage> sessionMessages = new ArrayList<>();
|
||||
|
||||
private final Map<String, WebAsyncTaskInfo> asyncTasks = new HashMap<>();
|
||||
@@ -127,17 +116,30 @@ public class WebSession extends BaseWebSession
|
||||
@NotNull WebAuthApplication application,
|
||||
@NotNull Map<String, DBWSessionHandler> sessionHandlers
|
||||
) throws DBException {
|
||||
super(requestInfo.getId(), application);
|
||||
this(requestInfo.getId(),
|
||||
CommonUtils.toString(requestInfo.getLocale()),
|
||||
application,
|
||||
sessionHandlers
|
||||
);
|
||||
updateSessionParameters(requestInfo);
|
||||
}
|
||||
|
||||
protected WebSession(
|
||||
@NotNull String id,
|
||||
@Nullable String locale,
|
||||
@NotNull WebApplication application,
|
||||
@NotNull Map<String, DBWSessionHandler> sessionHandlers
|
||||
) throws DBException {
|
||||
super(id, application);
|
||||
this.lastAccessTime = this.createTime;
|
||||
setLocale(CommonUtils.toString(requestInfo.getLocale(), this.locale));
|
||||
this.sessionHandlers = sessionHandlers;
|
||||
setLocale(CommonUtils.toString(locale, this.locale));
|
||||
//force authorization of anonymous session to avoid access error,
|
||||
//because before authorization could be called by any request,
|
||||
//but now 'updateInfo' is called only in special requests,
|
||||
//and the order of requests is not guaranteed.
|
||||
//look at CB-4747
|
||||
refreshSessionAuth();
|
||||
updateSessionParameters(requestInfo);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -151,8 +153,8 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DBPProject getSingletonProject() {
|
||||
@Nullable
|
||||
public WebSessionProjectImpl getSingletonProject() {
|
||||
return getWorkspace().getActiveProject();
|
||||
}
|
||||
|
||||
@@ -249,69 +251,6 @@ public class WebSession extends BaseWebSession
|
||||
initNavigatorModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* updates data sources based on event in web session
|
||||
*
|
||||
* @param project project of connection
|
||||
* @param dataSourceIds list of updated connections
|
||||
* @param type type of event
|
||||
*/
|
||||
public synchronized boolean updateProjectDataSources(
|
||||
DBPProject project,
|
||||
List<String> dataSourceIds,
|
||||
WSEventType type
|
||||
) {
|
||||
var sendDataSourceUpdatedEvent = false;
|
||||
DBPDataSourceRegistry registry = project.getDataSourceRegistry();
|
||||
// save old connections
|
||||
var oldDataSources = dataSourceIds.stream()
|
||||
.map(registry::getDataSource)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toMap(
|
||||
DBPDataSourceContainer::getId,
|
||||
ds -> new DataSourceDescriptor((DataSourceDescriptor) ds, ds.getRegistry())
|
||||
));
|
||||
if (type == WSEventType.DATASOURCE_CREATED || type == WSEventType.DATASOURCE_UPDATED) {
|
||||
registry.refreshConfig(dataSourceIds);
|
||||
}
|
||||
for (String dsId : dataSourceIds) {
|
||||
DataSourceDescriptor ds = (DataSourceDescriptor) registry.getDataSource(dsId);
|
||||
if (ds == null) {
|
||||
continue;
|
||||
}
|
||||
switch (type) {
|
||||
case DATASOURCE_CREATED -> {
|
||||
WebConnectionInfo connectionInfo = new WebConnectionInfo(this, ds);
|
||||
this.connections.put(getConnectionId(ds), connectionInfo);
|
||||
sendDataSourceUpdatedEvent = true;
|
||||
}
|
||||
case DATASOURCE_UPDATED -> // if settings were changed we need to send event
|
||||
sendDataSourceUpdatedEvent |= !ds.equalSettings(oldDataSources.get(dsId));
|
||||
case DATASOURCE_DELETED -> {
|
||||
WebDataSourceUtils.disconnectDataSource(this, ds);
|
||||
if (registry instanceof DBPDataSourceRegistryCache dsrc) {
|
||||
dsrc.removeDataSourceFromList(ds);
|
||||
}
|
||||
this.connections.remove(getConnectionId(ds));
|
||||
sendDataSourceUpdatedEvent = true;
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
return sendDataSourceUpdatedEvent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getConnectionId(@NotNull DBPDataSourceContainer container) {
|
||||
return getConnectionId(container.getProject().getId(), container.getId());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getConnectionId(@NotNull String projectId, @NotNull String dsId) {
|
||||
return projectId + ":" + dsId;
|
||||
}
|
||||
|
||||
// Note: for admin use only
|
||||
public synchronized void resetUserState() throws DBException {
|
||||
clearAuthTokens();
|
||||
@@ -332,7 +271,7 @@ public class WebSession extends BaseWebSession
|
||||
this.navigatorModel.dispose();
|
||||
this.navigatorModel = null;
|
||||
}
|
||||
this.connections.clear();
|
||||
this.globalProject = null;
|
||||
|
||||
loadProjects();
|
||||
|
||||
@@ -352,7 +291,6 @@ public class WebSession extends BaseWebSession
|
||||
// No anonymous mode in distributed apps
|
||||
return;
|
||||
}
|
||||
refreshAccessibleConnectionIds();
|
||||
try {
|
||||
RMController controller = getRmController();
|
||||
RMProject[] rmProjects = controller.listAccessibleProjects();
|
||||
@@ -372,57 +310,28 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
}
|
||||
|
||||
public WebProjectImpl createWebProject(RMProject project) {
|
||||
// Do not filter data sources from user project
|
||||
DataSourceFilter filter = project.getType() == RMProjectType.GLOBAL
|
||||
? this::isDataSourceAccessible
|
||||
: x -> true;
|
||||
WebProjectImpl sessionProject = application.createProjectImpl(this, project, filter);
|
||||
private WebSessionProjectImpl createWebProject(RMProject project) {
|
||||
WebSessionProjectImpl sessionProject;
|
||||
if (project.isGlobal()) {
|
||||
sessionProject = createGlobalProject(project);
|
||||
} else {
|
||||
sessionProject = new WebSessionProjectImpl(this, project);
|
||||
}
|
||||
// do not load data sources for anonymous project
|
||||
if (project.getType() == RMProjectType.USER && userContext.getUser() == null) {
|
||||
sessionProject.setInMemory(true);
|
||||
}
|
||||
DBPDataSourceRegistry dataSourceRegistry = sessionProject.getDataSourceRegistry();
|
||||
dataSourceRegistry.setAuthCredentialsProvider(this);
|
||||
addSessionProject(sessionProject);
|
||||
if (!project.isShared() || application.isConfigurationMode()) {
|
||||
getWorkspace().setActiveProject(sessionProject);
|
||||
}
|
||||
for (DBPDataSourceContainer ds : dataSourceRegistry.getDataSources()) {
|
||||
addConnection(new WebConnectionInfo(this, ds));
|
||||
}
|
||||
Throwable lastError = dataSourceRegistry.getLastError();
|
||||
if (lastError != null) {
|
||||
addSessionError(lastError);
|
||||
log.error("Error refreshing connections from project '" + project.getId() + "'", lastError);
|
||||
}
|
||||
return sessionProject;
|
||||
}
|
||||
|
||||
public void filterAccessibleConnections(List<WebConnectionInfo> connections) {
|
||||
connections.removeIf(c -> !isDataSourceAccessible(c.getDataSourceContainer()));
|
||||
}
|
||||
|
||||
private boolean isDataSourceAccessible(DBPDataSourceContainer dataSource) {
|
||||
return dataSource.isExternallyProvided() ||
|
||||
dataSource.isTemporary() ||
|
||||
this.hasPermission(DBWConstants.PERMISSION_ADMIN) ||
|
||||
accessibleConnectionIds.contains(dataSource.getId());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Set<String> readAccessibleConnectionIds() {
|
||||
try {
|
||||
return getSecurityController()
|
||||
.getAllAvailableObjectsPermissions(SMObjectType.datasource)
|
||||
.stream()
|
||||
.map(SMObjectPermissions::getObjectId)
|
||||
.collect(Collectors.toSet());
|
||||
} catch (DBException e) {
|
||||
addSessionError(e);
|
||||
log.error("Error reading connection grants", e);
|
||||
return Collections.emptySet();
|
||||
}
|
||||
protected WebSessionProjectImpl createGlobalProject(RMProject project) {
|
||||
globalProject = new WebSessionGlobalProjectImpl(this, project);
|
||||
globalProject.refreshAccessibleConnectionIds();
|
||||
return globalProject;
|
||||
}
|
||||
|
||||
private void resetSessionCache() throws DBCException {
|
||||
@@ -440,17 +349,7 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
|
||||
private void resetNavigationModel() {
|
||||
Map<String, WebConnectionInfo> conCopy;
|
||||
synchronized (this.connections) {
|
||||
conCopy = new HashMap<>(this.connections);
|
||||
this.connections.clear();
|
||||
}
|
||||
|
||||
for (WebConnectionInfo connectionInfo : conCopy.values()) {
|
||||
if (connectionInfo.isConnected()) {
|
||||
new DisconnectJob(connectionInfo.getDataSourceContainer()).schedule();
|
||||
}
|
||||
}
|
||||
getWorkspace().getProjects().forEach(WebSessionProjectImpl::dispose);
|
||||
|
||||
if (this.navigatorModel != null) {
|
||||
this.navigatorModel.dispose();
|
||||
@@ -464,7 +363,9 @@ public class WebSession extends BaseWebSession
|
||||
authAsAnonymousUser();
|
||||
} else if (getUserId() != null) {
|
||||
userContext.refreshPermissions();
|
||||
refreshAccessibleConnectionIds();
|
||||
if (globalProject != null) {
|
||||
globalProject.refreshAccessibleConnectionIds();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
@@ -473,32 +374,6 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void refreshAccessibleConnectionIds() {
|
||||
this.accessibleConnectionIds = readAccessibleConnectionIds();
|
||||
}
|
||||
|
||||
public synchronized void addAccessibleConnectionToCache(@NotNull String dsId) {
|
||||
this.accessibleConnectionIds.add(dsId);
|
||||
var registry = getProjectById(WebAppUtils.getGlobalProjectId()).getDataSourceRegistry();
|
||||
var dataSource = registry.getDataSource(dsId);
|
||||
if (dataSource != null) {
|
||||
connections.put(getConnectionId(dataSource), new WebConnectionInfo(this, dataSource));
|
||||
// reflect changes is navigator model
|
||||
registry.notifyDataSourceListeners(new DBPEvent(DBPEvent.Action.OBJECT_ADD, dataSource, true));
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void removeAccessibleConnectionFromCache(@NotNull String dsId) {
|
||||
var registry = getProjectById(WebAppUtils.getGlobalProjectId()).getDataSourceRegistry();
|
||||
var dataSource = registry.getDataSource(dsId);
|
||||
if (dataSource != null) {
|
||||
this.accessibleConnectionIds.remove(dsId);
|
||||
connections.remove(getConnectionId(dataSource));
|
||||
// reflect changes is navigator model
|
||||
registry.notifyDataSourceListeners(new DBPEvent(DBPEvent.Action.OBJECT_REMOVE, dataSource));
|
||||
dataSource.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void authAsAnonymousUser() throws DBException {
|
||||
if (!application.getAppConfiguration().isAnonymousAccessEnabled()) {
|
||||
@@ -563,69 +438,6 @@ public class WebSession extends BaseWebSession
|
||||
this.cacheExpired = false;
|
||||
}
|
||||
|
||||
@Association
|
||||
public List<WebConnectionInfo> getConnections() {
|
||||
synchronized (connections) {
|
||||
return new ArrayList<>(connections.values());
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public WebConnectionInfo getWebConnectionInfo(@Nullable String projectId, String connectionID) throws DBWebException {
|
||||
WebConnectionInfo connectionInfo = null;
|
||||
synchronized (connections) {
|
||||
if (projectId != null) {
|
||||
connectionInfo = connections.get(getConnectionId(projectId, connectionID));
|
||||
} else {
|
||||
addWarningMessage("Project id is not defined in request. Try to find it from connection cache");
|
||||
for (Map.Entry<String, WebConnectionInfo> entry : connections.entrySet()) {
|
||||
String k = entry.getKey();
|
||||
WebConnectionInfo v = entry.getValue();
|
||||
if (k.contains(connectionID)) {
|
||||
connectionInfo = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (connectionInfo == null) {
|
||||
WebProjectImpl project = getProjectById(projectId);
|
||||
if (project == null) {
|
||||
throw new DBWebException("Project '" + projectId + "' not found in web workspace");
|
||||
}
|
||||
DBPDataSourceContainer dataSource = project.getDataSourceRegistry().getDataSource(connectionID);
|
||||
if (dataSource != null) {
|
||||
connectionInfo = new WebConnectionInfo(this, dataSource);
|
||||
synchronized (connections) {
|
||||
connections.put(getConnectionId(dataSource), connectionInfo);
|
||||
}
|
||||
} else {
|
||||
throw new DBWebException("Connection '" + connectionID + "' not found");
|
||||
}
|
||||
}
|
||||
return connectionInfo;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public WebConnectionInfo findWebConnectionInfo(String projectId, String connectionId) {
|
||||
synchronized (connections) {
|
||||
return connections.get(getConnectionId(projectId, connectionId));
|
||||
}
|
||||
}
|
||||
|
||||
public void addConnection(WebConnectionInfo connectionInfo) {
|
||||
synchronized (connections) {
|
||||
connections.put(getConnectionId(connectionInfo.getDataSourceContainer()), connectionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeConnection(WebConnectionInfo connectionInfo) {
|
||||
connectionInfo.clearCache();
|
||||
synchronized (connections) {
|
||||
connections.remove(getConnectionId(connectionInfo.getDataSourceContainer()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
@@ -809,7 +621,7 @@ public class WebSession extends BaseWebSession
|
||||
synchronized (attributes) {
|
||||
Object value = attributes.get(name);
|
||||
if (value instanceof PersistentAttribute persistentAttribute) {
|
||||
value = persistentAttribute.getValue();
|
||||
value = persistentAttribute.value();
|
||||
}
|
||||
return (T) value;
|
||||
}
|
||||
@@ -825,7 +637,7 @@ public class WebSession extends BaseWebSession
|
||||
synchronized (attributes) {
|
||||
Object value = attributes.get(name);
|
||||
if (value instanceof PersistentAttribute persistentAttribute) {
|
||||
value = persistentAttribute.getValue();
|
||||
value = persistentAttribute.value();
|
||||
}
|
||||
if (value == null) {
|
||||
value = creator.apply(null);
|
||||
@@ -968,9 +780,12 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
configuration.setRuntimeAttribute(RUNTIME_PARAM_AUTH_INFOS, getAllAuthInfo());
|
||||
|
||||
WebConnectionInfo webConnectionInfo = findWebConnectionInfo(dataSourceContainer.getProject().getId(), dataSourceContainer.getId());
|
||||
if (webConnectionInfo != null) {
|
||||
WebDataSourceUtils.saveCredentialsInDataSource(webConnectionInfo, dataSourceContainer, configuration);
|
||||
WebSessionProjectImpl project = getProjectById(dataSourceContainer.getProject().getId());
|
||||
if (project != null) {
|
||||
WebConnectionInfo webConnectionInfo = project.findWebConnectionInfo(dataSourceContainer.getId());
|
||||
if (webConnectionInfo != null) {
|
||||
WebDataSourceUtils.saveCredentialsInDataSource(webConnectionInfo, dataSourceContainer, configuration);
|
||||
}
|
||||
}
|
||||
|
||||
// uncommented because we had the problem with non-native auth models
|
||||
@@ -979,7 +794,7 @@ public class WebSession extends BaseWebSession
|
||||
|
||||
InstanceCreator<DBAAuthCredentials> credTypeAdapter = type -> credentials;
|
||||
Gson credGson = new GsonBuilder()
|
||||
.setLenient()
|
||||
.setStrictness(Strictness.LENIENT)
|
||||
.registerTypeAdapter(credentials.getClass(), credTypeAdapter)
|
||||
.create();
|
||||
|
||||
@@ -1061,12 +876,17 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public WebProjectImpl getProjectById(@Nullable String projectId) {
|
||||
public WebSessionProjectImpl getProjectById(@Nullable String projectId) {
|
||||
return getWorkspace().getProjectById(projectId);
|
||||
}
|
||||
|
||||
public WebProjectImpl getAccessibleProjectById(@Nullable String projectId) throws DBWebException {
|
||||
WebProjectImpl project = null;
|
||||
/**
|
||||
* Returns project info from session cache.
|
||||
*
|
||||
* @throws DBWebException if project with provided id is not found.
|
||||
*/
|
||||
public WebSessionProjectImpl getAccessibleProjectById(@Nullable String projectId) throws DBWebException {
|
||||
WebSessionProjectImpl project = null;
|
||||
if (projectId != null) {
|
||||
project = getWorkspace().getProjectById(projectId);
|
||||
}
|
||||
@@ -1076,18 +896,24 @@ public class WebSession extends BaseWebSession
|
||||
return project;
|
||||
}
|
||||
|
||||
public List<WebProjectImpl> getAccessibleProjects() {
|
||||
public List<WebSessionProjectImpl> getAccessibleProjects() {
|
||||
return getWorkspace().getProjects();
|
||||
}
|
||||
|
||||
public void addSessionProject(@NotNull WebProjectImpl project) {
|
||||
/**
|
||||
* Adds project to session cache and navigator tree.
|
||||
*/
|
||||
public void addSessionProject(@NotNull WebSessionProjectImpl project) {
|
||||
getWorkspace().addProject(project);
|
||||
if (navigatorModel != null) {
|
||||
navigatorModel.getRoot().addProject(project, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteSessionProject(@Nullable WebProjectImpl project) {
|
||||
/**
|
||||
* Removes project from session cache and navigator tree.
|
||||
*/
|
||||
public void deleteSessionProject(@Nullable WebSessionProjectImpl project) {
|
||||
if (project != null) {
|
||||
project.dispose();
|
||||
}
|
||||
@@ -1112,10 +938,6 @@ public class WebSession extends BaseWebSession
|
||||
return;
|
||||
}
|
||||
deleteSessionProject(project);
|
||||
var projectConnections = project.getDataSourceRegistry().getDataSources();
|
||||
for (DBPDataSourceContainer c : projectConnections) {
|
||||
removeConnection(new WebConnectionInfo(this, c));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -1132,6 +954,11 @@ public class WebSession extends BaseWebSession
|
||||
return getUserContext().getPreferenceStore();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public WebSessionGlobalProjectImpl getGlobalProject() {
|
||||
return globalProject;
|
||||
}
|
||||
|
||||
private class SessionProgressMonitor extends BaseProgressMonitor {
|
||||
@Override
|
||||
public void beginTask(String name, int totalWork) {
|
||||
@@ -1166,15 +993,6 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
}
|
||||
|
||||
private static class PersistentAttribute {
|
||||
private final Object value;
|
||||
|
||||
public PersistentAttribute(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
private record PersistentAttribute(Object value) {
|
||||
}
|
||||
}
|
||||
|
||||
+21
-15
@@ -16,11 +16,12 @@
|
||||
*/
|
||||
package io.cloudbeaver.model.session;
|
||||
|
||||
import io.cloudbeaver.WebProjectImpl;
|
||||
import io.cloudbeaver.WebSessionProjectImpl;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.model.DBPAdaptable;
|
||||
import org.jkiss.dbeaver.model.DBPImage;
|
||||
import org.jkiss.dbeaver.model.app.DBPPlatform;
|
||||
import org.jkiss.dbeaver.model.app.DBPProject;
|
||||
import org.jkiss.dbeaver.model.app.DBPWorkspace;
|
||||
import org.jkiss.dbeaver.model.impl.auth.SessionContextImpl;
|
||||
import org.jkiss.dbeaver.model.rm.RMUtils;
|
||||
@@ -38,8 +39,8 @@ public class WebSessionWorkspace implements DBPWorkspace {
|
||||
|
||||
private final BaseWebSession session;
|
||||
private final SessionContextImpl workspaceAuthContext;
|
||||
private final List<WebProjectImpl> accessibleProjects = new ArrayList<>();
|
||||
private WebProjectImpl activeProject;
|
||||
private final List<WebSessionProjectImpl> accessibleProjects = new ArrayList<>();
|
||||
private WebSessionProjectImpl activeProject;
|
||||
|
||||
public WebSessionWorkspace(BaseWebSession session) {
|
||||
this.session = session;
|
||||
@@ -81,20 +82,20 @@ public class WebSessionWorkspace implements DBPWorkspace {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<WebProjectImpl> getProjects() {
|
||||
public List<WebSessionProjectImpl> getProjects() {
|
||||
return accessibleProjects;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public DBPProject getActiveProject() {
|
||||
public WebSessionProjectImpl getActiveProject() {
|
||||
return activeProject;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public WebProjectImpl getProject(@NotNull String projectName) {
|
||||
for (WebProjectImpl project : accessibleProjects) {
|
||||
public WebSessionProjectImpl getProject(@NotNull String projectName) {
|
||||
for (WebSessionProjectImpl project : accessibleProjects) {
|
||||
if (project.getName().equals(projectName)) {
|
||||
return project;
|
||||
}
|
||||
@@ -104,11 +105,11 @@ public class WebSessionWorkspace implements DBPWorkspace {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public WebProjectImpl getProjectById(@NotNull String projectId) {
|
||||
public WebSessionProjectImpl getProjectById(@NotNull String projectId) {
|
||||
if (projectId == null) {
|
||||
return activeProject;
|
||||
}
|
||||
for (WebProjectImpl project : accessibleProjects) {
|
||||
for (WebSessionProjectImpl project : accessibleProjects) {
|
||||
if (project.getId().equals(projectId)) {
|
||||
return project;
|
||||
}
|
||||
@@ -132,21 +133,26 @@ public class WebSessionWorkspace implements DBPWorkspace {
|
||||
clearProjects();
|
||||
}
|
||||
|
||||
public void setActiveProject(DBPProject activeProject) {
|
||||
this.activeProject = (WebProjectImpl) activeProject;
|
||||
@Override
|
||||
public DBPImage getResourceIcon(DBPAdaptable resourceAdapter) {
|
||||
return null;
|
||||
}
|
||||
|
||||
void addProject(WebProjectImpl project) {
|
||||
public void setActiveProject(WebSessionProjectImpl activeProject) {
|
||||
this.activeProject = activeProject;
|
||||
}
|
||||
|
||||
void addProject(WebSessionProjectImpl project) {
|
||||
accessibleProjects.add(project);
|
||||
}
|
||||
|
||||
void removeProject(WebProjectImpl project) {
|
||||
void removeProject(WebSessionProjectImpl project) {
|
||||
accessibleProjects.remove(project);
|
||||
}
|
||||
|
||||
void clearProjects() {
|
||||
if (!this.accessibleProjects.isEmpty()) {
|
||||
for (WebProjectImpl project : accessibleProjects) {
|
||||
for (WebSessionProjectImpl project : accessibleProjects) {
|
||||
project.dispose();
|
||||
}
|
||||
this.activeProject = null;
|
||||
|
||||
+1
@@ -46,6 +46,7 @@ import java.util.stream.Collectors;
|
||||
* Web user context.
|
||||
* Contains user state and services based on available permissions
|
||||
*/
|
||||
//TODO: split to authenticated and non authenticated context
|
||||
public class WebUserContext implements SMCredentialsProvider {
|
||||
private static final Log log = Log.getLog(WebUserContext.class);
|
||||
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ public class WebAuthProviderConfiguration {
|
||||
}
|
||||
|
||||
private String buildRedirectUrl(String baseUrl) {
|
||||
return baseUrl + "?" + CBAuthConstants.CB_REDIRECT_URL_REQUEST_PARAM + "=" + WebAppUtils.getWebApplication().getServerURL();
|
||||
return baseUrl + "?" + CBAuthConstants.CB_REDIRECT_URL_REQUEST_PARAM + "=" + WebAppUtils.getFullServerUrl();
|
||||
}
|
||||
|
||||
@Property
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 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 io.cloudbeaver.DBWConstants;
|
||||
import org.eclipse.core.runtime.Plugin;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.DBConstants;
|
||||
import org.jkiss.dbeaver.model.app.DBACertificateStorage;
|
||||
import org.jkiss.dbeaver.model.app.DBPWorkspace;
|
||||
import org.jkiss.dbeaver.model.impl.app.DefaultCertificateStorage;
|
||||
import org.jkiss.dbeaver.model.qm.QMRegistry;
|
||||
import org.jkiss.dbeaver.model.qm.QMUtils;
|
||||
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
|
||||
import org.jkiss.dbeaver.registry.BasePlatformImpl;
|
||||
import org.jkiss.dbeaver.registry.DataSourceProviderRegistry;
|
||||
import org.jkiss.dbeaver.runtime.SecurityProviderUtils;
|
||||
import org.jkiss.dbeaver.runtime.qm.QMLogFileWriter;
|
||||
import org.jkiss.dbeaver.runtime.qm.QMRegistryImpl;
|
||||
import org.jkiss.dbeaver.utils.ContentUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public abstract class BaseGQLPlatform extends BasePlatformImpl {
|
||||
private static final Log log = Log.getLog(BaseGQLPlatform.class);
|
||||
public static final String WORK_DATA_FOLDER_NAME = ".work-data";
|
||||
|
||||
private Path tempFolder;
|
||||
|
||||
private QMRegistryImpl queryManager;
|
||||
private QMLogFileWriter qmLogWriter;
|
||||
private DBACertificateStorage certificateStorage;
|
||||
private WebGlobalWorkspace workspace;
|
||||
|
||||
@Override
|
||||
protected synchronized void initialize() {
|
||||
// Register BC security provider
|
||||
SecurityProviderUtils.registerSecurityProvider();
|
||||
|
||||
// Register properties adapter
|
||||
this.workspace = new WebGlobalWorkspace(this);
|
||||
this.workspace.initializeProjects();
|
||||
QMUtils.initApplication(this);
|
||||
|
||||
this.queryManager = new QMRegistryImpl();
|
||||
|
||||
this.qmLogWriter = new QMLogFileWriter();
|
||||
this.queryManager.registerMetaListener(qmLogWriter);
|
||||
|
||||
this.certificateStorage = new DefaultCertificateStorage(
|
||||
WebPlatformActivator.getInstance()
|
||||
.getStateLocation()
|
||||
.toFile()
|
||||
.toPath()
|
||||
.resolve(DBConstants.CERTIFICATE_STORAGE_FOLDER));
|
||||
super.initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Plugin getProductPlugin() {
|
||||
return WebPlatformActivator.getInstance();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DBACertificateStorage getCertificateStorage() {
|
||||
return certificateStorage;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DBPWorkspace getWorkspace() {
|
||||
return workspace;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Path getTempFolder(@NotNull DBRProgressMonitor monitor, @NotNull String name) {
|
||||
if (tempFolder == null) {
|
||||
// Make temp folder
|
||||
monitor.subTask("Create temp folder");
|
||||
tempFolder = workspace.getAbsolutePath().resolve(DBWConstants.WORK_DATA_FOLDER_NAME);
|
||||
}
|
||||
if (!Files.exists(tempFolder)) {
|
||||
try {
|
||||
Files.createDirectories(tempFolder);
|
||||
} catch (IOException e) {
|
||||
log.error("Can't create temp directory " + tempFolder, e);
|
||||
}
|
||||
}
|
||||
Path folder = tempFolder.resolve(name);
|
||||
if (!Files.exists(folder)) {
|
||||
try {
|
||||
Files.createDirectories(folder);
|
||||
} catch (IOException e) {
|
||||
log.error("Error creating temp folder '" + folder.toAbsolutePath() + "'", e);
|
||||
}
|
||||
}
|
||||
return folder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void dispose() {
|
||||
super.dispose();
|
||||
if (this.qmLogWriter != null) {
|
||||
this.queryManager.unregisterMetaListener(qmLogWriter);
|
||||
this.qmLogWriter.dispose();
|
||||
this.qmLogWriter = null;
|
||||
}
|
||||
if (this.queryManager != null) {
|
||||
this.queryManager.dispose();
|
||||
//queryManager = null;
|
||||
}
|
||||
DataSourceProviderRegistry.dispose();
|
||||
|
||||
// Remove temp folder
|
||||
if (tempFolder != null) {
|
||||
|
||||
if (!ContentUtils.deleteFileRecursive(tempFolder.toFile())) {
|
||||
log.warn("Can't delete temp folder '" + tempFolder.toAbsolutePath() + "'");
|
||||
}
|
||||
tempFolder = null;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public QMRegistry getQueryManager() {
|
||||
return queryManager;
|
||||
}
|
||||
|
||||
}
|
||||
+2
@@ -87,4 +87,6 @@ public class CBConstants {
|
||||
|
||||
public static final String QUOTA_PROP_FILE_LIMIT = "dataExportFileSizeLimit";
|
||||
public static final String ADMIN_AUTO_GRANT = "auto-grant";
|
||||
public static final String HOST_LOCALHOST = "localhost";
|
||||
public static final String HOST_127_0_0_1 = "127.0.0.1";
|
||||
}
|
||||
@@ -34,15 +34,15 @@ public class WebGlobalProject extends BaseProjectImpl {
|
||||
|
||||
private static final Log log = Log.getLog(WebGlobalProject.class);
|
||||
|
||||
private final String projectId;
|
||||
private final String projectName;
|
||||
|
||||
public WebGlobalProject(
|
||||
@NotNull DBPWorkspace workspace,
|
||||
@Nullable SMSessionContext sessionContext,
|
||||
@NotNull String projectId
|
||||
@NotNull String projectName
|
||||
) {
|
||||
super(workspace, sessionContext);
|
||||
this.projectId = projectId;
|
||||
this.projectName = projectName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,13 +53,13 @@ public class WebGlobalProject extends BaseProjectImpl {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return projectId;
|
||||
return projectName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Path getAbsolutePath() {
|
||||
return getWorkspace().getAbsolutePath().resolve(projectId);
|
||||
return getWorkspace().getAbsolutePath().resolve(projectName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+8
-2
@@ -17,6 +17,7 @@
|
||||
package io.cloudbeaver.server;
|
||||
|
||||
import io.cloudbeaver.WebProjectImpl;
|
||||
import io.cloudbeaver.model.app.WebApplication;
|
||||
import io.cloudbeaver.utils.WebAppUtils;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.jkiss.code.NotNull;
|
||||
@@ -26,6 +27,7 @@ import org.jkiss.dbeaver.model.app.DBPPlatform;
|
||||
import org.jkiss.dbeaver.model.app.DBPProject;
|
||||
import org.jkiss.dbeaver.model.impl.app.BaseProjectImpl;
|
||||
import org.jkiss.dbeaver.model.impl.app.BaseWorkspaceImpl;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
@@ -48,7 +50,10 @@ public class WebGlobalWorkspace extends BaseWorkspaceImpl {
|
||||
private WebGlobalProject globalProject;
|
||||
|
||||
public WebGlobalWorkspace(DBPPlatform platform) {
|
||||
super(platform, Path.of(getWorkspaceURI()));
|
||||
super(platform,
|
||||
platform.getApplication().isMultiuser()
|
||||
? Path.of(getWorkspaceURI())
|
||||
: ((WebApplication) platform.getApplication()).getWorkspaceDirectory());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -78,7 +83,8 @@ public class WebGlobalWorkspace extends BaseWorkspaceImpl {
|
||||
globalProject = new WebGlobalProject(
|
||||
this,
|
||||
getAuthContext(),
|
||||
WebAppUtils.getGlobalProjectId());
|
||||
CommonUtils.notEmpty(WebAppUtils.getWebApplication().getDefaultProjectName())
|
||||
);
|
||||
activeProject = globalProject;
|
||||
}
|
||||
|
||||
|
||||
-9
@@ -16,8 +16,6 @@
|
||||
*/
|
||||
package io.cloudbeaver.server;
|
||||
|
||||
import org.eclipse.core.resources.IWorkspace;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.Plugin;
|
||||
import org.jkiss.dbeaver.ModelPreferences;
|
||||
import org.jkiss.dbeaver.model.impl.preferences.BundlePreferenceStore;
|
||||
@@ -76,13 +74,6 @@ public class WebPlatformActivator extends Plugin {
|
||||
return preferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the workspace instance.
|
||||
*/
|
||||
public static IWorkspace getWorkspace() {
|
||||
return ResourcesPlugin.getWorkspace();
|
||||
}
|
||||
|
||||
protected void shutdownPlatform() {
|
||||
|
||||
}
|
||||
|
||||
+3
@@ -23,6 +23,9 @@ import org.jkiss.dbeaver.DBException;
|
||||
* Servlet service
|
||||
*/
|
||||
public interface DBWServiceBindingServlet<APPLICATION extends WebApplication> extends DBWServiceBinding {
|
||||
default boolean isApplicable(WebApplication application) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void addServlets(APPLICATION application, DBWServletContext servletContext) throws DBException;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class WebAppUtils {
|
||||
private static final Log log = Log.getLog(WebAppUtils.class);
|
||||
@@ -269,4 +271,13 @@ public class WebAppUtils {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getFullServerUrl() {
|
||||
WebApplication application = WebAppUtils.getWebApplication();
|
||||
return Stream.of(application.getServerURL(), application.getRootURI())
|
||||
.map(WebAppUtils::removeSideSlashes)
|
||||
.filter(CommonUtils::isNotEmpty)
|
||||
.collect(Collectors.joining("/"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+34
-6
@@ -18,10 +18,9 @@ package io.cloudbeaver.utils;
|
||||
|
||||
import io.cloudbeaver.DBWConstants;
|
||||
import io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.WebProjectImpl;
|
||||
import io.cloudbeaver.WebSessionProjectImpl;
|
||||
import io.cloudbeaver.model.WebConnectionInfo;
|
||||
import io.cloudbeaver.model.WebNetworkHandlerConfigInput;
|
||||
import io.cloudbeaver.model.app.WebApplication;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
@@ -38,6 +37,7 @@ import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class WebDataSourceUtils {
|
||||
|
||||
@@ -114,18 +114,22 @@ public class WebDataSourceUtils {
|
||||
|
||||
@Nullable
|
||||
public static DBPDataSourceContainer getLocalOrGlobalDataSource(
|
||||
WebApplication application, WebSession webSession, @Nullable String projectId, String connectionId
|
||||
WebSession webSession, @Nullable String projectId, String connectionId
|
||||
) throws DBWebException {
|
||||
DBPDataSourceContainer dataSource = null;
|
||||
if (!CommonUtils.isEmpty(connectionId)) {
|
||||
WebProjectImpl project = webSession.getProjectById(projectId);
|
||||
WebSessionProjectImpl project = webSession.getProjectById(projectId);
|
||||
if (project == null) {
|
||||
throw new DBWebException("Project '" + projectId + "' not found");
|
||||
}
|
||||
dataSource = project.getDataSourceRegistry().getDataSource(connectionId);
|
||||
if (dataSource == null && (webSession.hasPermission(DBWConstants.PERMISSION_ADMIN) || application.isConfigurationMode())) {
|
||||
if (dataSource == null &&
|
||||
(webSession.hasPermission(DBWConstants.PERMISSION_ADMIN) || webSession.getApplication().isConfigurationMode())) {
|
||||
// If called for new connection in admin mode then this connection may absent in session registry yet
|
||||
dataSource = getGlobalDataSourceRegistry().getDataSource(connectionId);
|
||||
project = webSession.getGlobalProject();
|
||||
if (project != null) {
|
||||
dataSource = project.getDataSourceRegistry().getDataSource(connectionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataSource;
|
||||
@@ -162,4 +166,28 @@ public class WebDataSourceUtils {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The method that seeks for web connection in session cache by connection id.
|
||||
* Mostly used when project id is not defined.
|
||||
*/
|
||||
@NotNull
|
||||
public static WebConnectionInfo getWebConnectionInfo(
|
||||
@NotNull WebSession webSession,
|
||||
@Nullable String projectId,
|
||||
@NotNull String connectionId
|
||||
) throws DBWebException {
|
||||
if (projectId == null) {
|
||||
webSession.addWarningMessage("Project id is not defined in request. Try to find it from connection cache");
|
||||
// try to find connection in all accessible projects
|
||||
Optional<WebConnectionInfo> optional = webSession.getAccessibleProjects().stream()
|
||||
.flatMap(p -> p.getConnections().stream()) // get connection cache from web projects
|
||||
.filter(e -> e.getId().contains(connectionId))
|
||||
.findFirst();
|
||||
if (optional.isPresent()) {
|
||||
return optional.get();
|
||||
}
|
||||
}
|
||||
return webSession.getAccessibleProjectById(projectId).getWebConnectionInfo(connectionId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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: 24.2.1.qualifier
|
||||
Bundle-Release-Date: 20240923
|
||||
Bundle-Version: 24.2.2.qualifier
|
||||
Bundle-Release-Date: 20241007
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-17
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-ClassPath: .
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.product.ce</artifactId>
|
||||
<version>24.2.1-SNAPSHOT</version>
|
||||
<version>24.2.2-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -2,8 +2,8 @@ Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Base JDBC drivers
|
||||
Bundle-SymbolicName: io.cloudbeaver.resources.drivers.base;singleton:=true
|
||||
Bundle-Version: 1.0.106.qualifier
|
||||
Bundle-Release-Date: 20240923
|
||||
Bundle-Version: 1.0.107.qualifier
|
||||
Bundle-Release-Date: 20241007
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Automatic-Module-Name: io.cloudbeaver.resources.drivers.base
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.resources.drivers.base</artifactId>
|
||||
<version>1.0.106-SNAPSHOT</version>
|
||||
<version>1.0.107-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Server
|
||||
Bundle-SymbolicName: io.cloudbeaver.server;singleton:=true
|
||||
Bundle-Version: 24.2.1.qualifier
|
||||
Bundle-Release-Date: 20240923
|
||||
Bundle-Version: 24.2.2.qualifier
|
||||
Bundle-Release-Date: 20241007
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-17
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-Activator: io.cloudbeaver.server.CBPlatformActivator
|
||||
@@ -28,8 +28,11 @@ Export-Package: io.cloudbeaver,
|
||||
io.cloudbeaver.server.events,
|
||||
io.cloudbeaver.server,
|
||||
io.cloudbeaver.server.actions,
|
||||
io.cloudbeaver.server.jetty,
|
||||
io.cloudbeaver.server.graphql,
|
||||
io.cloudbeaver.server.jobs,
|
||||
io.cloudbeaver.server.servlets,
|
||||
io.cloudbeaver.server.websockets,
|
||||
io.cloudbeaver.service,
|
||||
io.cloudbeaver.service.navigator,
|
||||
io.cloudbeaver.service.session,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.server</artifactId>
|
||||
<version>24.2.1-SNAPSHOT</version>
|
||||
<version>24.2.2-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -22,15 +22,14 @@ import com.google.gson.InstanceCreator;
|
||||
import io.cloudbeaver.model.WebConnectionConfig;
|
||||
import io.cloudbeaver.model.WebNetworkHandlerConfigInput;
|
||||
import io.cloudbeaver.model.WebPropertyInfo;
|
||||
import io.cloudbeaver.model.config.CBAppConfig;
|
||||
import io.cloudbeaver.model.session.WebActionParameters;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
|
||||
import io.cloudbeaver.registry.WebAuthProviderRegistry;
|
||||
import io.cloudbeaver.server.CBAppConfig;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import io.cloudbeaver.service.navigator.WebPropertyFilter;
|
||||
import io.cloudbeaver.utils.WebAppUtils;
|
||||
import io.cloudbeaver.utils.WebCommonUtils;
|
||||
import io.cloudbeaver.utils.WebDataSourceUtils;
|
||||
import org.jkiss.code.NotNull;
|
||||
@@ -98,10 +97,6 @@ public class WebServiceUtils extends WebCommonUtils {
|
||||
return WebDataSourceUtils.getGlobalDataSourceRegistry();
|
||||
}
|
||||
|
||||
public static DBPDataSourceRegistry getGlobalRegistry(WebSession session) {
|
||||
return session.getProjectById(WebAppUtils.getGlobalProjectId()).getDataSourceRegistry();
|
||||
}
|
||||
|
||||
public static InputStream openStaticResource(String path) {
|
||||
return WebServiceUtils.class.getClassLoader().getResourceAsStream(path);
|
||||
}
|
||||
|
||||
+1
-1
@@ -18,9 +18,9 @@ package io.cloudbeaver.model;
|
||||
|
||||
import io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.WebServiceUtils;
|
||||
import io.cloudbeaver.model.config.CBAppConfig;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.model.utils.ConfigurationUtils;
|
||||
import io.cloudbeaver.server.CBAppConfig;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
|
||||
+6
-1
@@ -17,14 +17,19 @@
|
||||
|
||||
package io.cloudbeaver.model;
|
||||
|
||||
import io.cloudbeaver.model.config.CBAppConfig;
|
||||
import io.cloudbeaver.model.utils.ConfigurationUtils;
|
||||
import io.cloudbeaver.server.CBAppConfig;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.utils.WebAppUtils;
|
||||
import org.jkiss.dbeaver.model.connection.DBPDriver;
|
||||
|
||||
//TODO move to a separate CBApplication plugin
|
||||
public class WebDatasourceAccessCheckHandler extends BaseDatasourceAccessCheckHandler {
|
||||
@Override
|
||||
protected boolean isDriverDisabled(DBPDriver driver) {
|
||||
if (!WebAppUtils.getWebApplication().isMultiuser()) {
|
||||
return false;
|
||||
}
|
||||
CBAppConfig config = CBApplication.getInstance().getAppConfiguration();
|
||||
return !ConfigurationUtils.isDriverEnabled(
|
||||
driver,
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
*/
|
||||
package io.cloudbeaver.model;
|
||||
|
||||
import io.cloudbeaver.model.config.PasswordPolicyConfiguration;
|
||||
import io.cloudbeaver.registry.WebServiceDescriptor;
|
||||
import io.cloudbeaver.registry.WebServiceRegistry;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import io.cloudbeaver.service.security.PasswordPolicyConfiguration;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings;
|
||||
|
||||
+5
-1
@@ -19,6 +19,7 @@ package io.cloudbeaver.model.user;
|
||||
import io.cloudbeaver.WebServiceUtils;
|
||||
import io.cloudbeaver.auth.SMAuthProviderFederated;
|
||||
import io.cloudbeaver.auth.provisioning.SMProvisioner;
|
||||
import io.cloudbeaver.model.config.CBAppConfig;
|
||||
import io.cloudbeaver.registry.WebAuthProviderConfiguration;
|
||||
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
@@ -64,7 +65,10 @@ public class WebAuthProviderInfo {
|
||||
}
|
||||
|
||||
public boolean isDefaultProvider() {
|
||||
return descriptor.getId().equals(CBPlatform.getInstance().getApplication().getAppConfiguration().getDefaultAuthProvider());
|
||||
if (CBPlatform.getInstance().getApplication().getAppConfiguration() instanceof CBAppConfig cbAppConfig) {
|
||||
return descriptor.getId().equals(cbAppConfig.getDefaultAuthProvider());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isConfigurable() {
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 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 io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.model.session.BaseWebSession;
|
||||
import io.cloudbeaver.model.session.WebHeadlessSession;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Session;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface AppWebSessionManager {
|
||||
BaseWebSession closeSession(@NotNull HttpServletRequest request);
|
||||
|
||||
@NotNull
|
||||
WebSession getWebSession(
|
||||
@NotNull HttpServletRequest request,
|
||||
@NotNull HttpServletResponse response
|
||||
) throws DBWebException;
|
||||
|
||||
@NotNull
|
||||
WebSession getWebSession(
|
||||
@NotNull HttpServletRequest request,
|
||||
@NotNull HttpServletResponse response,
|
||||
boolean errorOnNoFound
|
||||
) throws DBWebException;
|
||||
|
||||
@Nullable
|
||||
BaseWebSession getSession(@NotNull String sessionId);
|
||||
|
||||
@Nullable
|
||||
WebSession findWebSession(HttpServletRequest request);
|
||||
|
||||
WebSession findWebSession(HttpServletRequest request, boolean errorOnNoFound) throws DBWebException;
|
||||
|
||||
Collection<BaseWebSession> getAllActiveSessions();
|
||||
|
||||
WebSession getOrRestoreSession(Request httpRequest);
|
||||
|
||||
WebHeadlessSession getHeadlessSession(Request request, Session session, boolean create) throws DBException;
|
||||
|
||||
boolean touchSession(HttpServletRequest request, HttpServletResponse response) throws DBWebException;
|
||||
}
|
||||
@@ -21,12 +21,14 @@ import io.cloudbeaver.auth.NoAuthCredentialsProvider;
|
||||
import io.cloudbeaver.model.app.BaseWebApplication;
|
||||
import io.cloudbeaver.model.app.WebAuthApplication;
|
||||
import io.cloudbeaver.model.app.WebAuthConfiguration;
|
||||
import io.cloudbeaver.model.config.CBAppConfig;
|
||||
import io.cloudbeaver.model.config.CBServerConfig;
|
||||
import io.cloudbeaver.model.config.SMControllerConfiguration;
|
||||
import io.cloudbeaver.registry.WebDriverRegistry;
|
||||
import io.cloudbeaver.registry.WebServiceRegistry;
|
||||
import io.cloudbeaver.server.jetty.CBJettyServer;
|
||||
import io.cloudbeaver.service.DBWServiceInitializer;
|
||||
import io.cloudbeaver.service.DBWServiceServerConfigurator;
|
||||
import io.cloudbeaver.service.security.SMControllerConfiguration;
|
||||
import io.cloudbeaver.service.session.WebSessionManager;
|
||||
import io.cloudbeaver.utils.WebDataSourceUtils;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
@@ -65,16 +67,14 @@ import java.net.NetworkInterface;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.file.Path;
|
||||
import java.security.Permission;
|
||||
import java.security.Policy;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* This class controls all aspects of the application's execution
|
||||
*/
|
||||
public abstract class CBApplication<T extends CBServerConfig> extends BaseWebApplication implements WebAuthApplication {
|
||||
public abstract class CBApplication<T extends CBServerConfig> extends
|
||||
BaseWebApplication implements WebAuthApplication, GQLApplicationAdapter {
|
||||
|
||||
private static final Log log = Log.getLog(CBApplication.class);
|
||||
|
||||
@@ -83,8 +83,6 @@ public abstract class CBApplication<T extends CBServerConfig> extends BaseWebApp
|
||||
* In configuration mode sessions expire after a week
|
||||
*/
|
||||
private static final long CONFIGURATION_MODE_SESSION_IDLE_TIME = 60 * 60 * 1000 * 24 * 7;
|
||||
public static final String HOST_LOCALHOST = "localhost";
|
||||
public static final String HOST_127_0_0_1 = "127.0.0.1";
|
||||
|
||||
|
||||
static {
|
||||
@@ -221,9 +219,9 @@ public abstract class CBApplication<T extends CBServerConfig> extends BaseWebApp
|
||||
if (CommonUtils.isEmpty(localHostAddress)) {
|
||||
localHostAddress = System.getProperty(CBConstants.VAR_CB_LOCAL_HOST_ADDR);
|
||||
}
|
||||
if (CommonUtils.isEmpty(localHostAddress) || HOST_127_0_0_1.equals(localHostAddress) || "::0".equals(
|
||||
if (CommonUtils.isEmpty(localHostAddress) || CBConstants.HOST_127_0_0_1.equals(localHostAddress) || "::0".equals(
|
||||
localHostAddress)) {
|
||||
localHostAddress = HOST_LOCALHOST;
|
||||
localHostAddress = CBConstants.HOST_LOCALHOST;
|
||||
}
|
||||
|
||||
final Runtime runtime = Runtime.getRuntime();
|
||||
@@ -231,7 +229,7 @@ public abstract class CBApplication<T extends CBServerConfig> extends BaseWebApp
|
||||
|
||||
Location instanceLoc = Platform.getInstanceLocation();
|
||||
try {
|
||||
if (!instanceLoc.isSet()) {
|
||||
if (!instanceLoc.isSet()) { // always false?
|
||||
URL wsLocationURL = new URL(
|
||||
"file", //$NON-NLS-1$
|
||||
null,
|
||||
@@ -314,16 +312,6 @@ public abstract class CBApplication<T extends CBServerConfig> extends BaseWebApp
|
||||
grantPermissionsToConnections();
|
||||
}
|
||||
|
||||
if (getServerConfiguration().isEnableSecurityManager()) {
|
||||
Policy.setPolicy(new Policy() {
|
||||
@Override
|
||||
public boolean implies(ProtectionDomain domain, Permission permission) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
System.setSecurityManager(new SecurityManager());
|
||||
}
|
||||
|
||||
eventController.scheduleCheckJob();
|
||||
|
||||
runWebServer();
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package io.cloudbeaver.server;
|
||||
|
||||
import io.cloudbeaver.auth.NoAuthCredentialsProvider;
|
||||
import io.cloudbeaver.model.config.CBServerConfig;
|
||||
import io.cloudbeaver.model.rm.local.LocalResourceController;
|
||||
import io.cloudbeaver.service.security.CBEmbeddedSecurityController;
|
||||
import io.cloudbeaver.service.security.EmbeddedSecurityControllerFactory;
|
||||
|
||||
@@ -17,43 +17,29 @@
|
||||
|
||||
package io.cloudbeaver.server;
|
||||
|
||||
import io.cloudbeaver.DBWConstants;
|
||||
import io.cloudbeaver.auth.NoAuthCredentialsProvider;
|
||||
import io.cloudbeaver.server.jobs.SessionStateJob;
|
||||
import io.cloudbeaver.server.jobs.WebDataSourceMonitorJob;
|
||||
import io.cloudbeaver.server.jobs.WebSessionMonitorJob;
|
||||
import io.cloudbeaver.service.session.WebSessionManager;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Plugin;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.DBConstants;
|
||||
import org.jkiss.dbeaver.model.DBFileController;
|
||||
import org.jkiss.dbeaver.model.app.DBACertificateStorage;
|
||||
import org.jkiss.dbeaver.model.app.DBPWorkspace;
|
||||
import org.jkiss.dbeaver.model.connection.DBPDataSourceProviderDescriptor;
|
||||
import org.jkiss.dbeaver.model.connection.DBPDriver;
|
||||
import org.jkiss.dbeaver.model.connection.DBPDriverLibrary;
|
||||
import org.jkiss.dbeaver.model.impl.app.DefaultCertificateStorage;
|
||||
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
|
||||
import org.jkiss.dbeaver.model.qm.QMRegistry;
|
||||
import org.jkiss.dbeaver.model.qm.QMUtils;
|
||||
import org.jkiss.dbeaver.model.runtime.AbstractJob;
|
||||
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
|
||||
import org.jkiss.dbeaver.registry.BasePlatformImpl;
|
||||
import org.jkiss.dbeaver.registry.DataSourceProviderRegistry;
|
||||
import org.jkiss.dbeaver.runtime.DBWorkbench;
|
||||
import org.jkiss.dbeaver.runtime.SecurityProviderUtils;
|
||||
import org.jkiss.dbeaver.runtime.qm.QMLogFileWriter;
|
||||
import org.jkiss.dbeaver.runtime.qm.QMRegistryImpl;
|
||||
import org.jkiss.dbeaver.utils.ContentUtils;
|
||||
import org.jkiss.utils.IOUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -61,7 +47,7 @@ import java.util.stream.Collectors;
|
||||
/**
|
||||
* CBPlatform
|
||||
*/
|
||||
public class CBPlatform extends BasePlatformImpl {
|
||||
public class CBPlatform extends BaseGQLPlatform {
|
||||
|
||||
// The plug-in ID
|
||||
public static final String PLUGIN_ID = "io.cloudbeaver.server"; //$NON-NLS-1$
|
||||
@@ -71,25 +57,19 @@ public class CBPlatform extends BasePlatformImpl {
|
||||
public static final String TEMP_FILE_IMPORT_FOLDER = "temp-import-files";
|
||||
|
||||
@Nullable
|
||||
private static CBApplication<?> application = null;
|
||||
private static GQLApplicationAdapter application = null;
|
||||
|
||||
private Path tempFolder;
|
||||
|
||||
private QMRegistryImpl queryManager;
|
||||
private QMLogFileWriter qmLogWriter;
|
||||
private DBACertificateStorage certificateStorage;
|
||||
private WebGlobalWorkspace workspace;
|
||||
private CBPreferenceStore preferenceStore;
|
||||
private final List<DBPDriver> applicableDrivers = new ArrayList<>();
|
||||
protected final List<DBPDriver> applicableDrivers = new ArrayList<>();
|
||||
|
||||
public static CBPlatform getInstance() {
|
||||
return (CBPlatform) DBWorkbench.getPlatform();
|
||||
}
|
||||
|
||||
CBPlatform() {
|
||||
protected CBPlatform() {
|
||||
}
|
||||
|
||||
public static void setApplication(CBApplication application) {
|
||||
public static void setApplication(@NotNull GQLApplicationAdapter application) {
|
||||
CBPlatform.application = application;
|
||||
}
|
||||
|
||||
@@ -98,32 +78,23 @@ public class CBPlatform extends BasePlatformImpl {
|
||||
long startTime = System.currentTimeMillis();
|
||||
log.info("Initialize web platform...: ");
|
||||
this.preferenceStore = new CBPreferenceStore(this, WebPlatformActivator.getInstance().getPreferences());
|
||||
// Register BC security provider
|
||||
SecurityProviderUtils.registerSecurityProvider();
|
||||
|
||||
// Register properties adapter
|
||||
this.workspace = new WebGlobalWorkspace(this);
|
||||
this.workspace.initializeProjects();
|
||||
|
||||
QMUtils.initApplication(this);
|
||||
this.queryManager = new QMRegistryImpl();
|
||||
|
||||
this.qmLogWriter = new QMLogFileWriter();
|
||||
this.queryManager.registerMetaListener(qmLogWriter);
|
||||
|
||||
this.certificateStorage = new DefaultCertificateStorage(
|
||||
WebPlatformActivator.getInstance().getStateLocation().toFile().toPath().resolve(DBConstants.CERTIFICATE_STORAGE_FOLDER));
|
||||
super.initialize();
|
||||
|
||||
refreshApplicableDrivers();
|
||||
|
||||
new WebSessionMonitorJob(this)
|
||||
.scheduleMonitor();
|
||||
scheduleServerJobs();
|
||||
log.info("Web platform initialized (" + (System.currentTimeMillis() - startTime) + "ms)");
|
||||
}
|
||||
|
||||
new SessionStateJob(this)
|
||||
.scheduleMonitor();
|
||||
protected void scheduleServerJobs() {
|
||||
if (getSessionManager() instanceof WebSessionManager webSessionManager) {
|
||||
new WebSessionMonitorJob(this, webSessionManager)
|
||||
.scheduleMonitor();
|
||||
|
||||
new WebDataSourceMonitorJob(this)
|
||||
new SessionStateJob(this, webSessionManager)
|
||||
.scheduleMonitor();
|
||||
}
|
||||
|
||||
new WebDataSourceMonitorJob(this, getSessionManager())
|
||||
.scheduleMonitor();
|
||||
|
||||
new AbstractJob("Delete temp folder") {
|
||||
@@ -138,7 +109,6 @@ public class CBPlatform extends BasePlatformImpl {
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
}.schedule();
|
||||
log.info("Web platform initialized (" + (System.currentTimeMillis() - startTime) + "ms)");
|
||||
}
|
||||
|
||||
public synchronized void dispose() {
|
||||
@@ -147,26 +117,6 @@ public class CBPlatform extends BasePlatformImpl {
|
||||
|
||||
super.dispose();
|
||||
|
||||
if (this.qmLogWriter != null) {
|
||||
this.queryManager.unregisterMetaListener(qmLogWriter);
|
||||
this.qmLogWriter.dispose();
|
||||
this.qmLogWriter = null;
|
||||
}
|
||||
if (this.queryManager != null) {
|
||||
this.queryManager.dispose();
|
||||
//queryManager = null;
|
||||
}
|
||||
DataSourceProviderRegistry.dispose();
|
||||
|
||||
// Remove temp folder
|
||||
if (tempFolder != null) {
|
||||
|
||||
if (!ContentUtils.deleteFileRecursive(tempFolder.toFile())) {
|
||||
log.warn("Can't delete temp folder '" + tempFolder.toAbsolutePath() + "'");
|
||||
}
|
||||
tempFolder = null;
|
||||
}
|
||||
|
||||
CBPlatform.application = null;
|
||||
System.gc();
|
||||
log.debug("Shutdown completed in " + (System.currentTimeMillis() - startTime) + "ms");
|
||||
@@ -174,13 +124,7 @@ public class CBPlatform extends BasePlatformImpl {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DBPWorkspace getWorkspace() {
|
||||
return workspace;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CBApplication<?> getApplication() {
|
||||
public GQLApplicationAdapter getApplication() {
|
||||
return application;
|
||||
}
|
||||
|
||||
@@ -188,10 +132,6 @@ public class CBPlatform extends BasePlatformImpl {
|
||||
return applicableDrivers;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public QMRegistry getQueryManager() {
|
||||
return queryManager;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -199,48 +139,12 @@ public class CBPlatform extends BasePlatformImpl {
|
||||
return preferenceStore;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DBACertificateStorage getCertificateStorage() {
|
||||
return certificateStorage;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Path getTempFolder(@NotNull DBRProgressMonitor monitor, @NotNull String name) {
|
||||
if (tempFolder == null) {
|
||||
// Make temp folder
|
||||
monitor.subTask("Create temp folder");
|
||||
tempFolder = workspace.getAbsolutePath().resolve(DBWConstants.WORK_DATA_FOLDER_NAME);
|
||||
}
|
||||
if (!Files.exists(tempFolder)) {
|
||||
try {
|
||||
Files.createDirectories(tempFolder);
|
||||
} catch (IOException e) {
|
||||
log.error("Can't create temp directory " + tempFolder, e);
|
||||
}
|
||||
}
|
||||
Path folder = tempFolder.resolve(name);
|
||||
if (!Files.exists(folder)) {
|
||||
try {
|
||||
Files.createDirectories(folder);
|
||||
} catch (IOException e) {
|
||||
log.error("Error creating temp folder '" + folder.toAbsolutePath() + "'", e);
|
||||
}
|
||||
}
|
||||
return folder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Plugin getProductPlugin() {
|
||||
return WebPlatformActivator.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShuttingDown() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public WebSessionManager getSessionManager() {
|
||||
public AppWebSessionManager getSessionManager() {
|
||||
return application.getSessionManager();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ public class CBPlatformActivator extends WebPlatformActivator {
|
||||
protected void shutdownPlatform() {
|
||||
try {
|
||||
// Dispose core
|
||||
if (DBWorkbench.getPlatform() instanceof CBPlatform cbPlatform) {
|
||||
if (DBWorkbench.isPlatformStarted() && DBWorkbench.getPlatform() instanceof CBPlatform cbPlatform) {
|
||||
cbPlatform.dispose();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
|
||||
@@ -187,10 +187,6 @@ public class CBPreferenceStore extends AbstractPreferenceStore {
|
||||
throw new RuntimeException("Not Implemented");
|
||||
}
|
||||
|
||||
public CBApplication getApp() {
|
||||
return cbPlatform.getApplication();
|
||||
}
|
||||
|
||||
private Map<String, Object> productConf() {
|
||||
var app = cbPlatform.getApplication();
|
||||
return app.getProductConfiguration();
|
||||
|
||||
+5
-3
@@ -21,8 +21,10 @@ import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.InstanceCreator;
|
||||
import io.cloudbeaver.model.app.BaseServerConfigurationController;
|
||||
import io.cloudbeaver.model.app.BaseWebApplication;
|
||||
import io.cloudbeaver.service.security.PasswordPolicyConfiguration;
|
||||
import io.cloudbeaver.service.security.SMControllerConfiguration;
|
||||
import io.cloudbeaver.model.config.CBAppConfig;
|
||||
import io.cloudbeaver.model.config.CBServerConfig;
|
||||
import io.cloudbeaver.model.config.PasswordPolicyConfiguration;
|
||||
import io.cloudbeaver.model.config.SMControllerConfiguration;
|
||||
import io.cloudbeaver.utils.WebAppUtils;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
@@ -158,7 +160,7 @@ public abstract class CBServerConfigurationController<T extends CBServerConfig>
|
||||
hostName = InetAddress.getLocalHost().getHostName();
|
||||
} catch (UnknownHostException e) {
|
||||
log.debug("Error resolving localhost address: " + e.getMessage());
|
||||
hostName = CBApplication.HOST_LOCALHOST;
|
||||
hostName = CBConstants.HOST_LOCALHOST;
|
||||
}
|
||||
}
|
||||
config.setServerURL("http://" + hostName + ":" + config.getServerPort());
|
||||
|
||||
+2
-1
@@ -19,7 +19,8 @@ package io.cloudbeaver.server;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.InstanceCreator;
|
||||
import io.cloudbeaver.service.security.db.WebDatabaseConfig;
|
||||
import io.cloudbeaver.model.config.CBServerConfig;
|
||||
import io.cloudbeaver.model.config.WebDatabaseConfig;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.data.json.JSONUtils;
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 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 io.cloudbeaver.model.app.WebApplication;
|
||||
import io.cloudbeaver.registry.WebDriverRegistry;
|
||||
import org.jkiss.code.NotNull;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
//FIXME: this interface should not exist,
|
||||
// the logic of platforms and applications should be separated from each other
|
||||
public interface GQLApplicationAdapter extends WebApplication {
|
||||
AppWebSessionManager getSessionManager();
|
||||
|
||||
WebDriverRegistry getDriverRegistry();
|
||||
|
||||
@NotNull
|
||||
Map<String, Object> getProductConfiguration();
|
||||
|
||||
List<InetAddress> getLocalInetAddresses();
|
||||
|
||||
Map<String, String> getInitActions();
|
||||
|
||||
boolean isLicenseValid();
|
||||
|
||||
String getLicenseStatus();
|
||||
}
|
||||
+4
-6
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
package io.cloudbeaver.server.events;
|
||||
|
||||
import io.cloudbeaver.WebProjectImpl;
|
||||
import io.cloudbeaver.WebSessionProjectImpl;
|
||||
import io.cloudbeaver.model.session.BaseWebSession;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import org.jkiss.code.NotNull;
|
||||
@@ -34,15 +34,13 @@ public class WSDataSourceUpdatedEventHandlerImpl extends WSAbstractProjectEventH
|
||||
@Override
|
||||
protected void updateSessionData(@NotNull BaseWebSession activeUserSession, @NotNull WSDataSourceEvent event) {
|
||||
var sendEvent = true;
|
||||
if (activeUserSession instanceof WebSession) {
|
||||
var webSession = (WebSession) activeUserSession;
|
||||
WebProjectImpl project = webSession.getProjectById(event.getProjectId());
|
||||
if (activeUserSession instanceof WebSession webSession) {
|
||||
WebSessionProjectImpl project = webSession.getProjectById(event.getProjectId());
|
||||
if (project == null) {
|
||||
log.debug("Project " + event.getProjectId() + " is not found in session " + webSession.getSessionId());
|
||||
return;
|
||||
}
|
||||
sendEvent = webSession.updateProjectDataSources(
|
||||
project,
|
||||
sendEvent = project.updateProjectDataSources(
|
||||
event.getDataSourceIds(),
|
||||
WSEventType.valueById(event.getId())
|
||||
);
|
||||
|
||||
+7
-6
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package io.cloudbeaver.server.events;
|
||||
|
||||
import io.cloudbeaver.WebSessionGlobalProjectImpl;
|
||||
import io.cloudbeaver.model.session.BaseWebSession;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.utils.WebAppUtils;
|
||||
@@ -74,34 +75,34 @@ public class WSObjectPermissionUpdatedEventHandler extends WSDefaultEventHandler
|
||||
var webSession = (WebSession) activeUserSession;
|
||||
var dataSources = List.of(objectId);
|
||||
|
||||
var project = webSession.getProjectById(WebAppUtils.getGlobalProjectId());
|
||||
WebSessionGlobalProjectImpl project = webSession.getGlobalProject();
|
||||
if (project == null) {
|
||||
log.error("Project " + WebAppUtils.getGlobalProjectId() +
|
||||
" is not found in session " + activeUserSession.getSessionId());
|
||||
return;
|
||||
}
|
||||
if (WSEventType.OBJECT_PERMISSIONS_UPDATED.getEventId().equals(event.getId())) {
|
||||
isAccessibleNow = webSession.findWebConnectionInfo(project.getId(), objectId) != null;
|
||||
isAccessibleNow = project.findWebConnectionInfo(objectId) != null;
|
||||
if (isAccessibleNow) {
|
||||
return;
|
||||
}
|
||||
webSession.addAccessibleConnectionToCache(objectId);
|
||||
project.addAccessibleConnectionToCache(objectId);
|
||||
webSession.addSessionEvent(
|
||||
WSDataSourceEvent.create(
|
||||
event.getSessionId(),
|
||||
event.getUserId(),
|
||||
WebAppUtils.getGlobalProjectId(),
|
||||
project.getId(),
|
||||
dataSources,
|
||||
WSDataSourceProperty.CONFIGURATION
|
||||
)
|
||||
);
|
||||
} else if (WSEventType.OBJECT_PERMISSIONS_DELETED.getEventId().equals(event.getId())) {
|
||||
webSession.removeAccessibleConnectionFromCache(objectId);
|
||||
project.removeAccessibleConnectionFromCache(objectId);
|
||||
webSession.addSessionEvent(
|
||||
WSDataSourceEvent.delete(
|
||||
event.getSessionId(),
|
||||
event.getUserId(),
|
||||
WebAppUtils.getGlobalProjectId(),
|
||||
project.getId(),
|
||||
dataSources,
|
||||
WSDataSourceProperty.CONFIGURATION
|
||||
)
|
||||
|
||||
+2
-2
@@ -53,13 +53,13 @@ public class WSRmResourceUpdatedEventHandlerImpl extends WSAbstractProjectEventH
|
||||
if (eventType == WSEventType.RM_RESOURCE_CREATED) {
|
||||
RMEventManager.fireEvent(
|
||||
new RMEvent(RMEvent.Action.RESOURCE_ADD,
|
||||
project.getRmProject(),
|
||||
project.getRMProject(),
|
||||
resourcePath)
|
||||
);
|
||||
} else if (eventType == WSEventType.RM_RESOURCE_DELETED) {
|
||||
RMEventManager.fireEvent(
|
||||
new RMEvent(RMEvent.Action.RESOURCE_DELETE,
|
||||
project.getRmProject(),
|
||||
project.getRMProject(),
|
||||
resourcePath)
|
||||
);
|
||||
}
|
||||
|
||||
+5
-1
@@ -32,7 +32,11 @@ public class WSUserEventHandler<EVENT extends WSAbstractEvent> implements WSEven
|
||||
if (eventType == null) {
|
||||
return;
|
||||
}
|
||||
WebSessionManager sessionManager = CBPlatform.getInstance().getSessionManager();
|
||||
var appSessionManager = CBPlatform.getInstance().getSessionManager();
|
||||
if (!(appSessionManager instanceof WebSessionManager)) {
|
||||
return;
|
||||
}
|
||||
var sessionManager = (WebSessionManager) appSessionManager;
|
||||
switch (eventType) {
|
||||
case CLOSE_USER_SESSIONS:
|
||||
if (event instanceof WSUserCloseSessionsEvent closeSessionsEvent) {
|
||||
|
||||
+8
-2
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package io.cloudbeaver.server.events;
|
||||
|
||||
import io.cloudbeaver.WebSessionProjectImpl;
|
||||
import io.cloudbeaver.model.session.BaseWebSession;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import org.jkiss.code.NotNull;
|
||||
@@ -36,11 +37,16 @@ public class WSUserSecretEventHandlerImpl extends WSDefaultEventHandler<WSUserSe
|
||||
|
||||
@Override
|
||||
protected void updateSessionData(@NotNull BaseWebSession activeUserSession, @NotNull WSUserSecretEvent event) {
|
||||
if (!(activeUserSession instanceof WebSession)) {
|
||||
if (!(activeUserSession instanceof WebSession webSession)) {
|
||||
activeUserSession.addSessionEvent(event);
|
||||
return;
|
||||
}
|
||||
var connectionInfo = ((WebSession) activeUserSession).findWebConnectionInfo(event.getProjectId(), event.getDataSourceId());
|
||||
WebSessionProjectImpl project = webSession.getProjectById(event.getProjectId());
|
||||
if (project == null) {
|
||||
log.debug("Project " + event.getDataSourceId() + " is not found in session " + webSession.getSessionId());
|
||||
return;
|
||||
}
|
||||
var connectionInfo = project.findWebConnectionInfo(event.getDataSourceId());
|
||||
if (connectionInfo == null) {
|
||||
log.debug("Connection " + event.getDataSourceId() + " is not found in session " + activeUserSession.getSessionId());
|
||||
return;
|
||||
|
||||
+7
-3
@@ -31,11 +31,11 @@ import io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.WebServiceUtils;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.registry.WebServiceRegistry;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.HttpConstants;
|
||||
import io.cloudbeaver.service.DBWBindingContext;
|
||||
import io.cloudbeaver.service.DBWServiceBindingGraphQL;
|
||||
import io.cloudbeaver.service.WebServiceBindingBase;
|
||||
import io.cloudbeaver.utils.WebAppUtils;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
@@ -61,6 +61,8 @@ public class GraphQLEndpoint extends HttpServlet {
|
||||
|
||||
private static final Log log = Log.getLog(GraphQLEndpoint.class);
|
||||
|
||||
private static final boolean DEBUG = true;
|
||||
|
||||
private static final String HEADER_ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
|
||||
private static final String HEADER_ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
|
||||
private static final String HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
|
||||
@@ -124,7 +126,7 @@ public class GraphQLEndpoint extends HttpServlet {
|
||||
}
|
||||
|
||||
private void setDevelHeaders(HttpServletRequest request, HttpServletResponse response) {
|
||||
if (CBApplication.getInstance().isDevelMode()) {
|
||||
if (WebAppUtils.getWebApplication().getServerConfiguration().isDevelMode()) {
|
||||
// response.setHeader(HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, "*");
|
||||
// response.setHeader(HEADER_ACCESS_CONTROL_ALLOW_HEADERS, "*");
|
||||
// response.setHeader(HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS, "*");
|
||||
@@ -211,7 +213,7 @@ public class GraphQLEndpoint extends HttpServlet {
|
||||
if (path == null) {
|
||||
path = request.getServletPath();
|
||||
}
|
||||
boolean develMode = CBApplication.getInstance().isDevelMode();
|
||||
boolean develMode = WebAppUtils.getWebApplication().getServerConfiguration().isDevelMode();
|
||||
|
||||
if (path.contentEquals("/schema.json") && develMode) {
|
||||
executeQuery(request, response, GraphQLConstants.SCHEMA_READ_QUERY, null, null);
|
||||
@@ -253,6 +255,8 @@ public class GraphQLEndpoint extends HttpServlet {
|
||||
// }
|
||||
if (apiCall != null) {
|
||||
log.debug("API > " + apiCall);
|
||||
} else if (DEBUG) {
|
||||
log.debug("API > " + query);
|
||||
}
|
||||
}
|
||||
ExecutionInput executionInput = contextBuilder.build();
|
||||
|
||||
+45
-13
@@ -16,9 +16,10 @@
|
||||
*/
|
||||
package io.cloudbeaver.server.jetty;
|
||||
|
||||
import io.cloudbeaver.model.config.CBServerConfig;
|
||||
import io.cloudbeaver.registry.WebServiceRegistry;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBServerConfig;
|
||||
import io.cloudbeaver.server.GQLApplicationAdapter;
|
||||
import io.cloudbeaver.server.graphql.GraphQLEndpoint;
|
||||
import io.cloudbeaver.server.servlets.CBImageServlet;
|
||||
import io.cloudbeaver.server.servlets.CBStaticServlet;
|
||||
@@ -26,7 +27,11 @@ import io.cloudbeaver.server.servlets.CBStatusServlet;
|
||||
import io.cloudbeaver.server.servlets.ProxyResourceHandler;
|
||||
import io.cloudbeaver.server.websockets.CBJettyWebSocketManager;
|
||||
import io.cloudbeaver.service.DBWServiceBindingServlet;
|
||||
import org.eclipse.jetty.ee10.servlet.*;
|
||||
import io.cloudbeaver.service.DBWServiceBindingWebSocket;
|
||||
import org.eclipse.jetty.ee10.servlet.ErrorPageErrorHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletMapping;
|
||||
import org.eclipse.jetty.server.*;
|
||||
import org.eclipse.jetty.session.DefaultSessionCache;
|
||||
import org.eclipse.jetty.session.DefaultSessionIdManager;
|
||||
@@ -117,11 +122,28 @@ public class CBJettyServer {
|
||||
// Add extensions from services
|
||||
|
||||
CBJettyServletContext servletContext = new CBJettyServletContext(servletContextHandler);
|
||||
for (DBWServiceBindingServlet wsd : WebServiceRegistry.getInstance().getWebServices(DBWServiceBindingServlet.class)) {
|
||||
try {
|
||||
wsd.addServlets(this.application, servletContext);
|
||||
} catch (DBException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
for (DBWServiceBindingServlet wsd : WebServiceRegistry.getInstance()
|
||||
.getWebServices(DBWServiceBindingServlet.class)
|
||||
) {
|
||||
if (wsd.isApplicable(this.application)) {
|
||||
try {
|
||||
wsd.addServlets(this.application, servletContext);
|
||||
} catch (DBException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CBJettyWebSocketContext webSocketContext = new CBJettyWebSocketContext(server, servletContextHandler);
|
||||
for (DBWServiceBindingWebSocket wsb : WebServiceRegistry.getInstance()
|
||||
.getWebServices(DBWServiceBindingWebSocket.class)
|
||||
) {
|
||||
if (wsb.isApplicable(this.application)) {
|
||||
try {
|
||||
wsb.addWebSockets(this.application, webSocketContext);
|
||||
} catch (DBException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,14 +151,19 @@ public class CBJettyServer {
|
||||
wsContainer.setIdleTimeout(Duration.ofMinutes(5));
|
||||
// Add websockets
|
||||
wsContainer.addMapping(
|
||||
serverConfiguration.getServicesURI() + "ws/*",
|
||||
serverConfiguration.getServicesURI() + "ws",
|
||||
new CBJettyWebSocketManager(this.application.getSessionManager())
|
||||
);
|
||||
}
|
||||
);
|
||||
servletContextHandler.insertHandler(webSocketHandler);
|
||||
|
||||
initSessionManager(this.application, server, servletContextHandler);
|
||||
initSessionManager(
|
||||
this.application.getMaxSessionIdleTime(),
|
||||
this.application,
|
||||
server,
|
||||
servletContextHandler
|
||||
);
|
||||
|
||||
server.setHandler(servletContextHandler);
|
||||
|
||||
@@ -149,6 +176,11 @@ public class CBJettyServer {
|
||||
log.debug("\t" + sm.getServletName() + ": " + Arrays.toString(sm.getPathSpecs())); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
log.debug("Active websocket mappings:");
|
||||
for (String mapping : webSocketContext.getMappings()) {
|
||||
log.debug("\t" + mapping);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
boolean forwardProxy = application.getAppConfiguration().isEnabledForwardProxy();
|
||||
@@ -184,14 +216,14 @@ public class CBJettyServer {
|
||||
return sslConfiguration.isAbsolute() ? sslConfiguration : application.getHomeDirectory().resolve(sslConfiguration);
|
||||
}
|
||||
|
||||
private void initSessionManager(
|
||||
@NotNull CBApplication<?> application,
|
||||
public static void initSessionManager(
|
||||
long maxIdleTime,
|
||||
@NotNull GQLApplicationAdapter application,
|
||||
@NotNull Server server,
|
||||
@NotNull ServletContextHandler servletContextHandler
|
||||
) {
|
||||
// Init sessions persistence
|
||||
SessionHandler sessionHandler = new SessionHandler();
|
||||
var maxIdleTime = application.getMaxSessionIdleTime();
|
||||
CBSessionHandler sessionHandler = new CBSessionHandler(application);
|
||||
int intMaxIdleSeconds;
|
||||
if (maxIdleTime > Integer.MAX_VALUE) {
|
||||
log.warn("Max session idle time value is greater than Integer.MAX_VALUE. Integer.MAX_VALUE will be used instead");
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 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.jetty;
|
||||
|
||||
import io.cloudbeaver.service.DBWWebSocketContext;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.websocket.api.Configurable;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketCreator;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketUpgradeHandler;
|
||||
import org.jkiss.code.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class CBJettyWebSocketContext implements DBWWebSocketContext {
|
||||
private final List<String> mappings = new ArrayList<>();
|
||||
|
||||
private final Server server;
|
||||
private final ContextHandler handler;
|
||||
|
||||
public CBJettyWebSocketContext(@NotNull Server server, @NotNull ContextHandler handler) {
|
||||
this.server = server;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addWebSocket(@NotNull String mapping, @NotNull Function<Configurable, WebSocketCreator> configurator) {
|
||||
handler.insertHandler(WebSocketUpgradeHandler.from(
|
||||
server,
|
||||
handler,
|
||||
container -> container.addMapping(mapping, configurator.apply(container))
|
||||
));
|
||||
mappings.add(mapping);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getMappings() {
|
||||
return mappings;
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
package io.cloudbeaver.server.jetty;
|
||||
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.GQLApplicationAdapter;
|
||||
import jakarta.servlet.SessionCookieConfig;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.SessionHandler;
|
||||
@@ -28,9 +28,9 @@ import java.util.TreeMap;
|
||||
|
||||
public class CBSessionHandler extends SessionHandler {
|
||||
private final CBCookieConfig cbCookieConfig;
|
||||
private final CBApplication<?> application;
|
||||
private final GQLApplicationAdapter application;
|
||||
|
||||
public CBSessionHandler(CBApplication<?> application) {
|
||||
public CBSessionHandler(GQLApplicationAdapter application) {
|
||||
this.cbCookieConfig = new CBCookieConfig();
|
||||
this.application = application;
|
||||
}
|
||||
|
||||
+3
-3
@@ -16,20 +16,20 @@
|
||||
*/
|
||||
package io.cloudbeaver.server.jobs;
|
||||
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.app.DBPPlatform;
|
||||
import org.jkiss.dbeaver.model.runtime.AbstractJob;
|
||||
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
|
||||
|
||||
public abstract class PeriodicSystemJob extends AbstractJob {
|
||||
|
||||
@NotNull
|
||||
protected final CBPlatform platform;
|
||||
protected final DBPPlatform platform;
|
||||
private final long periodMs;
|
||||
|
||||
public PeriodicSystemJob(@NotNull String name, @NotNull CBPlatform platform, long periodMs) {
|
||||
public PeriodicSystemJob(@NotNull String name, @NotNull DBPPlatform platform, long periodMs) {
|
||||
super(name);
|
||||
this.platform = platform;
|
||||
this.periodMs = periodMs;
|
||||
|
||||
+6
-3
@@ -16,23 +16,26 @@
|
||||
*/
|
||||
package io.cloudbeaver.server.jobs;
|
||||
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import io.cloudbeaver.service.session.WebSessionManager;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.app.DBPPlatform;
|
||||
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
|
||||
|
||||
public class SessionStateJob extends PeriodicSystemJob {
|
||||
private static final Log log = Log.getLog(SessionStateJob.class);
|
||||
private static final int PERIOD_MS = 30_000; // once per 30 seconds
|
||||
private final WebSessionManager sessionManager;
|
||||
|
||||
public SessionStateJob(@NotNull CBPlatform platform) {
|
||||
public SessionStateJob(@NotNull DBPPlatform platform, WebSessionManager sessionManager) {
|
||||
super("Session state sender", platform, PERIOD_MS);
|
||||
this.sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doJob(@NotNull DBRProgressMonitor monitor) {
|
||||
try {
|
||||
platform.getSessionManager().sendSessionsStates();
|
||||
sessionManager.sendSessionsStates();
|
||||
} catch (Exception e) {
|
||||
log.error("Error sending session state", e);
|
||||
}
|
||||
|
||||
+8
-3
@@ -16,9 +16,9 @@
|
||||
*/
|
||||
package io.cloudbeaver.server.jobs;
|
||||
|
||||
import io.cloudbeaver.server.AppWebSessionManager;
|
||||
import io.cloudbeaver.model.session.BaseWebSession;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.DBPDataSource;
|
||||
import org.jkiss.dbeaver.model.app.DBPPlatform;
|
||||
@@ -34,14 +34,19 @@ import java.util.List;
|
||||
* Web data source monitor job.
|
||||
*/
|
||||
public class WebDataSourceMonitorJob extends DataSourceMonitorJob {
|
||||
private final AppWebSessionManager sessionManager;
|
||||
|
||||
public WebDataSourceMonitorJob(DBPPlatform platform) {
|
||||
public WebDataSourceMonitorJob(
|
||||
@NotNull DBPPlatform platform,
|
||||
@NotNull AppWebSessionManager sessionManager
|
||||
) {
|
||||
super(platform);
|
||||
this.sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doJob() {
|
||||
Collection<BaseWebSession> allSessions = CBPlatform.getInstance().getSessionManager().getAllActiveSessions();
|
||||
Collection<BaseWebSession> allSessions = sessionManager.getAllActiveSessions();
|
||||
allSessions.parallelStream().forEach(s -> {
|
||||
checkDataSourceAliveInWorkspace(s.getWorkspace(), s.getLastAccessTimeMillis());
|
||||
});
|
||||
|
||||
+6
-3
@@ -16,9 +16,10 @@
|
||||
*/
|
||||
package io.cloudbeaver.server.jobs;
|
||||
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import io.cloudbeaver.service.session.WebSessionManager;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.app.DBPPlatform;
|
||||
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
|
||||
|
||||
/**
|
||||
@@ -27,15 +28,17 @@ import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
|
||||
public class WebSessionMonitorJob extends PeriodicSystemJob {
|
||||
private static final Log log = Log.getLog(WebSessionMonitorJob.class);
|
||||
private static final int MONITOR_INTERVAL = 10000; // once per 10 seconds
|
||||
private final WebSessionManager sessionManager;
|
||||
|
||||
public WebSessionMonitorJob(@NotNull CBPlatform platform) {
|
||||
public WebSessionMonitorJob(@NotNull DBPPlatform platform, @NotNull WebSessionManager sessionManager) {
|
||||
super("Web session monitor", platform, MONITOR_INTERVAL);
|
||||
this.sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doJob(@NotNull DBRProgressMonitor monitor) {
|
||||
try {
|
||||
platform.getSessionManager().expireIdleSessions();
|
||||
sessionManager.expireIdleSessions();
|
||||
} catch (Exception e) {
|
||||
log.error("Error on expire idle sessions", e);
|
||||
}
|
||||
|
||||
+2
-1
@@ -20,13 +20,14 @@ import io.cloudbeaver.DBWConstants;
|
||||
import io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.auth.CBAuthConstants;
|
||||
import io.cloudbeaver.auth.SMAuthProviderFederated;
|
||||
import io.cloudbeaver.model.config.CBAppConfig;
|
||||
import io.cloudbeaver.model.config.CBServerConfig;
|
||||
import io.cloudbeaver.model.session.WebActionParameters;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
|
||||
import io.cloudbeaver.registry.WebAuthProviderRegistry;
|
||||
import io.cloudbeaver.registry.WebHandlerRegistry;
|
||||
import io.cloudbeaver.registry.WebServletHandlerDescriptor;
|
||||
import io.cloudbeaver.server.CBAppConfig;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import jakarta.servlet.ServletException;
|
||||
|
||||
+2
-1
@@ -19,6 +19,7 @@ package io.cloudbeaver.server.servlets;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBConstants;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.annotation.WebServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
@@ -45,7 +46,7 @@ public class CBStatusServlet extends DefaultServlet {
|
||||
infoMap.put("health", "ok");
|
||||
infoMap.put("product.name", GeneralUtils.getProductName());
|
||||
infoMap.put("product.version", GeneralUtils.getProductVersion().toString());
|
||||
CBApplication.getInstance().getStatusInfo(infoMap);
|
||||
CBPlatform.getInstance().getApplication().getStatusInfo(infoMap);
|
||||
try (JsonWriter writer = new JsonWriter(response.getWriter())) {
|
||||
JSONUtils.serializeMap(writer, infoMap);
|
||||
}
|
||||
|
||||
+1
-1
@@ -16,8 +16,8 @@
|
||||
*/
|
||||
package io.cloudbeaver.server.servlets;
|
||||
|
||||
import io.cloudbeaver.model.config.CBServerConfig;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBServerConfig;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
|
||||
+3
-3
@@ -16,11 +16,11 @@
|
||||
*/
|
||||
package io.cloudbeaver.server.websockets;
|
||||
|
||||
import io.cloudbeaver.server.AppWebSessionManager;
|
||||
import io.cloudbeaver.model.session.BaseWebSession;
|
||||
import io.cloudbeaver.model.session.WebHeadlessSession;
|
||||
import io.cloudbeaver.model.session.WebHttpRequestInfo;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import io.cloudbeaver.service.session.WebSessionManager;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.server.ServerUpgradeRequest;
|
||||
@@ -42,9 +42,9 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
public class CBJettyWebSocketManager implements WebSocketCreator {
|
||||
private static final Log log = Log.getLog(CBJettyWebSocketManager.class);
|
||||
private final Map<String, List<CBEventsWebSocket>> socketBySessionId = new ConcurrentHashMap<>();
|
||||
private final WebSessionManager webSessionManager;
|
||||
private final AppWebSessionManager webSessionManager;
|
||||
|
||||
public CBJettyWebSocketManager(@NotNull WebSessionManager webSessionManager) {
|
||||
public CBJettyWebSocketManager(@NotNull AppWebSessionManager webSessionManager) {
|
||||
this.webSessionManager = webSessionManager;
|
||||
|
||||
new WebSocketPingPongJob(CBPlatform.getInstance(), this).scheduleMonitor();
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 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;
|
||||
|
||||
import io.cloudbeaver.model.app.WebApplication;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
|
||||
public interface DBWServiceBindingWebSocket<APPLICATION extends WebApplication> extends DBWServiceBinding {
|
||||
default boolean isApplicable(@NotNull WebApplication application) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void addWebSockets(@NotNull APPLICATION application, @NotNull DBWWebSocketContext context) throws DBException;
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 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;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.Configurable;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketCreator;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface DBWWebSocketContext {
|
||||
void addWebSocket(@NotNull String mapping, @NotNull Function<Configurable, WebSocketCreator> configurator) throws DBException;
|
||||
}
|
||||
+4
-3
@@ -27,6 +27,7 @@ import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import io.cloudbeaver.server.graphql.GraphQLEndpoint;
|
||||
import io.cloudbeaver.service.security.SMUtils;
|
||||
import io.cloudbeaver.utils.WebDataSourceUtils;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.jkiss.code.NotNull;
|
||||
@@ -136,7 +137,7 @@ public abstract class WebServiceBindingBase<API_TYPE extends DBWService> impleme
|
||||
|
||||
@NotNull
|
||||
public static WebConnectionInfo getWebConnection(WebSession session, String projectId, String connectionId) throws DBWebException {
|
||||
return session.getWebConnectionInfo(projectId, connectionId);
|
||||
return WebDataSourceUtils.getWebConnectionInfo(session, projectId, connectionId);
|
||||
}
|
||||
|
||||
private class ServiceInvocationHandler implements InvocationHandler {
|
||||
@@ -229,7 +230,7 @@ public abstract class WebServiceBindingBase<API_TYPE extends DBWService> impleme
|
||||
if (project == null) {
|
||||
throw new DBException("Project not found:" + projectId);
|
||||
}
|
||||
RMProject rmProject = project.getRmProject();
|
||||
RMProject rmProject = project.getRMProject();
|
||||
|
||||
for (String reqProjectPermission : requireProjectPermissions) {
|
||||
if (!rmProject.hasProjectPermission(reqProjectPermission)) {
|
||||
@@ -250,7 +251,7 @@ public abstract class WebServiceBindingBase<API_TYPE extends DBWService> impleme
|
||||
}
|
||||
|
||||
private void checkActionPermissions(@NotNull Method method, @NotNull WebAction webAction) throws DBWebException {
|
||||
CBApplication<?> application = CBApplication.getInstance();
|
||||
var application = CBPlatform.getInstance().getApplication();
|
||||
if (application.isInitializationMode() && webAction.initializationRequired()) {
|
||||
String message = "Server initialization in progress: "
|
||||
+ String.join(",", application.getInitActions().values()) + ".\nDo not restart the server.";
|
||||
|
||||
+20
-3
@@ -1,7 +1,24 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 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;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import io.cloudbeaver.model.app.WebApplication;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
@@ -27,13 +44,13 @@ public abstract class WebServiceServletBase extends HttpServlet {
|
||||
.setPrettyPrinting()
|
||||
.create();
|
||||
|
||||
private final CBApplication application;
|
||||
private final WebApplication application;
|
||||
|
||||
public WebServiceServletBase(CBApplication application) {
|
||||
public WebServiceServletBase(WebApplication application) {
|
||||
this.application = application;
|
||||
}
|
||||
|
||||
public CBApplication getApplication() {
|
||||
public WebApplication getApplication() {
|
||||
return application;
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -29,7 +29,6 @@ import io.cloudbeaver.server.graphql.GraphQLEndpoint;
|
||||
import io.cloudbeaver.service.DBWBindingContext;
|
||||
import io.cloudbeaver.service.WebServiceBindingBase;
|
||||
import io.cloudbeaver.service.core.impl.WebServiceCore;
|
||||
import io.cloudbeaver.service.session.WebSessionManager;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -50,7 +49,7 @@ public class WebServiceBindingCore extends WebServiceBindingBase<DBWServiceCore>
|
||||
@Override
|
||||
public void bindWiring(DBWBindingContext model) throws DBWebException {
|
||||
CBPlatform platform = CBPlatform.getInstance();
|
||||
WebSessionManager sessionManager = platform.getSessionManager();
|
||||
var sessionManager = platform.getSessionManager();
|
||||
model.getQueryType()
|
||||
.dataFetcher("serverConfig", env -> getService(env).getServerConfig())
|
||||
.dataFetcher("productSettings", env -> getService(env).getProductSettings(getWebSession(env)))
|
||||
|
||||
+41
-38
@@ -17,10 +17,7 @@
|
||||
package io.cloudbeaver.service.core.impl;
|
||||
|
||||
|
||||
import io.cloudbeaver.DBWConstants;
|
||||
import io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.WebProjectImpl;
|
||||
import io.cloudbeaver.WebServiceUtils;
|
||||
import io.cloudbeaver.*;
|
||||
import io.cloudbeaver.model.*;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.registry.WebHandlerRegistry;
|
||||
@@ -29,7 +26,6 @@ import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import io.cloudbeaver.service.core.DBWServiceCore;
|
||||
import io.cloudbeaver.service.security.SMUtils;
|
||||
import io.cloudbeaver.service.session.WebSessionManager;
|
||||
import io.cloudbeaver.utils.WebConnectionFolderUtils;
|
||||
import io.cloudbeaver.utils.WebDataSourceUtils;
|
||||
import io.cloudbeaver.utils.WebEventUtils;
|
||||
@@ -118,15 +114,17 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
return Collections.singletonList(connectionInfo);
|
||||
}
|
||||
}
|
||||
var stream = webSession.getConnections().stream();
|
||||
var stream = webSession.getAccessibleProjects().stream();
|
||||
if (projectId != null) {
|
||||
stream = stream.filter(c -> c.getProjectId().equals(projectId));
|
||||
stream = stream.filter(c -> c.getId().equals(projectId));
|
||||
}
|
||||
if (projectIds != null) {
|
||||
stream = stream.filter(c -> projectIds.contains(c.getProjectId()));
|
||||
stream = stream.filter(c -> projectIds.contains(c.getId()));
|
||||
}
|
||||
Set<String> applicableDrivers = WebServiceUtils.getApplicableDriversIds();
|
||||
return stream.filter(c -> applicableDrivers.contains(c.getDataSourceContainer().getDriver().getId()))
|
||||
return stream
|
||||
.flatMap(p -> p.getConnections().stream())
|
||||
.filter(c -> applicableDrivers.contains(c.getDataSourceContainer().getDriver().getId()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@@ -154,27 +152,30 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
public List<WebConnectionInfo> getTemplateConnections(
|
||||
@NotNull WebSession webSession, @Nullable String projectId
|
||||
) throws DBWebException {
|
||||
if (webSession.getApplication().isDistributed()) {
|
||||
return List.of();
|
||||
}
|
||||
List<WebConnectionInfo> result = new ArrayList<>();
|
||||
if (projectId == null) {
|
||||
for (DBPProject project : webSession.getAccessibleProjects()) {
|
||||
for (WebSessionProjectImpl project : webSession.getAccessibleProjects()) {
|
||||
getTemplateConnectionsFromProject(webSession, project, result);
|
||||
}
|
||||
} else {
|
||||
DBPProject project = getProjectById(webSession, projectId);
|
||||
WebSessionProjectImpl project = getProjectById(webSession, projectId);
|
||||
getTemplateConnectionsFromProject(webSession, project, result);
|
||||
}
|
||||
webSession.filterAccessibleConnections(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void getTemplateConnectionsFromProject(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull DBPProject project,
|
||||
@NotNull WebSessionProjectImpl project,
|
||||
List<WebConnectionInfo> result
|
||||
) {
|
||||
DBPDataSourceRegistry registry = project.getDataSourceRegistry();
|
||||
for (DBPDataSourceContainer ds : registry.getDataSources()) {
|
||||
if (ds.isTemplate() &&
|
||||
project.getDataSourceFilter().filter(ds) &&
|
||||
CBPlatform.getInstance().getApplicableDrivers().contains(ds.getDriver())) {
|
||||
result.add(new WebConnectionInfo(webSession, ds));
|
||||
}
|
||||
@@ -291,7 +292,7 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
@Deprecated
|
||||
public WebSession updateSession(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response)
|
||||
throws DBWebException {
|
||||
WebSessionManager sessionManager = CBPlatform.getInstance().getSessionManager();
|
||||
var sessionManager = CBPlatform.getInstance().getSessionManager();
|
||||
sessionManager.touchSession(request, response);
|
||||
return sessionManager.getWebSession(request, response, true);
|
||||
}
|
||||
@@ -317,9 +318,11 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
|
||||
@Override
|
||||
public WebConnectionInfo getConnectionState(
|
||||
WebSession webSession, @Nullable String projectId, String connectionId
|
||||
@NotNull WebSession webSession,
|
||||
@Nullable String projectId,
|
||||
@NotNull String connectionId
|
||||
) throws DBWebException {
|
||||
return webSession.getWebConnectionInfo(projectId, connectionId);
|
||||
return WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId);
|
||||
}
|
||||
|
||||
|
||||
@@ -334,7 +337,7 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
@Nullable Boolean sharedCredentials,
|
||||
@Nullable String selectedSecretId
|
||||
) throws DBWebException {
|
||||
WebConnectionInfo connectionInfo = webSession.getWebConnectionInfo(projectId, connectionId);
|
||||
WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId);
|
||||
connectionInfo.setSavedCredentials(authProperties, networkCredentials);
|
||||
|
||||
var dataSourceContainer = (DataSourceDescriptor) connectionInfo.getDataSourceContainer();
|
||||
@@ -430,8 +433,8 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
@Nullable String projectId,
|
||||
@NotNull WebConnectionConfig connectionConfig
|
||||
) throws DBWebException {
|
||||
var project = getProjectById(webSession, projectId);
|
||||
var rmProject = project.getRmProject();
|
||||
WebSessionProjectImpl project = getProjectById(webSession, projectId);
|
||||
var rmProject = project.getRMProject();
|
||||
if (rmProject.getType() == RMProjectType.USER
|
||||
&& !webSession.hasPermission(DBWConstants.PERMISSION_ADMIN)
|
||||
&& !CBApplication.getInstance().getAppConfiguration().isSupportsCustomConnections()
|
||||
@@ -460,8 +463,7 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
throw new DBWebException("Failed to create connection", e);
|
||||
}
|
||||
|
||||
WebConnectionInfo connectionInfo = new WebConnectionInfo(webSession, newDataSource);
|
||||
webSession.addConnection(connectionInfo);
|
||||
WebConnectionInfo connectionInfo = project.addConnection(newDataSource);
|
||||
webSession.addInfoMessage("New connection was created - " + WebServiceUtils.getConnectionContainerInfo(
|
||||
newDataSource));
|
||||
WebEventUtils.addDataSourceUpdatedEvent(
|
||||
@@ -485,9 +487,8 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
// if (!CBApplication.getInstance().getAppConfiguration().isSupportsCustomConnections()) {
|
||||
// throw new DBWebException("Connection edit is restricted by server configuration");
|
||||
// }
|
||||
DBPDataSourceRegistry sessionRegistry = getProjectById(webSession, projectId).getDataSourceRegistry();
|
||||
|
||||
WebConnectionInfo connectionInfo = webSession.getWebConnectionInfo(projectId, config.getConnectionId());
|
||||
WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, config.getConnectionId());
|
||||
DBPDataSourceContainer dataSource = connectionInfo.getDataSourceContainer();
|
||||
webSession.addInfoMessage("Update connection - " + WebServiceUtils.getConnectionContainerInfo(dataSource));
|
||||
var oldDataSource = new DataSourceDescriptor((DataSourceDescriptor) dataSource, dataSource.getRegistry());
|
||||
@@ -500,6 +501,8 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
dataSource.setDescription(config.getDescription());
|
||||
}
|
||||
|
||||
WebSessionProjectImpl project = getProjectById(webSession, projectId);
|
||||
DBPDataSourceRegistry sessionRegistry = project.getDataSourceRegistry();
|
||||
dataSource.setFolder(config.getFolder() != null ? sessionRegistry.getFolder(config.getFolder()) : null);
|
||||
if (config.isDefaultAutoCommit() != null) {
|
||||
dataSource.setDefaultAutoCommit(config.isDefaultAutoCommit());
|
||||
@@ -576,7 +579,7 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
public boolean deleteConnection(
|
||||
@NotNull WebSession webSession, @Nullable String projectId, @NotNull String connectionId
|
||||
) throws DBWebException {
|
||||
WebConnectionInfo connectionInfo = webSession.getWebConnectionInfo(projectId, connectionId);
|
||||
WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId);
|
||||
if (connectionInfo.getDataSourceContainer().getProject() != getProjectById(webSession, projectId)) {
|
||||
throw new DBWebException("Global connection '" + connectionInfo.getName() + "' configuration cannot be deleted");
|
||||
}
|
||||
@@ -600,7 +603,8 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
@NotNull String templateId,
|
||||
@Nullable String connectionName
|
||||
) throws DBWebException {
|
||||
DBPDataSourceRegistry templateRegistry = getProjectById(webSession, projectId).getDataSourceRegistry();
|
||||
WebSessionProjectImpl project = getProjectById(webSession, projectId);
|
||||
DBPDataSourceRegistry templateRegistry = project.getDataSourceRegistry();
|
||||
DBPDataSourceContainer dataSourceTemplate = templateRegistry.getDataSource(templateId);
|
||||
if (dataSourceTemplate == null) {
|
||||
throw new DBWebException("Template data source '" + templateId + "' not found");
|
||||
@@ -623,9 +627,7 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
throw new DBWebException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
WebConnectionInfo connectionInfo = new WebConnectionInfo(webSession, newDataSource);
|
||||
webSession.addConnection(connectionInfo);
|
||||
return connectionInfo;
|
||||
return project.addConnection(newDataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -637,7 +639,8 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
) throws DBWebException {
|
||||
try {
|
||||
DBNModel navigatorModel = webSession.getNavigatorModel();
|
||||
DBPDataSourceRegistry dataSourceRegistry = getProjectById(webSession, projectId).getDataSourceRegistry();
|
||||
WebSessionProjectImpl project = getProjectById(webSession, projectId);
|
||||
DBPDataSourceRegistry dataSourceRegistry = project.getDataSourceRegistry();
|
||||
|
||||
DBNNode srcNode = navigatorModel.getNodeByPath(webSession.getProgressMonitor(), nodePath);
|
||||
if (srcNode == null) {
|
||||
@@ -663,9 +666,8 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
|
||||
dataSourceRegistry.addDataSource(newDataSource);
|
||||
|
||||
WebConnectionInfo connectionInfo = new WebConnectionInfo(webSession, newDataSource);
|
||||
dataSourceRegistry.checkForErrors();
|
||||
webSession.addConnection(connectionInfo);
|
||||
WebConnectionInfo connectionInfo = project.addConnection(newDataSource);
|
||||
WebEventUtils.addDataSourceUpdatedEvent(
|
||||
webSession.getProjectById(projectId),
|
||||
webSession,
|
||||
@@ -688,7 +690,7 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
connectionConfig.setSaveCredentials(true); // It is used in createConnectionFromConfig
|
||||
|
||||
DataSourceDescriptor dataSource = (DataSourceDescriptor) WebDataSourceUtils.getLocalOrGlobalDataSource(
|
||||
CBApplication.getInstance(), webSession, projectId, connectionId);
|
||||
webSession, projectId, connectionId);
|
||||
|
||||
WebProjectImpl project = getProjectById(webSession, projectId);
|
||||
DBPDataSourceRegistry sessionRegistry = project.getDataSourceRegistry();
|
||||
@@ -824,12 +826,13 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
@NotNull String connectionId,
|
||||
boolean forceDelete
|
||||
) throws DBWebException {
|
||||
WebConnectionInfo connectionInfo = webSession.getWebConnectionInfo(projectId, connectionId);
|
||||
WebSessionProjectImpl project = getProjectById(webSession, projectId);
|
||||
WebConnectionInfo connectionInfo = project.getWebConnectionInfo(connectionId);
|
||||
|
||||
DBPDataSourceContainer dataSourceContainer = connectionInfo.getDataSourceContainer();
|
||||
boolean disconnected = WebDataSourceUtils.disconnectDataSource(webSession, dataSourceContainer);
|
||||
if (forceDelete) {
|
||||
DBPDataSourceRegistry registry = getProjectById(webSession, projectId).getDataSourceRegistry();
|
||||
DBPDataSourceRegistry registry = project.getDataSourceRegistry();
|
||||
registry.removeDataSource(dataSourceContainer);
|
||||
try {
|
||||
registry.checkForErrors();
|
||||
@@ -841,7 +844,7 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
}
|
||||
throw new DBWebException("Failed to delete connection", e);
|
||||
}
|
||||
webSession.removeConnection(connectionInfo);
|
||||
project.removeConnection(dataSourceContainer);
|
||||
} else {
|
||||
// Just reset saved credentials
|
||||
connectionInfo.clearCache();
|
||||
@@ -955,7 +958,7 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
public WebConnectionInfo setConnectionNavigatorSettings(
|
||||
WebSession webSession, @Nullable String projectId, String id, DBNBrowseSettings settings
|
||||
) throws DBWebException {
|
||||
WebConnectionInfo connectionInfo = webSession.getWebConnectionInfo(projectId, id);
|
||||
WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, id);
|
||||
DataSourceDescriptor dataSourceDescriptor = ((DataSourceDescriptor) connectionInfo.getDataSourceContainer());
|
||||
dataSourceDescriptor.setNavigatorSettings(settings);
|
||||
dataSourceDescriptor.persistConfiguration();
|
||||
@@ -984,8 +987,8 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
return new WebProductSettings(webSession, ProductSettingsRegistry.getInstance().getSettings());
|
||||
}
|
||||
|
||||
private WebProjectImpl getProjectById(WebSession webSession, String projectId) throws DBWebException {
|
||||
WebProjectImpl project = webSession.getProjectById(projectId);
|
||||
private WebSessionProjectImpl getProjectById(WebSession webSession, String projectId) throws DBWebException {
|
||||
WebSessionProjectImpl project = webSession.getProjectById(projectId);
|
||||
if (project == null) {
|
||||
throw new DBWebException("Project '" + projectId + "' not found");
|
||||
}
|
||||
|
||||
+17
-2
@@ -16,15 +16,17 @@
|
||||
*/
|
||||
package io.cloudbeaver.service.navigator;
|
||||
|
||||
import io.cloudbeaver.WebProjectImpl;
|
||||
import io.cloudbeaver.WebServiceUtils;
|
||||
import io.cloudbeaver.model.WebPropertyInfo;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.service.security.SMUtils;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.*;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
import org.jkiss.dbeaver.model.navigator.DBNDataSource;
|
||||
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
|
||||
import org.jkiss.dbeaver.model.rm.RMProjectPermission;
|
||||
import org.jkiss.dbeaver.model.struct.*;
|
||||
import org.jkiss.dbeaver.model.struct.rdb.DBSCatalog;
|
||||
import org.jkiss.dbeaver.model.struct.rdb.DBSSchema;
|
||||
@@ -91,9 +93,22 @@ public class WebDatabaseObjectInfo {
|
||||
|
||||
@Property
|
||||
public WebPropertyInfo[] filterProperties(@Nullable WebPropertyFilter filter) {
|
||||
if (object instanceof DBPDataSourceContainer container && !isDataSourceEditable(container)) {
|
||||
// If user cannot edit a connection, then return only name
|
||||
filter = new WebPropertyFilter();
|
||||
filter.setFeatures(List.of(DBConstants.PROP_FEATURE_NAME));
|
||||
}
|
||||
return WebServiceUtils.getObjectFilteredProperties(session, object, filter);
|
||||
}
|
||||
|
||||
private boolean isDataSourceEditable(@NotNull DBPDataSourceContainer container) {
|
||||
WebProjectImpl project = session.getProjectById(container.getProject().getId());
|
||||
if (project == null) {
|
||||
return false;
|
||||
}
|
||||
return SMUtils.hasProjectPermission(session, project.getRMProject(), RMProjectPermission.DATA_SOURCES_EDIT);
|
||||
}
|
||||
|
||||
///////////////////////////////////
|
||||
// Advanced
|
||||
|
||||
|
||||
+14
-13
@@ -111,7 +111,7 @@ public class WebNavigatorNodeInfo {
|
||||
|
||||
@Property
|
||||
public String getProjectId() {
|
||||
DBPProject ownerProject = node.getOwnerProject();
|
||||
DBPProject ownerProject = node.getOwnerProjectOrNull();
|
||||
return ownerProject == null ? null : ownerProject.getId();
|
||||
}
|
||||
|
||||
@@ -119,11 +119,11 @@ public class WebNavigatorNodeInfo {
|
||||
@Deprecated
|
||||
public String getFullName() {
|
||||
String nodeName;
|
||||
if (node instanceof DBNDatabaseNode && !(node instanceof DBNDataSource)) {
|
||||
DBSObject object = ((DBNDatabaseNode) node).getObject();
|
||||
if (node instanceof DBNDatabaseNode dbNode && !(node instanceof DBNDataSource)) {
|
||||
DBSObject object = dbNode.getObject();
|
||||
nodeName = DBUtils.getObjectFullName(object, DBPEvaluationContext.UI);
|
||||
} else if (node instanceof DBNDataSource) {
|
||||
DBPDataSourceContainer object = ((DBNDataSource) node).getDataSourceContainer();
|
||||
} else if (node instanceof DBNDataSource dataSource) {
|
||||
DBPDataSourceContainer object = dataSource.getDataSourceContainer();
|
||||
nodeName = object.getName();
|
||||
} else {
|
||||
nodeName = node.getNodeTargetName();
|
||||
@@ -235,7 +235,7 @@ public class WebNavigatorNodeInfo {
|
||||
if (objectManager != null && objectManager.canDeleteObject(object)) {
|
||||
features.add(NODE_FEATURE_CAN_DELETE);
|
||||
}
|
||||
if (objectManager instanceof DBEObjectRenamer && ((DBEObjectRenamer) objectManager).canRenameObject(object)) {
|
||||
if (objectManager instanceof DBEObjectRenamer renamer && renamer.canRenameObject(object)) {
|
||||
if (!object.getDataSource().getContainer().getNavigatorSettings().isShowOnlyEntities()) {
|
||||
features.add(NODE_FEATURE_CAN_RENAME);
|
||||
}
|
||||
@@ -259,7 +259,7 @@ public class WebNavigatorNodeInfo {
|
||||
if (project == null) {
|
||||
return false;
|
||||
}
|
||||
RMProject rmProject = project.getRmProject();
|
||||
RMProject rmProject = project.getRMProject();
|
||||
return SMUtils.hasProjectPermission(session, rmProject, permission);
|
||||
}
|
||||
|
||||
@@ -282,9 +282,10 @@ public class WebNavigatorNodeInfo {
|
||||
|
||||
@Property
|
||||
public WebPropertyInfo[] getNodeDetails() throws DBWebException {
|
||||
if (node instanceof DBPObjectWithDetails) {
|
||||
if (node instanceof DBPObjectWithDetails objectWithDetails) {
|
||||
try {
|
||||
DBPObject objectDetails = ((DBPObjectWithDetails) node).getObjectDetails(session.getProgressMonitor(), session.getSessionContext(), node);
|
||||
DBPObject objectDetails = objectWithDetails.getObjectDetails(
|
||||
session.getProgressMonitor(), session.getSessionContext(), node);
|
||||
if (objectDetails != null) {
|
||||
return WebServiceUtils.getObjectProperties(session, objectDetails);
|
||||
}
|
||||
@@ -301,8 +302,8 @@ public class WebNavigatorNodeInfo {
|
||||
|
||||
@Property
|
||||
public WebDatabaseObjectInfo getObject() {
|
||||
if (node instanceof DBNDatabaseNode) {
|
||||
DBSObject object = ((DBNDatabaseNode) node).getObject();
|
||||
if (node instanceof DBNDatabaseNode dbNode) {
|
||||
DBSObject object = dbNode.getObject();
|
||||
return object == null ? null : new WebDatabaseObjectInfo(session, object);
|
||||
}
|
||||
return null;
|
||||
@@ -320,10 +321,10 @@ public class WebNavigatorNodeInfo {
|
||||
|
||||
@Property
|
||||
public DBSObjectFilter getFilter() throws DBWebException {
|
||||
if (!(node instanceof DBNDatabaseNode)) {
|
||||
if (!(node instanceof DBNDatabaseNode dbNode)) {
|
||||
throw new DBWebException("Invalid navigator node type: " + node.getClass().getName());
|
||||
}
|
||||
DBSObjectFilter filter = ((DBNDatabaseNode) node).getNodeFilter(((DBNDatabaseNode) node).getItemsMeta(), true);
|
||||
DBSObjectFilter filter = dbNode.getNodeFilter(dbNode.getItemsMeta(), true);
|
||||
return filter == null || filter.isEmpty() || !filter.isEnabled() ? null : filter;
|
||||
}
|
||||
|
||||
|
||||
+13
-12
@@ -228,11 +228,12 @@ public class WebServiceNavigator implements DBWServiceNavigator {
|
||||
filter.setExclude(exclude);
|
||||
}
|
||||
filter.setEnabled(true);
|
||||
((DBNDatabaseNode) node).setNodeFilter(
|
||||
((DBNDatabaseNode) node).getItemsMeta(), filter, true);
|
||||
if (hasNodeEditPermission(webSession, node, ((WebProjectImpl) node.getOwnerProject()).getRmProject())) {
|
||||
// Save settings
|
||||
((DBNDatabaseNode) node).getDataSourceContainer().persistConfiguration();
|
||||
if (node instanceof DBNDatabaseNode dbNode) {
|
||||
dbNode.setNodeFilter(dbNode.getItemsMeta(), filter, true);
|
||||
if (hasNodeEditPermission(webSession, node, ((WebProjectImpl) node.getOwnerProject()).getRMProject())) {
|
||||
// Save settings
|
||||
dbNode.getDataSourceContainer().persistConfiguration();
|
||||
}
|
||||
}
|
||||
} catch (DBException e) {
|
||||
if (e instanceof DBWebException) {
|
||||
@@ -255,14 +256,14 @@ public class WebServiceNavigator implements DBWServiceNavigator {
|
||||
if (node == null) {
|
||||
throw new DBWebException("Navigator node '" + nodePath + "' not found");
|
||||
}
|
||||
if (node instanceof DBNDataSource) {
|
||||
if (node instanceof DBNDataSource dbnDataSource) {
|
||||
// Do not refresh entire tree - just clear child nodes
|
||||
// Otherwise refresh may fail if navigator settings were changed.
|
||||
DBPDataSource dataSource = ((DBNDataSource) node).getDataSource();
|
||||
if (dataSource instanceof DBPRefreshableObject) {
|
||||
((DBPRefreshableObject) dataSource).refreshObject(monitor);
|
||||
DBPDataSource dataSource = dbnDataSource.getDataSource();
|
||||
if (dataSource instanceof DBPRefreshableObject refreshableObject) {
|
||||
refreshableObject.refreshObject(monitor);
|
||||
}
|
||||
((DBNDataSource) node).cleanupNode();
|
||||
dbnDataSource.cleanupNode();
|
||||
} else if (node instanceof DBNLocalFolder) {
|
||||
// Refresh can't be applied to the local folder node
|
||||
return true;
|
||||
@@ -425,7 +426,7 @@ public class WebServiceNavigator implements DBWServiceNavigator {
|
||||
List<String> siblings = Arrays.stream(
|
||||
((DBNLocalFolder) node).getLogicalParent().getChildren(session.getProgressMonitor()))
|
||||
.filter(n -> n instanceof DBNLocalFolder)
|
||||
.map(DBNNode::getName).collect(Collectors.toList());
|
||||
.map(DBNNode::getName).toList();
|
||||
if (siblings.contains(newName)) {
|
||||
throw new DBWebException("Name " + newName + " is unavailable or invalid");
|
||||
}
|
||||
@@ -570,7 +571,7 @@ public class WebServiceNavigator implements DBWServiceNavigator {
|
||||
|
||||
private void checkProjectEditAccess(DBNNode node, WebSession session) throws DBException {
|
||||
BaseWebProjectImpl project = (BaseWebProjectImpl) node.getOwnerProject();
|
||||
if (project == null || !hasNodeEditPermission(session, node, project.getRmProject())) {
|
||||
if (project == null || !hasNodeEditPermission(session, node, project.getRMProject())) {
|
||||
throw new DBException("Access denied");
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user