2929import java .io .FileInputStream ;
3030import java .io .IOException ;
3131import java .io .InputStream ;
32+ import java .lang .module .ModuleReader ;
33+ import java .lang .module .ModuleReference ;
34+ import java .lang .module .ResolvedModule ;
3235import java .net .URISyntaxException ;
3336import java .net .URL ;
3437import java .net .URLClassLoader ;
3538import java .util .Arrays ;
3639import java .util .Collections ;
3740import java .util .Enumeration ;
3841import java .util .HashSet ;
42+ import java .util .List ;
3943import java .util .Set ;
4044import java .util .concurrent .ConcurrentHashMap ;
4145import java .util .jar .JarEntry ;
4246import java .util .jar .JarFile ;
4347import java .util .regex .Pattern ;
48+ import java .util .stream .Collectors ;
4449
50+ import com .oracle .svm .core .util .VMError ;
4551import org .graalvm .compiler .debug .DebugContext ;
4652import org .graalvm .compiler .options .Option ;
4753import org .graalvm .compiler .options .OptionType ;
54+ import org .graalvm .compiler .serviceprovider .JavaVersionUtil ;
4855import org .graalvm .nativeimage .ImageSingletons ;
4956import org .graalvm .nativeimage .hosted .Feature ;
5057
6067import com .oracle .svm .hosted .FeatureImpl .DuringAnalysisAccessImpl ;
6168import com .oracle .svm .hosted .config .ConfigurationParserUtils ;
6269
70+
6371@ AutomaticFeature
6472public final class ResourcesFeature implements Feature {
6573
6674 public static class Options {
6775 @ Option (help = "Regexp to match names of resources to be included in the image." , type = OptionType .User )//
6876 public static final HostedOptionKey <String []> IncludeResources = new HostedOptionKey <>(new String [0 ]);
77+
78+ @ Option (help = "Print included resources." , type = OptionType .User )//
79+ public static final HostedOptionKey <Boolean > PrintIncludedResources = new HostedOptionKey <>(false );
6980 }
7081
7182 private boolean sealed = false ;
@@ -106,11 +117,20 @@ public void duringAnalysis(DuringAnalysisAccess access) {
106117 if (newResources .isEmpty ()) {
107118 return ;
108119 }
120+
109121 access .requireAnalysisIteration ();
110- for (String regExp : newResources ) {
111- if (regExp .length () == 0 ) {
112- continue ;
113- }
122+ DebugContext debugContext = ((DuringAnalysisAccessImpl ) access ).getDebugContext ();
123+ final Pattern [] patterns = newResources .stream ()
124+ .filter (s -> s .length () > 0 )
125+ .map (Pattern ::compile )
126+ .collect (Collectors .toList ())
127+ .toArray (new Pattern []{});
128+
129+ if (JavaVersionUtil .JAVA_SPEC > 8 ) {
130+ findResourcesInModules (debugContext , patterns );
131+ }
132+
133+ for (Pattern pattern : patterns ) {
114134
115135 /*
116136 * Since IncludeResources takes regular expressions it's safer to disallow passing
@@ -122,8 +142,6 @@ public void duringAnalysis(DuringAnalysisAccess access) {
122142 * @formatter:on
123143 */
124144
125- Pattern pattern = Pattern .compile (regExp );
126-
127145 final Set <File > todo = new HashSet <>();
128146 // Checkstyle: stop
129147 final ClassLoader contextClassLoader = Thread .currentThread ().getContextClassLoader ();
@@ -140,7 +158,6 @@ public void duringAnalysis(DuringAnalysisAccess access) {
140158 // Checkstyle: resume
141159 for (File element : todo ) {
142160 try {
143- DebugContext debugContext = ((DuringAnalysisAccessImpl ) access ).getDebugContext ();
144161 if (element .isDirectory ()) {
145162 scanDirectory (debugContext , element , "" , pattern );
146163 } else {
@@ -157,6 +174,11 @@ public void duringAnalysis(DuringAnalysisAccess access) {
157174 @ Override
158175 public void afterAnalysis (AfterAnalysisAccess access ) {
159176 sealed = true ;
177+ if (Options .PrintIncludedResources .getValue ()) {
178+ for (String registeredResource : Resources .registeredResources ()) {
179+ System .out .println (registeredResource );
180+ }
181+ }
160182 }
161183
162184 @ Override
@@ -184,10 +206,7 @@ private void scanDirectory(DebugContext debugContext, File f, String relativePat
184206 } else {
185207 if (matches (patterns , relativePath )) {
186208 try (FileInputStream is = new FileInputStream (f )) {
187- try (DebugContext .Scope s = debugContext .scope ("registerResource" )) {
188- debugContext .log ("ResourcesFeature: registerResource: " + relativePath );
189- }
190- Resources .registerResource (relativePath , is );
209+ registerResource (debugContext , relativePath , is );
191210 }
192211 }
193212 }
@@ -204,11 +223,25 @@ private static void scanJar(DebugContext debugContext, File element, Pattern...
204223 }
205224 if (matches (patterns , e .getName ())) {
206225 try (InputStream is = jf .getInputStream (e )) {
207- try (DebugContext .Scope s = debugContext .scope ("registerResource" )) {
208- debugContext .log ("ResourcesFeature: registerResource: " + e .getName ());
209- }
210- Resources .registerResource (e .getName (), is );
226+ registerResource (debugContext , e .getName (), is );
227+ }
228+ }
229+ }
230+ }
231+
232+ private static void findResourcesInModules (DebugContext debugContext , Pattern [] patterns ) {
233+ for (ResolvedModule resolvedModule : ModuleLayer .boot ().configuration ().modules ()) {
234+ ModuleReference modRef = resolvedModule .reference ();
235+ try (ModuleReader moduleReader = modRef .open ()) {
236+ final List <String > resources = moduleReader .list ()
237+ .filter (s -> matches (patterns , s ))
238+ .collect (Collectors .toList ());
239+ for (String resName : resources ) {
240+ moduleReader .open (resName )
241+ .ifPresent (is -> registerResource (debugContext , resName , is ));
211242 }
243+ } catch (IOException ex ) {
244+ VMError .shouldNotReachHere ("Can not read the resources of module" , ex );
212245 }
213246 }
214247 }
@@ -221,4 +254,10 @@ private static boolean matches(Pattern[] patterns, String relativePath) {
221254 }
222255 return false ;
223256 }
257+
258+ private static void registerResource (DebugContext debugContext , String resourceName , InputStream resourceStream ) {
259+ debugContext .log (DebugContext .VERBOSE_LEVEL , "ResourcesFeature: registerResource: " + resourceName );
260+ Resources .registerResource (resourceName , resourceStream );
261+ }
262+
224263}
0 commit comments