Skip to content

Commit ff2c26a

Browse files
committed
Conditional resource configuration in NI
1 parent ab2fcbe commit ff2c26a

File tree

14 files changed

+161
-105
lines changed

14 files changed

+161
-105
lines changed

sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/ConfigurationCondition.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,9 @@ public int hashCode() {
8787
public int compareTo(ConfigurationCondition o) {
8888
return this.typeName.compareTo(o.typeName);
8989
}
90+
91+
@Override
92+
public String toString() {
93+
return "[typeReachable: \"" + typeName + "\"" + "]";
94+
}
9095
}

substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/OmitPreviousConfigTests.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,9 @@ private static void doTestResourceConfig(ResourceConfiguration resourceConfig) {
190190
Assert.assertFalse(resourceConfig.anyResourceMatches("seenResource.txt"));
191191
Assert.assertTrue(resourceConfig.anyResourceMatches("unseenResource.txt"));
192192

193-
Assert.assertFalse(resourceConfig.anyBundleMatches("seenBundle"));
194-
Assert.assertTrue(resourceConfig.anyBundleMatches("unseenBundle"));
193+
ConfigurationCondition condition = ConfigurationCondition.objectReachable();
194+
Assert.assertFalse(resourceConfig.anyBundleMatches(condition, "seenBundle"));
195+
Assert.assertTrue(resourceConfig.anyBundleMatches(condition, "unseenBundle"));
195196
}
196197

