Skip to content

Commit

Permalink
Make Classworld setup more alike to vanilla Maven
Browse files Browse the repository at this point in the history
Instead of providing a custom URLClassLoader, create the ClassWorld
using the plexus configurator and then pass it down the call chain.

This improves compatbility with any extensions or plugins that assume that
their ClassLoader is a ClassRealm.
  • Loading branch information
oehme committed Jan 31, 2023
1 parent 11c6567 commit 237e851
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 65 deletions.
35 changes: 25 additions & 10 deletions client/src/main/java/org/mvndaemon/mvnd/client/DaemonConnector.java
Original file line number Diff line number Diff line change
Expand Up @@ -339,22 +339,34 @@ private Process startDaemonProcess(String daemonId, ClientOutput output) {
final Path mvndHome = parameters.mvndHome();
final Path workingDir = parameters.userDir();
String command = "";
try (DirectoryStream<Path> jarPaths =
Files.newDirectoryStream(mvndHome.resolve("lib").resolve("ext"))) {
try {
List<String> args = new ArrayList<>();
// executable
final String java = Os.current().isUnixLike() ? "bin/java" : "bin\\java.exe";
args.add(parameters.javaHome().resolve(java).toString());
// classpath
String mvndCommonPath = null;
String mvndAgentPath = null;
for (Path jar : jarPaths) {
String s = jar.getFileName().toString();
if (s.endsWith(".jar")) {
if (s.startsWith("mvnd-common-")) {
mvndCommonPath = jar.toString();
} else if (s.startsWith("mvnd-agent-")) {
mvndAgentPath = jar.toString();
String plexusClassworldsPath = null;
try (DirectoryStream<Path> jarPaths = Files.newDirectoryStream(mvndHome.resolve("lib/ext"))) {
for (Path jar : jarPaths) {
String s = jar.getFileName().toString();
if (s.endsWith(".jar")) {
if (s.startsWith("mvnd-common-")) {
mvndCommonPath = jar.toString();
} else if (s.startsWith("mvnd-agent-")) {
mvndAgentPath = jar.toString();
}
}
}
}
try (DirectoryStream<Path> jarPaths = Files.newDirectoryStream(mvndHome.resolve("boot"))) {
for (Path jar : jarPaths) {
String s = jar.getFileName().toString();
if (s.endsWith(".jar")) {
if (s.startsWith("plexus-classworlds-")) {
plexusClassworldsPath = jar.toString();
}
}
}
}
Expand All @@ -364,8 +376,11 @@ private Process startDaemonProcess(String daemonId, ClientOutput output) {
if (mvndAgentPath == null) {
throw new IllegalStateException("Could not find mvnd-agent jar in lib/");
}
if (plexusClassworldsPath == null) {
throw new IllegalStateException("Could not find plexus-classworlds jar in boot/");
}
args.add("-classpath");
args.add(mvndCommonPath + File.pathSeparator + mvndAgentPath);
args.add(mvndCommonPath + File.pathSeparator + plexusClassworldsPath + File.pathSeparator + mvndAgentPath);
args.add("-javaagent:" + mvndAgentPath);
// debug options
if (parameters.property(Environment.MVND_DEBUG).asBoolean()) {
Expand Down
5 changes: 5 additions & 0 deletions common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@
<groupId>org.jline</groupId>
<artifactId>jline-terminal-jansi</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-classworlds</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
Expand Down
72 changes: 22 additions & 50 deletions common/src/main/java/org/mvndaemon/mvnd/common/MavenDaemon.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,67 +18,39 @@
*/
package org.mvndaemon.mvnd.common;

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;

import org.codehaus.plexus.classworlds.ClassWorld;
import org.codehaus.plexus.classworlds.launcher.Launcher;
import org.codehaus.plexus.classworlds.realm.ClassRealm;

public class MavenDaemon {

public static void main(String[] args) throws Exception {
final Path mvndHome = Environment.MVND_HOME.asPath();
URL[] classpath = Stream.concat(
/* jars */
Stream.of("lib/ext", "lib", "boot")
.map(mvndHome::resolve)
.flatMap((Path p) -> {
try {
return Files.list(p);
} catch (java.io.IOException e) {
throw new RuntimeException("Could not list " + p, e);
}
})
.filter(p -> {
final String fileName = p.getFileName().toString();
return fileName.endsWith(".jar") && !fileName.startsWith("mvnd-client-");
})
.filter(Files::isRegularFile),
/* resources */
Stream.of(mvndHome.resolve("conf"), mvndHome.resolve("conf/logging")))
.map(Path::normalize)
.map(Path::toUri)
.map(uri -> {
try {
return uri.toURL();
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
})
.toArray(URL[]::new);
ClassLoader loader = new URLClassLoader(classpath, null) {
Path mvndHome = Environment.MVND_HOME.asPath();
Launcher launcher = new Launcher();
launcher.setSystemClassLoader(new ClassLoader(ClassLoader.getPlatformClassLoader()) {

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
return super.findClass(name);
} catch (ClassNotFoundException e) {
if (name.startsWith("org.codehaus.plexus.classworlds.")
|| name.startsWith("org.codehaus.classworlds.")) {
return MavenDaemon.class.getClassLoader().loadClass(name);
}
throw new ClassNotFoundException(name);
}

@Override
public URL getResource(String name) {
URL url = super.getResource(name);
if (url == null) {
url = MavenDaemon.class.getClassLoader().getResource(name);
}
return url;
}
};
Thread.currentThread().setContextClassLoader(loader);
Class<?> clazz = loader.loadClass("org.mvndaemon.mvnd.daemon.Server");
try (AutoCloseable server = (AutoCloseable) clazz.getConstructor().newInstance()) {
});
try (InputStream in = Files.newInputStream(mvndHome.resolve("bin/m2.conf"))) {
launcher.configure(in);
}
ClassWorld world = launcher.getWorld();
ClassRealm coreRealm = launcher.getMainRealm();
Class<?> serverClass = coreRealm.loadClass("org.mvndaemon.mvnd.daemon.Server");
Constructor<?> serverConstructor = serverClass.getConstructor(ClassWorld.class);
try (AutoCloseable server = (AutoCloseable) serverConstructor.newInstance(world)) {
((Runnable) server).run();
}
}
Expand Down
6 changes: 3 additions & 3 deletions daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java
Original file line number Diff line number Diff line change
Expand Up @@ -174,13 +174,12 @@ public class DaemonMavenCli {
*/
private BuildEventListener buildEventListener = BuildEventListener.dummy();

public DaemonMavenCli() throws Exception {
public DaemonMavenCli(ClassWorld classWorld) throws Exception {
slf4jLoggerFactory = LoggerFactory.getILoggerFactory();
slf4jLogger = slf4jLoggerFactory.getLogger(this.getClass().getName());
plexusLoggerManager = new Slf4jLoggerManager();

ClassLoader cl = Thread.currentThread().getContextClassLoader();
classWorld = new ClassWorld("plexus.core", cl);
this.classWorld = classWorld;

container = container();

Expand Down Expand Up @@ -473,6 +472,7 @@ DefaultPlexusContainer container() throws Exception {

List<File> extClassPath = Stream.of(
Environment.MVND_EXT_CLASSPATH.asString().split(","))
.filter(s -> s != null && !s.isEmpty())
.map(File::new)
.collect(Collectors.toList());

Expand Down
5 changes: 3 additions & 2 deletions daemon/src/main/java/org/mvndaemon/mvnd/daemon/Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import java.util.stream.Collectors;

import org.apache.maven.cli.DaemonMavenCli;
import org.codehaus.plexus.classworlds.ClassWorld;
import org.mvndaemon.mvnd.builder.SmartBuilder;
import org.mvndaemon.mvnd.common.DaemonConnection;
import org.mvndaemon.mvnd.common.DaemonException;
Expand Down Expand Up @@ -99,7 +100,7 @@ public class Server implements AutoCloseable, Runnable {
private final DaemonMemoryStatus memoryStatus;
private final long keepAliveMs;

public Server() throws IOException {
public Server(ClassWorld world) throws IOException {
// When spawning a new process, the child process is create within
// the same process group. This means that a few signals are sent
// to the whole group. This is the case for SIGINT (Ctrl-C) and
Expand All @@ -123,7 +124,7 @@ public Server() throws IOException {
.orElse(SocketFamily.inet);

try {
cli = new DaemonMavenCli();
cli = new DaemonMavenCli(world);
registry = new DaemonRegistry(Environment.MVND_REGISTRY.asPath());
socket = socketFamily.openServerSocket();
executor = Executors.newScheduledThreadPool(1);
Expand Down
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-classworlds</artifactId>
<version>2.6.0</version>
</dependency>

</dependencies>
</dependencyManagement>
Expand Down

0 comments on commit 237e851

Please sign in to comment.