Added Nenjim Kicker (BROKEN!)

This commit is contained in:
2026-06-16 13:23:02 +02:00
parent 439febc110
commit b8bf70a178
7 changed files with 292 additions and 0 deletions
@@ -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 "";
}
}