tmf: fix potential bug when selecting trace types in import wizard
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / internal / tmf / core / statesystem / AttributeTree.java
CommitLineData
a52fde77 1/*******************************************************************************
11252342 2 * Copyright (c) 2012, 2013 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 *
a52fde77
AM
11 *******************************************************************************/
12
18ab1d18 13package org.eclipse.linuxtools.internal.tmf.core.statesystem;
a52fde77
AM
14
15import java.io.*;
16import java.util.ArrayList;
17import java.util.Arrays;
18import java.util.Collections;
19import java.util.List;
20
6d08acca 21import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
25e43749
AM
22import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
23import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
24import org.eclipse.linuxtools.tmf.core.statevalue.TmfStateValue;
6d08acca 25
a52fde77
AM
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".
8d1346f0 30 *
a52fde77 31 * @author alexmont
8d1346f0 32 *
a52fde77 33 */
339d27b4 34public class AttributeTree {
a52fde77
AM
35
36 /* "Magic number" for attribute tree files or file sections */
37 private final static 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
8d1346f0 45 *
a52fde77
AM
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 a attribute tree from a "mapping file"
57 * or mapping section previously saved somewhere.
8d1346f0 58 *
a52fde77
AM
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 * seeked 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$
0a9de3d2 72
a52fde77
AM
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];
ab604305
AM
102 res = in.read(curByteArray);
103 if (res != size) {
104 throw new IOException(errorMessage);
105 }
a52fde77
AM
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).
8d1346f0 139 *
a52fde77
AM
140 * @param fos
141 * Where to write. Make sure it's seeked at the right position
142 * you want.
143 * @return The total number of bytes written.
144 */
145 int writeSelf(File file, long pos) {
157906bb 146 RandomAccessFile raf = null;
a52fde77
AM
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
a52fde77
AM
187 } catch (IOException e) {
188 e.printStackTrace();
157906bb 189 } finally {
27e552b2
AM
190 if (raf != null) {
191 try {
192 raf.close();
193 } catch (IOException e) {
194 e.printStackTrace();
195 }
196 }
a52fde77
AM
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.
8d1346f0 205 *
a52fde77
AM
206 * @return
207 */
208 int getNbAttributes() {
209 return attributeList.size();
210 }
211
212 /**
213 * This is the version to specifically add missing attributes.
8d1346f0 214 *
a52fde77
AM
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.
8d1346f0 220 *
a52fde77
AM
221 * @throws AttributeNotFoundException
222 */
223 int getQuarkDontAdd(int startingNodeQuark, String... subPath)
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 */
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);
8d1346f0 286 ss.addEmptyAttribute();
a52fde77
AM
287 }
288 prevNode = nextNode;
289 }
25e43749
AM
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 RuntimeException();
300 } catch (AttributeNotFoundException e) {
301 /* Should not happen, we just created this attribute! */
302 throw new RuntimeException();
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 RuntimeException();
307 }
308
309 return newAttrib;
a52fde77
AM
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).getSubAttributesList().size();
320 }
321
0a9de3d2
AM
322 /**
323 * Returns the sub-attributes of the quark passed in parameter
8d1346f0 324 *
0a9de3d2 325 * @param attributeQuark
c66426fd 326 * @param recursive
0a9de3d2
AM
327 * @return
328 * @throws AttributeNotFoundException
329 */
c66426fd 330 List<Integer> getSubAttributes(int attributeQuark, boolean recursive)
0a9de3d2
AM
331 throws AttributeNotFoundException {
332 List<Integer> listOfChildren = new ArrayList<Integer>();
333 Attribute startingAttribute;
c66426fd 334
0a9de3d2 335 /* Check if the quark is valid */
f94a0bac 336 if (attributeQuark < -1 || attributeQuark >= attributeList.size()) {
0a9de3d2
AM
337 throw new AttributeNotFoundException();
338 }
c66426fd 339
0a9de3d2 340 /* Set up the node from which we'll start the search */
c66426fd 341 if (attributeQuark == -1) {
0a9de3d2
AM
342 startingAttribute = attributeTreeRoot;
343 } else {
344 startingAttribute = attributeList.get(attributeQuark);
345 }
c66426fd 346
0a9de3d2 347 /* Iterate through the sub-attributes and add them to the list */
c66426fd 348 addSubAttributes(listOfChildren, startingAttribute, recursive);
0a9de3d2 349
a52fde77
AM
350 return listOfChildren;
351 }
352
c66426fd
AM
353 private void addSubAttributes(List<Integer> list, Attribute curAttribute,
354 boolean recursive) {
355 for (Attribute childNode : curAttribute.getSubAttributesList()) {
356 list.add(childNode.getQuark());
357 if (recursive) {
358 addSubAttributes(list, childNode, true);
359 }
360 }
361 }
362
50678114
AM
363 String getAttributeName(int quark) {
364 return attributeList.get(quark).getName();
365 }
366
a52fde77
AM
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.055291 seconds and 5 git commands to generate.