From d5c552a55470b32ae5c2fb6ea60688087773a3c8 Mon Sep 17 00:00:00 2001 From: Laurent Cohen Date: Tue, 8 Oct 2019 06:37:26 +0200 Subject: [PATCH] fixed bug JPPF-606 --- .../jppf/node/protocol/TaskThreadLocals.java | 2 +- .../classloader/AbstractClassLoaderTest.java | 22 +++++++ .../test/org/jppf/classloader/MyTestTask.java | 57 +++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 tests/src/tests/test/org/jppf/classloader/MyTestTask.java diff --git a/common/src/java/org/jppf/node/protocol/TaskThreadLocals.java b/common/src/java/org/jppf/node/protocol/TaskThreadLocals.java index 8076c10559..b21aa9cc9c 100644 --- a/common/src/java/org/jppf/node/protocol/TaskThreadLocals.java +++ b/common/src/java/org/jppf/node/protocol/TaskThreadLocals.java @@ -27,7 +27,7 @@ public final class TaskThreadLocals { /** * Uuid of the original task bundle that triggered a resource loading request. */ - private static final ThreadLocal requestUuid = new ThreadLocal<>(); + private static final InheritableThreadLocal requestUuid = new InheritableThreadLocal<>(); /** * Instantiation not permitted. diff --git a/tests/src/tests/test/org/jppf/classloader/AbstractClassLoaderTest.java b/tests/src/tests/test/org/jppf/classloader/AbstractClassLoaderTest.java index b0688dd4e3..55628709bf 100644 --- a/tests/src/tests/test/org/jppf/classloader/AbstractClassLoaderTest.java +++ b/tests/src/tests/test/org/jppf/classloader/AbstractClassLoaderTest.java @@ -159,6 +159,28 @@ public void testClassLoadingInterruptionWithCallable() throws Exception { testInterruption(true); } + /** + * Test that class loading works from a thread created by a JPPF task. + *
See JPPF-606 ClassNotFoundException when submitting a Callable to an ExecutorService from a JPPF task + * @throws Exception if any error occurs + */ + @Test(timeout = TEST_TIMEOUT) + public void testClassLoadingFromSeparateThread() throws Exception { + final String name = ReflectionUtils.getCurrentMethodName(); + final List> results = client.submit(BaseTestHelper.createJob(name + "1", false, 1, MyTestTask.class)); + assertNotNull(results); + assertEquals(1, results.size()); + final Task task = results.get(0); + assertNotNull(task); + final Throwable throwable = task.getThrowable(); + if (throwable != null) { + print(false, false, "task raised exception:\n%s", ExceptionUtils.getStackTrace(throwable)); + fail("task raised exception: " + ExceptionUtils.getMessage(throwable)); + } + assertNotNull(task.getResult()); + assertEquals("hello from task", task.getResult()); + } + /** * @param callable . * @throws Exception if any error occurs diff --git a/tests/src/tests/test/org/jppf/classloader/MyTestTask.java b/tests/src/tests/test/org/jppf/classloader/MyTestTask.java new file mode 100644 index 0000000000..d3b74271d5 --- /dev/null +++ b/tests/src/tests/test/org/jppf/classloader/MyTestTask.java @@ -0,0 +1,57 @@ +/* + * JPPF. + * Copyright (C) 2005-2019 JPPF Team. + * http://www.jppf.org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package test.org.jppf.classloader; + +import java.util.concurrent.*; + +import org.jppf.node.protocol.AbstractTask; +import org.jppf.utils.concurrent.JPPFThreadFactory; + +/** + * + * @author Laurent Cohen + */ +public class MyTestTask extends AbstractTask { + @Override + public void run() { + final ExecutorService executor = Executors.newFixedThreadPool(1, new JPPFThreadFactory("Test")); + try { + final Callable callable = () -> "hello from " + new MyClass().getName(); + final String msg = executor.submit(callable).get(); + //final String msg = callable.call(); + setResult(msg); + } catch (final Exception e) { + setThrowable(e); + } finally { + executor.shutdownNow(); + } + } + + /** + * Class loaded during the execution of a callable sublitted to an {@link ExecutorService}. + */ + public static class MyClass { + /** + * @return an arbiitrary string. + */ + public String getName() { + return "task"; + } + } +}