Skip to content
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

Add support for locator.properties #15

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

dodgex
Copy link

@dodgex dodgex commented Oct 11, 2024

With this PR I want to bring up a possible implementation for supporting legacy and custom webjars with webjars-locator-lite. I started the related discussion in #13.

Unfortunately there was no decision on how to implement this feature in the related issue, therefore I tried to come up with something based on the suggestions.

The Implementation provided by this PR looks for META-INF/webjars/locator.properties files on the classpath and then reads them into a Properties instance. I decided to use a pattern of WEBJAR_NAME.version as key in the properties file to have the option to add other properties in the future (and be more specific about the purpose of the property -> providing a version). The value for each key has to be the version of the webjar as used in the resulting path.

When reading the locator.properties the .version suffix is removed and the given version is put into the cache. Before adding a given webjar version to the cache, it checks if the resulting path exists.

The files are loaded in whatever order LOADER.getResources() returns them.

With this change, it is possible to support any legacy (e.g. bower) or custom webjar, as long as the basic path structure is valid (META-INF/resources/webjars/WEBJAR/VERSION/any/folder/or.file)

@@ -25,17 +28,22 @@ public class WebJarVersionLocator {
private static final String NPM = "org.webjars.npm/";
private static final String PLAIN = "org.webjars/";
private static final String POM_PROPERTIES = "/pom.properties";
private static final String LOCATOR_PROPERTIES = "/locator.properties";

private static final String CACHE_KEY_PREFIX = "version-";
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this to avoid duplication of the string

}
}
} catch (IOException e) {
throw new RuntimeException("unable to load locator properties", e);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this exception should be rethrown, logged or just ignored (similar to version()). For now I opted for throwing.

return value;
});
return cache.computeIfAbsent(key, inspectableFunction);
}
}

final WebJarVersionLocator webJarVersionLocator = new WebJarVersionLocator(new InspectableCache());
// enable inspection after webJarVersionLocator has been constructed, to ignore lookups caused by loading locator.properties
shouldInspect.set(true);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My first Idea was to modifiy the assertEquals calls for numLookups but I think that this is a better solution.

}
}
} catch (IOException e) {
throw new RuntimeException("unable to load locator properties", e);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this Exception should only happen if the the locator.properties was found but could not be read. So we should be good if there is no locator.properties - is that right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, LOADER.getResources returns an empty Enumeration when there are no files found. I verified that by removing the locator.properties from test resources.

@jamesward
Copy link
Member

Thanks for tackling this! Overall I think this looks good. Does this address everything you need for #13?

@dodgex
Copy link
Author

dodgex commented Oct 13, 2024

Yeah, I am pretty sure, that this should be a proper solution for #13.

Due to the fact, that all webjars should have thier content in META-INF/resources/webjars/{webjar}/{version}/* providing pairs of webjar and version to the locator and its cache is enough to find the resources. This way we can bypass the need to scan in META-INF/maven/ for the pom.properties of non standard group ids. And at the same it also fixes the fact that our custom webjars have a diffrent artifact id (camera-module-webjar) than the webjar name in the resources folder (camera-module).

I'm not sure about the performance impacts of the two variants, but maybe the locator.properties could even be something to add to new webjars for the future by default and have the pom.properties as fallback for older webjars? But that is another topic. :)

@jamesward
Copy link
Member

Thanks! Since this is a change we'd like to have integrated into Spring, @dsyer want to review?

@dsyer
Copy link

dsyer commented Oct 14, 2024

If I’m reading it correctly this locator properties file kicks in whenever it is present (and mostly it would not be). So users don’t have to do anything unless they want to provide locator properties themselves, but libraries might do that for them most commonly. If all that is correct there’s nothing to be done to integrate with existing usage.

@bclozel
Copy link

bclozel commented Oct 14, 2024

I don't know if supporting GraalVM native images is in the scope of this library; if that's the case, I would suggest adding the following file src/main/resources/META-INF/native-image/org.webjars/webjars-locator-lite/resource-config.json with content:

{
    "resources": {
        "includes": [
            {
                "pattern": "\\QMETA-INF/webjars/locator.properties\\E",
                "condition": {
                    "typeReachable": "org.webjars.WebJarVersionLocator"
                }
            }
        ]
    }
}

@sdeleuze
Copy link

+1 for @bclozel proposal as well as doing a real test of a Spring application compiled to native to check this PR does not break native support (which was one of the goal of webjars-locator-lite).

@dodgex
Copy link
Author

dodgex commented Oct 14, 2024

If I’m reading it correctly this locator properties file kicks in whenever it is present (and mostly it would not be). So users don’t have to do anything unless they want to provide locator properties themselves, but libraries might do that for them most commonly. If all that is correct there’s nothing to be done to integrate with existing usage.

@dsyer Correct. As of now, the file would only be present if a user is adding it to support legacy webjars that would otherwise not be found, or by non-standard 3rd-party webjars. In theory, official webjars COULD provide the file going forward, but that is up to @jamesward or the webjars team to decide.

Regarding native-image, I think if it is just about adding that json file, I would say we should go for it. but that again is up to james to decide.

@bclozel @sdeleuze as I have no experience with graalvm/native-image at all, it would be awesome if one of you guys could help out with doing a native test for this.

@jamesward
Copy link
Member

Thanks all! Yes, we definitely want to make sure this is all compatible with native image. So a test would be great. It's a bit of a lift and we should do it. In the meantime, question for @bclozel and @sdeleuze - if we include the resource-config, it is ok if the referenced file (locator.properties) comes from outside this library, right?

@jamesward
Copy link
Member

btw, thanks all! you're amazing and I really appreciate your support!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants