Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ public final class RunnerClassLoader extends ClassLoader {
private final List<String> fullyIndexedDirectories;
private final Map<String, ClassLoadingResource[]> directlyIndexedResourcesIndexMap;

private final ClassLoadingResource generatedBytecodeClassLoadingResource;
private final Set<String> generatedBytecode;
private final ClassLoadingResource transformedBytecodeClassLoadingResource;
private final Set<String> transformedBytecode;

//Mutations protected by synchronization on the field value itself:
private final ClassLoadingResource[] currentlyBufferedResources = new ClassLoadingResource[4];//Experimentally found to be a reasonable number
//Protected by synchronization on the above field, as they are related.
Expand All @@ -55,13 +60,19 @@ public final class RunnerClassLoader extends ClassLoader {

RunnerClassLoader(ClassLoader parent, Map<String, ClassLoadingResource[]> resourceDirectoryMap,
Set<String> parentFirstPackages, Set<String> nonExistentResources,
List<String> fullyIndexedDirectories, Map<String, ClassLoadingResource[]> directlyIndexedResourcesIndexMap) {
List<String> fullyIndexedDirectories, Map<String, ClassLoadingResource[]> directlyIndexedResourcesIndexMap,
ClassLoadingResource generatedBytecodeClassLoadingResource, Set<String> generatedBytecode,
ClassLoadingResource transformedBytecodeClassLoadingResource, Set<String> transformedBytecode) {
super(parent);
this.resourceDirectoryMap = resourceDirectoryMap;
this.parentFirstPackages = parentFirstPackages;
this.nonExistentResources = nonExistentResources;
this.fullyIndexedDirectories = fullyIndexedDirectories;
this.directlyIndexedResourcesIndexMap = directlyIndexedResourcesIndexMap;
this.generatedBytecodeClassLoadingResource = generatedBytecodeClassLoadingResource;
this.generatedBytecode = generatedBytecode;
this.transformedBytecodeClassLoadingResource = transformedBytecodeClassLoadingResource;
this.transformedBytecode = transformedBytecode;

resource = new CracResource();
org.crac.Core.getGlobalContext().register(resource);
Expand Down Expand Up @@ -102,6 +113,13 @@ public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundExce
if (resources != null) {
String classResource = fromClassNameToResourceName(name);
for (ClassLoadingResource resource : resources) {
if (resource == generatedBytecodeClassLoadingResource && !generatedBytecode.contains(classResource)) {
continue;
}
if (resource == transformedBytecodeClassLoadingResource && !transformedBytecode.contains(classResource)) {
continue;
}

accessingResource(resource);
byte[] data = resource.getResourceData(classResource);
if (data == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,12 @@ public static SerializedApplication read(InputStream inputStream, Path appRoot)
}
String mainClass = in.readUTF();
ResourceDirectoryTracker resourceDirectoryTracker = new ResourceDirectoryTracker();
Set<String> parentFirstPackages = new HashSet<>();
int numPaths = in.readUnsignedShort();
ClassLoadingResource[] allClassLoadingResources = new ClassLoadingResource[numPaths];
ClassLoadingResource generatedBytecodeClassLoadingResource = null;
Set<String> generatedBytecode = Set.of();
ClassLoadingResource transformedBytecodeClassLoadingResource = null;
Set<String> transformedBytecode = Set.of();
for (int pathCount = 0; pathCount < numPaths; pathCount++) {
String path = in.readUTF();
boolean hasManifest = in.readBoolean();
Expand All @@ -124,6 +127,13 @@ public static SerializedApplication read(InputStream inputStream, Path appRoot)
readNullableString(in), readNullableString(in), readNullableString(in));
}
JarResource resource = new JarResource(info, appRoot.resolve(path));
boolean generatedBytecodeJar = in.readBoolean();
boolean transformedBytecodeJar = in.readBoolean();
if (generatedBytecodeJar) {
generatedBytecodeClassLoadingResource = resource;
} else if (transformedBytecodeJar) {
transformedBytecodeClassLoadingResource = resource;
}
allClassLoadingResources[pathCount] = resource;
int numDirs = in.readUnsignedShort();
for (int i = 0; i < numDirs; ++i) {
Expand All @@ -135,20 +145,35 @@ public static SerializedApplication read(InputStream inputStream, Path appRoot)
}
resourceDirectoryTracker.addResourceDir(dir, resource);
}
if (generatedBytecodeJar || transformedBytecodeJar) {
int numEntries = in.readInt();
// let's make the Set as compact as we can
Set<String> entries = new HashSet<>((int) Math.ceil(numEntries / 0.75f));
for (int i = 0; i < numEntries; ++i) {
entries.add(in.readUTF());
}
if (generatedBytecodeJar) {
generatedBytecode = entries;
} else if (transformedBytecodeJar) {
transformedBytecode = entries;
}
}
}
int packages = in.readUnsignedShort();
Set<String> parentFirstPackages = new HashSet<>((int) Math.ceil(packages / 0.75f));
for (int i = 0; i < packages; ++i) {
parentFirstPackages.add(in.readUTF());
}
Set<String> nonExistentResources = new HashSet<>();
int nonExistentResourcesSize = in.readUnsignedShort();
Set<String> nonExistentResources = new HashSet<>((int) Math.ceil(nonExistentResourcesSize / 0.75f));
for (int i = 0; i < nonExistentResourcesSize; i++) {
nonExistentResources.add(in.readUTF());
}
// this map is populated correctly because the JarResource entries are added to allClassLoadingResources
// in the same order as the classpath was written during the writing of the index
Map<String, ClassLoadingResource[]> directlyIndexedResourcesIndexMap = new HashMap<>();
int directlyIndexedSize = in.readUnsignedShort();
Map<String, ClassLoadingResource[]> directlyIndexedResourcesIndexMap = new HashMap<>(
(int) Math.ceil(directlyIndexedSize / 0.75f));
for (int i = 0; i < directlyIndexedSize; i++) {
String resource = in.readUTF();
int indexesSize = in.readUnsignedShort();
Expand All @@ -160,7 +185,9 @@ public static SerializedApplication read(InputStream inputStream, Path appRoot)
}
RunnerClassLoader runnerClassLoader = new RunnerClassLoader(ClassLoader.getSystemClassLoader(),
resourceDirectoryTracker.getResult(), parentFirstPackages,
nonExistentResources, FULLY_INDEXED_PATHS, directlyIndexedResourcesIndexMap);
nonExistentResources, FULLY_INDEXED_PATHS, directlyIndexedResourcesIndexMap,
generatedBytecodeClassLoadingResource, generatedBytecode,
transformedBytecodeClassLoadingResource, transformedBytecode);
for (ClassLoadingResource classLoadingResource : allClassLoadingResources) {
classLoadingResource.init();
}
Expand Down Expand Up @@ -200,8 +227,23 @@ private static List<String> writeJar(DataOutputStream out, Path jar) throws IOEx
}
}

