All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.gradle.tooling.internal.provider.serialization.ClientSidePayloadClassLoaderRegistry Maven / Gradle / Ivy

There is a newer version: 8.11.1
Show newest version
/*
 * Copyright 2016 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.tooling.internal.provider.serialization;

import com.google.common.collect.Sets;
import net.jcip.annotations.ThreadSafe;

import java.lang.ref.WeakReference;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * A {@link PayloadClassLoaderRegistry} used in the client JVM that maps classes loaded by application ClassLoaders. Inspects each class to calculate a minimal classpath to send across to the daemon process to recreate the ClassLoaders.
 *
 * 

Delegates to another {@link PayloadClassLoaderRegistry} to take care of managing the classes serialized from the daemon. */ @ThreadSafe public class ClientSidePayloadClassLoaderRegistry implements PayloadClassLoaderRegistry { private static final short CLIENT_CLASS_LOADER_ID = 1; private final PayloadClassLoaderRegistry delegate; private final ClasspathInferer classpathInferer; private final ClassLoaderCache classLoaderCache; private final Lock lock = new ReentrantLock(); // protects the following state // Contains only application owned ClassLoaders private final Map classLoaders = new LinkedHashMap(); public ClientSidePayloadClassLoaderRegistry(PayloadClassLoaderRegistry delegate, ClasspathInferer classpathInferer, ClassLoaderCache classLoaderCache) { this.delegate = delegate; this.classpathInferer = classpathInferer; this.classLoaderCache = classLoaderCache; } public SerializeMap newSerializeSession() { final Set candidates = new LinkedHashSet(); final Set classPath = new LinkedHashSet(); final Map classLoaderIds = new HashMap(); final Map classLoaderDetails = new HashMap(); return new SerializeMap() { public short visitClass(Class target) { ClassLoader classLoader = target.getClassLoader(); Short id = classLoaderIds.get(classLoader); if (id != null) { // Already seen this ClassLoader return id; } ClassLoaderDetails details = classLoaderCache.maybeGetDetails(classLoader); if (details != null) { // A cached ClassLoader id = (short) (classLoaderIds.size() + CLIENT_CLASS_LOADER_ID + 1); classLoaderIds.put(classLoader, id); classLoaderDetails.put(id, details); return id; } // An application ClassLoader: Inspect class to collect up the classpath for it classpathInferer.getClassPathFor(target, classPath); candidates.add(target.getClassLoader()); return CLIENT_CLASS_LOADER_ID; } @Override public void collectClassLoaderDefinitions(Map details) { lock.lock(); UUID uuid; try { uuid = getUuidForLocalClassLoaders(candidates); } finally { lock.unlock(); } details.putAll(classLoaderDetails); details.put(CLIENT_CLASS_LOADER_ID, new ClassLoaderDetails(uuid, new ClientOwnedClassLoaderSpec(new ArrayList(classPath)))); } }; } public DeserializeMap newDeserializeSession() { final DeserializeMap deserializeMap = delegate.newDeserializeSession(); return new DeserializeMap() { public Class resolveClass(ClassLoaderDetails classLoaderDetails, String className) throws ClassNotFoundException { Set candidates; lock.lock(); try { candidates = getClassLoaders(classLoaderDetails.uuid); } finally { lock.unlock(); } if (candidates != null) { // TODO:ADAM - This isn't quite right // MB: I think ^ refers to the first capable classloader loading the class. This could be different // from the loader which originally loaded it, which could pose equality and lifecycle issues. for (ClassLoader candidate : candidates) { try { return candidate.loadClass(className); } catch (ClassNotFoundException e) { // Ignore } } throw new UnsupportedOperationException("Unexpected class received in response."); } return deserializeMap.resolveClass(classLoaderDetails, className); } }; } private Set getClassLoaders(UUID uuid) { LocalClassLoaderMapping localClassLoaderMapping = classLoaders.get(uuid); if (localClassLoaderMapping == null) { return null; } Set candidates = Sets.newLinkedHashSet(); for (WeakReference reference : localClassLoaderMapping.classLoaders) { ClassLoader classLoader = reference.get(); if (classLoader != null) { candidates.add(classLoader); } } return candidates; } private UUID getUuidForLocalClassLoaders(Set candidates) { for (LocalClassLoaderMapping localClassLoaderMapping : new ArrayList(classLoaders.values())) { Set localCandidates = new LinkedHashSet(); for (WeakReference reference : localClassLoaderMapping.classLoaders) { ClassLoader cl = reference.get(); if (cl != null) { localCandidates.add(cl); } } if (localCandidates.isEmpty()) { classLoaders.remove(localClassLoaderMapping.uuid); continue; } if (localCandidates.equals(candidates)) { return localClassLoaderMapping.uuid; } } LocalClassLoaderMapping details = new LocalClassLoaderMapping(UUID.randomUUID()); for (ClassLoader candidate : candidates) { details.classLoaders.add(new WeakReference(candidate)); } classLoaders.put(details.uuid, details); return details.uuid; } private static class LocalClassLoaderMapping { private final Set> classLoaders = Sets.newLinkedHashSet(); private final UUID uuid; private LocalClassLoaderMapping(UUID uuid) { this.uuid = uuid; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy