diff --git a/step-functions/step-functions-handler/src/main/java/step/functions/handler/FileApplicationContextFactory.java b/step-functions/step-functions-handler/src/main/java/step/functions/handler/FileApplicationContextFactory.java
new file mode 100644
index 000000000..6cb7cc1fc
--- /dev/null
+++ b/step-functions/step-functions-handler/src/main/java/step/functions/handler/FileApplicationContextFactory.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2025, exense GmbH
+ *
+ * This file is part of Step
+ *
+ * Step is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Step is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Step. If not, see .
+ */
+
+package step.functions.handler;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import step.grid.contextbuilder.ApplicationContextFactory;
+import step.grid.contextbuilder.ClassPathHelper;
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.List;
+
+public class FileApplicationContextFactory extends ApplicationContextFactory {
+
+ private static final Logger logger = LoggerFactory.getLogger(FileApplicationContextFactory.class);
+
+ private final File jar;
+
+ public FileApplicationContextFactory(File jar) {
+ this.jar = jar;
+ }
+
+ public String getId() {
+ return this.jar.getAbsolutePath();
+ }
+
+ public boolean requiresReload() {
+ return false;
+ }
+
+ public ClassLoader buildClassLoader(ClassLoader parentClassLoader) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Creating URLClassLoader from extracted local file {}", this.jar.getAbsolutePath());
+ }
+ List urls = ClassPathHelper.forSingleFile(this.jar);
+ URL[] urlArray = urls.toArray(new URL[urls.size()]);
+ return new URLClassLoader(urlArray, parentClassLoader);
+ }
+
+ public void onClassLoaderClosed() {
+ }
+}
diff --git a/step-functions/step-functions-handler/src/main/java/step/functions/handler/FunctionMessageHandler.java b/step-functions/step-functions-handler/src/main/java/step/functions/handler/FunctionMessageHandler.java
index 1f8ae0f3b..c4b4c6e36 100644
--- a/step-functions/step-functions-handler/src/main/java/step/functions/handler/FunctionMessageHandler.java
+++ b/step-functions/step-functions-handler/src/main/java/step/functions/handler/FunctionMessageHandler.java
@@ -30,9 +30,9 @@
import step.grid.agent.handler.context.OutputMessageBuilder;
import step.grid.agent.tokenpool.AgentTokenWrapper;
import step.grid.agent.tokenpool.TokenReservationSession;
+import step.grid.bootstrap.ResourceExtractor;
import step.grid.contextbuilder.ApplicationContextBuilder;
import step.grid.contextbuilder.ApplicationContextControl;
-import step.grid.contextbuilder.LocalResourceApplicationContextFactory;
import step.grid.contextbuilder.RemoteApplicationContextFactory;
import step.grid.filemanager.FileVersionId;
import step.grid.io.InputMessage;
@@ -41,8 +41,10 @@
import step.livereporting.client.LiveReportingClient;
import step.reporting.LiveReporting;
+import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
+import java.nio.file.Files;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -71,6 +73,7 @@ public class FunctionMessageHandler extends AbstractMessageHandler {
private ApplicationContextBuilder applicationContextBuilder;
public FunctionHandlerFactory functionHandlerFactory;
+ private File functionHandlerInitializerJar;
public FunctionMessageHandler() {
super();
@@ -115,6 +118,7 @@ public void init(AgentTokenServices agentTokenServices) {
applicationContextBuilder.forkCurrentContext(BRANCH_HANDLER_INITIALIZER);
functionHandlerFactory = new FunctionHandlerFactory(applicationContextBuilder, agentTokenServices.getFileManagerClient());
+ functionHandlerInitializerJar = ResourceExtractor.extractResource(this.getClass().getClassLoader(), "step-functions-handler-initializer.jar");
}
@Override
@@ -179,8 +183,8 @@ public OutputMessage handle(AgentTokenWrapper token, InputMessage inputMessage)
}
private LiveReporting initializeLiveReporting(Map properties, TokenReservationSession tokenReservationSession) throws Exception {
- ApplicationContextControl applicationContextControl = applicationContextBuilder.pushContext(BRANCH_HANDLER_INITIALIZER, new LocalResourceApplicationContextFactory(this.getClass().getClassLoader(), "step-functions-handler-initializer.jar"), true);
- // The usage of this application context will be released when the session is closed, underlying registered file won't be cleanable before this release happens
+ ApplicationContextControl applicationContextControl = applicationContextBuilder.pushContext(BRANCH_HANDLER_INITIALIZER, new FileApplicationContextFactory(functionHandlerInitializerJar), false);
+ // The usage of this application context will be released when the session is closed
tokenReservationSession.registerObjectToBeClosedWithSession(applicationContextControl);
return applicationContextBuilder.runInContext(BRANCH_HANDLER_INITIALIZER, () -> {
// There's no easy way to do this in the AbstractFunctionHandler itself, because
@@ -273,5 +277,8 @@ public void close() throws Exception {
if (liveReportingExecutor != null) {
liveReportingExecutor.shutdownNow();
}
+ if (functionHandlerInitializerJar != null) {
+ Files.deleteIfExists(functionHandlerInitializerJar.toPath());
+ }
}
}