#8 Navigator service

This commit is contained in:
serge-rider
2020-04-29 09:57:09 +03:00
parent 5a7c605080
commit dfd6eddb59
15 changed files with 297 additions and 167 deletions
@@ -34,4 +34,8 @@
<service name="org.jkiss.dbeaver.runtime.DBServiceConnections" class="io.cloudbeaver.server.WebServiceConnectionsImpl"/>
</extension>
<extension point="io.cloudbeaver.service">
<service id="navigator" label="Database navigator" description="Database navigator services" class="io.cloudbeaver.service.navigator.WebServiceBindingNavigator"/>
</extension>
</plugin>
@@ -258,31 +258,6 @@ type DatabaseObjectInfo {
editors: [ String ]
}
type NavigatorNodeInfo {
# Node ID - generally a full path to the node from root of tree
id: ID!
# Node human readable name
name: String
# Node icon path
icon: String
# Node description
description: String
# Node type
nodeType: String
# Can this property have child nodes?
hasChildren: Boolean
# Associated object. Maybe null for non-database objects
object: DatabaseObjectInfo
# Supported features: item, container, leaf
features: [ String ]
folder: Boolean
inline: Boolean
navigable: Boolean
}
####################################################
# SQL helpers
####################################################
@@ -426,19 +401,6 @@ type Query {
readSessionLog(maxEntries: Int, clearEntries: Boolean): [ LogEntry! ]
# Get child nodes
navNodeChildren(
parentPath: ID!,
offset: Int,
limit: Int,
onlyFolders: Boolean): [ NavigatorNodeInfo! ]
navNodeInfo( nodePath: ID! ): NavigatorNodeInfo
navRefreshNode( nodePath: ID! ): Boolean
navGetStructContainers( connectionId: ID!, catalog: ID ): DatabaseStructContainers!
sqlDialectInfo( connectionId: ID! ): SQLDialectInfo
sqlListContexts( connectionId: ID! ): [ SQLContextInfo ]
@@ -0,0 +1,46 @@
type NavigatorNodeInfo {
# Node ID - generally a full path to the node from root of tree
id: ID!
# Node human readable name
name: String
# Node icon path
icon: String
# Node description
description: String
# Node type
nodeType: String
# Can this property have child nodes?
hasChildren: Boolean
# Associated object. Maybe null for non-database objects
object: DatabaseObjectInfo
# Supported features: item, container, leaf
features: [ String ]
folder: Boolean
inline: Boolean
navigable: Boolean
}
####################################################
# Main API
####################################################
extend type Query {
# Get child nodes
navNodeChildren(
parentPath: ID!,
offset: Int,
limit: Int,
onlyFolders: Boolean): [ NavigatorNodeInfo! ]
navNodeInfo( nodePath: ID! ): NavigatorNodeInfo
navRefreshNode( nodePath: ID! ): Boolean
navGetStructContainers( connectionId: ID!, catalog: ID ): DatabaseStructContainers!
}
@@ -60,8 +60,6 @@ public class WebSession {
private static final Log log = Log.getLog(WebSession.class);
public static final List<WebNavigatorNodeInfo> EMPTY_NODE_LIST = Collections.emptyList();
private static final String ATTR_LOCALE = "locale";
private static final AtomicInteger TASK_ID = new AtomicInteger();
@@ -141,6 +139,10 @@ public class WebSession {
return navigatorModel;
}
public DBNProjectDatabases getDatabases() {
return databases;
}
/**
* Returns and clears progress messages
*/
@@ -359,63 +361,6 @@ public class WebSession {
}
}
public List<WebNavigatorNodeInfo> getNavigatorNodeChildren(String parentPath, Integer offset, Integer limit, Boolean onlyFolders) throws DBWebException {
try {
DBRProgressMonitor monitor = getProgressMonitor();
DBNNode parentNode = CommonUtils.isEmpty(parentPath) || "/".equals(parentPath) ? databases : navigatorModel.getNodeByPath(monitor, parentPath);
if (parentNode == null) {
throw new DBWebException("Node '" + parentPath + "' not found");
}
if (!parentNode.hasChildren(true)) {
return EMPTY_NODE_LIST;
}
DBNNode[] nodeChildren = parentNode.getChildren(monitor);
if (nodeChildren == null) {
return EMPTY_NODE_LIST;
}
List<WebNavigatorNodeInfo> result = new ArrayList<>();
for (DBNNode node : nodeChildren) {
if (!CommonUtils.toBoolean(onlyFolders) || node instanceof DBNContainer) {
result.add(new WebNavigatorNodeInfo(this, node));
}
}
return result;
} catch (DBException e) {
throw new DBWebException("Error getting navigator nodes", e);
}
}
@NotNull
public WebNavigatorNodeInfo getNavigatorNodeInfo(String nodePath) throws DBWebException {
try {
DBRProgressMonitor monitor = getProgressMonitor();
DBNNode node = navigatorModel.getNodeByPath(monitor, nodePath);
if (node == null) {
throw new DBWebException("Navigator node '" + nodePath + "' not found");
}
return new WebNavigatorNodeInfo(this, node);
} catch (DBException e) {
throw new DBWebException("Error getting navigator node '" + nodePath + "'", e);
}
}
public boolean refreshNavigatorNode(String nodePath) throws DBWebException {
try {
DBRProgressMonitor monitor = getProgressMonitor();
DBNNode node = navigatorModel.getNodeByPath(monitor, nodePath);
if (node == null) {
throw new DBWebException("Navigator node '" + nodePath + "' not found");
}
node.refreshNode(monitor, this);
return true;
} catch (DBException e) {
throw new DBWebException("Error refreshing navigator node '" + nodePath + "'", e);
}
}
public DBRProgressMonitor getProgressMonitor() {
return progressMonitor;
}
@@ -77,18 +77,6 @@ class GraphQLBindingContext implements DBWBindingContext {
env.getArgument("maxEntries"),
env.getArgument("clearEntries")))
.dataFetcher("navNodeChildren", env -> sessionManager.getWebSession(getServletRequest(env)).getNavigatorNodeChildren(
env.getArgument("parentPath"), env.getArgument("offset"), env.getArgument("limit"), env.getArgument("onlyFolders")))
.dataFetcher("navNodeInfo", env -> sessionManager.getWebSession(getServletRequest(env)).getNavigatorNodeInfo(
env.getArgument("nodePath")))
.dataFetcher("navRefreshNode", env -> sessionManager.getWebSession(getServletRequest(env)).refreshNavigatorNode(
env.getArgument("nodePath")
))
.dataFetcher("navGetStructContainers", env -> DBWUtils.getSQLProcessor(sessionManager, env).getStructContainers(
env.getArgument("catalog")
))
.dataFetcher("sqlDialectInfo", env ->
DBWUtils.getSQLProcessor(sessionManager, env).getDialectInfo()
)
@@ -19,9 +19,12 @@ package io.cloudbeaver.service;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
import io.cloudbeaver.DBWUtils;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.DBWService;
import io.cloudbeaver.model.session.WebSession;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -36,22 +39,28 @@ import java.lang.reflect.Proxy;
public abstract class WebServiceBindingBase<API_TYPE extends DBWService> implements DBWServiceBindingGraphQL {
private final Class<API_TYPE> apiInterface;
private API_TYPE serviceImpl;
private final API_TYPE serviceImpl;
private final String schemaFileName;
public WebServiceBindingBase(Class<API_TYPE> apiInterface, API_TYPE impl) {
public WebServiceBindingBase(Class<API_TYPE> apiInterface, API_TYPE impl, String schemaFileName) {
this.apiInterface = apiInterface;
this.serviceImpl = impl;
this.schemaFileName = schemaFileName;
}
protected API_TYPE getServiceImpl() {
return serviceImpl;
}
@Override
public TypeDefinitionRegistry getTypeDefinition() throws DBWebException {
return loadSchemaDefinition(getClass(), schemaFileName);
}
/**
* Creates proxy for permission checks and other general API calls validation/logging.
*/
protected API_TYPE getAPI(DataFetchingEnvironment env) {
protected API_TYPE getService(DataFetchingEnvironment env) {
Object proxyImpl = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{apiInterface}, new ServiceInvocationHandler(serviceImpl));
return apiInterface.cast(proxyImpl);
}
@@ -69,6 +78,14 @@ public abstract class WebServiceBindingBase<API_TYPE extends DBWService> impleme
}
}
protected HttpServletRequest getServletRequest(DataFetchingEnvironment env) {
return DBWUtils.getServletRequest(env);
}
protected WebSession getWebSession(DBWBindingContext model, DataFetchingEnvironment env) throws DBWebException {
return model.getSessionManager().getWebSession(getServletRequest(env));
}
private class ServiceInvocationHandler implements InvocationHandler {
private final API_TYPE impl;
@@ -0,0 +1,41 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2020 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.navigator;
import io.cloudbeaver.DBWService;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.WebAction;
import io.cloudbeaver.model.WebNavigatorNodeInfo;
import io.cloudbeaver.model.session.WebSession;
import java.util.List;
/**
* Web service API
*/
public interface DBWServiceNavigator extends DBWService {
@WebAction
List<WebNavigatorNodeInfo> getNavigatorNodeChildren(WebSession session, String parentPath, Integer offset, Integer limit, Boolean onlyFolders) throws DBWebException;
@WebAction
WebNavigatorNodeInfo getNavigatorNodeInfo(WebSession session, String nodePath) throws DBWebException;
@WebAction
boolean refreshNavigatorNode(WebSession session, String nodePath) throws DBWebException;
}
@@ -0,0 +1,55 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2020 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.navigator;
import io.cloudbeaver.DBWUtils;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.service.DBWBindingContext;
import io.cloudbeaver.service.WebServiceBindingBase;
import io.cloudbeaver.service.navigator.impl.WebServiceNavigator;
/**
* Web service implementation
*/
public class WebServiceBindingNavigator extends WebServiceBindingBase<DBWServiceNavigator> {
public WebServiceBindingNavigator() {
super(DBWServiceNavigator.class, new WebServiceNavigator(), "schema/service.navigator.graphqls");
}
@Override
public void bindWiring(DBWBindingContext model) throws DBWebException {
model.getQueryType()
.dataFetcher("navNodeChildren", env -> getService(env).getNavigatorNodeChildren(
getWebSession(model, env),
env.getArgument("parentPath"),
env.getArgument("offset"),
env.getArgument("limit"),
env.getArgument("onlyFolders")))
.dataFetcher("navNodeInfo", env -> getService(env).getNavigatorNodeInfo(
getWebSession(model, env),
env.getArgument("nodePath")))
.dataFetcher("navRefreshNode", env -> getService(env).refreshNavigatorNode(
getWebSession(model, env),
env.getArgument("nodePath")
))
.dataFetcher("navGetStructContainers", env -> DBWUtils.getSQLProcessor(model.getSessionManager(), env).getStructContainers(
env.getArgument("catalog")
));
}
}
@@ -0,0 +1,102 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2020 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.navigator.impl;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.model.WebNavigatorNodeInfo;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.service.navigator.DBWServiceNavigator;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.navigator.DBNContainer;
import org.jkiss.dbeaver.model.navigator.DBNNode;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.utils.CommonUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Web service implementation
*/
public class WebServiceNavigator implements DBWServiceNavigator {
private static final List<WebNavigatorNodeInfo> EMPTY_NODE_LIST = Collections.emptyList();
@Override
public List<WebNavigatorNodeInfo> getNavigatorNodeChildren(WebSession session, String parentPath, Integer offset, Integer limit, Boolean onlyFolders) throws DBWebException {
try {
DBRProgressMonitor monitor = session.getProgressMonitor();
DBNNode parentNode = CommonUtils.isEmpty(parentPath) || "/".equals(parentPath) ? session.getDatabases() : session.getNavigatorModel().getNodeByPath(monitor, parentPath);
if (parentNode == null) {
throw new DBWebException("Node '" + parentPath + "' not found");
}
if (!parentNode.hasChildren(true)) {
return EMPTY_NODE_LIST;
}
DBNNode[] nodeChildren = parentNode.getChildren(monitor);
if (nodeChildren == null) {
return EMPTY_NODE_LIST;
}
List<WebNavigatorNodeInfo> result = new ArrayList<>();
for (DBNNode node : nodeChildren) {
if (!CommonUtils.toBoolean(onlyFolders) || node instanceof DBNContainer) {
result.add(new WebNavigatorNodeInfo(session, node));
}
}
return result;
} catch (DBException e) {
throw new DBWebException("Error getting navigator nodes", e);
}
}
@Override
@NotNull
public WebNavigatorNodeInfo getNavigatorNodeInfo(WebSession session, String nodePath) throws DBWebException {
try {
DBRProgressMonitor monitor = session.getProgressMonitor();
DBNNode node = session.getNavigatorModel().getNodeByPath(monitor, nodePath);
if (node == null) {
throw new DBWebException("Navigator node '" + nodePath + "' not found");
}
return new WebNavigatorNodeInfo(session, node);
} catch (DBException e) {
throw new DBWebException("Error getting navigator node '" + nodePath + "'", e);
}
}
@Override
public boolean refreshNavigatorNode(WebSession session, String nodePath) throws DBWebException {
try {
DBRProgressMonitor monitor = session.getProgressMonitor();
DBNNode node = session.getNavigatorModel().getNodeByPath(monitor, nodePath);
if (node == null) {
throw new DBWebException("Navigator node '" + nodePath + "' not found");
}
node.refreshNode(monitor, this);
return true;
} catch (DBException e) {
throw new DBWebException("Error refreshing navigator node '" + nodePath + "'", e);
}
}
}
@@ -30,12 +30,7 @@ public class WebServiceBindingAdmin extends WebServiceBindingBase<DBWServiceAdmi
private static final String SCHEMA_FILE_NAME = "schema/service.admin.graphqls";
public WebServiceBindingAdmin() {
super(DBWServiceAdmin.class, new WebServiceAdmin());
}
@Override
public TypeDefinitionRegistry getTypeDefinition() throws DBWebException {
return loadSchemaDefinition(getClass(), SCHEMA_FILE_NAME);
super(DBWServiceAdmin.class, new WebServiceAdmin(), SCHEMA_FILE_NAME);
}
@Override
@@ -30,12 +30,7 @@ public class WebServiceBindingAuth extends WebServiceBindingBase<DBWServiceAuth>
private static final String SCHEMA_FILE_NAME = "schema/service.auth.graphqls";
public WebServiceBindingAuth() {
super(DBWServiceAuth.class, new WebServiceAuthImpl());
}
@Override
public TypeDefinitionRegistry getTypeDefinition() throws DBWebException {
return loadSchemaDefinition(getClass(), SCHEMA_FILE_NAME);
super(DBWServiceAuth.class, new WebServiceAuthImpl(), SCHEMA_FILE_NAME);
}
@Override
@@ -16,18 +16,14 @@
*/
package io.cloudbeaver.service.data.transfer;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.idl.TypeDefinitionRegistry;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.DBWUtils;
import io.cloudbeaver.server.CloudbeaverApplication;
import io.cloudbeaver.service.DBWBindingContext;
import io.cloudbeaver.service.DBWServiceBindingServlet;
import io.cloudbeaver.DBWUtils;
import io.cloudbeaver.service.WebServiceBindingBase;
import io.cloudbeaver.server.CloudbeaverApplication;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.service.data.transfer.impl.WebServiceDataTransfer;
import io.cloudbeaver.service.data.transfer.impl.WebDataTransferParameters;
import io.cloudbeaver.service.data.transfer.impl.WebDataTransferServlet;
import io.cloudbeaver.service.data.transfer.impl.WebServiceDataTransfer;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
@@ -36,15 +32,8 @@ import org.eclipse.jetty.servlet.ServletHolder;
*/
public class WebServiceBindingDataTransfer extends WebServiceBindingBase<DBWServiceDataTransfer> implements DBWServiceBindingServlet {
private static final String DT_SCHEMA_FILE_NAME = "schema/service.data.transfer.graphqls";
public WebServiceBindingDataTransfer() {
super(DBWServiceDataTransfer.class, new WebServiceDataTransfer());
}
@Override
public TypeDefinitionRegistry getTypeDefinition() throws DBWebException {
return loadSchemaDefinition(getClass(), DT_SCHEMA_FILE_NAME);
super(DBWServiceDataTransfer.class, new WebServiceDataTransfer(), "schema/service.data.transfer.graphqls");
}
@Override
@@ -52,18 +41,18 @@ public class WebServiceBindingDataTransfer extends WebServiceBindingBase<DBWServ
model.getQueryType()
.dataFetcher("dataTransferAvailableStreamProcessors",
env -> getAPI(env).getAvailableStreamProcessors(getWebSession(model, env)))
.dataFetcher("dataTransferExportDataFromContainer", env -> getAPI(env).dataTransferExportDataFromContainer(
env -> getService(env).getAvailableStreamProcessors(getWebSession(model, env)))
.dataFetcher("dataTransferExportDataFromContainer", env -> getService(env).dataTransferExportDataFromContainer(
DBWUtils.getSQLProcessor(model.getSessionManager(), env),
env.getArgument("containerNodePath"),
new WebDataTransferParameters(env.getArgument("parameters"))
))
.dataFetcher("dataTransferExportDataFromResults", env -> getAPI(env).dataTransferExportDataFromResults(
.dataFetcher("dataTransferExportDataFromResults", env -> getService(env).dataTransferExportDataFromResults(
DBWUtils.getSQLContext(model.getSessionManager(), env),
env.getArgument("resultsId"),
new WebDataTransferParameters(env.getArgument("parameters"))
))
.dataFetcher("dataTransferRemoveDataFile", env -> getAPI(env).dataTransferRemoveDataFile(
.dataFetcher("dataTransferRemoveDataFile", env -> getService(env).dataTransferRemoveDataFile(
DBWUtils.getSQLProcessor(model.getSessionManager(), env),
env.getArgument("dataFileId")
))
@@ -71,10 +60,6 @@ public class WebServiceBindingDataTransfer extends WebServiceBindingBase<DBWServ
}
private WebSession getWebSession(DBWBindingContext model, DataFetchingEnvironment env) throws DBWebException {
return model.getSessionManager().getWebSession(DBWUtils.getServletRequest(env));
}
@Override
public void addServlets(CloudbeaverApplication application, ServletContextHandler servletContextHandler) {
servletContextHandler.addServlet(
@@ -21,6 +21,7 @@ import io.cloudbeaver.DBWService;
import io.cloudbeaver.WebAction;
import io.cloudbeaver.model.WebNavigatorNodeInfo;
import io.cloudbeaver.model.session.WebSession;
import org.jkiss.dbeaver.model.navigator.DBNNode;
import java.util.Map;
@@ -30,6 +31,6 @@ import java.util.Map;
public interface DBWServiceMetadata extends DBWService {
@WebAction
String getNodeDDL(WebSession webSession, WebNavigatorNodeInfo node, Map<String, Object> options) throws DBWebException;
String getNodeDDL(WebSession webSession, DBNNode node, Map<String, Object> options) throws DBWebException;
}
@@ -16,14 +16,12 @@
*/
package io.cloudbeaver.service.metadata;
import graphql.schema.idl.TypeDefinitionRegistry;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.service.DBWBindingContext;
import io.cloudbeaver.DBWUtils;
import io.cloudbeaver.service.WebServiceBindingBase;
import io.cloudbeaver.model.WebNavigatorNodeInfo;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.service.DBWBindingContext;
import io.cloudbeaver.service.WebServiceBindingBase;
import io.cloudbeaver.service.metadata.impl.WebServiceMetadata;
import org.jkiss.dbeaver.model.navigator.DBNNode;
import java.util.Map;
@@ -35,22 +33,19 @@ public class WebServiceBindingMetadata extends WebServiceBindingBase<DBWServiceM
private static final String SCHEMA_FILE_NAME = "schema/service.metadata.graphqls";
public WebServiceBindingMetadata() {
super(DBWServiceMetadata.class, new WebServiceMetadata());
}
@Override
public TypeDefinitionRegistry getTypeDefinition() throws DBWebException {
return loadSchemaDefinition(getClass(), SCHEMA_FILE_NAME);
super(DBWServiceMetadata.class, new WebServiceMetadata(), SCHEMA_FILE_NAME);
}
@Override
public void bindWiring(DBWBindingContext model) throws DBWebException {
model.getQueryType().dataFetcher("metadataGetNodeDDL", env -> {
WebSession webSession = model.getSessionManager().getWebSession(DBWUtils.getServletRequest(env));
WebNavigatorNodeInfo node = webSession.getNavigatorNodeInfo(env.getArgument("nodeId"));
WebSession webSession = getWebSession(model, env);
String nodePath = env.getArgument("nodeId");
DBNNode node = webSession.getNavigatorModel().getNodeByPath(webSession.getProgressMonitor(), nodePath);
Map<String, Object> options = env.getArgument("options");
return getAPI(env).getNodeDDL(webSession, node, options);
return getService(env).getNodeDDL(webSession, node, options);
});
}
@@ -36,8 +36,7 @@ public class WebServiceMetadata implements DBWServiceMetadata {
@Override
public String getNodeDDL(WebSession webSession, WebNavigatorNodeInfo node, Map<String, Object> options) throws DBWebException {
DBNNode dbNode = node.getNode();
public String getNodeDDL(WebSession webSession, DBNNode dbNode, Map<String, Object> options) throws DBWebException {
if (dbNode instanceof DBNDatabaseNode) {
DBSObject object = ((DBNDatabaseNode) dbNode).getObject();
if (object instanceof DBPScriptObject) {
@@ -50,10 +49,10 @@ public class WebServiceMetadata implements DBWServiceMetadata {
throw new DBWebException("Error extracting DDL", e);
}
} else {
throw new DBWebException("Object '" + node.getId() + "' doesn't support DDL");
throw new DBWebException("Object '" + dbNode.getNodeItemPath() + "' doesn't support DDL");
}
} else {
throw new DBWebException("Node '" + node.getId() + "' is not database node");
throw new DBWebException("Node '" + dbNode.getNodeItemPath() + "' is not database node");
}
}
}