ss: Replace AttributeNotFoundException with IOOBE for quark parameters
[deliverable/tracecompass.git] / statesystem / org.eclipse.tracecompass.statesystem.core / src / org / eclipse / tracecompass / internal / statesystem / core / AttributeTree.java
CommitLineData
a52fde77 1/*******************************************************************************
c44f0a0c 2 * Copyright (c) 2012, 2016 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
04927a83 18import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
c44f0a0c
PT
19import static org.eclipse.tracecompass.statesystem.core.ITmfStateSystem.INVALID_ATTRIBUTE;
20import static org.eclipse.tracecompass.statesystem.core.ITmfStateSystem.ROOT_ATTRIBUTE;
04927a83 21
085a78a8 22import java.io.BufferedInputStream;
085a78a8
AM
23import java.io.File;
24import java.io.FileInputStream;
da66cc75 25import java.io.FileOutputStream;
085a78a8 26import java.io.IOException;
da66cc75
AM
27import java.io.ObjectInputStream;
28import java.io.ObjectOutputStream;
085a78a8 29import java.io.PrintWriter;
da66cc75 30import java.nio.channels.FileChannel;
a52fde77 31import java.util.ArrayList;
a52fde77
AM
32import java.util.List;
33
50a47aa6 34import org.eclipse.jdt.annotation.NonNull;
c44f0a0c 35import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
6d08acca 36
a52fde77
AM
37/**
38 * The Attribute Tree is the /proc-like filesystem used to organize attributes.
39 * Each node of this tree is both like a file and a directory in the
40 * "file system".
8d1346f0 41 *
a52fde77 42 * @author alexmont
8d1346f0 43 *
a52fde77 44 */
cb42195c 45public final class AttributeTree {
a52fde77
AM
46
47 /* "Magic number" for attribute tree files or file sections */
cb42195c 48 private static final int ATTRIB_TREE_MAGIC_NUMBER = 0x06EC3671;
a52fde77
AM
49
50 private final StateSystem ss;
51 private final List<Attribute> attributeList;
52 private final Attribute attributeTreeRoot;
53
54 /**
55 * Standard constructor, create a new empty Attribute Tree
8d1346f0 56 *
a52fde77
AM
57 * @param ss
58 * The StateSystem to which this AT is attached
59 */
a6917276 60 public AttributeTree(StateSystem ss) {
a52fde77 61 this.ss = ss;
a69a9003 62 this.attributeList = new ArrayList<>();
c44f0a0c 63 this.attributeTreeRoot = new Attribute(null, "root", ROOT_ATTRIBUTE); //$NON-NLS-1$
a52fde77
AM
64 }
65
66 /**
6f04e06c
EB
67 * "Existing file" constructor. Builds an attribute tree from a
68 * "mapping file" or mapping section previously saved somewhere.
8d1346f0 69 *
a52fde77
AM
70 * @param ss
71 * StateSystem to which this AT is attached
72 * @param fis
73 * File stream where to read the AT information. Make sure it's
6f04e06c 74 * sought at the right place!
a52fde77 75 * @throws IOException
a6917276 76 * If there is a problem reading from the file stream
a52fde77 77 */
a6917276 78 public AttributeTree(StateSystem ss, FileInputStream fis) throws IOException {
a52fde77 79 this(ss);
da66cc75 80 ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(fis));
a52fde77
AM
81
82 /* Read the header of the Attribute Tree file (or file section) */
da66cc75 83 int res = ois.readInt(); /* Magic number */
a52fde77 84 if (res != ATTRIB_TREE_MAGIC_NUMBER) {
da66cc75 85 throw new IOException("The attribute tree file section is either invalid or corrupted."); //$NON-NLS-1$
a52fde77
AM
86 }
87
a52fde77 88
da66cc75
AM
89 ArrayList<String[]> attribList;
90 try {
91 @SuppressWarnings("unchecked")
92 ArrayList<String[]> list = (ArrayList<String[]>) ois.readObject();
93 attribList = list;
94 } catch (ClassNotFoundException e) {
95 throw new IOException("Unrecognizable attribute list"); //$NON-NLS-1$
a52fde77
AM
96 }
97
98 /*
99 * Now we have 'list', the ArrayList of String arrays representing all
100 * the attributes. Simply create attributes the normal way from them.
101 */
da66cc75 102 for (String[] attrib : attribList) {
c44f0a0c 103 this.getQuarkAndAdd(ROOT_ATTRIBUTE, attrib);
a52fde77
AM
104 }
105 }
106
107 /**
a6917276 108 * Tell the Attribute Tree to write itself somewhere in a file.
8d1346f0 109 *
a6917276
AM
110 * @param file
111 * The file to write to
112 * @param pos
113 * The position (in bytes) in the file where to write
a52fde77 114 */
a69a9003 115 public synchronized void writeSelf(File file, long pos) {
da66cc75
AM
116 try (FileOutputStream fos = new FileOutputStream(file, true);
117 FileChannel fc = fos.getChannel();) {
118 fc.position(pos);
119 try (ObjectOutputStream oos = new ObjectOutputStream(fos)) {
120
121 /* Write the almost-magic number */
122 oos.writeInt(ATTRIB_TREE_MAGIC_NUMBER);
123
124 /* Compute the serialized list of attributes and write it */
125 List<String[]> list = new ArrayList<>(attributeList.size());
126 for (Attribute entry : this.attributeList) {
127 list.add(entry.getFullAttribute());
a52fde77 128 }
da66cc75 129 oos.writeObject(list);
a52fde77 130 }
a52fde77
AM
131 } catch (IOException e) {
132 e.printStackTrace();
133 }
da66cc75 134
a52fde77
AM
135 }
136
137 /**
138 * Return the number of attributes this system as seen so far. Note that
139 * this also equals the integer value (quark) the next added attribute will
140 * have.
8d1346f0 141 *
a6917276 142 * @return The current number of attributes in the tree
a52fde77 143 */
a69a9003 144 public synchronized int getNbAttributes() {
a52fde77
AM
145 return attributeList.size();
146 }
147
148 /**
a6917276 149 * Get the quark for a given attribute path. No new attribute will be
c44f0a0c
PT
150 * created : if the specified path does not exist, return
151 * {@link ITmfStateSystem#INVALID_ATTRIBUTE}.
8d1346f0 152 *
a6917276
AM
153 * @param startingNodeQuark
154 * The quark of the attribute from which relative queries will
c44f0a0c
PT
155 * start. Use {@link ITmfStateSystem#ROOT_ATTRIBUTE} to start at
156 * the root node.
a6917276
AM
157 * @param subPath
158 * The path to the attribute, relative to the starting node.
c44f0a0c
PT
159 * @return The quark of the specified attribute, or
160 * {@link ITmfStateSystem#INVALID_ATTRIBUTE} if that attribute does
161 * not exist.
ed48dc75
PT
162 * @throws IndexOutOfBoundsException
163 * If the starting node quark is out of range
a52fde77 164 */
c44f0a0c 165 public synchronized int getQuarkDontAdd(int startingNodeQuark, String... subPath) {
a52fde77
AM
166 Attribute prevNode;
167
6abc2d88
AM
168 /* If subPath is empty, simply return the starting quark */
169 if (subPath == null || subPath.length == 0) {
170 return startingNodeQuark;
171 }
172
a52fde77 173 /* Get the "starting node" */
c44f0a0c 174 if (startingNodeQuark == ROOT_ATTRIBUTE) {
a52fde77
AM
175 prevNode = attributeTreeRoot;
176 } else {
177 prevNode = attributeList.get(startingNodeQuark);
178 }
179
c44f0a0c 180 return prevNode.getSubAttributeQuark(subPath);
a52fde77
AM
181 }
182
a6917276
AM
183 /**
184 * Get the quark of a given attribute path. If that specified path does not
185 * exist, it will be created (and the quark that was just created will be
186 * returned).
187 *
188 * @param startingNodeQuark
189 * The quark of the attribute from which relative queries will
c44f0a0c
PT
190 * start. Use {@link ITmfStateSystem#ROOT_ATTRIBUTE} to start at
191 * the root node.
a6917276
AM
192 * @param subPath
193 * The path to the attribute, relative to the starting node.
194 * @return The quark of the attribute represented by the path
ed48dc75
PT
195 * @throws IndexOutOfBoundsException
196 * If the starting node quark is out of range
a6917276
AM
197 */
198 public synchronized int getQuarkAndAdd(int startingNodeQuark, String... subPath) {
199 // FIXME synchronized here is probably quite costly... maybe only locking
200 // the "for" would be enough?
a52fde77
AM
201
202 Attribute nextNode = null;
203 Attribute prevNode;
204
205 /* Get the "starting node" */
c44f0a0c 206 if (startingNodeQuark == ROOT_ATTRIBUTE) {
a52fde77
AM
207 prevNode = attributeTreeRoot;
208 } else {
209 prevNode = attributeList.get(startingNodeQuark);
210 }
211
212 int knownQuark = prevNode.getSubAttributeQuark(subPath);
c44f0a0c 213 if (knownQuark == INVALID_ATTRIBUTE) {
a52fde77
AM
214 /*
215 * The attribute was not in the table previously, and we want to add
216 * it
217 */
218 for (String curDirectory : subPath) {
219 nextNode = prevNode.getSubAttributeNode(curDirectory);
220 if (nextNode == null) {
221 /* This is where we need to start adding */
04927a83 222 nextNode = new Attribute(prevNode, checkNotNull(curDirectory), attributeList.size());
a52fde77
AM
223 prevNode.addSubAttribute(nextNode);
224 attributeList.add(nextNode);
8d1346f0 225 ss.addEmptyAttribute();
a52fde77
AM
226 }
227 prevNode = nextNode;
228 }
085a78a8 229 return attributeList.size() - 1;
a52fde77
AM
230 }
231 /*
232 * The attribute was already existing, return the quark of that
233 * attribute
234 */
235 return knownQuark;
236 }
237
0a9de3d2
AM
238 /**
239 * Returns the sub-attributes of the quark passed in parameter
8d1346f0 240 *
0a9de3d2 241 * @param attributeQuark
a6917276 242 * The quark of the attribute to print the sub-attributes of.
c66426fd 243 * @param recursive
a6917276
AM
244 * Should the query be recursive or not? If false, only children
245 * one level deep will be returned. If true, all descendants will
246 * be returned (depth-first search)
247 * @return The list of quarks representing the children attributes
ed48dc75
PT
248 * @throws IndexOutOfBoundsException
249 * If the attribute quark is out of range
0a9de3d2 250 */
ed48dc75 251 public synchronized @NonNull List<@NonNull Integer> getSubAttributes(int attributeQuark, boolean recursive) {
df2597e0 252 List<@NonNull Integer> listOfChildren = new ArrayList<>();
0a9de3d2 253 Attribute startingAttribute;
c66426fd 254
0a9de3d2 255 /* Set up the node from which we'll start the search */
c44f0a0c 256 if (attributeQuark == ROOT_ATTRIBUTE) {
0a9de3d2
AM
257 startingAttribute = attributeTreeRoot;
258 } else {
259 startingAttribute = attributeList.get(attributeQuark);
260 }
c66426fd 261
0a9de3d2 262 /* Iterate through the sub-attributes and add them to the list */
c66426fd 263 addSubAttributes(listOfChildren, startingAttribute, recursive);
0a9de3d2 264
a52fde77
AM
265 return listOfChildren;
266 }
267
0fdd2c45
FG
268 /**
269 * Returns the parent quark of the attribute. The root attribute has no
c44f0a0c 270 * parent and will return {@link ITmfStateSystem#ROOT_ATTRIBUTE}.
0fdd2c45
FG
271 *
272 * @param quark
273 * The quark of the attribute
c44f0a0c
PT
274 * @return Quark of the parent attribute or
275 * {@link ITmfStateSystem#ROOT_ATTRIBUTE} for the root attribute
ed48dc75
PT
276 * @throws IndexOutOfBoundsException
277 * If the quark is out of range
0fdd2c45 278 */
a69a9003 279 public synchronized int getParentAttributeQuark(int quark) {
c44f0a0c 280 if (quark == ROOT_ATTRIBUTE) {
0fdd2c45
FG
281 return quark;
282 }
283 return attributeList.get(quark).getParentAttributeQuark();
284 }
285
c66426fd
AM
286 private void addSubAttributes(List<Integer> list, Attribute curAttribute,
287 boolean recursive) {
cb42195c 288 for (Attribute childNode : curAttribute.getSubAttributes()) {
c66426fd
AM
289 list.add(childNode.getQuark());
290 if (recursive) {
291 addSubAttributes(list, childNode, true);
292 }
293 }
294 }
295
a6917276
AM
296 /**
297 * Get then base name of an attribute specified by a quark.
298 *
299 * @param quark
300 * The quark of the attribute
301 * @return The (base) name of the attribute
ed48dc75
PT
302 * @throws IndexOutOfBoundsException
303 * If the quark is out of range
a6917276 304 */
a69a9003 305 public synchronized @NonNull String getAttributeName(int quark) {
50678114
AM
306 return attributeList.get(quark).getName();
307 }
308
a6917276
AM
309 /**
310 * Get the full path name of an attribute specified by a quark.
311 *
312 * @param quark
313 * The quark of the attribute
314 * @return The full path name of the attribute
ed48dc75
PT
315 * @throws IndexOutOfBoundsException
316 * If the quark is out of range
a6917276 317 */
a69a9003 318 public synchronized @NonNull String getFullAttributeName(int quark) {
a52fde77
AM
319 return attributeList.get(quark).getFullAttributeName();
320 }
321
34638411
AM
322 /**
323 * Get the full path name (as an array of path elements) of an attribute
324 * specified by a quark.
325 *
326 * @param quark
327 * The quark of the attribute
328 * @return The path elements of the full path
ed48dc75
PT
329 * @throws IndexOutOfBoundsException
330 * If the quark is out of range
34638411 331 */
4c4e2816 332 public synchronized String @NonNull [] getFullAttributePathArray(int quark) {
34638411
AM
333 return attributeList.get(quark).getFullAttribute();
334 }
335
a6917276
AM
336 /**
337 * Debug-print all the attributes in the tree.
338 *
339 * @param writer
340 * The writer where to print the output
341 */
a69a9003 342 public synchronized void debugPrint(PrintWriter writer) {
a52fde77
AM
343 attributeTreeRoot.debugPrint(writer);
344 }
345
a6917276 346}
This page took 0.095705 seconds and 5 git commands to generate.