From: Patrick Tasse Date: Wed, 27 Jan 2016 22:15:24 +0000 (-0500) Subject: ss: Bug 486689: Add methods for getting an optional attribute quark X-Git-Url: http://git.efficios.com/?a=commitdiff_plain;h=c44f0a0cabdc6e024cea461fc89d013af6cee117;p=deliverable%2Ftracecompass.git ss: Bug 486689: Add methods for getting an optional attribute quark Change AttributeTree.getQuarkDontAdd() to return -1 instead of throwing an AttributeNotFoundException. Add methods optQuarkAbsolute() and optQuarkRelative() to the ITmfStateSystem API. Define and use quark constants ROOT_ATTRIBUTE and INVALID_ATTRIBUTE. Use the new methods in the implementation of StateSystem.getQuarks(). Change-Id: I9f28e8aa8f3ba7377bebf8a5e8042ae7675aecab Signed-off-by: Patrick Tasse Reviewed-on: https://git.eclipse.org/r/65328 Reviewed-by: Hudson CI Reviewed-by: Matthew Khouzam Tested-by: Matthew Khouzam --- diff --git a/lttng/org.eclipse.tracecompass.lttng2.kernel.core.tests/src/org/eclipse/tracecompass/lttng2/kernel/core/tests/analysis/kernel/statesystem/StateSystemTest.java b/lttng/org.eclipse.tracecompass.lttng2.kernel.core.tests/src/org/eclipse/tracecompass/lttng2/kernel/core/tests/analysis/kernel/statesystem/StateSystemTest.java index ebb379b34e..0f869c1bee 100644 --- a/lttng/org.eclipse.tracecompass.lttng2.kernel.core.tests/src/org/eclipse/tracecompass/lttng2/kernel/core/tests/analysis/kernel/statesystem/StateSystemTest.java +++ b/lttng/org.eclipse.tracecompass.lttng2.kernel.core.tests/src/org/eclipse/tracecompass/lttng2/kernel/core/tests/analysis/kernel/statesystem/StateSystemTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2015 Ericsson + * Copyright (c) 2012, 2016 Ericsson * Copyright (c) 2010, 2011 École Polytechnique de Montréal * Copyright (c) 2010, 2011 Alexandre Montplaisir * @@ -12,7 +12,10 @@ package org.eclipse.tracecompass.lttng2.kernel.core.tests.analysis.kernel.statesystem; +import static org.eclipse.tracecompass.statesystem.core.ITmfStateSystem.INVALID_ATTRIBUTE; +import static org.eclipse.tracecompass.statesystem.core.ITmfStateSystem.ROOT_ATTRIBUTE; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; @@ -326,6 +329,49 @@ public abstract class StateSystemTest { } } + @Test + public void testOptQuarkAbsolute() { + int quark = fixture.optQuarkAbsolute(); + assertEquals(ROOT_ATTRIBUTE, quark); + + quark = fixture.optQuarkAbsolute(Attributes.THREADS, "1432", Attributes.EXEC_NAME); + assertNotEquals(INVALID_ATTRIBUTE, quark); + assertEquals(Attributes.EXEC_NAME, fixture.getAttributeName(quark)); + + quark = fixture.optQuarkAbsolute(Attributes.THREADS, "1432", "absent"); + assertEquals(INVALID_ATTRIBUTE, quark); + + quark = fixture.optQuarkAbsolute(Attributes.THREADS, "absent", Attributes.EXEC_NAME); + assertEquals(INVALID_ATTRIBUTE, quark); + + quark = fixture.optQuarkAbsolute("absent", "1432", Attributes.EXEC_NAME); + assertEquals(INVALID_ATTRIBUTE, quark); + } + + @Test + public void testOptQuarkRelative() { + int threadsQuark = INVALID_ATTRIBUTE; + try { + threadsQuark = fixture.getQuarkAbsolute(Attributes.THREADS); + } catch (AttributeNotFoundException e) { + fail(); + } + assertNotEquals(INVALID_ATTRIBUTE, threadsQuark); + + int quark = fixture.optQuarkRelative(threadsQuark); + assertEquals(threadsQuark, quark); + + quark = fixture.optQuarkRelative(threadsQuark, "1432", Attributes.EXEC_NAME); + assertNotEquals(INVALID_ATTRIBUTE, quark); + assertEquals(Attributes.EXEC_NAME, fixture.getAttributeName(quark)); + + quark = fixture.optQuarkRelative(threadsQuark, "1432", "absent"); + assertEquals(INVALID_ATTRIBUTE, quark); + + quark = fixture.optQuarkRelative(threadsQuark, "absent", Attributes.EXEC_NAME); + assertEquals(INVALID_ATTRIBUTE, quark); + } + @Test public void testFullAttributeName() { try { @@ -361,6 +407,21 @@ public abstract class StateSystemTest { assertEquals(5, list.size()); } + @Test + public void testGetQuarksNoMatch() { + List list = fixture.getQuarks("invalid"); + assertEquals(0, list.size()); + + list = fixture.getQuarks("*", "invalid"); + assertEquals(0, list.size()); + + list = fixture.getQuarks("invalid", "*"); + assertEquals(0, list.size()); + + list = fixture.getQuarks(Attributes.THREADS, "*", "invalid"); + assertEquals(0, list.size()); + } + // ------------------------------------------------------------------------ // Tests verifying the *complete* results of a full queries // ------------------------------------------------------------------------ @@ -424,9 +485,9 @@ public abstract class StateSystemTest { assertEquals(path[i], name); q = fixture.getParentAttributeQuark(q); } - assertEquals(-1, q); + assertEquals(ROOT_ATTRIBUTE, q); q = fixture.getParentAttributeQuark(q); - assertEquals(-1, q); + assertEquals(ROOT_ATTRIBUTE, q); } catch (AttributeNotFoundException e) { fail(); } diff --git a/statesystem/org.eclipse.tracecompass.statesystem.core.tests/src/org/eclipse/tracecompass/statesystem/core/tests/AttributeTreeTest.java b/statesystem/org.eclipse.tracecompass.statesystem.core.tests/src/org/eclipse/tracecompass/statesystem/core/tests/AttributeTreeTest.java index 9fa9aee2db..22fb6145fe 100644 --- a/statesystem/org.eclipse.tracecompass.statesystem.core.tests/src/org/eclipse/tracecompass/statesystem/core/tests/AttributeTreeTest.java +++ b/statesystem/org.eclipse.tracecompass.statesystem.core.tests/src/org/eclipse/tracecompass/statesystem/core/tests/AttributeTreeTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015 Ericsson + * Copyright (c) 2015, 2016 Ericsson * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which @@ -14,6 +14,7 @@ package org.eclipse.tracecompass.statesystem.core.tests; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import java.io.File; import java.io.FileInputStream; @@ -21,9 +22,9 @@ import java.io.IOException; import org.eclipse.tracecompass.internal.statesystem.core.AttributeTree; import org.eclipse.tracecompass.internal.statesystem.core.StateSystem; +import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; import org.eclipse.tracecompass.statesystem.core.backend.IStateHistoryBackend; import org.eclipse.tracecompass.statesystem.core.backend.StateHistoryBackendFactory; -import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; import org.junit.Test; /** @@ -92,11 +93,9 @@ public class AttributeTreeTest { * * @throws IOException * if there is an error accessing the test file - * @throws AttributeNotFoundException - * if the test fails */ @Test - public void testAttributeTreeFileStorage() throws IOException, AttributeNotFoundException { + public void testAttributeTreeFileStorage() throws IOException { File file = File.createTempFile("AttributeTreeTest", ".ht"); IStateHistoryBackend backend1 = StateHistoryBackendFactory.createNullBackend("test"); StateSystem ss1 = new StateSystem(backend1); @@ -114,7 +113,8 @@ public class AttributeTreeTest { AttributeTree attributeTree2 = new AttributeTree(ss2, fis); for (String name : NAMES) { String[] path = new String[] { THREADS, name, STATUS }; - int quark = attributeTree2.getQuarkDontAdd(-1, path); + int quark = attributeTree2.getQuarkDontAdd(ITmfStateSystem.ROOT_ATTRIBUTE, path); + assertNotEquals(ITmfStateSystem.INVALID_ATTRIBUTE, quark); assertArrayEquals(path, attributeTree2.getFullAttributePathArray(quark)); assertEquals(name, attributeTree2.getAttributeName(attributeTree2.getParentAttributeQuark(quark))); } diff --git a/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/Attribute.java b/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/Attribute.java index 0fe8418bda..ff26cc0f37 100644 --- a/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/Attribute.java +++ b/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/Attribute.java @@ -15,6 +15,7 @@ package org.eclipse.tracecompass.internal.statesystem.core; import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; +import static org.eclipse.tracecompass.statesystem.core.ITmfStateSystem.INVALID_ATTRIBUTE; import java.io.PrintWriter; import java.util.Collections; @@ -23,6 +24,7 @@ import java.util.LinkedList; import java.util.Map; import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; import com.google.common.collect.ImmutableList; @@ -99,7 +101,8 @@ public final class Attribute { * * @param path * The path we are looking for, *relative to this node*. - * @return The matching quark, or -1 if that attribute does not exist. + * @return The matching quark, or {@link ITmfStateSystem#INVALID_ATTRIBUTE} + * if that attribute does not exist. */ public int getSubAttributeQuark(String... path) { return this.getSubAttributeQuark(path, 0); @@ -129,7 +132,7 @@ public final class Attribute { private int getSubAttributeQuark(String[] path, int index) { Attribute targetNode = this.getSubAttributeNode(path, index); if (targetNode == null) { - return -1; + return INVALID_ATTRIBUTE; } return targetNode.getQuark(); } diff --git a/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/AttributeTree.java b/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/AttributeTree.java index 54ea463e83..fa3ca8ed31 100644 --- a/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/AttributeTree.java +++ b/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/AttributeTree.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2015 Ericsson + * Copyright (c) 2012, 2016 Ericsson * Copyright (c) 2010, 2011 École Polytechnique de Montréal * Copyright (c) 2010, 2011 Alexandre Montplaisir * @@ -16,6 +16,8 @@ package org.eclipse.tracecompass.internal.statesystem.core; import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; +import static org.eclipse.tracecompass.statesystem.core.ITmfStateSystem.INVALID_ATTRIBUTE; +import static org.eclipse.tracecompass.statesystem.core.ITmfStateSystem.ROOT_ATTRIBUTE; import java.io.BufferedInputStream; import java.io.File; @@ -27,10 +29,10 @@ import java.io.ObjectOutputStream; import java.io.PrintWriter; import java.nio.channels.FileChannel; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem; import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException; /** @@ -59,7 +61,7 @@ public final class AttributeTree { public AttributeTree(StateSystem ss) { this.ss = ss; this.attributeList = new ArrayList<>(); - this.attributeTreeRoot = new Attribute(null, "root", -1); //$NON-NLS-1$ + this.attributeTreeRoot = new Attribute(null, "root", ROOT_ATTRIBUTE); //$NON-NLS-1$ } /** @@ -99,7 +101,7 @@ public final class AttributeTree { * the attributes. Simply create attributes the normal way from them. */ for (String[] attrib : attribList) { - this.getQuarkAndAdd(-1, attrib); + this.getQuarkAndAdd(ROOT_ATTRIBUTE, attrib); } } @@ -146,20 +148,21 @@ public final class AttributeTree { /** * Get the quark for a given attribute path. No new attribute will be - * created : if the specified path does not exist, throw an error. + * created : if the specified path does not exist, return + * {@link ITmfStateSystem#INVALID_ATTRIBUTE}. * * @param startingNodeQuark * The quark of the attribute from which relative queries will - * start. Use '-1' to start at the root node. + * start. Use {@link ITmfStateSystem#ROOT_ATTRIBUTE} to start at + * the root node. * @param subPath * The path to the attribute, relative to the starting node. - * @return The quark of the specified attribute - * @throws AttributeNotFoundException - * If the specified path was not found + * @return The quark of the specified attribute, or + * {@link ITmfStateSystem#INVALID_ATTRIBUTE} if that attribute does + * not exist. */ - public synchronized int getQuarkDontAdd(int startingNodeQuark, String... subPath) - throws AttributeNotFoundException { - assert (startingNodeQuark >= -1); + public synchronized int getQuarkDontAdd(int startingNodeQuark, String... subPath) { + assert (startingNodeQuark >= ROOT_ATTRIBUTE); Attribute prevNode; @@ -169,25 +172,13 @@ public final class AttributeTree { } /* Get the "starting node" */ - if (startingNodeQuark == -1) { + if (startingNodeQuark == ROOT_ATTRIBUTE) { prevNode = attributeTreeRoot; } else { prevNode = attributeList.get(startingNodeQuark); } - int knownQuark = prevNode.getSubAttributeQuark(subPath); - if (knownQuark == -1) { - /* - * The attribute doesn't exist, but we have been specified to NOT - * add any new attributes. - */ - throw new AttributeNotFoundException(ss.getSSID() + " Quark:" + startingNodeQuark + ", SubPath:" + Arrays.toString(subPath)); //$NON-NLS-1$ //$NON-NLS-2$ - } - /* - * The attribute was already existing, return the quark of that - * attribute - */ - return knownQuark; + return prevNode.getSubAttributeQuark(subPath); } /** @@ -197,7 +188,8 @@ public final class AttributeTree { * * @param startingNodeQuark * The quark of the attribute from which relative queries will - * start. Use '-1' to start at the root node. + * start. Use {@link ITmfStateSystem#ROOT_ATTRIBUTE} to start at + * the root node. * @param subPath * The path to the attribute, relative to the starting node. * @return The quark of the attribute represented by the path @@ -206,20 +198,20 @@ public final class AttributeTree { // FIXME synchronized here is probably quite costly... maybe only locking // the "for" would be enough? assert (subPath != null && subPath.length > 0); - assert (startingNodeQuark >= -1); + assert (startingNodeQuark >= ROOT_ATTRIBUTE); Attribute nextNode = null; Attribute prevNode; /* Get the "starting node" */ - if (startingNodeQuark == -1) { + if (startingNodeQuark == ROOT_ATTRIBUTE) { prevNode = attributeTreeRoot; } else { prevNode = attributeList.get(startingNodeQuark); } int knownQuark = prevNode.getSubAttributeQuark(subPath); - if (knownQuark == -1) { + if (knownQuark == INVALID_ATTRIBUTE) { /* * The attribute was not in the table previously, and we want to add * it @@ -255,7 +247,7 @@ public final class AttributeTree { * be returned (depth-first search) * @return The list of quarks representing the children attributes * @throws AttributeNotFoundException - * If 'attributeQuark' is invalid, or if there is no attrbiute + * If 'attributeQuark' is invalid, or if there is no attribute * associated to it. */ public synchronized @NonNull List<@NonNull Integer> getSubAttributes(int attributeQuark, boolean recursive) @@ -264,12 +256,12 @@ public final class AttributeTree { Attribute startingAttribute; /* Check if the quark is valid */ - if (attributeQuark < -1 || attributeQuark >= attributeList.size()) { + if (attributeQuark < ROOT_ATTRIBUTE || attributeQuark >= attributeList.size()) { throw new AttributeNotFoundException(ss.getSSID() + " Quark:" + attributeQuark); //$NON-NLS-1$ } /* Set up the node from which we'll start the search */ - if (attributeQuark == -1) { + if (attributeQuark == ROOT_ATTRIBUTE) { startingAttribute = attributeTreeRoot; } else { startingAttribute = attributeList.get(attributeQuark); @@ -283,15 +275,15 @@ public final class AttributeTree { /** * Returns the parent quark of the attribute. The root attribute has no - * parent and will return -1 + * parent and will return {@link ITmfStateSystem#ROOT_ATTRIBUTE}. * * @param quark * The quark of the attribute - * @return Quark of the parent attribute or -1 for the root - * attribute + * @return Quark of the parent attribute or + * {@link ITmfStateSystem#ROOT_ATTRIBUTE} for the root attribute */ public synchronized int getParentAttributeQuark(int quark) { - if (quark == -1) { + if (quark == ROOT_ATTRIBUTE) { return quark; } return attributeList.get(quark).getParentAttributeQuark(); diff --git a/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/StateSystem.java b/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/StateSystem.java index d4c85ff77c..e11bccc437 100644 --- a/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/StateSystem.java +++ b/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/StateSystem.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2015 Ericsson + * Copyright (c) 2012, 2016 Ericsson * Copyright (c) 2010, 2011 École Polytechnique de Montréal * Copyright (c) 2010, 2011 Alexandre Montplaisir * @@ -19,6 +19,7 @@ import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.concurrent.CountDownLatch; @@ -235,17 +236,35 @@ public class StateSystem implements ITmfStateSystemBuilder { @Override public int getQuarkAbsolute(String... attribute) throws AttributeNotFoundException { - return getAttributeTree().getQuarkDontAdd(-1, attribute); + int quark = getAttributeTree().getQuarkDontAdd(ROOT_ATTRIBUTE, attribute); + if (quark == INVALID_ATTRIBUTE) { + throw new AttributeNotFoundException(getSSID() + " Path:" + Arrays.toString(attribute)); //$NON-NLS-1$ + } + return quark; + } + + @Override + public int optQuarkAbsolute(String... attribute) { + return getAttributeTree().getQuarkDontAdd(ROOT_ATTRIBUTE, attribute); } @Override public int getQuarkAbsoluteAndAdd(String... attribute) { - return getAttributeTree().getQuarkAndAdd(-1, attribute); + return getAttributeTree().getQuarkAndAdd(ROOT_ATTRIBUTE, attribute); } @Override public int getQuarkRelative(int startingNodeQuark, String... subPath) throws AttributeNotFoundException { + int quark = getAttributeTree().getQuarkDontAdd(startingNodeQuark, subPath); + if (quark == INVALID_ATTRIBUTE) { + throw new AttributeNotFoundException(getSSID() + " Quark:" + startingNodeQuark + ", SubPath:" + Arrays.toString(subPath)); //$NON-NLS-1$ //$NON-NLS-2$ + } + return quark; + } + + @Override + public int optQuarkRelative(int startingNodeQuark, String... subPath) { return getAttributeTree().getQuarkDontAdd(startingNodeQuark, subPath); } @@ -330,20 +349,24 @@ public class StateSystem implements ITmfStateSystemBuilder { return quarks; } - try { - if (prefix.size() == 0) { - /* - * If 'prefix' is empty, this means the wildcard was the first - * element. Look for the root node's sub-attributes. - */ - startingAttribute = -1; - } else { - startingAttribute = getQuarkAbsolute(prefixStr); + if (prefix.isEmpty()) { + /* + * If 'prefix' is empty, this means the wildcard was the first + * element. Look for the root node's sub-attributes. + */ + startingAttribute = ROOT_ATTRIBUTE; + } else { + startingAttribute = optQuarkAbsolute(prefixStr); + if (startingAttribute == INVALID_ATTRIBUTE) { + /* That attribute path did not exist, return the empty array */ + return quarks; } + } + try { directChildren = getSubAttributes(startingAttribute, false); } catch (AttributeNotFoundException e) { - /* That attribute path did not exist, return the empty array */ - return quarks; + /* Should not happen, starting attribute is a valid quark */ + throw new IllegalStateException(); } /* @@ -351,13 +374,10 @@ public class StateSystem implements ITmfStateSystemBuilder { * 'suffix' part of the initial pattern. */ for (int childQuark : directChildren) { - int matchingQuark; - try { - matchingQuark = getQuarkRelative(childQuark, suffixStr); - } catch (AttributeNotFoundException e) { - continue; + int matchingQuark = optQuarkRelative(childQuark, suffixStr); + if (matchingQuark != INVALID_ATTRIBUTE) { + quarks.add(matchingQuark); } - quarks.add(matchingQuark); } return quarks; diff --git a/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/statesystem/core/ITmfStateSystem.java b/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/statesystem/core/ITmfStateSystem.java index 3236bfc4a8..8af7d09953 100644 --- a/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/statesystem/core/ITmfStateSystem.java +++ b/statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/statesystem/core/ITmfStateSystem.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2015 Ericsson and others. + * Copyright (c) 2012, 2016 Ericsson and others. * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which @@ -32,6 +32,13 @@ import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue; */ public interface ITmfStateSystem { + /** Root attribute quark + * @since 2.0*/ + int ROOT_ATTRIBUTE = -1; + /** Invalid attribute quark + * @since 2.0*/ + int INVALID_ATTRIBUTE = -2; + /** * Get the ID of this state system. * @@ -120,9 +127,12 @@ public interface ITmfStateSystem { /** * Basic quark-retrieving method. Pass an attribute in parameter as an array * of strings, the matching quark will be returned. - * + *

* This version will NOT create any new attributes. If an invalid attribute * is requested, an exception will be thrown. + *

+ * If it is expected that the requested attribute might be absent, it is + * recommended to use {@link #optQuarkAbsolute(String...)} instead. * * @param attribute * Attribute given as its full path in the Attribute Tree @@ -134,17 +144,36 @@ public interface ITmfStateSystem { int getQuarkAbsolute(String... attribute) throws AttributeNotFoundException; + /** + * Quark-retrieving method for an optional attribute that may or may not be + * present. Pass an attribute in parameter as an array of strings, if it + * exists, the matching quark will be returned. + *

+ * This version will NOT create any new attributes. If an attribute that + * does not exist is requested, {@link #INVALID_ATTRIBUTE} will be returned. + * + * @param attribute + * Attribute given as its full path in the Attribute Tree + * @return The quark of the requested attribute, or + * {@link #INVALID_ATTRIBUTE} if it does not exist. + * @since 2.0 + */ + int optQuarkAbsolute(String... attribute); + /** * "Relative path" quark-getting method. Instead of specifying a full path, * if you know the path is relative to another attribute for which you * already have the quark, use this for better performance. - * + *

* This is useful for cases where a lot of modifications or queries will * originate from the same branch of the attribute tree : the common part of * the path won't have to be re-hashed for every access. - * + *

* This version will NOT create any new attributes. If an invalid attribute * is requested, an exception will be thrown. + *

+ * If it is expected that the requested sub-attribute might be absent, it is + * recommended to use {@link #optQuarkRelative(int, String...)} instead. * * @param startingNodeQuark * The quark of the attribute from which 'subPath' originates. @@ -159,12 +188,37 @@ public interface ITmfStateSystem { int getQuarkRelative(int startingNodeQuark, String... subPath) throws AttributeNotFoundException; + /** + * "Relative path" quark-getting method for an optional attribute that may + * or may not be present. Instead of specifying a full path, if you know the + * path is relative to another attribute for which you already have the + * quark, use this for better performance. + *

+ * This is useful for cases where a lot of modifications or queries will + * originate from the same branch of the attribute tree : the common part of + * the path won't have to be re-hashed for every access. + *

+ * This version will NOT create any new attributes. If a sub-attribute that + * does not exist is requested, {@link #INVALID_ATTRIBUTE} will be returned. + * + * @param startingNodeQuark + * The quark of the attribute from which 'subPath' originates. + * @param subPath + * "Rest" of the path to get to the final attribute + * @return The quark of the requested sub-attribute, or + * {@link #INVALID_ATTRIBUTE} if it does not exist. + * @throws IndexOutOfBoundsException + * If the starting node quark is out of range + * @since 2.0 + */ + int optQuarkRelative(int startingNodeQuark, String... subPath); + /** * Return the sub-attributes of the target attribute, as a List of quarks. * * @param quark * The attribute of which you want to sub-attributes. You can use - * "-1" here to specify the root node. + * {@link #ROOT_ATTRIBUTE} here to specify the root node. * @param recursive * True if you want all recursive sub-attributes, false if you * only want the first level. @@ -182,7 +236,7 @@ public interface ITmfStateSystem { * * @param quark * The attribute of which you want to sub-attributes. You can use - * "-1" here to specify the root node. + * {@link #ROOT_ATTRIBUTE} here to specify the root node. * @param recursive * True if you want all recursive sub-attributes, false if you * only want the first level. Note that the returned value will @@ -266,8 +320,8 @@ public interface ITmfStateSystem { * * @param attributeQuark * The quark of the attribute - * @return Quark of the parent attribute or -1 if root quark or - * no parent. + * @return Quark of the parent attribute or {@link #ROOT_ATTRIBUTE} if root + * quark or no parent. * @throws IndexOutOfBoundsException * If the attribute quark is out of range */