Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
package io.cloudbeaver.model.rm.local;

import com.google.gson.reflect.TypeToken;
import io.cloudbeaver.DBWConstants;
import io.cloudbeaver.model.app.ServletApplication;
import io.cloudbeaver.service.security.SMUtils;
Expand All @@ -30,9 +31,11 @@
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.auth.SMCredentials;
import org.jkiss.dbeaver.model.auth.SMCredentialsProvider;
import org.jkiss.dbeaver.model.data.json.JSONUtils;
import org.jkiss.dbeaver.model.fs.lock.FileLockController;
import org.jkiss.dbeaver.model.impl.app.BaseProjectImpl;
import org.jkiss.dbeaver.model.impl.auth.SessionContextImpl;
Expand All @@ -56,6 +59,7 @@
import org.jkiss.utils.Pair;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.text.MessageFormat;
import java.time.OffsetDateTime;
Expand All @@ -71,6 +75,7 @@
public class LocalResourceController extends BaseLocalResourceController {

private static final Log log = Log.getLog(LocalResourceController.class);
private static final String PROJECTS_INFO_FILE_NAME = "projects-info.json";

protected final SMCredentialsProvider credentialsProvider;

Expand All @@ -82,6 +87,7 @@ public class LocalResourceController extends BaseLocalResourceController {
protected final List<RMFileOperationHandler> fileHandlers;

private final Map<String, RMLocalProject> projectRegistries = new LinkedHashMap<>();
private final Map<String, RMProjectInfo> sharedProjectsInfo = new LinkedHashMap<>();

public LocalResourceController(
DBPWorkspace workspace,
Expand All @@ -100,6 +106,78 @@ public LocalResourceController(

this.globalProjectName = DBWorkbench.getPlatform().getApplication().getDefaultProjectName();
this.fileHandlers = RMFileOperationHandlersRegistry.getInstance().getFileHandlers();
readProjectInfos(sharedProjectsPath);
}

private void readProjectInfos(@NotNull Path sharedProjectsPath) {
if (!Files.exists(sharedProjectsPath)) {
return;
}

if (Files.exists(sharedProjectsPath.resolve(PROJECTS_INFO_FILE_NAME))) {
try {
log.info("Reading shared project information");
String content = Files.readString(sharedProjectsPath.resolve(PROJECTS_INFO_FILE_NAME), StandardCharsets.UTF_8);
Map<String, RMProjectInfo> loaded = JSONUtils.GSON.fromJson(
content,
TypeToken.getParameterized(Map.class, String.class, RMProjectInfo.class).getType()
);
sharedProjectsInfo.clear();
if (loaded != null) {
sharedProjectsInfo.putAll(loaded);
}
} catch (IOException e) {
log.error("Error reading existing " + PROJECTS_INFO_FILE_NAME, e);
}
return;
}

createProjectInfosFile(sharedProjectsPath);
}

private void createProjectInfosFile(@NotNull Path sharedProjectsPath) {
log.info("Migrating shared project information to the common place");
Map<String, RMProjectInfo> infos = new LinkedHashMap<>();
try (Stream<Path> stream = Files.list(sharedProjectsPath)) {
stream.filter(Files::isDirectory).forEach(projectDir -> {
String name = null;
String description = null;

Path settings = projectDir.resolve(DBPProject.METADATA_FOLDER).resolve(BaseProjectImpl.SETTINGS_STORAGE_FILE);
if (Files.exists(settings) && Files.isRegularFile(settings)) {
try {
String json = Files.readString(settings, StandardCharsets.UTF_8);
Map<String, Object> map = JSONUtils.GSON.fromJson(json, JSONUtils.MAP_TYPE_TOKEN);
name = JSONUtils.getString(map, BaseProjectImpl.PROP_PROJECT_NAME);
description = JSONUtils.getString(map, BaseProjectImpl.PROP_PROJECT_DESCRIPTION);
} catch (IOException e) {
log.warn("Failed to read project settings for " + projectDir + ": " + e.getMessage());
} catch (Exception e) {
log.warn("Failed to parse project settings for " + projectDir + ": " + e.getMessage());
}
}
RMProjectInfo info = new RMProjectInfo();
info.setName(CommonUtils.isEmpty(name) ? projectDir.getFileName().toString() : name);
info.setDescription(description);
String projectId = RMUtils.makeProjectIdFromPath(projectDir, RMProjectType.SHARED);
infos.put(projectId, info);
});
} catch (IOException e) {
log.error("Error listing shared projects path", e);
}
log.info("Migration for project information completed");
sharedProjectsInfo.clear();
sharedProjectsInfo.putAll(infos);
saveProjectsInfo();
}

private void saveProjectsInfo() {
try {
log.info("Saving shared project information");
Files.writeString(sharedProjectsPath.resolve(PROJECTS_INFO_FILE_NAME), JSONUtils.GSON.toJson(sharedProjectsInfo));
} catch (IOException e) {
log.error("Error writing " + PROJECTS_INFO_FILE_NAME, e);
}
}

protected SMController getSecurityController() {
Expand All @@ -121,6 +199,9 @@ protected RMLocalProject getWebProject(String projectId, boolean refresh) throws
RMLocalProject project = projectRegistries.get(projectId);
if (project == null || refresh) {
project = createWebProjectImpl(projectId, new SessionContextImpl(null));
if (RMProjectType.SHARED.equals(project.getProjectType())) {
project.setProjectInfo(getProjectInfoIfNeeded(projectId));
}
projectRegistries.put(projectId, project);
}
return project;
Expand All @@ -135,6 +216,11 @@ protected RMLocalProject createWebProjectImpl(
return new RMLocalProject(workspace, sessionContext, getProjectPath(projectId), WebRMUtils.parseProjectName(projectId).getType());
}

@NotNull
private RMProjectInfo getProjectInfoIfNeeded(@NotNull String projectId) {
return sharedProjectsInfo.computeIfAbsent(projectId, key -> new RMProjectInfo());
}

@NotNull
@Override
public RMProject[] listAccessibleProjects() throws DBException {
Expand Down Expand Up @@ -312,6 +398,8 @@ public RMProject updateProject(@NotNull String projectId, @NotNull RMProjectInfo
throw new DBException("Project '" + projectId + "' is not shared");
}
project.updateProject(projectInfo.getName(), projectInfo.getDescription());
sharedProjectsInfo.put(projectId, projectInfo);
saveProjectsInfo();
return WebRMUtils.createRmProjectFromWebProject(project);
}
}
Expand Down Expand Up @@ -993,6 +1081,9 @@ private RMProject makeProjectFromPath(Path path, Set<RMProjectPermission> permis
.toArray(String[]::new);

RMLocalProject webProject = new RMLocalProject(workspace, new SessionContextImpl(null), path, type);
if (type == RMProjectType.SHARED) {
webProject.setProjectInfo(getProjectInfoIfNeeded(webProject.getId()));
}
return createRmProjectFromWebProject(path, webProject, allProjectPermissions);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@

import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.auth.SMSessionContext;
import org.jkiss.dbeaver.model.rm.RMProjectInfo;
import org.jkiss.dbeaver.model.rm.RMProjectType;
import org.jkiss.dbeaver.model.rm.RMUtils;
import org.jkiss.dbeaver.registry.project.LocalProjectImpl;
Expand All @@ -29,6 +31,8 @@
public class RMLocalProject extends LocalProjectImpl {
@NotNull
private final RMProjectType projectType;
@Nullable
private RMProjectInfo projectInfo;

public RMLocalProject(
@NotNull DBPWorkspace workspace,
Expand All @@ -51,6 +55,39 @@ public String getId() {
return RMUtils.makeProjectIdFromPath(projectPath, projectType);
}

@Nullable
@Override
public String getDescription() {
if (projectInfo == null) {
return null;
}
return projectInfo.getDescription();
}

@NotNull
@Override
public String getName() {
if (projectInfo == null || projectInfo.getName() == null) {
return projectPath.getFileName().toString();
}
return projectInfo.getName();
}

@NotNull
public RMProjectType getProjectType() {
return projectType;
}

@Override
public void updateProject(@Nullable String newName, @Nullable String description) throws DBException {
this.projectInfo = new RMProjectInfo();
projectInfo.setName(newName);
projectInfo.setDescription(description);
}

public void setProjectInfo(@NotNull RMProjectInfo projectInfo) {
this.projectInfo = projectInfo;
}

public boolean canUpdateProjectName() {
return RMProjectType.SHARED.equals(projectType);
Expand Down
Loading