Commit | Line | Data |
---|---|---|
a52fde77 | 1 | /******************************************************************************* |
04927a83 | 2 | * Copyright (c) 2012, 2015 Ericsson, EfficiOS Inc. |
a52fde77 AM |
3 | * Copyright (c) 2010, 2011 École Polytechnique de Montréal |
4 | * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com> | |
cb42195c | 5 | * |
a52fde77 AM |
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 | |
cb42195c | 10 | * |
04927a83 AM |
11 | * Contributors: |
12 | * Alexandre Montplaisir - Initial API and implementation | |
a52fde77 AM |
13 | *******************************************************************************/ |
14 | ||
e894a508 | 15 | package org.eclipse.tracecompass.internal.statesystem.core; |
a52fde77 | 16 | |
04927a83 AM |
17 | import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; |
18 | ||
a52fde77 AM |
19 | import java.io.PrintWriter; |
20 | import java.util.Collections; | |
fe0b6837 | 21 | import java.util.LinkedHashMap; |
a52fde77 | 22 | import java.util.LinkedList; |
cb42195c | 23 | import java.util.Map; |
a52fde77 | 24 | |
04927a83 AM |
25 | import org.eclipse.jdt.annotation.NonNull; |
26 | ||
c3f21a07 AM |
27 | import com.google.common.collect.ImmutableList; |
28 | ||
a52fde77 AM |
29 | /** |
30 | * An Attribute is a "node" in the Attribute Tree. It represents a smallest | |
31 | * unit of the model which can be in a particular state at a given time. | |
cb42195c | 32 | * |
a52fde77 AM |
33 | * It is abstract, as different implementations can provide different ways to |
34 | * access sub-attributes | |
cb42195c | 35 | * |
04927a83 | 36 | * @author Alexandre Montplaisir |
cb42195c | 37 | * |
a52fde77 | 38 | */ |
c3f21a07 | 39 | public final class Attribute { |
a52fde77 AM |
40 | |
41 | private final Attribute parent; | |
04927a83 | 42 | private final @NonNull String name; |
a52fde77 | 43 | private final int quark; |
a6917276 | 44 | |
c3f21a07 AM |
45 | /** The sub-attributes (<basename, attribute>) of this attribute */ |
46 | private final Map<String, Attribute> subAttributes; | |
a52fde77 AM |
47 | |
48 | /** | |
49 | * Constructor | |
a6917276 AM |
50 | * |
51 | * @param parent | |
52 | * The parent attribute of this one. Can be 'null' to represent | |
53 | * this attribute is the root node of the tree. | |
54 | * @param name | |
55 | * Base name of this attribute | |
56 | * @param quark | |
57 | * The integer representation of this attribute | |
a52fde77 | 58 | */ |
04927a83 | 59 | public Attribute(Attribute parent, @NonNull String name, int quark) { |
a52fde77 AM |
60 | this.parent = parent; |
61 | this.quark = quark; | |
62 | this.name = name; | |
fe0b6837 | 63 | this.subAttributes = Collections.synchronizedMap(new LinkedHashMap<String, Attribute>()); |
a52fde77 AM |
64 | } |
65 | ||
a6917276 AM |
66 | // ------------------------------------------------------------------------ |
67 | // Accessors | |
68 | // ------------------------------------------------------------------------ | |
69 | ||
a52fde77 | 70 | /** |
a6917276 AM |
71 | * Get the quark (integer representation) of this attribute. |
72 | * | |
73 | * @return The quark of this attribute | |
a52fde77 | 74 | */ |
a6917276 | 75 | public int getQuark() { |
a52fde77 AM |
76 | return quark; |
77 | } | |
78 | ||
a6917276 AM |
79 | /** |
80 | * Get the name of this attribute. | |
81 | * | |
82 | * @return The name of this attribute | |
83 | */ | |
04927a83 | 84 | public @NonNull String getName() { |
a6917276 | 85 | return name; |
a52fde77 AM |
86 | } |
87 | ||
a6917276 | 88 | /** |
c3f21a07 | 89 | * Get the list of child attributes below this one. |
a6917276 | 90 | * |
c3f21a07 | 91 | * @return The child attributes. |
a6917276 | 92 | */ |
c3f21a07 AM |
93 | public Iterable<Attribute> getSubAttributes() { |
94 | return ImmutableList.copyOf(subAttributes.values()); | |
a52fde77 AM |
95 | } |
96 | ||
a52fde77 AM |
97 | /** |
98 | * Get the matching quark for a given path-of-strings | |
cb42195c | 99 | * |
a52fde77 AM |
100 | * @param path |
101 | * The path we are looking for, *relative to this node*. | |
102 | * @return The matching quark, or -1 if that attribute does not exist. | |
103 | */ | |
a6917276 | 104 | public int getSubAttributeQuark(String... path) { |
a52fde77 AM |
105 | return this.getSubAttributeQuark(path, 0); |
106 | } | |
107 | ||
108 | /** | |
109 | * Other method to search through the attribute tree, but instead of | |
110 | * returning the matching quark we return the AttributeTreeNode object | |
111 | * itself. It can then be used as new "root node" for faster queries on the | |
112 | * tree. | |
cb42195c | 113 | * |
a52fde77 AM |
114 | * @param path |
115 | * The target path, *relative to this node* | |
116 | * @return The Node object matching the last element in the path, or "null" | |
117 | * if that attribute does not exist. | |
118 | */ | |
a6917276 | 119 | public Attribute getSubAttributeNode(String... path) { |
a52fde77 AM |
120 | return this.getSubAttributeNode(path, 0); |
121 | } | |
122 | ||
123 | /** | |
124 | * "Inner" part of the previous public method, which is used recursively. To | |
125 | * avoid having to copy sub-arrays to pass down, we just track where we are | |
126 | * at with the index parameter. It uses getSubAttributeNode(), whose | |
127 | * implementation is left to the derived classes. | |
128 | */ | |
129 | private int getSubAttributeQuark(String[] path, int index) { | |
130 | Attribute targetNode = this.getSubAttributeNode(path, index); | |
131 | if (targetNode == null) { | |
132 | return -1; | |
133 | } | |
134 | return targetNode.getQuark(); | |
135 | } | |
136 | ||
0fdd2c45 FG |
137 | /** |
138 | * Get the parent attribute of this attribute | |
139 | * | |
140 | * @return The parent attribute | |
141 | */ | |
142 | public Attribute getParentAttribute() { | |
143 | return this.parent; | |
144 | } | |
145 | ||
146 | /** | |
147 | * Get the parent quark of this attribute | |
148 | * | |
149 | * @return The quark of the parent attribute | |
150 | */ | |
151 | public int getParentAttributeQuark() { | |
152 | return this.parent.getQuark(); | |
153 | } | |
154 | ||
a52fde77 | 155 | /* The methods how to access children are left to derived classes */ |
a6917276 AM |
156 | |
157 | /** | |
158 | * Add a sub-attribute to this attribute | |
159 | * | |
160 | * @param newSubAttribute The new attribute to add | |
161 | */ | |
c3f21a07 | 162 | public void addSubAttribute(Attribute newSubAttribute) { |
04927a83 | 163 | if (newSubAttribute == null) { |
c3f21a07 AM |
164 | throw new IllegalArgumentException(); |
165 | } | |
166 | subAttributes.put(newSubAttribute.getName(), newSubAttribute); | |
167 | } | |
a6917276 AM |
168 | |
169 | /** | |
170 | * Get a sub-attribute from this node's sub-attributes | |
171 | * | |
172 | * @param path | |
173 | * The *full* path to the attribute | |
174 | * @param index | |
175 | * The index in 'path' where this attribute is located | |
176 | * (indicating where to start searching). | |
177 | * @return The requested attribute | |
178 | */ | |
c3f21a07 AM |
179 | private Attribute getSubAttributeNode(String[] path, int index) { |
180 | final Attribute nextNode = subAttributes.get(path[index]); | |
181 | ||
182 | if (nextNode == null) { | |
183 | /* We don't have the expected child => the attribute does not exist */ | |
184 | return null; | |
185 | } | |
186 | if (index == path.length - 1) { | |
187 | /* It's our job to process this request */ | |
188 | return nextNode; | |
189 | } | |
190 | ||
191 | /* Pass on the rest of the path to the relevant child */ | |
192 | return nextNode.getSubAttributeNode(path, index + 1); | |
193 | } | |
a52fde77 AM |
194 | |
195 | /** | |
196 | * Return a String array composed of the full (absolute) path representing | |
197 | * this attribute | |
cb42195c | 198 | * |
34638411 | 199 | * @return The full attribute path elements |
a52fde77 | 200 | */ |
4c4e2816 | 201 | public String @NonNull [] getFullAttribute() { |
a4524c1b | 202 | LinkedList<String> list = new LinkedList<>(); |
a52fde77 AM |
203 | Attribute curNode = this; |
204 | ||
205 | /* Add recursive parents to the list, but stop at the root node */ | |
a6917276 | 206 | while (curNode.parent != null) { |
e2af45f9 | 207 | list.addFirst(curNode.getName()); |
a6917276 | 208 | curNode = curNode.parent; |
a52fde77 AM |
209 | } |
210 | ||
367e2932 | 211 | return list.toArray(new String[0]); |
a52fde77 AM |
212 | } |
213 | ||
214 | /** | |
215 | * Return the absolute path of this attribute, as a single slash-separated | |
216 | * String. | |
cb42195c | 217 | * |
a6917276 | 218 | * @return The full name of this attribute |
a52fde77 | 219 | */ |
04927a83 | 220 | public @NonNull String getFullAttributeName() { |
ab604305 AM |
221 | String[] array = this.getFullAttribute(); |
222 | StringBuffer buf = new StringBuffer(); | |
a52fde77 | 223 | |
a52fde77 | 224 | for (int i = 0; i < array.length - 1; i++) { |
ab604305 AM |
225 | buf.append(array[i]); |
226 | buf.append('/'); | |
a52fde77 | 227 | } |
ab604305 | 228 | buf.append(array[array.length - 1]); |
04927a83 | 229 | return checkNotNull(buf.toString()); |
a52fde77 AM |
230 | } |
231 | ||
232 | @Override | |
233 | public String toString() { | |
234 | return getFullAttributeName() + " (" + quark + ')'; //$NON-NLS-1$ | |
235 | } | |
236 | ||
237 | private int curDepth; | |
238 | ||
239 | private void attributeNodeToString(PrintWriter writer, Attribute currentNode) { | |
a52fde77 AM |
240 | writer.println(currentNode.getName() + " (" + currentNode.quark + ')'); //$NON-NLS-1$ |
241 | curDepth++; | |
242 | ||
cb42195c | 243 | for (Attribute nextNode : currentNode.getSubAttributes()) { |
a52fde77 AM |
244 | /* Skip printing 'null' entries */ |
245 | if (nextNode == null) { | |
246 | continue; | |
247 | } | |
c3f21a07 | 248 | for (int j = 0; j < curDepth - 1; j++) { |
a52fde77 AM |
249 | writer.print(" "); //$NON-NLS-1$ |
250 | } | |
251 | writer.print(" "); //$NON-NLS-1$ | |
252 | attributeNodeToString(writer, nextNode); | |
253 | } | |
254 | curDepth--; | |
255 | return; | |
256 | } | |
257 | ||
a6917276 AM |
258 | /** |
259 | * Debugging method to print the contents of this attribute | |
260 | * | |
261 | * @param writer | |
262 | * PrintWriter where to write the information | |
263 | */ | |
264 | public void debugPrint(PrintWriter writer) { | |
a52fde77 AM |
265 | /* Only used for debugging, shouldn't be externalized */ |
266 | writer.println("------------------------------"); //$NON-NLS-1$ | |
267 | writer.println("Attribute tree: (quark)\n"); //$NON-NLS-1$ | |
268 | curDepth = 0; | |
269 | attributeNodeToString(writer, this); | |
270 | writer.print('\n'); | |
271 | } | |
272 | } |