org.gradle.api.internal.initialization.DefaultClassLoaderScope Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2013 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.initialization;
import org.gradle.api.internal.initialization.loadercache.ClassLoaderCache;
import org.gradle.api.internal.initialization.loadercache.ClassLoaderId;
import org.gradle.initialization.ClassLoaderScopeOrigin;
import org.gradle.initialization.ClassLoaderScopeRegistryListener;
import org.gradle.internal.classloader.CachingClassLoader;
import org.gradle.internal.classloader.MultiParentClassLoader;
import org.gradle.internal.classpath.ClassPath;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class DefaultClassLoaderScope extends AbstractClassLoaderScope {
public static final String STRICT_MODE_PROPERTY = "org.gradle.classloaderscope.strict";
private final ClassLoaderScope parent;
private boolean locked;
protected ClassPath export = ClassPath.EMPTY;
private List exportLoaders; // if not null, is not empty
private ClassPath local = ClassPath.EMPTY;
private List ownLoaders;
// If these are not null, we are pessimistic (loaders asked for before locking)
private MultiParentClassLoader exportingClassLoader;
private MultiParentClassLoader localClassLoader;
// What is actually exposed
private ClassLoader effectiveLocalClassLoader;
private ClassLoader effectiveExportClassLoader;
public DefaultClassLoaderScope(ClassLoaderScopeIdentifier id, ClassLoaderScope parent, @Nullable ClassLoaderScopeOrigin origin, ClassLoaderCache classLoaderCache, ClassLoaderScopeRegistryListener listener) {
super(id, origin, classLoaderCache, listener);
this.parent = parent;
listener.childScopeCreated(parent.getId(), id, origin);
}
private ClassLoader loader(ClassLoaderId id, ClassLoader parent, ClassPath classPath, @Nullable List additionalLoaders) {
if (additionalLoaders == null) {
return loader(id, parent, classPath);
}
return new CachingClassLoader(multiLoader(id, parent, classPath, additionalLoaders));
}
private MultiParentClassLoader multiLoader(ClassLoaderId id, ClassLoader parent, ClassPath classPath, @Nullable List additionalLoaders) {
int numParents = 1;
if (additionalLoaders != null) {
numParents += additionalLoaders.size();
}
if (!classPath.isEmpty()) {
numParents += 1;
}
List parents = new ArrayList<>(numParents);
parents.add(parent);
if (additionalLoaders != null) {
parents.addAll(additionalLoaders);
}
if (!classPath.isEmpty()) {
parents.add(loader(id, parent, classPath));
}
return new MultiParentClassLoader(parents);
}
private ClassLoader localLoader(ClassLoaderId classLoaderId, ClassLoader parent, ClassPath classPath) {
return loader(classLoaderId, parent, classPath);
}
private void buildEffectiveLoaders() {
if (effectiveLocalClassLoader == null) {
boolean hasExports = !export.isEmpty() || exportLoaders != null;
boolean hasLocals = !local.isEmpty();
if (locked) {
if (hasExports && hasLocals) {
effectiveExportClassLoader = loader(id.exportId(), parent.getExportClassLoader(), export, exportLoaders);
effectiveLocalClassLoader = localLoader(id.localId(), effectiveExportClassLoader, local);
} else if (hasLocals) {
classLoaderCache.remove(id.exportId());
effectiveExportClassLoader = parent.getExportClassLoader();
effectiveLocalClassLoader = localLoader(id.localId(), effectiveExportClassLoader, local);
} else if (hasExports) {
classLoaderCache.remove(id.localId());
effectiveExportClassLoader = loader(id.exportId(), parent.getExportClassLoader(), export, exportLoaders);
effectiveLocalClassLoader = effectiveExportClassLoader;
} else {
classLoaderCache.remove(id.localId());
classLoaderCache.remove(id.exportId());
effectiveLocalClassLoader = parent.getExportClassLoader();
effectiveExportClassLoader = parent.getExportClassLoader();
}
} else { // creating before locking, have to create the most flexible setup
if (Boolean.getBoolean(STRICT_MODE_PROPERTY)) {
throw new IllegalStateException("Attempt to define scope class loader before scope is locked, scope identifier is " + id);
}
exportingClassLoader = multiLoader(id.exportId(), parent.getExportClassLoader(), export, exportLoaders);
effectiveExportClassLoader = new CachingClassLoader(exportingClassLoader);
localClassLoader = new MultiParentClassLoader(loader(id.localId(), effectiveExportClassLoader, local));
effectiveLocalClassLoader = new CachingClassLoader(localClassLoader);
}
exportLoaders = null;
}
}
@Override
public ClassLoader getExportClassLoader() {
buildEffectiveLoaders();
return effectiveExportClassLoader;
}
@Override
public ClassLoader getLocalClassLoader() {
buildEffectiveLoaders();
return effectiveLocalClassLoader;
}
@Override
public ClassLoaderScope getParent() {
return parent;
}
@Override
public boolean defines(Class> clazz) {
if (ownLoaders != null) {
for (ClassLoader ownLoader : ownLoaders) {
if (ownLoader.equals(clazz.getClassLoader())) {
return true;
}
}
}
return false;
}
protected ClassLoader loader(ClassLoaderId classLoaderId, ClassLoader parent, ClassPath classPath) {
if (classPath.isEmpty()) {
return parent;
}
ClassLoader classLoader = classLoaderCache.get(classLoaderId, classPath, parent, null);
listener.classloaderCreated(this.id, classLoaderId, classLoader, classPath, null);
if (ownLoaders == null) {
ownLoaders = new ArrayList<>();
}
ownLoaders.add(classLoader);
return classLoader;
}
@Override
public ClassLoaderScope local(ClassPath classPath) {
if (classPath.isEmpty()) {
return this;
}
assertNotLocked();
if (localClassLoader != null) {
ClassLoader loader = loader(id.localId(), effectiveExportClassLoader, classPath);
localClassLoader.addParent(loader);
} else {
local = local.plus(classPath);
}
return this;
}
@Override
public ClassLoaderScope export(ClassPath classPath) {
if (classPath.isEmpty()) {
return this;
}
assertNotLocked();
if (exportingClassLoader != null) {
exportingClassLoader.addParent(loader(id.exportId(), parent.getExportClassLoader(), classPath));
} else {
export = export.plus(classPath);
}
return this;
}
@Override
public ClassLoaderScope export(ClassLoader classLoader) {
assertNotLocked();
if (exportingClassLoader != null) {
exportingClassLoader.addParent(classLoader);
} else {
if (exportLoaders == null) {
exportLoaders = new ArrayList<>(1);
}
exportLoaders.add(classLoader);
}
return this;
}
private void assertNotLocked() {
if (locked) {
throw new IllegalStateException("class loader scope is locked, scope identifier is " + id);
}
}
@Override
public ClassLoaderScope lock() {
locked = true;
return this;
}
@Override
public boolean isLocked() {
return locked;
}
@Override
public void onReuse() {
parent.onReuse();
listener.childScopeCreated(parent.getId(), id, origin);
if (!export.isEmpty()) {
listener.classloaderCreated(this.id, id.exportId(), effectiveExportClassLoader, export, null);
}
if (!local.isEmpty()) {
listener.classloaderCreated(this.id, id.localId(), effectiveLocalClassLoader, export, null);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy