/*
* 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.twill.internal.utils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.io.ByteStreams;
import com.google.common.io.Files;
import org.apache.twill.filesystem.LocalLocationFactory;
import org.apache.twill.filesystem.Location;
import org.apache.twill.internal.ApplicationBundler;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
/**
*
*/
public class ApplicationBundlerTest {
@Rule
public TemporaryFolder tmpDir = new TemporaryFolder();
@Test
public void testFindDependencies() throws IOException, ClassNotFoundException {
Location location = new LocalLocationFactory(tmpDir.newFolder()).create("test.jar");
// Create a jar file with by tracing dependency
ApplicationBundler bundler = new ApplicationBundler(ImmutableList.<String>of());
bundler.createBundle(location, ApplicationBundler.class);
File targetDir = tmpDir.newFolder();
unjar(new File(location.toURI()), targetDir);
// Load the class back, it should be loaded by the custom classloader
ClassLoader classLoader = createClassLoader(targetDir);
Class<?> clz = classLoader.loadClass(ApplicationBundler.class.getName());
Assert.assertSame(classLoader, clz.getClassLoader());
// For system classes, they shouldn't be packaged, hence loaded by different classloader.
clz = classLoader.loadClass(Object.class.getName());
Assert.assertNotSame(classLoader, clz.getClassLoader());
}
private void unjar(File jarFile, File targetDir) throws IOException {
JarInputStream jarInput = new JarInputStream(new FileInputStream(jarFile));
try {
JarEntry jarEntry = jarInput.getNextJarEntry();
while (jarEntry != null) {
File target = new File(targetDir, jarEntry.getName());
if (jarEntry.isDirectory()) {
target.mkdirs();
} else {
target.getParentFile().mkdirs();
ByteStreams.copy(jarInput, Files.newOutputStreamSupplier(target));
}
jarEntry = jarInput.getNextJarEntry();
}
} finally {
jarInput.close();
}
}
private ClassLoader createClassLoader(File dir) throws MalformedURLException {
List<URL> urls = Lists.newArrayList();
urls.add(new File(dir, "classes").toURI().toURL());
File[] libFiles = new File(dir, "lib").listFiles();
if (libFiles != null) {
for (File file : libFiles) {
urls.add(file.toURI().toURL());
}
}
return new URLClassLoader(urls.toArray(new URL[0])) {
@Override
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
// Load class from the given URLs first before delegating to parent.
try {
return super.findClass(name);
} catch (ClassNotFoundException e) {
ClassLoader parent = getParent();
return parent == null ? ClassLoader.getSystemClassLoader().loadClass(name) : parent.loadClass(name);
}
}
};
}
}