Skip to content

Commit

Permalink
use faster gen with JDK methods
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinWitt committed Aug 25, 2023
1 parent 16775bc commit aabd918
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 25 deletions.
5 changes: 0 additions & 5 deletions terminator-commons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,6 @@
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>io.github.classgraph</groupId>
<artifactId>classgraph</artifactId>
<version>4.8.162</version>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.github.algomaster99.terminator.commons.fingerprint;

import java.nio.ByteBuffer;

/**
* A class that represents a JDK class. It contains the name of the class and the bytes of the class as a {@link ByteBuffer}.
*/
public record JdkClass(String name, ByteBuffer bytes) {}
Original file line number Diff line number Diff line change
@@ -1,23 +1,53 @@
package io.github.algomaster99.terminator.commons.fingerprint;

import io.github.classgraph.ClassGraph;
import io.github.classgraph.Resource;
import io.github.classgraph.ScanResult;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReader;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The JdkIndexer class provides a utility to list all JDK classes by scanning the JDK used for the execution of the application.
*/
public class JdkIndexer {

private static final Logger logger = LoggerFactory.getLogger(JdkIndexer.class);

/**
* Returns a list of all jdk classes. The list is populated by scanning the jdk used for the execution of this application.
* @return a list of all jdk classes, never null.
* Returns a list of all JDK classes. The list is populated by scanning the JDK used for the execution of this application.
*
* @return a list of all JDK classes, never null.
*/
public static List<Resource> listJdkClasses() {
try (ScanResult scanResult = new ClassGraph()
.enableSystemJarsAndModules()
.acceptPackages("java.*", "jdk.*", "oracle.*", "sun.*")
.scan()) {
return scanResult.getAllClasses().stream().map(v -> v.getResource()).collect(Collectors.toList());
}
public static List<JdkClass> listJdkClasses() {
List<JdkClass> jdkClasses = new ArrayList<>();
ModuleFinder.ofSystem().findAll().forEach(mr -> {
try {
try (ModuleReader reader = mr.open()) {
for (String resource : reader.list().toList()) {
if (!resource.endsWith(".class")) {
continue;
}
Optional<ByteBuffer> contents = reader.read(resource);
if (contents.isPresent()) {
jdkClasses.add(new JdkClass(resource, contents.get()));
} else {
logger.atWarn()
.log(
"Could not read resource {} from module {}",
resource,
mr.descriptor().name());
}
}
}
} catch (Throwable e) {
logger.atError()
.setCause(e)
.log("Error while reading module {}", mr.descriptor().name());
}
});
return jdkClasses;
}
}
24 changes: 17 additions & 7 deletions watchdog-agent/src/main/java/io/github/algomaster99/Options.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import io.github.algomaster99.terminator.commons.jar.JarDownloader;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.NoSuchAlgorithmException;
Expand Down Expand Up @@ -155,25 +156,34 @@ private void processAllComponents(Bom14Schema sbom) {
private void processJdk() {
JdkIndexer.listJdkClasses().forEach(resource -> {
try {

byte[] classfileBytes = resource.load();
byte[] classfileBytes = toArray(resource.bytes());
ClassReader classReader = new ClassReader(classfileBytes);

String classfileVersion = ClassfileVersion.getVersion(classfileBytes);
String hash = HashComputer.computeHash(classfileBytes, algorithm);
jdkFingerprints.put(
classReader.getClassName(),
List.of(new Jdk(new ClassFileAttributes(classfileVersion, hash, algorithm))));
} catch (IOException e) {
LOGGER.error("Failed to load classfile bytes for: " + resource, e);
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
LOGGER.error("Failed to compute hash with algorithm: " + algorithm, e);
throw new RuntimeException(e);
} catch (Exception e) {
LOGGER.error("Failed to compute hash for: " + resource, e);
System.out.println("Failed to compute hash for: " + resource.getPath());
}
});
}

/**
* Converts a bytebuffer to a byte array. If the buffer has an array, it returns it, otherwise it copies the bytes. This is needed because the buffer is not guaranteed to have an array.
* See {@link java.nio.ByteBuffer#hasArray()} and {@link java.nio.DirectByteBuffer}.
* @param buffer the buffer to convert
* @return the byte array
*/
private byte[] toArray(ByteBuffer buffer) {
if (buffer.hasArray()) {
return buffer.array();
}
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
return bytes;
}
}

0 comments on commit aabd918

Please sign in to comment.