Skip to content

Commit 64cac7b

Browse files
authored
Merge pull request #15 from dodgex/13-locator-properties
Add support for webjars-locator.properties
2 parents 063c33a + 688013c commit 64cac7b

File tree

6 files changed

+106
-2
lines changed

6 files changed

+106
-2
lines changed

pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@
9797
<version>3.1.1</version>
9898
<scope>test</scope>
9999
</dependency>
100+
<dependency>
101+
<groupId>org.webjars.bower</groupId>
102+
<artifactId>js-base64</artifactId>
103+
<version>2.3.2</version>
104+
<scope>test</scope>
105+
</dependency>
100106
</dependencies>
101107

102108
<build>

src/main/java/org/webjars/WebJarVersionLocator.java

+39-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
import java.io.IOException;
77
import java.io.InputStream;
8+
import java.net.URL;
9+
import java.util.Enumeration;
10+
import java.util.Map;
811
import java.util.Optional;
912
import java.util.Properties;
1013
import java.util.concurrent.ConcurrentHashMap;
@@ -25,17 +28,22 @@ public class WebJarVersionLocator {
2528
private static final String NPM = "org.webjars.npm/";
2629
private static final String PLAIN = "org.webjars/";
2730
private static final String POM_PROPERTIES = "/pom.properties";
31+
private static final String LOCATOR_PROPERTIES = "META-INF/resources/webjars-locator.properties";
32+
33+
private static final String CACHE_KEY_PREFIX = "version-";
2834

2935
private static final ClassLoader LOADER = WebJarVersionLocator.class.getClassLoader();
3036

3137
private final WebJarCache cache;
3238

3339
public WebJarVersionLocator() {
3440
this.cache = new WebJarCacheDefault(new ConcurrentHashMap<>());
41+
readLocatorProperties();
3542
}
3643

3744
WebJarVersionLocator(WebJarCache cache) {
3845
this.cache = cache;
46+
readLocatorProperties();
3947
}
4048

4149
/**
@@ -83,7 +91,7 @@ public String path(final String webJarName, final String exactPath) {
8391
*/
8492
@Nullable
8593
public String version(final String webJarName) {
86-
final String cacheKey = "version-" + webJarName;
94+
final String cacheKey = CACHE_KEY_PREFIX + webJarName;
8795
final Optional<String> optionalVersion = cache.computeIfAbsent(cacheKey, (key) -> {
8896
InputStream resource = LOADER.getResourceAsStream(PROPERTIES_ROOT + NPM + webJarName + POM_PROPERTIES);
8997
if (resource == null) {
@@ -126,6 +134,36 @@ public String version(final String webJarName) {
126134
return optionalVersion.orElse(null);
127135
}
128136

137+
private void readLocatorProperties() {
138+
try {
139+
Enumeration<URL> resources = LOADER.getResources(LOCATOR_PROPERTIES);
140+
while (resources.hasMoreElements()) {
141+
URL resourceUrl = resources.nextElement();
142+
try (InputStream resource = resourceUrl.openStream()) {
143+
Properties properties = new Properties();
144+
properties.load(resource);
145+
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
146+
String webJarName = entry.getKey().toString();
147+
if (!webJarName.endsWith(".version")) {
148+
// ".version" suffix is required
149+
continue;
150+
}
151+
152+
webJarName = webJarName.substring(0, webJarName.lastIndexOf(".version"));
153+
154+
String version = entry.getValue().toString();
155+
if (hasResourcePath(webJarName, version)) {
156+
// Only add configured versions if their path exists
157+
cache.computeIfAbsent(CACHE_KEY_PREFIX + webJarName, x -> Optional.of(version));
158+
}
159+
}
160+
}
161+
}
162+
} catch (IOException e) {
163+
throw new RuntimeException("unable to load locator properties", e);
164+
}
165+
}
166+
129167
private boolean hasResourcePath(final String webJarName, final String path) {
130168
return LOADER.getResource(WEBJARS_PATH_PREFIX + "/" + webJarName + "/" + path) != null;
131169
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"resources": {
3+
"includes": [
4+
{
5+
"pattern": "\\QMETA-INF/resources/webjars-locator.properties\\E",
6+
"condition": {
7+
"typeReachable": "org.webjars.WebJarVersionLocator"
8+
}
9+
},
10+
{
11+
"pattern": "\\QMETA-INF\/resources\/webjars\/\\E.*",
12+
"condition": {
13+
"typeReachable": "org.webjars.WebJarVersionLocator"
14+
}
15+
},
16+
{
17+
"pattern": "\\QMETA-INF/maven/org.webjars/\\E.*\\Q/pom.properties\\E",
18+
"condition": {
19+
"typeReachable": "org.webjars.WebJarVersionLocator"
20+
}
21+
},
22+
{
23+
"pattern": "\\QMETA-INF/maven/org.webjars.npm/\\E.*\\Q/pom.properties\\E",
24+
"condition": {
25+
"typeReachable": "org.webjars.WebJarVersionLocator"
26+
}
27+
}
28+
]
29+
}
30+
}

src/test/java/org/webjars/WebJarVersionLocatorTest.java

+22-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import java.util.Optional;
1010
import java.util.concurrent.ConcurrentHashMap;
11+
import java.util.concurrent.atomic.AtomicBoolean;
1112
import java.util.concurrent.atomic.AtomicInteger;
1213
import java.util.function.Function;
1314

@@ -23,6 +24,21 @@ void should_get_a_webjar_version() {
2324
assertEquals("3.1.1", new WebJarVersionLocator().version("bootswatch-yeti"));
2425
}
2526

27+
@Test
28+
void should_find_good_custom_webjar_version() {
29+
assertEquals("3.2.1", new WebJarVersionLocator().version("goodwebjar"));
30+
}
31+
32+
@Test
33+
void should_not_find_bad_custom_webjar_version() {
34+
assertNull(new WebJarVersionLocator().version("badwebjar"));
35+
}
36+
37+
@Test
38+
void should_find_bower_webjar_version() {
39+
assertEquals("2.3.2", new WebJarVersionLocator().version("js-base64"));
40+
}
41+
2642
@Test
2743
void webjar_version_doesnt_match_path() {
2844
assertEquals("3.1.1", new WebJarVersionLocator().version("bootstrap"));
@@ -45,6 +61,7 @@ void full_path_exists_version_supplied() {
4561

4662
@Test
4763
void cache_is_populated_on_lookup() {
64+
AtomicBoolean shouldInspect = new AtomicBoolean(false);
4865
AtomicInteger numLookups = new AtomicInteger(0);
4966

5067
@NullMarked
@@ -54,14 +71,18 @@ class InspectableCache implements WebJarCache {
5471
@Override
5572
public Optional<String> computeIfAbsent(String key, Function<String, Optional<String>> function) {
5673
Function<String, Optional<String>> inspectableFunction = function.andThen((value) -> {
57-
numLookups.incrementAndGet();
74+
if(shouldInspect.get()) {
75+
numLookups.incrementAndGet();
76+
}
5877
return value;
5978
});
6079
return cache.computeIfAbsent(key, inspectableFunction);
6180
}
6281
}
6382

6483
final WebJarVersionLocator webJarVersionLocator = new WebJarVersionLocator(new InspectableCache());
84+
// enable inspection after webJarVersionLocator has been constructed, to ignore lookups caused by loading webjars-locator.properties
85+
shouldInspect.set(true);
6586

6687
assertEquals("3.1.1", webJarVersionLocator.version("bootstrap"));
6788
assertEquals(1, numLookups.get());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# WebJar that can be found on classpath
2+
goodwebjar.version=3.2.1
3+
4+
# WebJar that is not present in classpath
5+
badwebjar.version=1.2.3
6+
7+
# Bower Webjar from dependencies
8+
js-base64.version=2.3.2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// Awesome WebJar content

0 commit comments

Comments
 (0)