/******************************************************************************* * 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 v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * 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$ } }