mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2025-09-07 11:31:25 -04:00
Merge branch 'v3_openjdk' into fix/incorrect-accountjson-encoding-crash
Signed-off-by: Eva Isabella Luna <me@crystall1ne.dev>
This commit is contained in:
commit
200343885c
@ -4,7 +4,7 @@
|
||||
|
||||
[](https://github.com/AngelAuraMC/Amethyst-Android/actions)
|
||||
[](https://github.com/AngelAuraMC/Amethyst-Android/actions)
|
||||
[](https://crowdin.com/project/amethyst)
|
||||
[](https://crowdin.com/project/pojavlauncher)
|
||||
[](https://discord.gg/5ptqkyZxEy)
|
||||
|
||||
*From [Boardwalk](https://github.com/zhuowei/Boardwalk)'s ashes and [PojavLauncher](https://github.com/PojavLauncherTeam/PojavLauncher)'s ruined reputation, here comes Amethyst!*
|
||||
|
Binary file not shown.
@ -1 +1 @@
|
||||
53f2f037cef9b7447a6abbdf82150ca8a2f2a587
|
||||
2016eba00f043842122d7aecb9410cf9371a7693
|
@ -17,7 +17,6 @@ import androidx.fragment.app.Fragment;
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
import net.kdt.pojavlaunch.extra.ExtraCore;
|
||||
import net.kdt.pojavlaunch.mirrors.DownloadMirror;
|
||||
import net.kdt.pojavlaunch.modloaders.ModloaderDownloadListener;
|
||||
import net.kdt.pojavlaunch.modloaders.ModloaderListenerProxy;
|
||||
import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper;
|
||||
@ -106,7 +105,7 @@ public abstract class ModVersionListFragment<T> extends Fragment implements Runn
|
||||
Object forgeVersion = expandableListView.getExpandableListAdapter().getChild(i, i1);
|
||||
ModloaderListenerProxy taskProxy = new ModloaderListenerProxy();
|
||||
Runnable downloadTask = createDownloadTask(forgeVersion, taskProxy);
|
||||
setTaskProxy(taskProxy);
|
||||
setTaskProxyValue(taskProxy);
|
||||
taskProxy.attachListener(this);
|
||||
mExpandableListView.setEnabled(false);
|
||||
new Thread(downloadTask).start();
|
||||
@ -118,7 +117,7 @@ public abstract class ModVersionListFragment<T> extends Fragment implements Runn
|
||||
Tools.runOnUiThread(()->{
|
||||
Context context = requireContext();
|
||||
getTaskProxy().detachListener();
|
||||
setTaskProxy(null);
|
||||
deleteTaskProxy();
|
||||
mExpandableListView.setEnabled(true);
|
||||
// Read the comment in FabricInstallFragment.onDownloadFinished() to see how this works
|
||||
getParentFragmentManager().popBackStackImmediate();
|
||||
@ -131,7 +130,7 @@ public abstract class ModVersionListFragment<T> extends Fragment implements Runn
|
||||
Tools.runOnUiThread(()->{
|
||||
Context context = requireContext();
|
||||
getTaskProxy().detachListener();
|
||||
setTaskProxy(null);
|
||||
deleteTaskProxy();
|
||||
mExpandableListView.setEnabled(true);
|
||||
Tools.dialog(context,
|
||||
context.getString(R.string.global_error),
|
||||
@ -144,15 +143,18 @@ public abstract class ModVersionListFragment<T> extends Fragment implements Runn
|
||||
Tools.runOnUiThread(()->{
|
||||
Context context = requireContext();
|
||||
getTaskProxy().detachListener();
|
||||
setTaskProxy(null);
|
||||
deleteTaskProxy();
|
||||
mExpandableListView.setEnabled(true);
|
||||
Tools.showError(context, e);
|
||||
});
|
||||
}
|
||||
|
||||
private void setTaskProxy(ModloaderListenerProxy proxy) {
|
||||
private void setTaskProxyValue(ModloaderListenerProxy proxy) {
|
||||
ExtraCore.setValue(mExtraTag, proxy);
|
||||
}
|
||||
private void deleteTaskProxy(){
|
||||
ExtraCore.removeValue(mExtraTag);
|
||||
}
|
||||
|
||||
private ModloaderListenerProxy getTaskProxy() {
|
||||
return (ModloaderListenerProxy) ExtraCore.getValue(mExtraTag);
|
||||
|
@ -0,0 +1,80 @@
|
||||
package net.kdt.pojavlaunch.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.ExpandableListAdapter;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import net.kdt.pojavlaunch.JavaGUILauncherActivity;
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
import net.kdt.pojavlaunch.modloaders.ForgeDownloadTask;
|
||||
import net.kdt.pojavlaunch.modloaders.ForgeUtils;
|
||||
import net.kdt.pojavlaunch.modloaders.ModloaderListenerProxy;
|
||||
import net.kdt.pojavlaunch.modloaders.NeoForgeDownloadTask;
|
||||
import net.kdt.pojavlaunch.modloaders.NeoForgeVersionListAdapter;
|
||||
import net.kdt.pojavlaunch.utils.DownloadUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class NeoForgeInstallFragment extends ModVersionListFragment<List<String>> {
|
||||
public static final String TAG = "NeoForgeInstallFragment";
|
||||
public NeoForgeInstallFragment() {
|
||||
super(TAG);
|
||||
}
|
||||
|
||||
private static final String NEOFORGE_METADATA_URL = "https://meta.prismlauncher.org/v1/net.neoforged/index.json";
|
||||
|
||||
|
||||
@Override
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTitleText() {
|
||||
return R.string.neoforge_dl_select_version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNoDataMsg() {
|
||||
return R.string.neoforge_dl_no_installer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> loadVersionList() {
|
||||
String test = null;
|
||||
try {
|
||||
test = DownloadUtils.downloadStringCached(NEOFORGE_METADATA_URL, "neoforge_versions", input -> input);
|
||||
} catch (Exception e) {
|
||||
Tools.showErrorRemote(e);
|
||||
}
|
||||
return Collections.singletonList(test);
|
||||
// Moved the parsing logic to the adapter because there is no way to get this info easily, we use prism's index
|
||||
// since neoforge doesn't actually give this information easily anywhere.
|
||||
// To clarify, neoforge does not provide maven APIs to get supported Minecraft versions for each loader version
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpandableListAdapter createAdapter(List<String> versionList, LayoutInflater layoutInflater) {
|
||||
return new NeoForgeVersionListAdapter(versionList, layoutInflater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Runnable createDownloadTask(Object selectedVersion, ModloaderListenerProxy listenerProxy) {
|
||||
return new NeoForgeDownloadTask(listenerProxy, (String) selectedVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownloadFinished(Context context, File downloadedFile) {
|
||||
Intent modInstallerStartIntent = new Intent(context, JavaGUILauncherActivity.class);
|
||||
modInstallerStartIntent.putExtra("javaArgs", "-jar "+downloadedFile.getAbsolutePath()+" --install-client");
|
||||
context.startActivity(modInstallerStartIntent);
|
||||
}
|
||||
}
|
@ -36,6 +36,8 @@ public class ProfileTypeSelectFragment extends Fragment {
|
||||
tryInstall(FabricInstallFragment.class, FabricInstallFragment.TAG));
|
||||
view.findViewById(R.id.modded_profile_forge).setOnClickListener((v)->
|
||||
tryInstall(ForgeInstallFragment.class, ForgeInstallFragment.TAG));
|
||||
view.findViewById(R.id.modded_profile_neoforge).setOnClickListener((v)->
|
||||
tryInstall(NeoForgeInstallFragment.class, NeoForgeInstallFragment.TAG));
|
||||
view.findViewById(R.id.modded_profile_modpack).setOnClickListener((v)->
|
||||
tryInstall(SearchModFragment.class, SearchModFragment.TAG));
|
||||
view.findViewById(R.id.modded_profile_quilt).setOnClickListener((v)->
|
||||
|
@ -0,0 +1,88 @@
|
||||
package net.kdt.pojavlaunch.modloaders;
|
||||
|
||||
import com.kdt.mcgui.ProgressLayout;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.Tools;
|
||||
import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper;
|
||||
import net.kdt.pojavlaunch.utils.DownloadUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class NeoForgeDownloadTask implements Runnable, Tools.DownloaderFeedback {
|
||||
private String mDownloadUrl;
|
||||
private String mFullVersion;
|
||||
private String mLoaderVersion;
|
||||
private String mGameVersion;
|
||||
private final ModloaderDownloadListener mListener;
|
||||
public NeoForgeDownloadTask(ModloaderDownloadListener listener, String forgeVersion) {
|
||||
this.mListener = listener;
|
||||
this.mDownloadUrl = "https://maven.neoforged.net/releases/net/neoforged/neoforge/"+ forgeVersion +"/neoforge-"+forgeVersion+"-installer.jar";
|
||||
this.mFullVersion = forgeVersion;
|
||||
}
|
||||
|
||||
public NeoForgeDownloadTask(ModloaderDownloadListener listener, String gameVersion, String loaderVersion) {
|
||||
this.mListener = listener;
|
||||
this.mLoaderVersion = loaderVersion;
|
||||
this.mGameVersion = gameVersion;
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
if(determineDownloadUrl()) {
|
||||
downloadForge();
|
||||
}
|
||||
ProgressLayout.clearProgress(ProgressLayout.INSTALL_MODPACK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProgress(int curr, int max) {
|
||||
int progress100 = (int)(((float)curr / (float)max)*100f);
|
||||
ProgressKeeper.submitProgress(ProgressLayout.INSTALL_MODPACK, progress100, R.string.forge_dl_progress, mFullVersion);
|
||||
}
|
||||
|
||||
private void downloadForge() {
|
||||
ProgressKeeper.submitProgress(ProgressLayout.INSTALL_MODPACK, 0, R.string.forge_dl_progress, mFullVersion);
|
||||
try {
|
||||
File destinationFile = new File(Tools.DIR_CACHE, "neoforge-installer.jar");
|
||||
byte[] buffer = new byte[8192];
|
||||
DownloadUtils.downloadFileMonitored(mDownloadUrl, destinationFile, buffer, this);
|
||||
mListener.onDownloadFinished(destinationFile);
|
||||
}catch (FileNotFoundException e) {
|
||||
mListener.onDataNotAvailable();
|
||||
} catch (IOException e) {
|
||||
mListener.onDownloadError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean determineDownloadUrl() {
|
||||
if(mDownloadUrl != null && mFullVersion != null) return true;
|
||||
ProgressKeeper.submitProgress(ProgressLayout.INSTALL_MODPACK, 0, R.string.forge_dl_searching);
|
||||
try {
|
||||
if(!findVersion()) {
|
||||
mListener.onDataNotAvailable();
|
||||
return false;
|
||||
}
|
||||
}catch (IOException e) {
|
||||
mListener.onDownloadError(e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean findVersion() throws IOException {
|
||||
List<String> forgeVersions = ForgeUtils.downloadForgeVersions();
|
||||
if(forgeVersions == null) return false;
|
||||
String versionStart = mGameVersion+"-"+mLoaderVersion;
|
||||
for(String versionName : forgeVersions) {
|
||||
if(!versionName.startsWith(versionStart)) continue;
|
||||
mFullVersion = versionName;
|
||||
mDownloadUrl = ForgeUtils.getInstallerUrl(mFullVersion);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
package net.kdt.pojavlaunch.modloaders;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseExpandableListAdapter;
|
||||
import android.widget.ExpandableListAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
||||
public class NeoForgeVersionListAdapter extends BaseExpandableListAdapter implements ExpandableListAdapter {
|
||||
private final LayoutInflater mLayoutInflater;
|
||||
private final LinkedHashMap<String, LinkedHashSet<String>> minecraftToLoaderVersionsHashmap;
|
||||
private LinkedHashSet<String> generatedHashSet = null;
|
||||
|
||||
|
||||
public NeoForgeVersionListAdapter(List<String> forgeVersions, LayoutInflater layoutInflater) {
|
||||
this.mLayoutInflater = layoutInflater;
|
||||
minecraftToLoaderVersionsHashmap = new LinkedHashMap<>();
|
||||
JsonArray versionsJsonArray = JsonParser.parseString(forgeVersions.get(0)).getAsJsonObject().getAsJsonArray("versions");
|
||||
|
||||
ArrayList<JsonElement> sortedVersionsList = new ArrayList<>();
|
||||
for (JsonElement elem : versionsJsonArray) {
|
||||
sortedVersionsList.add(elem);
|
||||
}
|
||||
Collections.sort(sortedVersionsList, (o1, o2) -> {
|
||||
String versionString1 = ((JsonObject) o1).get("requires").getAsJsonArray().get(0).getAsJsonObject().get("equals").getAsString();
|
||||
String versionString2 = ((JsonObject) o2).get("requires").getAsJsonArray().get(0).getAsJsonObject().get("equals").getAsString();
|
||||
return versionString2.compareTo(versionString1); // Sorts by Minecraft version
|
||||
});
|
||||
|
||||
for (JsonElement sortedVersionPick : sortedVersionsList) {
|
||||
String loaderVersion = ((JsonObject) sortedVersionPick).get("version").getAsString();
|
||||
String minecraftVersion = ((JsonObject) sortedVersionPick).get("requires").getAsJsonArray().get(0).getAsJsonObject().get("equals").getAsString();
|
||||
if (minecraftToLoaderVersionsHashmap.containsKey(minecraftVersion)) {
|
||||
minecraftToLoaderVersionsHashmap.get(minecraftVersion).add(loaderVersion);
|
||||
} else {
|
||||
generatedHashSet = new LinkedHashSet<>();
|
||||
generatedHashSet.add(loaderVersion);
|
||||
minecraftToLoaderVersionsHashmap.put(minecraftVersion, generatedHashSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public int getGroupCount() {
|
||||
return minecraftToLoaderVersionsHashmap.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildrenCount(int i) {
|
||||
return new ArrayList<>(minecraftToLoaderVersionsHashmap.values()).get(i).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGroup(int i) {
|
||||
return getGameVersion(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getChild(int i, int i1) {
|
||||
return getForgeVersion(i, i1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getGroupId(int i) {
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getChildId(int i, int i1) {
|
||||
return i1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getGroupView(int i, boolean b, View convertView, ViewGroup viewGroup) {
|
||||
if(convertView == null)
|
||||
convertView = mLayoutInflater.inflate(android.R.layout.simple_expandable_list_item_1, viewGroup, false);
|
||||
|
||||
((TextView) convertView).setText(getGameVersion(i));
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getChildView(int i, int i1, boolean b, View convertView, ViewGroup viewGroup) {
|
||||
if(convertView == null)
|
||||
convertView = mLayoutInflater.inflate(android.R.layout.simple_expandable_list_item_1, viewGroup, false);
|
||||
((TextView) convertView).setText(getForgeVersion(i, i1));
|
||||
return convertView;
|
||||
}
|
||||
|
||||
private String getGameVersion(int i) {
|
||||
return minecraftToLoaderVersionsHashmap.keySet().toArray()[i].toString();
|
||||
}
|
||||
|
||||
private String getForgeVersion(int i, int i1){
|
||||
return new ArrayList<>(minecraftToLoaderVersionsHashmap.values()).get(i).toArray()[i1].toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChildSelectable(int i, int i1) {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ public class AsyncVersionList {
|
||||
|
||||
public void getVersionList(@Nullable VersionDoneListener listener, boolean secondPass){
|
||||
sExecutorService.execute(() -> {
|
||||
File versionFile = new File(Tools.DIR_DATA + "/version_list.json");
|
||||
File versionFile = new File(Tools.DIR_CACHE + "/version_list.json");
|
||||
JMinecraftVersionList versionList = null;
|
||||
try{
|
||||
if(!versionFile.exists() || (System.currentTimeMillis() > versionFile.lastModified() + 86400000 )){
|
||||
@ -68,7 +68,7 @@ public class AsyncVersionList {
|
||||
|
||||
// Then save the version list
|
||||
//TODO make it not save at times ?
|
||||
FileOutputStream fos = new FileOutputStream(Tools.DIR_DATA + "/version_list.json");
|
||||
FileOutputStream fos = new FileOutputStream(Tools.DIR_CACHE + "/version_list.json");
|
||||
fos.write(jsonString.getBytes());
|
||||
fos.close();
|
||||
|
||||
|
@ -103,6 +103,14 @@
|
||||
android:layout_marginTop="@dimen/padding_large"
|
||||
android:text="@string/modloader_dl_install_forge" />
|
||||
|
||||
<com.kdt.mcgui.MineButton
|
||||
android:id="@+id/modded_profile_neoforge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/padding_large"
|
||||
android:layout_marginTop="@dimen/padding_large"
|
||||
android:text="@string/modloader_dl_install_neoforge" />
|
||||
|
||||
<com.kdt.mcgui.MineButton
|
||||
android:id="@+id/modded_profile_modpack"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -453,4 +453,7 @@
|
||||
<string name="delete_account_and_login">Delete account and log in</string>
|
||||
<string name="login_again">Please log in again</string>
|
||||
<string name="account_corrupted">Selected account is corrupted</string>
|
||||
<string name="modloader_dl_install_neoforge">Create Neoforge profile</string>
|
||||
<string name="neoforge_dl_select_version">Select NeoForge version</string>
|
||||
<string name="neoforge_dl_no_installer">Sorry, but this version of NeoForge does not have an installer, which is not yet supported.</string>
|
||||
</resources>
|
||||
|
@ -5,16 +5,23 @@ public class ArcDNSInjectorAgent {
|
||||
System.out.println("Arc Capes DNS Injector");
|
||||
System.out.println("Parts of Alibaba's DCM library were used, please read https://github.com/alibaba/java-dns-cache-manipulator/blob/main/README.md for more info");
|
||||
String[] injectedIps = new String[]{args};
|
||||
|
||||
try {
|
||||
CacheUtil_J9.setInetAddressCache("s.optifine.net", injectedIps, CacheUtilCommons.NEVER_EXPIRATION);
|
||||
CacheUtil_J21.setInetAddressCache("s.optifine.net", injectedIps, CacheUtilCommons.NEVER_EXPIRATION);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
CacheUtil_J8.setInetAddressCache("s.optifine.net", injectedIps, CacheUtilCommons.NEVER_EXPIRATION);
|
||||
CacheUtil_J9.setInetAddressCache("s.optifine.net", injectedIps, CacheUtilCommons.NEVER_EXPIRATION);
|
||||
} catch (Exception e2) {
|
||||
System.out.println("Failed to inject cache!");
|
||||
e2.addSuppressed(e);
|
||||
e2.printStackTrace();
|
||||
return;
|
||||
try {
|
||||
CacheUtil_J8.setInetAddressCache("s.optifine.net", injectedIps, CacheUtilCommons.NEVER_EXPIRATION);
|
||||
} catch (Exception e3) {
|
||||
System.out.println("Failed to inject cache!");
|
||||
e2.addSuppressed(e);
|
||||
e2.printStackTrace();
|
||||
e3.addSuppressed(e);
|
||||
e3.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("Added DNS cache entry: s.optifine.net/"+args);
|
||||
|
@ -0,0 +1,145 @@
|
||||
package git.artdeell.arcdns;
|
||||
import static git.artdeell.arcdns.CacheUtilCommons.NEVER_EXPIRATION;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
public class CacheUtil_J21 {
|
||||
public static void setInetAddressCache(String host, String[] ips, long expireMillis)
|
||||
throws UnknownHostException, IllegalAccessException, InstantiationException,
|
||||
InvocationTargetException, ClassNotFoundException, NoSuchFieldException {
|
||||
long expiration = expireMillis == NEVER_EXPIRATION ? NEVER_EXPIRATION : System.nanoTime() + expireMillis * 1_000_000;
|
||||
Object cachedAddresses = newCachedAddresses(host, ips, expiration);
|
||||
|
||||
getCacheOfInetAddress().put(host, cachedAddresses);
|
||||
getExpirySetOfInetAddress().add(cachedAddresses);
|
||||
}
|
||||
|
||||
private static Object newCachedAddresses(String host, String[] ips, long expiration)
|
||||
throws ClassNotFoundException, UnknownHostException, IllegalAccessException,
|
||||
InvocationTargetException, InstantiationException {
|
||||
// InetAddress.CachedAddresses has only one constructor
|
||||
return getConstructorOfInetAddress$CachedAddresses().newInstance(host, CacheUtilCommons.toInetAddressArray(host, ips), expiration);
|
||||
}
|
||||
|
||||
private static volatile Constructor<?> constructorOfInetAddress$CachedAddresses = null;
|
||||
|
||||
private static Constructor<?> getConstructorOfInetAddress$CachedAddresses() throws ClassNotFoundException {
|
||||
if (constructorOfInetAddress$CachedAddresses != null) return constructorOfInetAddress$CachedAddresses;
|
||||
|
||||
synchronized (CacheUtilCommons.class) {
|
||||
// double check
|
||||
if (constructorOfInetAddress$CachedAddresses != null) return constructorOfInetAddress$CachedAddresses;
|
||||
|
||||
final Class<?> clazz = Class.forName(inetAddress$CachedAddresses_ClassName);
|
||||
|
||||
// InetAddress.CacheEntry has only one constructor:
|
||||
//
|
||||
// - for jdk 9-jdk12, constructor signature is CachedAddresses(String host, InetAddress[] inetAddresses, long expiryTime)
|
||||
// code in jdk 9:
|
||||
// https://hg.openjdk.java.net/jdk9/jdk9/jdk/file/65464a307408/src/java.base/share/classes/java/net/InetAddress.java#l783
|
||||
// code in jdk 11:
|
||||
// https://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/java.base/share/classes/java/net/InetAddress.java#l787
|
||||
final Constructor<?> constructor = clazz.getDeclaredConstructors()[0];
|
||||
constructor.setAccessible(true);
|
||||
|
||||
constructorOfInetAddress$CachedAddresses = constructor;
|
||||
return constructor;
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeInetAddressCache(String host) throws NoSuchFieldException, IllegalAccessException {
|
||||
getCacheOfInetAddress().remove(host);
|
||||
removeHostFromExpirySetOfInetAddress(host);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #getExpirySetOfInetAddress()
|
||||
*/
|
||||
private static void removeHostFromExpirySetOfInetAddress(String host)
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
for (Iterator<Object> iterator = getExpirySetOfInetAddress().iterator(); iterator.hasNext(); ) {
|
||||
Object cachedAddresses = iterator.next();
|
||||
if (getHostOfInetAddress$CacheAddress(cachedAddresses).equals(host)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static volatile Field hostFieldOfInetAddress$CacheAddress = null;
|
||||
|
||||
private static String getHostOfInetAddress$CacheAddress(Object cachedAddresses)
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
if (hostFieldOfInetAddress$CacheAddress == null) {
|
||||
synchronized (CacheUtil_J21.class) {
|
||||
if (hostFieldOfInetAddress$CacheAddress == null) { // double check
|
||||
final Field f = cachedAddresses.getClass().getDeclaredField("host");
|
||||
f.setAccessible(true);
|
||||
hostFieldOfInetAddress$CacheAddress = f;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (String) hostFieldOfInetAddress$CacheAddress.get(cachedAddresses);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// getters of static cache related fields of InetAddress
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static ConcurrentMap<String, Object> getCacheOfInetAddress()
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
return (ConcurrentMap<String, Object>) getCacheAndExpirySetOfInetAddress0()[0];
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static ConcurrentSkipListSet<Object> getExpirySetOfInetAddress()
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
return (ConcurrentSkipListSet<Object>) getCacheAndExpirySetOfInetAddress0()[1];
|
||||
}
|
||||
|
||||
private static volatile Object[] ADDRESS_CACHE_AND_EXPIRY_SET = null;
|
||||
|
||||
private static Object[] getCacheAndExpirySetOfInetAddress0()
|
||||
throws NoSuchFieldException, IllegalAccessException {
|
||||
if (ADDRESS_CACHE_AND_EXPIRY_SET != null) return ADDRESS_CACHE_AND_EXPIRY_SET;
|
||||
|
||||
synchronized (CacheUtil_J21.class) {
|
||||
if (ADDRESS_CACHE_AND_EXPIRY_SET != null) return ADDRESS_CACHE_AND_EXPIRY_SET;
|
||||
|
||||
final Field cacheField = InetAddress.class.getDeclaredField("cache");
|
||||
cacheField.setAccessible(true);
|
||||
|
||||
final Field expirySetField = InetAddress.class.getDeclaredField("expirySet");
|
||||
expirySetField.setAccessible(true);
|
||||
|
||||
ADDRESS_CACHE_AND_EXPIRY_SET = new Object[]{
|
||||
cacheField.get(InetAddress.class),
|
||||
expirySetField.get(InetAddress.class)
|
||||
};
|
||||
|
||||
return ADDRESS_CACHE_AND_EXPIRY_SET;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private static final String inetAddress$CachedAddresses_ClassName = "java.net.InetAddress$CachedLookup";
|
||||
public static void clearInetAddressCache() throws NoSuchFieldException, IllegalAccessException {
|
||||
getCacheOfInetAddress().clear();
|
||||
getExpirySetOfInetAddress().clear();
|
||||
}
|
||||
|
||||
private CacheUtil_J21() {
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user