1 /*******************************************************************************
2 * Copyright (c) 2011, 2012 Ericsson
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Mathieu Denis <mathieu.denis@polymtl.ca> - Implementation and Initial API
12 *******************************************************************************/
14 package org
.eclipse
.linuxtools
.tmf
.ui
.viewers
.statistics
.model
;
16 import java
.util
.Arrays
;
17 import java
.util
.HashMap
;
18 import java
.util
.HashSet
;
19 import java
.util
.LinkedList
;
20 import java
.util
.List
;
25 * Base class for the statistics storage. It allow to implement a tree structure
26 * while avoiding the need to run through the tree each time you need to add a
27 * node at a given place.
29 * @author Mathieu Denis
33 public class TmfStatisticsTree
{
36 * Identification of the root.
38 public static final String
[] ROOT
= new String
[] { "root" }; //$NON-NLS-1$
41 * Header for the event type categories.
43 public static final String HEADER_EVENT_TYPES
= Messages
.TmfStatisticsData_EventTypes
;
46 * Indicate that it's a value.
48 * Used when checking the possible child node for a node.
50 * It differentiate a category of a value by being appended to a value.
52 protected static final String NODE
= "z"; //$NON-NLS-1$
57 protected static final String ROOT_NODE_KEY
= mergeString(ROOT
[0], NODE
);
60 * Define what children a node can have. The management and usage of this map
61 * is done by subclasses. HashSet are always faster than TreeSet for String keys.
63 protected Map
<String
, Set
<String
>> fKeys
;
66 * The nodes in the tree.
68 protected Map
<List
<String
>, TmfStatisticsTreeNode
> fNodes
;
71 * Default constructor. Creates base statistics tree for counting total
72 * number of events and number of events per event type.
74 public TmfStatisticsTree() {
75 fNodes
= new HashMap
<List
<String
>, TmfStatisticsTreeNode
>();
76 fKeys
= new HashMap
<String
, Set
<String
>>();
78 Map
<String
, Set
<String
>> keys
= getKeys();
80 // //////////// Adding category sets
82 keys
.put(HEADER_EVENT_TYPES
, new HashSet
<String
>());
84 // /////////// Adding value sets
86 Set
<String
> temp
= new HashSet
<String
>(8);
87 temp
.add(HEADER_EVENT_TYPES
);
88 keys
.put(ROOT_NODE_KEY
, temp
);
89 // Under an event type
90 temp
= new HashSet
<String
>(16);
91 keys
.put(mergeString(HEADER_EVENT_TYPES
, NODE
), temp
);
93 // //////////// CREATE root
94 keys
.put(ROOT
[0], new HashSet
<String
>(2)); // 1 trace at the time
103 * @return The node or null.
105 public TmfStatisticsTreeNode
get(String
... path
) {
106 List
<String
> pathAsList
= Arrays
.asList(path
);
107 return fNodes
.get(pathAsList
);
111 * Get the children of a node.
115 * @return Collection containing the children.
117 public List
<TmfStatisticsTreeNode
> getChildren(String
... path
) {
118 List
<TmfStatisticsTreeNode
> result
= new LinkedList
<TmfStatisticsTreeNode
>();
120 if (path
.length
% 2 == 0) { // if we are at a Category
121 TmfStatisticsTreeNode current
= null;
122 for (String value
: getKeys().get(path
[path
.length
- 1])) {
123 current
= get(addToArray(path
, value
));
124 if (current
!= null) {
125 if (current
.getValues().getTotal() > 0 || current
.getValues().getPartial() > 0) {
130 } else if (path
.length
== 1) { // Special case.
131 if (path
.equals(ROOT
)) {
132 for (String value
: getKeys().get(ROOT
[0])) {
133 result
.add(getOrCreate(value
));
136 // Get value under the root
137 for (String value
: getKeys().get(ROOT_NODE_KEY
)) {
138 result
.add(getOrCreate(addToArray(path
, value
)));
141 } else {// If we are at a value
142 for (String value
: getKeys().get(mergeString(path
[path
.length
- 2], NODE
))) {
143 // Search the parent name + NODE
144 result
.add(getOrCreate(addToArray(path
, value
)));
152 * Get every children of a node, even if it doesn't have any registered
153 * events, as opposed to getChildren
157 * @return Collection containing all the children.
159 public List
<TmfStatisticsTreeNode
> getAllChildren(String
... path
) {
160 LinkedList
<TmfStatisticsTreeNode
> result
= new LinkedList
<TmfStatisticsTreeNode
>();
162 if (path
.length
% 2 == 0) { // if we are at a Category
163 TmfStatisticsTreeNode current
= null;
164 for (String value
: getKeys().get(path
[path
.length
- 1])) {
165 current
= get(addToArray(path
, value
));
166 if (current
!= null) {
170 } else if (path
.length
== 1) { // Special case.
171 if (path
.equals(ROOT
)) {
172 for (String value
: getKeys().get(ROOT
[0])) {
173 result
.add(getOrCreate(value
));
176 // Get value under the root
177 for (String value
: getKeys().get(ROOT_NODE_KEY
)) {
178 result
.add(getOrCreate(addToArray(path
, value
)));
181 } else {// If we are at a value
182 for (String value
: getKeys().get(mergeString(path
[path
.length
- 2], NODE
))) {
183 // Search the parent name + NODE
184 result
.add(getOrCreate(addToArray(path
, value
)));
191 * Get the map of existing elements of path classified by parent.
195 public Map
<String
, Set
<String
>> getKeys() {
200 * Get or create a node.
206 public TmfStatisticsTreeNode
getOrCreate(String
... path
) {
207 List
<String
> pathAsList
= Arrays
.asList(path
);
208 TmfStatisticsTreeNode current
= fNodes
.get(pathAsList
);
210 if (current
== null) {
212 current
= new TmfStatisticsTreeNode(this, path
);
213 fNodes
.put(pathAsList
, current
);
219 * Get the parent of a node.
223 * @return Parent node or null.
225 public TmfStatisticsTreeNode
getParent(final String
... path
) {
226 if (path
.length
== 1) {
227 if (path
.equals(ROOT
)) {
233 String
[] parentPath
= new String
[path
.length
- 1];
234 System
.arraycopy(path
, 0, parentPath
, 0, parentPath
.length
);
235 return get(parentPath
);
239 * Set the value to display in the "total" cells. This means the row
240 * indicating the total count of events for a trace.
243 * The name of the trace (will be used as a sub-tree in the view)
245 * Is this a for a global or a time range request? Determines if
246 * this goes in the Global column or the Selected Time Range one.
248 * The value to display
250 public void setTotal(String traceName
, boolean isGlobal
, long qty
) {
251 String
[][] paths
= getNormalPaths(traceName
);
252 for (String path
[] : paths
) {
253 getOrCreate(path
).getValues().setValue(isGlobal
, qty
);
258 * Set the value to display in the "Type count" cells. These are the counts
259 * for each event types.
262 * The name of the trace (will be used as a sub-tree in the view)
266 * Is this a for a global or a time range request? Determines if
267 * this goes in the Global column or the Selected Time Range one.
269 * The value to display
271 public void setTypeCount(String traceName
, String type
, boolean isGlobal
, long qty
) {
272 String
[][] paths
= getTypePaths(traceName
, type
);
273 for (String
[] path
: paths
) {
274 getOrCreate(path
).getValues().setValue(isGlobal
, qty
);
279 * Get the event types paths.
282 * Event to get the path for.
284 * Extra information to pass along with the event
285 * @return Array of FixedArray representing the paths.
287 protected String
[][] getTypePaths(String traceName
, String type
) {
288 String
[][] paths
= { new String
[] {traceName
, HEADER_EVENT_TYPES
, type
} };
293 * Get the standard paths for an event.
296 * Event to get the path for.
298 * Extra information to pass along with the event
299 * @return Array of FixedArray representing the paths.
301 protected String
[][] getNormalPaths(String traceName
) {
302 String
[][] paths
= { new String
[] { traceName
} };
307 * Register that a new node was created.
309 * Must make sure the {@link #getChildren(TmfFixedArray)} on the parent node
310 * will return the newly created node.
313 * Path of the new node.
315 protected void registerName(String
... path
) {
316 if (path
.length
== 1) {
317 if (!path
.equals(ROOT
)) {
318 getKeys().get(ROOT
[0]).add(path
[0]);
320 } else if (path
.length
% 2 != 0) {
321 getKeys().get(path
[path
.length
- 2]).add(path
[path
.length
- 1]);
333 public void reset(final String
... path
) {
334 for (TmfStatisticsTreeNode node
: getAllChildren(path
)) {
335 reset(node
.getPath());
336 List
<String
> nodePathList
= Arrays
.asList(node
.getPath());
337 fNodes
.remove(nodePathList
);
342 * Reset the global value of a node.
350 public void resetGlobalValue(final String
... path
) {
351 for (TmfStatisticsTreeNode node
: getChildren(path
)) {
352 node
.resetGlobalValue();
357 * Reset the time range value of a node.
365 public void resetTimeRangeValue(final String
... path
) {
366 for (TmfStatisticsTreeNode node
: getChildren(path
)) {
367 node
.resetTimeRangeValue();
372 * Function to merge many string more efficiently.
376 * @return A new string containing all the strings.
378 protected static String
mergeString(String
... strings
) {
379 StringBuilder builder
= new StringBuilder();
380 for (String s
: strings
) {
383 return builder
.toString();
387 * Return a new array that's a copy of the old one, plus 'newElem' added at
390 private static String
[] addToArray(String
[] array
, String newElem
) {
391 String
[] newArray
= new String
[array
.length
+ 1];
392 System
.arraycopy(array
, 0, newArray
, 0, array
.length
);
393 newArray
[array
.length
] = newElem
;