Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import org.terasology.launcher.util.LauncherDirectoryUtils;
import org.terasology.launcher.util.LauncherManagedDirectory;
import org.terasology.launcher.util.LauncherStartFailedException;
import org.terasology.launcher.util.Platform;
import org.terasology.launcher.platform.Platform;

import java.io.IOException;
import java.net.URI;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
import org.terasology.launcher.util.JavaHeapSize;
import org.terasology.launcher.util.Platform;
import org.terasology.launcher.platform.Platform;

import java.io.IOException;
import java.nio.file.Path;
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/org/terasology/launcher/jre/JREArtefact.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2023 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.launcher.jre;

import org.terasology.launcher.platform.Platform;

//TODO(Java17): make this a 'record'
public final class JREArtefact {

public final String url;
public final String checksum;
public final Platform platform;
public final int version;

public JREArtefact(int version, Platform platform,String url, String checksum) {
this.url = url;
this.checksum = checksum;
this.platform = platform;
this.version = version;
}
}
88 changes: 88 additions & 0 deletions src/main/java/org/terasology/launcher/jre/ManagedJRE.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright 2023 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.launcher.jre;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.terasology.launcher.platform.Arch;
import org.terasology.launcher.platform.OS;
import org.terasology.launcher.platform.Platform;

import java.util.HashSet;
import java.util.Set;

