Skip to content

Commit 9c1678c

Browse files
vkirstDariaMarkaryanmr-anton-tserge-rider
authored
dbeaver/pro#8824 Inject lock manager into CloudBeaver RM controllers (#4242)
* dbeaver/pro#8824 Inject lock manager into CloudBeaver RM controllers * dbeaver/pro#8824 Use application lock manager provider in servlet applications * dbeaver/pro#8824 Use default application lock manager * dbeaver/pro#8824 Fix codestyle warnings --------- Co-authored-by: Daria Markaryan <43252954+DariaMarkaryan@users.noreply.github.com> Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com> Co-authored-by: Serge Rider <serge@jkiss.org>
1 parent 321d45b commit 9c1678c

5 files changed

Lines changed: 89 additions & 46 deletions

File tree

server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/BaseServletApplication.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* DBeaver - Universal Database Manager
3-
* Copyright (C) 2010-2025 DBeaver Corp and others
3+
* Copyright (C) 2010-2026 DBeaver Corp and others
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -25,10 +25,13 @@
2525
import org.jkiss.dbeaver.DBException;
2626
import org.jkiss.dbeaver.Log;
2727
import org.jkiss.dbeaver.model.DBFileController;
28+
import org.jkiss.dbeaver.model.app.DBPLockManagerProvider;
2829
import org.jkiss.dbeaver.model.app.DBPWorkspace;
2930
import org.jkiss.dbeaver.model.auth.SMCredentialsProvider;
3031
import org.jkiss.dbeaver.model.auth.SMSessionContext;
3132
import org.jkiss.dbeaver.model.data.json.JSONUtils;
33+
import org.jkiss.dbeaver.model.fs.lock.LockManager;
34+
import org.jkiss.dbeaver.model.fs.lock.shared.SharedFileLockManager;
3235
import org.jkiss.dbeaver.model.impl.app.ApplicationRegistry;
3336
import org.jkiss.dbeaver.model.impl.app.BaseApplicationImpl;
3437
import org.jkiss.dbeaver.model.impl.app.BaseWorkspaceImpl;
@@ -48,7 +51,7 @@
4851
/**
4952
* Servlet application
5053
*/
51-
public abstract class BaseServletApplication extends BaseApplicationImpl implements ServletApplication {
54+
public abstract class BaseServletApplication extends BaseApplicationImpl implements ServletApplication, DBPLockManagerProvider {
5255

5356
public static final String DEFAULT_CONFIG_FILE_PATH = "/etc/cloudbeaver.conf";
5457
public static final String CUSTOM_CONFIG_FOLDER = "custom";
@@ -59,6 +62,7 @@ public abstract class BaseServletApplication extends BaseApplicationImpl impleme
5962

6063
private String instanceId;
6164

65+
@NotNull
6266
@Override
6367
public RMController createResourceController(
6468
@NotNull SMCredentialsProvider credentialsProvider,
@@ -73,6 +77,18 @@ public DBFileController createFileController(@NotNull SMCredentialsProvider cred
7377
throw new IllegalStateException("File controller is not supported by " + getClass().getSimpleName());
7478
}
7579

80+
@NotNull
81+
@Override
82+
public LockManager createLockManager(@NotNull Path metadataFolder) throws DBException {
83+
return new SharedFileLockManager(getApplicationInstanceId(), metadataFolder);
84+
}
85+
86+
@NotNull
87+
@Override
88+
public LockManager createLockManager() throws DBException {
89+
return new SharedFileLockManager(getApplicationInstanceId());
90+
}
91+
7692
@Nullable
7793
@Override
7894
public Path getDefaultWorkingFolder() {

server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/local/BaseLocalResourceController.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
2727
import org.jkiss.dbeaver.model.app.DBPProject;
2828
import org.jkiss.dbeaver.model.app.DBPWorkspace;
29-
import org.jkiss.dbeaver.model.fs.lock.FileLockController;
29+
import org.jkiss.dbeaver.model.fs.lock.LockManager;
30+
import org.jkiss.dbeaver.model.fs.lock.LockOptions;
31+
import org.jkiss.dbeaver.model.fs.lock.LockTarget;
3032
import org.jkiss.dbeaver.model.rm.RMController;
3133
import org.jkiss.dbeaver.model.rm.RMEvent;
3234
import org.jkiss.dbeaver.model.rm.RMEventManager;
@@ -53,11 +55,11 @@ public abstract class BaseLocalResourceController implements RMController {
5355
@NotNull
5456
protected final DBPWorkspace workspace;
5557
@NotNull
56-
protected final FileLockController lockController;
58+
protected final LockManager lockController;
5759

5860
protected BaseLocalResourceController(
5961
@NotNull DBPWorkspace workspace,
60-
@NotNull FileLockController lockController
62+
@NotNull LockManager lockController
6163
) {
6264
this.workspace = workspace;
6365
this.lockController = lockController;
@@ -157,7 +159,7 @@ protected DataSourceParseResults updateProjectDataSourcesConfig(
157159
@NotNull String configuration,
158160
@Nullable List<String> dataSourceIds
159161
) throws DBException {
160-
try (var ignoredLock = lockController.lock(projectId, "updateProjectDataSources")) {
162+
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("updateProjectDataSources"))) {
161163
DBPProject project = getWebProject(projectId, false);
162164
return doFileWriteOperation(
163165
projectId, project.getMetadataFolder(false),
@@ -188,7 +190,7 @@ public void deleteProjectDataSources(
188190
@NotNull String projectId,
189191
@NotNull String[] dataSourceIds
190192
) throws DBException {
191-
try (var ignoredLock = lockController.lock(projectId, "deleteDataSources")) {
193+
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("deleteDataSources"))) {
192194
DBPProject project = getWebProject(projectId, false);
193195
doFileWriteOperation(projectId, project.getMetadataFolder(false), () -> {
194196
DBPDataSourceRegistry registry = project.getDataSourceRegistry();
@@ -213,7 +215,7 @@ public void createProjectDataSourceFolder(
213215
@NotNull String projectId,
214216
@NotNull String folderPath
215217
) throws DBException {
216-
try (var ignoredLock = lockController.lock(projectId, "createDatasourceFolder")) {
218+
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("createDatasourceFolder"))) {
217219
DBPProject project = getWebProject(projectId, false);
218220
log.debug("Creating data source folder '" + folderPath + "' in project '" + projectId + "'");
219221
doFileWriteOperation(projectId, project.getMetadataFolder(false),
@@ -241,7 +243,7 @@ public void deleteProjectDataSourceFolders(
241243
@NotNull String[] folderPaths,
242244
boolean dropContents
243245
) throws DBException {
244-
try (var ignoredLock = lockController.lock(projectId, "createDatasourceFolder")) {
246+
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("createDatasourceFolder"))) {
245247
DBPProject project = getWebProject(projectId, false);
246248
doFileWriteOperation(projectId, project.getMetadataFolder(false),
247249
() -> {
@@ -267,7 +269,7 @@ public void moveProjectDataSourceFolder(
267269
@NotNull String oldPath,
268270
@NotNull String newPath
269271
) throws DBException {
270-
try (var ignoredLock = lockController.lock(projectId, "createDatasourceFolder")) {
272+
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("createDatasourceFolder"))) {
271273
DBPProject project = getWebProject(projectId, false);
272274
log.debug("Moving data source folder from '" + oldPath + "' to '" + newPath + "' in project '" + projectId + "'");
273275
doFileWriteOperation(projectId, project.getMetadataFolder(false),

server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/local/LocalResourceController.java

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* DBeaver - Universal Database Manager
3-
* Copyright (C) 2010-2025 DBeaver Corp and others
3+
* Copyright (C) 2010-2026 DBeaver Corp and others
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -33,7 +33,9 @@
3333
import org.jkiss.dbeaver.model.app.DBPWorkspace;
3434
import org.jkiss.dbeaver.model.auth.SMCredentials;
3535
import org.jkiss.dbeaver.model.auth.SMCredentialsProvider;
36-
import org.jkiss.dbeaver.model.fs.lock.FileLockController;
36+
import org.jkiss.dbeaver.model.fs.lock.LockManager;
37+
import org.jkiss.dbeaver.model.fs.lock.LockOptions;
38+
import org.jkiss.dbeaver.model.fs.lock.LockTarget;
3739
import org.jkiss.dbeaver.model.impl.app.BaseProjectImpl;
3840
import org.jkiss.dbeaver.model.impl.auth.SessionContextImpl;
3941
import org.jkiss.dbeaver.model.navigator.DBNLocalFolder;
@@ -90,9 +92,10 @@ public LocalResourceController(
9092
@NotNull Path rootPath,
9193
@NotNull Path userProjectsPath,
9294
@NotNull Path sharedProjectsPath,
93-
@NotNull Supplier<SMAdminController> smControllerSupplier
95+
@NotNull Supplier<SMAdminController> smControllerSupplier,
96+
@NotNull LockManager lockController
9497
) throws DBException {
95-
super(workspace, new FileLockController(ServletAppUtils.getServletApplication().getApplicationInstanceId()));
98+
super(workspace, lockController);
9699
this.credentialsProvider = credentialsProvider;
97100
this.rootPath = rootPath;
98101
this.userProjectsPath = userProjectsPath;
@@ -101,7 +104,7 @@ public LocalResourceController(
101104

102105
this.globalProjectName = DBWorkbench.getPlatform().getApplication().getDefaultProjectName();
103106
this.fileHandlers = RMFileOperationHandlersRegistry.getInstance().getFileHandlers();
104-
this.sharedProjectsMetadataInfo = new ProjectsMetadataInfo(sharedProjectsPath);
107+
this.sharedProjectsMetadataInfo = new ProjectsMetadataInfo(sharedProjectsPath, lockController);
105108
}
106109

107110
@NotNull
@@ -303,7 +306,7 @@ public RMProject createProject(@NotNull String name, @Nullable String descriptio
303306
@Override
304307
public RMProject updateProject(@NotNull String projectId, @NotNull RMProjectInfo projectInfo) throws DBException {
305308
validateProjectName(projectId, projectInfo.getName());
306-
try (var ignoredLock = lockController.lock(projectId, "updateProject")) {
309+
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("updateProject"))) {
307310
RMLocalProject project = getWebProject(projectId, false);
308311
Path targetPath = getProjectPath(projectId);
309312
if (!Files.exists(targetPath)) {
@@ -330,7 +333,7 @@ private void validateProjectName(@Nullable String projectId, @Nullable String na
330333

331334
@Override
332335
public void deleteProject(@NotNull String projectId) throws DBException {
333-
try (var ignoredLock = lockController.lock(projectId, "deleteProject")) {
336+
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("deleteProject"))) {
334337
Path targetPath = getProjectPath(projectId);
335338
if (!Files.exists(targetPath)) {
336339
log.error(MessageFormat.format("Project folder ''{0}'' is not found", projectId));
@@ -699,7 +702,7 @@ public String createResource(
699702
@NotNull String resourcePath,
700703
boolean isFolder
701704
) throws DBException {
702-
try (var ignoredLock = lockController.lock(projectId, "createResource")) {
705+
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("createResource"))) {
703706
validateResourcePath(resourcePath);
704707
Path targetPath = getTargetPath(projectId, resourcePath);
705708
if (Files.exists(targetPath)) {
@@ -731,7 +734,7 @@ public String moveResource(
731734
@NotNull String oldResourcePath,
732735
@NotNull String newResourcePath
733736
) throws DBException {
734-
try (var ignoredLock = lockController.lock(projectId, "moveResource")) {
737+
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("moveResource"))) {
735738
var normalizedOldResourcePath = CommonUtils.normalizeResourcePath(oldResourcePath);
736739
var normalizedNewResourcePath = CommonUtils.normalizeResourcePath(newResourcePath);
737740
if (log.isDebugEnabled()) {
@@ -803,7 +806,7 @@ private void movePropertiesRecursive(
803806

804807
@Override
805808
public void deleteResource(@NotNull String projectId, @NotNull String resourcePath, boolean recursive) throws DBException {
806-
try (var ignoredLock = lockController.lock(projectId, "deleteResource")) {
809+
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("deleteResource"))) {
807810
if (log.isDebugEnabled()) {
808811
log.debug("Removing resource from '" + resourcePath + "' in project '" + projectId + "'" + (recursive ? " recursive" : ""));
809812
}
@@ -891,7 +894,7 @@ public String setResourceContents(
891894
@NotNull byte[] data,
892895
boolean forceOverwrite
893896
) throws DBException {
894-
try (var ignoredLock = lockController.lock(projectId, "setResourceContents")) {
897+
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("setResourceContents"))) {
895898
validateResourcePath(resourcePath);
896899
Number fileSizeLimit = ServletAppUtils.getServletApplication()
897900
.getAppConfiguration()
@@ -936,7 +939,7 @@ public String setResourceProperty(
936939
@NotNull String propertyName,
937940
@Nullable Object propertyValue
938941
) throws DBException {
939-
try (var ignoredLock = lockController.lock(projectId, "resourcePropertyUpdate")) {
942+
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("resourcePropertyUpdate"))) {
940943
validateResourcePath(resourcePath);
941944
RMLocalProject webProject = getWebProject(projectId, false);
942945
doFileWriteOperation(projectId, webProject.getMetadataFilePath(),
@@ -957,7 +960,7 @@ public String setResourceProperties(
957960
@NotNull String resourcePath,
958961
@NotNull Map<String, Object> properties
959962
) throws DBException {
960-
try (var ignoredLock = lockController.lock(projectId, "resourcePropertyUpdate")) {
963+
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("resourcePropertyUpdate"))) {
961964
validateResourcePath(resourcePath);
962965
RMLocalProject webProject = getWebProject(projectId, false);
963966
doFileWriteOperation(projectId, webProject.getMetadataFilePath(),
@@ -1204,12 +1207,14 @@ private String getProjectRelativePath(@NotNull String projectId, @NotNull Path p
12041207
return getProjectPath(projectId).toAbsolutePath().relativize(path).toString().replace('\\', IPath.SEPARATOR);
12051208
}
12061209

1210+
@NotNull
12071211
public static Builder builder(
1208-
SMCredentialsProvider credentialsProvider,
1209-
DBPWorkspace workspace,
1210-
Supplier<SMAdminController> smControllerSupplier
1212+
@NotNull SMCredentialsProvider credentialsProvider,
1213+
@NotNull DBPWorkspace workspace,
1214+
@NotNull LockManager lockController,
1215+
@NotNull Supplier<SMAdminController> smControllerSupplier
12111216
) {
1212-
return new Builder(workspace, credentialsProvider, smControllerSupplier);
1217+
return new Builder(workspace, credentialsProvider, lockController, smControllerSupplier);
12131218
}
12141219

12151220
@Override
@@ -1225,36 +1230,52 @@ public static class Builder {
12251230
protected Path rootPath;
12261231
protected Path userProjectsPath;
12271232
protected Path sharedProjectsPath;
1233+
protected LockManager lockController;
12281234

12291235
protected Builder(
1230-
DBPWorkspace workspace, SMCredentialsProvider credentialsProvider,
1231-
Supplier<SMAdminController> smControllerSupplier
1236+
@NotNull DBPWorkspace workspace,
1237+
@NotNull SMCredentialsProvider credentialsProvider,
1238+
@NotNull LockManager lockController,
1239+
@NotNull Supplier<SMAdminController> smControllerSupplier
12321240
) {
12331241
this.workspace = workspace;
12341242
this.credentialsProvider = credentialsProvider;
12351243
this.smController = smControllerSupplier;
12361244
this.rootPath = RMUtils.getRootPath();
12371245
this.userProjectsPath = RMUtils.getUserProjectsPath();
12381246
this.sharedProjectsPath = RMUtils.getSharedProjectsPath();
1247+
this.lockController = lockController;
12391248
}
12401249

1241-
public Builder setRootPath(Path rootPath) {
1250+
@NotNull
1251+
public Builder setRootPath(@NotNull Path rootPath) {
12421252
this.rootPath = rootPath;
12431253
return this;
12441254
}
12451255

1246-
public Builder setUserProjectsPath(Path userProjectsPath) {
1256+
@NotNull
1257+
public Builder setUserProjectsPath(@NotNull Path userProjectsPath) {
12471258
this.userProjectsPath = userProjectsPath;
12481259
return this;
12491260
}
12501261

1251-
public Builder setSharedProjectsPath(Path sharedProjectsPath) {
1262+
@NotNull
1263+
public Builder setSharedProjectsPath(@NotNull Path sharedProjectsPath) {
12521264
this.sharedProjectsPath = sharedProjectsPath;
12531265
return this;
12541266
}
12551267

1268+
@NotNull
12561269
public LocalResourceController build() throws DBException {
1257-
return new LocalResourceController(workspace, credentialsProvider, rootPath, userProjectsPath, sharedProjectsPath, smController);
1270+
return new LocalResourceController(
1271+
workspace,
1272+
credentialsProvider,
1273+
rootPath,
1274+
userProjectsPath,
1275+
sharedProjectsPath,
1276+
smController,
1277+
lockController
1278+
);
12581279
}
12591280
}
12601281

server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/local/ProjectsMetadataInfo.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@
1717
package io.cloudbeaver.model.rm.local;
1818

1919
import com.google.gson.reflect.TypeToken;
20-
import io.cloudbeaver.utils.ServletAppUtils;
2120
import org.jkiss.code.NotNull;
2221
import org.jkiss.code.Nullable;
2322
import org.jkiss.dbeaver.DBException;
2423
import org.jkiss.dbeaver.Log;
2524
import org.jkiss.dbeaver.model.app.DBPProject;
2625
import org.jkiss.dbeaver.model.data.json.JSONUtils;
27-
import org.jkiss.dbeaver.model.fs.lock.FileLockController;
26+
import org.jkiss.dbeaver.model.fs.lock.LockManager;
27+
import org.jkiss.dbeaver.model.fs.lock.LockOptions;
28+
import org.jkiss.dbeaver.model.fs.lock.LockTarget;
2829
import org.jkiss.dbeaver.model.impl.app.BaseProjectImpl;
2930
import org.jkiss.dbeaver.model.rm.RMProjectInfo;
3031
import org.jkiss.dbeaver.model.rm.RMProjectType;
@@ -45,12 +46,12 @@ public class ProjectsMetadataInfo {
4546

4647
private final Map<String, RMProjectInfo> projectsInfo = new LinkedHashMap<>();
4748
private final Path projectsPath;
48-
private final FileLockController lockController;
49+
private final LockManager lockController;
4950

5051

51-
public ProjectsMetadataInfo(@NotNull Path projectsPath) throws DBException {
52+
public ProjectsMetadataInfo(@NotNull Path projectsPath, @NotNull LockManager lockController) throws DBException {
5253
this.projectsPath = projectsPath;
53-
this.lockController = new FileLockController(ServletAppUtils.getServletApplication().getApplicationInstanceId());
54+
this.lockController = lockController;
5455
readProjectInfos(projectsPath);
5556
}
5657

@@ -139,7 +140,7 @@ private RMProjectInfo getProjectInfoFromProjectSettings(@NotNull Path projectPat
139140
}
140141

141142
private void saveProjectsInfo() {
142-
try (var lock = lockController.lock(PROJECTS_INFO_FILE_NAME, "saveProjectsInfo")) {
143+
try (var lock = lockController.lock(LockTarget.of(PROJECTS_INFO_FILE_NAME), LockOptions.of("saveProjectsInfo"))) {
143144
log.info("Saving project information");
144145
Files.writeString(projectsPath.resolve(PROJECTS_INFO_FILE_NAME), JSONUtils.GSON.toJson(projectsInfo));
145146
} catch (IOException e) {
@@ -148,4 +149,4 @@ private void saveProjectsInfo() {
148149
log.error("Error locking file " + PROJECTS_INFO_FILE_NAME + ": " + e.getMessage());
149150
}
150151
}
151-
}
152+
}

server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/server/CBApplicationCE.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* DBeaver - Universal Database Manager
3-
* Copyright (C) 2010-2024 DBeaver Corp and others
3+
* Copyright (C) 2010-2026 DBeaver Corp and others
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -75,13 +75,16 @@ protected SMAdminController createGlobalSecurityController() throws DBException
7575
);
7676
}
7777

78-
79-
8078
@NotNull
8179
@Override
82-
public RMController createResourceController(@NotNull SMCredentialsProvider credentialsProvider,
83-
@NotNull DBPWorkspace workspace) throws DBException {
84-
return LocalResourceController.builder(credentialsProvider, workspace, this::getSecurityController).build();
80+
public RMController createResourceController(
81+
@NotNull SMCredentialsProvider credentialsProvider,
82+
@NotNull DBPWorkspace workspace
83+
) throws DBException {
84+
var lockManager = createLockManager();
85+
return LocalResourceController
86+
.builder(credentialsProvider, workspace, lockManager, this::getSecurityController)
87+
.build();
8588
}
8689

8790
@NotNull

0 commit comments

Comments
 (0)