Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,18 @@ public ClassLoader getClassLoader() {
}

/**
* Returns a classloader containing only the libraries contained in the custom resources, with
* no parent classloader. If no custom libraries are being used in the current JavaScript
* context, this will return null.
*
* @return A classloader containing only the libraries contained in the custom resources, with
* no parent classloader.
* Returns a classloader containing only the libraries in the custom resources assigned to the
* current context. Use it to load classes from those libraries in isolation, for example a
* specific JDBC driver version, without interference from the versions the server itself ships.
* <p>
* Core Java classes (for example {@code java.sql} or {@code javax.xml}) are visible through this
* classloader, but classes from the server or its plugins are not (its parent is
* {@link ClassLoader#getPlatformClassLoader()}). A class that exists in both a custom resource
* and the JDK resolves to the JDK's copy. The "Load Parent-First" option on a resource does not
* affect this classloader; it applies only to the classloader returned by {@link #getClassLoader()}.
*
* @return A classloader containing only the custom resource libraries, or null if the current
* context has no custom resources.
*/
public ClassLoader getIsolatedClassLoader() {
return delegate.getIsolatedClassLoader();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public ClassLoader getIsolatedClassLoader() {
if (isolatedClassLoader == null && ArrayUtils.isNotEmpty(urls)) {
synchronized (this) {
if (isolatedClassLoader == null) {
isolatedClassLoader = new URLClassLoader(urls, null);
isolatedClassLoader = new URLClassLoader(urls, ClassLoader.getPlatformClassLoader());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: Open Integration Engine

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Several issues with this, but I know you only used the suggestion you were given.

  1. An author cannot claim copyright for AI Generated content where there was not significant creative input given in the prompt or in post-editing.
  2. The AI notes that this class was derived from JavaScriptUtilTest, so it should carry the copyright from that file at minimum.
  3. The project cannot claim copyright, as it is not a person or legal entity. When a specific person is not named and the changes are suitable for claiming copyright, this is typically noted as "Open Integration Engine Contributors."
Suggested change
// SPDX-FileCopyrightText: Open Integration Engine
// SPDX-FileCopyrightText: Mirth Corporation


package com.mirth.connect.server.util.javascript;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.io.File;
import java.net.URL;
import java.util.HashSet;

import org.junit.BeforeClass;
import org.junit.Test;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.mirth.connect.server.builders.JavaScriptBuilder;
import com.mirth.connect.server.controllers.CodeTemplateController;
import com.mirth.connect.server.controllers.ConfigurationController;
import com.mirth.connect.server.controllers.ControllerFactory;
import com.mirth.connect.server.controllers.EventController;
import com.mirth.connect.server.controllers.ExtensionController;

public class MirthContextFactoryTest {

@BeforeClass
public static void setUpBeforeClass() {
// Same mocked ControllerFactory pattern as JavaScriptUtilTest, so this class is
// self-sufficient regardless of which test classes ran (and injected) before it.
ControllerFactory controllerFactory = mock(ControllerFactory.class);

EventController eventController = mock(EventController.class);
when(controllerFactory.createEventController()).thenReturn(eventController);

ConfigurationController configurationController = mock(ConfigurationController.class);
when(controllerFactory.createConfigurationController()).thenReturn(configurationController);

ExtensionController extensionController = mock(ExtensionController.class);
when(controllerFactory.createExtensionController()).thenReturn(extensionController);

CodeTemplateController codeTemplateController = mock(CodeTemplateController.class);
when(controllerFactory.createCodeTemplateController()).thenReturn(codeTemplateController);

Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
requestStaticInjection(ControllerFactory.class);
bind(ControllerFactory.class).toInstance(controllerFactory);
}
});
injector.getInstance(ControllerFactory.class);

JavaScriptBuilder.setControllersForTesting(extensionController, codeTemplateController);
}

/*
* Regression test for #338: with a null parent, the isolated classloader cannot see java.sql
* on Java 9+, so custom driver resources failed to deploy. The parent must be the platform
* classloader: JRE classes visible, server classpath not.
*/
@Test
public void isolatedClassLoaderResolvesPlatformButNotServerClasses() throws Exception {
// This jar URL never gets read; it only exists because getIsolatedClassLoader() returns null on empty array.
URL dummyJar = new File("build/tmp/mirth-context-factory-test-dummy.jar").toURI().toURL();
MirthContextFactory contextFactory = new MirthContextFactory(new URL[] { dummyJar }, new HashSet<>(), false);

ClassLoader isolated = contextFactory.getIsolatedClassLoader();
assertNotNull(isolated);

// Fails with ClassNotFoundException if the parent ever goes back to null
isolated.loadClass("java.sql.Driver");

// Fails if the parent is ever widened to a loader that can see the server classpath
assertThrows(ClassNotFoundException.class, () -> isolated.loadClass(MirthContextFactory.class.getName()));
}

@Test
public void isolatedClassLoaderIsNullWithoutResources() {
MirthContextFactory contextFactory = new MirthContextFactory(new URL[0], new HashSet<>(), false);
assertNull(contextFactory.getIsolatedClassLoader());
}
}
Loading