Skip to content

Commit

Permalink
Maven classloader
Browse files Browse the repository at this point in the history
This will allow us to test different versions of the client.

Also includes some extra methods to make it easier to work with the
bookkeeper client.

Master Issue: apache#903

Author: Ivan Kelly <[email protected]>
Author: Sijie Guo <[email protected]>

Reviewers: Enrico Olivelli <[email protected]>, Sijie Guo <[email protected]>

This closes apache#975 from ivankelly/maven-classloader
  • Loading branch information
ivankelly committed Jan 18, 2018
1 parent 9fca590 commit 733ce31
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 0 deletions.
28 changes: 28 additions & 0 deletions tests/integration-tests-utils/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<name>Apache BookKeeper :: Tests :: Utility module for Arquillian based integration tests</name>

<properties>
<shrinkwrap.version>3.0.1</shrinkwrap.version>
<arquillian-cube.version>1.13.0</arquillian-cube.version>
<commons-compress.version>1.15</commons-compress.version>
</properties>
Expand All @@ -45,6 +46,17 @@
<version>${commons-compress.version}</version>
</dependency>

<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-impl-maven</artifactId>
<version>${shrinkwrap.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-api</artifactId>
<version>${shrinkwrap.version}</version>
</dependency>

<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
Expand Down Expand Up @@ -81,4 +93,20 @@
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- forkCount=0 forces tests to run in isolated classloaders
which is required if want to test maven classloader without
test deps interfering //-->
<forkCount>0</forkCount>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/**
*
* 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.bookkeeper.tests;

import com.google.common.collect.Lists;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import org.jboss.shrinkwrap.resolver.api.maven.Maven;
import org.jboss.shrinkwrap.resolver.api.maven.ScopeType;
import org.jboss.shrinkwrap.resolver.api.maven.coordinate.MavenDependencies;
import org.jboss.shrinkwrap.resolver.api.maven.coordinate.MavenDependency;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MavenClassLoader implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(MavenClassLoader.class);

private MavenClassLoader(URLClassLoader cl) {
this.classloader = cl;
}

private final URLClassLoader classloader;

public static MavenClassLoader forArtifact(String mainArtifact) throws Exception {
Optional<String> slf4jVersion = Arrays.stream(Maven.resolver().resolve(mainArtifact)
.withTransitivity().asResolvedArtifact())
.filter((a) -> a.getCoordinate().getGroupId().equals("org.slf4j")
&& a.getCoordinate().getArtifactId().equals("slf4j-log4j12"))
.map((a) -> a.getCoordinate().getVersion())
.findFirst();

List<MavenDependency> deps = Lists.newArrayList(
MavenDependencies.createDependency(
mainArtifact, ScopeType.COMPILE, false,
MavenDependencies.createExclusion("org.slf4j:slf4j-log4j12"),
MavenDependencies.createExclusion("log4j:log4j")));
if (slf4jVersion.isPresent()) {
deps.add(MavenDependencies.createDependency("org.slf4j:slf4j-simple:" + slf4jVersion.get(),
ScopeType.COMPILE, false));
}

File[] files = Maven.resolver().addDependencies(deps.toArray(new MavenDependency[0]))
.resolve().withTransitivity().asFile();
URLClassLoader cl = AccessController.doPrivileged(
new PrivilegedAction<URLClassLoader>() {
@Override
public URLClassLoader run() {
return new URLClassLoader(Arrays.stream(files)
.map((f) -> {
try {
return f.toURI().toURL();
} catch (Throwable t) {
throw new RuntimeException(t);
}
})
.toArray(URL[]::new),
ClassLoader.getSystemClassLoader());
}
});
return new MavenClassLoader(cl);
}

public static MavenClassLoader forBookKeeperVersion(String version) throws Exception {
return forArtifact("org.apache.bookkeeper:bookkeeper-server:" + version);
}

public Object newInstance(String className, Object... args) throws Exception {
Class<?> klass = Class.forName(className, true, classloader);
return klass.getConstructor(Arrays.stream(args).map((a)-> a.getClass()).toArray(Class[]::new))
.newInstance(args);
}

public Object newBookKeeper(String zookeeper) throws Exception {
return newInstance("org.apache.bookkeeper.client.BookKeeper", zookeeper);
}

public Object digestType(String type) throws Exception {
String className = "org.apache.bookkeeper.client.BookKeeper$DigestType";
for (Object o : classloader.loadClass(className).getEnumConstants()) {
if (o.toString().equals(type)) {
return o;
}
}
throw new ClassNotFoundException("No such digest type " + type);
}

public void close() throws Exception {
classloader.close();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
*
* 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.bookkeeper.tests;

import org.junit.Assert;
import org.junit.Test;

public class MavenClassLoaderTest {
@Test(expected=ClassNotFoundException.class)
public void testLog4JReplacement() throws Exception {
MavenClassLoader.forBookKeeperVersion("4.0.0")
.newInstance("org.apache.log4j.Logger");
}

@Test
public void testNoZooKeeperInterference() throws Exception {
// Use KeeperException, because ZooKeeper needs a watcher which would be a pain to construct
Object o = MavenClassLoader.forBookKeeperVersion("4.0.0")
.newInstance("org.apache.zookeeper.KeeperException$NoNodeException");
Assert.assertFalse(o.getClass().equals(
org.apache.zookeeper.KeeperException.NoNodeException.class));
}

}

0 comments on commit 733ce31

Please sign in to comment.