Mercurial > hg > thermostat-ng > agent
changeset 2446:bc7fbc2c3512
Use graph API in storage populator command.
Reviewed-by: jerboaa
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2016-September/020829.html
line wrap: on
line diff
--- a/dependency-tool/command/src/main/java/com/redhat/thermostat/tools/dependency/internal/TopologicalSort.java Fri Sep 09 08:51:50 2016 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -/* - * Copyright 2012-2016 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.tools.dependency.internal; - -import com.redhat.thermostat.collections.graph.DFSPayload; -import com.redhat.thermostat.collections.graph.DefaultTraversalListener; -import com.redhat.thermostat.collections.graph.DepthFirstSearch; -import com.redhat.thermostat.collections.graph.Node; -import com.redhat.thermostat.collections.graph.Relationship; -import com.redhat.thermostat.collections.graph.RelationshipType; -import com.redhat.thermostat.collections.graph.SearchPayload; - -import java.util.HashSet; -import java.util.Set; -import java.util.Stack; - -/** - */ -public class TopologicalSort extends DefaultTraversalListener { - private Stack<Node> ordered; - private Set<Node> discovered; - - public TopologicalSort(Stack<Node> ordered, Set<Node> discovered) { - this.ordered = ordered; - this.discovered = discovered; - } - - public TopologicalSort() { - this.ordered = new Stack<>(); - this.discovered = new HashSet<>(); - } - - public Stack<Node> getOrdered() { - return ordered; - } - - public Set<Node> getDiscovered() { - return discovered; - } - - @Override - protected void preProcessNodeImpl(Node node) { - discovered.add(node); - } - - @Override - protected void postProcessNodeImpl(Node node) { - ordered.add(node); - } - - @Override - public Status processRelationship(Relationship relationship, - SearchPayload payload) - { - RelationshipType type = - DepthFirstSearch.classify(relationship, (DFSPayload) payload); - - if (type.equals(RelationshipType.BACK)) { - throw new IllegalStateException("back node! " + relationship); - } - - return Status.CONTINUE; - } -}
--- a/dependency-tool/command/src/main/java/com/redhat/thermostat/tools/dependency/internal/actions/ListDependenciesAction.java Fri Sep 09 08:51:50 2016 -0400 +++ b/dependency-tool/command/src/main/java/com/redhat/thermostat/tools/dependency/internal/actions/ListDependenciesAction.java Mon Sep 12 12:53:41 2016 -0400 @@ -42,7 +42,7 @@ import com.redhat.thermostat.common.cli.CommandContext; import com.redhat.thermostat.tools.dependency.internal.DependencyGraphBuilder; import com.redhat.thermostat.tools.dependency.internal.PathProcessorHandler; -import com.redhat.thermostat.tools.dependency.internal.TopologicalSort; +import com.redhat.thermostat.collections.graph.TopologicalSort; import com.redhat.thermostat.tools.dependency.internal.Utils; import java.nio.file.Path;
--- a/dev/storage-populator/command/pom.xml Fri Sep 09 08:51:50 2016 -0400 +++ b/dev/storage-populator/command/pom.xml Mon Sep 12 12:53:41 2016 -0400 @@ -131,6 +131,11 @@ <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-platform-collections</artifactId> + <version>${project.version}</version> + </dependency> </dependencies> </project>
--- a/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/PopulationConfig.java Fri Sep 09 08:51:50 2016 -0400 +++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/PopulationConfig.java Mon Sep 12 12:53:41 2016 -0400 @@ -37,156 +37,118 @@ package com.redhat.thermostat.storage.populator.internal.config; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.ArrayList; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.redhat.thermostat.collections.graph.DepthFirstSearch; +import com.redhat.thermostat.collections.graph.HashGraph; import com.redhat.thermostat.storage.populator.internal.config.typeadapter.ConfigItemTypeAdapter; import com.redhat.thermostat.storage.populator.internal.config.typeadapter.PopulationConfigTypeAdapterFactory; import com.redhat.thermostat.storage.populator.internal.config.typeadapter.RelationShipTypeAdapter; -import com.redhat.thermostat.storage.populator.internal.dependencies.Relationship; +import com.redhat.thermostat.collections.graph.Relationship; +import com.redhat.thermostat.collections.graph.TopologicalSort; +import com.redhat.thermostat.collections.graph.Graph; +import com.redhat.thermostat.collections.graph.Node; public class PopulationConfig { public static final String RECORDS = "records"; public static final String RELATIONSHIPS = "relationships"; - private final Map<String, ConfigItem> configs; - private final List<ConfigItem> allConfigs; - private final Map<String, List<Relationship>> incomingRelationShips; - private final Map<String, List<Relationship>> outgoingRelationShips; + public static final String ITEM = "item"; + private final Map<String, Node> configs; + private final Map<Node, Set<Relationship>> relationshipMap; + private final Graph graph; private PopulationConfig() { configs = new HashMap<>(); - allConfigs = new ArrayList<>(); - incomingRelationShips = new HashMap<>(); - outgoingRelationShips = new HashMap<>(); + graph = new HashGraph(); + relationshipMap = new HashMap<>(); } - public ConfigItem getConfig(String name) { - return configs.get(name); + public Node getConfig(String configItem) { + Node cfg = configs.get(configItem); + if (cfg == null) { + throw new InvalidConfigurationException("Config is missing from collection!"); + } + return cfg; } public List<ConfigItem> getConfigsTopologicallySorted() { - return topologicallySort(allConfigs); + return topologicallySort(); } - + /** * Sort config items topologically. That is, get them in an order so as * to process collections with no incoming links to other collections. - * - * It uses Kahn's algorithm to do so. - * - * @param configs unsorted configs. + * + * It uses the standard DFS algorithm to do so. + * * @return A topologically sorted list. */ - private List<ConfigItem> topologicallySort(List<ConfigItem> configs) { - LinkedList<ConfigItem> sortedList = new LinkedList<>(); - LinkedList<ConfigItem> queue = getConfigItemsWithNoIncomingEdge(configs); - while (!queue.isEmpty()) { - ConfigItem n = queue.remove(0); - sortedList.addLast(n); - List<Relationship> source = getOutgoingRelationShipsForConfig(n); - List<Relationship> outgoingRels = new LinkedList<>(source); - for (Relationship edge: outgoingRels) { - ConfigItem m = getConfig(edge.getTo()); - removeEdge(edge, n, m); - if (hasNoIncomingEdge(m)) { - queue.addLast(m); - } - } + private List<ConfigItem> topologicallySort() { + DepthFirstSearch dfs = new DepthFirstSearch(graph); + TopologicalSort tsort = new TopologicalSort(); + List<Node> roots = getRoots(); + Set<ConfigItem> cfgs = new LinkedHashSet<>(); + // If no roots were found to start from, the graph must be cyclic or empty. + if (roots.size() == 0) { + throw new InvalidConfigurationException("Relationships form cycle!"); } - if (hasRelationShips(configs)) { - throw new AssertionError("Relationships form at least one cycle! Excpected an acyclic directed graph."); - } - return sortedList; - } - private boolean hasRelationShips(List<ConfigItem> configs) { - for (ConfigItem i: configs) { - List<Relationship> incoming = getIncomingRelationShipsForConfig(i); - List<Relationship> outgoing = getOutgoingRelationShipsForConfig(i); - if (!incoming.isEmpty() || - !outgoing.isEmpty()) { - // We are going to bomb, print some debug info. - System.err.println("outgoings for " + i.getName() + " " + outgoing); - System.err.println("incomings for " + i.getName() + " " + incoming); - return true; + for (Node root : roots) { + dfs.search(getConfig(root.getName()), tsort); + for (Node n : tsort.getOrdered()) { + Node cfg = getConfig(n.getName()); + cfgs.add((ConfigItem) cfg.getProperty(ITEM)); } + // Isolated nodes will return empty from DFS + if (tsort.getOrdered().size() == 0) { + cfgs.add((ConfigItem) root.getProperty(ITEM)); + } + dfs.reset(); + tsort.reset(); } - return false; - } - private void removeEdge(Relationship toRemove, ConfigItem from, ConfigItem to) { - if (from == null || to == null) { - throw new InvalidConfigurationException("Found relationship [" + - toRemove + - "] but either incoming or outgoing records config is missing"); - } - List<Relationship> incoming = getIncomingRelationShipsForConfig(to); - List<Relationship> outgoing = getOutgoingRelationShipsForConfig(from); - incoming.remove(toRemove); - outgoing.remove(toRemove); + List<ConfigItem> ordered = new ArrayList<>(cfgs); + Collections.reverse(ordered); + return ordered; } - private LinkedList<ConfigItem> getConfigItemsWithNoIncomingEdge(List<ConfigItem> allConfigs) { - LinkedList<ConfigItem> startNodes = new LinkedList<>(); - for (ConfigItem item: allConfigs) { - if (hasNoIncomingEdge(item)) { - startNodes.add(item); + private List<Node> getRoots() { + List<Node> roots = new ArrayList<>(); + for (Node n : relationshipMap.keySet()) { + if (relationshipMap.get(n).size() == 0) { + roots.add(n); } } - return startNodes; + return roots; } - private boolean hasNoIncomingEdge(ConfigItem item) { - List<Relationship> rels = getIncomingRelationShipsForConfig(item); - if (rels == null || rels.isEmpty()) { - return true; - } - return false; - } - - private List<Relationship> getIncomingRelationShipsForConfig(ConfigItem item) { - List<Relationship> result = incomingRelationShips.get(item.getName()); - if (result == null) { - return Collections.emptyList(); - } - return result; + private void addConfig(ConfigItem configItem) { + Node item = new Node(configItem.getName()); + item.setProperty(ITEM, configItem); + configs.put(item.getName(), item); + relationshipMap.put(item, new HashSet<Relationship>()); } - private List<Relationship> getOutgoingRelationShipsForConfig(ConfigItem item) { - List<Relationship> result = outgoingRelationShips.get(item.getName()); - if (result == null) { - return Collections.emptyList(); + private void addRelationShip(Relationship relationship) { + graph.addRelationship(relationship); + if (relationshipMap.get(relationship.getTo()) == null) { + Set<Relationship> rels = new HashSet<>(); + rels.add(relationship); + relationshipMap.put(relationship.getTo(), rels); } - return result; - } - - private void addConfig(ConfigItem item) { - configs.put(item.getName(), item); - allConfigs.add(item); - } - - private void addIncomingRelationShipForConfig(ConfigItem item, Relationship relationship) { - addRelationShip(item, relationship, incomingRelationShips); - } - - private void addOutgoingRelationShipForConfig(ConfigItem item, Relationship relationship) { - addRelationShip(item, relationship, outgoingRelationShips); - } - - private void addRelationShip(ConfigItem item, Relationship relationship, Map<String, List<Relationship>> map) { - List<Relationship> existingRels = map.get(item.getName()); - if (existingRels == null) { - existingRels = new LinkedList<>(); - map.put(item.getName(), existingRels); + else { + relationshipMap.get(relationship.getTo()).add(relationship); } - existingRels.add(relationship); } public static PopulationConfig parseFromJsonString(String json) throws IOException { @@ -204,14 +166,7 @@ for (ConfigItem item: items) { pc.addConfig(item); for (Relationship r: rels) { - // keep track of incoming relationships (incoming edge) - if (r.getTo().equals(item.getName())) { - pc.addIncomingRelationShipForConfig(item, r); - } - // keep track of outgoing relationships (outgoing edge) - if (r.getFrom().equals(item.getName())) { - pc.addOutgoingRelationShipForConfig(item, r); - } + pc.addRelationShip(r); } } return pc;
--- a/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/PopulationConfigTypeAdapter.java Fri Sep 09 08:51:50 2016 -0400 +++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/PopulationConfigTypeAdapter.java Mon Sep 12 12:53:41 2016 -0400 @@ -50,7 +50,7 @@ import com.google.gson.stream.JsonWriter; import com.redhat.thermostat.storage.populator.internal.config.ConfigItem; import com.redhat.thermostat.storage.populator.internal.config.PopulationConfig; -import com.redhat.thermostat.storage.populator.internal.dependencies.Relationship; +import com.redhat.thermostat.collections.graph.Relationship; public class PopulationConfigTypeAdapter extends TypeAdapter<PopulationConfig> {
--- a/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/RelationShipTypeAdapter.java Fri Sep 09 08:51:50 2016 -0400 +++ b/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/RelationShipTypeAdapter.java Mon Sep 12 12:53:41 2016 -0400 @@ -44,10 +44,15 @@ import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; -import com.redhat.thermostat.storage.populator.internal.dependencies.Relationship; +import com.redhat.thermostat.collections.graph.Relationship; +import com.redhat.thermostat.collections.graph.Node; public class RelationShipTypeAdapter extends TypeAdapter<Relationship> { + private static final String TO = "to"; + private static final String FROM = "from"; + private static final String KEY = "key"; + @Override public Relationship read(JsonReader in) throws IOException { // handle null @@ -68,20 +73,22 @@ while (in.hasNext()) { String name = in.nextName(); switch(name) { - case Relationship.FROM: - values.put(Relationship.FROM, in.nextString()); + case FROM: + values.put(FROM, in.nextString()); break; - case Relationship.TO: - values.put(Relationship.TO, in.nextString()); + case TO: + values.put(TO, in.nextString()); break; - case Relationship.KEY: - values.put(Relationship.KEY, in.nextString()); + case KEY: + values.put(KEY, in.nextString()); break; default: throw new IllegalStateException("Unknown relationship value: '" + name + "'"); } } - return new Relationship(values.get(Relationship.FROM), values.get(Relationship.TO), values.get(Relationship.KEY)); + Relationship r = new Relationship(new Node(values.get(FROM)), "->", new Node(values.get(TO))); + r.setProperty(KEY, values.get(KEY)); + return r; } @Override
--- a/dev/storage-populator/command/src/main/java/com/redhat/thermostat/storage/populator/internal/dependencies/Relationship.java Fri Sep 09 08:51:50 2016 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * Copyright 2012-2016 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.storage.populator.internal.dependencies; - -import java.util.Objects; - -public class Relationship { - - public static final String TO = "to"; - public static final String FROM = "from"; - public static final String KEY = "key"; - private final String from; - private final String to; - private final String key; - - public Relationship(String from, String to, String key) { - this.from = from; - this.to = to; - this.key = key; - } - - public String getFrom() { - return from; - } - - public String getTo() { - return to; - } - - public String getKey() { - return key; - } - - @Override - public boolean equals(Object o) { - if (o == null || o.getClass() != Relationship.class) { - return false; - } - Relationship other = (Relationship)o; - return Objects.equals(to, other.to) && - Objects.equals(from, other.from) && - Objects.equals(key, other.key); - } - - @Override - public int hashCode() { - return Objects.hash(to, from, key); - } - - @Override - public String toString() { - return from + " -> " + to + "(" + key + ")"; - } -}
--- a/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/config/PopulationConfigTest.java Fri Sep 09 08:51:50 2016 -0400 +++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/config/PopulationConfigTest.java Mon Sep 12 12:53:41 2016 -0400 @@ -49,7 +49,8 @@ import org.junit.Test; -import com.redhat.thermostat.storage.populator.internal.dependencies.Relationship; +import com.redhat.thermostat.collections.graph.Relationship; +import com.redhat.thermostat.collections.graph.Node; import com.redhat.thermostat.storage.populator.internal.config.ConfigItem; import com.redhat.thermostat.storage.populator.internal.config.PopulationConfig; @@ -67,16 +68,16 @@ public void canParseFromFile() throws IOException { String json = new String(Files.readAllBytes(new File(getClass().getResource("/testconfig").getFile()).toPath())); PopulationConfig config = PopulationConfig.parseFromJsonString(json); - ConfigItem item = config.getConfig("agent-config"); + ConfigItem item = config.getConfig("agent-config").getProperty("item"); assertNotNull(item); assertEquals(100, item.getNumber()); assertEquals(20, item.getAliveItems()); List<ConfigItem> items = config.getConfigsTopologicallySorted(); assertEquals(7, items.size()); - item = config.getConfig("vm-info"); + item = config.getConfig("vm-info").getProperty("item"); assertEquals(50, item.getNumber()); assertEquals(40, item.getAliveItems()); - item = config.getConfig("vm-gc-stats"); + item = config.getConfig("vm-gc-stats").getProperty("item"); assertNotNull(item); } @@ -149,15 +150,20 @@ private List<Relationship> buildGoodRels() { List<Relationship> relationships = new LinkedList<>(); - Relationship agentConfigToNetworkInfo = new Relationship(AGENT_CONFIG_NAME, NETWORK_INFO_NAME, AGENT_KEY); + Relationship agentConfigToNetworkInfo = new Relationship(new Node(AGENT_CONFIG_NAME), "->", new Node(NETWORK_INFO_NAME)); + agentConfigToNetworkInfo.setProperty("key", AGENT_KEY); relationships.add(agentConfigToNetworkInfo); - Relationship agentConfigToVmGcStat = new Relationship(AGENT_CONFIG_NAME, VM_GC_STAT_NAME, AGENT_KEY); + Relationship agentConfigToVmGcStat = new Relationship(new Node(AGENT_CONFIG_NAME), "->", new Node(VM_GC_STAT_NAME)); + agentConfigToVmGcStat.setProperty("key", AGENT_KEY); relationships.add(agentConfigToVmGcStat); - Relationship agentConfigToHostInfo = new Relationship(AGENT_CONFIG_NAME, HOST_INFO_NAME, AGENT_KEY); + Relationship agentConfigToHostInfo = new Relationship(new Node(AGENT_CONFIG_NAME), "->", new Node(HOST_INFO_NAME)); + agentConfigToHostInfo.setProperty("key", AGENT_KEY); relationships.add(agentConfigToHostInfo); - Relationship agentConfigToVmInfo = new Relationship(AGENT_CONFIG_NAME, VM_INFO_NAME, AGENT_KEY); + Relationship agentConfigToVmInfo = new Relationship(new Node(AGENT_CONFIG_NAME), "->", new Node(VM_INFO_NAME)); + agentConfigToVmInfo.setProperty("key", AGENT_KEY); relationships.add(agentConfigToVmInfo); - Relationship vmInfoToVmGcStat = new Relationship(VM_INFO_NAME, VM_GC_STAT_NAME, VM_KEY); + Relationship vmInfoToVmGcStat = new Relationship(new Node(VM_INFO_NAME), "->", new Node(VM_GC_STAT_NAME)); + vmInfoToVmGcStat.setProperty("key", VM_KEY); relationships.add(vmInfoToVmGcStat); return relationships; } @@ -180,14 +186,16 @@ /** * Tests topological sorting with a cycle. Expected to fail. */ - @Test(expected = AssertionError.class) + @Test(expected = PopulationConfig.InvalidConfigurationException.class) public void testTopogicalSortCycle() throws IOException { List<ConfigItem> records = buildGoodRecords(); List<Relationship> rels = buildGoodRels(); // add a cycle between vm-info -> host-info -> agent-config - Relationship cyclePartOne = new Relationship(VM_INFO_NAME, HOST_INFO_NAME, VM_KEY); + Relationship cyclePartOne = new Relationship(new Node(VM_INFO_NAME), "->", new Node(HOST_INFO_NAME)); + cyclePartOne.setProperty("key", VM_KEY); rels.add(cyclePartOne); - Relationship cyclePartTwo = new Relationship(HOST_INFO_NAME, AGENT_CONFIG_NAME, AGENT_KEY); + Relationship cyclePartTwo = new Relationship(new Node(HOST_INFO_NAME), "->", new Node(AGENT_CONFIG_NAME)); + cyclePartTwo.setProperty("key", AGENT_KEY); rels.add(cyclePartTwo); PopulationConfig pc = PopulationConfig.createFromLists(records, rels); // This is expected to fail
--- a/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/PopulationConfigTypeAdapterTest.java Fri Sep 09 08:51:50 2016 -0400 +++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/PopulationConfigTypeAdapterTest.java Mon Sep 12 12:53:41 2016 -0400 @@ -47,7 +47,7 @@ import com.google.gson.GsonBuilder; import com.redhat.thermostat.storage.populator.internal.config.ConfigItem; import com.redhat.thermostat.storage.populator.internal.config.PopulationConfig; -import com.redhat.thermostat.storage.populator.internal.dependencies.Relationship; +import com.redhat.thermostat.collections.graph.Relationship; import com.redhat.thermostat.storage.populator.internal.config.typeadapter.ConfigItemTypeAdapter; import com.redhat.thermostat.storage.populator.internal.config.typeadapter.PopulationConfigTypeAdapterFactory; import com.redhat.thermostat.storage.populator.internal.config.typeadapter.RelationShipTypeAdapter; @@ -72,11 +72,11 @@ "{ \"name\": \"agent-config\", \"number\": 10, \"alive\": 3 }]" + "}"; PopulationConfig config = gson.fromJson(json, PopulationConfig.class); - ConfigItem item = config.getConfig("config-item"); + ConfigItem item = config.getConfig("config-item").getProperty("item"); assertEquals(3, item.getNumber()); assertEquals(1, item.getAliveItems()); assertEquals("config-item", item.getName()); - item = config.getConfig("agent-config"); + item = config.getConfig("agent-config").getProperty("item"); assertEquals(10, item.getNumber()); assertEquals(3, item.getAliveItems()); assertEquals("agent-config", item.getName()); @@ -91,11 +91,11 @@ "[{ \"from\": \"config-item\", \"to\": \"agent-config\", \"key\": \"foo\"}]" + "}"; PopulationConfig config = gson.fromJson(json, PopulationConfig.class); - ConfigItem item = config.getConfig("config-item"); + ConfigItem item = config.getConfig("config-item").getProperty("item"); assertEquals(3, item.getNumber()); assertEquals(1, item.getAliveItems()); assertEquals("config-item", item.getName()); - item = config.getConfig("agent-config"); + item = config.getConfig("agent-config").getProperty("item"); assertEquals(10, item.getNumber()); assertEquals(3, item.getAliveItems()); assertEquals("agent-config", item.getName());
--- a/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/RelationShipTypeAdapterTest.java Fri Sep 09 08:51:50 2016 -0400 +++ b/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/config/typeadapter/RelationShipTypeAdapterTest.java Mon Sep 12 12:53:41 2016 -0400 @@ -43,7 +43,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.redhat.thermostat.storage.populator.internal.dependencies.Relationship; +import com.redhat.thermostat.collections.graph.Relationship; import com.redhat.thermostat.storage.populator.internal.config.typeadapter.RelationShipTypeAdapter; public class RelationShipTypeAdapterTest { @@ -60,8 +60,8 @@ @Test public void testBasicNonNull() { Relationship rel = gson.fromJson("{ \"from\": \"foo\", \"to\": \"bar\", \"key\": \"baz\"}", Relationship.class); - assertEquals("foo", rel.getFrom()); - assertEquals("bar", rel.getTo()); - assertEquals("baz", rel.getKey()); + assertEquals("foo", rel.getFrom().getName()); + assertEquals("bar", rel.getTo().getName()); + assertEquals("baz", rel.getProperty("key")); } }
--- a/dev/storage-populator/command/src/test/java/com/redhat/thermostat/storage/populator/internal/dependencies/RelationshipTest.java Fri Sep 09 08:51:50 2016 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright 2012-2016 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * <http://www.gnu.org/licenses/>. - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.storage.populator.internal.dependencies; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -import com.redhat.thermostat.storage.populator.internal.dependencies.Relationship; - -public class RelationshipTest { - - @Test - public void testEquals() { - Relationship one = new Relationship("foo", "bar", "key"); - Relationship two = new Relationship("foo", "bar", "key"); - Relationship different = new Relationship("foo", "bar", "something"); - assertTrue(one.equals(two)); - assertTrue(one.equals(one)); - assertFalse(one.equals(different)); - assertFalse(one.equals(null)); - assertTrue(two.equals(one)); - } - - @Test - public void testHashCode() { - Relationship one = new Relationship("foo", "bar", "key"); - Relationship two = new Relationship("foo", "bar", "key"); - Relationship different = new Relationship("foo", "bar", "something"); - assertEquals(one.hashCode(), two.hashCode()); - assertFalse(different.hashCode() == one.hashCode()); - assertFalse(two.hashCode() == different.hashCode()); - assertEquals(one.hashCode(), one.hashCode()); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/platform/collections/src/main/java/com/redhat/thermostat/collections/graph/TopologicalSort.java Mon Sep 12 12:53:41 2016 -0400 @@ -0,0 +1,97 @@ +/* + * Copyright 2012-2016 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.collections.graph; + +import java.util.HashSet; +import java.util.Set; +import java.util.Stack; + +/** + * A {@link DefaultTraversalListener} used by {@link DepthFirstSearch} to construct a + * topological ordering of a {@link Graph}. + */ +public class TopologicalSort extends DefaultTraversalListener { + private Stack<Node> ordered; + private Set<Node> discovered; + + public TopologicalSort(Stack<Node> ordered, Set<Node> discovered) { + this.ordered = ordered; + this.discovered = discovered; + } + + public TopologicalSort() { + this.ordered = new Stack<>(); + this.discovered = new HashSet<>(); + } + + public void reset() { + ordered.clear(); + discovered.clear(); + } + + public Stack<Node> getOrdered() { + return ordered; + } + + public Set<Node> getDiscovered() { + return discovered; + } + + @Override + protected void preProcessNodeImpl(Node node) { + discovered.add(node); + } + + @Override + protected void postProcessNodeImpl(Node node) { + ordered.add(node); + } + + @Override + public Status processRelationship(Relationship relationship, + SearchPayload payload) + { + RelationshipType type = + DepthFirstSearch.classify(relationship, (DFSPayload) payload); + + if (type.equals(RelationshipType.BACK)) { + throw new IllegalStateException("back node! " + relationship); + } + + return Status.CONTINUE; + } +}