org.apache.dubbo.qos.textui.TTree Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dubbo Show documentation
Show all versions of dubbo Show documentation
The all in one project of dubbo
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.dubbo.qos.textui;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import static java.lang.System.currentTimeMillis;
import static org.apache.dubbo.common.utils.StringUtils.EMPTY_STRING;
import static org.apache.dubbo.common.utils.StringUtils.length;
import static org.apache.dubbo.common.utils.StringUtils.repeat;
/**
* tree
*/
public class TTree implements TComponent {
private static final String STEP_FIRST_CHAR = "`---";
private static final String STEP_NORMAL_CHAR = "+---";
private static final String STEP_HAS_BOARD = "| ";
private static final String STEP_EMPTY_BOARD = " ";
// should output cost or not
private final boolean isPrintCost;
// tree node
private final Node root;
// current node
private Node current;
public TTree(boolean isPrintCost, String title) {
this.root = new Node(title).markBegin().markEnd();
this.current = root;
this.isPrintCost = isPrintCost;
}
@Override
public String rendering() {
final StringBuilder treeSB = new StringBuilder();
recursive(0, true, "", root, new Callback() {
@Override
public void callback(int deep, boolean isLast, String prefix, Node node) {
final boolean hasChild = !node.children.isEmpty();
final String stepString = isLast ? STEP_FIRST_CHAR : STEP_NORMAL_CHAR;
final int stepStringLength = length(stepString);
treeSB.append(prefix).append(stepString);
int costPrefixLength = 0;
if (hasChild) {
treeSB.append('+');
}
if (isPrintCost && !node.isRoot()) {
final String costPrefix = String.format(
"[%s,%sms]",
(node.endTimestamp - root.beginTimestamp), (node.endTimestamp - node.beginTimestamp));
costPrefixLength = length(costPrefix);
treeSB.append(costPrefix);
}
try (Scanner scanner = new Scanner(new StringReader(node.data.toString()))) {
boolean isFirst = true;
while (scanner.hasNextLine()) {
if (isFirst) {
treeSB.append(scanner.nextLine()).append('\n');
isFirst = false;
} else {
treeSB.append(prefix)
.append(repeat(' ', stepStringLength))
.append(hasChild ? "|" : EMPTY_STRING)
.append(repeat(' ', costPrefixLength))
.append(scanner.nextLine())
.append(System.lineSeparator());
}
}
}
}
});
return treeSB.toString();
}
/**
* recursive visit
*/
private void recursive(int deep, boolean isLast, String prefix, Node node, Callback callback) {
callback.callback(deep, isLast, prefix, node);
if (!node.isLeaf()) {
final int size = node.children.size();
for (int index = 0; index < size; index++) {
final boolean isLastFlag = index == size - 1;
final String currentPrefix = isLast ? prefix + STEP_EMPTY_BOARD : prefix + STEP_HAS_BOARD;
recursive(deep + 1, isLastFlag, currentPrefix, node.children.get(index), callback);
}
}
}
public boolean isTop() {
return current.isRoot();
}
/**
* create a branch node
*
* @param data node data
* @return this
*/
public TTree begin(Object data) {
current = new Node(current, data);
current.markBegin();
return this;
}
public TTree begin() {
return begin(null);
}
public Object get() {
if (current.isRoot()) {
throw new IllegalStateException("current node is root.");
}
return current.data;
}
public TTree set(Object data) {
if (current.isRoot()) {
throw new IllegalStateException("current node is root.");
}
current.data = data;
return this;
}
/**
* end a branch node
*
* @return this
*/
public TTree end() {
if (current.isRoot()) {
throw new IllegalStateException("current node is root.");
}
current.markEnd();
current = current.parent;
return this;
}
/**
* tree node
*/
private static class Node {
/**
* parent node
*/
final Node parent;
/**
* node data
*/
Object data;
/**
* child nodes
*/
final List children = new ArrayList<>();
/**
* begin timestamp
*/
private long beginTimestamp;
/**
* end timestamp
*/
private long endTimestamp;
/**
* construct root node
*/
private Node(Object data) {
this.parent = null;
this.data = data;
}
/**
* construct a regular node
*
* @param parent parent node
* @param data node data
*/
private Node(Node parent, Object data) {
this.parent = parent;
this.data = data;
parent.children.add(this);
}
/**
* is the current node the root node
*
* @return true / false
*/
boolean isRoot() {
return null == parent;
}
/**
* if the current node the leaf node
*
* @return true / false
*/
boolean isLeaf() {
return children.isEmpty();
}
Node markBegin() {
beginTimestamp = currentTimeMillis();
return this;
}
Node markEnd() {
endTimestamp = currentTimeMillis();
return this;
}
}
/**
* callback interface for recursive visit
*/
private interface Callback {
void callback(int deep, boolean isLast, String prefix, Node node);
}
}