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

[NO_MERGE] [JENKINS-54905] - Experimental branch for Java 11 support #41

Closed
wants to merge 5 commits into from
Closed
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

@@ -0,0 +1,4 @@
Dockerfile
**/target
demo
test
@@ -1,7 +1,7 @@
ARG JENKINS_VERSION=2.121.1
ARG JENKINS_VERSION=jdk11

This comment has been minimized.

Copy link
@batmat

batmat Nov 30, 2018

Member

Do you really intend to modify JFR's master branch with using JDK11 as default? Or maybe we don't care because packagers are always expected to pass this ARG?


# Define maven version for other stages
FROM maven:3.5.2 as maven
FROM maven:3.6.0 as maven

FROM maven as jenkinsfilerunner-mvncache
ADD pom.xml /src/pom.xml
@@ -23,9 +23,23 @@ RUN cd /jenkinsfile-runner && mvn package

FROM jenkins/jenkins:${JENKINS_VERSION}
USER root

# Libs required to run on Java 11, they come from the base image
ENV JAVA_LIB_DIR /usr/share/jenkins/ref/java_cp

# TODO: java.sql does not help
# 0.555 [id=1] SEVERE jenkins.model.Jenkins#<clinit>: Failed to load Jenkins.class
# java.lang.NoClassDefFoundError: java.sql.Date
# at org.apache.commons.beanutils.ConvertUtilsBean.class$(ConvertUtilsBean.java:157)
ENV JAVA_MODULES "java.xml.bind,java.activation,java.sql"

#TODO: support overrides by the user
ENV JAVA_OPTS "-p ${JAVA_LIB_DIR}/jaxb-api.jar:${JAVA_LIB_DIR}/javax.activation.jar --add-modules ${JAVA_MODULES} -cp ${JAVA_LIB_DIR}/jaxb-impl.jar:${JAVA_LIB_DIR}/jaxb-core.jar"

RUN mkdir /app && unzip /usr/share/jenkins/jenkins.war -d /app/jenkins
COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt

COPY --from=jenkinsfilerunner-build /jenkinsfile-runner/app/target/appassembler /app

