Skip to content

[GR-40906] Add RuntimeResourceAccess#addResource(Module, String, byte[]) API method. #4945

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 14, 2022
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
1 change: 1 addition & 0 deletions sdk/src/org.graalvm.nativeimage/snapshot.sigtest
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,7 @@ supr java.lang.Object

CLSS public final org.graalvm.nativeimage.hosted.RuntimeResourceAccess
meth public static void addResource(java.lang.Module,java.lang.String)
meth public static void addResource(java.lang.Module,java.lang.String,byte[])
meth public static void addResourceBundle(java.lang.Module,java.lang.String,java.util.Locale[])
meth public static void addResourceBundle(java.lang.Module,java.lang.String)
supr java.lang.Object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,28 @@ public final class RuntimeResourceAccess {
* @since 22.3
*/
public static void addResource(Module module, String resourcePath) {
Objects.requireNonNull(module);
Objects.requireNonNull(resourcePath);
ImageSingletons.lookup(RuntimeResourceSupport.class).addResources(ConfigurationCondition.alwaysTrue(),
withModuleName(module, Pattern.quote(resourcePath)));
}

/**
* Inject a Java resource at {@code resourcePath} in {@code module} with the specified
* {@code resourceContent}. At runtime the resource can be accessed as if it was part of the
* original application. If the given {@code module} is unnamed, the resource is placed on the
* classpath instead.
*
* @since 22.3
*/
public static void addResource(Module module, String resourcePath, byte[] resourceContent) {
Objects.requireNonNull(module);
Objects.requireNonNull(resourcePath);
Objects.requireNonNull(resourceContent);
ImageSingletons.lookup(RuntimeResourceSupport.class).injectResource(
module, resourcePath, resourceContent);
}

/**
* Make Java ResourceBundle that is specified by a {@code baseBundleName} and {@code locales}
* from module {@code module} available at run time. If the given {@code module} is unnamed, the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
public interface RuntimeResourceSupport {
void addResources(ConfigurationCondition condition, String pattern);

void injectResource(Module module, String resourcePath, byte[] resourceContent);

void ignoreResources(ConfigurationCondition condition, String pattern);

void addResourceBundles(ConfigurationCondition condition, String name);
Expand Down
1 change: 1 addition & 0 deletions substratevm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This changelog summarizes major changes to GraalVM Native Image.
* (GR-15630) Allow multiple classes with the same name from different class loaders.
* (GR-40198) Introduce public API for programmatic JNI / Resource / Proxy / Serialization registration from Feature classes during the image build.
* (GR-38909) Moved strictly-internal annotation classes (e.g. @AlwaysInline, @NeverInline, @Uninterruptible, ...) out of com.oracle.svm.core.annotate. Moved remaining annotation classes to org.graalvm.sdk module.
* (GR-40906) Add RuntimeResourceAccess#addResource(Module module, String resourcePath, byte[] resource) API method that allows injecting resources into images

## Version 22.2.0
* (GR-20653) Re-enable the usage of all CPU features for JIT compilation on AMD64.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ public void addResources(ConfigurationCondition condition, String pattern) {
addedResources.add(pattern);
}

@Override
public void injectResource(Module module, String resourcePath, byte[] resourceContent) {
}

@Override
public void ignoreResources(ConfigurationCondition condition, String pattern) {
ignoredResources.add(pattern);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,16 @@
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Pattern;

import com.oracle.svm.core.configure.ConfigurationParser;
import com.oracle.svm.core.configure.ResourceConfigurationParser;
import org.graalvm.nativeimage.impl.ConfigurationCondition;

import com.oracle.svm.configure.ConfigurationBase;
import com.oracle.svm.configure.json.JsonPrinter;
import com.oracle.svm.configure.json.JsonWriter;
import com.oracle.svm.core.configure.ConditionalElement;
import com.oracle.svm.core.configure.ConfigurationParser;
import com.oracle.svm.core.configure.ResourceConfigurationParser;
import com.oracle.svm.core.configure.ResourcesRegistry;
import com.oracle.svm.core.util.VMError;

public final class ResourceConfiguration extends ConfigurationBase<ResourceConfiguration, ResourceConfiguration.Predicate> {

Expand All @@ -62,6 +63,11 @@ public void addResources(ConfigurationCondition condition, String pattern) {
configuration.addResourcePattern(condition, pattern);
}

@Override
public void injectResource(Module module, String resourcePath, byte[] resourceContent) {
VMError.shouldNotReachHere("Resource injection is only supported via Feature implementation");
}

@Override
public void ignoreResources(ConfigurationCondition condition, String pattern) {
configuration.ignoreResourcePattern(condition, pattern);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;

import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
import com.oracle.svm.core.feature.InternalFeature;
import com.oracle.svm.core.jdk.resources.NativeImageResourcePath;
import com.oracle.svm.core.jdk.resources.ResourceStorageEntry;
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
import com.oracle.svm.core.util.ImageHeapMap;
import com.oracle.svm.core.util.VMError;

Expand Down Expand Up @@ -86,14 +86,16 @@ public static byte[] inputStreamToByteArray(InputStream is) {
}

private static void addEntry(String moduleName, String resourceName, boolean isDirectory, byte[] data, boolean fromJar) {
Resources support = singleton();
Pair<String, String> key = Pair.create(moduleName, resourceName);
ResourceStorageEntry entry = support.resources.get(key);
if (entry == null) {
entry = new ResourceStorageEntry(isDirectory, fromJar);
support.resources.put(key, entry);
var resources = singleton().resources;
synchronized (resources) {
Pair<String, String> key = Pair.create(moduleName, resourceName);
ResourceStorageEntry entry = resources.get(key);
if (entry == null) {
entry = new ResourceStorageEntry(isDirectory, fromJar);
resources.put(key, entry);
}
entry.getData().add(data);
}
entry.getData().add(data);
}

@Platforms(Platform.HOSTED_ONLY.class)
Expand All @@ -111,6 +113,11 @@ public static void registerResource(String moduleName, String resourceName, Inpu
registerResource(moduleName, resourceName, is, true);
}

@Platforms(Platform.HOSTED_ONLY.class)
public static void registerResource(String moduleName, String resourceName, byte[] resourceContent) {
addEntry(moduleName, resourceName, false, resourceContent, true);
}

@Platforms(Platform.HOSTED_ONLY.class)
public static void registerResource(String moduleName, String resourceName, InputStream is, boolean fromJar) {
addEntry(moduleName, resourceName, false, inputStreamToByteArray(is), fromJar);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ void processClassLoaderOptions() {

private static void processListModulesOption(ModuleLayer layer) {
Class<?> launcherHelperClass = ReflectionUtil.lookupClass(false, "sun.launcher.LauncherHelper");
Method initOutputMethod = ReflectionUtil.lookupMethod(launcherHelperClass, "initOutput", boolean.class);
Method showModuleMethod = ReflectionUtil.lookupMethod(launcherHelperClass, "showModule", ModuleReference.class);

boolean first = true;
Expand All @@ -411,6 +412,11 @@ private static void processListModulesOption(ModuleLayer layer) {
.sorted(Comparator.comparing(ResolvedModule::name))
.collect(Collectors.toList());
if (first) {
try {
initOutputMethod.invoke(null, false);
} catch (ReflectiveOperationException e) {
throw VMError.shouldNotReachHere("Unable to use " + initOutputMethod + " to set printing with " + showModuleMethod + " to System.out.", e);
}
first = false;
} else if (!resolvedModules.isEmpty()) {
System.out.println();
Expand All @@ -419,7 +425,7 @@ private static void processListModulesOption(ModuleLayer layer) {
try {
showModuleMethod.invoke(null, resolvedModule.reference());
} catch (ReflectiveOperationException e) {
throw VMError.shouldNotReachHere("Unable to " + showModuleMethod + " for printing list of modules.", e);
throw VMError.shouldNotReachHere("Unable to use " + showModuleMethod + " for printing list of modules.", e);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import com.oracle.svm.core.configure.ConfigurationFiles;
import com.oracle.svm.core.configure.ResourceConfigurationParser;
import com.oracle.svm.core.configure.ResourcesRegistry;
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
import com.oracle.svm.core.feature.InternalFeature;
import com.oracle.svm.core.jdk.Resources;
import com.oracle.svm.core.jdk.resources.NativeImageResourceFileAttributes;
Expand All @@ -60,7 +61,6 @@
import com.oracle.svm.core.jdk.resources.NativeImageResourceFileSystemProvider;
import com.oracle.svm.core.option.HostedOptionKey;
import com.oracle.svm.core.option.LocatableMultiOptionValue;
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
import com.oracle.svm.core.util.UserError;
import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl;
import com.oracle.svm.hosted.config.ConfigurationParserUtils;
Expand Down Expand Up @@ -133,6 +133,12 @@ public void addResources(ConfigurationCondition condition, String pattern) {
});
}

@Override
public void injectResource(Module module, String resourcePath, byte[] resourceContent) {
var moduleName = module.isNamed() ? module.getName() : null;
Resources.registerResource(moduleName, resourcePath, resourceContent);
}

@Override
public void ignoreResources(ConfigurationCondition condition, String pattern) {
if (configurationTypeResolver.resolveType(condition.getTypeName()) == null) {
Expand Down Expand Up @@ -261,13 +267,11 @@ public void duringAnalysis(DuringAnalysisAccess access) {

access.requireAnalysisIteration();

DebugContext debugContext = ((DuringAnalysisAccessImpl) access).getDebugContext();
ResourcePattern[] includePatterns = compilePatterns(resourcePatternWorkSet);
ResourcePattern[] excludePatterns = compilePatterns(excludedResourcePatterns);
DebugContext debugContext = ((DuringAnalysisAccessImpl) access).getDebugContext();
ResourceCollectorImpl collector = new ResourceCollectorImpl(debugContext, includePatterns, excludePatterns, includedResourcesModules);

ImageSingletons.lookup(ClassLoaderSupport.class).collectResources(collector);

resourcePatternWorkSet.clear();
}

Expand Down