197198
private static void doTestSerializationConfig(SerializationConfiguration serializationConfig) {

substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/ResourceConfigurationTest.java

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.util.LinkedList;
3232
import java.util.List;
3333

34+
import org.graalvm.nativeimage.impl.ConfigurationCondition;
3435
import org.junit.Assert;
3536
import org.junit.Test;
3637

@@ -44,14 +45,15 @@ public class ResourceConfigurationTest {
4445
@Test
4546
public void anyResourceMatches() {
4647
ResourceConfiguration rc = new ResourceConfiguration();
47-
rc.addResourcePattern(".*/Resource.*txt$");
48+
ConfigurationCondition defaultCond = ConfigurationCondition.objectReachable();
49+
rc.addResourcePattern(defaultCond, ".*/Resource.*txt$");
4850

4951
Assert.assertTrue(rc.anyResourceMatches("com/my/app/Resource0.txt"));
5052
Assert.assertTrue(rc.anyResourceMatches("com/my/app/Resource1.txt"));
5153
Assert.assertTrue(rc.anyResourceMatches("/Resource2.txt"));
5254
Assert.assertTrue(rc.anyResourceMatches("/Resource3.txt"));
5355

54-
rc.ignoreResourcePattern(".*/Resource2.txt$");
56+
rc.ignoreResourcePattern(defaultCond, ".*/Resource2.txt$");
5557

5658
Assert.assertTrue(rc.anyResourceMatches("com/my/app/Resource0.txt"));
5759
Assert.assertTrue(rc.anyResourceMatches("com/my/app/Resource1.txt"));
@@ -62,28 +64,20 @@ public void anyResourceMatches() {
6264
@Test
6365
public void printJson() {
6466
ResourceConfiguration rc = new ResourceConfiguration();
65-
rc.addResourcePattern(".*/Resource.*txt$");
66-
rc.ignoreResourcePattern(".*/Resource2.txt$");
67+
ConfigurationCondition defaultCond = ConfigurationCondition.objectReachable();
68+
rc.addResourcePattern(defaultCond, ".*/Resource.*txt$");
69+
rc.ignoreResourcePattern(defaultCond, ".*/Resource2.txt$");
6770
PipedWriter pw = new PipedWriter();
6871
JsonWriter jw = new JsonWriter(pw);
6972

7073
try (PipedReader pr = new PipedReader()) {
7174
pr.connect(pw);
7275

73-
Thread writerThread = new Thread(new Runnable() {
74-
75-
@Override
76-
public void run() {
77-
try {
78-
rc.printJson(jw);
79-
} catch (IOException e) {
80-
Assert.fail(e.getMessage());
81-
} finally {
82-
try {
83-
jw.close();
84-
} catch (IOException e) {
85-
}
86-
}
76+
Thread writerThread = new Thread(() -> {
77+
try (JsonWriter w = jw) {
78+
rc.printJson(w);
79+
} catch (IOException e) {
80+
Assert.fail(e.getMessage());
8781
}
8882
});
8983

@@ -93,17 +87,17 @@ public void run() {
9387
ResourcesRegistry registry = new ResourcesRegistry() {
9488

9589
@Override
96-
public void addResources(String pattern) {
90+
public void addResources(ConfigurationCondition condition, String pattern) {
9791
addedResources.add(pattern);
9892
}
9993

10094
@Override
101-
public void ignoreResources(String pattern) {
95+
public void ignoreResources(ConfigurationCondition condition, String pattern) {
10296
ignoredResources.add(pattern);
10397
}
10498

10599
@Override
106-
public void addResourceBundles(String name) {
100+
public void addResourceBundles(ConfigurationCondition condition, String name) {
107101
}
108102
};
109103

substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ResourceConfiguration.java

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,44 +25,49 @@
2525
package com.oracle.svm.configure.config;
2626

2727
import java.io.IOException;
28-
import java.util.Comparator;
2928
import java.util.concurrent.ConcurrentHashMap;
3029
import java.util.concurrent.ConcurrentMap;
3130
import java.util.regex.Pattern;
3231

32+
import org.graalvm.nativeimage.impl.ConfigurationCondition;
33+
3334
import com.oracle.svm.configure.ConfigurationBase;
3435
import com.oracle.svm.configure.json.JsonPrinter;
3536
import com.oracle.svm.configure.json.JsonWriter;
37+
import com.oracle.svm.core.configure.ConditionalElement;
3638
import com.oracle.svm.core.configure.ResourcesRegistry;
3739

3840
public class ResourceConfiguration implements ConfigurationBase {
3941

4042
public static class ParserAdapter implements ResourcesRegistry {
43+
4144
private final ResourceConfiguration configuration;
4245

43-
public ParserAdapter(ResourceConfiguration configuration) {
46+
ParserAdapter(ResourceConfiguration configuration) {
4447
this.configuration = configuration;
4548
}
4649

4750
@Override
48-
public void addResources(String pattern) {
49-
configuration.addResourcePattern(pattern);
51+
public void addResources(ConfigurationCondition condition, String pattern) {
52+
configuration.addResourcePattern(condition, pattern);
5053
}
5154

5255
@Override
53-
public void ignoreResources(String pattern) {
54-
configuration.ignoreResourcePattern(pattern);
56+
public void ignoreResources(ConfigurationCondition condition, String pattern) {
57+
configuration.ignoreResourcePattern(condition, pattern);
5558
}
5659

5760
@Override
58-
public void addResourceBundles(String name) {
59-
configuration.addBundle(name);
61+
public void addResourceBundles(ConfigurationCondition condition, String name) {
62+
configuration.addBundle(condition, name);
6063
}
64+
6165
}
6266

63-
private final ConcurrentMap<String, Pattern> addedResources = new ConcurrentHashMap<>();
64-
private final ConcurrentMap<String, Pattern> ignoredResources = new ConcurrentHashMap<>();
65-
private final ConcurrentHashMap.KeySetView<String, Boolean> bundles = ConcurrentHashMap.newKeySet();
67+
private final ConcurrentMap<ConditionalElement<String>, Pattern> addedResources = new ConcurrentHashMap<>();
68+
69+
private final ConcurrentMap<ConditionalElement<String>, Pattern> ignoredResources = new ConcurrentHashMap<>();
70+
private final ConcurrentHashMap.KeySetView<ConditionalElement<String>, Boolean> bundles = ConcurrentHashMap.newKeySet();
6671

6772
public ResourceConfiguration() {
6873
}
@@ -79,16 +84,16 @@ public void removeAll(ResourceConfiguration other) {
7984
bundles.removeAll(other.bundles);
8085
}
8186

82-
public void addResourcePattern(String pattern) {
83-
addedResources.computeIfAbsent(pattern, Pattern::compile);
87+
public void addResourcePattern(ConfigurationCondition condition, String pattern) {
88+
addedResources.computeIfAbsent(new ConditionalElement<>(condition, pattern), p -> Pattern.compile(p.getElement()));
8489
}
8590

86-
public void ignoreResourcePattern(String pattern) {
87-
ignoredResources.computeIfAbsent(pattern, Pattern::compile);
91+
public void ignoreResourcePattern(ConfigurationCondition condition, String pattern) {
92+
ignoredResources.computeIfAbsent(new ConditionalElement<>(condition, pattern), p -> Pattern.compile(p.getElement()));
8893
}
8994

90-
public void addBundle(String bundle) {
91-
bundles.add(bundle);
95+
public void addBundle(ConfigurationCondition condition, String bundle) {
96+
bundles.add(new ConditionalElement<>(condition, bundle));
9297
}
9398

9499
public boolean anyResourceMatches(String s) {
@@ -109,24 +114,24 @@ public boolean anyResourceMatches(String s) {
109114
return false;
110115
}
111116

112-
public boolean anyBundleMatches(String s) {
113-
return bundles.contains(s);
117+
public boolean anyBundleMatches(ConfigurationCondition condition, String bundleName) {
118+
return bundles.contains(new ConditionalElement<>(condition, bundleName));
114119
}
115120

116121
@Override
117122
public void printJson(JsonWriter writer) throws IOException {
118123
writer.append('{').indent().newline();
119124
writer.quote("resources").append(':').append('{').newline();
120125
writer.quote("includes").append(':');
121-
JsonPrinter.printCollection(writer, addedResources.keySet(), Comparator.naturalOrder(), (String p, JsonWriter w) -> w.append('{').quote("pattern").append(':').quote(p).append('}'));
126+
JsonPrinter.printCollection(writer, addedResources.keySet(), ConditionalElement.comparator(), (p, w) -> conditionalElementJson(p, w, "pattern"));
122127
if (!ignoredResources.isEmpty()) {
123128
writer.append(',').newline();
124129
writer.quote("excludes").append(':');
125-
JsonPrinter.printCollection(writer, ignoredResources.keySet(), Comparator.naturalOrder(), (String p, JsonWriter w) -> w.append('{').quote("pattern").append(':').quote(p).append('}'));
130+
JsonPrinter.printCollection(writer, ignoredResources.keySet(), ConditionalElement.comparator(), (p, w) -> conditionalElementJson(p, w, "pattern"));
126131
}
127132
writer.append('}').append(',').newline();
128133
writer.quote("bundles").append(':');
129-
JsonPrinter.printCollection(writer, bundles, Comparator.naturalOrder(), (String p, JsonWriter w) -> w.append('{').quote("name").append(':').quote(p).append('}'));
134+
JsonPrinter.printCollection(writer, bundles, ConditionalElement.comparator(), (p, w) -> conditionalElementJson(p, w, "name"));
130135
writer.unindent().newline().append('}');
131136
}
132137

@@ -135,4 +140,10 @@ public boolean isEmpty() {
135140
return addedResources.isEmpty() && bundles.isEmpty();
136141
}
137142

143+
private static void conditionalElementJson(ConditionalElement<String> p, JsonWriter w, String elementName) throws IOException {
144+
w.append('{').indent().newline();
145+
ConfigurationConditionPrintable.printConditionAttribute(p.getCondition(), w);
146+
w.quote(elementName).append(':').quote(p.getElement());
147+
w.unindent().newline().append('}');
148+
}
138149
}

substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/ReflectionProcessor.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public void processEntry(Map<String, ?> entry) {
9090
case "getSystemResources":
9191
String literal = singleElement(args);
9292
String regex = Pattern.quote(literal);
93-
resourceConfiguration.addResourcePattern(regex);
93+
resourceConfiguration.addResourcePattern(condition, regex);
9494
return;
9595
}
9696
String callerClass = (String) entry.get("caller_class");
@@ -238,12 +238,12 @@ public void processEntry(Map<String, ?> entry) {
238238

239239
case "getBundleImplJDK8OrEarlier": {
240240
expectSize(args, 4);
241-
resourceConfiguration.addBundle((String) args.get(0));
241+
resourceConfiguration.addBundle(condition, (String) args.get(0));
242242
break;
243243
}
244244
case "getBundleImplJDK11OrLater": {
245245
expectSize(args, 5);
246-
resourceConfiguration.addBundle((String) args.get(2));
246+
resourceConfiguration.addBundle(condition, (String) args.get(2));
247247
break;
248248
}
249249
default:

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConditionalElement.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525

2626
package com.oracle.svm.core.configure;
2727

28+
import java.util.Comparator;
2829
import java.util.Objects;
30+
import java.util.function.Function;
2931

3032
import org.graalvm.nativeimage.impl.ConfigurationCondition;
3133

@@ -63,4 +65,11 @@ public boolean equals(Object o) {
6365
public int hashCode() {
6466
return Objects.hash(condition, element);
6567
}
68+
69+
public static <T extends Comparable<T>> Comparator<ConditionalElement<T>> comparator() {
70+
return (o1, o2) -> Comparator
71+
.comparing((Function<ConditionalElement<T>, T>) ConditionalElement::getElement)
72+
.thenComparing(ConditionalElement::getCondition)
73+
.compare(o1, o2);
74+
}
6675
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceConfigurationParser.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,16 @@
2929
import java.util.Collections;
3030
import java.util.List;
3131
import java.util.Map;
32-
import java.util.function.Consumer;
32+
import java.util.function.BiConsumer;
33+
34+
import org.graalvm.nativeimage.impl.ConfigurationCondition;
3335

3436
import com.oracle.svm.core.util.json.JSONParser;
3537

3638
public class ResourceConfigurationParser extends ConfigurationParser {
3739
private final ResourcesRegistry registry;
3840

39-
public <T> ResourceConfigurationParser(ResourcesRegistry registry, boolean strictConfiguration) {
41+
public ResourceConfigurationParser(ResourcesRegistry registry, boolean strictConfiguration) {
4042
super(strictConfiguration);
4143
this.registry = registry;
4244
}
@@ -68,35 +70,36 @@ private void parseTopLevelObject(Map<String, Object> obj) {
6870

6971
List<Object> includes = asList(includesObject, "Attribute 'includes' must be a list of resources");
7072
for (Object object : includes) {
71-
parseEntry(object, "pattern", registry::addResources, "resource descriptor object", "'includes' list");
73+
parseStringEntry(object, "pattern", registry::addResources, "resource descriptor object", "'includes' list");
7274
}
7375

7476
if (excludesObject != null) {
7577
List<Object> excludes = asList(excludesObject, "Attribute 'excludes' must be a list of resources");
7678
for (Object object : excludes) {
77-
parseEntry(object, "pattern", registry::ignoreResources, "resource descriptor object", "'excludes' list");
79+
parseStringEntry(object, "pattern", registry::ignoreResources, "resource descriptor object", "'excludes' list");
7880
}
7981
}
8082
} else { // Old format: may be deprecated in future versions
8183
List<Object> resources = asList(resourcesObject, "Attribute 'resources' must be a list of resources");
8284
for (Object object : resources) {
83-
parseEntry(object, "pattern", registry::addResources, "resource descriptor object", "'resources' list");
85+
parseStringEntry(object, "pattern", registry::addResources, "resource descriptor object", "'resources' list");
8486
}
8587
}
8688
}
8789
if (bundlesObject != null) {
8890
List<Object> bundles = asList(bundlesObject, "Attribute 'bundles' must be a list of bundles");
8991
for (Object object : bundles) {
90-
parseEntry(object, "name", registry::addResourceBundles, "bundle descriptor object", "'bundles' list");
92+
parseStringEntry(object, "name", registry::addResourceBundles, "bundle descriptor object", "'bundles' list");
9193
}
9294
}
9395
}
9496

95-
private void parseEntry(Object data, String valueKey, Consumer<String> resourceRegistry, String expectedType, String parentType) {
97+
private void parseStringEntry(Object data, String valueKey, BiConsumer<ConfigurationCondition, String> resourceRegistry, String expectedType, String parentType) {
9698
Map<String, Object> resource = asMap(data, "Elements of " + parentType + " must be a " + expectedType);
97-
checkAttributes(resource, "resource and resource bundle descriptor object", Collections.singleton(valueKey));
99+
checkAttributes(resource, "resource and resource bundle descriptor object", Collections.singletonList(valueKey), Collections.singletonList(CONDITIONAL_KEY));
100+
ConfigurationCondition condition = parseCondition(resource);
98101
Object valueObject = resource.get(valueKey);
99102
String value = asString(valueObject, valueKey);
100-
resourceRegistry.accept(value);
103+
resourceRegistry.accept(condition, value);
101104
}
102105
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourcesRegistry.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@
2424
*/
2525
package com.oracle.svm.core.configure;
2626

27+
import org.graalvm.nativeimage.impl.ConfigurationCondition;
28+
2729
public interface ResourcesRegistry {
28-
void addResources(String pattern);
30+
void addResources(ConfigurationCondition condition, String pattern);
2931

30-
void ignoreResources(String pattern);
32+
void ignoreResources(ConfigurationCondition condition, String pattern);
3133

32-
void addResourceBundles(String name);
34+
void addResourceBundles(ConfigurationCondition condition, String name);
3335
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/CharsetSubstitutionsFeature.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,17 @@
2424
*/
2525
package com.oracle.svm.core.jdk.localization;
2626

27-
import com.oracle.svm.core.annotate.AutomaticFeature;
28-
import com.oracle.svm.core.configure.ResourcesRegistry;
2927
import org.graalvm.nativeimage.ImageSingletons;
3028
import org.graalvm.nativeimage.hosted.Feature;
29+
import org.graalvm.nativeimage.impl.ConfigurationCondition;
30+
31+
import com.oracle.svm.core.annotate.AutomaticFeature;
32+
import com.oracle.svm.core.configure.ResourcesRegistry;
3133

3234
@AutomaticFeature
3335
class CharsetSubstitutionsFeature implements Feature {
3436
@Override
3537
public void beforeAnalysis(BeforeAnalysisAccess access) {
36-
Class<?> clazz = access.findClassByName("java.lang.CharacterName");
37-
access.registerReachabilityHandler(a -> ImageSingletons.lookup(ResourcesRegistry.class).addResources("java/lang/uniName.dat"), clazz);
38+
ImageSingletons.lookup(ResourcesRegistry.class).addResources(ConfigurationCondition.create("java.lang.CharacterName"), "java/lang/uniName.dat");
3839
}
3940
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.graalvm.nativeimage.Platform;
4141
import org.graalvm.nativeimage.Platforms;
4242
import org.graalvm.nativeimage.hosted.RuntimeReflection;
43+
import org.graalvm.nativeimage.impl.ConfigurationCondition;
4344

4445
import com.oracle.svm.core.configure.ResourcesRegistry;
4546
import com.oracle.svm.core.util.VMError;
@@ -91,7 +92,7 @@ public Map<String, Object> getBundleContentOf(Object bundle) {
9192
public void prepareBundle(String bundleName, ResourceBundle bundle, Locale locale) {
9293
if (bundle instanceof PropertyResourceBundle) {
9394
String withLocale = control.toBundleName(bundleName, locale);
94-
ImageSingletons.lookup(ResourcesRegistry.class).addResources(withLocale.replace('.', '/') + "\\.properties");
95+
ImageSingletons.lookup(ResourcesRegistry.class).addResources(ConfigurationCondition.objectReachable(), withLocale.replace('.', '/') + "\\.properties");
9596
} else {
9697
RuntimeReflection.register(bundle.getClass());
9798
RuntimeReflection.registerForReflectiveInstantiation(bundle.getClass());

0 commit comments

Comments
 (0)