ENTRYPOINT ["/app/bin/jenkinsfile-runner", \
@@ -21,4 +21,5 @@ build: .build/cwp-cli-${CWP_VERSION}.jar

run:
docker run --rm -v $(shell pwd)/Jenkinsfile:/workspace/Jenkinsfile \
-e JAVA_OPTS="--add-modules java.sql" \
jenkins-experimental/jenkinsfile-runner-demo
@@ -14,14 +14,14 @@ buildSettings:
source:
dir: ../..
docker:
base: "jenkins/jenkins:2.138.2"
base: "jenkins/jenkins-experimental:latest-jdk11"

This comment has been minimized.

Copy link
@batmat

batmat Nov 30, 2018

Member

Don't you want to use jenkins/jenkins now we got the official JDK 11 support there, like you did above?

This comment has been minimized.

Copy link
@oleg-nenashev

oleg-nenashev Nov 30, 2018

Author Member

agreed

tag: "jenkins-experimental/jenkinsfile-runner-demo"
build: true
war:
groupId: "org.jenkins-ci.main"
artifactId: "jenkins-war"
source:
version: "2.138.2"
version: "2.149"
plugins:
- groupId: "org.jenkins-ci.plugins.workflow"
artifactId: "workflow-job"
@@ -1 +1,2 @@
pipeline-model-definition:latest
workflow-support:incrementals;org.jenkins-ci.plugins.workflow;2.21-rc591.43d37d4d080a

This comment has been minimized.

Copy link
@batmat

batmat Nov 30, 2018

Member

Might make sense to bump to 2.23-rc674.73bb98187744 for clarity and consistency with the one we ended up releasing and use on Evergreen: https://github.com/jenkins-infra/evergreen/blob/36a60c268be9529c0f5c019b9ac1b0f192b3032a/services/essentials.yaml#L171

@@ -1,6 +1,8 @@
package io.jenkins.jenkinsfile.runner;

import com.sun.org.apache.bcel.internal.util.ClassLoader;
import hudson.security.ACL;
import io.jenkins.jenkinsfile.runner.util.JoinClassLoader;
import jenkins.slaves.DeprecatedAgentProtocolMonitor;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.security.LoginService;
@@ -14,6 +16,7 @@

import javax.servlet.ServletContext;
import java.io.File;
import java.net.URLClassLoader;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
@@ -37,6 +40,11 @@ public JenkinsfileRunnerRule(File warDir, File pluginsDir) {
this.pluginsDir = pluginsDir;
}

private static boolean isPostJava8() {
String javaVersion = System.getProperty("java.version");
return !javaVersion.startsWith("1.");
}

/**
* Sets up Jetty without any actual TCP port serving HTTP.
*/
@@ -46,7 +54,16 @@ protected ServletContext createWebServer() throws Exception {
server = new Server(queuedThreadPool);

WebAppContext context = new WebAppContext(warDir.getPath(), contextPath);
context.setClassLoader(getClass().getClassLoader());
String javaVersion = System.getProperty("java.version");

This comment has been minimized.

Copy link
@batmat

batmat Nov 30, 2018

Member

unused, I guess leftover from the new isPostJava8() method introduced above.


// if (javaVersion.startsWith("1.")) {

This comment has been minimized.

Copy link
@batmat

batmat Nov 30, 2018

Member

Let's remove the commented out code?

Also, if you mean to keep it, then I guess you'd use isPostJava8()

// context.setClassLoader(getClass().getClassLoader());
// } else {
ClassLoader platform = (ClassLoader) ClassLoader.class.getMethod("getPlatformClassLoader").invoke(null);

This comment has been minimized.

Copy link
@batmat

batmat Nov 30, 2018

Member

Can we have a comment explaining the intent a bit here?

This comment has been minimized.

Copy link
@varyvol

varyvol Jan 3, 2019

Contributor

Yes please!

This comment has been minimized.

Copy link
@fcojfernandez

fcojfernandez Jan 3, 2019

Contributor

IIUC, the goal here is get exactly the same classloader as in previous JDK versions. Since this piece of code is executed always and not only with java11, what will happen if this code is executed with java8? The getPlatformClassLoader is only available from java9 (if I'm not wrong), so it will throw an exception

java.lang.ClassLoader cl = new JoinClassLoader(getClass().getClassLoader(), platform);
context.setClassLoader(cl);
// }

context.setConfigurations(new Configuration[]{new WebXmlConfiguration()});
context.addBean(new NoListenerConfiguration(context));
server.setHandler(context);
@@ -0,0 +1,90 @@
package io.jenkins.jenkinsfile.runner.util;// Copyright 2010 Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland
// www.source-code.biz, www.inventec.ch/chdh
//
// This module is multi-licensed and may be used under the terms
// of any of the following licenses:
//
// LGPL, GNU Lesser General Public License, V2 or later, http://www.gnu.org/licenses/lgpl.html

This comment has been minimized.

Copy link
@oleg-nenashev

oleg-nenashev Nov 30, 2018

Author Member

Note that this code is not compatible w.r.t the license. I put it here only for the experiment (which does not work so far), and it should not be merged as is

// AL, Apache License, V2.0 or later, http://www.apache.org/licenses
//
// Please contact the author if you need another license.
// This module is provided "as is", without warranties of any kind.

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.ByteBuffer;
import java.security.SecureClassLoader;
import java.util.Enumeration;
import java.util.Vector;

/**
* A class loader that combines multiple class loaders into one.<br>
* The classes loaded by this class loader are associated with this class loader,
* i.e. Class.getClassLoader() points to this class loader.
*/
public class JoinClassLoader extends ClassLoader {

private ClassLoader[] delegateClassLoaders;

public JoinClassLoader (ClassLoader parent, ClassLoader... delegateClassLoaders) {
super(parent);
this.delegateClassLoaders = delegateClassLoaders; }

protected Class<?> findClass (String name) throws ClassNotFoundException {
// It would be easier to call the loadClass() methods of the delegateClassLoaders
// here, but we have to load the class from the byte code ourselves, because we
// need it to be associated with our class loader.
String path = name.replace('.', '/') + ".class";
URL url = findResource(path);
if (url == null) {
throw new ClassNotFoundException(name); }
ByteBuffer byteCode;
try {
byteCode = loadResource(url); }
catch (IOException e) {
throw new ClassNotFoundException(name, e); }
return defineClass(name, byteCode, null); }

private ByteBuffer loadResource (URL url) throws IOException {
InputStream stream = null;
try {
stream = url.openStream();
int initialBufferCapacity = Math.min(0x40000, stream.available() + 1);
if (initialBufferCapacity <= 2) {
initialBufferCapacity = 0x10000; }
else {
initialBufferCapacity = Math.max(initialBufferCapacity, 0x200); }
ByteBuffer buf = ByteBuffer.allocate(initialBufferCapacity);
while (true) {
if (!buf.hasRemaining()) {
ByteBuffer newBuf = ByteBuffer.allocate(2*buf.capacity());
buf.flip();
newBuf.put(buf);
buf = newBuf; }
int len = stream.read(buf.array(), buf.position(), buf.remaining());
if (len <= 0) {
break; }
buf.position(buf.position()+len); }
buf.flip();
return buf; }
finally {
if (stream != null) {
stream.close(); }}}

protected URL findResource (String name) {
for (ClassLoader delegate : delegateClassLoaders) {
URL resource = delegate.getResource(name);
if (resource != null) {
return resource; }}
return null; }

protected Enumeration<URL> findResources (String name) throws IOException {
Vector<URL> vector = new Vector<URL>();
for (ClassLoader delegate : delegateClassLoaders) {
Enumeration<URL> enumeration = delegate.getResources(name);
while (enumeration.hasMoreElements()) {
vector.add(enumeration.nextElement()); }}
return vector.elements(); }

}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.