| /* |
| * $Id$ |
| * |
| * Copyright (c) 2005 The Codehaus - http://groovy.codehaus.org |
| * |
| * 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 groovy.lang; |
| |
| import java.security.CodeSource |
| import org.codehaus.groovy.control.* |
| import org.codehaus.groovy.ast.* |
| import org.codehaus.groovy.classgen.* |
| |
| |
| public class GroovyClassLoaderTest extends GroovyTestCase { |
| |
| private final GroovyClassLoader classLoader = new GroovyClassLoader() |
| |
| private boolean contains(String[] paths, String eval) { |
| try { |
| eval = (new File(eval)).toURI().toURL().getFile(); |
| } catch (MalformedURLException e) { |
| return false; |
| } |
| for (it in paths) { |
| if(eval.equals(it)) return true; |
| } |
| return false; |
| } |
| |
| public void testAddsAClasspathEntryOnlyIfItHasNotAlreadyBeenAdded() { |
| String newClasspathEntry = "/tmp" |
| int initialNumberOfClasspathEntries = classLoader.getClassPath().length |
| |
| classLoader.addClasspath(newClasspathEntry) |
| assert initialNumberOfClasspathEntries + 1 == classLoader.getClassPath().length |
| assert contains(classLoader.getClassPath(),newClasspathEntry) |
| |
| classLoader.addClasspath(newClasspathEntry); |
| assert initialNumberOfClasspathEntries + 1 == classLoader.getClassPath().length |
| assert contains(classLoader.getClassPath(),newClasspathEntry) |
| } |
| |
| def getPaths(URLClassLoader ucl) { |
| def urls = ucl.getURLs() |
| return urls.findAll {!it.file.endsWith(".jar")} |
| } |
| |
| def getPaths(String path) { |
| int start = 0, end=0 |
| String sep = File.pathSeparator |
| def ret = [] |
| while (end<path.length()) { |
| start = end |
| end = path.indexOf(sep,end) |
| if (end==-1) break |
| def sub = path.substring(start,end) |
| if (!sub.endsWith(".jar")) { |
| ret << ((new File(sub)).toURL()) |
| } |
| end++ |
| } |
| return ret |
| } |
| |
| |
| public void testClassNotFoundIsNotHidden() { |
| def paths=[] |
| def loader = this.class.classLoader |
| while (loader!=null) { |
| if (loader instanceof URLClassLoader) { |
| paths += getPaths(loader) |
| } |
| loader = loader.parent |
| } |
| paths += getPaths(System.getProperty("java.class.path")) |
| paths=paths.unique() |
| |
| def file = File.createTempFile("Foo",".groovy") |
| def name = file.name-".groovy" |
| def script = """ |
| class $name extends GroovyTestCase{} |
| """ |
| file << script |
| paths << file.parentFile.toURL() |
| def cl = new URLClassLoader(paths as URL[],null) |
| def gcl = new GroovyClassLoader(cl) |
| try { |
| gcl.loadClass(name) |
| assert false |
| } catch (NoClassDefFoundError ncdfe) { |
| // TODO: hack for running when under coverage - find a better way |
| assert ncdfe.message.indexOf("TestCase")>0 || ncdfe.message.indexOf("cobertura")>0 |
| } |
| } |
| |
| public void testClassPathNotDerived() { |
| def config = new CompilerConfiguration() |
| def loader1 = new GroovyClassLoader(null,config) |
| config = new CompilerConfiguration() |
| config.setClasspath("foo") |
| def loader2 = new GroovyClassLoader(loader1,config) |
| config = new CompilerConfiguration() |
| def loader3 = new GroovyClassLoader(loader2,config) |
| def urls = loader1.URLs |
| assert urls.length == 0 |
| urls = loader2.URLs |
| assert urls.length == 1 |
| assert urls[0].toString().endsWith("foo") |
| urls = loader3.URLs |
| assert urls.length == 0 |
| } |
| |
| public void testMultithreading() { |
| def config = new CompilerConfiguration() |
| config.recompileGroovySource = true; |
| |
| def loader = new GroovyClassLoaderTestCustomGCL(config) |
| |
| def ts = new Thread[100] |
| for (i in 0..<100) { |
| ts[i] = Thread.start { |
| if (i%2==1) sleep(100) |
| assert GroovyClassLoaderTestFoo1==loader.loadClass("Foox") |
| } |
| } |
| sleep(100) |
| for (i in 0..<100) {ts[i].join()} |
| |
| assert GroovyClassLoaderTestFoo2==loader.loadClass("Foox") |
| } |
| |
| public void testAdditionalPhaseOperation(){ |
| def loader = new GroovyClassLoaderTestCustomPhaseOperation() |
| def ret = loader.parseClass("""class Foo{}""") |
| def field = ret.declaredFields.find {it.name=="id" && it.type==Long.TYPE} |
| assert field != null |
| } |
| } |
| |
| class GroovyClassLoaderTestFoo1{} |
| class GroovyClassLoaderTestFoo2{} |
| |
| class GroovyClassLoaderTestCustomGCL extends GroovyClassLoader{ |
| def GroovyClassLoaderTestCustomGCL(config) { |
| super(null,config); |
| } |
| def counter = 0 |
| protected Class recompile(URL source, String name, Class oldClass) { |
| if (name=="Foox") { |
| if (counter<100) { |
| counter++ |
| return GroovyClassLoaderTestFoo1 |
| } else { |
| return GroovyClassLoaderTestFoo2 |
| } |
| } |
| return super.recompile(source,name,oldClass) |
| } |
| |
| protected boolean isSourceNewer(URL source, Class cls) { |
| return true |
| } |
| } |
| |
| class GroovyClassLoaderTestPropertyAdder extends CompilationUnit.PrimaryClassNodeOperation { |
| void call(SourceUnit source, GeneratorContext context, ClassNode classNode) { |
| classNode.addProperty("id", ClassNode.ACC_PUBLIC, ClassHelper.long_TYPE,null,null,null); |
| } |
| } |
| |
| class GroovyClassLoaderTestCustomPhaseOperation extends GroovyClassLoader { |
| CompilationUnit createCompilationUnit(CompilerConfiguration config, CodeSource source) { |
| def cu = super.createCompilationUnit(config,source) |
| cu.addPhaseOperation(new GroovyClassLoaderTestPropertyAdder(),Phases.CONVERSION) |
| return cu |
| } |
| } |