generated from Nekojimi/JavaMavenTemplate
Initial version of a lot of behaviour.
This commit is contained in:
parent
b35bd6c2d5
commit
f4e9c3e823
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jimj316
|
||||
*/
|
||||
public enum ClassMethodType
|
||||
{
|
||||
/**
|
||||
* takes no input, makes no changes, returns a value
|
||||
* Should be added to an object node, given a constant port
|
||||
*/
|
||||
GETTER,
|
||||
SETTER, // takes one input, changes one field, returns nothing
|
||||
ADDER, // takes one input, makes other state changes, returns nothing
|
||||
TAKER, // takes no input, makes other state changes, returns a value
|
||||
CALLBACK, // takes a single argument of an abstract class
|
||||
ACTION, // takes no input or output
|
||||
|
||||
TRANSFORMER, // takes input, changes the object, then returns the object (eg. builder methods)
|
||||
FUNCTION, // takes one or more unrelated types, and returns a result
|
||||
CONSTANT, // static; no input, returns a value
|
||||
FACTORY,
|
||||
OTHER,
|
||||
}
|
|
@ -1,16 +1,190 @@
|
|||
package moe.nekojimi.nodeprocessor;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import moe.nekojimi.nodeprocessor.links.Link;
|
||||
import moe.nekojimi.nodeprocessor.nodes.MethodNode;
|
||||
import moe.nekojimi.nodeprocessor.nodes.DebugOutNode;
|
||||
import moe.nekojimi.nodeprocessor.nodes.ValueNode;
|
||||
import org.reflections.Reflections;
|
||||
import org.reflections.scanners.SubTypesScanner;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nekojimi
|
||||
*/
|
||||
public class Main
|
||||
{
|
||||
|
||||
private static final Class[] testClasses =
|
||||
{
|
||||
String.class,
|
||||
Integer.class,
|
||||
Math.class,
|
||||
HashMap.class,
|
||||
OffsetDateTime.class,
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args)
|
||||
public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException, IOException
|
||||
{
|
||||
System.out.println("Hello world!");
|
||||
for (Class testClass : testClasses)
|
||||
{
|
||||
System.out.println(testClass.getName() + ":");
|
||||
Method[] methods = testClass.getMethods();
|
||||
for (Method method : methods)
|
||||
{
|
||||
if (method.getDeclaringClass() == testClass)
|
||||
{
|
||||
ClassMethodType type = guessMethodType(method);
|
||||
System.out.println("\t" + method.toString());
|
||||
System.out.println("\t\t" + type.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
// helloWorldProgram();
|
||||
}
|
||||
|
||||
private static void fibonnaciProgram()
|
||||
{
|
||||
Program program = new Program();
|
||||
}
|
||||
|
||||
private static void addNumbersProgram() throws NoSuchMethodException
|
||||
{
|
||||
Program program = new Program();
|
||||
ValueNode<Integer> twoNode = new ValueNode<>(program, Integer.class);
|
||||
twoNode.setValue(2);
|
||||
ValueNode<Integer> threeNode = new ValueNode<>(program, Integer.class);
|
||||
threeNode.setValue(3);
|
||||
|
||||
MethodNode<Integer> methodNode = new MethodNode<>(program, Integer.class, Integer.class.getMethod("sum", Integer.class, Integer.class));
|
||||
|
||||
DebugOutNode debugOutNode = new DebugOutNode(program);
|
||||
|
||||
// Link.makeLink(Integer.class, twoNode, fromPort, twoNode, toPort);
|
||||
|
||||
program.start();
|
||||
}
|
||||
|
||||
private static void helloWorldProgram() throws SecurityException, NoSuchMethodException
|
||||
{
|
||||
Program program = new Program();
|
||||
ValueNode<String> valueNode = new ValueNode<>(program, String.class);
|
||||
valueNode.setValue("Hello world!");
|
||||
final Method method = String.class.getMethod("toUpperCase");
|
||||
MethodNode<String> methodNode = new MethodNode<>(program, String.class, method);
|
||||
DebugOutNode debugOutNode = new DebugOutNode(program);
|
||||
|
||||
Link.makeLink(String.class, valueNode, "out", methodNode, "object");
|
||||
Link.makeLink(String.class, methodNode, "out", debugOutNode, "in");
|
||||
|
||||
program.start();
|
||||
}
|
||||
|
||||
public static Set<Class> findAllClassesUsingClassLoader(String packageName)
|
||||
{
|
||||
InputStream stream = ClassLoader.getSystemClassLoader()
|
||||
.getResourceAsStream(packageName.replaceAll("[.]", "/"));
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
|
||||
return reader.lines()
|
||||
.filter(line -> line.endsWith(".class"))
|
||||
.map(line -> getClass(line, packageName))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static Set<Class> findAllClassesUsingReflectionsLibrary(String packageName)
|
||||
{
|
||||
Reflections reflections = new Reflections(packageName, new SubTypesScanner(false));
|
||||
return reflections.getSubTypesOf(Object.class)
|
||||
.stream()
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private static Class getClass(String className, String packageName)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Class.forName(packageName + "."
|
||||
+ className.substring(0, className.lastIndexOf('.')));
|
||||
} catch (ClassNotFoundException e)
|
||||
{
|
||||
// handle the exception
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static ClassMethodType guessMethodType(Method method)
|
||||
{
|
||||
String name = method.getName();
|
||||
Class<?> clazz = method.getDeclaringClass();
|
||||
Class<?> returnType = method.getReturnType();
|
||||
boolean hasReturn = (returnType != Void.TYPE);
|
||||
int paramCount = method.getParameterCount();
|
||||
Class<?> firstParamType = null;
|
||||
Parameter[] parameters = method.getParameters();
|
||||
if (paramCount > 0)
|
||||
firstParamType = parameters[0].getType();
|
||||
boolean isStatic = Modifier.isStatic(method.getModifiers());
|
||||
|
||||
if (!isStatic)
|
||||
{
|
||||
if (hasReturn)
|
||||
{
|
||||
if (paramCount == 0) // methods that only return
|
||||
{
|
||||
if (name.startsWith("take") || name.startsWith("poll") || name.startsWith("remove") || name.startsWith("pop") || name.startsWith("read"))
|
||||
return ClassMethodType.TAKER;
|
||||
else
|
||||
return ClassMethodType.GETTER;
|
||||
} else if (clazz.isAssignableFrom(returnType))
|
||||
return ClassMethodType.TRANSFORMER;
|
||||
else if (paramCount == 1
|
||||
&& Modifier.isAbstract(parameters[0].getType().getModifiers())
|
||||
&& !parameters[0].getType().isPrimitive()
|
||||
&& name.toLowerCase().matches("(on.+|.*listener.*|.*observer.*)"))
|
||||
{
|
||||
int abstractMethods = 0;
|
||||
Method[] paramTypeMethods = parameters[0].getType().getMethods();
|
||||
for (Method paramTypeMethod : paramTypeMethods)
|
||||
{
|
||||
if (Modifier.isAbstract(paramTypeMethod.getModifiers()))
|
||||
abstractMethods++;
|
||||
}
|
||||
if (abstractMethods >= 1)
|
||||
return ClassMethodType.CALLBACK;
|
||||
} else
|
||||
return ClassMethodType.FUNCTION;
|
||||
} else // returns nothing
|
||||
{
|
||||
if (paramCount == 1)
|
||||
{
|
||||
if (name.startsWith("give") || name.startsWith("add") || name.startsWith("push") || name.startsWith("write"))
|
||||
return ClassMethodType.ADDER;
|
||||
else
|
||||
return ClassMethodType.SETTER;
|
||||
} else if (paramCount == 0) // no input, return nothing
|
||||
return ClassMethodType.ACTION;
|
||||
}
|
||||
} else // static method
|
||||
{
|
||||
if (clazz.isAssignableFrom(returnType))
|
||||
return ClassMethodType.FACTORY;
|
||||
else if (hasReturn && paramCount > 0)
|
||||
return ClassMethodType.FUNCTION;
|
||||
else if (hasReturn && paramCount == 0)
|
||||
return ClassMethodType.CONSTANT;
|
||||
}
|
||||
|
||||
return ClassMethodType.OTHER;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor;
|
||||
|
||||
import com.amihaiemil.eoyaml.YamlMapping;
|
||||
import moe.nekojimi.nodeprocessor.nodes.Node;
|
||||
|
||||
/**
|
||||
* Specifies a type of node that can exist.
|
||||
* Holds a list of one or more methods and their archetypes to be added to the
|
||||
* new node???
|
||||
*
|
||||
* @author jimj316
|
||||
*/
|
||||
public class NodeSpec<T extends Node>
|
||||
{
|
||||
|
||||
public static NodeSpec fromYAML(YamlMapping yaml) throws ClassNotFoundException
|
||||
{
|
||||
Class<?> clazz = ClassLoader.getSystemClassLoader().loadClass(yaml.string("class"));
|
||||
final NodeSpec nodeSpec = new NodeSpec(clazz);
|
||||
return nodeSpec;
|
||||
}
|
||||
|
||||
public NodeSpec(Class<T> clazz)
|
||||
{
|
||||
}
|
||||
|
||||
public T construct()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor;
|
||||
|
||||
import java.util.*;
|
||||
import moe.nekojimi.nodeprocessor.links.Link;
|
||||
import moe.nekojimi.nodeprocessor.nodes.Node;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jimj316
|
||||
*/
|
||||
public class Program
|
||||
{
|
||||
private final List<Node> nodes = new ArrayList<>();
|
||||
private final Set<Link> links = new HashSet<>();
|
||||
|
||||
private final Queue<Node> executionQueue = new LinkedList<>();
|
||||
private final Set<Node> idleNodes = new HashSet<>();
|
||||
|
||||
private Thread thread;
|
||||
private State state = State.STOPPED;
|
||||
|
||||
public void addNode(Node node)
|
||||
{
|
||||
if (!nodes.contains(node))
|
||||
nodes.add(node);
|
||||
nodes.sort(Node.DEPENDENCY_ORDER);
|
||||
}
|
||||
|
||||
public void addLink(Link link)
|
||||
{
|
||||
links.add(link);
|
||||
}
|
||||
|
||||
public void queueNodeProcess(Node node)
|
||||
{
|
||||
executionQueue.add(node);
|
||||
}
|
||||
|
||||
public void setIdleNode(Node node, boolean idle)
|
||||
{
|
||||
if (idle)
|
||||
idleNodes.add(node);
|
||||
else
|
||||
idleNodes.remove(node);
|
||||
}
|
||||
|
||||
public State getState()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
public void start()
|
||||
{
|
||||
if (state != State.STOPPED)
|
||||
throw new IllegalStateException("Thread isn't stopped!");
|
||||
if (thread == null)
|
||||
thread = new Thread(runnable);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
private final Runnable runnable = () ->
|
||||
{
|
||||
state = State.RUNNING;
|
||||
for (Node node : nodes)
|
||||
{
|
||||
node.reset();
|
||||
if (node.getNumberOfInputs() == 0)
|
||||
node.signal();
|
||||
}
|
||||
while (!executionQueue.isEmpty())
|
||||
{
|
||||
Node node = executionQueue.poll();
|
||||
boolean done = node.process();
|
||||
if (!done)
|
||||
queueNodeProcess(node);
|
||||
}
|
||||
state = State.STOPPED;
|
||||
};
|
||||
|
||||
public List<Node> getNodes()
|
||||
{
|
||||
return nodes;
|
||||
}
|
||||
|
||||
public Set<Link> getLinks()
|
||||
{
|
||||
return links;
|
||||
}
|
||||
|
||||
public Set<Node> getIdleNodes()
|
||||
{
|
||||
return idleNodes;
|
||||
}
|
||||
|
||||
public enum State
|
||||
{
|
||||
STOPPED,
|
||||
PAUSED,
|
||||
RUNNING,
|
||||
IDLE
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor.links;
|
||||
|
||||
import moe.nekojimi.nodeprocessor.ports.ConstantOutPort;
|
||||
import moe.nekojimi.nodeprocessor.ports.InPort;
|
||||
|
||||
|
||||
public class ConstantLink<T> extends Link<T, InPort<T>, ConstantOutPort<T>>
|
||||
{
|
||||
|
||||
T value = null;
|
||||
|
||||
public ConstantLink(ConstantOutPort<T> from, InPort<T> to)
|
||||
{
|
||||
super(from, to);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(T val)
|
||||
{
|
||||
if (val != value)
|
||||
signal();
|
||||
value = val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has()
|
||||
{
|
||||
return value != null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor.links;
|
||||
|
||||
import moe.nekojimi.nodeprocessor.nodes.Node;
|
||||
import moe.nekojimi.nodeprocessor.ports.ConstantOutPort;
|
||||
import moe.nekojimi.nodeprocessor.ports.InPort;
|
||||
import moe.nekojimi.nodeprocessor.ports.OutPort;
|
||||
import moe.nekojimi.nodeprocessor.ports.QueueOutPort;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jimj316
|
||||
*/
|
||||
public abstract class Link<T, I extends InPort<T>, O extends OutPort<T>>
|
||||
{
|
||||
final O from;
|
||||
private final I to;
|
||||
|
||||
public Link(O from, I to)
|
||||
{
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
connect();
|
||||
}
|
||||
|
||||
public final void connect()
|
||||
{
|
||||
from.connect(this);
|
||||
to.connect(this);
|
||||
from.getNode().getProgram().addLink(this);
|
||||
to.getNode().getProgram().addLink(this);
|
||||
}
|
||||
|
||||
public final void disconnect()
|
||||
{
|
||||
from.disconnect(this);
|
||||
to.disconnect(this);
|
||||
}
|
||||
|
||||
public abstract T read();
|
||||
|
||||
public abstract void write(T val);
|
||||
|
||||
public abstract boolean has();
|
||||
|
||||
public static <T> Link<T, ?, ?> makeLink(Class<T> clazz, Node from, String fromPort, Node to, String toPort)
|
||||
{
|
||||
OutPort<T> outPort = from.getOutPort(fromPort, clazz);
|
||||
InPort<T> inPort = to.getInPort(toPort, clazz);
|
||||
if (outPort instanceof QueueOutPort)
|
||||
{
|
||||
QueueOutPort<T> q = (QueueOutPort<T>) outPort;
|
||||
return new QueueLink<>(q, inPort);
|
||||
} else if (outPort instanceof ConstantOutPort)
|
||||
{
|
||||
ConstantOutPort<T> c = (ConstantOutPort<T>) outPort;
|
||||
return new ConstantLink<>(c, inPort);
|
||||
} else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void signal()
|
||||
{
|
||||
to.signal();
|
||||
}
|
||||
|
||||
public O getFrom()
|
||||
{
|
||||
return from;
|
||||
}
|
||||
|
||||
public I getTo()
|
||||
{
|
||||
return to;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor.links;
|
||||
|
||||
import moe.nekojimi.nodeprocessor.ports.InPort;
|
||||
import moe.nekojimi.nodeprocessor.ports.PullOutPort;
|
||||
|
||||
|
||||
public class PullLink<T> extends Link<T, InPort<T>, PullOutPort<T>>
|
||||
{
|
||||
|
||||
public PullLink(PullOutPort<T> from, InPort<T> to)
|
||||
{
|
||||
super(from, to);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read()
|
||||
{
|
||||
return from.pull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(T val)
|
||||
{
|
||||
// not used
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor.links;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import moe.nekojimi.nodeprocessor.ports.InPort;
|
||||
import moe.nekojimi.nodeprocessor.ports.QueueOutPort;
|
||||
|
||||
|
||||
public class QueueLink<T> extends Link<T, InPort<T>, QueueOutPort<T>>
|
||||
{
|
||||
|
||||
private final Queue<T> queue = new LinkedList<>();
|
||||
|
||||
public QueueLink(QueueOutPort<T> from, InPort<T> to)
|
||||
{
|
||||
super(from, to);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read()
|
||||
{
|
||||
return queue.poll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(T val)
|
||||
{
|
||||
queue.add(val);
|
||||
signal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has()
|
||||
{
|
||||
return !queue.isEmpty();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor.nodes;
|
||||
|
||||
import moe.nekojimi.nodeprocessor.Program;
|
||||
import moe.nekojimi.nodeprocessor.ports.InPort;
|
||||
|
||||
public class DebugOutNode extends Node
|
||||
{
|
||||
|
||||
public DebugOutNode(Program scene)
|
||||
{
|
||||
super(scene);
|
||||
addInPort(new InPort("in", Object.class, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process()
|
||||
{
|
||||
InPort<Object> inPort = getInPort("in", Object.class);
|
||||
System.out.println(inPort.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check()
|
||||
{
|
||||
InPort<Object> inPort = getInPort("in", Object.class);
|
||||
return inPort.has();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor.nodes;
|
||||
|
||||
import moe.nekojimi.nodeprocessor.ports.InPort;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import moe.nekojimi.nodeprocessor.Program;
|
||||
import moe.nekojimi.nodeprocessor.ports.QueueOutPort;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jimj316
|
||||
* @param <C> the class that declares this method.
|
||||
*/
|
||||
public class MethodNode<C> extends Node
|
||||
{
|
||||
|
||||
private final InPort<C> objectInPort;
|
||||
private final QueueOutPort returnOutPort;
|
||||
private final Method method;
|
||||
|
||||
public MethodNode(Program scene, Class<C> clazz, Method method)
|
||||
{
|
||||
super(scene);
|
||||
assert (method.getDeclaringClass() == clazz);
|
||||
if (Modifier.isStatic(method.getModifiers()))
|
||||
objectInPort = null;
|
||||
else
|
||||
{
|
||||
objectInPort = new InPort<>("object", clazz, this);
|
||||
addInPort(objectInPort);
|
||||
}
|
||||
this.method = method;
|
||||
Parameter[] parameters = method.getParameters();
|
||||
for (Parameter parameter : parameters)
|
||||
addInPort(new InPort(parameter.getName(), parameter.getType(), this));
|
||||
Class<?> returnType = method.getReturnType();
|
||||
returnOutPort = new QueueOutPort("out", returnType, this);
|
||||
addOutPort(returnOutPort);
|
||||
|
||||
setName(method.getDeclaringClass().getSimpleName() + " " + method.getName());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean process()
|
||||
{
|
||||
try
|
||||
{
|
||||
C object = null;
|
||||
if (objectInPort != null)
|
||||
object = objectInPort.get();
|
||||
Object ret = method.invoke(object);
|
||||
returnOutPort.set(ret);
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex)
|
||||
{
|
||||
Logger.getLogger(MethodNode.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check()
|
||||
{
|
||||
return getInPorts().stream().allMatch(in -> (in.has()));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor.nodes;
|
||||
|
||||
import java.util.*;
|
||||
import moe.nekojimi.nodeprocessor.ports.InPort;
|
||||
import moe.nekojimi.nodeprocessor.ports.OutPort;
|
||||
import moe.nekojimi.nodeprocessor.Program;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jimj316
|
||||
*/
|
||||
public abstract class Node
|
||||
{
|
||||
// protected Map<String, Link> inLinks = new HashMap<>();
|
||||
// protected Map<String, Link> outLinks = new HashMap<>();
|
||||
|
||||
private final Program program;
|
||||
private Map<String, InPort> inPorts = new HashMap<>();
|
||||
private Map<String, OutPort> outPorts = new HashMap<>();
|
||||
private String name;
|
||||
|
||||
public Node(Program program)
|
||||
{
|
||||
this.program = program;
|
||||
program.addNode(this);
|
||||
this.name = this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
protected void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
protected final void addInPort(InPort port)
|
||||
{
|
||||
inPorts.putIfAbsent(getPortName(port.getClazz(), port.getName()), port);
|
||||
}
|
||||
protected final void addOutPort(OutPort port)
|
||||
{
|
||||
outPorts.putIfAbsent(getPortName(port.getClazz(), port.getName()), port);
|
||||
}
|
||||
|
||||
public final <X> InPort<X> getInPort(String name, Class<X> clazz)
|
||||
{
|
||||
Class<? super X> c = clazz;
|
||||
InPort ret;
|
||||
do
|
||||
{
|
||||
ret = inPorts.get(getPortName(c, name));
|
||||
c = c.getSuperclass();
|
||||
} while (ret == null && c != null);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public final <X> OutPort<X> getOutPort(String name, Class<X> clazz)
|
||||
{
|
||||
Class<? super X> c = clazz;
|
||||
OutPort ret;
|
||||
do
|
||||
{
|
||||
ret = outPorts.get(getPortName(clazz, name));
|
||||
c = c.getSuperclass();
|
||||
} while (ret == null && c != null);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public final Collection<InPort> getInPorts()
|
||||
{
|
||||
return inPorts.values();
|
||||
}
|
||||
|
||||
public final Collection<OutPort> getOutPorts()
|
||||
{
|
||||
return outPorts.values();
|
||||
}
|
||||
|
||||
private static <X> String getPortName(Class<X> clazz, String name)
|
||||
{
|
||||
return clazz.getCanonicalName() + "-" + name;
|
||||
}
|
||||
|
||||
public int getNumberOfInputs()
|
||||
{
|
||||
return inPorts.values().stream().mapToInt((t) -> t.getNumberOfConnections()).sum();
|
||||
}
|
||||
|
||||
public int getNumberOfOutputs()
|
||||
{
|
||||
return outPorts.values().stream().mapToInt((t) -> t.getNumberOfConnections()).sum();
|
||||
}
|
||||
|
||||
public Program getProgram()
|
||||
{
|
||||
return program;
|
||||
}
|
||||
|
||||
public boolean dependsOn(Node other)
|
||||
{
|
||||
// TODO: this is a crude search that will enter an infinite loop if a node depends on itself
|
||||
for (InPort port : inPorts.values())
|
||||
{
|
||||
Set<Node> linkedNodes = port.getLinkedNodes();
|
||||
if (linkedNodes.contains(other))
|
||||
return true;
|
||||
else
|
||||
for (Node dependent : linkedNodes)
|
||||
{
|
||||
if (dependent.dependsOn(other))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes this node's inputs, and generates output (or performs some
|
||||
* other useful function).
|
||||
*
|
||||
* @return true if there will be no more output until an input is received;
|
||||
* false if process() should be called again.
|
||||
*/
|
||||
public abstract boolean process();
|
||||
|
||||
public abstract boolean check();
|
||||
|
||||
public void signal()
|
||||
{
|
||||
if (check())
|
||||
program.queueNodeProcess(this);
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
// assume most nodes are stateless
|
||||
// default implementation does nothing
|
||||
}
|
||||
|
||||
public static final Comparator<Node> DEPENDENCY_ORDER = (Node a, Node b) ->
|
||||
{
|
||||
int ret = 0;
|
||||
if (a.dependsOn(b))
|
||||
ret--;
|
||||
if (b.dependsOn(a))
|
||||
ret++;
|
||||
return ret;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor.nodes;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import moe.nekojimi.nodeprocessor.Program;
|
||||
import moe.nekojimi.nodeprocessor.ports.ConstantOutPort;
|
||||
import moe.nekojimi.nodeprocessor.ports.InPort;
|
||||
import moe.nekojimi.nodeprocessor.ports.OutPort;
|
||||
|
||||
/**
|
||||
* Represents an object that performs some function.
|
||||
* Has a set of inputs that will cause the object to be (re) created when
|
||||
* changed.
|
||||
*
|
||||
* @author jimj316
|
||||
* @param <T>
|
||||
*/
|
||||
public class ObjectNode<T> extends Node
|
||||
{
|
||||
protected T object;
|
||||
private final Constructor<T> constructor;
|
||||
private final Set<InPort> composingInPorts = new HashSet<>();
|
||||
private final Set<InPort> setterInPorts = new HashSet<>();
|
||||
private final Set<OutPort> getterOutPorts = new HashSet<>();
|
||||
private final OutPort<T> objectOutPort;
|
||||
private final Map<String, Object> composingValues = new HashMap<>();
|
||||
private final Class<T> clazz;
|
||||
|
||||
public ObjectNode(Program scene, Class<T> clazz, Constructor<T> constructor)
|
||||
{
|
||||
super(scene);
|
||||
this.clazz = clazz;
|
||||
this.constructor = constructor;
|
||||
objectOutPort = new ConstantOutPort<>("this", clazz, this);
|
||||
|
||||
addConstructor();
|
||||
addAutoMethods();
|
||||
}
|
||||
|
||||
public void addAutoMethods() throws SecurityException
|
||||
{
|
||||
for (Method method : clazz.getMethods())
|
||||
{
|
||||
String name = method.getName();
|
||||
Class<?> returnType = method.getReturnType();
|
||||
Parameter[] parameters = method.getParameters();
|
||||
if (returnType == null && parameters.length == 1 && name.startsWith("set"))
|
||||
{
|
||||
// this is a setter method
|
||||
InPort in = new InPort(name, parameters[0].getType(), this);
|
||||
addInPort(in);
|
||||
setterInPorts.add(in);
|
||||
} else if (returnType != null && parameters.length == 0 && (name.startsWith("get") || name.startsWith("is")))
|
||||
{
|
||||
// this is a getter method
|
||||
ConstantOutPort out = new ConstantOutPort(name, returnType, this);
|
||||
addOutPort(out);
|
||||
getterOutPorts.add(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addConstructor()
|
||||
{
|
||||
Parameter[] parameters = constructor.getParameters();
|
||||
for (Parameter parameter : parameters)
|
||||
{
|
||||
InPort in = new InPort(parameter.getName(), parameter.getType(), this);
|
||||
addInPort(in);
|
||||
composingInPorts.add(in);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
super.reset();
|
||||
if (object instanceof Closeable)
|
||||
{
|
||||
try
|
||||
{
|
||||
((Closeable) object).close();
|
||||
} catch (IOException ex)
|
||||
{
|
||||
Logger.getLogger(ObjectNode.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
object = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process()
|
||||
{
|
||||
// check if the composing values have changed; if so delete the object
|
||||
|
||||
// if the object doesn't exist, create it
|
||||
if (object == null)
|
||||
{
|
||||
Constructor<?>[] constructors = clazz.getConstructors();
|
||||
for (Constructor constructor : constructors)
|
||||
{
|
||||
Parameter[] parameters = constructor.getParameters();
|
||||
List<Object> args = new ArrayList<>();
|
||||
for (Parameter parameter : parameters)
|
||||
{
|
||||
InPort<?> inPort = getInPort(parameter.getName(), parameter.getType());
|
||||
if (inPort.has())
|
||||
args.add(inPort.get());
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (args.size() == parameters.length)
|
||||
{
|
||||
try
|
||||
{
|
||||
object = (T) constructor.newInstance(args.toArray());
|
||||
objectOutPort.set(object);
|
||||
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex)
|
||||
{
|
||||
Logger.getLogger(ObjectNode.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now the object exists, do something with it
|
||||
if (object != null)
|
||||
{
|
||||
// take input from setters
|
||||
// give output to getters
|
||||
|
||||
return doProcess();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean doProcess()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check()
|
||||
{
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor.nodes;
|
||||
|
||||
import java.util.Iterator;
|
||||
import moe.nekojimi.nodeprocessor.Program;
|
||||
import moe.nekojimi.nodeprocessor.ports.InPort;
|
||||
import moe.nekojimi.nodeprocessor.ports.OutPort;
|
||||
import moe.nekojimi.nodeprocessor.ports.QueueOutPort;
|
||||
|
||||
public class SerialiserNode<T> extends Node
|
||||
{
|
||||
|
||||
private final Class<Iterable<T>> aClass;
|
||||
private final Class<T> clazz;
|
||||
|
||||
public SerialiserNode(Program scene, Class<T> clazz)
|
||||
{
|
||||
super(scene);
|
||||
Iterable<T> it = () ->
|
||||
{
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
};
|
||||
aClass = (Class<Iterable<T>>) it.getClass();
|
||||
addInPort(new InPort("in", aClass, this));
|
||||
this.clazz = clazz;
|
||||
addOutPort(new QueueOutPort("out", clazz, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process()
|
||||
{
|
||||
InPort<Iterable<T>> inPort = getInPort("in", aClass);
|
||||
OutPort<T> outPort = getOutPort("out", clazz);
|
||||
if (inPort.has())
|
||||
{
|
||||
Iterable<T> iterable = inPort.get();
|
||||
Iterator<T> iterator = iterable.iterator();
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
outPort.set(iterator.next());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check()
|
||||
{
|
||||
InPort<Iterable<T>> inPort = getInPort("in", aClass);
|
||||
return inPort.has();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor.nodes;
|
||||
|
||||
import moe.nekojimi.nodeprocessor.Program;
|
||||
import moe.nekojimi.nodeprocessor.ports.ConstantOutPort;
|
||||
import moe.nekojimi.nodeprocessor.ports.InPort;
|
||||
|
||||
public class ValueNode<T> extends Node
|
||||
{
|
||||
|
||||
private T value;
|
||||
|
||||
private final ConstantOutPort<T> outPort;
|
||||
private final InPort<T> inPort;
|
||||
|
||||
public ValueNode(Program scene, Class<T> clazz)
|
||||
{
|
||||
super(scene);
|
||||
inPort = new InPort("set", clazz, this);
|
||||
addInPort(inPort);
|
||||
outPort = new ConstantOutPort("out", clazz, this);
|
||||
addOutPort(outPort);
|
||||
}
|
||||
|
||||
public void setValue(T val)
|
||||
{
|
||||
value = val;
|
||||
signal();
|
||||
}
|
||||
|
||||
public T getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process()
|
||||
{
|
||||
if (inPort.has())
|
||||
value = inPort.get();
|
||||
outPort.set(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check()
|
||||
{
|
||||
return inPort.has();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor.ports;
|
||||
|
||||
import moe.nekojimi.nodeprocessor.nodes.Node;
|
||||
|
||||
public class ConstantOutPort<T> extends OutPort<T>
|
||||
{
|
||||
|
||||
public ConstantOutPort(String name, Class<T> clazz, Node node)
|
||||
{
|
||||
super(name, clazz, node);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor.ports;
|
||||
|
||||
import moe.nekojimi.nodeprocessor.links.Link;
|
||||
import moe.nekojimi.nodeprocessor.nodes.Node;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jimj316
|
||||
*/
|
||||
public class InPort<T> extends Port<T>
|
||||
{
|
||||
|
||||
public InPort(String name, Class<T> clazz, Node node)
|
||||
{
|
||||
super(name, clazz, node);
|
||||
}
|
||||
|
||||
public boolean has()
|
||||
{
|
||||
if (links.isEmpty())
|
||||
return false;
|
||||
else
|
||||
return links.stream().anyMatch((l) -> l.has());
|
||||
}
|
||||
|
||||
public T get()
|
||||
{
|
||||
for (Link<T, ?, ?> link : links)
|
||||
{
|
||||
if (link.has())
|
||||
return link.read();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void signal()
|
||||
{
|
||||
node.signal();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor.ports;
|
||||
|
||||
import moe.nekojimi.nodeprocessor.links.Link;
|
||||
import moe.nekojimi.nodeprocessor.nodes.Node;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jimj316
|
||||
*/
|
||||
public abstract class OutPort<T> extends Port<T>
|
||||
{
|
||||
|
||||
public OutPort(String name, Class<T> clazz, Node node)
|
||||
{
|
||||
super(name, clazz, node);
|
||||
}
|
||||
|
||||
public void set(T value)
|
||||
{
|
||||
for (Link<T, ?, ?> link : links)
|
||||
{
|
||||
link.write(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(Link<T, ?, ?> link)
|
||||
{
|
||||
super.connect(link);
|
||||
// also re-order the links into dependency order
|
||||
links.sort((Link a, Link b) ->
|
||||
{
|
||||
Node aNode = a.getTo().getNode();
|
||||
Node bNode = b.getTo().getNode();
|
||||
return Node.DEPENDENCY_ORDER.compare(aNode, bNode);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor.ports;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import moe.nekojimi.nodeprocessor.links.Link;
|
||||
import moe.nekojimi.nodeprocessor.nodes.Node;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jimj316
|
||||
*/
|
||||
public abstract class Port<T>
|
||||
{
|
||||
protected final String name;
|
||||
protected final Class<T> clazz;
|
||||
protected final Node node;
|
||||
protected final List<Link<T, ?, ?>> links = new ArrayList<>();
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public Class<T> getClazz()
|
||||
{
|
||||
return clazz;
|
||||
}
|
||||
|
||||
public void connect(Link<T, ?, ?> link)
|
||||
{
|
||||
links.add(link);
|
||||
}
|
||||
|
||||
public void disconnect(Link<T, ?, ?> link)
|
||||
{
|
||||
links.remove(link);
|
||||
}
|
||||
|
||||
public Port(String name, Class<T> clazz, Node node)
|
||||
{
|
||||
this.name = name;
|
||||
this.clazz = clazz;
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public Set<Node> getLinkedNodes()
|
||||
{
|
||||
Set<Node> ret = new HashSet<>();
|
||||
for (Link<T, ?, ?> link : links)
|
||||
{
|
||||
Port otherSide;
|
||||
if (link.getFrom() == this)
|
||||
otherSide = link.getTo();
|
||||
else
|
||||
otherSide = link.getFrom();
|
||||
ret.add(otherSide.node);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public int getNumberOfConnections()
|
||||
{
|
||||
return links.size();
|
||||
}
|
||||
|
||||
public Node getNode()
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
public List<Link<T, ?, ?>> getLinks()
|
||||
{
|
||||
return links;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor.ports;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
import moe.nekojimi.nodeprocessor.nodes.Node;
|
||||
|
||||
public class PullOutPort<T> extends OutPort<T>
|
||||
{
|
||||
|
||||
private Supplier<T> supplier;
|
||||
|
||||
public PullOutPort(String name, Class<T> clazz, Node node)
|
||||
{
|
||||
super(name, clazz, node);
|
||||
}
|
||||
|
||||
public void setSupplier(Supplier<T> supplier)
|
||||
{
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(T value)
|
||||
{
|
||||
// not used
|
||||
}
|
||||
|
||||
public T pull()
|
||||
{
|
||||
return supplier.get();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package moe.nekojimi.nodeprocessor.ports;
|
||||
|
||||
import moe.nekojimi.nodeprocessor.nodes.Node;
|
||||
|
||||
public class QueueOutPort<T> extends OutPort<T>
|
||||
{
|
||||
|
||||
public QueueOutPort(String name, Class<T> clazz, Node node)
|
||||
{
|
||||
super(name, clazz, node);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue