Skip to content

Commit 1fda5ed

Browse files
committed
support jar-in-jar for dependencies
1 parent 47f58d2 commit 1fda5ed

File tree

4 files changed

+95
-50
lines changed

4 files changed

+95
-50
lines changed

src/main/java/com/falsepattern/lib/internal/Internet.java

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.io.OutputStream;
3232
import java.net.HttpURLConnection;
3333
import java.net.URL;
34+
import java.net.URLConnection;
3435
import java.util.Collections;
3536
import java.util.Map;
3637
import java.util.function.Consumer;
@@ -44,33 +45,12 @@ public static void connect(URL URL, Consumer<Exception> onError, Consumer<InputS
4445

4546
public static void connect(URL URL, Map<String, String> headers, Consumer<Exception> onError, Consumer<InputStream> onSuccess, Consumer<Long> contentLengthCallback) {
4647
try {
47-
val connection = (HttpURLConnection) URL.openConnection();
48-
connection.setConnectTimeout(3500);
49-
connection.setReadTimeout(5000);
50-
connection.setRequestProperty("User-Agent",
51-
Tags.MODNAME
52-
+ " "
53-
+ Tags.VERSION
54-
+ " Internet Connector"
55-
+ " (https://github.com/FalsePattern/FalsePatternLib)");
56-
for (val header : headers.entrySet()) {
57-
val key = header.getKey();
58-
val value = header.getValue();
59-
if (key == null || value == null) {
60-
throw new IllegalArgumentException("Null key or value");
61-
}
62-
if (key.isEmpty()) {
63-
throw new IllegalArgumentException("Empty key");
64-
}
65-
connection.setRequestProperty(key, value);
66-
}
67-
if (connection.getResponseCode() != 200) {
68-
onError.accept(new Exception("HTTP response code " + connection.getResponseCode()));
48+
val urlConnection = URL.openConnection();
49+
if (urlConnection instanceof HttpURLConnection) {
50+
connectHTTP((HttpURLConnection) urlConnection, headers, onError, onSuccess, contentLengthCallback);
6951
} else {
70-
contentLengthCallback.accept(connection.getContentLengthLong());
71-
onSuccess.accept(connection.getInputStream());
52+
executeTransfer(urlConnection, onSuccess, contentLengthCallback);
7253
}
73-
connection.disconnect();
7454
} catch (Exception e) {
7555
//Check if NonUpdate is present
7656
try {
@@ -86,6 +66,39 @@ public static void connect(URL URL, Map<String, String> headers, Consumer<Except
8666
}
8767
}
8868

69+
private static void connectHTTP(HttpURLConnection connection, Map<String, String> headers, Consumer<Exception> onError, Consumer<InputStream> onSuccess, Consumer<Long> contentLengthCallback) throws IOException {
70+
connection.setConnectTimeout(3500);
71+
connection.setReadTimeout(5000);
72+
connection.setRequestProperty("User-Agent",
73+
Tags.MODNAME
74+
+ " "
75+
+ Tags.VERSION
76+
+ " Internet Connector"
77+
+ " (https://github.com/FalsePattern/FalsePatternLib)");
78+
for (val header : headers.entrySet()) {
79+
val key = header.getKey();
80+
val value = header.getValue();
81+
if (key == null || value == null) {
82+
throw new IllegalArgumentException("Null key or value");
83+
}
84+
if (key.isEmpty()) {
85+
throw new IllegalArgumentException("Empty key");
86+
}
87+
connection.setRequestProperty(key, value);
88+
}
89+
if (connection.getResponseCode() != 200) {
90+
onError.accept(new Exception("HTTP response code " + connection.getResponseCode()));
91+
} else {
92+
executeTransfer(connection, onSuccess, contentLengthCallback);
93+
}
94+
connection.disconnect();
95+
}
96+
97+
private static void executeTransfer(URLConnection connection, Consumer<InputStream> onSuccess, Consumer<Long> contentLengthCallback) throws IOException {
98+
contentLengthCallback.accept(connection.getContentLengthLong());
99+
onSuccess.accept(connection.getInputStream());
100+
}
101+
89102
public static void transferAndClose(InputStream is, OutputStream target, Consumer<Integer> downloadSizeCallback)
90103
throws IOException {
91104
var bytesRead = 0;

src/main/java/com/falsepattern/lib/internal/impl/dependencies/DependencyLoaderImpl.java

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ public class DependencyLoaderImpl {
9696
private static final String[] CHECKSUM_TYPES = new String[]{"sha512", "sha256", "sha1", "md5"};
9797
private static final Map<String, Version> loadedLibraries = new ConcurrentHashMap<>();
9898
private static final Map<String, String> loadedLibraryMods = new ConcurrentHashMap<>();
99-
private static final Set<String> mavenRepositories = new ConcurrentSet<>();
99+
private static final Set<String> remoteMavenRepositories = new ConcurrentSet<>();
100+
private static final Set<String> localMavenRepositories = new ConcurrentSet<>();
100101
private static final Logger LOG = LogManager.getLogger(Tags.MODNAME + " Library Loader");
101102

102103
private static final AtomicLong counter = new AtomicLong(0);
@@ -176,7 +177,7 @@ private static void ensureExists(Path directory) {
176177
}
177178

178179
public static void addMavenRepo(String url) {
179-
mavenRepositories.add(url);
180+
remoteMavenRepositories.add(url);
180181
}
181182

182183
private static String bytesToHex(byte[] hash) {
@@ -262,7 +263,7 @@ public static CompletableFuture<Void> loadLibrariesAsync(Library... libraries) {
262263
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
263264
}
264265

265-
private static boolean scanForDepSpecs(URL source, List<URL> output) {
266+
private static boolean scanForDepSpecs(URL source, List<URL> output, List<URL> jijURLs) {
266267
if (!source.getProtocol().equals("file")) {
267268
return false;
268269
}
@@ -274,14 +275,22 @@ private static boolean scanForDepSpecs(URL source, List<URL> output) {
274275
val jarFile = new JarInputStream(inputStream, false)) {
275276
ZipEntry entry;
276277
while ((entry = jarFile.getNextEntry()) != null) {
277-
if (!entry.getName().startsWith("META-INF") || !entry.getName().endsWith(".json")) {
278+
val name = entry.getName();
279+
if (!name.startsWith("META-INF/"))
278280
continue;
279-
}
280-
try {
281-
output.add(new URL("jar:" + source + "!/" + entry.getName()));
282-
found = true;
283-
} catch (MalformedURLException e) {
284-
LOG.error("Failed to add json source {} to dependency source list: {}", entry.getName(), e);
281+
if (name.endsWith(".json") && name.matches("META-INF/\\w+.json")) {
282+
try {
283+
output.add(new URL("jar:" + source + "!/" + entry.getName()));
284+
found = true;
285+
} catch (MalformedURLException e) {
286+
LOG.error("Failed to add json source {} to dependency source list: {}", entry.getName(), e);
287+
}
288+
} else if (name.equals("META-INF/falsepatternlib_repo/")) {
289+
try {
290+
jijURLs.add(new URL("jar:" + source + "!/" + entry.getName()));
291+
} catch (MalformedURLException e) {
292+
LOG.error("Failed to add jar-in-jar repo {}: {}", entry.getName(), e);
293+
}
285294
}
286295
}
287296
} catch (IOException e) {
@@ -306,14 +315,22 @@ private static boolean scanForDepSpecs(URL source, List<URL> output) {
306315
}
307316
try (val files = Files.list(metaInf)) {
308317
found = files.reduce(false, (prev,file) -> {
309-
if (!file.endsWith(".json")) {
310-
return prev;
311-
}
312-
try {
313-
output.add(file.toUri().toURL());
314-
return true;
315-
} catch (MalformedURLException e) {
316-
LOG.error("Failed to add json source {} to dependency source list: {}", file.getFileName(), e);
318+
val entryFileName = file.getFileName().toString();
319+
if (entryFileName.endsWith(".json")) {
320+
try {
321+
output.add(file.toUri().toURL());
322+
return true;
323+
} catch (MalformedURLException e) {
324+
LOG.error("Failed to add json source {} to dependency source list: {}",
325+
file.toString(),
326+
e);
327+
}
328+
} else if (entryFileName.equals("falsepatternlib_repo")) {
329+
try {
330+
jijURLs.add(file.toUri().toURL());
331+
} catch (MalformedURLException e) {
332+
LOG.error("Failed to add jar-in-jar repo {}: {}", file.toString(), e);
333+
}
317334
}
318335
return prev;
319336
}, (a,b) -> a || b);
@@ -420,8 +437,9 @@ private static void scanDeps() {
420437
.filter((url) -> !urlsWithoutDeps.contains(url.toString()))
421438
.collect(Collectors.toList());
422439
val urls = new ArrayList<URL>();
440+
val jijURLs = new ArrayList<URL>();
423441
for (val candidate : candidates) {
424-
if (!scanForDepSpecs(candidate, urls)) {
442+
if (!scanForDepSpecs(candidate, urls, jijURLs)) {
425443
urlsWithoutDeps.add(candidate.toString());
426444
}
427445
}
@@ -459,9 +477,11 @@ private static void scanDeps() {
459477
}).filter(Objects::nonNull).collect(Collectors.toSet());
460478
long end = System.currentTimeMillis();
461479
LOG.debug("Discovered {} dependency source candidates in {}ms", dependencySpecs.size(), end - start);
462-
mavenRepositories.addAll(dependencySpecs.stream()
463-
.flatMap((dep) -> dep.repositories().stream())
464-
.collect(Collectors.toSet()));
480+
remoteMavenRepositories.addAll(dependencySpecs.stream()
481+
.flatMap((dep) -> dep.repositories().stream())
482+
.map(repo -> repo.endsWith("/") ? repo : repo + "/")
483+
.collect(Collectors.toSet()));
484+
localMavenRepositories.addAll(jijURLs.stream().map(URL::toString).map(repo -> repo.endsWith("/") ? repo : repo + "/").collect(Collectors.toSet()));
465485
val artifacts = dependencySpecs.stream()
466486
.map((root) -> new Pair<>(root.source(), root.dependencies()))
467487
.flatMap(pair -> flatMap(pair,
@@ -706,8 +726,13 @@ private void load() {
706726
if (tryLoadingExistingFile()) {
707727
return;
708728
}
729+
for (val repo: localMavenRepositories) {
730+
if (tryDownloadFromMaven(repo)) {
731+
return;
732+
}
733+
}
709734
validateDownloadsAllowed();
710-
for (var repo : mavenRepositories) {
735+
for (var repo : remoteMavenRepositories) {
711736
if (tryDownloadFromMaven(repo)) {
712737
return;
713738
}

src/main/java/com/falsepattern/lib/internal/impl/dependencies/LetsEncryptHelper.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,14 @@ private LetsEncryptHelper() {}
4848
@SuppressWarnings("java:S6437")
4949
public static void replaceSSLContext() {
5050
if (!EarlyConfig.getInstance().enableLetsEncryptRoot()) {
51+
FPLog.LOG.info("[LetsEncryptHelper] Disabled by config");
5152
return;
5253
}
5354
if (patched) {
55+
FPLog.LOG.info("[LetsEncryptHelper] Already patched");
5456
return;
5557
}
58+
FPLog.LOG.info("[LetsEncryptHelper] Starting patcher");
5659
patched = true;
5760

5861
try (val x1 = LetsEncryptHelper.class.getResourceAsStream("/letsencrypt/isrgrootx1.pem");
@@ -79,6 +82,9 @@ public static void replaceSSLContext() {
7982
FPLog.LOG.error("[LetsEncryptHelper] Failed to load certificates from classpath.", e);
8083
} catch (GeneralSecurityException e) {
8184
FPLog.LOG.error("[LetsEncryptHelper] Failed to load default keystore.", e);
85+
} catch (Throwable t) {
86+
FPLog.LOG.error("[LetsEncryptHelper] Unknown error", t);
87+
throw t;
8288
}
8389
}
8490
}

src/main/resources/DEPENDENCIES.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ Explanation:
3939
to recognize it.
4040
- `repositories`: A list of maven repositories to use when downloading dependencies. These are used in addition to the
4141
default maven repositories. This is just a list of strings, each string being a https repository url.
42+
Additionally, every jar with a dependencies json file inside of it is treated as a "jar in jar" maven repository.
43+
This maven repository exists under `META-INF/falsepatternlib_repo/`
4244
- `dependencies`: A categorized list of dependencies.
4345
- The `always` category gets downloaded both inside and outside the dev environment. Usually not needed, as gradle
4446
will automatically download dependencies.
@@ -57,5 +59,4 @@ Each of these categories also have 3 more subcategories:
5759
Each of these subcategories is a list of strings, each string being a maven dependency string. These are the same as
5860
the ones used in the gradle dependencies block. Note that this DOES NOT support the version range syntax, so you must
5961
specify a specific version. For example, `com.example:examplejar:1.0.0` is valid,
60-
but `com.example:examplejar:[1.0.0,2.0.0]`
61-
is not.
62+
but `com.example:examplejar:[1.0.0,2.0.0]` is not.

0 commit comments

Comments
 (0)