/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* 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 org.jkiss.dbeaver.model.navigator.meta;
import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlException;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.DBPImage;
import org.jkiss.dbeaver.model.navigator.DBNDatabaseNode;
import org.jkiss.dbeaver.model.navigator.DBNNode;
import org.jkiss.dbeaver.model.impl.AbstractDescriptor;
import org.jkiss.utils.CommonUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* DBXTreeNode
*/
public abstract class DBXTreeNode
{
private static final Log log = Log.getLog(DBXTreeNode.class);
private final AbstractDescriptor source;
private final DBXTreeNode parent;
private final String id;
private List<DBXTreeNode> children;
private DBPImage defaultIcon;
private List<DBXTreeIcon> icons;
private final boolean navigable;
private final boolean inline;
private final boolean virtual;
private boolean standaloneNode;
//private final boolean embeddable;
private Expression visibleIf;
private DBXTreeNode recursiveLink;
private List<DBXTreeNodeHandler> handlers = null;
public DBXTreeNode(AbstractDescriptor source, DBXTreeNode parent, String id, boolean navigable, boolean inline, boolean virtual, boolean standalone, String visibleIf, String recursive)
{
this.source = source;
this.parent = parent;
if (parent != null) {
parent.addChild(this);
}
this.id = id;
this.navigable = navigable;
this.inline = inline;
this.virtual = virtual;
this.standaloneNode = standalone;
if (!CommonUtils.isEmpty(visibleIf)) {
try {
this.visibleIf = AbstractDescriptor.parseExpression(visibleIf);
} catch (DBException e) {
log.warn(e);
}
}
if (recursive != null) {
recursiveLink = this;
for (String path : recursive.split("/")) {
if (path.equals("..")) {
recursiveLink = recursiveLink.parent;
}
}
}
}
public AbstractDescriptor getSource()
{
return source;
}
public abstract String getNodeType(DBPDataSource dataSource);
public abstract String getChildrenType(DBPDataSource dataSource);
public boolean isNavigable()
{
return navigable;
}
public boolean isInline()
{
return inline;
}
/**
* Virtual items. Such items are not added to global meta model and couldn't
* be found in tree by object
* @return true or false
*/
public boolean isVirtual()
{
return virtual;
}
public boolean isStandaloneNode() {
return standaloneNode;
}
public DBXTreeNode getParent()
{
return parent;
}
public String getId()
{
return id;
}
public boolean hasChildren(DBNNode context)
{
return hasChildren(context, false);
}
public boolean hasChildren(DBNNode context, boolean navigable)
{
if (CommonUtils.isEmpty(children)) {
return recursiveLink != null && recursiveLink.hasChildren(context, navigable);
}
if (context == null) {
return true;
}
for (DBXTreeNode child : children) {
if ((!navigable || child.isNavigable()) && child.isVisible(context)) {
return true;
}
}
return false;
}
public List<DBXTreeNode> getChildren(DBNNode context)
{
if (context != null && !CommonUtils.isEmpty(children)) {
boolean hasExpr = false;
for (DBXTreeNode child : children) {
if (child.getVisibleIf() != null) {
hasExpr = true;
break;
}
}
if (hasExpr) {
List<DBXTreeNode> filteredChildren = new ArrayList<>(children.size());
for (DBXTreeNode child : children) {
if (child.isVisible(context)) {
filteredChildren.add(child);
}
}
return filteredChildren;
}
}
if (children == null) {
if (recursiveLink != null) {
return recursiveLink.getChildren(context);
}
return Collections.emptyList();
}
return children;
}
private boolean isVisible(DBNNode context)
{
try {
return visibleIf == null || Boolean.TRUE.equals(visibleIf.evaluate(makeContext(context)));
} catch (JexlException e) {
log.warn(e);
return false;
}
}
public void addChild(DBXTreeNode child)
{
if (this.children == null) {
this.children = new ArrayList<>();
}
this.children.add(child);
}
public DBXTreeNode getRecursiveLink()
{
return recursiveLink;
}
public DBPImage getDefaultIcon()
{
return defaultIcon;
}
public void setDefaultIcon(DBPImage defaultIcon)
{
this.defaultIcon = defaultIcon;
}
public List<DBXTreeIcon> getIcons()
{
return icons;
}
public void addIcon(DBXTreeIcon icon)
{
if (this.icons == null) {
this.icons = new ArrayList<>();
}
this.icons.add(icon);
}
public DBPImage getIcon(DBNNode context)
{
List<DBXTreeIcon> extIcons = getIcons();
if (!CommonUtils.isEmpty(extIcons)) {
// Try to get some icon depending on it's condition
for (DBXTreeIcon icon : extIcons) {
if (icon.getExpression() == null) {
continue;
}
try {
Object result = icon.getExpression().evaluate(makeContext(context));
if (Boolean.TRUE.equals(result)) {
return icon.getIcon();
}
} catch (JexlException e) {
// do nothing
log.debug("Error evaluating expression '" + icon.getExprString() + "'", e);
}
}
}
return getDefaultIcon();
}
public Expression getVisibleIf()
{
return visibleIf;
}
public void addActionHandler(DBXTreeNodeHandler.Action action, DBXTreeNodeHandler.Perform perform, String command) {
if (handlers == null) {
handlers = new ArrayList<>();
}
handlers.add(new DBXTreeNodeHandler(action, perform, command));
}
public DBXTreeNodeHandler getHandler(DBXTreeNodeHandler.Action action) {
if (handlers != null) {
for (DBXTreeNodeHandler handler : handlers) {
if (handler.getAction() == action) {
return handler;
}
}
}
return null;
}
private static JexlContext makeContext(final DBNNode node)
{
return new JexlContext() {
@Override
public Object get(String name)
{
if (node instanceof DBNDatabaseNode && name.equals("object")) {
return ((DBNDatabaseNode) node).getValueObject();
}
return null;
}
@Override
public void set(String name, Object value)
{
log.warn("Set is not implemented in DBX model");
}
@Override
public boolean has(String name)
{
return node instanceof DBNDatabaseNode && name.equals("object")
&& ((DBNDatabaseNode) node).getValueObject() != null;
}
};
}
}