diff --git a/src/main/java/io/github/chronosx88/GunJava/Dup.java b/src/main/java/io/github/chronosx88/GunJava/Dup.java deleted file mode 100644 index 788274b..0000000 --- a/src/main/java/io/github/chronosx88/GunJava/Dup.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.github.chronosx88.GunJava; - -import java.util.Map; -import java.util.Random; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - -public class Dup { - private static char[] randomSeed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); - private static Random random = new Random(System.currentTimeMillis()); - private Map s = new ConcurrentHashMap<>(); - private DupOpt opt = new DupOpt(); - private Thread to = null; - - public Dup() { - opt.max = 1000; - opt.age = 1000 * 9; - } - - public String track(String id) { - s.put(id, System.currentTimeMillis()); - if(to == null) { - Utils.setTimeout(() -> { - for(Map.Entry entry : s.entrySet()) { - if(opt.age > (System.currentTimeMillis() - entry.getValue())) - continue; - s.remove(entry.getKey()); - } - to = null; - }, opt.age); - } - return id; - } - - public boolean check(String id) { - if(s.containsKey(id)) { - track(id); - return true; - } else { - return false; - } - } - - public static String random() { - return UUID.randomUUID().toString(); - } -} diff --git a/src/main/java/io/github/chronosx88/GunJava/DupOpt.java b/src/main/java/io/github/chronosx88/GunJava/DupOpt.java deleted file mode 100644 index 029a9b3..0000000 --- a/src/main/java/io/github/chronosx88/GunJava/DupOpt.java +++ /dev/null @@ -1,6 +0,0 @@ -package io.github.chronosx88.GunJava; - -public class DupOpt { - public int max; - public int age; -} diff --git a/src/main/java/io/github/chronosx88/GunJava/HAM.java b/src/main/java/io/github/chronosx88/GunJava/HAM.java deleted file mode 100644 index 0e9d022..0000000 --- a/src/main/java/io/github/chronosx88/GunJava/HAM.java +++ /dev/null @@ -1,164 +0,0 @@ -package io.github.chronosx88.GunJava; - -import io.github.chronosx88.GunJava.storageBackends.MemoryBackend; -import io.github.chronosx88.GunJava.storageBackends.StorageBackend; -import org.json.JSONObject; - -import java.util.Map; - -public class HAM { - private static long defer = Long.MAX_VALUE; - - static class HAMResult { - public boolean defer = false; - public boolean historical = false; - public boolean converge = false; - public boolean incoming = false; - public boolean current = false; - public boolean state = false; - public String err = null; - } - - public static HAMResult ham(long machineState, long incomingState, long currentState, Object incomingValue, Object currentValue) { - HAMResult result = new HAMResult(); - - if(machineState < incomingState) { - result.defer = true; - return result; - } - if(incomingState < currentState){ - result.historical = true; - return result; - } - if(currentState < incomingState) { - result.converge = true; - result.incoming = true; - return result; - } - if(incomingState == currentState) { - if(incomingValue.equals(currentValue)) { - result.state = true; - return result; - } - if((incomingValue.toString().compareTo(currentValue.toString())) < 0) { - result.converge = true; - result.current = true; - return result; - } - if((currentValue.toString().compareTo(incomingValue.toString())) < 0) { - result.converge = true; - result.incoming = true; - return result; - } - } - result.err = "Invalid CRDT Data: "+ incomingValue +" to "+ currentValue +" at "+ incomingState +" to "+ currentState +"!"; - return result; - } - - public static MemoryBackend mix(MemoryBackend change, StorageBackend data) { - long machine = System.currentTimeMillis(); - MemoryBackend diff = null; - for(Map.Entry entry : change.entries()) { - Node node = entry.getValue(); - for(String key : node.values.keySet()) { - Object value = node.values.get(key); - if ("_".equals(key)) { continue; } - long state = node.states.getLong(key); - long was = -1; - Object known = null; - if(data == null) { - data = new MemoryBackend(); - } - if(data.hasNode(node.soul)) { - if(data.getNode(node.soul).states.opt(key) != null) { - was = data.getNode(node.soul).states.getLong(key); - } - known = data.getNode(node.soul).values.opt(key) == null ? 0 : data.getNode(node.soul).values.opt(key); - } - - HAMResult ham = ham(machine, state, was, value, known); - if(!ham.incoming) { - if(ham.defer) { - System.out.println("DEFER: " + key + " " + value); - // Hack for accessing value in lambda without making the variable final - StorageBackend[] graph = new StorageBackend[] {data}; - Utils.setTimeout(() -> mix(node, graph[0]), (int) (state - System.currentTimeMillis())); - } - continue; - } - - if(diff == null) { - diff = new MemoryBackend(); - } - - if(!diff.hasNode(node.soul)) { - diff.addNode(node.soul, Utils.newNode(node.soul, new JSONObject())); - } - - if(!data.hasNode(node.soul)) { - data.addNode(node.soul, Utils.newNode(node.soul, new JSONObject())); - } - - data.getNode(node.soul).values.put(key, value); - diff.getNode(node.soul).values.put(key, value); - - diff.getNode(node.soul).states.put(key, state); - data.getNode(node.soul).states.put(key, state); - } - } - - return diff; - } - - public static MemoryBackend mix(Node incomingNode, StorageBackend data) { - long machine = System.currentTimeMillis(); - MemoryBackend diff = null; - - for(String key : incomingNode.values.keySet()) { - Object value = incomingNode.values.get(key); - if ("_".equals(key)) { continue; } - long state = incomingNode.states.getLong(key); - long was = -1; - Object known = null; - if(data == null) { - data = new MemoryBackend(); - } - if(data.hasNode(incomingNode.soul)) { - if(data.getNode(incomingNode.soul).states.opt(key) != null) { - was = data.getNode(incomingNode.soul).states.getLong(key); - } - known = data.getNode(incomingNode.soul).values.opt(key) == null ? 0 : data.getNode(incomingNode.soul).values.opt(key); - } - - HAMResult ham = ham(machine, state, was, value, known); - if(!ham.incoming) { - if(ham.defer) { - System.out.println("DEFER: " + key + " " + value); - // Hack for accessing value in lambda without making the variable final - StorageBackend[] graph = new StorageBackend[] {data}; - Utils.setTimeout(() -> mix(incomingNode, graph[0]), (int) (state - System.currentTimeMillis())); - } - continue; - } - - if(diff == null) { - diff = new MemoryBackend(); - } - - if(!diff.hasNode(incomingNode.soul)) { - diff.addNode(incomingNode.soul, Utils.newNode(incomingNode.soul, new JSONObject())); - } - - if(!data.hasNode(incomingNode.soul)) { - data.addNode(incomingNode.soul, Utils.newNode(incomingNode.soul, new JSONObject())); - } - - data.getNode(incomingNode.soul).values.put(key, value); - diff.getNode(incomingNode.soul).values.put(key, value); - - diff.getNode(incomingNode.soul).states.put(key, state); - data.getNode(incomingNode.soul).states.put(key, state); - } - return diff; - } -} diff --git a/src/main/java/io/github/chronosx88/GunJava/Node.java b/src/main/java/io/github/chronosx88/GunJava/Node.java deleted file mode 100644 index 5c15a02..0000000 --- a/src/main/java/io/github/chronosx88/GunJava/Node.java +++ /dev/null @@ -1,76 +0,0 @@ -package io.github.chronosx88.GunJava; - -import io.github.chronosx88.GunJava.storageBackends.MemoryBackend; -import org.json.JSONObject; - -public class Node implements Comparable { - public JSONObject values; // Data - public JSONObject states; // Metadata for diff - public String soul; // i.e. ID of node - - /** - * Create a Node from a JSON object. - * - * @param rawData JSON object, which contains the data - */ - public Node(JSONObject rawData) { - this.values = new JSONObject(rawData.toString()); - this.states = values.getJSONObject("_").getJSONObject(">"); - this.soul = values.getJSONObject("_").getString("#"); - values.remove("_"); - } - - @Override - public int compareTo(Node other) { - return soul.compareTo(other.soul); - } - - @Override - public boolean equals(Object other) { - if (other == null) - return false; - if (other instanceof String) - return soul.equals(other); - if (other instanceof Node) - return compareTo((Node) other) == 0; - return false; - } - - @Override - public int hashCode() { - return soul.hashCode(); - } - - public boolean isNode(String key) { - return values.optJSONObject(key) != null; - } - - public Node getNode(String key, MemoryBackend g) { - String soulRef = values.getJSONObject(key).getString("#"); - return g.getNode(soulRef); - } - - @Override - public String toString() { - JSONObject jsonObject = new JSONObject(values.toString()); - jsonObject.put("_", new JSONObject().put("#", soul).put(">", states)); - return jsonObject.toString(); - } - - public JSONObject toJSONObject() { - JSONObject jsonObject = new JSONObject(values.toString()); - jsonObject.put("_", new JSONObject().put("#", soul).put(">", states)); - return jsonObject; - } - - public JSONObject getMetadata() { - JSONObject jsonObject = new JSONObject(); - jsonObject.put("_", new JSONObject().put("#", soul).put(">", states)); - return jsonObject; - } - - public void setMetadata(JSONObject metadata) { - soul = metadata.getJSONObject("_").getString("#"); - states = metadata.getJSONObject("_").getJSONObject(">"); - } -} \ No newline at end of file diff --git a/src/main/java/io/github/chronosx88/GunJava/Utils.java b/src/main/java/io/github/chronosx88/GunJava/Utils.java deleted file mode 100644 index 8a549d3..0000000 --- a/src/main/java/io/github/chronosx88/GunJava/Utils.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.github.chronosx88.GunJava; - -import io.github.chronosx88.GunJava.storageBackends.MemoryBackend; -import io.github.chronosx88.GunJava.storageBackends.StorageBackend; -import org.json.JSONObject; - -public class Utils { - public static Thread setTimeout(Runnable runnable, int delay){ - Thread thread = new Thread(() -> { - try { - Thread.sleep(delay); - runnable.run(); - } - catch (Exception e){ - e.printStackTrace(); - } - }); - thread.start(); - return thread; - } - - public static Node newNode(String soul, JSONObject data) { - JSONObject states = new JSONObject(); - for (String key : data.keySet()) { - states.put(key, System.currentTimeMillis()); - } - data.put("_", new JSONObject().put("#", soul).put(">", states)); - return new Node(data); - } - - public static MemoryBackend getRequest(JSONObject lex, StorageBackend graph) { - String soul = lex.getString("#"); - String key = lex.optString(".", null); - Node node = graph.getNode(soul); - Object tmp; - if(node == null) { - return new MemoryBackend(); - } - if(key != null) { - tmp = node.values.opt(key); - if(tmp == null) { - return new MemoryBackend(); - } - Node node1 = new Node(node.toJSONObject()); - node = Utils.newNode(node.soul, new JSONObject()); - node.setMetadata(node1.getMetadata()); - node.values.put(key, tmp); - JSONObject tmpStates = node1.states; - node.states.put(key, tmpStates.get(key)); - } - MemoryBackend ack = new MemoryBackend(); - ack.addNode(soul, node); - return ack; - } -} diff --git a/src/main/java/io/github/chronosx88/GunJava/storageBackends/MemoryBackend.java b/src/main/java/io/github/chronosx88/GunJava/storageBackends/MemoryBackend.java deleted file mode 100644 index e55172f..0000000 --- a/src/main/java/io/github/chronosx88/GunJava/storageBackends/MemoryBackend.java +++ /dev/null @@ -1,69 +0,0 @@ -package io.github.chronosx88.GunJava.storageBackends; - -import io.github.chronosx88.GunJava.Node; -import org.json.JSONObject; - -import java.util.*; - -public class MemoryBackend implements StorageBackend { - - private final HashMap nodes; - - public MemoryBackend(JSONObject source) { - nodes = new LinkedHashMap<>(); - - for (String soul : source.keySet()) - nodes.put(soul, new Node(source.getJSONObject(soul))); - } - - public MemoryBackend() { - nodes = new LinkedHashMap<>(); - } - - public Node getNode(String soul) { - return nodes.getOrDefault(soul, null); - } - - public void addNode(String soul, Node incomingNode) { - nodes.put(soul, incomingNode); - } - - public boolean hasNode(String soul) { - return nodes.containsKey(soul); - } - - public Set> entries() { - return nodes.entrySet(); - } - - public Collection nodes() { return nodes.values(); } - - @Override - public String toString() { - JSONObject jsonObject = new JSONObject(); - for(Map.Entry entry : nodes.entrySet()) { - jsonObject.put(entry.getKey(), entry.getValue().toJSONObject()); - } - return jsonObject.toString(); - } - - public String toPrettyString() { - JSONObject jsonObject = new JSONObject(); - for(Map.Entry entry : nodes.entrySet()) { - jsonObject.put(entry.getKey(), entry.getValue().toJSONObject()); - } - return jsonObject.toString(2); - } - - public JSONObject toJSONObject() { - JSONObject jsonObject = new JSONObject(); - for(Map.Entry entry : nodes.entrySet()) { - jsonObject.put(entry.getKey(), entry.getValue().toJSONObject()); - } - return jsonObject; - } - - public boolean isEmpty() { - return nodes.isEmpty(); - } -} \ No newline at end of file diff --git a/src/main/java/io/github/chronosx88/GunJava/storageBackends/StorageBackend.java b/src/main/java/io/github/chronosx88/GunJava/storageBackends/StorageBackend.java deleted file mode 100644 index 73c35b5..0000000 --- a/src/main/java/io/github/chronosx88/GunJava/storageBackends/StorageBackend.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.github.chronosx88.GunJava.storageBackends; - -import io.github.chronosx88.GunJava.Node; -import org.json.JSONObject; - -import java.util.Collection; -import java.util.Map; -import java.util.Set; - -public interface StorageBackend { - Node getNode(String soul); - void addNode(String soul, Node node); - boolean hasNode(String soul); - Set> entries(); - Collection nodes(); - String toString(); - String toPrettyString(); - JSONObject toJSONObject(); - boolean isEmpty(); -} diff --git a/src/main/java/io/github/chronosx88/JGUN/Dispatcher.java b/src/main/java/io/github/chronosx88/JGUN/Dispatcher.java index 95bd3de..85f3537 100644 --- a/src/main/java/io/github/chronosx88/JGUN/Dispatcher.java +++ b/src/main/java/io/github/chronosx88/JGUN/Dispatcher.java @@ -46,13 +46,6 @@ public class Dispatcher { }).start(); } - public void sendGetRequest(String key) { - new Thread(() -> { - JSONObject jsonGet = Utils.formatGetRequest(key, null); - peer.emit(jsonGet.toString()); - }).start(); - } - public void sendGetRequest(String key, String field) { new Thread(() -> { JSONObject jsonGet = Utils.formatGetRequest(key, field); diff --git a/src/main/java/io/github/chronosx88/JGUN/PathRef.java b/src/main/java/io/github/chronosx88/JGUN/PathRef.java index 946185f..ed21cec 100644 --- a/src/main/java/io/github/chronosx88/JGUN/PathRef.java +++ b/src/main/java/io/github/chronosx88/JGUN/PathRef.java @@ -1,10 +1,13 @@ package io.github.chronosx88.JGUN; -import io.github.chronosx88.JGUN.futures.builders.GetBuilder; +import io.github.chronosx88.JGUN.futures.FutureGet; import io.github.chronosx88.JGUN.futures.builders.PutBuilder; import org.json.JSONObject; import java.util.ArrayList; +import java.util.Iterator; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; public class PathRef { private final ArrayList path = new ArrayList<>(); @@ -19,8 +22,50 @@ public class PathRef { return this; } - public GetBuilder getData() { - return new GetBuilder(path); + public FutureGet getData() { + FutureGet futureGet = new FutureGet(Dup.random()); + Iterator iterator = path.iterator(); + new Thread(() -> { + CompletableFuture future = CompletableFuture.supplyAsync(() -> { + String rootSoul = iterator.next(); + String field = iterator.hasNext() ? iterator.next() : null; + FutureGet futureGetRootSoul = new FutureGet(Dup.random()); + dispatcher.addPendingFuture(futureGetRootSoul); + dispatcher.sendGetRequest(rootSoul, field); + futureGetRootSoul.awaitUninterruptibly(); + if(futureGetRootSoul.isSuccess() && futureGetRootSoul.getData() != null) { + return futureGetRootSoul.getData(); + } else { + return null; + } + }); + while(iterator.hasNext()) { + future = future.thenApply(jsonObject -> { + String soul = iterator.next(); + String field = iterator.hasNext() ? iterator.next() : null; + if(jsonObject != null) { + String nodeRef = jsonObject.getJSONObject(soul).getString("#"); + FutureGet get = new FutureGet(Dup.random()); + dispatcher.addPendingFuture(get); + dispatcher.sendGetRequest(nodeRef, field); + get.awaitUninterruptibly(); + if(get.isSuccess() && get.getData() != null) { + return get.getData(); + } else { + return null; + } + } + return null; + }); + } + try { + JSONObject data = future.get(); + futureGet.done(data); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + }).start(); + return futureGet; } public PutBuilder put(JSONObject data) { diff --git a/src/main/java/io/github/chronosx88/JGUN/futures/FutureGet.java b/src/main/java/io/github/chronosx88/JGUN/futures/FutureGet.java index 96ca6f4..d8e6750 100644 --- a/src/main/java/io/github/chronosx88/JGUN/futures/FutureGet.java +++ b/src/main/java/io/github/chronosx88/JGUN/futures/FutureGet.java @@ -28,14 +28,17 @@ public class FutureGet extends BaseFuture { public FutureGet done(JSONObject data) { synchronized (lock) { - if(!data.isEmpty()) { - this.getStatus = GetStatus.OK; - this.type = FutureType.OK; + if(data != null) { + if (!data.isEmpty()) { + this.getStatus = GetStatus.OK; + this.type = FutureType.OK; + } } else { this.getStatus = GetStatus.NOT_FOUND; this.type = FutureType.FAILED; this.reason = "Not found"; } + this.data = data; if (!completedAndNotify()) { return this; diff --git a/src/main/java/io/github/chronosx88/JGUN/futures/builders/GetBuilder.java b/src/main/java/io/github/chronosx88/JGUN/futures/builders/GetBuilder.java deleted file mode 100644 index 8cb8ccb..0000000 --- a/src/main/java/io/github/chronosx88/JGUN/futures/builders/GetBuilder.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.github.chronosx88.JGUN.futures.builders; - -import java.util.ArrayList; - -public class GetBuilder { - private final ArrayList path; - - public GetBuilder(ArrayList path) { - this.path = path; - } -}