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