Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#322, enable to control the exec:java interaction with JVM classloader more finely #337

Merged
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
1 change: 1 addition & 0 deletions src/it/projects/github322/invoker.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
invoker.goals = clean compile exec:java
43 changes: 43 additions & 0 deletions src/it/projects/github322/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<project>
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.codehaus.mojo.exec.it</groupId>
<artifactId>parent</artifactId>
<version>0.1</version>
</parent>

<groupId>org.cb.maven.plugins.exec</groupId>
<artifactId>github322</artifactId>
<version>0.1</version>

<dependencies>
<dependency>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.4.01</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>@pom.version@</version>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>org.codehaus.mojo.exec.it.github322.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.codehaus.mojo.exec.it.github322;

import javax.xml.transform.sax.SAXTransformerFactory;

public class Main {
public static void main(final String... args) {
System.out.println(
"Main Result: <" +
(
SAXTransformerFactory.class.getProtectionDomain().getCodeSource() != null ?
SAXTransformerFactory.class.getProtectionDomain().getCodeSource().getLocation() :
null
) +
">");
}
}
21 changes: 21 additions & 0 deletions src/it/projects/github322/verify.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* 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.
*/

File log = new File(basedir, 'build.log')
assert log.text.contains( 'Main Result: <null>')
22 changes: 20 additions & 2 deletions src/main/java/org/codehaus/mojo/exec/ExecJavaMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,23 @@ public class ExecJavaMojo extends AbstractExecMojo {
@Parameter
private List<String> classpathFilenameExclusions;

/**
* Additional packages to load from the jvm even if a classpath dependency matches.
*
* @since 3.5.0
*/
@Parameter
private List<String> forcedJvmPackages;

/**
* Additional packages to NOT load from the jvm even if it is in a flat classpath.
* Can enable to reproduce a webapp behavior for example where library is loaded over the JVM.
*
* @since 3.5.0
*/
@Parameter
private List<String> excludedJvmPackages;

/**
* Whether to try and prohibit the called Java program from terminating the JVM (and with it the whole Maven build)
* by calling {@link System#exit(int)}. When active, loaded classes will replace this call by a custom callback.
Expand Down Expand Up @@ -678,12 +695,13 @@ private URLClassLoader getClassLoader() throws MojoExecutionException {
this.addRelevantPluginDependenciesToClasspath(classpathURLs);
this.addRelevantProjectDependenciesToClasspath(classpathURLs);
this.addAdditionalClasspathElements(classpathURLs);

try {
final URLClassLoaderBuilder builder = URLClassLoaderBuilder.builder()
.setLogger(getLog())
.setPaths(classpathURLs)
.setExclusions(classpathFilenameExclusions);
.setExclusions(classpathFilenameExclusions)
.setForcedJvmPackages(forcedJvmPackages)
.setExcludedJvmPackages(excludedJvmPackages);
if (blockSystemExit) {
builder.setTransformer(new BlockExitTransformer());
}
Expand Down
150 changes: 69 additions & 81 deletions src/main/java/org/codehaus/mojo/exec/URLClassLoaderBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,13 @@
import static java.util.Arrays.asList;

/**
*
* @author Robert Scholte
* @since 3.0.0
*/
class URLClassLoaderBuilder {
private Log logger;
private List<String> forcedJvmPackages;
private List<String> excludedJvmPackages;
private Collection<Path> paths;
private Collection<String> exclusions;
private ClassFileTransformer transformer;
Expand All @@ -58,6 +59,16 @@ static URLClassLoaderBuilder builder() {
return new URLClassLoaderBuilder();
}

URLClassLoaderBuilder setExcludedJvmPackages(List<String> excludedJvmPackages) {
this.excludedJvmPackages = excludedJvmPackages;
return this;
}

URLClassLoaderBuilder setForcedJvmPackages(List<String> forcedJvmPackages) {
this.forcedJvmPackages = forcedJvmPackages;
return this;
}

public URLClassLoaderBuilder setTransformer(final ClassFileTransformer transformer) {
this.transformer = transformer;
return this;
Expand Down Expand Up @@ -96,7 +107,7 @@ URLClassLoader build() throws IOException {
}
}

return new ExecJavaClassLoader(urls.toArray(new URL[0]), transformer, logger);
return new ExecJavaClassLoader(urls.toArray(new URL[0]), transformer, forcedJvmPackages, excludedJvmPackages);
}

// child first strategy
Expand All @@ -110,14 +121,20 @@ private static class ExecJavaClassLoader extends URLClassLoader {
}

private final String jre;
private final Log logger;
private final ClassFileTransformer transformer;

public ExecJavaClassLoader(final URL[] urls, final ClassFileTransformer transformer, final Log logger) {
private final List<String> forcedJvmPackages;
private final List<String> excludedJvmPackages;

public ExecJavaClassLoader(
URL[] urls,
ClassFileTransformer transformer,
List<String> forcedJvmPackages,
List<String> excludedJvmPackages) {
super(urls);
this.jre = getJre();
this.logger = logger;
this.transformer = transformer;
this.forcedJvmPackages = forcedJvmPackages;
this.excludedJvmPackages = excludedJvmPackages;
}

@Override
Expand Down Expand Up @@ -307,130 +324,101 @@ private boolean postLoad(boolean resolve, Class<?> clazz) {
return false;
}

// not all jvm classes, for ex "javax" can be overriden so don't list it here
// not all jvm classes, for ex "javax" can be overridden so don't list it them all here (javax.resource for ex)
private boolean isDirectJvmClass(final String name) {
if (excludedJvmPackages != null && excludedJvmPackages.stream().anyMatch(name::startsWith)) {
return false;
}
if (name.startsWith("java.")) {
return true;
}
if (name.startsWith("sun.")) {
} else if (name.startsWith("javax.")) {
final String sub = name.substring("javax.".length());
if (sub.startsWith("xml.")) {
return true;
}
} else if (name.startsWith("sun.")) {
return true;
}
if (name.startsWith("jdk.")) {
} else if (name.startsWith("jdk.")) {
return true;
}
if (name.startsWith("oracle.")) {
} else if (name.startsWith("oracle.")) {
return true;
}
if (name.startsWith("javafx.")) {
} else if (name.startsWith("javafx.")) {
return true;
}
if (name.startsWith("netscape.")) {
} else if (name.startsWith("netscape.")) {
return true;
}
if (name.startsWith("org.")) {
} else if (name.startsWith("org.")) {
final String sub = name.substring("org.".length());
if (sub.startsWith("w3c.dom.")) {
return true;
}
if (sub.startsWith("omg.")) {
} else if (sub.startsWith("omg.")) {
return true;
}
if (sub.startsWith("xml.sax.")) {
} else if (sub.startsWith("xml.sax.")) {
return true;
}
if (sub.startsWith("ietf.jgss.")) {
} else if (sub.startsWith("ietf.jgss.")) {
return true;
}
if (sub.startsWith("jcp.xml.dsig.internal.")) {
} else if (sub.startsWith("jcp.xml.dsig.internal.")) {
return true;
}
}
if (name.startsWith("com.")) {
} else if (name.startsWith("com.")) {
final String sub = name.substring("com.".length());
if (sub.startsWith("oracle.")) {
return true;
}
if (sub.startsWith("sun.")) {
} else if (sub.startsWith("sun.")) {
final String subSun = sub.substring("sun.".length());
if (subSun.startsWith("accessibility.")) {
return true;
}
if (subSun.startsWith("activation.")) {
} else if (subSun.startsWith("activation.")) {
return true;
}
if (subSun.startsWith("awt.")) {
} else if (subSun.startsWith("awt.")) {
return true;
}
if (subSun.startsWith("beans.")) {
} else if (subSun.startsWith("beans.")) {
return true;
}
if (subSun.startsWith("corba.se.")) {
} else if (subSun.startsWith("corba.se.")) {
return true;
}
if (subSun.startsWith("demo.jvmti.")) {
} else if (subSun.startsWith("demo.jvmti.")) {
return true;
}
if (subSun.startsWith("image.codec.jpeg.")) {
} else if (subSun.startsWith("image.codec.jpeg.")) {
return true;
}
if (subSun.startsWith("imageio.")) {
} else if (subSun.startsWith("imageio.")) {
return true;
}
if (subSun.startsWith("istack.internal.")) {
} else if (subSun.startsWith("istack.internal.")) {
return true;
}
if (subSun.startsWith("java.")) {
} else if (subSun.startsWith("java.")) {
return true;
}
if (subSun.startsWith("java_cup.")) {
} else if (subSun.startsWith("java_cup.")) {
return true;
}
if (subSun.startsWith("jmx.")) {
} else if (subSun.startsWith("jmx.")) {
return true;
}
if (subSun.startsWith("jndi.")) {
} else if (subSun.startsWith("jndi.")) {
return true;
}
if (subSun.startsWith("management.")) {
} else if (subSun.startsWith("management.")) {
return true;
}
if (subSun.startsWith("media.sound.")) {
} else if (subSun.startsWith("media.sound.")) {
return true;
}
if (subSun.startsWith("naming.internal.")) {
} else if (subSun.startsWith("naming.internal.")) {
return true;
}
if (subSun.startsWith("net.")) {
} else if (subSun.startsWith("net.")) {
return true;
}
if (subSun.startsWith("nio.")) {
} else if (subSun.startsWith("nio.")) {
return true;
}
if (subSun.startsWith("org.")) {
} else if (subSun.startsWith("org.")) {
return true;
}
if (subSun.startsWith("rmi.rmid.")) {
} else if (subSun.startsWith("rmi.rmid.")) {
return true;
}
if (subSun.startsWith("rowset.")) {
} else if (subSun.startsWith("rowset.")) {
return true;
}
if (subSun.startsWith("security.")) {
} else if (subSun.startsWith("security.")) {
return true;
}
if (subSun.startsWith("swing.")) {
} else if (subSun.startsWith("swing.")) {
return true;
}
if (subSun.startsWith("tracing.")) {
} else if (subSun.startsWith("tracing.")) {
return true;
}
if (subSun.startsWith("xml.internal.")) {
} else if (subSun.startsWith("xml.internal.")) {
return true;
}
return false;
}
}
return false;
return forcedJvmPackages != null && forcedJvmPackages.stream().anyMatch(name::startsWith);
}

private class FilteringUrlEnum implements Enumeration<URL> {
Expand Down