diff --git a/server/bundles/graphql.config.yml b/server/bundles/graphql.config.yml new file mode 100644 index 0000000000..9dd806b67e --- /dev/null +++ b/server/bundles/graphql.config.yml @@ -0,0 +1,9 @@ +projects: + schema: + include: ./**/*.graphqls +schema: "gql.ce" +extensions: + endpoints: + Default GraphQL Endpoint: + url: http://localhost:8080/api/gql + introspect: false diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMNIOResourceFileStore.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMNIOResourceFileStore.java deleted file mode 100644 index a4bc1d4c5c..0000000000 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMNIOResourceFileStore.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2023 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.rm.fs.nio; - -import org.jkiss.dbeaver.model.nio.NIOFileStore; -import org.jkiss.dbeaver.model.rm.RMResource; - -import java.io.IOException; - -public class RMNIOResourceFileStore extends NIOFileStore { - private final RMResource rmResource; - - public RMNIOResourceFileStore(RMResource rmResource) { - this.rmResource = rmResource; - } - - @Override - public String name() { - return rmResource.getName(); - } - - @Override - public String type() { - return "rmfs"; - } - - @Override - public boolean isReadOnly() { - return false; - } - - @Override - public long getTotalSpace() throws IOException { - return rmResource.getLength(); - } -} diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java index 35e5827198..3dbe3c3b6e 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java @@ -51,6 +51,7 @@ 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; +import org.jkiss.dbeaver.model.fs.DBFFileSystemManager; import org.jkiss.dbeaver.model.meta.Association; import org.jkiss.dbeaver.model.meta.Property; import org.jkiss.dbeaver.model.navigator.DBNModel; @@ -76,15 +77,15 @@ import org.jkiss.dbeaver.runtime.DBWorkbench; import org.jkiss.dbeaver.runtime.jobs.DisconnectJob; import org.jkiss.utils.CommonUtils; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; import java.lang.reflect.InvocationTargetException; import java.time.Instant; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; /** * Web session. @@ -617,7 +618,6 @@ public class WebSession extends BaseWebSession log.error("Error closing web session tokens"); } this.userContext.setUser(null); - super.close(); } @@ -901,7 +901,11 @@ public class WebSession extends BaseWebSession // Auth credentials provider // Adds auth properties passed from web (by user) @Override - public boolean provideAuthParameters(@NotNull DBRProgressMonitor monitor, @NotNull DBPDataSourceContainer dataSourceContainer, @NotNull DBPConnectionConfiguration configuration) { + public boolean provideAuthParameters( + @NotNull DBRProgressMonitor monitor, + @NotNull DBPDataSourceContainer dataSourceContainer, + @NotNull DBPConnectionConfiguration configuration + ) { try { // Properties from nested auth sessions for (DBACredentialsProvider contextCredentialsProvider : getContextCredentialsProviders()) { @@ -1019,6 +1023,9 @@ public class WebSession extends BaseWebSession } public void deleteSessionProject(@Nullable WebProjectImpl project) { + if (project != null) { + project.dispose(); + } getWorkspace().removeProject(project); if (navigatorModel != null) { navigatorModel.getRoot().removeProject(project); @@ -1046,6 +1053,15 @@ public class WebSession extends BaseWebSession } } + @NotNull + public DBFFileSystemManager getFileSystemManager(String projectId) throws DBException { + var project = getProjectById(projectId); + if (project == null) { + throw new DBException("Project not found: " + projectId); + } + return project.getFileSystemManager(); + } + private class SessionProgressMonitor extends BaseProgressMonitor { @Override public void beginTask(String name, int totalWork) { diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebUserContext.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebUserContext.java index 36b70e0b8a..21725e7ef7 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebUserContext.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebUserContext.java @@ -115,11 +115,7 @@ public class WebUserContext implements SMCredentialsProvider { ); setRefreshToken(smRefreshToken); setUserPermissions(smAuthPermissions.getPermissions()); - this.securityController = application.createSecurityController(this); this.adminSecurityController = application.getAdminSecurityController(this); - this.secretController = application.getSecretController(this); - this.rmController = application.createResourceController(this, workspace); - this.fileController = application.createFileController(this); if (isSessionChanged) { this.smSessionId = smAuthPermissions.getSessionId(); setUser(smAuthPermissions.getUserId() == null ? null : new WebUser(securityController.getCurrentUser())); diff --git a/server/bundles/io.cloudbeaver.server/schema/schema.graphqls b/server/bundles/io.cloudbeaver.server/schema/schema.graphqls index 873430e94e..afffe35fef 100644 --- a/server/bundles/io.cloudbeaver.server/schema/schema.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/schema.graphqls @@ -8,6 +8,8 @@ input PageInput { offset: Int } +directive @since(version: String!) on OBJECT|SCALAR|QUERY|MUTATION|FIELD|VARIABLE_DEFINITION|OBJECT|FIELD_DEFINITION|ARGUMENT_DEFINITION|INTERFACE|ENUM|ENUM_VALUE|INPUT_OBJECT|INPUT_FIELD_DEFINITION + type Query type Mutation diff --git a/server/bundles/io.cloudbeaver.service.fs/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.fs/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..dcf8f1c8d1 --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.fs/META-INF/MANIFEST.MF @@ -0,0 +1,13 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Vendor: DBeaver Corp +Bundle-Name: Cloudbeaver Web Service - File System +Bundle-SymbolicName: io.cloudbeaver.service.fs;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Release-Date: 20230904 +Bundle-RequiredExecutionEnvironment: JavaSE-11 +Bundle-ActivationPolicy: lazy +Bundle-ClassPath: . +Require-Bundle: io.cloudbeaver.server, + io.cloudbeaver.service.admin +Automatic-Module-Name: io.cloudbeaver.service.fs diff --git a/server/bundles/io.cloudbeaver.service.fs/build.properties b/server/bundles/io.cloudbeaver.service.fs/build.properties new file mode 100644 index 0000000000..06be359875 --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.fs/build.properties @@ -0,0 +1,6 @@ +source.. = src/ +output.. = target/classes/ +bin.includes = .,\ + META-INF/,\ + schema/,\ + plugin.xml diff --git a/server/bundles/io.cloudbeaver.service.fs/plugin.xml b/server/bundles/io.cloudbeaver.service.fs/plugin.xml new file mode 100644 index 0000000000..45540f23a6 --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.fs/plugin.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/server/bundles/io.cloudbeaver.service.fs/pom.xml b/server/bundles/io.cloudbeaver.service.fs/pom.xml new file mode 100644 index 0000000000..67e34d889a --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.fs/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + + io.cloudbeaver + bundles + 1.0.0-SNAPSHOT + ../ + + io.cloudbeaver.service.fs + 1.0.0-SNAPSHOT + eclipse-plugin + + diff --git a/server/bundles/io.cloudbeaver.service.fs/schema/service.fs.graphqls b/server/bundles/io.cloudbeaver.service.fs/schema/service.fs.graphqls new file mode 100644 index 0000000000..558d088c43 --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.fs/schema/service.fs.graphqls @@ -0,0 +1,34 @@ +type FSFile @since(version: "23.2.2") { + name: String! + length: Int! + folder: Boolean! + metaData: Object! +} + +extend type Query @since(version: "23.2.2") { + fsListFileSystems(projectId: ID!): [String!]! + + fsFile(projectId: ID!, fileURI: String!): FSFile! + + fsListFiles(projectId: ID!, folderURI: String!): [FSFile!]! + + # Reads file contents as string in UTF-8 + fsReadFileContentAsString(projectId: ID!, fileURI: String!): String! +} + +extend type Mutation @since(version: "23.2.2") { + fsCreateFile(projectId: ID!, fileURI:String!): FSFile! + + fsCreateFolder(projectId: ID!, folderURI:String!): FSFile! + + fsDeleteFile(projectId: ID!, fileURI:String!): Boolean! + + fsMoveFile(projectId: ID!, fromURI: String!, toURI: String!): FSFile! + + fsWriteFileStringContent( + projectId: ID!, + fileURI:String!, + data: String!, + forceOverwrite: Boolean! + ): Boolean! +} \ No newline at end of file diff --git a/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/DBWServiceFS.java b/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/DBWServiceFS.java new file mode 100644 index 0000000000..fefd6d1a09 --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/DBWServiceFS.java @@ -0,0 +1,90 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2023 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.fs; + +import io.cloudbeaver.DBWebException; +import io.cloudbeaver.model.session.WebSession; +import io.cloudbeaver.service.DBWService; +import io.cloudbeaver.service.fs.model.FSFile; +import org.jkiss.code.NotNull; + +import java.net.URI; + +/** + * Web service API + */ +public interface DBWServiceFS extends DBWService { + @NotNull + String[] getAvailableFileSystems(@NotNull WebSession webSession, @NotNull String projectId) throws DBWebException; + + @NotNull + FSFile getFile( + @NotNull WebSession webSession, + @NotNull String projectId, + @NotNull URI fileURI + ) throws DBWebException; + + @NotNull + FSFile[] getFiles( + @NotNull WebSession webSession, + @NotNull String projectId, + @NotNull URI folderURI + ) throws DBWebException; + + @NotNull + String readFileContent( + @NotNull WebSession webSession, + @NotNull String projectId, + @NotNull URI fileURI + ) throws DBWebException; + + boolean writeFileContent( + @NotNull WebSession webSession, + @NotNull String projectId, + @NotNull URI fileURI, + @NotNull String data, + boolean forceOverwrite + ) throws DBWebException; + + @NotNull + FSFile createFile( + @NotNull WebSession webSession, + @NotNull String projectId, + @NotNull URI fileURI + ) throws DBWebException; + + FSFile moveFile( + @NotNull WebSession webSession, + @NotNull String projectId, + @NotNull URI fromURI, + @NotNull URI toURI + ) throws DBWebException; + + @NotNull + FSFile createFolder( + @NotNull WebSession webSession, + @NotNull String projectId, + @NotNull URI folderURI + ) throws DBWebException; + + boolean deleteFile( + @NotNull WebSession webSession, + @NotNull String projectId, + @NotNull URI fileURI + ) throws DBWebException; + +} diff --git a/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/WebServiceBindingFS.java b/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/WebServiceBindingFS.java new file mode 100644 index 0000000000..4e0d92f056 --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/WebServiceBindingFS.java @@ -0,0 +1,91 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2023 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.fs; + +import io.cloudbeaver.DBWebException; +import io.cloudbeaver.service.DBWBindingContext; +import io.cloudbeaver.service.WebServiceBindingBase; +import io.cloudbeaver.service.fs.impl.WebServiceFS; +import org.jkiss.utils.CommonUtils; + +/** + * Web service implementation + */ +public class WebServiceBindingFS extends WebServiceBindingBase { + + private static final String SCHEMA_FILE_NAME = "schema/service.fs.graphqls"; + + public WebServiceBindingFS() { + super(DBWServiceFS.class, new WebServiceFS(), SCHEMA_FILE_NAME); + } + + @Override + public void bindWiring(DBWBindingContext model) throws DBWebException { + model.getQueryType() + .dataFetcher("fsListFileSystems", + env -> getService(env).getAvailableFileSystems(getWebSession(env), env.getArgument("projectId"))) + .dataFetcher("fsFile", + env -> getService(env).getFile(getWebSession(env), + env.getArgument("projectId"), + env.getArgument("fileURI")) + ) + .dataFetcher("fsListFiles", + env -> getService(env).getFiles(getWebSession(env), + env.getArgument("projectId"), + env.getArgument("folderURI")) + ) + .dataFetcher("fsReadFileContentAsString", + env -> getService(env).readFileContent(getWebSession(env), + env.getArgument("projectId"), + env.getArgument("fileURI")) + ) + ; + model.getMutationType() + .dataFetcher("fsCreateFile", + env -> getService(env).createFile(getWebSession(env), + env.getArgument("projectId"), + env.getArgument("fileURI")) + ) + .dataFetcher("fsCreateFolder", + env -> getService(env).createFolder(getWebSession(env), + env.getArgument("projectId"), + env.getArgument("folderURI")) + ) + .dataFetcher("fsDeleteFile", + env -> getService(env).deleteFile(getWebSession(env), + env.getArgument("projectId"), + env.getArgument("fileURI")) + ) + .dataFetcher("fsMoveFile", + env -> getService(env).moveFile( + getWebSession(env), + env.getArgument("projectId"), + env.getArgument("fromURI"), + env.getArgument("toURI")) + ) + .dataFetcher("fsWriteFileStringContent", + env -> getService(env).writeFileContent( + getWebSession(env), + env.getArgument("projectId"), + env.getArgument("fileURI"), + env.getArgument("data"), + CommonUtils.toBoolean(env.getArgument("forceOverwrite")) + ) + ) + ; + } +} diff --git a/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/impl/WebServiceFS.java b/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/impl/WebServiceFS.java new file mode 100644 index 0000000000..2acfa3e0c4 --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/impl/WebServiceFS.java @@ -0,0 +1,174 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2023 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.fs.impl; + +import io.cloudbeaver.DBWebException; +import io.cloudbeaver.model.session.WebSession; +import io.cloudbeaver.service.fs.DBWServiceFS; +import io.cloudbeaver.service.fs.model.FSFile; +import org.jkiss.code.NotNull; +import org.jkiss.dbeaver.DBException; +import org.jkiss.dbeaver.model.fs.DBFVirtualFileSystem; + +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * Web file system implementation + */ +public class WebServiceFS implements DBWServiceFS { + + @NotNull + @Override + public String[] getAvailableFileSystems(@NotNull WebSession webSession, @NotNull String projectId) + throws DBWebException { + try { + return webSession.getFileSystemManager(projectId) + .getVirtualFileSystems() + .stream() + .map(DBFVirtualFileSystem::getType) + .toArray(String[]::new); + } catch (Exception e) { + throw new DBWebException("Failed to load file systems: " + e.getMessage(), e); + } + } + + @NotNull + @Override + public FSFile getFile(@NotNull WebSession webSession, @NotNull String projectId, @NotNull URI fileUri) + throws DBWebException { + try { + Path filePath = webSession.getFileSystemManager(projectId).of(webSession.getProgressMonitor(), fileUri); + return new FSFile(filePath); + } catch (Exception e) { + throw new DBWebException("Failed to found file: " + e.getMessage(), e); + } + } + + @NotNull + @Override + public FSFile[] getFiles(@NotNull WebSession webSession, @NotNull String projectId, @NotNull URI folderURI) + throws DBWebException { + try { + Path folderPath = webSession.getFileSystemManager(projectId).of(webSession.getProgressMonitor(), folderURI); + try (var filesStream = Files.list(folderPath)) { + return filesStream.map(FSFile::new) + .toArray(FSFile[]::new); + } + } catch (Exception e) { + throw new DBWebException("Failed to list files: " + e.getMessage(), e); + } + } + + @NotNull + @Override + public String readFileContent(@NotNull WebSession webSession, @NotNull String projectId, @NotNull URI fileUri) + throws DBWebException { + try { + Path filePath = webSession.getFileSystemManager(projectId).of(webSession.getProgressMonitor(), fileUri); + return Files.readString(filePath); + } catch (Exception e) { + throw new DBWebException("Failed to read file content: " + e.getMessage(), e); + } + } + + @Override + public boolean writeFileContent( + @NotNull WebSession webSession, + @NotNull String projectId, + @NotNull URI fileURI, + @NotNull String data, + boolean forceOverwrite + ) + throws DBWebException { + try { + Path filePath = webSession.getFileSystemManager(projectId).of(webSession.getProgressMonitor(), fileURI); + if (!forceOverwrite && Files.exists(filePath)) { + throw new DBException("Cannot overwrite exist file"); + } + Files.writeString(filePath, data); + return true; + } catch (Exception e) { + throw new DBWebException("Failed to write file content: " + e.getMessage(), e); + } + } + + @NotNull + @Override + public FSFile createFile( + @NotNull WebSession webSession, + @NotNull String projectId, + @NotNull URI fileUri + ) throws DBWebException { + try { + Path filePath = webSession.getFileSystemManager(projectId).of(webSession.getProgressMonitor(), fileUri); + Files.createFile(filePath); + return new FSFile(filePath); + } catch (Exception e) { + throw new DBWebException("Failed to create file: " + e.getMessage(), e); + } + } + + @Override + public FSFile moveFile( + @NotNull WebSession webSession, + @NotNull String projectId, + @NotNull URI fromURI, + @NotNull URI toURI + ) throws DBWebException { + try { + Path from = webSession.getFileSystemManager(projectId).of(webSession.getProgressMonitor(), fromURI); + Path to = webSession.getFileSystemManager(projectId).of(webSession.getProgressMonitor(), toURI); + Files.move(from, to); + return new FSFile(to); + } catch (Exception e) { + throw new DBWebException("Failed to move file: " + e.getMessage(), e); + } + } + + @NotNull + @Override + public FSFile createFolder( + @NotNull WebSession webSession, + @NotNull String projectId, + @NotNull URI folderURI + ) throws DBWebException { + try { + Path folderPath = webSession.getFileSystemManager(projectId).of(webSession.getProgressMonitor(), folderURI); + Files.createDirectory(folderPath); + return new FSFile(folderPath); + } catch (Exception e) { + throw new DBWebException("Failed to create folder: " + e.getMessage(), e); + } + } + + @Override + public boolean deleteFile( + @NotNull WebSession webSession, + @NotNull String projectId, + @NotNull URI fileUri + ) throws DBWebException { + try { + Path filePath = webSession.getFileSystemManager(projectId).of(webSession.getProgressMonitor(), fileUri); + Files.delete(filePath); + return true; + } catch (Exception e) { + throw new DBWebException("Failed to create folder: " + e.getMessage(), e); + } + } +} diff --git a/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/model/FSFile.java b/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/model/FSFile.java new file mode 100644 index 0000000000..757a956f52 --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/model/FSFile.java @@ -0,0 +1,59 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2023 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.fs.model; + +import org.jkiss.dbeaver.model.meta.Property; +import org.jkiss.utils.ArrayUtils; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; + +public class FSFile { + private final Path path; + + public FSFile(Path path) { + this.path = path; + } + + @Property + public String getName() { + String[] pathParts = path.getFileName().toString().split(path.getFileSystem().getSeparator()); + if (ArrayUtils.isEmpty(pathParts)) { + return ""; + } + return pathParts[pathParts.length - 1]; + } + + @Property + + public long getLength() throws IOException { + return Files.size(path); + } + + @Property + + public boolean isFolder() { + return Files.isDirectory(path); + } + + @Property + public Map getMetaData() { + return Map.of(); + } +} diff --git a/server/bundles/io.cloudbeaver.service.rm.nio/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.rm.nio/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..25d8f12537 --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.rm.nio/META-INF/MANIFEST.MF @@ -0,0 +1,16 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Vendor: DBeaver Corp +Bundle-Name: Cloudbeaver Resource manager NIO implementation +Bundle-SymbolicName: io.cloudbeaver.service.rm.nio;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Release-Date: 20230927 +Bundle-RequiredExecutionEnvironment: JavaSE-11 +Bundle-ActivationPolicy: lazy +Bundle-ClassPath: . +Require-Bundle: io.cloudbeaver.model, + org.jkiss.dbeaver.model, + org.jkiss.dbeaver.model.nio +Export-Package: io.cloudbeaver.service.rm.nio, + io.cloudbeaver.service.rm.fs +Automatic-Module-Name: io.cloudbeaver.service.rm.nio diff --git a/server/bundles/io.cloudbeaver.service.rm.nio/build.properties b/server/bundles/io.cloudbeaver.service.rm.nio/build.properties new file mode 100644 index 0000000000..0511fdeb94 --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.rm.nio/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = target/classes/ +bin.includes = .,\ + META-INF/,\ + plugin.xml diff --git a/server/bundles/io.cloudbeaver.service.rm.nio/plugin.xml b/server/bundles/io.cloudbeaver.service.rm.nio/plugin.xml new file mode 100644 index 0000000000..d6694efc2c --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.rm.nio/plugin.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/server/bundles/io.cloudbeaver.service.rm.nio/pom.xml b/server/bundles/io.cloudbeaver.service.rm.nio/pom.xml new file mode 100644 index 0000000000..2aefd764ac --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.rm.nio/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + + io.cloudbeaver + bundles + 1.0.0-SNAPSHOT + ../ + + io.cloudbeaver.service.rm.nio + 1.0.0-SNAPSHOT + eclipse-plugin + + diff --git a/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/fs/RMVirtualFileSystem.java b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/fs/RMVirtualFileSystem.java new file mode 100644 index 0000000000..49b68bfd67 --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/fs/RMVirtualFileSystem.java @@ -0,0 +1,81 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2023 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.rm.fs; + +import io.cloudbeaver.model.session.WebSession; +import io.cloudbeaver.service.rm.nio.RMNIOFileSystemProvider; +import org.jkiss.code.NotNull; +import org.jkiss.dbeaver.DBException; +import org.jkiss.dbeaver.model.DBPImage; +import org.jkiss.dbeaver.model.fs.DBFVirtualFileSystem; +import org.jkiss.dbeaver.model.fs.DBFVirtualFileSystemRoot; +import org.jkiss.dbeaver.model.rm.RMProject; +import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; + +import java.net.URI; +import java.nio.file.Path; + +public class RMVirtualFileSystem implements DBFVirtualFileSystem { + @NotNull + private final RMNIOFileSystemProvider rmNioFileSystemProvider; + + @NotNull + private final RMProject rmProject; + public RMVirtualFileSystem(@NotNull WebSession webSession, @NotNull RMProject rmProject) { + this.rmNioFileSystemProvider = new RMNIOFileSystemProvider(webSession.getRmController()); + this.rmProject = rmProject; + } + + @NotNull + @Override + public String getFileSystemDisplayName() { + return "RM"; + } + + @NotNull + @Override + public String getType() { + return "rm"; + } + + @Override + public String getDescription() { + return "Resource Manager file system"; + } + + @Override + public DBPImage getIcon() { + return null; + } + + @NotNull + @Override + public String getId() { + return rmProject.getId(); + } + + @Override + public Path getPathByURI(DBRProgressMonitor monitor, URI uri) { + return rmNioFileSystemProvider.getPath(uri); + } + + @NotNull + @Override + public DBFVirtualFileSystemRoot[] getRootFolders(DBRProgressMonitor monitor) throws DBException { + return new RMVirtualFileSystemRoot[]{new RMVirtualFileSystemRoot(this, rmProject, rmNioFileSystemProvider)}; + } +} diff --git a/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/fs/RMVirtualFileSystemProvider.java b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/fs/RMVirtualFileSystemProvider.java new file mode 100644 index 0000000000..e5355ee310 --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/fs/RMVirtualFileSystemProvider.java @@ -0,0 +1,48 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2023 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.rm.fs; + +import io.cloudbeaver.WebProjectImpl; +import io.cloudbeaver.model.session.WebSession; +import org.jkiss.code.NotNull; +import org.jkiss.dbeaver.Log; +import org.jkiss.dbeaver.model.app.DBPProject; +import org.jkiss.dbeaver.model.fs.DBFFileSystemProvider; +import org.jkiss.dbeaver.model.fs.DBFVirtualFileSystem; +import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; + +public class RMVirtualFileSystemProvider implements DBFFileSystemProvider { + private static final Log log = Log.getLog(RMVirtualFileSystemProvider.class); + + @Override + public DBFVirtualFileSystem[] getAvailableFileSystems( + @NotNull DBRProgressMonitor monitor, + @NotNull DBPProject project + ) { + var session = project.getSessionContext().getPrimaryAuthSpace(); + if (!(session instanceof WebSession)) { + return new DBFVirtualFileSystem[0]; + } + WebSession webSession = (WebSession) session; + WebProjectImpl webProject = webSession.getProjectById(project.getId()); + if (webProject == null) { + log.warn(String.format("Project %s not found in session %s", project.getId(), webSession.getSessionId())); + return new DBFVirtualFileSystem[0]; + } + return new DBFVirtualFileSystem[]{new RMVirtualFileSystem(webSession, webProject.getRmProject())}; + } +} diff --git a/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/fs/RMVirtualFileSystemRoot.java b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/fs/RMVirtualFileSystemRoot.java new file mode 100644 index 0000000000..10f9ad6d9b --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/fs/RMVirtualFileSystemRoot.java @@ -0,0 +1,77 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2023 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.rm.fs; + +import io.cloudbeaver.service.rm.nio.RMNIOFileSystemProvider; +import io.cloudbeaver.service.rm.nio.RMNIOFileSystem; +import io.cloudbeaver.service.rm.nio.RMPath; +import org.jkiss.code.NotNull; +import org.jkiss.dbeaver.model.DBPImage; +import org.jkiss.dbeaver.model.fs.DBFVirtualFileSystem; +import org.jkiss.dbeaver.model.fs.DBFVirtualFileSystemRoot; +import org.jkiss.dbeaver.model.rm.RMProject; +import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; + +import java.nio.file.Path; + +public class RMVirtualFileSystemRoot implements DBFVirtualFileSystemRoot { + @NotNull + private final RMVirtualFileSystem rmFileSystem; + @NotNull + private final RMProject rmProject; + @NotNull + private final RMNIOFileSystemProvider rmNioFileSystemProvider; + + public RMVirtualFileSystemRoot( + @NotNull RMVirtualFileSystem rmFileSystem, + @NotNull RMProject rmProject, + @NotNull RMNIOFileSystemProvider rmNioFileSystemProvider + ) { + this.rmFileSystem = rmFileSystem; + this.rmProject = rmProject; + this.rmNioFileSystemProvider = rmNioFileSystemProvider; + } + + @NotNull + @Override + public String getName() { + return rmProject.getName(); + } + + @NotNull + @Override + public DBFVirtualFileSystem getFileSystem() { + return rmFileSystem; + } + + @NotNull + @Override + public String getRootId() { + return rmProject.getId(); + } + + @Override + public DBPImage getRootIcon() { + return null; + } + + @NotNull + @Override + public Path getRootPath(DBRProgressMonitor monitor) { + return new RMPath(new RMNIOFileSystem(rmProject.getId(), rmNioFileSystemProvider)); + } +} diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMByteArrayChannel.java b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMByteArrayChannel.java similarity index 98% rename from server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMByteArrayChannel.java rename to server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMByteArrayChannel.java index d0f6913f7f..9d51f07a57 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMByteArrayChannel.java +++ b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMByteArrayChannel.java @@ -23,7 +23,7 @@ * questions. */ -package io.cloudbeaver.model.rm.fs.nio; +package io.cloudbeaver.service.rm.nio; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.model.nio.ByteArrayChannel; diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMNIOFileSystem.java b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMNIOFileSystem.java similarity index 93% rename from server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMNIOFileSystem.java rename to server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMNIOFileSystem.java index 0abc646d75..f0ed593597 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMNIOFileSystem.java +++ b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMNIOFileSystem.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.cloudbeaver.model.rm.fs.nio; +package io.cloudbeaver.service.rm.nio; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; @@ -41,19 +41,15 @@ public class RMNIOFileSystem extends NIOFileSystem { // null for root 'rm://' path private final String rmProjectId; @NotNull - private final RMController rmController; - @NotNull private final RMNIOFileSystemProvider rmNioFileSystemProvider; @Nullable private RMProject rmProject; public RMNIOFileSystem( @Nullable String rmProjectId, - @NotNull RMController rmController, @NotNull RMNIOFileSystemProvider rmNioFileSystemProvider ) { this.rmProjectId = rmProjectId; - this.rmController = rmController; this.rmNioFileSystemProvider = rmNioFileSystemProvider; } @@ -119,7 +115,7 @@ public class RMNIOFileSystem extends NIOFileSystem { @NotNull public RMController getRmController() { - return rmController; + return rmNioFileSystemProvider.getRmController(); } @Nullable @@ -136,7 +132,7 @@ public class RMNIOFileSystem extends NIOFileSystem { throw new IOException("Project id not specified"); } try { - RMProject project = rmController.getProject(rmProjectId, false, false); + RMProject project = getRmController().getProject(rmProjectId, false, false); if (project == null) { throw new FileNotFoundException("Project not exist: " + rmProjectId); } @@ -146,4 +142,8 @@ public class RMNIOFileSystem extends NIOFileSystem { throw new IOException("Failed to get project:" + e.getMessage(), e); } } + + public RMNIOFileSystemProvider rmProvider() { + return rmNioFileSystemProvider; + } } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMNIOFileSystemProvider.java b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMNIOFileSystemProvider.java similarity index 88% rename from server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMNIOFileSystemProvider.java rename to server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMNIOFileSystemProvider.java index e87da418fa..676b28dddc 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMNIOFileSystemProvider.java +++ b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMNIOFileSystemProvider.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.cloudbeaver.model.rm.fs.nio; +package io.cloudbeaver.service.rm.nio; import org.jkiss.code.NotNull; import org.jkiss.dbeaver.DBException; @@ -53,8 +53,8 @@ public class RMNIOFileSystemProvider extends NIOFileSystemProvider { } @Override - public FileSystem newFileSystem(URI uri, Map env) throws IOException { - throw new FileAlreadyExistsException("RM file system already exist"); + public FileSystem newFileSystem(URI uri, Map env) { + return getFileSystem(uri); } @Override @@ -65,7 +65,7 @@ public class RMNIOFileSystemProvider extends NIOFileSystemProvider { projectId = null; } try { - return new RMNIOFileSystem(projectId, rmController, this); + return new RMNIOFileSystem(projectId, this); } catch (Exception e) { throw new FileSystemNotFoundException("RM file system not found: " + e.getMessage()); } @@ -78,7 +78,7 @@ public class RMNIOFileSystemProvider extends NIOFileSystemProvider { if (CommonUtils.isEmpty(projectId)) { projectId = null; } - RMNIOFileSystem rmNioFileSystem = new RMNIOFileSystem(projectId, rmController, this); + RMNIOFileSystem rmNioFileSystem = new RMNIOFileSystem(projectId, this); String resourcePath = uri.getPath(); if (CommonUtils.isNotEmpty(resourcePath) && projectId == null) { throw new IllegalArgumentException("Project is not specified in URI"); @@ -91,10 +91,11 @@ public class RMNIOFileSystemProvider extends NIOFileSystemProvider { } @Override - public RMByteArrayChannel newByteChannel(Path path, Set options, FileAttribute... attrs) throws IOException { + public RMByteArrayChannel newByteChannel(Path path, Set options, FileAttribute... attrs) + throws IOException { RMPath rmPath = (RMPath) path; - if (rmPath.isProjectPath()) { - throw new IllegalArgumentException("Cannot open channel for the project"); + if (Files.isDirectory(rmPath)) { + throw new IllegalArgumentException("Cannot open channel for a folder"); } try { @@ -115,7 +116,8 @@ public class RMNIOFileSystemProvider extends NIOFileSystemProvider { } @Override - public DirectoryStream newDirectoryStream(Path dir, DirectoryStream.Filter filter) throws IOException { + public DirectoryStream newDirectoryStream(Path dir, DirectoryStream.Filter filter) + throws IOException { RMPath rmDir = (RMPath) dir; String rmDirPath = rmDir.getResourcePath(); String separator = rmDir.getFileSystem().getSeparator(); @@ -130,7 +132,6 @@ public class RMNIOFileSystemProvider extends NIOFileSystemProvider { .map(rmProject -> (Path) new RMPath( new RMNIOFileSystem( rmProject.getId(), - rmController, RMNIOFileSystemProvider.this ) ) @@ -166,6 +167,9 @@ public class RMNIOFileSystemProvider extends NIOFileSystemProvider { public void createDirectory(Path dir, FileAttribute... attrs) throws IOException { RMPath rmDir = (RMPath) dir; try { + if (rmDir.isRmRootPath()) { + return; + } if (rmDir.isProjectPath()) { rmController.createProject(RMUtils.getProjectName(rmDir.getRmProjectId()), null); } else { @@ -180,7 +184,7 @@ public class RMNIOFileSystemProvider extends NIOFileSystemProvider { public void delete(Path path) throws IOException { RMPath rmPath = (RMPath) path; if (rmPath.isRmRootPath()) { - throw new IOException("Can not delete root rm directory"); + throw new IOException("Cannot delete root rm dir:" + path); } try { String rmProjectId = rmPath.getRmProjectId(); @@ -205,7 +209,9 @@ public class RMNIOFileSystemProvider extends NIOFileSystemProvider { RMPath rmSource = (RMPath) source; RMPath rmTarget = (RMPath) target; try { - rmController.moveResource(rmSource.getRmProjectId(), rmSource.getResourcePath(), rmTarget.getResourcePath()); + rmController.moveResource(rmSource.getRmProjectId(), + rmSource.getResourcePath(), + rmTarget.getResourcePath()); } catch (DBException e) { throw new IOException("Failed to move rm resource: " + e.getMessage(), e); } @@ -225,25 +231,19 @@ public class RMNIOFileSystemProvider extends NIOFileSystemProvider { @Override public FileStore getFileStore(Path path) throws IOException { RMPath rmPath = (RMPath) path; - if (rmPath.isProjectPath()) { - return new RMNIOProjectFileStore(rmPath.getFileSystem().getRmProject()); - } else { - try { - RMResource rmResource = rmController.getResource(rmPath.getRmProjectId(), rmPath.getResourcePath()); - if (rmResource == null) { - throw new FileNotFoundException(); - } - return new RMNIOResourceFileStore(rmResource); - } catch (DBException e) { - throw new IOException("Failed to "); - } + if (rmPath.isRmRootPath()) { + throw new IllegalArgumentException("Cannot create file store for path: " + path); } + return new RMNIOProjectFileStore(rmPath.getFileSystem().getRmProject()); } @Override public void checkAccess(Path path, AccessMode... modes) throws IOException { RMPath rmPath = (RMPath) path; try { + if (rmPath.isRmRootPath()) { + return; + } if (rmPath.isProjectPath()) { if (rmController.getProject(rmPath.getRmProjectId(), false, false) == null) { // we should throw error, otherwise Files.exists return true @@ -272,8 +272,8 @@ public class RMNIOFileSystemProvider extends NIOFileSystemProvider { return type.cast(new RMRootBasicAttribute()); } if (rmPath.isProjectPath()) { - boolean projectNotExist = rmController.getProject(rmPath.getRmProjectId(), false, false) == null; - if (projectNotExist) { + boolean projectExist = rmController.getProject(rmPath.getRmProjectId(), false, false) != null; + if (!projectExist) { throw new FileNotFoundException(); } return type.cast(new RMRootBasicAttribute()); @@ -290,4 +290,9 @@ public class RMNIOFileSystemProvider extends NIOFileSystemProvider { } return null; } + + @NotNull + public RMController getRmController() { + return rmController; + } } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMNIOProjectFileStore.java b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMNIOProjectFileStore.java similarity index 97% rename from server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMNIOProjectFileStore.java rename to server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMNIOProjectFileStore.java index da1bd715f8..2e08f5f0a8 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMNIOProjectFileStore.java +++ b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMNIOProjectFileStore.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.cloudbeaver.model.rm.fs.nio; +package io.cloudbeaver.service.rm.nio; import org.jkiss.dbeaver.model.nio.NIOFileStore; import org.jkiss.dbeaver.model.rm.RMProject; diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMOutputStream.java b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMOutputStream.java similarity index 97% rename from server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMOutputStream.java rename to server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMOutputStream.java index 09fee299e9..4db2a79a69 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMOutputStream.java +++ b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMOutputStream.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.cloudbeaver.model.rm.fs.nio; +package io.cloudbeaver.service.rm.nio; import org.jkiss.dbeaver.DBException; diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMPath.java b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMPath.java similarity index 92% rename from server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMPath.java rename to server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMPath.java index a1e9a49c37..c38642269e 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMPath.java +++ b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMPath.java @@ -14,12 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.cloudbeaver.model.rm.fs.nio; +package io.cloudbeaver.service.rm.nio; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.model.nio.NIOPath; +import org.jkiss.utils.ArrayUtils; import org.jkiss.utils.CommonUtils; import java.io.IOException; @@ -58,7 +59,7 @@ public class RMPath extends NIOPath { @Override public Path getRoot() { - if (isProjectPath()) { + if (isProjectPath() || isRmRootPath()) { return null; } return new RMPath(rmNioFileSystem); @@ -66,13 +67,16 @@ public class RMPath extends NIOPath { @Override public Path getFileName() { - return this; + var parts = pathParts(); + if (ArrayUtils.isEmpty(parts)) { + return this; + } + return new RMPath(rmNioFileSystem, parts[parts.length - 1]); } @Override public Path getParent() { - // project is root and have no parent - if (isProjectPath()) { + if (isRmRootPath() || isProjectPath()) { return null; } @@ -90,14 +94,6 @@ public class RMPath extends NIOPath { return pathParts().length; } - @Override - public boolean startsWith(@NotNull Path other) { - if (!(other instanceof RMPath)) { - return false; - } - return toString().startsWith(other.toString()); - } - @Override public Path normalize() { return this; @@ -127,8 +123,11 @@ public class RMPath extends NIOPath { public URI toUri() { var fileSystem = getFileSystem(); var uriBuilder = new StringBuilder(fileSystem.provider().getScheme()) - .append("://") - .append(rmProjectId); + .append("://"); + + if (rmProjectId != null) { + uriBuilder.append(rmProjectId); + } String rmResourcePath = getResourcePath(); if (rmResourcePath != null) { diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMResourceBasicAttribute.java b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMResourceBasicAttribute.java similarity index 97% rename from server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMResourceBasicAttribute.java rename to server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMResourceBasicAttribute.java index 2387e3e07e..cff20b301c 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMResourceBasicAttribute.java +++ b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMResourceBasicAttribute.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.cloudbeaver.model.rm.fs.nio; +package io.cloudbeaver.service.rm.nio; import org.jkiss.code.NotNull; import org.jkiss.dbeaver.model.nio.NIOFileBasicAttribute; diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMRootBasicAttribute.java b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMRootBasicAttribute.java similarity index 96% rename from server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMRootBasicAttribute.java rename to server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMRootBasicAttribute.java index 5ce279ae3f..7cb22e8123 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/fs/nio/RMRootBasicAttribute.java +++ b/server/bundles/io.cloudbeaver.service.rm.nio/src/io/cloudbeaver/service/rm/nio/RMRootBasicAttribute.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.cloudbeaver.model.rm.fs.nio; +package io.cloudbeaver.service.rm.nio; import org.jkiss.dbeaver.model.nio.NIOFileBasicAttribute; diff --git a/server/bundles/io.cloudbeaver.service.rm/schema/service.rm.graphqls b/server/bundles/io.cloudbeaver.service.rm/schema/service.rm.graphqls index a3797f5a70..79589bb1fa 100644 --- a/server/bundles/io.cloudbeaver.service.rm/schema/service.rm.graphqls +++ b/server/bundles/io.cloudbeaver.service.rm/schema/service.rm.graphqls @@ -34,6 +34,7 @@ input RMSubjectProjectPermissions { permissions: [String!]! } + input RMProjectPermissions { projectId: String! permissions: [String!]! @@ -59,42 +60,41 @@ extend type Query { folder: String, nameMask: String, readProperties: Boolean, - readHistory: Boolean): [RMResource!]! + readHistory: Boolean): [RMResource!]! @deprecated # Reads resource contents as string in UTF-8 rmReadResourceAsString( projectId: String!, - resourcePath: String!): String! + resourcePath: String!): String! @deprecated } extend type Mutation { - rmCreateResource( projectId: String!, resourcePath: String!, - isFolder: Boolean!): String! + isFolder: Boolean!): String! @deprecated rmMoveResource( projectId: String!, oldResourcePath: String!, - newResourcePath: String): String! + newResourcePath: String): String! @deprecated rmDeleteResource( projectId: String!, resourcePath: String!, - recursive: Boolean!): Boolean + recursive: Boolean!): Boolean @deprecated rmWriteResourceStringContent( projectId: String!, resourcePath: String!, data: String!, - forceOverwrite: Boolean!): String! + forceOverwrite: Boolean!): String! @deprecated rmCreateProject( projectId: ID, projectName: String!, - description: String): RMProject! + description: String): RMProject! @deprecated rmDeleteProject(projectId: ID!): Boolean! diff --git a/server/bundles/pom.xml b/server/bundles/pom.xml index 0926706826..453987399b 100644 --- a/server/bundles/pom.xml +++ b/server/bundles/pom.xml @@ -19,7 +19,9 @@ io.cloudbeaver.service.admin io.cloudbeaver.service.auth io.cloudbeaver.service.metadata + io.cloudbeaver.service.fs io.cloudbeaver.service.rm + io.cloudbeaver.service.rm.nio io.cloudbeaver.service.data.transfer io.cloudbeaver.service.security diff --git a/server/features/io.cloudbeaver.server.feature/feature.xml b/server/features/io.cloudbeaver.server.feature/feature.xml index 513cd1aeb8..3be4b73b5b 100644 --- a/server/features/io.cloudbeaver.server.feature/feature.xml +++ b/server/features/io.cloudbeaver.server.feature/feature.xml @@ -36,7 +36,9 @@ + + diff --git a/server/test/io.cloudbeaver.test.platform/META-INF/MANIFEST.MF b/server/test/io.cloudbeaver.test.platform/META-INF/MANIFEST.MF index b66eb7fdf3..55384ba6ab 100644 --- a/server/test/io.cloudbeaver.test.platform/META-INF/MANIFEST.MF +++ b/server/test/io.cloudbeaver.test.platform/META-INF/MANIFEST.MF @@ -24,5 +24,6 @@ Require-Bundle: org.eclipse.core.runtime, io.cloudbeaver.resources.drivers.base, io.cloudbeaver.product.ce, io.cloudbeaver.service.auth, - io.cloudbeaver.service.rm + io.cloudbeaver.service.rm, + io.cloudbeaver.service.rm.nio Export-Package: io.cloudbeaver.test.platform diff --git a/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/model/rm/RMNIOTest.java b/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/model/rm/RMNIOTest.java index 7aeb0c9f6d..80ca252be3 100644 --- a/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/model/rm/RMNIOTest.java +++ b/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/model/rm/RMNIOTest.java @@ -16,11 +16,11 @@ */ package io.cloudbeaver.model.rm; -import io.cloudbeaver.model.rm.fs.nio.RMNIOFileSystem; -import io.cloudbeaver.model.rm.fs.nio.RMNIOFileSystemProvider; -import io.cloudbeaver.model.rm.fs.nio.RMPath; import io.cloudbeaver.model.session.WebSession; import io.cloudbeaver.server.CBConstants; +import io.cloudbeaver.service.rm.nio.RMNIOFileSystem; +import io.cloudbeaver.service.rm.nio.RMNIOFileSystemProvider; +import io.cloudbeaver.service.rm.nio.RMPath; import io.cloudbeaver.test.platform.CEServerTestSuite; import io.cloudbeaver.utils.WebTestUtils; import org.jkiss.dbeaver.DBException; @@ -96,7 +96,7 @@ public class RMNIOTest { @Test public void testNotExistProject() { - RMPath notExistPath = new RMPath(new RMNIOFileSystem("s_not_exist", webSession.getRmController(), rmFsProvider)); + RMPath notExistPath = new RMPath(new RMNIOFileSystem("s_not_exist", rmFsProvider)); Assert.assertFalse(Files.exists(notExistPath)); } @@ -105,7 +105,7 @@ public class RMNIOTest { var randomName = SecurityUtils.generateUniqueId(); String randomProject = "s_random_project_" + randomName; - RMPath newProjectPath = new RMPath(new RMNIOFileSystem(randomProject, webSession.getRmController(), rmFsProvider)); + RMPath newProjectPath = new RMPath(new RMNIOFileSystem(randomProject, rmFsProvider)); Assert.assertFalse(Files.exists(newProjectPath)); //create project via nio