org.gradle.api.internal.project.antbuilder.DefaultIsolatedAntBuilder Maven / Gradle / Ivy
/*
* Copyright 2015 the original author or authors.
*
* 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 org.gradle.api.internal.project.antbuilder;
import com.google.common.collect.Lists;
import groovy.lang.Closure;
import org.gradle.api.Action;
import org.gradle.api.JavaVersion;
import org.gradle.api.internal.ClassPathRegistry;
import org.gradle.api.internal.ClosureBackedAction;
import org.gradle.api.internal.classloading.GroovySystemLoader;
import org.gradle.api.internal.classloading.GroovySystemLoaderFactory;
import org.gradle.api.internal.classpath.ModuleRegistry;
import org.gradle.api.internal.project.IsolatedAntBuilder;
import org.gradle.api.logging.LogLevel;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.internal.Factory;
import org.gradle.internal.UncheckedException;
import org.gradle.internal.classloader.CachingClassLoader;
import org.gradle.internal.classloader.ClassLoaderFactory;
import org.gradle.internal.classloader.FilteringClassLoader;
import org.gradle.internal.classloader.MultiParentClassLoader;
import org.gradle.internal.classloader.MutableURLClassLoader;
import org.gradle.internal.classpath.ClassPath;
import org.gradle.internal.classpath.DefaultClassPath;
import org.gradle.internal.concurrent.Stoppable;
import org.gradle.internal.jvm.Jvm;
import java.io.File;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Vector;
public class DefaultIsolatedAntBuilder implements IsolatedAntBuilder, Stoppable {
private final static Logger LOG = Logging.getLogger(DefaultIsolatedAntBuilder.class);
private final ClassLoader antLoader;
private final ClassLoader baseAntLoader;
private final ClassPath libClasspath;
private final ClassLoader antAdapterLoader;
private final ClassPathRegistry classPathRegistry;
private final ClassLoaderFactory classLoaderFactory;
private final ModuleRegistry moduleRegistry;
private final ClassPathToClassLoaderCache classLoaderCache;
private final GroovySystemLoader gradleApiGroovyLoader;
private final GroovySystemLoader antAdapterGroovyLoader;
public DefaultIsolatedAntBuilder(ClassPathRegistry classPathRegistry, ClassLoaderFactory classLoaderFactory, ModuleRegistry moduleRegistry) {
this.classPathRegistry = classPathRegistry;
this.classLoaderFactory = classLoaderFactory;
this.moduleRegistry = moduleRegistry;
this.libClasspath = new DefaultClassPath();
GroovySystemLoaderFactory groovySystemLoaderFactory = new GroovySystemLoaderFactory();
this.classLoaderCache = new ClassPathToClassLoaderCache(groovySystemLoaderFactory);
List antClasspath = Lists.newArrayList(classPathRegistry.getClassPath("ANT").getAsFiles());
// Need tools.jar for compile tasks
File toolsJar = Jvm.current().getToolsJar();
if (toolsJar != null) {
antClasspath.add(toolsJar);
}
/**
* Mix in an XML parser implementation when running on Java 6 and another XML parser is present on the system ClassLoader, to work around a bug in older implementations of JAXP
* @see org.gradle.internal.classloader.DefaultClassLoaderFactory#createFilteringClassLoader(ClassLoader)
*/
if (needJaxpHackery()) {
antClasspath.addAll(moduleRegistry.getExternalModule("xercesImpl").getImplementationClasspath().getAsFiles());
}
antLoader = classLoaderFactory.createIsolatedClassLoader(new DefaultClassPath(antClasspath));
FilteringClassLoader loggingLoader = new FilteringClassLoader(getClass().getClassLoader());
loggingLoader.allowPackage("org.slf4j");
loggingLoader.allowPackage("org.apache.commons.logging");
loggingLoader.allowPackage("org.apache.log4j");
loggingLoader.allowClass(Logger.class);
loggingLoader.allowClass(LogLevel.class);
this.baseAntLoader = new CachingClassLoader(new MultiParentClassLoader(antLoader, loggingLoader));
// Need gradle core to pick up ant logging adapter, AntBuilder and such
ClassPath gradleCoreUrls = moduleRegistry.getModule("gradle-core").getImplementationClasspath();
gradleCoreUrls = gradleCoreUrls.plus(moduleRegistry.getModule("gradle-logging").getImplementationClasspath());
gradleCoreUrls = gradleCoreUrls.plus(moduleRegistry.getExternalModule("groovy-all").getClasspath());
// Need Transformer (part of AntBuilder API) from base services
gradleCoreUrls = gradleCoreUrls.plus(moduleRegistry.getModule("gradle-base-services").getImplementationClasspath());
this.antAdapterLoader = new MutableURLClassLoader(baseAntLoader, gradleCoreUrls);
gradleApiGroovyLoader = groovySystemLoaderFactory.forClassLoader(this.getClass().getClassLoader());
antAdapterGroovyLoader = groovySystemLoaderFactory.forClassLoader(antAdapterLoader);
}
private boolean needJaxpHackery() {
return !JavaVersion.current().isJava7Compatible() && ClassLoader.getSystemResource("META-INF/services/javax.xml.parsers.SAXParserFactory") != null;
}
protected DefaultIsolatedAntBuilder(DefaultIsolatedAntBuilder copy, Iterable libClasspath) {
this.classPathRegistry = copy.classPathRegistry;
this.classLoaderFactory = copy.classLoaderFactory;
this.moduleRegistry = copy.moduleRegistry;
this.antLoader = copy.antLoader;
this.baseAntLoader = copy.baseAntLoader;
this.antAdapterLoader = copy.antAdapterLoader;
this.libClasspath = new DefaultClassPath(libClasspath);
this.gradleApiGroovyLoader = copy.gradleApiGroovyLoader;
this.antAdapterGroovyLoader = copy.antAdapterGroovyLoader;
this.classLoaderCache = copy.classLoaderCache;
}
public ClassPathToClassLoaderCache getClassLoaderCache() {
return classLoaderCache;
}
public IsolatedAntBuilder withClasspath(Iterable classpath) {
if (LOG.isDebugEnabled()) {
LOG.debug("Forking a new isolated ant builder for classpath : {}", classpath);
}
return new DefaultIsolatedAntBuilder(this, classpath);
}
public void execute(final Closure antClosure) {
classLoaderCache.withCachedClassLoader(libClasspath, gradleApiGroovyLoader, antAdapterGroovyLoader,
new Factory() {
@Override
public ClassLoader create() {
return new MutableURLClassLoader(baseAntLoader, libClasspath);
}
}, new Action() {
@Override
public void execute(CachedClassLoader cachedClassLoader) {
ClassLoader classLoader = cachedClassLoader.getClassLoader();
Object antBuilder = newInstanceOf("org.gradle.api.internal.project.ant.BasicAntBuilder");
Object antLogger = newInstanceOf("org.gradle.api.internal.project.ant.AntLoggingAdapter");
// This looks ugly, very ugly, but that is apparently what Ant does itself
ClassLoader originalLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
try {
configureAntBuilder(antBuilder, antLogger);
// Ideally, we'd delegate directly to the AntBuilder, but its Closure class is different to our caller's
// Closure class, so the AntBuilder's methodMissing() doesn't work. It just converts our Closures to String
// because they are not an instanceof its Closure class.
Object delegate = new AntBuilderDelegate(antBuilder, classLoader);
new ClosureBackedAction
© 2015 - 2025 Weber Informatics LLC | Privacy Policy