mirror of
https://github.com/apache/maven-mvnd.git
synced 2025-10-13 13:44:26 +00:00
Make Classworld setup more alike to vanilla Maven (#784)
Use the plexus Launcher to start the daemon server, just like we would launch a normal Maven process. This improves compatibility with any extensions or plugins that assume that their ClassLoader is a ClassRealm.
This commit is contained in:
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
package org.mvndaemon.mvnd.client;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
@@ -52,7 +51,6 @@ import org.mvndaemon.mvnd.common.DaemonRegistry;
|
||||
import org.mvndaemon.mvnd.common.DaemonState;
|
||||
import org.mvndaemon.mvnd.common.DaemonStopEvent;
|
||||
import org.mvndaemon.mvnd.common.Environment;
|
||||
import org.mvndaemon.mvnd.common.MavenDaemon;
|
||||
import org.mvndaemon.mvnd.common.Message;
|
||||
import org.mvndaemon.mvnd.common.Os;
|
||||
import org.mvndaemon.mvnd.common.SocketFamily;
|
||||
@@ -339,33 +337,43 @@ public class DaemonConnector {
|
||||
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").resolve("ext"))) {
|
||||
for (Path jar : jarPaths) {
|
||||
String s = jar.getFileName().toString();
|
||||
if (s.endsWith(".jar")) {
|
||||
if (s.startsWith("mvnd-agent-")) {
|
||||
mvndAgentPath = jar.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mvndCommonPath == null) {
|
||||
throw new IllegalStateException("Could not find mvnd-common jar in lib/");
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mvndAgentPath == null) {
|
||||
throw new IllegalStateException("Could not find mvnd-agent jar in lib/");
|
||||
throw new IllegalStateException("Could not find mvnd-agent jar in lib/ext/");
|
||||
}
|
||||
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(plexusClassworldsPath);
|
||||
args.add("-javaagent:" + mvndAgentPath);
|
||||
// debug options
|
||||
if (parameters.property(Environment.MVND_DEBUG).asBoolean()) {
|
||||
@@ -422,6 +430,7 @@ public class DaemonConnector {
|
||||
Environment.MVND_HOME.addSystemProperty(args, mvndHome.toString());
|
||||
args.add("-Dmaven.home=" + mvndHome);
|
||||
args.add("-Dmaven.conf=" + mvndHome.resolve("conf"));
|
||||
args.add("-Dclassworlds.conf=" + mvndHome.resolve("bin").resolve("mvnd-server.conf"));
|
||||
|
||||
Environment.MVND_JAVA_HOME.addSystemProperty(
|
||||
args, parameters.javaHome().toString());
|
||||
@@ -439,7 +448,7 @@ public class DaemonConnector {
|
||||
.orElseGet(() -> getJavaVersion() >= 16.0f ? SocketFamily.unix : SocketFamily.inet)
|
||||
.toString());
|
||||
parameters.discriminatingSystemProperties(args);
|
||||
args.add(MavenDaemon.class.getName());
|
||||
args.add("org.codehaus.plexus.classworlds.launcher.Launcher");
|
||||
command = String.join(" ", args);
|
||||
|
||||
LOGGER.debug(
|
||||
|
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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 org.mvndaemon.mvnd.common;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
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) {
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
try {
|
||||
return super.findClass(name);
|
||||
} catch (ClassNotFoundException e) {
|
||||
return MavenDaemon.class.getClassLoader().loadClass(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()) {
|
||||
((Runnable) server).run();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,385 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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 org.apache.maven.classrealm;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.apache.maven.artifact.ArtifactUtils;
|
||||
import org.apache.maven.extension.internal.CoreExportsProvider;
|
||||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.Plugin;
|
||||
import org.codehaus.plexus.MutablePlexusContainer;
|
||||
import org.codehaus.plexus.PlexusContainer;
|
||||
import org.codehaus.plexus.classworlds.ClassWorld;
|
||||
import org.codehaus.plexus.classworlds.realm.ClassRealm;
|
||||
import org.codehaus.plexus.classworlds.realm.DuplicateRealmException;
|
||||
import org.codehaus.plexus.logging.Logger;
|
||||
import org.codehaus.plexus.util.StringUtils;
|
||||
import org.eclipse.aether.artifact.Artifact;
|
||||
import org.eclipse.sisu.Priority;
|
||||
|
||||
/**
|
||||
* This class is a copy of DefaultClassRealmManager with one modification:
|
||||
* the {@link #PARENT_CLASSLOADER} is set to null instead of classworld's classloader.
|
||||
* The reason is that mvnd is booted by {@link org.mvndaemon.mvnd.common.MavenDaemon}
|
||||
* instead of {@link org.codehaus.plexus.classworlds.launcher.Launcher} and classworld
|
||||
* is contained by the maven classloader. This can cause problems with extensions
|
||||
* as their parent contains the whole maven classloader.
|
||||
* See <a href="https://github.com/apache/maven-mvnd/issues/690">mvnd#690</a>
|
||||
*/
|
||||
@Named
|
||||
@Singleton
|
||||
@Priority(10)
|
||||
public class MvndClassRealmManager implements ClassRealmManager {
|
||||
public static final String API_REALMID = "maven.api";
|
||||
|
||||
/**
|
||||
* During normal command line build, ClassWorld is loaded by jvm system classloader, which only includes
|
||||
* plexus-classworlds jar and possibly javaagent classes, see https://issues.apache.org/jira/browse/MNG-4747.
|
||||
* <p>
|
||||
* Using ClassWorld to determine plugin/extensions realm parent classloaders gives m2e and integration test harness
|
||||
* flexibility to load multiple version of maven into dedicated classloaders without assuming state of jvm system
|
||||
* classloader.
|
||||
*/
|
||||
private static final ClassLoader PARENT_CLASSLOADER = ClassLoader.getSystemClassLoader();
|
||||
|
||||
private final Logger logger;
|
||||
|
||||
private final ClassWorld world;
|
||||
|
||||
private final ClassRealm containerRealm;
|
||||
|
||||
// this is a live injected collection
|
||||
private final List<ClassRealmManagerDelegate> delegates;
|
||||
|
||||
private final ClassRealm mavenApiRealm;
|
||||
|
||||
/**
|
||||
* Patterns of artifacts provided by maven core and exported via maven api realm. These artifacts are filtered from
|
||||
* plugin and build extensions realms to avoid presence of duplicate and possibly conflicting classes on classpath.
|
||||
*/
|
||||
private final Set<String> providedArtifacts;
|
||||
|
||||
@Inject
|
||||
public MvndClassRealmManager(
|
||||
Logger logger,
|
||||
PlexusContainer container,
|
||||
List<ClassRealmManagerDelegate> delegates,
|
||||
CoreExportsProvider exports) {
|
||||
this.logger = logger;
|
||||
this.world = ((MutablePlexusContainer) container).getClassWorld();
|
||||
this.containerRealm = container.getContainerRealm();
|
||||
this.delegates = delegates;
|
||||
|
||||
Map<String, ClassLoader> foreignImports = exports.get().getExportedPackages();
|
||||
|
||||
this.mavenApiRealm = createRealm(
|
||||
API_REALMID,
|
||||
ClassRealmRequest.RealmType.Core,
|
||||
null /* parent */,
|
||||
null /* parentImports */,
|
||||
foreignImports,
|
||||
null /* artifacts */);
|
||||
|
||||
this.providedArtifacts = exports.get().getExportedArtifacts();
|
||||
}
|
||||
|
||||
private ClassRealm newRealm(String id) {
|
||||
synchronized (world) {
|
||||
String realmId = id;
|
||||
|
||||
Random random = new Random();
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
ClassRealm classRealm = world.newRealm(realmId, null);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Created new class realm " + realmId);
|
||||
}
|
||||
|
||||
return classRealm;
|
||||
} catch (DuplicateRealmException e) {
|
||||
realmId = id + '-' + random.nextInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ClassRealm getMavenApiRealm() {
|
||||
return mavenApiRealm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new class realm with the specified parent and imports.
|
||||
*
|
||||
* @param baseRealmId The base id to use for the new realm, must not be {@code null}.
|
||||
* @param type The type of the class realm, must not be {@code null}.
|
||||
* @param parent The parent realm for the new realm, may be {@code null}.
|
||||
* @param parentImports The packages/types to import from the parent realm, may be {@code null}.
|
||||
* @param foreignImports The packages/types to import from foreign realms, may be {@code null}.
|
||||
* @param artifacts The artifacts to add to the realm, may be {@code null}. Unresolved artifacts (i.e. with a
|
||||
* missing file) will automatically be excluded from the realm.
|
||||
* @return The created class realm, never {@code null}.
|
||||
*/
|
||||
private ClassRealm createRealm(
|
||||
String baseRealmId,
|
||||
ClassRealmRequest.RealmType type,
|
||||
ClassLoader parent,
|
||||
List<String> parentImports,
|
||||
Map<String, ClassLoader> foreignImports,
|
||||
List<Artifact> artifacts) {
|
||||
Set<String> artifactIds = new LinkedHashSet<>();
|
||||
|
||||
List<ClassRealmConstituent> constituents = new ArrayList<>();
|
||||
|
||||
if (artifacts != null) {
|
||||
for (Artifact artifact : artifacts) {
|
||||
if (!isProvidedArtifact(artifact)) {
|
||||
artifactIds.add(getId(artifact));
|
||||
if (artifact.getFile() != null) {
|
||||
constituents.add(new ArtifactClassRealmConstituent(artifact));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parentImports != null) {
|
||||
parentImports = new ArrayList<>(parentImports);
|
||||
} else {
|
||||
parentImports = new ArrayList<>();
|
||||
}
|
||||
|
||||
if (foreignImports != null) {
|
||||
foreignImports = new TreeMap<>(foreignImports);
|
||||
} else {
|
||||
foreignImports = new TreeMap<>();
|
||||
}
|
||||
|
||||
ClassRealm classRealm = newRealm(baseRealmId);
|
||||
|
||||
if (parent != null) {
|
||||
classRealm.setParentClassLoader(parent);
|
||||
}
|
||||
|
||||
callDelegates(classRealm, type, parent, parentImports, foreignImports, constituents);
|
||||
|
||||
wireRealm(classRealm, parentImports, foreignImports);
|
||||
|
||||
Set<String> includedIds = populateRealm(classRealm, constituents);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
artifactIds.removeAll(includedIds);
|
||||
|
||||
for (String id : artifactIds) {
|
||||
logger.debug(" Excluded: " + id);
|
||||
}
|
||||
}
|
||||
|
||||
return classRealm;
|
||||
}
|
||||
|
||||
public ClassRealm getCoreRealm() {
|
||||
return containerRealm;
|
||||
}
|
||||
|
||||
public ClassRealm createProjectRealm(Model model, List<Artifact> artifacts) {
|
||||
Objects.requireNonNull(model, "model cannot be null");
|
||||
|
||||
ClassLoader parent = getMavenApiRealm();
|
||||
|
||||
return createRealm(getKey(model), ClassRealmRequest.RealmType.Project, parent, null, null, artifacts);
|
||||
}
|
||||
|
||||
private static String getKey(Model model) {
|
||||
return "project>" + model.getGroupId() + ":" + model.getArtifactId() + ":" + model.getVersion();
|
||||
}
|
||||
|
||||
public ClassRealm createExtensionRealm(Plugin plugin, List<Artifact> artifacts) {
|
||||
Objects.requireNonNull(plugin, "plugin cannot be null");
|
||||
|
||||
ClassLoader parent = PARENT_CLASSLOADER;
|
||||
|
||||
Map<String, ClassLoader> foreignImports = Collections.<String, ClassLoader>singletonMap("", getMavenApiRealm());
|
||||
|
||||
return createRealm(
|
||||
getKey(plugin, true), ClassRealmRequest.RealmType.Extension, parent, null, foreignImports, artifacts);
|
||||
}
|
||||
|
||||
private boolean isProvidedArtifact(Artifact artifact) {
|
||||
return providedArtifacts.contains(artifact.getGroupId() + ":" + artifact.getArtifactId());
|
||||
}
|
||||
|
||||
public ClassRealm createPluginRealm(
|
||||
Plugin plugin,
|
||||
ClassLoader parent,
|
||||
List<String> parentImports,
|
||||
Map<String, ClassLoader> foreignImports,
|
||||
List<Artifact> artifacts) {
|
||||
Objects.requireNonNull(plugin, "plugin cannot be null");
|
||||
|
||||
if (parent == null) {
|
||||
parent = PARENT_CLASSLOADER;
|
||||
}
|
||||
|
||||
return createRealm(
|
||||
getKey(plugin, false),
|
||||
ClassRealmRequest.RealmType.Plugin,
|
||||
parent,
|
||||
parentImports,
|
||||
foreignImports,
|
||||
artifacts);
|
||||
}
|
||||
|
||||
private static String getKey(Plugin plugin, boolean extension) {
|
||||
String version = ArtifactUtils.toSnapshotVersion(plugin.getVersion());
|
||||
return (extension ? "extension>" : "plugin>") + plugin.getGroupId() + ":" + plugin.getArtifactId() + ":"
|
||||
+ version;
|
||||
}
|
||||
|
||||
private static String getId(Artifact artifact) {
|
||||
return getId(
|
||||
artifact.getGroupId(),
|
||||
artifact.getArtifactId(),
|
||||
artifact.getExtension(),
|
||||
artifact.getClassifier(),
|
||||
artifact.getBaseVersion());
|
||||
}
|
||||
|
||||
private static String getId(ClassRealmConstituent constituent) {
|
||||
return getId(
|
||||
constituent.getGroupId(),
|
||||
constituent.getArtifactId(),
|
||||
constituent.getType(),
|
||||
constituent.getClassifier(),
|
||||
constituent.getVersion());
|
||||
}
|
||||
|
||||
private static String getId(String gid, String aid, String type, String cls, String ver) {
|
||||
return gid + ':' + aid + ':' + type + (StringUtils.isNotEmpty(cls) ? ':' + cls : "") + ':' + ver;
|
||||
}
|
||||
|
||||
private void callDelegates(
|
||||
ClassRealm classRealm,
|
||||
ClassRealmRequest.RealmType type,
|
||||
ClassLoader parent,
|
||||
List<String> parentImports,
|
||||
Map<String, ClassLoader> foreignImports,
|
||||
List<ClassRealmConstituent> constituents) {
|
||||
List<ClassRealmManagerDelegate> delegates = new ArrayList<>(this.delegates);
|
||||
|
||||
if (!delegates.isEmpty()) {
|
||||
ClassRealmRequest request =
|
||||
new DefaultClassRealmRequest(type, parent, parentImports, foreignImports, constituents);
|
||||
|
||||
for (ClassRealmManagerDelegate delegate : delegates) {
|
||||
try {
|
||||
delegate.setupRealm(classRealm, request);
|
||||
} catch (Exception e) {
|
||||
logger.error(
|
||||
delegate.getClass().getName() + " failed to setup class realm " + classRealm + ": "
|
||||
+ e.getMessage(),
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> populateRealm(ClassRealm classRealm, List<ClassRealmConstituent> constituents) {
|
||||
Set<String> includedIds = new LinkedHashSet<>();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Populating class realm " + classRealm.getId());
|
||||
}
|
||||
|
||||
for (ClassRealmConstituent constituent : constituents) {
|
||||
File file = constituent.getFile();
|
||||
|
||||
String id = getId(constituent);
|
||||
includedIds.add(id);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(" Included: " + id);
|
||||
}
|
||||
|
||||
try {
|
||||
classRealm.addURL(file.toURI().toURL());
|
||||
} catch (MalformedURLException e) {
|
||||
// Not going to happen
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return includedIds;
|
||||
}
|
||||
|
||||
private void wireRealm(ClassRealm classRealm, List<String> parentImports, Map<String, ClassLoader> foreignImports) {
|
||||
if (foreignImports != null && !foreignImports.isEmpty()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Importing foreign packages into class realm " + classRealm.getId());
|
||||
}
|
||||
|
||||
for (Map.Entry<String, ClassLoader> entry : foreignImports.entrySet()) {
|
||||
ClassLoader importedRealm = entry.getValue();
|
||||
String imp = entry.getKey();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(" Imported: " + imp + " < " + getId(importedRealm));
|
||||
}
|
||||
|
||||
classRealm.importFrom(importedRealm, imp);
|
||||
}
|
||||
}
|
||||
|
||||
if (parentImports != null && !parentImports.isEmpty()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Importing parent packages into class realm " + classRealm.getId());
|
||||
}
|
||||
|
||||
for (String imp : parentImports) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(" Imported: " + imp + " < " + getId(classRealm.getParentClassLoader()));
|
||||
}
|
||||
|
||||
classRealm.importFromParent(imp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getId(ClassLoader classLoader) {
|
||||
if (classLoader instanceof ClassRealm) {
|
||||
return ((ClassRealm) classLoader).getId();
|
||||
}
|
||||
return String.valueOf(classLoader);
|
||||
}
|
||||
}
|
@@ -179,8 +179,7 @@ public class DaemonMavenCli {
|
||||
slf4jLogger = slf4jLoggerFactory.getLogger(this.getClass().getName());
|
||||
plexusLoggerManager = new Slf4jLoggerManager();
|
||||
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
classWorld = new ClassWorld("plexus.core", cl);
|
||||
this.classWorld = ((ClassRealm) Thread.currentThread().getContextClassLoader()).getWorld();
|
||||
|
||||
container = container();
|
||||
|
||||
@@ -473,6 +472,7 @@ public class DaemonMavenCli {
|
||||
|
||||
List<File> extClassPath = Stream.of(
|
||||
Environment.MVND_EXT_CLASSPATH.asString().split(","))
|
||||
.filter(s -> s != null && !s.isEmpty())
|
||||
.map(File::new)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
@@ -99,7 +99,13 @@ public class Server implements AutoCloseable, Runnable {
|
||||
private final DaemonMemoryStatus memoryStatus;
|
||||
private final long keepAliveMs;
|
||||
|
||||
public Server() throws IOException {
|
||||
public static void main(String[] args) {
|
||||
try (Server server = new Server()) {
|
||||
server.run();
|
||||
}
|
||||
}
|
||||
|
||||
public Server() {
|
||||
// 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
|
||||
|
25
dist/src/main/distro/bin/mvnd-server.conf
vendored
Normal file
25
dist/src/main/distro/bin/mvnd-server.conf
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
main is org.mvndaemon.mvnd.daemon.Server from plexus.core
|
||||
|
||||
set maven.home default ${mvnd.home}
|
||||
set maven.conf default ${maven.home}/conf
|
||||
|
||||
[plexus.core]
|
||||
load ${maven.conf}/logging
|
||||
optionally ${maven.home}/lib/ext/*.jar
|
||||
load ${maven.home}/lib/*.jar
|
Reference in New Issue
Block a user