From 8b22a49218526172e9d9e0830a10a235452538ac Mon Sep 17 00:00:00 2001 From: Riley Park Date: Tue, 21 Dec 2021 14:28:19 -0800 Subject: [PATCH] feat(api): Internal configuration --- .../kyori/adventure/internal/Internals.java | 7 ++ .../adventure/internal/package-info.java | 2 +- .../properties/AdventureProperties.java | 97 ++++++++++++++++ .../properties/AdventurePropertiesImpl.java | 106 ++++++++++++++++++ .../internal/properties/package-info.java | 28 +++++ .../adventure/text/TextComponentImpl.java | 3 +- .../translation/TranslationLocales.java | 4 +- .../net/kyori/adventure/util/Services.java | 4 +- 8 files changed, 246 insertions(+), 5 deletions(-) create mode 100644 api/src/main/java/net/kyori/adventure/internal/properties/AdventureProperties.java create mode 100644 api/src/main/java/net/kyori/adventure/internal/properties/AdventurePropertiesImpl.java create mode 100644 api/src/main/java/net/kyori/adventure/internal/properties/package-info.java diff --git a/api/src/main/java/net/kyori/adventure/internal/Internals.java b/api/src/main/java/net/kyori/adventure/internal/Internals.java index 1d2e3bca9f..5e05386091 100644 --- a/api/src/main/java/net/kyori/adventure/internal/Internals.java +++ b/api/src/main/java/net/kyori/adventure/internal/Internals.java @@ -36,6 +36,13 @@ public final class Internals { private Internals() { } + /** + * Examines an {@link Examinable} using the {@link StringExaminer}. + * + * @param examinable the examinable + * @return the result from examining + * @since 4.10.0 + */ public static @NotNull String toString(final @NotNull Examinable examinable) { return examinable.examine(StringExaminer.simpleEscaping()); } diff --git a/api/src/main/java/net/kyori/adventure/internal/package-info.java b/api/src/main/java/net/kyori/adventure/internal/package-info.java index d7cc37b012..87191ad772 100644 --- a/api/src/main/java/net/kyori/adventure/internal/package-info.java +++ b/api/src/main/java/net/kyori/adventure/internal/package-info.java @@ -22,7 +22,7 @@ * SOFTWARE. */ /** - * Utilities that are not considered part of the Public API. + * Internal things, not for public use. */ @org.jetbrains.annotations.ApiStatus.Internal package net.kyori.adventure.internal; diff --git a/api/src/main/java/net/kyori/adventure/internal/properties/AdventureProperties.java b/api/src/main/java/net/kyori/adventure/internal/properties/AdventureProperties.java new file mode 100644 index 0000000000..3be704bd2e --- /dev/null +++ b/api/src/main/java/net/kyori/adventure/internal/properties/AdventureProperties.java @@ -0,0 +1,97 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2022 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.internal.properties; + +import java.util.function.Function; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Adventure properties. + * + * @since 4.10.0 + */ +@ApiStatus.Internal +public final class AdventureProperties { + /** + * Property for specifying whether debug mode is enabled. + * + * @since 4.10.0 + */ + public static final Property DEBUG = property("debug", Boolean::parseBoolean, false); + /** + * Property for specifying the default translation locale. + * + * @since 4.10.0 + */ + public static final Property DEFAULT_TRANSLATION_LOCALE = property("defaultTranslationLocale", Function.identity(), null); + /** + * Property for specifying whether service load failures are fatal. + * + * @since 4.10.0 + */ + public static final Property SERVICE_LOAD_FAILURES_ARE_FATAL = property("serviceLoadFailuresAreFatal", Boolean::parseBoolean, Boolean.TRUE); + /** + * Property for specifying whether to warn when legacy formatting is detected. + * + * @since 4.10.0 + */ + public static final Property TEXT_WARN_WHEN_LEGACY_FORMATTING_DETECTED = property("text.warnWhenLegacyFormattingDetected", Boolean::parseBoolean, Boolean.FALSE); + + private AdventureProperties() { + } + + /** + * Creates a new property. + * + * @param name the property name + * @param parser the value parser + * @param defaultValue the default value + * @param the value type + * @return a property + * @since 4.10.0 + */ + public static @NotNull Property property(final @NotNull String name, final @NotNull Function parser, final @Nullable T defaultValue) { + return AdventurePropertiesImpl.property(name, parser, defaultValue); + } + + /** + * A property. + * + * @param the value type + * @since 4.10.0 + */ + @ApiStatus.Internal + @ApiStatus.NonExtendable + public interface Property { + /** + * Gets the value. + * + * @return the value + * @since 4.10.0 + */ + @Nullable T value(); + } +} diff --git a/api/src/main/java/net/kyori/adventure/internal/properties/AdventurePropertiesImpl.java b/api/src/main/java/net/kyori/adventure/internal/properties/AdventurePropertiesImpl.java new file mode 100644 index 0000000000..df75e47caf --- /dev/null +++ b/api/src/main/java/net/kyori/adventure/internal/properties/AdventurePropertiesImpl.java @@ -0,0 +1,106 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2022 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package net.kyori.adventure.internal.properties; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Optional; +import java.util.Properties; +import java.util.function.Function; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +final class AdventurePropertiesImpl { + private static final String FILESYSTEM_DIRECTORY_NAME = "config"; + private static final String FILESYSTEM_FILE_NAME = "adventure.properties"; + private static final Properties PROPERTIES = new Properties(); + + static { + final Path path = Optional.ofNullable(System.getProperty(systemPropertyName("config"))) + .map(Paths::get) + .orElseGet(() -> Paths.get(FILESYSTEM_DIRECTORY_NAME, FILESYSTEM_FILE_NAME)); + if (Files.isRegularFile(path)) { + try (final InputStream is = Files.newInputStream(path)) { + PROPERTIES.load(is); + } catch (final IOException e) { + // Well, that's awkward. + e.printStackTrace(); + } + } + } + + private AdventurePropertiesImpl() { + } + + static @NotNull String systemPropertyName(final String name) { + return String.join(".", "net", "kyori", "adventure", name); + } + + static AdventureProperties.@NotNull Property property(final @NotNull String name, final @NotNull Function parser, final @Nullable T defaultValue) { + return new PropertyImpl<>(name, parser, defaultValue); + } + + private static final class PropertyImpl implements AdventureProperties.Property { + private final String name; + private final Function parser; + private final @Nullable T defaultValue; + private boolean valueCalculated; + private @Nullable T value; + + PropertyImpl(final @NotNull String name, final @NotNull Function parser, final @Nullable T defaultValue) { + this.name = name; + this.parser = parser; + this.defaultValue = defaultValue; + } + + @Override + public @Nullable T value() { + if (!this.valueCalculated) { + final String property = systemPropertyName(this.name); + final String value = System.getProperty(property, PROPERTIES.getProperty(this.name)); + if (value != null) { + this.value = this.parser.apply(value); + } + if (this.value == null) { + this.value = this.defaultValue; + } + this.valueCalculated = true; + } + return this.value; + } + + @Override + public boolean equals(final @Nullable Object that) { + return this == that; + } + + @Override + public int hashCode() { + return this.name.hashCode(); + } + } +} diff --git a/api/src/main/java/net/kyori/adventure/internal/properties/package-info.java b/api/src/main/java/net/kyori/adventure/internal/properties/package-info.java new file mode 100644 index 0000000000..22f4308c43 --- /dev/null +++ b/api/src/main/java/net/kyori/adventure/internal/properties/package-info.java @@ -0,0 +1,28 @@ +/* + * This file is part of adventure, licensed under the MIT License. + * + * Copyright (c) 2017-2022 KyoriPowered + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + * Internal properties. + */ +@org.jetbrains.annotations.ApiStatus.Internal +package net.kyori.adventure.internal.properties; diff --git a/api/src/main/java/net/kyori/adventure/text/TextComponentImpl.java b/api/src/main/java/net/kyori/adventure/text/TextComponentImpl.java index 4b63050358..cc7542fa5c 100644 --- a/api/src/main/java/net/kyori/adventure/text/TextComponentImpl.java +++ b/api/src/main/java/net/kyori/adventure/text/TextComponentImpl.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Objects; import net.kyori.adventure.internal.Internals; +import net.kyori.adventure.internal.properties.AdventureProperties; import net.kyori.adventure.text.format.Style; import net.kyori.adventure.util.Nag; import org.jetbrains.annotations.NotNull; @@ -36,7 +37,7 @@ import static java.util.Objects.requireNonNull; final class TextComponentImpl extends AbstractComponent implements TextComponent { - private static final boolean WARN_WHEN_LEGACY_FORMATTING_DETECTED = Boolean.getBoolean(String.join(".", "net", "kyori", "adventure", "text", "warnWhenLegacyFormattingDetected")); + private static final boolean WARN_WHEN_LEGACY_FORMATTING_DETECTED = Boolean.TRUE.equals(AdventureProperties.TEXT_WARN_WHEN_LEGACY_FORMATTING_DETECTED.value()); @VisibleForTesting static final char SECTION_CHAR = 'ยง'; diff --git a/api/src/main/java/net/kyori/adventure/translation/TranslationLocales.java b/api/src/main/java/net/kyori/adventure/translation/TranslationLocales.java index 1e8b5c101c..950ad5d8db 100644 --- a/api/src/main/java/net/kyori/adventure/translation/TranslationLocales.java +++ b/api/src/main/java/net/kyori/adventure/translation/TranslationLocales.java @@ -25,12 +25,14 @@ import java.util.Locale; import java.util.function.Supplier; +import net.kyori.adventure.internal.properties.AdventureProperties; +import org.jetbrains.annotations.Nullable; final class TranslationLocales { private static final Supplier GLOBAL; static { - final String property = System.getProperty("net.kyo".concat("ri.adventure.defaultTranslationLocale")); + final @Nullable String property = AdventureProperties.DEFAULT_TRANSLATION_LOCALE.value(); if (property == null || property.isEmpty()) { GLOBAL = () -> Locale.US; } else if (property.equals("system")) { diff --git a/api/src/main/java/net/kyori/adventure/util/Services.java b/api/src/main/java/net/kyori/adventure/util/Services.java index d71ac09111..264649ac80 100644 --- a/api/src/main/java/net/kyori/adventure/util/Services.java +++ b/api/src/main/java/net/kyori/adventure/util/Services.java @@ -26,6 +26,7 @@ import java.util.Iterator; import java.util.Optional; import java.util.ServiceLoader; +import net.kyori.adventure.internal.properties.AdventureProperties; import org.jetbrains.annotations.NotNull; /** @@ -34,8 +35,7 @@ * @since 4.8.0 */ public final class Services { - // net.kyori.adventure.serviceLoadFailuresAreFatal - private static final boolean SERVICE_LOAD_FAILURES_ARE_FATAL = Boolean.parseBoolean(System.getProperty(String.join(".", "net", "kyori", "adventure", "serviceLoadFailuresAreFatal"), String.valueOf(true))); + private static final boolean SERVICE_LOAD_FAILURES_ARE_FATAL = Boolean.TRUE.equals(AdventureProperties.SERVICE_LOAD_FAILURES_ARE_FATAL.value()); private Services() { }