blob: 4bec7ccd2986471f10aa7e7c44c5d6e36b70939e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2014 Ericsson
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Yann N. Dauphin <dhaemon@gmail.com> - Implementation for stats
* Francois Godin <copelnug@gmail.com> - Re-design for new stats structure
* Mathieu Denis <mathieu.denis@polymtl.ca> - Re-design for new stats structure (2)
* Alexandre Montplaisir - Move the tree structure logic into the nodes
*******************************************************************************/
package org.eclipse.tracecompass.internal.tmf.ui.viewers.statistics.model;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* A tree where nodes can be accessed efficiently using paths.
*
* It works like file systems. Each node is identified by a key. A path is an
* array of String. The elements of the array represent the path from the root
* to this node.
*
* @author Mathieu Denis
*/
public class TmfStatisticsTreeNode {
/** Tree to which this node belongs */
private final TmfStatisticsTree fTree;
/** Path of this node. The last element represents its basename. */
private final String[] fPath;
/** Parent node */
private final TmfStatisticsTreeNode fParent;
/** Children of this node, indexed by their basename. */
private final Map<String, TmfStatisticsTreeNode> fChildren;
/** Statistics values associated to this node. */
private final TmfStatisticsValues fValues;
/**
* Return the node at the top of the branch
*/
private final TmfStatisticsTreeNode fTopNode;
/**
* Constructor.
*
* @param tree
* Owner tree of this node
* @param parent
* Parent node of this one
* @param path
* Path to the node.
*/
public TmfStatisticsTreeNode(TmfStatisticsTree tree,
TmfStatisticsTreeNode parent, final String... path) {
/*
* The path must not contain any null element, or else we won't be able
* to walk the tree.
*/
for (String elem : path) {
if (elem == null) {
throw new IllegalArgumentException();
}
}
fTree = tree;
fPath = path;
fParent = parent;
fChildren = new ConcurrentHashMap<>();
fValues = new TmfStatisticsValues();
/* calculating top node */
TmfStatisticsTreeNode topNode = this;
while (topNode.getParent() != null && topNode.getParent().getParent() != null) {
topNode = topNode.getParent();
}
fTopNode = topNode;
}
/**
* Get the name for this node. It's used as the key in the parent's node.
*
* @return Name of this node.
*/
public String getName() {
if (fPath.length == 0) {
/* This means we are the root node, which has no path itself */
return "root"; //$NON-NLS-1$
}
return fPath[fPath.length - 1];
}
/**
* Test if a node contain the specified child.
*
* @param childName
* Name of the child.
* @return true: if child with given key is present, false: if no child
* exists with given key name
*/
public boolean containsChild(String childName) {
return fChildren.containsKey(childName);
}
/**
* Retrieve the given child from this node.
*
* @param childName
* The (base)name of the child you want
* @return The child object, or null if it doesn't exist
*/
public TmfStatisticsTreeNode getChild(String childName) {
return fChildren.get(childName);
}
/**
* Get the children of this node.
*
* @return Direct children of this node.
*/
public Collection<TmfStatisticsTreeNode> getChildren() {
return fChildren.values();
}
/**
* @param childrenName
* the name to search for
* @param recursive
* if the search should be recursive
* @return a Collection of children node (could be empty) with the same name
* as childrenName
*/
public Collection<TmfStatisticsTreeNode> findChildren(String childrenName, boolean recursive) {
if(childrenName.equals(getName())){
return Collections.singletonList(this);
}
if (fChildren.isEmpty()) {
return Collections.emptyList();
}
if (!recursive) {
if (!fChildren.containsKey(childrenName)) {
return Collections.emptyList();
}
return Collections.singletonList(fChildren.get(childrenName));
}
List<TmfStatisticsTreeNode> returnList = new LinkedList<>();
for (TmfStatisticsTreeNode node : fChildren.values()) {
returnList.addAll(node.findChildren(childrenName, true));
}
return returnList;
}
/**
* Add a child to this node.
*
* @param childName
* Name of the child to add
* @return The newly-created child
*/
public TmfStatisticsTreeNode addChild(String childName) {
TmfStatisticsTreeNode child;
String[] childPath = new String[fPath.length + 1];
System.arraycopy(fPath, 0, childPath, 0, fPath.length);
childPath[fPath.length] = childName;
child = new TmfStatisticsTreeNode(this.fTree, this, childPath);
fChildren.put(childName, child);
return child;
}
/**
* Get the number of children this node have.
*
* @return Number of direct children of this node.
*/
public int getNbChildren() {
return fChildren.size();
}
/**
* Return the parent node.
*
* @return Parent node.
*/
public TmfStatisticsTreeNode getParent() {
return fParent;
}
/**
* Return the top node.
*
* @return Top node.
*/
public TmfStatisticsTreeNode getTop() {
return fTopNode;
}
/**
* Get the path of the node.
*
* @return The path of the node.
*/
public String[] getPath() {
return fPath;
}
/**
* Get the value of this node.
*
* @return Value associated with this node.
*/
public TmfStatisticsValues getValues() {
return fValues;
}
/**
* Indicate if the node have children.
*
* @return True if the node has children.
*/
public boolean hasChildren() {
return (fChildren.size() > 0);
}
/**
* Start from creation time i.e. keep key and parent but new statistics and
* no children.
*/
public void reset() {
fValues.resetTotalCount();
fValues.resetPartialCount();
fChildren.clear();
}
/**
* Resets the global number of events. It doesn't remove any node and
* doesn't modify the partial event count. Works recursively.
*/
public void resetGlobalValue() {
for (TmfStatisticsTreeNode child : fChildren.values()) {
child.resetGlobalValue();
}
fValues.resetTotalCount();
}
/**
* Resets the number of events in the time range. It doesn't remove any node
* and doesn't modify the global event count. Works recursively.
*/
public void resetTimeRangeValue() {
for (TmfStatisticsTreeNode child : fChildren.values()) {
child.resetTimeRangeValue();
}
fValues.resetPartialCount();
}
@Override
public String toString() {
/* Used for debugging only */
return "Stats node, path = " + Arrays.toString(fPath) + //$NON-NLS-1$
", values = " + fValues.toString(); //$NON-NLS-1$
}
}