tmf: Avoid HistoryTree to expose its internal HT_IO node.
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / internal / tmf / core / statesystem / AttributeTree.java
1 /*******************************************************************************
2 * Copyright (c) 2012, 2013 Ericsson
3 * Copyright (c) 2010, 2011 École Polytechnique de Montréal
4 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
5 *
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
10 *
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.internal.tmf.core.statesystem;
14
15 import java.io.*;
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.Collections;
19 import java.util.List;
20
21 import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
22 import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
23 import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
24 import org.eclipse.linuxtools.tmf.core.statevalue.TmfStateValue;
25
26 /**
27 * The Attribute Tree is the /proc-like filesystem used to organize attributes.
28 * Each node of this tree is both like a file and a directory in the
29 * "file system".
30 *
31 * @author alexmont
32 *
33 */
34 public final class AttributeTree {
35
36 /* "Magic number" for attribute tree files or file sections */
37 private static final int ATTRIB_TREE_MAGIC_NUMBER = 0x06EC3671;
38
39 private final StateSystem ss;
40 private final List<Attribute> attributeList;
41 private final Attribute attributeTreeRoot;
42
43 /**
44 * Standard constructor, create a new empty Attribute Tree
45 *
46 * @param ss
47 * The StateSystem to which this AT is attached
48 */
49 AttributeTree(StateSystem ss) {
50 this.ss = ss;
51 this.attributeList = Collections.synchronizedList(new ArrayList<Attribute>());
52 this.attributeTreeRoot = new AlphaNumAttribute(null, "root", -1); //$NON-NLS-1$
53 }
54
55 /**
56 * "Existing file" constructor. Builds an attribute tree from a
57 * "mapping file" or mapping section previously saved somewhere.
58 *
59 * @param ss
60 * StateSystem to which this AT is attached
61 * @param fis
62 * File stream where to read the AT information. Make sure it's
63 * sought at the right place!
64 * @throws IOException
65 */
66 AttributeTree(StateSystem ss, FileInputStream fis) throws IOException {
67 this(ss);
68 DataInputStream in = new DataInputStream(new BufferedInputStream(fis));
69
70 /* Message for exceptions, shouldn't be externalized */
71 final String errorMessage = "The attribute tree file section is either invalid or corrupted."; //$NON-NLS-1$
72
73 ArrayList<String[]> list = new ArrayList<String[]>();
74 byte[] curByteArray;
75 String curFullString;
76 String[] curStringArray;
77 int res, remain, size;
78 int expectedSize = 0;
79 int total = 0;
80
81 /* Read the header of the Attribute Tree file (or file section) */
82 res = in.readInt(); /* Magic number */
83 if (res != ATTRIB_TREE_MAGIC_NUMBER) {
84 throw new IOException(errorMessage);
85 }
86
87 /* Expected size of the section */
88 expectedSize = in.readInt();
89 if (expectedSize <= 12) {
90 throw new IOException(errorMessage);
91 }
92
93 /* How many entries we have to read */
94 remain = in.readInt();
95 total += 12;
96
97 /* Read each entry */
98 for (; remain > 0; remain--) {
99 /* Read the first byte = the size of the entry */
100 size = in.readByte();
101 curByteArray = new byte[size];
102 res = in.read(curByteArray);
103 if (res != size) {
104 throw new IOException(errorMessage);
105 }
106
107 /*
108 * Go buffer -> byteArray -> String -> String[] -> insert in list.
109 * bleh
110 */
111 curFullString = new String(curByteArray);
112 curStringArray = curFullString.split("/"); //$NON-NLS-1$
113 list.add(curStringArray);
114
115 /* Read the 0'ed confirmation byte */
116 res = in.readByte();
117 if (res != 0) {
118 throw new IOException(errorMessage);
119 }
120 total += curByteArray.length + 2;
121 }
122
123 if (total != expectedSize) {
124 throw new IOException(errorMessage);
125 }
126
127 /*
128 * Now we have 'list', the ArrayList of String arrays representing all
129 * the attributes. Simply create attributes the normal way from them.
130 */
131 for (String[] attrib : list) {
132 this.getQuarkAndAdd(-1, attrib);
133 }
134 }
135
136 /**
137 * Tell the Attribute Tree to write itself somewhere. The passed
138 * FileOutputStream defines where (which file/position).
139 *
140 * @param fos
141 * Where to write. Make sure it's sought at the right position
142 * you want.
143 * @return The total number of bytes written.
144 */
145 int writeSelf(File file, long pos) {
146 RandomAccessFile raf = null;
147 int total = 0;
148 byte[] curByteArray;
149
150 try {
151 raf = new RandomAccessFile(file, "rw"); //$NON-NLS-1$
152 raf.seek(pos);
153
154 /* Write the almost-magic number */
155 raf.writeInt(ATTRIB_TREE_MAGIC_NUMBER);
156
157 /* Placeholder for the total size of the section... */
158 raf.writeInt(-8000);
159
160 /* Write the number of entries */
161 raf.writeInt(this.attributeList.size());
162 total += 12;
163
164 /* Write the attributes themselves */
165 for (Attribute entry : this.attributeList) {
166 curByteArray = entry.getFullAttributeName().getBytes();
167 if (curByteArray.length > Byte.MAX_VALUE) {
168 throw new IOException("Attribute with name \"" //$NON-NLS-1$
169 + Arrays.toString(curByteArray) + "\" is too long."); //$NON-NLS-1$
170 }
171 /* Write the first byte = size of the array */
172 raf.writeByte((byte) curByteArray.length);
173
174 /* Write the array itself */
175 raf.write(curByteArray);
176
177 /* Write the 0'ed byte */
178 raf.writeByte((byte) 0);
179
180 total += curByteArray.length + 2;
181 }
182
183 /* Now go back and write the actual size of this section */
184 raf.seek(pos + 4);
185 raf.writeInt(total);
186
187 } catch (IOException e) {
188 e.printStackTrace();
189 } finally {
190 if (raf != null) {
191 try {
192 raf.close();
193 } catch (IOException e) {
194 e.printStackTrace();
195 }
196 }
197 }
198 return total;
199 }
200
201 /**
202 * Return the number of attributes this system as seen so far. Note that
203 * this also equals the integer value (quark) the next added attribute will
204 * have.
205 *
206 * @return
207 */
208 int getNbAttributes() {
209 return attributeList.size();
210 }
211
212 /**
213 * This is the version to specifically add missing attributes.
214 *
215 * If 'numericalNode' is true, all the new attributes created will be of
216 * type 'NumericalNode' instead of 'AlphaNumNode'. Be careful with this, if
217 * you do not want ALL added attributes to be numerical, call this function
218 * first with 'false' to create the parent nodes, then call it again to make
219 * sure only the final node is numerical.
220 *
221 * @throws AttributeNotFoundException
222 */
223 int getQuarkDontAdd(int startingNodeQuark, String... subPath)
224 throws AttributeNotFoundException {
225 assert (startingNodeQuark >= -1);
226
227 Attribute prevNode;
228
229 /* If subPath is empty, simply return the starting quark */
230 if (subPath == null || subPath.length == 0) {
231 return startingNodeQuark;
232 }
233
234 /* Get the "starting node" */
235 if (startingNodeQuark == -1) {
236 prevNode = attributeTreeRoot;
237 } else {
238 prevNode = attributeList.get(startingNodeQuark);
239 }
240
241 int knownQuark = prevNode.getSubAttributeQuark(subPath);
242 if (knownQuark == -1) {
243 /*
244 * The attribute doesn't exist, but we have been specified to NOT
245 * add any new attributes.
246 */
247 throw new AttributeNotFoundException();
248 }
249 /*
250 * The attribute was already existing, return the quark of that
251 * attribute
252 */
253 return knownQuark;
254 }
255
256 // FIXME synchronized here is probably quite costly... maybe only locking
257 // the "for" would be enough?
258 synchronized int getQuarkAndAdd(int startingNodeQuark, String... subPath) {
259 assert (subPath != null && subPath.length > 0);
260 assert (startingNodeQuark >= -1);
261
262 Attribute nextNode = null;
263 Attribute prevNode;
264
265 /* Get the "starting node" */
266 if (startingNodeQuark == -1) {
267 prevNode = attributeTreeRoot;
268 } else {
269 prevNode = attributeList.get(startingNodeQuark);
270 }
271
272 int knownQuark = prevNode.getSubAttributeQuark(subPath);
273 if (knownQuark == -1) {
274 /*
275 * The attribute was not in the table previously, and we want to add
276 * it
277 */
278 for (String curDirectory : subPath) {
279 nextNode = prevNode.getSubAttributeNode(curDirectory);
280 if (nextNode == null) {
281 /* This is where we need to start adding */
282 nextNode = new AlphaNumAttribute(prevNode, curDirectory,
283 attributeList.size());
284 prevNode.addSubAttribute(nextNode);
285 attributeList.add(nextNode);
286 ss.addEmptyAttribute();
287 }
288 prevNode = nextNode;
289 }
290 /*
291 * Insert an initial null value for this attribute in the state
292 * system (in case the state provider doesn't set one).
293 */
294 final int newAttrib = attributeList.size() - 1;
295 try {
296 ss.modifyAttribute(ss.getStartTime(), TmfStateValue.nullValue(), newAttrib);
297 } catch (TimeRangeException e) {
298 /* Should not happen, we're inserting at ss's start time */
299 throw new IllegalStateException(e);
300 } catch (AttributeNotFoundException e) {
301 /* Should not happen, we just created this attribute! */
302 throw new IllegalStateException(e);
303 } catch (StateValueTypeException e) {
304 /* Should not happen, there is no existing state value, and the
305 * one we insert is a null value anyway. */
306 throw new IllegalStateException(e);
307 }
308
309 return newAttrib;
310 }
311 /*
312 * The attribute was already existing, return the quark of that
313 * attribute
314 */
315 return knownQuark;
316 }
317
318 int getSubAttributesCount(int quark) {
319 return attributeList.get(quark).getSubAttributes().size();
320 }
321
322 /**
323 * Returns the sub-attributes of the quark passed in parameter
324 *
325 * @param attributeQuark
326 * @param recursive
327 * @return
328 * @throws AttributeNotFoundException
329 */
330 List<Integer> getSubAttributes(int attributeQuark, boolean recursive)
331 throws AttributeNotFoundException {
332 List<Integer> listOfChildren = new ArrayList<Integer>();
333 Attribute startingAttribute;
334
335 /* Check if the quark is valid */
336 if (attributeQuark < -1 || attributeQuark >= attributeList.size()) {
337 throw new AttributeNotFoundException();
338 }
339
340 /* Set up the node from which we'll start the search */
341 if (attributeQuark == -1) {
342 startingAttribute = attributeTreeRoot;
343 } else {
344 startingAttribute = attributeList.get(attributeQuark);
345 }
346
347 /* Iterate through the sub-attributes and add them to the list */
348 addSubAttributes(listOfChildren, startingAttribute, recursive);
349
350 return listOfChildren;
351 }
352
353 private void addSubAttributes(List<Integer> list, Attribute curAttribute,
354 boolean recursive) {
355 for (Attribute childNode : curAttribute.getSubAttributes()) {
356 list.add(childNode.getQuark());
357 if (recursive) {
358 addSubAttributes(list, childNode, true);
359 }
360 }
361 }
362
363 String getAttributeName(int quark) {
364 return attributeList.get(quark).getName();
365 }
366
367 String getFullAttributeName(int quark) {
368 if (quark >= attributeList.size() || quark < 0) {
369 return null;
370 }
371 return attributeList.get(quark).getFullAttributeName();
372 }
373
374 void debugPrint(PrintWriter writer) {
375 attributeTreeRoot.debugPrint(writer);
376 }
377
378 }
This page took 0.039422 seconds and 5 git commands to generate.