1 /*******************************************************************************
2 * Copyright (c) 2012, 2015 Ericsson, EfficiOS Inc.
3 * Copyright (c) 2010, 2011 École Polytechnique de Montréal
4 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
6 * All rights reserved. This program and the accompanying materials are
7 * made available under the terms of the Eclipse Public License v1.0 which
8 * accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
12 * Alexandre Montplaisir - Initial API and implementation
13 *******************************************************************************/
15 package org
.eclipse
.tracecompass
.internal
.statesystem
.core
;
17 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
18 import static org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystem
.INVALID_ATTRIBUTE
;
20 import java
.io
.PrintWriter
;
21 import java
.util
.Collections
;
22 import java
.util
.LinkedHashMap
;
23 import java
.util
.LinkedList
;
26 import org
.eclipse
.jdt
.annotation
.NonNull
;
27 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystem
;
29 import com
.google
.common
.collect
.ImmutableList
;
32 * An Attribute is a "node" in the Attribute Tree. It represents a smallest
33 * unit of the model which can be in a particular state at a given time.
35 * It is abstract, as different implementations can provide different ways to
36 * access sub-attributes
38 * @author Alexandre Montplaisir
41 public final class Attribute
{
43 private final Attribute parent
;
44 private final @NonNull String name
;
45 private final int quark
;
47 /** The sub-attributes (<basename, attribute>) of this attribute */
48 private final Map
<String
, Attribute
> subAttributes
;
54 * The parent attribute of this one. Can be 'null' to represent
55 * this attribute is the root node of the tree.
57 * Base name of this attribute
59 * The integer representation of this attribute
61 public Attribute(Attribute parent
, @NonNull String name
, int quark
) {
65 this.subAttributes
= Collections
.synchronizedMap(new LinkedHashMap
<String
, Attribute
>());
68 // ------------------------------------------------------------------------
70 // ------------------------------------------------------------------------
73 * Get the quark (integer representation) of this attribute.
75 * @return The quark of this attribute
77 public int getQuark() {
82 * Get the name of this attribute.
84 * @return The name of this attribute
86 public @NonNull String
getName() {
91 * Get the list of child attributes below this one.
93 * @return The child attributes.
95 public Iterable
<Attribute
> getSubAttributes() {
96 return ImmutableList
.copyOf(subAttributes
.values());
100 * Get the matching quark for a given path-of-strings
103 * The path we are looking for, *relative to this node*.
104 * @return The matching quark, or {@link ITmfStateSystem#INVALID_ATTRIBUTE}
105 * if that attribute does not exist.
107 public int getSubAttributeQuark(String
... path
) {
108 return this.getSubAttributeQuark(path
, 0);
112 * Other method to search through the attribute tree, but instead of
113 * returning the matching quark we return the AttributeTreeNode object
114 * itself. It can then be used as new "root node" for faster queries on the
118 * The target path, *relative to this node*
119 * @return The Node object matching the last element in the path, or "null"
120 * if that attribute does not exist.
122 public Attribute
getSubAttributeNode(String
... path
) {
123 return this.getSubAttributeNode(path
, 0);
127 * "Inner" part of the previous public method, which is used recursively. To
128 * avoid having to copy sub-arrays to pass down, we just track where we are
129 * at with the index parameter. It uses getSubAttributeNode(), whose
130 * implementation is left to the derived classes.
132 private int getSubAttributeQuark(String
[] path
, int index
) {
133 Attribute targetNode
= this.getSubAttributeNode(path
, index
);
134 if (targetNode
== null) {
135 return INVALID_ATTRIBUTE
;
137 return targetNode
.getQuark();
141 * Get the parent attribute of this attribute
143 * @return The parent attribute
145 public Attribute
getParentAttribute() {
150 * Get the parent quark of this attribute
152 * @return The quark of the parent attribute
154 public int getParentAttributeQuark() {
155 return this.parent
.getQuark();
158 /* The methods how to access children are left to derived classes */
161 * Add a sub-attribute to this attribute
163 * @param newSubAttribute The new attribute to add
165 public void addSubAttribute(Attribute newSubAttribute
) {
166 if (newSubAttribute
== null) {
167 throw new IllegalArgumentException();
169 subAttributes
.put(newSubAttribute
.getName(), newSubAttribute
);
173 * Get a sub-attribute from this node's sub-attributes
176 * The *full* path to the attribute
178 * The index in 'path' where this attribute is located
179 * (indicating where to start searching).
180 * @return The requested attribute
182 private Attribute
getSubAttributeNode(String
[] path
, int index
) {
183 final Attribute nextNode
= subAttributes
.get(path
[index
]);
185 if (nextNode
== null) {
186 /* We don't have the expected child => the attribute does not exist */
189 if (index
== path
.length
- 1) {
190 /* It's our job to process this request */
194 /* Pass on the rest of the path to the relevant child */
195 return nextNode
.getSubAttributeNode(path
, index
+ 1);
199 * Return a String array composed of the full (absolute) path representing
202 * @return The full attribute path elements
204 public String
@NonNull [] getFullAttribute() {
205 LinkedList
<String
> list
= new LinkedList
<>();
206 Attribute curNode
= this;
208 /* Add recursive parents to the list, but stop at the root node */
209 while (curNode
.parent
!= null) {
210 list
.addFirst(curNode
.getName());
211 curNode
= curNode
.parent
;
214 return list
.toArray(new String
[0]);
218 * Return the absolute path of this attribute, as a single slash-separated
221 * @return The full name of this attribute
223 public @NonNull String
getFullAttributeName() {
224 String
[] array
= this.getFullAttribute();
225 StringBuffer buf
= new StringBuffer();
227 for (int i
= 0; i
< array
.length
- 1; i
++) {
228 buf
.append(array
[i
]);
231 buf
.append(array
[array
.length
- 1]);
232 return checkNotNull(buf
.toString());
236 public String
toString() {
237 return getFullAttributeName() + " (" + quark
+ ')'; //$NON-NLS-1$
240 private int curDepth
;
242 private void attributeNodeToString(PrintWriter writer
, Attribute currentNode
) {
243 writer
.println(currentNode
.getName() + " (" + currentNode
.quark
+ ')'); //$NON-NLS-1$
246 for (Attribute nextNode
: currentNode
.getSubAttributes()) {
247 /* Skip printing 'null' entries */
248 if (nextNode
== null) {
251 for (int j
= 0; j
< curDepth
- 1; j
++) {
252 writer
.print(" "); //$NON-NLS-1$
254 writer
.print(" "); //$NON-NLS-1$
255 attributeNodeToString(writer
, nextNode
);
262 * Debugging method to print the contents of this attribute
265 * PrintWriter where to write the information
267 public void debugPrint(PrintWriter writer
) {
268 /* Only used for debugging, shouldn't be externalized */
269 writer
.println("------------------------------"); //$NON-NLS-1$
270 writer
.println("Attribute tree: (quark)\n"); //$NON-NLS-1$
272 attributeNodeToString(writer
, this);