/*
* Copyright 2013 eXo Platform SAS
*
* Licensed 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 juzu.impl.common;
import japa.parser.ast.type.ClassOrInterfaceType;
import juzu.test.AbstractTestCase;
import juzu.test.CompilerAssert;
import juzu.test.JavaFile;
import org.junit.Test;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.ParameterizedType;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
/** @author Julien Viet */
public class LiveClassLoaderTestCase extends AbstractTestCase {
private class Context {
/** . */
final String name;
/** . */
CompilerAssert<File, File> compilerAssert1;
/** . */
CompilerAssert<File, File> compilerAssert2;
/** . */
URLClassLoader parent;
/** . */
LiveClassLoader local;
private Context(String name) {
this.name = name;
this.compilerAssert1 = compiler(name);
this.compilerAssert2 = compiler(name);
this.parent = null;
this.local = null;
}
void aExtends(String name, String type) {
JavaFile<?> file = compilerAssert2.assertJavaSource("common.live." + name + ".A");
file.assertDeclaration().setExtends(Arrays.asList(new ClassOrInterfaceType(type)));
file.assertSave();
}
void init() {
if (local == null)
try {
compilerAssert1.assertCompile();
compilerAssert2.assertCompile();
parent = new URLClassLoader(new URL[]{compilerAssert1.getClassOutput().getURL()});
local = new LiveClassLoader(new URL[]{compilerAssert2.getClassOutput().getURL()}, parent);
}
catch (IOException e) {
throw failure(e);
}
}
Class<?> assertLoadedBy(ClassLoader expectedLoader, String name) {
try {
Class<?> clazz = local.loadClass(name);
assertSame(expectedLoader, clazz.getClassLoader());
return clazz;
}
catch (ClassNotFoundException e) {
throw failure(e);
}
}
Class<?> assertLoadedByParent(String name) {
return assertLoadedBy(parent, name);
}
Class<?> assertLoadedLocally(String name) {
return assertLoadedBy(local, name);
}
}
@Test
public void testNotModified() throws Exception {
Context ctx = new Context("common.live.notmodified");
ctx.init();
//
Class<?> a = ctx.assertLoadedByParent("common.live.notmodified.A");
}
@Test
public void testModified() throws Exception {
Context ctx = new Context("common.live.modified");
JavaFile<?> file = ctx.compilerAssert2.assertJavaSource("common.live.modified.A");
file.assertDeclaration().setExtends(Arrays.asList(new ClassOrInterfaceType("java.util.Date")));
file.assertSave();
ctx.init();
//
Class<?> a = ctx.assertLoadedLocally("common.live.modified.A");
}
@Test
public void testDependsOnModified() throws Exception {
Context ctx = new Context("common.live.dependsonmodified");
JavaFile<?> file = ctx.compilerAssert2.assertJavaSource("common.live.dependsonmodified.B");
file.assertDeclaration().setExtends(Arrays.asList(new ClassOrInterfaceType("java.util.Date")));
file.assertSave();
ctx.init();
//
Class<?> d = ctx.assertLoadedLocally("common.live.dependsonmodified.D");
Class<?> c = ctx.assertLoadedLocally("common.live.dependsonmodified.C");
Class<?> b = ctx.assertLoadedLocally("common.live.dependsonmodified.B");
Class<?> a = ctx.assertLoadedByParent("common.live.dependsonmodified.A");
//
assertSame(a, b.getDeclaredField("ref").getType());
assertSame(b, c.getDeclaredField("ref").getType());
assertSame(c, d.getDeclaredField("ref").getType());
}
@Test
public void testCircularNonModified() throws Exception {
Context ctx = new Context("common.live.circular");
ctx.init();
//
Class<?> b = ctx.assertLoadedByParent("common.live.circular.B");
Class<?> a = ctx.assertLoadedByParent("common.live.circular.A");
//
assertSame(b, a.getDeclaredField("ref").getType());
assertSame(a, b.getDeclaredField("ref").getType());
}
@Test
public void testCircular() throws Exception {
Context ctx = new Context("common.live.circular");
ctx.aExtends("circular", "java.util.Date");
ctx.init();
//
Class<?> b = ctx.assertLoadedLocally("common.live.circular.B");
Class<?> a = ctx.assertLoadedLocally("common.live.circular.A");
//
assertSame(b, a.getDeclaredField("ref").getType());
assertSame(a, b.getDeclaredField("ref").getType());
}
@Test
public void testNotFound() {
LiveClassLoader loader = new LiveClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
try {
loader.loadClass("foo.bar");
fail();
}
catch (ClassNotFoundException ok) {
}
}
@Test
public void testFoundLocally() throws Exception {
Context ctx = new Context("common.live.foundlocally");
ctx.compilerAssert1.assertJavaSource("common.live.foundlocally.B").assertRemove();
ctx.init();
//
Class<?> b = ctx.assertLoadedLocally("common.live.foundlocally.B");
Class<?> a = ctx.assertLoadedByParent("common.live.foundlocally.A");
//
assertSame(a, b.getDeclaredField("ref").getType());
}
@Test
public void testMethodReturnTypeModified() throws Exception {
Context ctx = new Context("common.live.methodreturntypemodified");
ctx.aExtends("methodreturntypemodified", "java.util.Date");
ctx.init();
//
Class<?> a = ctx.assertLoadedLocally("common.live.methodreturntypemodified.A");
Class<?> b = ctx.assertLoadedLocally("common.live.methodreturntypemodified.B");
//
assertSame(a, b.getDeclaredMethod("m").getReturnType());
}
@Test
public void testMethodParameterTypeModified() throws Exception {
Context ctx = new Context("common.live.methodparametertypemodified");
ctx.aExtends("methodparametertypemodified", "java.util.Date");
ctx.init();
//
Class<?> a = ctx.assertLoadedLocally("common.live.methodparametertypemodified.A");
Class<?> b = ctx.assertLoadedLocally("common.live.methodparametertypemodified.B");
//
assertSame(a, b.getDeclaredMethods()[0].getParameterTypes()[0]);
}
@Test
public void testConstructorParameterTypeModified() throws Exception {
Context ctx = new Context("common.live.constructorparametertypemodified");
ctx.aExtends("constructorparametertypemodified", "java.util.Date");
ctx.init();
//
Class<?> a = ctx.assertLoadedLocally("common.live.constructorparametertypemodified.A");
Class<?> b = ctx.assertLoadedLocally("common.live.constructorparametertypemodified.B");
//
assertSame(a, b.getDeclaredConstructors()[0].getParameterTypes()[0]);
}
@Test
public void testSuperClassModified() throws Exception {
Context ctx = new Context("common.live.superclassmodified");
ctx.aExtends("superclassmodified", "java.util.Date");
ctx.init();
//
Class<?> a = ctx.assertLoadedLocally("common.live.superclassmodified.A");
Class<?> b = ctx.assertLoadedLocally("common.live.superclassmodified.B");
//
assertSame(a, b.getSuperclass());
}
@Test
public void testImplementedIntefaceModified() throws Exception {
Context ctx = new Context("common.live.implementedinterfacemodified");
ctx.aExtends("implementedinterfacemodified", "java.io.Serializable");
ctx.init();
//
Class<?> a = ctx.assertLoadedLocally("common.live.implementedinterfacemodified.A");
Class<?> b = ctx.assertLoadedLocally("common.live.implementedinterfacemodified.B");
//
assertSame(a, b.getInterfaces()[0]);
}
@Test
public void testSuperIntefaceModified() throws Exception {
Context ctx = new Context("common.live.superinterfacemodified");
ctx.aExtends("superinterfacemodified", "java.io.Serializable");
ctx.init();
//
Class<?> a = ctx.assertLoadedLocally("common.live.superinterfacemodified.A");
Class<?> b = ctx.assertLoadedLocally("common.live.superinterfacemodified.B");
//
assertSame(a, b.getInterfaces()[0]);
}
@Test
public void testSuperTypeParameterModified1() throws Exception {
Context ctx = new Context("common.live.supertypeparametermodified1");
ctx.aExtends("supertypeparametermodified1", "java.util.Date");
ctx.init();
//
Class<?> a = ctx.assertLoadedLocally("common.live.supertypeparametermodified1.A");
Class<?> b = ctx.assertLoadedLocally("common.live.supertypeparametermodified1.B");
//
assertSame(a, ((ParameterizedType)b.getGenericSuperclass()).getActualTypeArguments()[0]);
}
@Test
public void testSuperTypeParameterModified2() throws Exception {
Context ctx = new Context("common.live.supertypeparametermodified2");
ctx.aExtends("supertypeparametermodified2", "java.util.Date");
ctx.init();
//
Class<?> a = ctx.assertLoadedLocally("common.live.supertypeparametermodified2.A");
Class<?> b = ctx.assertLoadedLocally("common.live.supertypeparametermodified2.B");
//
assertSame(a, ((ParameterizedType)((ParameterizedType)b.getGenericSuperclass()).getActualTypeArguments()[0]).getActualTypeArguments()[0]);
}
@Test
public void testSuperInterfaceParameterModified1() throws Exception {
Context ctx = new Context("common.live.superinterfaceparametermodified1");
ctx.aExtends("superinterfaceparametermodified1", "java.io.Serializable");
ctx.init();
//
Class<?> a = ctx.assertLoadedLocally("common.live.superinterfaceparametermodified1.A");
Class<?> b = ctx.assertLoadedLocally("common.live.superinterfaceparametermodified1.B");
//
assertSame(a, ((ParameterizedType)b.getGenericInterfaces()[0]).getActualTypeArguments()[0]);
}
@Test
public void testMethodGenericParameterTypeModified1() throws Exception {
Context ctx = new Context("common.live.methodgenericparametertypemodified1");
ctx.aExtends("methodgenericparametertypemodified1", "java.util.Date");
ctx.init();
//
Class<?> a = ctx.assertLoadedLocally("common.live.methodgenericparametertypemodified1.A");
Class<?> b = ctx.assertLoadedLocally("common.live.methodgenericparametertypemodified1.B");
//
// assertSame(a, ((ParameterizedType)b.getGenericInterfaces()[0]).getActualTypeArguments()[0]);
}
@Test
public void testMethodGenericParameterTypeModified2() throws Exception {
Context ctx = new Context("common.live.methodgenericparametertypemodified2");
ctx.aExtends("methodgenericparametertypemodified2", "java.util.Date");
ctx.init();
//
Class<?> a = ctx.assertLoadedLocally("common.live.methodgenericparametertypemodified2.A");
Class<?> b = ctx.assertLoadedLocally("common.live.methodgenericparametertypemodified2.B");
//
// assertSame(a, ((ParameterizedType)b.getGenericInterfaces()[0]).getActualTypeArguments()[0]);
}
@Test
public void testMethodGenericParameterTypeModified3() throws Exception {
Context ctx = new Context("common.live.methodgenericparametertypemodified3");
ctx.aExtends("methodgenericparametertypemodified3", "java.util.Date");
ctx.init();
//
Class<?> a = ctx.assertLoadedLocally("common.live.methodgenericparametertypemodified3.A");
Class<?> b = ctx.assertLoadedLocally("common.live.methodgenericparametertypemodified3.B");
//
// assertSame(a, ((ParameterizedType)b.getGenericInterfaces()[0]).getActualTypeArguments()[0]);
}
@Test
public void testMethodGenericReturnTypeModified1() throws Exception {
Context ctx = new Context("common.live.methodgenericreturntypemodified1");
ctx.aExtends("methodgenericreturntypemodified1", "java.util.Date");
ctx.init();
//
Class<?> a = ctx.assertLoadedLocally("common.live.methodgenericreturntypemodified1.A");
Class<?> b = ctx.assertLoadedLocally("common.live.methodgenericreturntypemodified1.B");
//
// assertSame(a, ((ParameterizedType)b.getGenericInterfaces()[0]).getActualTypeArguments()[0]);
}
@Test
public void testConstructorGenericParameterTypeModified1() throws Exception {
Context ctx = new Context("common.live.constructorgenericparametertypemodified1");
ctx.aExtends("constructorgenericparametertypemodified1", "java.util.Date");
ctx.init();
//
Class<?> a = ctx.assertLoadedLocally("common.live.constructorgenericparametertypemodified1.A");
Class<?> b = ctx.assertLoadedLocally("common.live.constructorgenericparametertypemodified1.B");
//
// assertSame(a, ((ParameterizedType)b.getGenericInterfaces()[0]).getActualTypeArguments()[0]);
}
@Test
public void testFieldGenericTypeModified1() throws Exception {
Context ctx = new Context("common.live.fieldgenerictypemodified1");
ctx.aExtends("fieldgenerictypemodified1", "java.util.Date");
ctx.init();
//
Class<?> a = ctx.assertLoadedLocally("common.live.fieldgenerictypemodified1.A");
Class<?> b = ctx.assertLoadedLocally("common.live.fieldgenerictypemodified1.B");
//
// assertSame(a, ((ParameterizedType)b.getGenericInterfaces()[0]).getActualTypeArguments()[0]);
}
@Test
public void testResource() throws IOException {
Context ctx = new Context("common.live.resource");
ctx.init();
//
assertEquals("bar", Tools.read(ctx.local.getResource("common/live/resource/foo.txt")));
//
File dir = new File(ctx.compilerAssert2.getClassOutput().getRoot(), "common/live/resource");
assertTrue(dir.mkdirs());
File f = new File(dir, "foo.txt");
new FileWriter(f).append("bar_").close();
assertEquals("bar_", Tools.read(ctx.local.getResource("common/live/resource/foo.txt")));
}
}