/* * Copyright 2016 DiffPlug * * 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 com.diffplug.spotless; import java.io.IOException; import java.io.Serializable; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; /** * Spotless' global cache. {@link SpotlessCache#clear()} should be called * when Spotless is no longer in use to release any resources it has grabbed. */ public final class SpotlessCache { /** Allows comparing keys based on their serialization. */ static final class SerializedKey { final byte[] serialized; final int hashCode; SerializedKey(Serializable key) { Objects.requireNonNull(key); serialized = LazyForwardingEquality.toBytes(key); hashCode = Arrays.hashCode(serialized); } @Override public final boolean equals(Object other) { return other instanceof SerializedKey && Arrays.equals(serialized, ((SerializedKey) other).serialized); } @Override public final int hashCode() { return hashCode; } } final Map<SerializedKey, URLClassLoader> cache = new HashMap<>(); @SuppressFBWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED") synchronized ClassLoader classloader(JarState state) { SerializedKey key = new SerializedKey(state); return cache .computeIfAbsent(key, k -> new URLClassLoader(state.jarUrls(), null)); } static SpotlessCache instance() { return instance; } /** Closes all cached classloaders. */ public static void clear() { List<URLClassLoader> toDelete; synchronized (instance) { toDelete = new ArrayList<>(instance.cache.values()); instance.cache.clear(); } for (URLClassLoader classLoader : toDelete) { try { classLoader.close(); } catch (IOException e) { throw ThrowingEx.asRuntime(e); } } } private static final SpotlessCache instance = new SpotlessCache(); }