ss: Bug 486689: Add methods for getting an optional attribute quark
authorPatrick Tasse <patrick.tasse@gmail.com>
Wed, 27 Jan 2016 22:15:24 +0000 (17:15 -0500)
committerPatrick Tasse <patrick.tasse@gmail.com>
Sun, 14 Feb 2016 16:10:44 +0000 (11:10 -0500)
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 <patrick.tasse@gmail.com>
Reviewed-on: https://git.eclipse.org/r/65328
Reviewed-by: Hudson CI
Reviewed-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Tested-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
lttng/org.eclipse.tracecompass.lttng2.kernel.core.tests/src/org/eclipse/tracecompass/lttng2/kernel/core/tests/analysis/kernel/statesystem/StateSystemTest.java
statesystem/org.eclipse.tracecompass.statesystem.core.tests/src/org/eclipse/tracecompass/statesystem/core/tests/AttributeTreeTest.java
statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/Attribute.java
statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/AttributeTree.java
statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/internal/statesystem/core/StateSystem.java
statesystem/org.eclipse.tracecompass.statesystem.core/src/org/eclipse/tracecompass/statesystem/core/ITmfStateSystem.java

index ebb379b34efedc08d7835d855cb9f45447ac52dd..0f869c1beea9af8709a5b952559b70e8b6b9fb4b 100644 (file)
@@ -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 <alexandre.montplaisir@gmail.com>
  *
 
 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<Integer> 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();
         }
index 9fa9aee2dbb51c2a64a416ccd6dab4517b83120f..22fb6145fe1edc7b5beb26dddd58fc1b27d8a23f 100644 (file)
@@ -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)));
             }
index 0fe8418bda6e02089d886bb7843ed43424603939..ff26cc0f375cbed93d08c15f9fffc5d2132715a5 100644 (file)
@@ -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();
     }
index 54ea463e83e88d404e0147dd6300feb7170f3022..fa3ca8ed31fb9f2f880a2ab80d2d34d13087e694 100644 (file)
@@ -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 <alexandre.montplaisir@gmail.com>
  *
@@ -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 <code>-1</code>
+     * parent and will return {@link ITmfStateSystem#ROOT_ATTRIBUTE}.
      *
      * @param quark
      *            The quark of the attribute
-     * @return Quark of the parent attribute or <code>-1</code> 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();
index d4c85ff77cc79f5bae48f31d62597d7d1e18faff..e11bccc437f0f657d36b2073ebaf7b316abca698 100644 (file)
@@ -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 <alexandre.montplaisir@gmail.com>
  *
@@ -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;
index 3236bfc4a88a8bf69307542784619fe7ae1cf79e..8af7d09953ad3b693f64194d3e54b0dde11d9d72 100644 (file)
@@ -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.
-     *
+     * <p>
      * This version will NOT create any new attributes. If an invalid attribute
      * is requested, an exception will be thrown.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
-     *
+     * <p>
      * 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.
-     *
+     * <p>
      * This version will NOT create any new attributes. If an invalid attribute
      * is requested, an exception will be thrown.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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 <code>-1</code> 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
      */
This page took 0.035314 seconds and 5 git commands to generate.