public final class ManagedJRE {

public static final Set<Integer> SUPPORTED_JAVA_VERSIONS = Sets.newHashSet(8, 11, 17);

private static final Set<JREArtefact> supportedJavaVersions;
Comment on lines +17 to +19
Copy link
Member Author

Choose a reason for hiding this comment

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

Hm, bad naming 🤔 SUPPORTED_JAVA_VERSIONS denotes all the major Java versions we may need, while supportedJavaVersions is actually something like jreInfoForAllSupportedPlatformsAndJavaVersions - what a mouthful!


static {
supportedJavaVersions = new HashSet<>();


supportedJavaVersions.addAll(
Lists.newArrayList(
// Linux
new JREArtefact(8,
new Platform(OS.LINUX, Arch.X64),
"https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u392-b08/OpenJDK8U-jre_x64_linux_hotspot_8u392b08.tar.gz",
"91d31027da0d985be3549714389593d9e0da3da5057d87e3831c7c538b9a2a0f"
),
new JREArtefact(11,
new Platform(OS.LINUX, Arch.X64),
"https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.21%2B9/OpenJDK11U-jre_x64_linux_hotspot_11.0.21_9.tar.gz",
"156861bb901ef18759e05f6f008595220c7d1318a46758531b957b0c950ef2c3"
),
new JREArtefact(17,
new Platform(OS.LINUX, Arch.X64),
"https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9%2B9.1/OpenJDK17U-jre_x64_linux_hotspot_17.0.9_9.tar.gz",
"c37f729200b572884b8f8e157852c739be728d61d9a1da0f920104876d324733"
),
// Mac
new JREArtefact(8,
new Platform(OS.MAC, Arch.X64),
"https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u392-b08/OpenJDK8U-jre_x64_mac_hotspot_8u392b08.tar.gz",
"f1f15920ed299e10c789aef6274d88d45eb21b72f9a7b0d246a352107e344e6a"
),
new JREArtefact(11,
new Platform(OS.MAC, Arch.X64),
"https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.21%2B9/OpenJDK11U-jre_x64_mac_hotspot_11.0.21_9.tar.gz",
"43d29affe994a09de31bf2fb6f8ab6d6792ba4267b9a2feacaa1f6e042481b9b"
),
new JREArtefact(17,
new Platform(OS.MAC, Arch.X64),
"https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9%2B9.1/OpenJDK17U-jre_x64_mac_hotspot_17.0.9_9.tar.gz",
"c69b37ea72136df49ce54972408803584b49b2c91b0fbc876d7125e963c7db37"
),
// Window
new JREArtefact(8,
new Platform(OS.WINDOWS, Arch.X64),
"https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u392-b08/OpenJDK8U-jre_x64_mac_hotspot_8u392b08.tar.gz",
"a6b7e671cc12f9fc16db59419bda8be00da037e14aaf5d5afb78042c145b76ed"
),
new JREArtefact(11,
new Platform(OS.WINDOWS, Arch.X64),
"https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.21%2B9/OpenJDK11U-jre_x64_windows_hotspot_11.0.21_9.zip",
"a93d8334a85f6cbb228694346aad0353a8cb9ff3c84b5dc3221daf2c54a11e54"
),
new JREArtefact(17,
new Platform(OS.WINDOWS, Arch.X64),
"https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9%2B9.1/OpenJDK17U-jre_x64_windows_hotspot_17.0.9_9.zip",
"6c491d6f8c28c6f451f08110a30348696a04b009f8c58592191046e0fab1477b"
)
Comment on lines +28 to +74
Copy link
Member Author

Choose a reason for hiding this comment

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

I tried for some time to be "smart" about assembling the URL, but that became so much code in the end I don't think it's worth it in a list that we will rarely update or extend.

The main issues are:

  • different format of Java version for Java 8 (e.g. 8u392-b08) and new versions (e.g. 17.0.0+9.1)
  • different ways this version is encoded in the URL
    • for Java 8 it's jdk8u392-b08 for the jdk path element and 8u392b08 in the artifact version
    • for Java 17 its's URL encoded 17.0.9%2B9.1 in the jdk path element (with full 9.1 build version) and 17.0.9_9in the artifact version (with only the major build version 9)
  • the major version is also referenced alone

So while we can write some Regex to handle that, compute the correct suffix, etc, I think that just maintaining these lists by hand is probably a better solution.

));

for (var v : supportedJavaVersions) {
System.out.println(v.url);
}
}

public static JREArtefact getJreFor(Platform platform, int version) throws UnsupportedJREException {
return supportedJavaVersions.stream()
.filter(jre -> jre.platform.equals(platform) && jre.version == version)
.findFirst()
.orElseThrow(() -> new UnsupportedJREException(platform, version));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2023 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.launcher.jre;

import org.terasology.launcher.platform.Platform;

public class UnsupportedJREException extends Exception {
private Platform platform;
private int version;

public UnsupportedJREException(Platform platform, int version) {
this.platform = platform;
this.version = version;
}

@Override
public String getMessage() {
return "UnsupportedJre: No managed JRE supported for Java version " + version + " and platform " + platform;
}
}
9 changes: 9 additions & 0 deletions src/main/java/org/terasology/launcher/platform/Arch.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright 2023 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.launcher.platform;

public enum Arch {
X64,
X86;
}
10 changes: 10 additions & 0 deletions src/main/java/org/terasology/launcher/platform/OS.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright 2023 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.launcher.platform;

public enum OS {
WINDOWS,
MAC,
LINUX;
}
Original file line number Diff line number Diff line change
@@ -1,70 +1,87 @@
// Copyright 2020 The Terasology Foundation
// Copyright 2023 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.launcher.util;
package org.terasology.launcher.platform;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import java.util.List;
import java.util.Set;

/**
* A simplified representation of a computer platform as `os` and `arch`
*/
public final class Platform {
public static final Set<Platform> SUPPORTED_PLATFORMS = Sets.newHashSet(
new Platform(OS.WINDOWS, Arch.X64),
new Platform(OS.LINUX, Arch.X64),
new Platform(OS.MAC, Arch.X64)
);

private static final Platform PLATFORM = new Platform();

private String os;
private String arch;
private final OS os;
private final Arch arch;

/**
* Constructs platform information for the current host system.
* Simplifies operating system name to one of `linux`, `mac`, `windows` if applicable.
* Simplifies operating system architecture to one of `32` and `64` if applicable.
*/
private Platform() {
private Platform() throws UnsupportedPlatformException{
final String platformOs = System.getProperty("os.name").toLowerCase();
// TODO: consider using regex
if (platformOs.startsWith("linux")) {
os = "linux";
os = OS.LINUX;
} else if (platformOs.startsWith("mac os")) {
os = "mac";
os = OS.MAC;
} else if (platformOs.startsWith("windows")) {
os = "windows";
os = OS.WINDOWS;
} else {
os = platformOs;
throw new UnsupportedPlatformException();
}

final String platformArch = System.getProperty("os.arch");
if (platformArch.equals("x86_64") || platformArch.equals("amd64")) {
arch = "64";
arch = Arch.X64;
} else if (platformArch.equals("x86") || platformArch.equals("i386")) {
arch = "32";
arch = Arch.X86;
} else {
arch = platformArch;
arch = Arch.X64;
//TODO: throw new UnsupportedPlatformException();
Copy link
Member Author

Choose a reason for hiding this comment

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

Little hack for me to be able to develop on M1 Mac 😕 With this in place, the static platform initialisation will throw an exception and I cannot even run the tests.

I think this is kind of nice, because we can detect whether running the launcher would have make any sense on that platform or fail early on, but it is a bit annoying for development.

The brain split situation here is that the launcher can run on more platforms than the actual game. Maybe I'll add a "development mode" to be able to start the launcher on your own risk 🤔

}
}

public Platform(OS os, Arch arch) {
this.os = os;
this.arch = arch;
}

/**
* @return the simplified operating system name as platform os
*/
public String getOs() {
return os;
return os.name().toLowerCase();
}

/**
* @return the simplified operating system architecture as platform arch
*/
public String getArch() {
return arch;
return arch.name().toLowerCase();
}

public boolean isLinux() {
return os.equals("linux");
return os.equals(OS.LINUX);
}

public boolean isMac() {
return os.equals("mac");
return os.equals(OS.MAC);
}

public boolean isWindows() {
return os.equals("windows");
return os.equals(OS.WINDOWS);
}

public String toString() {
Expand All @@ -79,4 +96,22 @@ public String toString() {
public static Platform getPlatform() {
return PLATFORM;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Platform platform = (Platform) o;

if (os != platform.os) return false;
return arch == platform.arch;
}
Comment on lines +101 to +109
Copy link
Member Author

Choose a reason for hiding this comment

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

Previously, we only checked whether we are on a specific platform and had no means to create new instances of this class. Now that we want to manage the JRE for multiple platforms we have to open this up a bit.


@Override
public int hashCode() {
int result = os != null ? os.hashCode() : 0;
result = 31 * result + (arch != null ? arch.hashCode() : 0);
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright 2023 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.launcher.platform;

public class UnsupportedPlatformException extends RuntimeException {
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.launcher.platform.Platform;

import java.io.IOException;
import java.net.URISyntaxException;
Expand Down
26 changes: 26 additions & 0 deletions src/test/java/org/terasology/launcher/jre/ManagedJRETest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2023 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.launcher.jre;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.terasology.launcher.platform.Platform;

import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

class ManagedJRETest {

@ParameterizedTest(name = "JRE in version {1} available for platform {0}")
@MethodSource("provideSupportedPlatforms")
void testJresForAllSupportedPlatforms(Platform platform, Integer javaVersion) {
assertDoesNotThrow(() -> ManagedJRE.getJreFor(platform, javaVersion));
}

private static Stream<Arguments> provideSupportedPlatforms() {
return Platform.SUPPORTED_PLATFORMS.stream().flatMap(p -> ManagedJRE.SUPPORTED_JAVA_VERSIONS.stream().map(v -> Arguments.of(p, v)));
}
Comment on lines +17 to +25
Copy link
Member Author

Choose a reason for hiding this comment

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

First round of tests to ensure that for all the supported platforms and java versions a respective entry is added to ManagedJRE.supportedJavaVersions.

I don't think we should try to download all of these in a regular test run, but we should have a "pre-release test" that tries to download all of these and validate their checksums. For the start, this can be a manual task.

}