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