Skip to content
Merged
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 @@ -1012,7 +1012,7 @@ public Object[] getEnumConstantsShared() {
@Substitute
public InputStream getResourceAsStream(String resourceName) {
String resolvedName = resolveName(resourceName);
return Resources.singleton().createInputStream(companion.module, resolvedName);
return Resources.createInputStream(companion.module, resolvedName);
}

@KeepOriginal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

Expand All @@ -53,6 +55,7 @@
import com.oracle.svm.core.ClassLoaderSupport.ConditionWithOrigin;
import com.oracle.svm.core.MissingRegistrationUtils;
import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.configure.ConditionalRuntimeValue;
import com.oracle.svm.core.configure.RuntimeConditionSet;
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
Expand All @@ -67,6 +70,9 @@
import com.oracle.svm.core.jdk.resources.CompressedGlobTrie.CompressedGlobTrie;
import com.oracle.svm.core.jdk.resources.CompressedGlobTrie.GlobTrieNode;
import com.oracle.svm.core.jdk.resources.CompressedGlobTrie.GlobUtils;
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
import com.oracle.svm.core.layeredimagesingleton.UnsavedSingleton;
import com.oracle.svm.core.util.ImageHeapMap;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.util.LogUtils;
Expand All @@ -78,15 +84,29 @@
* Registered resources are then available from DynamicHub#getResource classes and
* {@link Target_java_lang_ClassLoader class loaders}.
*/
public final class Resources {
public final class Resources implements MultiLayeredImageSingleton, UnsavedSingleton {

private static final int INVALID_TIMESTAMP = -1;
public static final char RESOURCES_INTERNAL_PATH_SEPARATOR = '/';

/**
* @return the singleton corresponding to this layer's resources in a layered build, the unique
* singleton otherwise
*/
@Platforms(Platform.HOSTED_ONLY.class)
public static Resources singleton() {
return ImageSingletons.lookup(Resources.class);
}

/**
* @return an array of singletons corresponding to all layers in a layered build, or an array
* with a single element otherwise
*/
public static Resources[] layeredSingletons() {
assert !SubstrateUtil.HOSTED : "Accessing all layers resources at build time";
return MultiLayeredImageSingleton.getAllLayers(Resources.class);
}

/**
* The hosted map used to collect registered resources. Using a {@link ModuleResourceKey} of
* (module, resourceName) provides implementations for {@code hashCode()} and {@code equals()}
Expand Down Expand Up @@ -139,20 +159,31 @@ public void setResourcesTrieRoot(GlobTrieNode<ConditionWithOrigin> resourcesTrie
this.resourcesTrieRoot = resourcesTrieRoot;
}

public EconomicMap<ModuleResourceKey, ConditionalRuntimeValue<ResourceStorageEntryBase>> getResourceStorage() {
return resources;
public void forEachResource(BiConsumer<ModuleResourceKey, ConditionalRuntimeValue<ResourceStorageEntryBase>> action) {
MapCursor<ModuleResourceKey, ConditionalRuntimeValue<ResourceStorageEntryBase>> entries = resources.getEntries();
while (entries.advance()) {
action.accept(entries.getKey(), entries.getValue());
}
}

@Platforms(Platform.HOSTED_ONLY.class)
public ConditionalRuntimeValue<ResourceStorageEntryBase> getResource(ModuleResourceKey storageKey) {
return resources.get(storageKey);
}

@Platforms(Platform.HOSTED_ONLY.class)
public Iterable<ConditionalRuntimeValue<ResourceStorageEntryBase>> resources() {
return resources.getValues();
}

@Platforms(Platform.HOSTED_ONLY.class)
public int count() {
return resources.size();
}

public long getLastModifiedTime() {
return lastModifiedTime;
public static long getLastModifiedTime() {
var singletons = layeredSingletons();
return singletons[singletons.length - 1].lastModifiedTime;
}

public static String moduleName(Module module) {
Expand All @@ -169,6 +200,7 @@ public static ModuleResourceKey createStorageKey(Module module, String resourceN
return new ModuleResourceKey(m, resourceName);
}

@Platforms(Platform.HOSTED_ONLY.class)
public static Set<String> getIncludedResourcesModules() {
return StreamSupport.stream(singleton().resources.getKeys().spliterator(), false)
.map(ModuleResourceKey::module)
Expand Down Expand Up @@ -320,7 +352,7 @@ private static boolean wasAlreadyInCanonicalForm(String resourceName, String can
return resourceName.equals(canonicalResourceName) || removeTrailingSlash(resourceName).equals(canonicalResourceName);
}

public ResourceStorageEntryBase getAtRuntime(String name, boolean throwOnMissing) {
public static ResourceStorageEntryBase getAtRuntime(String name, boolean throwOnMissing) {
return getAtRuntime(null, name, throwOnMissing);
}

Expand All @@ -330,29 +362,31 @@ public ResourceStorageEntryBase getAtRuntime(String name, boolean throwOnMissing
* {@link MissingResourceRegistrationError}. This is needed because different modules can be
* tried on the same resource name, causing an unexpected exception if we throw directly.
*/
public ResourceStorageEntryBase getAtRuntime(Module module, String resourceName, boolean throwOnMissing) {
public static ResourceStorageEntryBase getAtRuntime(Module module, String resourceName, boolean throwOnMissing) {
VMError.guarantee(ImageInfo.inImageRuntimeCode(), "This function should be used only at runtime.");
String canonicalResourceName = toCanonicalForm(resourceName);
String moduleName = moduleName(module);
ConditionalRuntimeValue<ResourceStorageEntryBase> entry = resources.get(createStorageKey(module, canonicalResourceName));
ConditionalRuntimeValue<ResourceStorageEntryBase> entry = getEntry(module, canonicalResourceName);
if (entry == null) {
if (MissingRegistrationUtils.throwMissingRegistrationErrors()) {
MapCursor<RequestedPattern, RuntimeConditionSet> cursor = requestedPatterns.getEntries();
while (cursor.advance()) {
RequestedPattern moduleResourcePair = cursor.getKey();
if (Objects.equals(moduleName, moduleResourcePair.module) &&
((matchResource(moduleResourcePair.resource, resourceName) || matchResource(moduleResourcePair.resource, canonicalResourceName)) &&
cursor.getValue().satisfied())) {
return null;
for (var r : layeredSingletons()) {
MapCursor<RequestedPattern, RuntimeConditionSet> cursor = r.requestedPatterns.getEntries();
while (cursor.advance()) {
RequestedPattern moduleResourcePair = cursor.getKey();
if (Objects.equals(moduleName, moduleResourcePair.module) &&
((matchResource(moduleResourcePair.resource, resourceName) || matchResource(moduleResourcePair.resource, canonicalResourceName)) &&
cursor.getValue().satisfied())) {
return null;
}
}
}

String glob = GlobUtils.transformToTriePath(resourceName, moduleName);
String canonicalGlob = GlobUtils.transformToTriePath(canonicalResourceName, moduleName);
GlobTrieNode<ConditionWithOrigin> globsTrie = getResourcesTrieRoot();
if (CompressedGlobTrie.match(globsTrie, glob) ||
CompressedGlobTrie.match(globsTrie, canonicalGlob)) {
return null;
String glob = GlobUtils.transformToTriePath(resourceName, moduleName);
String canonicalGlob = GlobUtils.transformToTriePath(canonicalResourceName, moduleName);
GlobTrieNode<ConditionWithOrigin> globsTrie = r.getResourcesTrieRoot();
if (CompressedGlobTrie.match(globsTrie, glob) ||
CompressedGlobTrie.match(globsTrie, canonicalGlob)) {
return null;
}
}

return missingMetadata(resourceName, throwOnMissing);
Expand Down Expand Up @@ -389,6 +423,16 @@ public ResourceStorageEntryBase getAtRuntime(Module module, String resourceName,
return unconditionalEntry;
}

private static ConditionalRuntimeValue<ResourceStorageEntryBase> getEntry(Module module, String canonicalResourceName) {
for (var r : layeredSingletons()) {
ConditionalRuntimeValue<ResourceStorageEntryBase> entry = r.resources.get(createStorageKey(module, canonicalResourceName));
if (entry != null) {
return entry;
}
}
return null;
}

private static ResourceStorageEntryBase missingMetadata(String resourceName, boolean throwOnMissing) {
if (throwOnMissing) {
MissingResourceRegistrationUtils.missingResource(resourceName);
Expand All @@ -407,11 +451,11 @@ private static URL createURL(Module module, String resourceName, int index) {
}
}

public URL createURL(String resourceName) {
public static URL createURL(String resourceName) {
return createURL(null, resourceName);
}

public URL createURL(Module module, String resourceName) {
public static URL createURL(Module module, String resourceName) {
if (resourceName == null) {
return null;
}
Expand All @@ -420,12 +464,12 @@ public URL createURL(Module module, String resourceName) {
return urls.hasMoreElements() ? urls.nextElement() : null;
}

public InputStream createInputStream(String resourceName) {
public static InputStream createInputStream(String resourceName) {
return createInputStream(null, resourceName);
}

/* Avoid pulling in the URL class when only an InputStream is needed. */
public InputStream createInputStream(Module module, String resourceName) {
public static InputStream createInputStream(Module module, String resourceName) {
if (resourceName == null) {
return null;
}
Expand Down Expand Up @@ -458,11 +502,11 @@ public InputStream createInputStream(Module module, String resourceName) {
return data.isEmpty() ? null : new ByteArrayInputStream(data.get(0));
}

public Enumeration<URL> createURLs(String resourceName) {
public static Enumeration<URL> createURLs(String resourceName) {
return createURLs(null, resourceName);
}

public Enumeration<URL> createURLs(Module module, String resourceName) {
public static Enumeration<URL> createURLs(Module module, String resourceName) {
if (resourceName == null) {
return null;
}
Expand Down Expand Up @@ -541,6 +585,11 @@ private static boolean matchResource(String pattern, String resource) {

return resource.startsWith(start) && resource.endsWith(end);
}

@Override
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
return LayeredImageSingletonBuilderFlags.ALL_ACCESS;
}
}

@AutomaticallyRegisteredFeature
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,18 @@
import java.util.Enumeration;
import java.util.List;

import com.oracle.svm.core.util.VMError;

import org.graalvm.nativeimage.ImageInfo;

import com.oracle.svm.core.util.VMError;

public class ResourcesHelper {

public static URL nameToResourceURL(String resourceName) {
return Resources.singleton().createURL(resourceName);
return Resources.createURL(resourceName);
}

public static URL nameToResourceURL(Module module, String resourceName) {
return Resources.singleton().createURL(module, resourceName);
return Resources.createURL(module, resourceName);
}

public static InputStream nameToResourceInputStream(String mn, String resourceName) throws IOException {
Expand All @@ -54,7 +54,7 @@ public static InputStream nameToResourceInputStream(String mn, String resourceNa
}

public static List<URL> nameToResourceListURLs(String resourcesName) {
Enumeration<URL> urls = Resources.singleton().createURLs(resourcesName);
Enumeration<URL> urls = Resources.createURLs(resourcesName);
List<URL> resourceURLs = new ArrayList<>();
while (urls.hasMoreElements()) {
resourceURLs.add(urls.nextElement());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,7 @@
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.regex.Pattern;

import org.graalvm.collections.MapCursor;

import com.oracle.svm.core.MissingRegistrationUtils;
import com.oracle.svm.core.configure.ConditionalRuntimeValue;
import com.oracle.svm.core.jdk.Resources;
import com.oracle.svm.core.util.TimeUtils;

Expand Down Expand Up @@ -577,7 +574,7 @@ IndexNode getInode(byte[] path) {
IndexNode indexNode = inodes.get(IndexNode.keyOf(path));
if (indexNode == null && MissingRegistrationUtils.throwMissingRegistrationErrors()) {
// Try to access the resource to see if the metadata is present
Resources.singleton().getAtRuntime(getString(path), true);
Resources.getAtRuntime(getString(path), true);
}
return indexNode;
}
Expand Down Expand Up @@ -658,14 +655,15 @@ private void update(Entry e) {
}

private void readAllEntries() {
MapCursor<Resources.ModuleResourceKey, ConditionalRuntimeValue<ResourceStorageEntryBase>> entries = Resources.singleton().getResourceStorage().getEntries();
while (entries.advance()) {
byte[] name = getBytes(entries.getKey().resource());
ResourceStorageEntryBase entry = entries.getValue().getValue();
if (entry != null && entry.hasData()) {
IndexNode newIndexNode = new IndexNode(name, entry.isDirectory(), true);
inodes.put(newIndexNode, newIndexNode);
}
for (var resources : Resources.layeredSingletons()) {
resources.forEachResource((key, value) -> {
byte[] name = getBytes(key.resource());
ResourceStorageEntryBase entry = value.getValue();
if (entry != null && entry.hasData()) {
IndexNode newIndexNode = new IndexNode(name, entry.isDirectory(), true);
inodes.put(newIndexNode, newIndexNode);
}
});
}
buildNodeTree();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ private NativeImageResourceFileSystemUtil() {
}

public static byte[] getBytes(String resourceName, boolean readOnly) {
Object entry = Resources.singleton().getAtRuntime(resourceName, true);
Object entry = Resources.getAtRuntime(resourceName, true);
if (entry == null) {
return new byte[0];
}
Expand All @@ -49,7 +49,7 @@ public static byte[] getBytes(String resourceName, boolean readOnly) {
}

public static int getSize(String resourceName) {
Object entry = Resources.singleton().getAtRuntime(resourceName, true);
Object entry = Resources.getAtRuntime(resourceName, true);
if (entry == null) {
return 0;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public void connect() {
String resourceName = urlPath.substring(1);

Module module = hostNameOrNull != null ? ModuleLayer.boot().findModule(hostNameOrNull).orElse(null) : null;
Object entry = Resources.singleton().getAtRuntime(module, resourceName, true);
Object entry = Resources.getAtRuntime(module, resourceName, true);
if (entry != null) {
ResourceStorageEntry resourceStorageEntry = (ResourceStorageEntry) entry;
List<byte[]> bytes = resourceStorageEntry.getData();
Expand Down Expand Up @@ -174,7 +174,7 @@ private void initializeHeaders() {
properties.add(CONTENT_LENGTH, String.valueOf(data.length));
}

long lastModified = Resources.singleton().getLastModifiedTime();
long lastModified = Resources.getLastModifiedTime();
Date date = new Date(lastModified);
SimpleDateFormat fo = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
fo.setTimeZone(TimeZone.getTimeZone("GMT"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,9 @@
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import org.graalvm.collections.EconomicMap;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;

import com.oracle.svm.core.configure.ConditionalRuntimeValue;
import com.oracle.svm.core.jdk.Resources;
import com.oracle.svm.core.jdk.resources.ResourceStorageEntryBase;
import com.oracle.svm.core.util.VMError;
Expand Down Expand Up @@ -101,12 +99,11 @@ private static List<ResourceReportEntry> getResourceReportEntryList(ConcurrentHa
}

List<ResourceReportEntry> resourceInfoList = new ArrayList<>();
EconomicMap<Resources.ModuleResourceKey, ConditionalRuntimeValue<ResourceStorageEntryBase>> resourceStorage = Resources.singleton().getResourceStorage();
resourceStorage.getKeys().forEach(key -> {
Resources.singleton().forEachResource((key, value) -> {
Module module = key.module();
String resourceName = key.resource();

ResourceStorageEntryBase storageEntry = resourceStorage.get(key).getValueUnconditionally();
ResourceStorageEntryBase storageEntry = value.getValueUnconditionally();
List<SourceAndOrigin> registeredEntrySources = collection.get(key);

if (registeredEntrySources == null && storageEntry != NEGATIVE_QUERY_MARKER) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ public void addGlob(ConfigurationCondition condition, String module, String glob

@Override
public void addCondition(ConfigurationCondition condition, Module module, String resourcePath) {
var conditionalResource = Resources.singleton().getResourceStorage().get(createStorageKey(module, resourcePath));
var conditionalResource = Resources.singleton().getResource(createStorageKey(module, resourcePath));
if (conditionalResource != null) {
classInitializationSupport.addForTypeReachedTracking(condition.getType());
conditionalResource.getConditions().addCondition(condition);
Expand Down