Added Nenjim Kicker (BROKEN!)
This commit is contained in:
@@ -0,0 +1,27 @@
|
|||||||
|
package com.r35157.nenjim.kicker;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public interface NenjimKicker {
|
||||||
|
/**
|
||||||
|
* Starts a process based on the provided fully qualified interface name.
|
||||||
|
* The actual implementation that is run is bound according to the Context.
|
||||||
|
*
|
||||||
|
* @param fqInterfaceName the fully qualified interface name for the actual class to start as a process. The interface must extend the {@code NenjimProcess} interface.
|
||||||
|
*/
|
||||||
|
void startProcess(@NotNull String fqInterfaceName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a map of all running processes managed by the NenjimHub, keyed by the processId.
|
||||||
|
*
|
||||||
|
* @return a map of {@code NenjimProcess} running processes
|
||||||
|
*/
|
||||||
|
@NotNull HashMap<Integer, NenjimProcess> getRunningProcesses();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A no-operation (noop). This method does nothing.
|
||||||
|
*/
|
||||||
|
void noop();
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.r35157.nenjim.kicker;
|
||||||
|
|
||||||
|
//import com.r35157.nenjim.hubd.Context;
|
||||||
|
import com.r35157.nenjim.hubd.NenjimHub;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public interface NenjimProcess {
|
||||||
|
void run() throws Exception;
|
||||||
|
|
||||||
|
default void setContext(/*@NotNull Context context*/) {};
|
||||||
|
default void setHub(@NotNull NenjimHub hub) {};
|
||||||
|
|
||||||
|
@NotNull String getName();
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.r35157.nenjim.kicker.impl.ref;
|
||||||
|
|
||||||
|
import com.r35157.nenjim.kicker.NenjimProcess;
|
||||||
|
//import org.apache.logging.log4j.LogManager;
|
||||||
|
//import org.apache.logging.log4j.Logger;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public final class Dummy implements NenjimProcess {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
//log.error("Process '" + getName() + "' started.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String getName() {
|
||||||
|
return "Just A Dummy";
|
||||||
|
}
|
||||||
|
|
||||||
|
//private static final Logger log = LogManager.getLogger(Dummy.class);
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.r35157.nenjim.kicker.impl.ref;
|
||||||
|
|
||||||
|
import com.r35157.nenjim.hubd.NenjimHub;
|
||||||
|
import com.r35157.nenjim.hubd.ctx.Context;
|
||||||
|
import com.r35157.nenjim.kicker.NenjimKicker;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public final class Initializer {
|
||||||
|
static void main() {
|
||||||
|
try {
|
||||||
|
Initializer bs = new Initializer();
|
||||||
|
String classesCacheDirOrig = "~/.config/nenjim/kicker/cache/classes";
|
||||||
|
String classesCacheDir = (classesCacheDirOrig.startsWith("~/"))
|
||||||
|
? System.getProperty("user.home") + classesCacheDirOrig.substring(1)
|
||||||
|
: classesCacheDirOrig;
|
||||||
|
Path pathToClassesCache = Path.of(classesCacheDir);
|
||||||
|
|
||||||
|
if(Files.exists(pathToClassesCache) == false) {
|
||||||
|
System.err.println("Cannot find '" + classesCacheDirOrig + "'");
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bs.startNenjimKicker(pathToClassesCache);
|
||||||
|
} catch(Throwable t) {
|
||||||
|
System.err.println("Error initializing NenjimKicker - " + t.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Initializer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startNenjimKicker(Path pathToClassCache) throws Exception {
|
||||||
|
System.out.println("Initializing NenjimKicker...");
|
||||||
|
|
||||||
|
NenjimHub nenjimHub = null;
|
||||||
|
Context defaultContext = new Context();
|
||||||
|
NenjimClassLoader nenjimClassLoader = new NenjimClassLoader(defaultContext, pathToClassCache);
|
||||||
|
|
||||||
|
Class<?> clazz = nenjimClassLoader.findClass("com.r35157.nenjim.kicker.impl.ref.NenjimKickerImpl");
|
||||||
|
Object instance = clazz.getDeclaredConstructor().newInstance();
|
||||||
|
NenjimKicker kicker = (NenjimKicker)instance;
|
||||||
|
|
||||||
|
System.out.println(kicker);
|
||||||
|
System.out.println("Loaded class: " + clazz.getName());
|
||||||
|
System.out.println("ClassLoader: " + clazz.getClassLoader());
|
||||||
|
System.out.println("Parent: " + clazz.getClassLoader().getParent());
|
||||||
|
System.out.println("Instance: " + instance);
|
||||||
|
|
||||||
|
System.out.println("Done!");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package com.r35157.nenjim.kicker.impl.ref;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import com.r35157.nenjim.hubd.ctx.Context;
|
||||||
|
import com.r35157.libs.valuetypes.basic.SemanticVersion;
|
||||||
|
//import com.r35157.nenjim.hubd.NenjimJournal;
|
||||||
|
|
||||||
|
public final class NenjimClassLoader extends ClassLoader {
|
||||||
|
public NenjimClassLoader(Context context, Path classCacheRoot) {
|
||||||
|
this.context = context;
|
||||||
|
this.classCacheRoot = classCacheRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||||
|
// Check if we have any local version preferences configured for the associated Context.
|
||||||
|
SemanticVersion version = context.getVersion(name);
|
||||||
|
|
||||||
|
if(version == null) {
|
||||||
|
// No local configurations for a specific version has been configured for this package
|
||||||
|
// in this Context. Use the version the developer do recommend in the Journal.
|
||||||
|
version = null;//journal.getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Searching for class '" + name + "' in local class cache...");
|
||||||
|
String relativePath = name.replace('.', '/') + ".class";
|
||||||
|
Path classFile = classCacheRoot.resolve(relativePath);
|
||||||
|
|
||||||
|
if (!Files.exists(classFile)) {
|
||||||
|
throw new ClassNotFoundException("Class not found: " + name + " at " + classFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
byte[] classBytes = Files.readAllBytes(classFile);
|
||||||
|
return defineClass(name, classBytes, 0, classBytes.length);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ClassNotFoundException("Failed to load class: " + name, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//private NenjimJournal journal;
|
||||||
|
private Context context;
|
||||||
|
private Path classCacheRoot;
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package com.r35157.nenjim.kicker.impl.ref;
|
||||||
|
|
||||||
|
//import com.r35157.nenjim.hubd.Context;
|
||||||
|
import com.r35157.nenjim.kicker.NenjimKicker;
|
||||||
|
import com.r35157.nenjim.kicker.NenjimProcess;
|
||||||
|
//import org.apache.logging.log4j.LogManager;
|
||||||
|
//import org.apache.logging.log4j.Logger;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
public final class NenjimKickerImpl implements NenjimKicker {
|
||||||
|
|
||||||
|
public NenjimKickerImpl() throws InterruptedException {
|
||||||
|
lock = new Object();
|
||||||
|
running = 0;
|
||||||
|
processes = new ConcurrentHashMap<>();
|
||||||
|
processThreads = new ConcurrentHashMap<>();
|
||||||
|
nextProcessId = new AtomicInteger(1);
|
||||||
|
|
||||||
|
startProcess("com.r35157.nenjim.kicker.impl.ref.Dummy");
|
||||||
|
|
||||||
|
//log.info("Waiting for all processes to finish!");
|
||||||
|
awaitAllProcessesFinished();
|
||||||
|
//log.info("Kicker successfully shutdown!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startProcess(@NotNull String fqInterfaceName) {
|
||||||
|
ClassLoader loader = ClassLoader.getSystemClassLoader();
|
||||||
|
int processId = nextProcessId.getAndIncrement();
|
||||||
|
|
||||||
|
final NenjimProcess proc;
|
||||||
|
final String procName;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Class<?> clazz = loader.loadClass(fqInterfaceName);
|
||||||
|
|
||||||
|
if (!NenjimProcess.class.isAssignableFrom(clazz)) {
|
||||||
|
throw new IllegalArgumentException("'" + fqInterfaceName + "' does NOT implement NenjimProcess");
|
||||||
|
}
|
||||||
|
|
||||||
|
proc = (NenjimProcess) clazz.getDeclaredConstructor().newInstance();
|
||||||
|
procName = proc.getName();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
//log.error("Failed to create process '{}' (#{}).", fqInterfaceName, processId, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
processes.put(processId, proc);
|
||||||
|
|
||||||
|
//Context context = new Context(); log.warn("TODO: Set the Context here when we have one!");
|
||||||
|
//proc.setContext(context);
|
||||||
|
//proc.setHub(null); log.warn("TODO: Set the HUB here when we have one!");
|
||||||
|
|
||||||
|
synchronized (lock) {
|
||||||
|
running++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread t = Thread.ofVirtual()
|
||||||
|
.name(procName)
|
||||||
|
.start(() -> {
|
||||||
|
try {
|
||||||
|
//log.info("Starting process '{}' (#{})...", procName, processId);
|
||||||
|
proc.run();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
//log.error("Process '{}' (#{}) crashed!", procName, processId, e);
|
||||||
|
} finally {
|
||||||
|
processThreads.remove(processId);
|
||||||
|
processes.remove(processId);
|
||||||
|
synchronized (lock) {
|
||||||
|
running--;
|
||||||
|
lock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
processThreads.put(processId, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull HashMap<Integer, NenjimProcess> getRunningProcesses() {
|
||||||
|
return new HashMap<>(processes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void noop() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void awaitAllProcessesFinished() throws InterruptedException {
|
||||||
|
synchronized (lock) {
|
||||||
|
while (running > 0) {
|
||||||
|
lock.wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//private static final Logger log = LogManager.getLogger(NenjimKickerImpl.class);
|
||||||
|
|
||||||
|
private int running;
|
||||||
|
private final Object lock;
|
||||||
|
private final ConcurrentHashMap<Integer, NenjimProcess> processes;
|
||||||
|
private final ConcurrentHashMap<Integer, Thread> processThreads;
|
||||||
|
private final AtomicInteger nextProcessId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.r35157.nenjim.kicker.impl.ref;
|
||||||
|
|
||||||
|
//import com.r35157.nenjim.hubd.Context;
|
||||||
|
import com.r35157.nenjim.hubd.NenjimHub;
|
||||||
|
import com.r35157.nenjim.kicker.NenjimProcess;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public final class NenjimProcessImpl implements NenjimProcess {
|
||||||
|
@Override
|
||||||
|
public void run() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContext(/*@NotNull Context context*/) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHub(@NotNull NenjimHub nenjimHub) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String getName() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user