Skip to content

Commit

Permalink
Add ComputeTree project
Browse files Browse the repository at this point in the history
  • Loading branch information
iryndin committed Jan 30, 2017
1 parent 678fa79 commit 40d6ffc
Show file tree
Hide file tree
Showing 18 changed files with 867 additions and 0 deletions.
59 changes: 59 additions & 0 deletions computetree/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>net.iryndin</groupId>
<artifactId>computetree</artifactId>
<version>1.0</version>

<properties>
<project.build.source>UTF-8</project.build.source>

<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.fork>true</maven.compiler.fork>

<guava.version>19.0</guava.version>
<snakeyaml.version>1.17</snakeyaml.version>
<commons.io.version>2.5</commons.io.version>
<slf4j.version>1.7.22</slf4j.version>
<logback.version>1.1.9</logback.version>
<junit.version>4.11</junit.version>
</properties>

<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${snakeyaml.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons.io.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
80 changes: 80 additions & 0 deletions computetree/src/main/java/net/iryndin/computetree/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package net.iryndin.computetree;

import com.google.common.base.Optional;
import net.iryndin.computetree.api.INode;
import net.iryndin.computetree.api.INodeRegistry;
import net.iryndin.computetree.api.ITreeResult;
import net.iryndin.computetree.core.TreeComputation;
import net.iryndin.computetree.core.YamlTreeReader;
import net.iryndin.computetree.node.DebugNode;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

/**
* @author iryndin
* @since 25/01/17
*/
public class Main {

final static Logger log = LoggerFactory.getLogger(Main.class);

public static void main(String[] args) throws Exception {
String yaml;
try (InputStream is = Main.class.getClassLoader().getResourceAsStream("tree.yaml")) {
yaml = IOUtils.toString(is, StandardCharsets.UTF_8);
}
YamlTreeReader ytr = new YamlTreeReader(yaml);
String start = ytr.getStartNodeId();
INodeRegistry registry = ytr.createNodeRegistry();
try (TreeComputation tc = new TreeComputation(registry)) {
Optional<ITreeResult> tr = tc.compute(start);
if (tr.isPresent()) {
log.info("TreeResult: " + tr.get());
} else {
log.info("TreeResult is absent!");
}
}
}

/*
static INodeRegistry createINodeRegistry() {
return new INodeRegistry() {
@Override
public Optional<INode> getNode(String id) {
log.debug("Try to get node by id: '{}'", id);
switch (id) {
case "valid": return Optional.of(new DebugNode("valid"));
case "wanted": return Optional.of(new DebugNode("wanted"));
}
log.debug("No nodes by id: '{}'", id);
return Optional.absent();
}
@Override
public Optional<List<String>> getNodeResults(String id, String result) {
switch (id) {
case "valid":
switch (result) {
case "success": return Optional.of(Arrays.asList("wanted", "terror"));
case "notValid": return Optional.of(Arrays.asList("end"));
default: return Optional.absent();
}
case "wanted":
switch (result) {
case "success": return Optional.of(Arrays.asList("wantedLocal", "wantedIntl"));
default: return Optional.absent();
}
}
return Optional.absent();
}
};
}
*/
}
30 changes: 30 additions & 0 deletions computetree/src/main/java/net/iryndin/computetree/api/INode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package net.iryndin.computetree.api;


import com.google.common.base.Optional;

/**
* @author iryndin
* @since 20/01/17
*/
public interface INode {
/**
* Get node ID
* @return node ID
*/
String getId();

/**
* Set node ID
* @param nodeId node ID
*/
void setId(String nodeId);

/**
* Node computation is made here.
* @param treeResult reference to tree result object. This tree result object can be modified during
* node computation.
* @return result of node computation
*/
INodeResult compute(ITreeResult treeResult);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package net.iryndin.computetree.api;

import com.google.common.base.Optional;

import java.util.List;

/**
* @author iryndin
* @since 20/01/17
*/
public interface INodeRegistry {
Optional<INode> getNode(String id);
Optional<List<String>> getNodeResults(String id, String result);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package net.iryndin.computetree.api;

import com.google.common.base.Optional;

import java.util.Map;

/**
* @author iryndin
* @since 20/01/17
*/
public interface INodeResult {
String getNodeId();
String getValue();
Optional<Map<Object, Object>> getData();

static INodeResult createEmptyNodeResult(String nodeId, String result) {
return new INodeResult() {

@Override
public String getNodeId() {
return nodeId;
}

@Override
public String getValue() {
return result;
}

@Override
public Optional<Map<Object, Object>> getData() {
return Optional.absent();
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package net.iryndin.computetree.api;

import java.util.Set;

/**
* @author iryndin
* @since 20/01/17
*/
public interface ITreeResult {
void put(String id, Object data);
Object get(String id);
Set<String> keys();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package net.iryndin.computetree.core;

import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import net.iryndin.computetree.api.INode;
import net.iryndin.computetree.api.INodeRegistry;
import net.iryndin.computetree.api.INodeResult;
import net.iryndin.computetree.api.ITreeResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

/**
* @author iryndin
* @since 20/01/17
*/
public class TreeComputation implements AutoCloseable {

final static Logger log = LoggerFactory.getLogger(TreeComputation.class);

private final INodeRegistry registry;
private final ExecutorService executorService;

public TreeComputation(INodeRegistry registry) {
this(registry, Executors.newCachedThreadPool());
}

public TreeComputation(INodeRegistry registry, ExecutorService executorService) {
this.registry = registry;
this.executorService = executorService;
}

@Override
public void close() throws Exception {
log.info("Closing TreeComputation...");
executorService.shutdown();
log.info("TreeComputation closed");
}

public Optional<ITreeResult> compute(String start) throws Exception {
log.info("Start tree computation, start node ID: '{}'", start);
// 1. get configured and created node by node ID
Optional<INode> node = registry.getNode(start);
if (node.isPresent()) {
// 2. Create empty TreeResult
ITreeResult treeResult = new TreeResultImpl();
log.debug("Start node: {}", node.get());
// 3. Start tree computation
computeRecursive(Collections.singletonList(node.get()), treeResult);
return Optional.of(treeResult);
} else {
log.info("Cannot find node with ID: '{}'", start);
}
return Optional.absent();
}

private void computeRecursive(List<INode> nodes, ITreeResult treeResult) throws ExecutionException, InterruptedException {
if (nodes.isEmpty()) {
log.debug("Empty list of nodes passed");
return;
}
log.debug("Going to compute following nodes: '{}'",
Joiner.on(",").join(nodes.stream().map(n -> n.getId()).collect(Collectors.toList())));
List<NodeComputationCallable> callables = nodes.stream()
.map(node -> new NodeComputationCallable(node, treeResult))
.collect(Collectors.toList());

List<Future<INodeResult>> futures = executorService.invokeAll(callables);

List<INodeResult> results = Lists.newArrayListWithCapacity(futures.size());
for (Future<INodeResult> f : futures) {
results.add(f.get());
}

List<INode> treeNodes = results.stream()
.map(res -> {
Optional<List<String>> nodeResults = registry.getNodeResults(res.getNodeId(), res.getValue());
if (nodeResults.isPresent()) {
log.debug("Results from registry by nodeID '{}' and result '{}': '{}'",
res.getNodeId(), res.getValue(), Joiner.on(",").join(nodeResults.get()));
} else {
log.debug("No results from registry by nodeID '{}' and result '{}'", res.getNodeId(), res.getValue());
}
return nodeResults.orNull();
})
.filter(x -> x != null)
.flatMap(x -> x.stream())
.map(nodeId -> {
log.debug("Going to search node by id: {}", nodeId);
return registry.getNode(nodeId).orNull();
})
.filter(node -> node != null)
.collect(Collectors.toList());

if (!treeNodes.isEmpty()) {
computeRecursive(treeNodes, treeResult);
} else {
log.debug("Empty list of nodes, do not pass it to computation");
}
}

/**
* This class wraps node computation call
*/
static class NodeComputationCallable implements Callable<INodeResult> {

private final INode node;
private final ITreeResult treeResult;

public NodeComputationCallable(INode node, ITreeResult treeResult) {
this.node = node;
this.treeResult = treeResult;
}

@Override
public INodeResult call() throws Exception {
return node.compute(treeResult);
}
}
}
Loading

0 comments on commit 40d6ffc

Please sign in to comment.