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