Compare commits

15 Commits

20 changed files with 371 additions and 31 deletions

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@
# Ignore Gradle build output directory
build
/logs/

View File

@@ -1,5 +1,6 @@
plugins {
id("java")
id("application")
id("maven-publish")
}
@@ -9,6 +10,10 @@ if (version == "UNSET" && gradle.startParameter.taskNames.any { it.startsWith("p
throw GradleException("You must set -Pversion=... (use publish.sh / publishCICD.sh)")
}
application {
mainClass.set("com.r35157.nenjim.kicker.impl.ref.Main")
}
repositories {
mavenLocal()
@@ -28,17 +33,44 @@ repositories {
}
dependencies {
implementation("org.jetbrains:annotations:26.0.1")
implementation("log4j:log4j:1.2.17")
implementation("com.r35157.nenjim:kicker-api:0.0.0")
implementation(platform("org.apache.logging.log4j:log4j-bom:2.25.2"))
implementation("org.apache.logging.log4j:log4j-api")
runtimeOnly("org.apache.logging.log4j:log4j-core")
compileOnly("org.jetbrains:annotations:26.0.2-1")
implementation("com.r35157.nenjim:hubd-api:0.1-dev")
implementation("com.r35157.nenjim:kicker-api:0.1-dev")
}
java {
toolchain { languageVersion.set(JavaLanguageVersion.of(24)) }
toolchain { languageVersion.set(JavaLanguageVersion.of(25)) }
}
tasks.withType<JavaCompile> {
options.release.set(24)
tasks.withType<JavaCompile>().configureEach {
options.release.set(25)
options.compilerArgs.add("--enable-preview")
}
val libsDir = layout.buildDirectory.dir("libs")
tasks.register<Sync>("prepareLibs") {
group = "distribution"
description = "Copies runtime deps to build/libs without deleting the app jar"
val jarTask = tasks.named<Jar>("jar")
dependsOn(jarTask)
into(libsDir)
// Kun deps (transitivt)
from(configurations.runtimeClasspath)
// Bevar jar-filen som jar-tasken allerede har lagt i build/libs
preserve {
include(jarTask.get().archiveFileName.get())
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
publishing {

View File

@@ -1,6 +1,45 @@
#!/usr/bin/env bash
set -euo pipefail
JREVERSION=25.0.2-0
export VERSION=$(git describe --tags --exact-match 2>/dev/null \
|| git symbolic-ref --short -q HEAD \
|| git rev-parse --short HEAD)
echo "Building $VERSION..."
./gradlew -Pversion=$VERSION jar
GITHASH=$(git rev-parse --short=8 HEAD)
export VERSION_LONG=${VERSION}_${GITHASH}
# Build this artifact
echo "Building 'NenjimKicker v${VERSION_LONG}'..."
./gradlew -Pversion=$VERSION jar prepareLibs
# Prepare container dependencies
mkdir -p build/docker/{conf,libs}
cd build/docker
cp ../../src/main/docker/run.sh run.sh
cp ../libs/*.jar libs/
cp ../../conf/* conf/
sed -e "s|_VERSION_|${VERSION}|g" \
-e "s|_JREVERSION_|${JREVERSION}|g" \
../../src/main/docker/Dockerfile_template > Dockerfile
# Build the container
GROUP=r35157
NAME=nenjimkicker
BASETAG=dockerreg.r35157.com/${GROUP}/${NAME}
HASHTAG=${BASETAG}:${GITHASH}_amd64
VERSIONTAG=${BASETAG}:${VERSION}_amd64
LATESTTAG=${BASETAG}:latest_amd64
CANONICALNAME=${HASHTAG}
docker build -t ${CANONICALNAME} .
docker tag ${CANONICALNAME} ${VERSIONTAG}
docker tag ${CANONICALNAME} ${LATESTTAG}
# Prepare publishing script
sed -e "s|_HASHTAG_|${HASHTAG}|g" \
-e "s|_VERSIONTAG_|${VERSIONTAG}|g" \
-e "s|_LATESTTAG_|${LATESTTAG}|g" \
../../src/main/docker/publish_template.sh > publish.sh
chmod 755 publish.sh

View File

@@ -1 +1,4 @@
#!/usr/bin/env bash
set -euo pipefail
./gradlew clean ; rm -rf build

23
conf/log4j2.xml Normal file
View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<RollingFile name="File"
fileName="logs/NenjimKicker.log"
filePattern="logs/NenjimKicker-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="%d{ISO8601} %-5p %c - %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<SizeBasedTriggeringPolicy size="50 MB"/>
</Policies>
<DefaultRolloverStrategy max="14"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>

View File

@@ -1,5 +1,5 @@
org.gradle.java.installations.auto-detect=true
org.gradle.java.installations.fromEnv=JAVA_HOME
org.gradle.java.installations.paths=/usr/local/software/java/jfx-24
org.gradle.java.installations.paths=/usr/local/software/java/jfx-25
org.gradle.java.installations.auto-download=false
org.gradle.configuration-cache=true

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

1
libs Symbolic link
View File

@@ -0,0 +1 @@
build/libs

View File

@@ -1,6 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
export VERSION=$(git describe --tags --exact-match 2>/dev/null \
|| git symbolic-ref --short -q HEAD \
|| git rev-parse --short HEAD)
echo "Building and publishing $VERSION..."
echo "Publishing artifact to local Maven repo ($VERSION)..."
./gradlew -Pversion=$VERSION publishToMavenLocal
echo "Publishing docker container to public 'dockerreg.r35157.com' ($VERSION)..."
./build/docker/publish.sh

View File

@@ -1,6 +0,0 @@
export VERSION=$(git describe --tags --exact-match 2>/dev/null \
|| git symbolic-ref --short -q HEAD \
|| git rev-parse --short HEAD)
echo "Building and publishing (CI/CD) $VERSION..."
./gradlew -Pversion=$VERSION publish

1
publishCICD.sh Symbolic link
View File

@@ -0,0 +1 @@
publish.sh

1
run.sh Symbolic link
View File

@@ -0,0 +1 @@
src/main/docker/run.sh

View File

@@ -1 +1 @@
rootProject.name = "kicker-impl-ref"
rootProject.name = "kicker-impl_ref"

View File

@@ -0,0 +1,43 @@
FROM dockerreg.r35157.com/r35157/jre:_JREVERSION__amd64
LABEL maintainer="Minimons <minimons@r35157.com>"
# Setup environment
ENV APP_HOME=/usr/local/software/nenjimkicker
WORKDIR /usr/local/software
USER root
RUN mkdir nenjimkicker-_VERSION_ \
&& ln -s nenjimkicker-_VERSION_ nenjimkicker
WORKDIR nenjimkicker
RUN mkdir libs
# These dirs are expected to be overshadowed by host mounts
RUN mkdir conf logs && chown user:user logs
# Set timezone
ENV TZ=Europe/Copenhagen
RUN apt-get update
RUN apt-get install -y tzdata \
&& ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone \
&& dpkg-reconfigure -f noninteractive tzdata
# Clean-up
RUN apt-get autoremove -y \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Install application and configuration (Do this as late as possible to be able to reuse layers between builds)
COPY run.sh .
COPY conf/* conf/
COPY libs/*.jar libs/
RUN chown root:root -R conf
RUN chmod 755 ./run.sh \
&& chmod -R a+rX /usr/local/software/nenjimkicker-_VERSION_
USER user:user
CMD ["./run.sh"]

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -euo pipefail
echo "Publishing '_HASHTAG_', '_VERSIONTAG_' and '_LATESTTAG_'..."
docker push _HASHTAG_
docker push _VERSIONTAG_
docker push _LATESTTAG_
echo "Publishing completed!"

17
src/main/docker/run.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -euo pipefail
shopt -s nullglob
jars=(libs/*.jar)
if (( ${#jars[@]} == 0 )); then
echo "ERROR: No JARs found in libs/" >&2
exit 1
fi
CLASSPATH=$(IFS=:; echo "${jars[*]}")
exec java \
-Dlog4j.configurationFile=conf/log4j2.xml \
-cp "$CLASSPATH" \
com.r35157.nenjim.kicker.impl.ref.Main

View File

@@ -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 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);
}

View File

@@ -0,0 +1,31 @@
package com.r35157.nenjim.kicker.impl.ref;
import com.r35157.nenjim.kicker.NenjimKicker;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Main {
static void main(String[] args) throws Exception {
try {
new Main(args).service();
} catch(Throwable t) {
log.error("Error initializing NenjimKicker - " + t.getMessage());
}
}
public Main(String[] args) throws Exception {
kicker = new NenjimKickerImpl();
log.info("Initializing NenjimKicker...");
log.info("Ready!");
kicker.noop();
Thread.sleep(Long.MAX_VALUE);
}
private void service() throws Exception {
}
private static final Logger log = LogManager.getLogger(Main.class);
private final NenjimKicker kicker;
}

View File

@@ -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 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;
}

View File

@@ -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 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 "";
}
}

View File

@@ -1,13 +0,0 @@
package com.r35157.nenjim.kicker.impl.ref;
import com.r35157.nenjim.kicker.SomeInterface;
public class SomeImpl implements SomeInterface {
public String concat(String x, String y) {
return x + y;
}
public void divideByZero() throws ArithmeticException {
int a = 0/0;
}
}