statesystem: Move plugins to their own sub-directory
[deliverable/tracecompass.git] / statesystem / org.eclipse.tracecompass.statesystem.core / src / org / eclipse / tracecompass / internal / statesystem / core / AttributeTree.java
1 /*******************************************************************************
2 * Copyright (c) 2012, 2015 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 * Contributors:
12 * Alexandre Montplaisir - Initial API and implementation
13 * Patrick Tasse - Add message to exceptions
14 *******************************************************************************/
15
16 package org.eclipse.tracecompass.internal.statesystem.core;
17
18 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
19
20 import java.io.BufferedInputStream;
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.io.ObjectInputStream;
26 import java.io.ObjectOutputStream;
27 import java.io.PrintWriter;
28 import java.nio.channels.FileChannel;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Collections;
32 import java.util.List;
33
34 import org.eclipse.jdt.annotation.NonNull;
35 import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
36
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".
41 *
42 * @author alexmont
43 *
44 */
45 public final class AttributeTree {
46
47 /* "Magic number" for attribute tree files or file sections */
48 private static final int ATTRIB_TREE_MAGIC_NUMBER = 0x06EC3671;
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
56 *
57 * @param ss
58 * The StateSystem to which this AT is attached
59 */
60 public AttributeTree(StateSystem ss) {
61 this.ss = ss;
62 this.attributeList = Collections.synchronizedList(new ArrayList<Attribute>());
63 this.attributeTreeRoot = new Attribute(null, "root", -1); //$NON-NLS-1$
64 }
65
66 /**
67 * "Existing file" constructor. Builds an attribute tree from a
68 * "mapping file" or mapping section previously saved somewhere.
69 *
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
74 * sought at the right place!
75 * @throws IOException
76 * If there is a problem reading from the file stream
77 */
78 public AttributeTree(StateSystem ss, FileInputStream fis) throws IOException {
79 this(ss);
80 ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(fis));
81
82 /* Read the header of the Attribute Tree file (or file section) */
83 int res = ois.readInt(); /* Magic number */
84 if (res != ATTRIB_TREE_MAGIC_NUMBER) {
85 throw new IOException("The attribute tree file section is either invalid or corrupted."); //$NON-NLS-1$
86 }
87
88
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$
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 */
102 for (String[] attrib : attribList) {
103 this.getQuarkAndAdd(-1, attrib);
104 }
105 }
106
107 /**
108 * Tell the Attribute Tree to write itself somewhere in a file.
109 *
110 * @param file
111 * The file to write to
112 * @param pos
113 * The position (in bytes) in the file where to write
114 */
115 public void writeSelf(File file, long pos) {
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());
128 }
129 oos.writeObject(list);
130 }
131 } catch (IOException e) {
132 e.printStackTrace();
133 }
134
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.
141 *
142 * @return The current number of attributes in the tree
143 */
144 public int getNbAttributes() {
145 return attributeList.size();
146 }
147
148 /**
149 * Get the quark for a given attribute path. No new attribute will be
150 * created : if the specified path does not exist, throw an error.
151 *
152 * @param startingNodeQuark
153 * The quark of the attribute from which relative queries will
154 * start. Use '-1' to start at the root node.
155 * @param subPath
156 * The path to the attribute, relative to the starting node.
157 * @return The quark of the specified attribute
158 * @throws AttributeNotFoundException
159 * If the specified path was not found
160 */
161 public int getQuarkDontAdd(int startingNodeQuark, String... subPath)
162 throws AttributeNotFoundException {
163 assert (startingNodeQuark >= -1);
164
165 Attribute prevNode;
166
167 /* If subPath is empty, simply return the starting quark */
168 if (subPath == null || subPath.length == 0) {
169 return startingNodeQuark;
170 }
171
172 /* Get the "starting node" */
173 if (startingNodeQuark == -1) {
174 prevNode = attributeTreeRoot;
175 } else {
176 prevNode = attributeList.get(startingNodeQuark);
177 }
178
179 int knownQuark = prevNode.getSubAttributeQuark(subPath);
180 if (knownQuark == -1) {
181 /*
182 * The attribute doesn't exist, but we have been specified to NOT
183 * add any new attributes.
184 */
185 throw new AttributeNotFoundException(ss.getSSID() + " Quark:" + startingNodeQuark + ", SubPath:" + Arrays.toString(subPath)); //$NON-NLS-1$ //$NON-NLS-2$
186 }
187 /*
188 * The attribute was already existing, return the quark of that
189 * attribute
190 */
191 return knownQuark;
192 }
193
194 /**
195 * Get the quark of a given attribute path. If that specified path does not
196 * exist, it will be created (and the quark that was just created will be
197 * returned).
198 *
199 * @param startingNodeQuark
200 * The quark of the attribute from which relative queries will
201 * start. Use '-1' to start at the root node.
202 * @param subPath
203 * The path to the attribute, relative to the starting node.
204 * @return The quark of the attribute represented by the path
205 */
206 public synchronized int getQuarkAndAdd(int startingNodeQuark, String... subPath) {
207 // FIXME synchronized here is probably quite costly... maybe only locking
208 // the "for" would be enough?
209 assert (subPath != null && subPath.length > 0);
210 assert (startingNodeQuark >= -1);
211
212 Attribute nextNode = null;
213 Attribute prevNode;
214
215 /* Get the "starting node" */
216 if (startingNodeQuark == -1) {
217 prevNode = attributeTreeRoot;
218 } else {
219 prevNode = attributeList.get(startingNodeQuark);
220 }
221
222 int knownQuark = prevNode.getSubAttributeQuark(subPath);
223 if (knownQuark == -1) {
224 /*
225 * The attribute was not in the table previously, and we want to add
226 * it
227 */
228 for (String curDirectory : subPath) {
229 nextNode = prevNode.getSubAttributeNode(curDirectory);
230 if (nextNode == null) {
231 /* This is where we need to start adding */
232 nextNode = new Attribute(prevNode, checkNotNull(curDirectory), attributeList.size());
233 prevNode.addSubAttribute(nextNode);
234 attributeList.add(nextNode);
235 ss.addEmptyAttribute();
236 }
237 prevNode = nextNode;
238 }
239 return attributeList.size() - 1;
240 }
241 /*
242 * The attribute was already existing, return the quark of that
243 * attribute
244 */
245 return knownQuark;
246 }
247
248 /**
249 * Returns the sub-attributes of the quark passed in parameter
250 *
251 * @param attributeQuark
252 * The quark of the attribute to print the sub-attributes of.
253 * @param recursive
254 * Should the query be recursive or not? If false, only children
255 * one level deep will be returned. If true, all descendants will
256 * be returned (depth-first search)
257 * @return The list of quarks representing the children attributes
258 * @throws AttributeNotFoundException
259 * If 'attributeQuark' is invalid, or if there is no attrbiute
260 * associated to it.
261 */
262 public @NonNull List<Integer> getSubAttributes(int attributeQuark, boolean recursive)
263 throws AttributeNotFoundException {
264 List<Integer> listOfChildren = new ArrayList<>();
265 Attribute startingAttribute;
266
267 /* Check if the quark is valid */
268 if (attributeQuark < -1 || attributeQuark >= attributeList.size()) {
269 throw new AttributeNotFoundException(ss.getSSID() + " Quark:" + attributeQuark); //$NON-NLS-1$
270 }
271
272 /* Set up the node from which we'll start the search */
273 if (attributeQuark == -1) {
274 startingAttribute = attributeTreeRoot;
275 } else {
276 startingAttribute = attributeList.get(attributeQuark);
277 }
278
279 /* Iterate through the sub-attributes and add them to the list */
280 addSubAttributes(listOfChildren, startingAttribute, recursive);
281
282 return listOfChildren;
283 }
284
285 /**
286 * Returns the parent quark of the attribute. The root attribute has no
287 * parent and will return <code>-1</code>
288 *
289 * @param quark
290 * The quark of the attribute
291 * @return Quark of the parent attribute or <code>-1</code> for the root
292 * attribute
293 */
294 public int getParentAttributeQuark(int quark) {
295 if (quark == -1) {
296 return quark;
297 }
298 return attributeList.get(quark).getParentAttributeQuark();
299 }
300
301 private void addSubAttributes(List<Integer> list, Attribute curAttribute,
302 boolean recursive) {
303 for (Attribute childNode : curAttribute.getSubAttributes()) {
304 list.add(childNode.getQuark());
305 if (recursive) {
306 addSubAttributes(list, childNode, true);
307 }
308 }
309 }
310
311 /**
312 * Get then base name of an attribute specified by a quark.
313 *
314 * @param quark
315 * The quark of the attribute
316 * @return The (base) name of the attribute
317 */
318 public @NonNull String getAttributeName(int quark) {
319 return attributeList.get(quark).getName();
320 }
321
322 /**
323 * Get the full path name of an attribute specified by a quark.
324 *
325 * @param quark
326 * The quark of the attribute
327 * @return The full path name of the attribute
328 */
329 public @NonNull String getFullAttributeName(int quark) {
330 return attributeList.get(quark).getFullAttributeName();
331 }
332
333 /**
334 * Get the full path name (as an array of path elements) of an attribute
335 * specified by a quark.
336 *
337 * @param quark
338 * The quark of the attribute
339 * @return The path elements of the full path
340 */
341 public @NonNull String[] getFullAttributePathArray(int quark) {
342 return attributeList.get(quark).getFullAttribute();
343 }
344
345 /**
346 * Debug-print all the attributes in the tree.
347 *
348 * @param writer
349 * The writer where to print the output
350 */
351 public void debugPrint(PrintWriter writer) {
352 attributeTreeRoot.debugPrint(writer);
353 }
354
355 }
This page took 0.041347 seconds and 5 git commands to generate.