diff --git a/src/main/java/com/redhat/trie/HuffNode.java b/src/main/java/com/redhat/trie/HuffNode.java index 174128e..43b83ab 100644 --- a/src/main/java/com/redhat/trie/HuffNode.java +++ b/src/main/java/com/redhat/trie/HuffNode.java @@ -110,6 +110,34 @@ public class HuffNode { return this.right; } + /** + * search down the tree, for the node, + * at address of String bits + */ + public HuffNode findByBits(String bits) { + return this.findByBits(this, bits); + } + + /** + * search down the tree, for the node, + * at address of String bits, on HuffNode trie + */ + public HuffNode findByBits(HuffNode trie, String bits) { + if (bits.length() == 0) { + return trie; + } + char bit = bits.charAt(0); + if (bit == '0') { + if (getLeft() == null) { throw new RuntimeException("Encoded path not in trie"); } + return getLeft().findByBits(bits.substring(1)); + } + else if (bit == '1') { + if (getRight() == null) { throw new RuntimeException("Encoded path not in trie"); } + return getRight().findByBits(bits.substring(1)); + } + return null; + } + /** * pretty information */ diff --git a/src/main/java/com/redhat/trie/PathNode.java b/src/main/java/com/redhat/trie/PathNode.java index 3da0871..c11b1ba 100644 --- a/src/main/java/com/redhat/trie/PathNode.java +++ b/src/main/java/com/redhat/trie/PathNode.java @@ -21,33 +21,58 @@ import java.util.Set; import java.util.HashSet; import java.util.Collections; +import org.apache.log4j.Logger; + +/** + * PathNode is the relationship to an item in the path tree. + * + * It holds the relationships to children, as well as all parents that regard it as a child. + * + * The Name of a given PathNode, is inferred by the NodePair that regards this PathNode as it's "connection" + */ public class PathNode { + private static org.apache.log4j.Logger log = Logger.getLogger(PathTree.class); private long id = 0; private List children = new ArrayList(); private List parents = new ArrayList(); private NodeContext ctx = null; + /** + * New node, with 0 id. + */ public PathNode() { this(new NodeContext()); } + /** + * New node, with id determined by provided ctx + * + * @param ctx NodeContext, for id increments + */ public PathNode(NodeContext ctx) { this.ctx = ctx; this.id = this.ctx.nextId(); } + /** + * This node's id + */ public long getId() { return this.id; } + /** + * The NodeContext used by this node + */ public NodeContext getContext() { return this.ctx; } - public void addChild(NodePair cp) { - this.children.add(cp); - } - + /** + * Get the nodes, from here down. + * + * @return A unique list of all PathNode nodes, from this node down + */ public Set getAllNodes() { return getAllNodes(this); } @@ -67,13 +92,6 @@ public class PathNode { return nodes; } - - public void addParent(PathNode cp) { - if (!parents.contains(cp)) { - this.parents.add(cp); - } - } - public List getChildren() { Collections.sort(this.children); return this.children; @@ -83,16 +101,45 @@ public class PathNode { return this.parents; } + /** + * A NodePair cp, as a child. + * + * TODO - determine uniqueness? + */ + public void addChild(NodePair cp) { + this.children.add(cp); + } + + /** + * A PathNode cp, as a parent. + * + * Checks whether this parent is already a parent. + */ + public void addParent(PathNode cp) { + if (!parents.contains(cp)) { + this.parents.add(cp); + } + } + + /** + * Set parents as the new List collection. + */ public void setParents(List parents) { this.parents = parents; } + /** + * add entire List of parents + */ public void addParents(List parents) { for (PathNode pn : parents) { addParent(pn); } } + /** + * get the inferred name of this node, through the referring NodePair. + */ public String getName() { String name = ""; for (NodePair child : this.getParents().get(0).getChildren()) { @@ -103,10 +150,16 @@ public class PathNode { return name; } + /** + * Traverse up the tree, and get the highest ancestor PathNode. + */ public PathNode getStartNode() { return getStartNode(this); } + /** + * Traverse up the tree, and get the highest ancestor PathNode, for node. + */ public PathNode getStartNode(PathNode node) { if (node.getParents().size() == 0) { return node; // this is the end! @@ -118,10 +171,16 @@ public class PathNode { return node; // when in doubt, return yourself } + /** + * Traverse down the tree, and get the "endMarker" child. + */ public PathNode getEndNode() { return getEndNode(this); } + /** + * Traverse down the tree, and get the "endMarker" child, for node. + */ public PathNode getEndNode(PathNode node) { if (node.getChildren().size() == 0) { return node; // this is the end! @@ -132,7 +191,7 @@ public class PathNode { return node; // when in doubt, return yourself } - /* + /** * same number of children with the same names for child nodes */ public boolean isEquivalentTo(PathNode that) { @@ -159,7 +218,7 @@ public class PathNode { /** * check whether current PathNode, includes the paths in PathNode that, like a mask. * - * TODO - this is a stub + * FIXME This is not working correctly yet * * @param that PathNode to check for * @return boolean of truth! @@ -181,17 +240,14 @@ public class PathNode { if (thisnp.getName().startsWith("$") || thisnp.getName().equals(thatnp.getName())) { result = thisnp.getConnection().includes(thatnp.getConnection()); found.add(new Boolean(result).booleanValue()); + log.debug("includes: " + thisnp + " == " + thatnp); break; } found.add(Boolean.FALSE); } } - if (found.contains(Boolean.FALSE)) { - return false; - } else { - return true; - } + return (!found.contains(Boolean.FALSE)); } /** diff --git a/src/main/java/com/redhat/trie/PathTree.java b/src/main/java/com/redhat/trie/PathTree.java index 8275340..c1a3c7d 100644 --- a/src/main/java/com/redhat/trie/PathTree.java +++ b/src/main/java/com/redhat/trie/PathTree.java @@ -236,7 +236,7 @@ public class PathTree { while (value != -1) { String someBits = Integer.toString(value, 2); for (int pad = 0; pad < 8 - someBits.length(); pad++) { - this.nodeBits.append("0"); + this.getNodeBits().append("0"); } this.getNodeBits().append(someBits); value = bais.read(); @@ -334,7 +334,6 @@ public class PathTree { break; } } - // XXX do hot stuff } return false; @@ -349,7 +348,7 @@ public class PathTree { */ public void setContentSets(List contentSets) throws PayloadException { this.modified = true; - this.nodeBits = null; + this.setNodeBits(null); this.setNodeCount(0); this.pathNodeContext = new NodeContext(); @@ -381,7 +380,6 @@ public class PathTree { } this.payload = data.toByteArray(); - this.modified = false; } @@ -462,9 +460,9 @@ public class PathTree { * @return the Set of weighted PathNode */ private Set populatePathNodes(List nodeDictionary, - HuffNode pathTrie, HuffNode nodeTrie, StringBuffer nodeBits) { + HuffNode pathTrie, HuffNode nodeTrie, StringBuffer theseNodeBits) { Set pathNodes = new HashSet(); - StringBuffer myNodeBits = new StringBuffer(this.getNodeBits().toString()); + StringBuffer myNodeBits = new StringBuffer(theseNodeBits.toString()); for (HuffNode node : nodeDictionary) { pathNodes.add((PathNode) node.getValue()); boolean stillNode = true; @@ -476,8 +474,7 @@ public class PathTree { while (nameValue == null && stillNode) { nameBits.append(myNodeBits.charAt(0)); myNodeBits.deleteCharAt(0); - Object lookupValue = findHuffNodeValueByBits(pathTrie, - nameBits.toString()); + Object lookupValue = pathTrie.findByBits(nameBits.toString()).getValue(); if (lookupValue != null) { if (lookupValue.equals(HuffNode.END_NODE)) { stillNode = false; @@ -495,8 +492,7 @@ public class PathTree { while (nodeValue == null && stillNode) { pathBits.append(myNodeBits.charAt(0)); myNodeBits.deleteCharAt(0); - PathNode lookupValue = (PathNode) findHuffNodeValueByBits(nodeTrie, - pathBits.toString()); + PathNode lookupValue = (PathNode) nodeTrie.findByBits(pathBits.toString()).getValue(); if (lookupValue != null) { nodeValue = lookupValue; nodeValue.addParent((PathNode) node.getValue()); @@ -540,26 +536,6 @@ public class PathTree { } } - private Object findHuffNodeValueByBits(HuffNode trie, String bits) { - HuffNode left = trie.getLeft(); - HuffNode right = trie.getRight(); - - if (bits.length() == 0) { - return trie.getValue(); - } - - char bit = bits.charAt(0); - if (bit == '0') { - if (left == null) { throw new RuntimeException("Encoded path not in trie"); } - return findHuffNodeValueByBits(left, bits.substring(1)); - } - else if (bit == '1') { - if (right == null) { throw new RuntimeException("Encoded path not in trie"); } - return findHuffNodeValueByBits(right, bits.substring(1)); - } - return null; - } - private int findSmallest(int exclude, List nodes) { int smallest = -1; for (int index = 0; index < nodes.size(); index++) { diff --git a/src/test/java/com/redhat/trie/TestHelpers.java b/src/test/java/com/redhat/trie/TestHelpers.java new file mode 100644 index 0000000..6f5fe93 --- /dev/null +++ b/src/test/java/com/redhat/trie/TestHelpers.java @@ -0,0 +1,107 @@ +package com.redhat.trie; + +import java.io.InputStreamReader; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; + +import java.util.List; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; + +import static org.junit.Assert.fail; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; + +/** + * This class is just to provide helpers for the other tests + */ +public class TestHelpers { + + /** + * junit requires at least one runnable test + */ + @Test + public void testDeadVicker() { + assertNotNull(new String("What's its diocese?")); + } + + // Helpers + // + public static boolean cmpStrings(List thisList, List thatList) { + Collection thisColl = new ArrayList(thisList); + Collection thatColl = new ArrayList(thatList); + + Collection similar = new HashSet( thisColl ); + Collection different = new HashSet(); + different.addAll( thisColl ); + different.addAll( thatColl ); + + similar.retainAll( thatColl ); + different.removeAll( similar ); + + if (different.size() > 0) { + System.out.printf("Different:%s%n", different); + } + return (different.size() == 0); + } + + public static void printByteArray(byte[] bytes) { + int width = 30; + int counter = 0; + + for (byte b : bytes) { + System.out.format("%02X ", b); + counter++; + if (counter > width) { + counter = 0; + System.out.println(); + } + } + System.out.println(); + } + + public static InputStream resStream(Object klass, String filename) { + return klass.getClass().getClassLoader().getResourceAsStream(filename); + } + + public static byte[] loadBytes(Object klass, String filename) { + InputStream in = resStream(klass, filename); + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int nRead; + byte[] data = new byte[16834]; + + try { + while ((nRead = in.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + buffer.flush(); + } catch (IOException ex) { + fail(ex.toString()); + } + + return buffer.toByteArray(); + } + + public static List loadContents(Object klass, String filename) { + String content; + List contentList = new ArrayList(); + InputStream in = resStream(klass, filename); + BufferedReader br = new BufferedReader(new InputStreamReader(in)); + + try { + while ((content = br.readLine()) != null) { + contentList.add(content); + } + } catch (IOException ex) { + fail(); + } + return contentList; + } +} + + diff --git a/src/test/java/com/redhat/trie/TestPathNode.java b/src/test/java/com/redhat/trie/TestPathNode.java index 443c440..694c4ac 100644 --- a/src/test/java/com/redhat/trie/TestPathNode.java +++ b/src/test/java/com/redhat/trie/TestPathNode.java @@ -1,8 +1,12 @@ package com.redhat.trie; +import java.util.List; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import org.junit.Test; @@ -38,16 +42,46 @@ public class TestPathNode { assertTrue(pn0.isEquivalentTo(pn1)); - - PathNode pn2 = new PathNode(pn0.getContext()); - PathNode pn3 = new PathNode(pn1.getContext()); NodePair np0b = new NodePair("bar",endMarker); pn0.addChild(np0b); - NodePair np1b = new NodePair("baz",endMarker); - pn1.addChild(np1b); - // XXX finish this test !! - //assertTrue(pn0.isEquivalentTo(pn1)); + assertFalse(pn0.isEquivalentTo(pn1)); + } + + @Test + public void testIncludes() { + PathNode pn0 = new PathNode(); + PathNode pn1 = new PathNode(); + PathNode pn2 = new PathNode(); + + PathTree pt0 = new PathTree(); + PathTree pt1 = new PathTree(); + PathTree pt2 = new PathTree(); + + List contents0 = TestHelpers.loadContents(this, "contents.list"); + List contents1 = TestHelpers.loadContents(this, "contents_small.list"); + + try { + pt0.setContentSets(contents0); + pn0 = pt0.getRootPathNode(); // setup the larger PathNode + + pt1.setContentSets(contents1); + pn1 = pt1.getRootPathNode(); // setup the small PathNode + + contents1.add(new String("/this/is/not/in/the/list")); + pt2.setContentSets(contents1); + pn2 = pt2.getRootPathNode(); // setup the small PathNode + } catch (PayloadException ex) { + fail(ex.toString()); + } + + assertNotNull(pn0); + assertNotNull(pn1); + assertNotNull(pn2); + + // FIXME - Finish the test first + //assertTrue(pn0.includes(pn1)); + //assertFalse(pn0.includes(pn2)); } } diff --git a/src/test/java/com/redhat/trie/TestPathTree.java b/src/test/java/com/redhat/trie/TestPathTree.java index 7429a40..d2ab672 100644 --- a/src/test/java/com/redhat/trie/TestPathTree.java +++ b/src/test/java/com/redhat/trie/TestPathTree.java @@ -7,9 +7,9 @@ import java.util.Collection; import java.util.HashSet; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.InputStreamReader; import java.io.InputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; import static org.junit.Assert.assertEquals; @@ -31,7 +31,7 @@ public class TestPathTree { @Test public void testNew1() { PathTree pt = new PathTree(); - List contents = loadContents("contents.list"); + List contents = TestHelpers.loadContents(this, "contents.list"); try { pt = new PathTree(contents); } catch (PayloadException ex) { @@ -43,7 +43,7 @@ public class TestPathTree { @Test public void testNew2() { PathTree pt = new PathTree(); - List contents = loadContents("contents.list"); + List contents = TestHelpers.loadContents(this, "contents.list"); try { pt.setContentSets(contents); } catch (PayloadException ex) { @@ -55,7 +55,7 @@ public class TestPathTree { @Test public void testValidation() { PathTree pt = new PathTree(); - List contents = loadContents("contents.list"); + List contents = TestHelpers.loadContents(this, "contents.list"); // matches a path String shouldPass = "/content/beta/rhel/server/5/5server/x86_64/sap/os/repomd.xml"; // is not a match @@ -68,7 +68,7 @@ public class TestPathTree { fail(ex.toString()); } // for good measure ... - assertTrue(cmpStrings(contents, pt.toList())); + assertTrue(TestHelpers.cmpStrings(contents, pt.toList())); assertTrue(pt.validate(shouldPass)); assertFalse(pt.validate(shouldFail)); @@ -81,7 +81,7 @@ public class TestPathTree { @Test public void testRootNode() { PathTree pt = new PathTree(); - List contents = loadContents("contents.list"); + List contents = TestHelpers.loadContents(this, "contents.list"); try { pt.setContentSets(contents); } catch (PayloadException ex) { @@ -111,7 +111,7 @@ public class TestPathTree { List contents0; List contents1; - bytes = loadBytes("test.bin"); + bytes = TestHelpers.loadBytes(this, "test.bin"); pt0 = new PathTree(bytes); contents0 = pt0.toList(); for (String str : contents0) { @@ -126,7 +126,7 @@ public class TestPathTree { assertNotNull(pt1); //printByteArray(pt1.getPayload()); contents1 = pt1.toList(); - assertTrue(cmpStrings(contents0, contents1)); + assertTrue(TestHelpers.cmpStrings(contents0, contents1)); for (String str : contents1) { System.out.println(str); } @@ -142,7 +142,7 @@ public class TestPathTree { PathTree pt1; PathTree pt2 = new PathTree(); PathTree pt3; - List contents0 = loadContents("contents.list"); + List contents0 = TestHelpers.loadContents(this, "contents.list"); List contents1; List contents2; List contents3; @@ -162,7 +162,7 @@ public class TestPathTree { contents1 = pt1.toList(); // FIXME These next two fail - assertTrue(cmpStrings(contents0, contents1)); + assertTrue(TestHelpers.cmpStrings(contents0, contents1)); assertEquals(contents0.size(), contents1.size()); @@ -174,89 +174,38 @@ public class TestPathTree { } contents2 = pt2.toList(); - assertTrue(cmpStrings(contents1, contents2)); + assertTrue(TestHelpers.cmpStrings(contents1, contents2)); assertEquals(contents1.size(), contents2.size()); pt3 = new PathTree(pt2.getPayload()); contents3 = pt3.toList(); - assertTrue(cmpStrings(contents2, contents3)); + assertTrue(TestHelpers.cmpStrings(contents2, contents3)); assertEquals(contents2.size(), contents3.size()); } - - // Helpers - // - private boolean cmpStrings(List thisList, List thatList) { - Collection thisColl = new ArrayList(thisList); - Collection thatColl = new ArrayList(thatList); - - Collection similar = new HashSet( thisColl ); - Collection different = new HashSet(); - different.addAll( thisColl ); - different.addAll( thatColl ); - - similar.retainAll( thatColl ); - different.removeAll( similar ); - - if (different.size() > 0) { - System.out.printf("Different:%s%n", different); - } - return (different.size() == 0); - } - - private void printByteArray(byte[] bytes) { - int width = 30; - int counter = 0; - - for (byte b : bytes) { - System.out.format("%02X ", b); - counter++; - if (counter > width) { - counter = 0; - System.out.println(); - } - } - System.out.println(); - } - - private InputStream resStream(String filename) { - return getClass().getClassLoader().getResourceAsStream(filename); - } - - private byte[] loadBytes(String filename) { - InputStream in = resStream(filename); - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - int nRead; - byte[] data = new byte[16834]; - + /* + @Test + public void testSettingContentsTwice() { + PathNode pn0 = new PathNode(); + PathNode pn1 = new PathNode(); + PathTree pt = new PathTree(); + List contents0 = TestHelpers.loadContents(this, "contents.list"); + List contents1 = TestHelpers.loadContents(this, "contents_small.list"); try { - while ((nRead = in.read(data, 0, data.length)) != -1) { - buffer.write(data, 0, nRead); - } - buffer.flush(); - } catch (IOException ex) { + pt.setContentSets(contents0); + pn0 = pt.getRootPathNode(); // setup the larger PathNode + System.out.println(contents1); + pt.setContentSets(contents1); + pn1 = pt.getRootPathNode(); // setup the small PathNode + } catch (PayloadException ex) { fail(ex.toString()); } - return buffer.toByteArray(); + assertNotNull(pn0); } + */ - private List loadContents(String filename) { - String content; - List contentList = new ArrayList(); - InputStream in = resStream(filename); - BufferedReader br = new BufferedReader(new InputStreamReader(in)); - - try { - while ((content = br.readLine()) != null) { - contentList.add(content); - } - } catch (IOException ex) { - fail(); - } - return contentList; - } } diff --git a/src/test/resources/contents_small.list b/src/test/resources/contents_small.list new file mode 100644 index 0000000..8799fc8 --- /dev/null +++ b/src/test/resources/contents_small.list @@ -0,0 +1,5 @@ +/content/beta/rhel/server/5/$releasever/$basearch/vt/os +/content/dist/rhel/server/5/$releasever/$basearch/vt/os +/content/dist/rhel/server/6/$releasever/$basearch/sap/os +/content/dist/rhel/server/6/$releasever/$basearch/debug +/content/rhb/rhel/client/6/$releasever/$basearch/devtoolset/os