1 /*******************************************************************************
2 * Copyright (c) 2012, 2014 Ericsson
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
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.internal
.tmf
.core
.statesystem
;
15 import java
.io
.PrintWriter
;
16 import java
.util
.ArrayList
;
17 import java
.util
.Collections
;
18 import java
.util
.HashMap
;
19 import java
.util
.LinkedList
;
20 import java
.util
.List
;
24 * An Attribute is a "node" in the Attribute Tree. It represents a smallest
25 * unit of the model which can be in a particular state at a given time.
27 * It is abstract, as different implementations can provide different ways to
28 * access sub-attributes
33 public abstract class Attribute
{
35 private final Attribute parent
;
36 private final String name
;
37 private final int quark
;
39 /** The list of sub-attributes */
40 protected final List
<Attribute
> subAttributes
;
46 * The parent attribute of this one. Can be 'null' to represent
47 * this attribute is the root node of the tree.
49 * Base name of this attribute
51 * The integer representation of this attribute
53 public Attribute(Attribute parent
, String name
, int quark
) {
57 this.subAttributes
= new ArrayList
<>();
60 // ------------------------------------------------------------------------
62 // ------------------------------------------------------------------------
65 * Get the quark (integer representation) of this attribute.
67 * @return The quark of this attribute
69 public int getQuark() {
74 * Get the name of this attribute.
76 * @return The name of this attribute
78 public String
getName() {
83 * Get the list of child attributes below this one. This is a read-only
86 * @return The list of child attributes.
88 public List
<Attribute
> getSubAttributes() {
89 return Collections
.unmodifiableList(subAttributes
);
93 * Get the matching quark for a given path-of-strings
96 * The path we are looking for, *relative to this node*.
97 * @return The matching quark, or -1 if that attribute does not exist.
99 public int getSubAttributeQuark(String
... path
) {
100 return this.getSubAttributeQuark(path
, 0);
104 * Other method to search through the attribute tree, but instead of
105 * returning the matching quark we return the AttributeTreeNode object
106 * itself. It can then be used as new "root node" for faster queries on the
110 * The target path, *relative to this node*
111 * @return The Node object matching the last element in the path, or "null"
112 * if that attribute does not exist.
114 public Attribute
getSubAttributeNode(String
... path
) {
115 return this.getSubAttributeNode(path
, 0);
119 * "Inner" part of the previous public method, which is used recursively. To
120 * avoid having to copy sub-arrays to pass down, we just track where we are
121 * at with the index parameter. It uses getSubAttributeNode(), whose
122 * implementation is left to the derived classes.
124 private int getSubAttributeQuark(String
[] path
, int index
) {
125 Attribute targetNode
= this.getSubAttributeNode(path
, index
);
126 if (targetNode
== null) {
129 return targetNode
.getQuark();
133 * Get the parent attribute of this attribute
135 * @return The parent attribute
137 public Attribute
getParentAttribute() {
142 * Get the parent quark of this attribute
144 * @return The quark of the parent attribute
146 public int getParentAttributeQuark() {
147 return this.parent
.getQuark();
150 /* The methods how to access children are left to derived classes */
153 * Add a sub-attribute to this attribute
155 * @param newSubAttribute The new attribute to add
157 protected abstract void addSubAttribute(Attribute newSubAttribute
);
160 * Get a sub-attribute from this node's sub-attributes
163 * The *full* path to the attribute
165 * The index in 'path' where this attribute is located
166 * (indicating where to start searching).
167 * @return The requested attribute
169 protected abstract Attribute
getSubAttributeNode(String
[] path
, int index
);
172 * Return a String array composed of the full (absolute) path representing
177 private String
[] getFullAttribute() {
178 LinkedList
<String
> list
= new LinkedList
<>();
179 Attribute curNode
= this;
181 /* Add recursive parents to the list, but stop at the root node */
182 while (curNode
.parent
!= null) {
183 list
.addFirst(curNode
.getName());
184 curNode
= curNode
.parent
;
187 return list
.toArray(new String
[0]);
191 * Return the absolute path of this attribute, as a single slash-separated
194 * @return The full name of this attribute
196 public String
getFullAttributeName() {
197 String
[] array
= this.getFullAttribute();
198 StringBuffer buf
= new StringBuffer();
200 for (int i
= 0; i
< array
.length
- 1; i
++) {
201 buf
.append(array
[i
]);
204 buf
.append(array
[array
.length
- 1]);
205 return buf
.toString();
209 public String
toString() {
210 return getFullAttributeName() + " (" + quark
+ ')'; //$NON-NLS-1$
213 private int curDepth
;
215 private void attributeNodeToString(PrintWriter writer
, Attribute currentNode
) {
218 writer
.println(currentNode
.getName() + " (" + currentNode
.quark
+ ')'); //$NON-NLS-1$
221 for (Attribute nextNode
: currentNode
.getSubAttributes()) {
222 /* Skip printing 'null' entries */
223 if (nextNode
== null) {
226 for (j
= 0; j
< curDepth
- 1; j
++) {
227 writer
.print(" "); //$NON-NLS-1$
229 writer
.print(" "); //$NON-NLS-1$
230 attributeNodeToString(writer
, nextNode
);
237 * Debugging method to print the contents of this attribute
240 * PrintWriter where to write the information
242 public void debugPrint(PrintWriter writer
) {
243 /* Only used for debugging, shouldn't be externalized */
244 writer
.println("------------------------------"); //$NON-NLS-1$
245 writer
.println("Attribute tree: (quark)\n"); //$NON-NLS-1$
247 attributeNodeToString(writer
, this);
253 * This is the basic implementation, where sub-attributes names can be composed
254 * of any alphanumeric characters, and are stored as Strings. A HashMap is used
260 final class AlphaNumAttribute
extends Attribute
{
262 private final Map
<String
, Integer
> subAttributesMap
;
264 public AlphaNumAttribute(Attribute parent
, String name
, int quark
) {
265 super(parent
, name
, quark
);
266 this.subAttributesMap
= new HashMap
<>();
270 protected synchronized void addSubAttribute(Attribute newSubAttribute
) {
271 assert (newSubAttribute
!= null);
272 assert (newSubAttribute
.getName() != null);
273 /* This should catch buggy state changing statements */
274 assert (!newSubAttribute
.getName().equals(this.getName()));
276 subAttributesMap
.put(newSubAttribute
.getName(), subAttributes
.size());
277 subAttributes
.add(newSubAttribute
);
281 protected synchronized Attribute
getSubAttributeNode(String
[] path
,
283 Integer indexOfNextNode
= subAttributesMap
.get(path
[index
]);
286 if (indexOfNextNode
== null) {
287 /* We don't have the expected child => the attribute does not exist */
290 if (index
== path
.length
- 1) {
291 /* It's our job to process this request */
292 return subAttributes
.get(indexOfNextNode
);
295 nextNode
= subAttributes
.get(indexOfNextNode
);
296 return nextNode
.getSubAttributeNode(path
, index
+ 1);