boolean writeAllEntries = false;
if (jar.endsWith("generated-bytecode.jar")) {
out.writeBoolean(true);
writeAllEntries = true;
} else {
out.writeBoolean(false);
}
if (jar.endsWith("transformed-bytecode.jar")) {
out.writeBoolean(true);
writeAllEntries = true;
} else {
out.writeBoolean(false);
}

Set<String> dirs = new LinkedHashSet<>();
Map<String, List<String>> fullyIndexedPaths = new LinkedHashMap<>();
Set<String> allEntries = new LinkedHashSet<>();
Enumeration<? extends ZipEntry> entries = zip.entries();
boolean hasDefaultPackage = false;
while (entries.hasMoreElements()) {
Expand Down Expand Up @@ -243,6 +285,10 @@ private static List<String> writeJar(DataOutputStream out, Path jar) throws IOEx
.add(entry.getName());
}
}

if (writeAllEntries) {
allEntries.add(entry.getName());
}
}
}
if (hasDefaultPackage) {
Expand All @@ -252,6 +298,12 @@ private static List<String> writeJar(DataOutputStream out, Path jar) throws IOEx
for (String i : dirs) {
out.writeUTF(i);
}
if (writeAllEntries) {
out.writeInt(allEntries.size());
for (String entry : allEntries) {
out.writeUTF(entry);
}
}
List<String> result = new ArrayList<>();
for (List<String> values : fullyIndexedPaths.values()) {
result.addAll(values);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ public void testConcurrentJarCloseAndReload() throws Exception {

RunnerClassLoader runnerClassLoader = new RunnerClassLoader(ClassLoader.getSystemClassLoader(), resourceDirectoryMap,
Collections.emptySet(), Collections.emptySet(),
Collections.emptyList(), Collections.emptyMap());
Collections.emptyList(), Collections.emptyMap(),
null, Collections.emptySet(),
null, Collections.emptySet());

// Put the RunnerClassLoader in a postBootPhase thus enabling the jars cache
runnerClassLoader.resetInternalCaches();
Expand Down Expand Up @@ -110,7 +112,9 @@ public void testUrlWithTrailingSlash() {

RunnerClassLoader runnerClassLoader = new RunnerClassLoader(ClassLoader.getSystemClassLoader(), resourceDirectoryMap,
Collections.emptySet(), Collections.emptySet(),
Collections.emptyList(), Collections.emptyMap());
Collections.emptyList(), Collections.emptyMap(),
null, Collections.emptySet(),
null, Collections.emptySet());

assertThat(runnerClassLoader.findResource("org").toString()).endsWith("/org");
assertThat(runnerClassLoader.findResource("org/").toString()).endsWith("/org/");
Expand Down