From 38d961216fc2ad1a531c621764cb42f71326f649 Mon Sep 17 00:00:00 2001 From: Timur Harin Date: Tue, 27 Feb 2024 19:16:09 +0300 Subject: [PATCH 1/2] add script to delete not utf8 java files and delete them --- fixtures/filters/unparseable/PlotPlayer.java | 1098 ----------------- .../filters/unparseable/UUIDPipeline.java | 434 ------- .../jaxec/src/main/java/com/yegor256/Foo.java | 30 - .../src/main/java/com/yegor256/Jaxec.java | 353 ------ help/delete-not-utf8.sh | 26 + 5 files changed, 26 insertions(+), 1915 deletions(-) delete mode 100644 fixtures/filters/unparseable/PlotPlayer.java delete mode 100644 fixtures/filters/unparseable/UUIDPipeline.java delete mode 100644 fixtures/jaxec/src/main/java/com/yegor256/Foo.java delete mode 100644 fixtures/jaxec/src/main/java/com/yegor256/Jaxec.java create mode 100644 help/delete-not-utf8.sh diff --git a/fixtures/filters/unparseable/PlotPlayer.java b/fixtures/filters/unparseable/PlotPlayer.java deleted file mode 100644 index 97ca6c7d..00000000 --- a/fixtures/filters/unparseable/PlotPlayer.java +++ /dev/null @@ -1,1098 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.player; - -import com.google.common.base.Objects; -import com.google.common.base.Preconditions; -import com.google.common.primitives.Ints; -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.collection.ByteArrayUtilities; -import com.plotsquared.core.command.CommandCaller; -import com.plotsquared.core.command.RequiredType; -import com.plotsquared.core.configuration.Settings; -import com.plotsquared.core.configuration.caption.Caption; -import com.plotsquared.core.configuration.caption.CaptionMap; -import com.plotsquared.core.configuration.caption.CaptionUtility; -import com.plotsquared.core.configuration.caption.LocaleHolder; -import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.database.DBFunc; -import com.plotsquared.core.events.TeleportCause; -import com.plotsquared.core.location.Location; -import com.plotsquared.core.permissions.NullPermissionProfile; -import com.plotsquared.core.permissions.PermissionHandler; -import com.plotsquared.core.permissions.PermissionProfile; -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.plot.PlotArea; -import com.plotsquared.core.plot.PlotCluster; -import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.plot.PlotWeather; -import com.plotsquared.core.plot.flag.implementations.DoneFlag; -import com.plotsquared.core.plot.world.PlotAreaManager; -import com.plotsquared.core.plot.world.SinglePlotArea; -import com.plotsquared.core.plot.world.SinglePlotAreaManager; -import com.plotsquared.core.synchronization.LockRepository; -import com.plotsquared.core.util.EventDispatcher; -import com.plotsquared.core.util.query.PlotQuery; -import com.plotsquared.core.util.task.RunnableVal; -import com.plotsquared.core.util.task.TaskManager; -import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.world.gamemode.GameMode; -import com.sk89q.worldedit.world.item.ItemType; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.minimessage.MiniMessage; -import net.kyori.adventure.text.minimessage.tag.Tag; -import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; -import net.kyori.adventure.title.Title; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; - -import java.nio.ByteBuffer; -import java.time.Duration; -import java.time.temporal.ChronoUnit; -import java.util.ArrayDeque; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Locale; -import java.util.Map; -import java.util.Queue; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * The abstract class supporting {@code BukkitPlayer} and {@code SpongePlayer}. - */ -public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer, LocaleHolder { - - private static final String NON_EXISTENT_CAPTION = "PlotSquared does not recognize the caption: "; - - private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + PlotPlayer.class.getSimpleName()); - - // Used to track debug mode - private static final Set> debugModeEnabled = - Collections.synchronizedSet(new HashSet<>()); - - @SuppressWarnings("rawtypes") - private static final Map, PlotPlayerConverter> converters = new HashMap<>(); - private final LockRepository lockRepository = new LockRepository(); - private final PlotAreaManager plotAreaManager; - private final EventDispatcher eventDispatcher; - private final PermissionHandler permissionHandler; - private Map metaMap = new HashMap<>(); - /** - * The metadata map. - */ - private ConcurrentHashMap meta; - private int hash; - private Locale locale; - // Delayed initialisation - private PermissionProfile permissionProfile; - - public PlotPlayer( - final @NonNull PlotAreaManager plotAreaManager, final @NonNull EventDispatcher eventDispatcher, - final @NonNull PermissionHandler permissionHandler - ) { - this.plotAreaManager = plotAreaManager; - this.eventDispatcher = eventDispatcher; - this.permissionHandler = permissionHandler; - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - public static PlotPlayer from(final @NonNull T object) { - // fast path - if (converters.containsKey(object.getClass())) { - return converters.get(object.getClass()).convert(object); - } - // slow path, meant to only run once per object#getClass instance - Queue> toVisit = new ArrayDeque<>(); - toVisit.add(object.getClass()); - Class current; - while ((current = toVisit.poll()) != null) { - PlotPlayerConverter converter = converters.get(current); - if (converter != null) { - if (current != object.getClass()) { - // register shortcut for this sub type to avoid further loops - converters.put(object.getClass(), converter); - LOGGER.info("Registered {} as with converter for {}", object.getClass(), current); - } - return converter.convert(object); - } - // no converter found yet - if (current.getSuperclass() != null) { - toVisit.add(current.getSuperclass()); // add super class if available - } - toVisit.addAll(Arrays.asList(current.getInterfaces())); // add interfaces - } - throw new IllegalArgumentException(String - .format( - "There is no registered PlotPlayer converter for type %s", - object.getClass().getSimpleName() - )); - } - - public static void registerConverter( - final @NonNull Class clazz, - final PlotPlayerConverter converter - ) { - converters.put(clazz, converter); - } - - public static Collection> getDebugModePlayers() { - return Collections.unmodifiableCollection(debugModeEnabled); - } - - public static Collection> getDebugModePlayersInPlot(final @NonNull Plot plot) { - if (debugModeEnabled.isEmpty()) { - return Collections.emptyList(); - } - final Collection> players = new LinkedList<>(); - for (final PlotPlayer player : debugModeEnabled) { - if (player.getCurrentPlot().equals(plot)) { - players.add(player); - } - } - return players; - } - - protected void setupPermissionProfile() { - this.permissionProfile = permissionHandler.getPermissionProfile(this).orElse( - NullPermissionProfile.INSTANCE); - } - - @Override - public final boolean hasPermission( - final @Nullable String world, - final @NonNull String permission - ) { - return this.permissionProfile.hasPermission(world, permission); - } - - @Override - public final boolean hasKeyedPermission( - final @Nullable String world, - final @NonNull String permission, - final @NonNull String key - ) { - return this.permissionProfile.hasKeyedPermission(world, permission, key); - } - - @Override - public final boolean hasPermission(@NonNull String permission, boolean notify) { - if (!hasPermission(permission)) { - if (notify) { - sendMessage( - TranslatableCaption.of("permission.no_permission_event"), - TagResolver.resolver("node", Tag.inserting(Component.text(permission))) - ); - } - return false; - } - return true; - } - - public abstract Actor toActor(); - - public abstract P getPlatformPlayer(); - - /** - * Set some session only metadata for this player. - * - * @param key - * @param value - */ - void setMeta(String key, Object value) { - if (value == null) { - deleteMeta(key); - } else { - if (this.meta == null) { - this.meta = new ConcurrentHashMap<>(); - } - this.meta.put(key, value); - } - } - - /** - * Get the session metadata for a key. - * - * @param key the name of the metadata key - * @param the object type to return - * @return the value assigned to the key or null if it does not exist - */ - @SuppressWarnings("unchecked") - T getMeta(String key) { - if (this.meta != null) { - return (T) this.meta.get(key); - } - return null; - } - - T getMeta(String key, T defaultValue) { - T meta = getMeta(key); - if (meta == null) { - return defaultValue; - } - return meta; - } - - public ConcurrentHashMap getMeta() { - return meta; - } - - /** - * Delete the metadata for a key. - * - metadata is session only - * - deleting other plugin's metadata may cause issues - * - * @param key - */ - Object deleteMeta(String key) { - return this.meta == null ? null : this.meta.remove(key); - } - - - /** - * Returns the name of the player. - * - * @return the name of the player - */ - @Override - public String toString() { - return getName(); - } - - /** - * Get this player's current plot. - * - * @return the plot the player is standing on or null if standing on a road or not in a {@link PlotArea} - */ - public Plot getCurrentPlot() { - try (final MetaDataAccess lastPlotAccess = - this.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { - if (lastPlotAccess.get().orElse(null) == null && !Settings.Enabled_Components.EVENTS) { - return this.getLocation().getPlot(); - } - return lastPlotAccess.get().orElse(null); - } - } - - /** - * Get the total number of allowed plots - * - * @return number of allowed plots within the scope (globally, or in the player's current world as defined in the settings.yml) - */ - public int getAllowedPlots() { - final int calculatedLimit = hasPermissionRange("plots.plot", Settings.Limit.MAX_PLOTS); - return this.eventDispatcher.callPlayerPlotLimit(this, calculatedLimit).limit(); - } - - /** - * Get the number of plots this player owns. - * - * @return number of plots within the scope (globally, or in the player's current world as defined in the settings.yml) - * @see #getPlotCount(String) - * @see #getPlots() - */ - public int getPlotCount() { - if (!Settings.Limit.GLOBAL) { - return getPlotCount(getLocation().getWorldName()); - } - final AtomicInteger count = new AtomicInteger(0); - final UUID uuid = getUUID(); - this.plotAreaManager.forEachPlotArea(value -> { - if (!Settings.Done.COUNTS_TOWARDS_LIMIT) { - for (Plot plot : value.getPlotsAbs(uuid)) { - if (!DoneFlag.isDone(plot)) { - count.incrementAndGet(); - } - } - } else { - count.addAndGet(value.getPlotsAbs(uuid).size()); - } - }); - return count.get(); - } - - public int getClusterCount() { - if (!Settings.Limit.GLOBAL) { - return getClusterCount(getLocation().getWorldName()); - } - final AtomicInteger count = new AtomicInteger(0); - this.plotAreaManager.forEachPlotArea(value -> { - for (PlotCluster cluster : value.getClusters()) { - if (cluster.isOwner(getUUID())) { - count.incrementAndGet(); - } - } - }); - return count.get(); - } - - /** - * Get the number of plots this player owns in the world. - * - * @param world the name of the plotworld to check. - * @return plot count - */ - public int getPlotCount(String world) { - UUID uuid = getUUID(); - int count = 0; - for (PlotArea area : this.plotAreaManager.getPlotAreasSet(world)) { - if (!Settings.Done.COUNTS_TOWARDS_LIMIT) { - count += - area.getPlotsAbs(uuid).stream().filter(plot -> !DoneFlag.isDone(plot)).count(); - } else { - count += area.getPlotsAbs(uuid).size(); - } - } - return count; - } - - public int getClusterCount(String world) { - int count = 0; - for (PlotArea area : this.plotAreaManager.getPlotAreasSet(world)) { - for (PlotCluster cluster : area.getClusters()) { - if (cluster.isOwner(getUUID())) { - count++; - } - } - } - return count; - } - - /** - * Get a {@link Set} of plots owned by this player. - * - *

- * Take a look at {@link PlotSquared} for more searching functions. - * See {@link #getPlotCount()} for the number of plots. - *

- * - * @return a {@link Set} of plots owned by the player - */ - public Set getPlots() { - return PlotQuery.newQuery().ownedBy(this).asSet(); - } - - /** - * Return the PlotArea this player is currently in, or null. - * - * @return Plot area the player is currently in, or {@code null} - */ - public @Nullable PlotArea getPlotAreaAbs() { - return this.plotAreaManager.getPlotArea(getLocation()); - } - - public PlotArea getApplicablePlotArea() { - return this.plotAreaManager.getApplicablePlotArea(getLocation()); - } - - @Override - public @NonNull RequiredType getSuperCaller() { - return RequiredType.PLAYER; - } - - /** - * Get this player's last recorded location or null if they don't any plot relevant location. - * - * @return The location - */ - public @NonNull Location getLocation() { - Location location = getMeta("location"); - if (location != null) { - return location; - } - return getLocationFull(); - } - - /////////////// PLAYER META /////////////// - - ////////////// PARTIALLY IMPLEMENTED /////////// - - /** - * Get this player's full location (including yaw/pitch) - * - * @return location - */ - public abstract Location getLocationFull(); - - //////////////////////////////////////////////// - - /** - * Get this player's UUID. - * === !IMPORTANT ===
- * The UUID is dependent on the mode chosen in the settings.yml and may not be the same as Bukkit has - * (especially if using an old version of Bukkit that does not support UUIDs) - * - * @return UUID - */ - @Override - public @NonNull - abstract UUID getUUID(); - - public boolean canTeleport(final @NonNull Location location) { - Preconditions.checkNotNull(location, "Specified location cannot be null"); - final Location current = getLocationFull(); - teleport(location); - boolean result = getLocation().equals(location); - teleport(current); - return result; - } - - /** - * Teleport this player to a location. - * - * @param location the target location - */ - public void teleport(Location location) { - teleport(location, TeleportCause.PLUGIN); - } - - /** - * Teleport this player to a location. - * - * @param location the target location - * @param cause the cause of the teleport - */ - public abstract void teleport(Location location, TeleportCause cause); - - /** - * Kick this player to a location - * - * @param location the target location - */ - public void plotkick(Location location) { - setMeta("kick", true); - teleport(location, TeleportCause.KICK); - deleteMeta("kick"); - } - - /** - * Set this compass target. - * - * @param location the target location - */ - public abstract void setCompassTarget(Location location); - - /** - * Set player data that will persist restarts. - * - Please note that this is not intended to store large values - * - For session only data use meta - * - * @param key metadata key - */ - public void setAttribute(String key) { - setPersistentMeta("attrib_" + key, new byte[]{(byte) 1}); - } - - /** - * Retrieves the attribute of this player. - * - * @param key metadata key - * @return the attribute will be either {@code true} or {@code false} - */ - public boolean getAttribute(String key) { - if (!hasPersistentMeta("attrib_" + key)) { - return false; - } - return getPersistentMeta("attrib_" + key)[0] == 1; - } - - /** - * Remove an attribute from a player. - * - * @param key metadata key - */ - public void removeAttribute(String key) { - removePersistentMeta("attrib_" + key); - } - - /** - * Sets the local weather for this Player. - * - * @param weather the weather visible to the player - */ - public abstract void setWeather(@NonNull PlotWeather weather); - - /** - * Get this player's gamemode. - * - * @return the gamemode of the player. - */ - public abstract @NonNull GameMode getGameMode(); - - /** - * Set this player's gameMode. - * - * @param gameMode the gamemode to set - */ - public abstract void setGameMode(@NonNull GameMode gameMode); - - /** - * Set this player's local time (ticks). - * - * @param time the time visible to the player - */ - public abstract void setTime(long time); - - /** - * Determines whether or not the player can fly. - * - * @return {@code true} if the player is allowed to fly - */ - public abstract boolean getFlight(); - - /** - * Sets whether or not this player can fly. - * - * @param fly {@code true} if the player can fly, otherwise {@code false} - */ - public abstract void setFlight(boolean fly); - - /** - * Play music at a location for this player. - * - * @param location where to play the music - * @param id the record item id - */ - public abstract void playMusic(@NonNull Location location, @NonNull ItemType id); - - /** - * Check if this player is banned. - * - * @return {@code true} if the player is banned, {@code false} otherwise. - */ - public abstract boolean isBanned(); - - /** - * Kick this player from the game. - * - * @param message the reason for the kick - */ - public abstract void kick(String message); - - public void refreshDebug() { - final boolean debug = this.getAttribute("debug"); - if (debug && !debugModeEnabled.contains(this)) { - debugModeEnabled.add(this); - } else if (!debug) { - debugModeEnabled.remove(this); - } - } - - /** - * Called when this player quits. - */ - public void unregister() { - Plot plot = getCurrentPlot(); - if (plot != null && Settings.Enabled_Components.PERSISTENT_META && plot - .getArea() instanceof SinglePlotArea) { - PlotId id = plot.getId(); - int x = id.getX(); - int z = id.getY(); - ByteBuffer buffer = ByteBuffer.allocate(13); - buffer.putShort((short) x); - buffer.putShort((short) z); - Location location = getLocation(); - buffer.putInt(location.getX()); - buffer.put((byte) location.getY()); - buffer.putInt(location.getZ()); - setPersistentMeta("quitLoc", buffer.array()); - } else if (hasPersistentMeta("quitLoc")) { - removePersistentMeta("quitLoc"); - } - if (plot != null) { - this.eventDispatcher.callLeave(this, plot); - } - if (Settings.Enabled_Components.BAN_DELETER && isBanned()) { - for (Plot owned : getPlots()) { - owned.getPlotModificationManager().deletePlot(null, null); - LOGGER.info("Plot {} was deleted + cleared due to {} getting banned", owned.getId(), getName()); - } - } - if (PlotSquared.platform().expireManager() != null) { - PlotSquared.platform().expireManager().storeDate(getUUID(), System.currentTimeMillis()); - } - PlotSquared.platform().playerManager().removePlayer(this); - PlotSquared.platform().unregister(this); - - debugModeEnabled.remove(this); - } - - /** - * Get the amount of clusters this player owns in the specific world. - * - * @param world world - * @return number of clusters owned - */ - public int getPlayerClusterCount(String world) { - return PlotSquared.get().getClusters(world).stream() - .filter(cluster -> getUUID().equals(cluster.owner)).mapToInt(PlotCluster::getArea) - .sum(); - } - - /** - * Get the amount of clusters this player owns. - * - * @return the number of clusters this player owns - */ - public int getPlayerClusterCount() { - final AtomicInteger count = new AtomicInteger(); - this.plotAreaManager.forEachPlotArea(value -> count.addAndGet(value.getClusters().size())); - return count.get(); - } - - /** - * Return a {@code Set} of all plots this player owns in a certain world. - * - * @param world the world to retrieve plots from - * @return a {@code Set} of plots this player owns in the provided world - */ - public Set getPlots(String world) { - return PlotQuery.newQuery().inWorld(world).ownedBy(getUUID()).asSet(); - } - - public void populatePersistentMetaMap() { - if (Settings.Enabled_Components.PERSISTENT_META) { - DBFunc.getPersistentMeta(getUUID(), new RunnableVal<>() { - @Override - public void run(Map value) { - try { - PlotPlayer.this.metaMap = value; - if (value.isEmpty()) { - return; - } - - if (PlotPlayer.this.getAttribute("debug")) { - debugModeEnabled.add(PlotPlayer.this); - } - - if (!Settings.Teleport.ON_LOGIN) { - return; - } - PlotAreaManager manager = PlotPlayer.this.plotAreaManager; - - if (!(manager instanceof SinglePlotAreaManager)) { - return; - } - PlotArea area = ((SinglePlotAreaManager) manager).getArea(); - byte[] arr = PlotPlayer.this.getPersistentMeta("quitLoc"); - if (arr == null) { - return; - } - removePersistentMeta("quitLoc"); - - if (!getMeta("teleportOnLogin", true)) { - return; - } - ByteBuffer quitWorld = ByteBuffer.wrap(arr); - final int plotX = quitWorld.getShort(); - final int plotZ = quitWorld.getShort(); - PlotId id = PlotId.of(plotX, plotZ); - int x = quitWorld.getInt(); - int y = quitWorld.get() & 0xFF; - int z = quitWorld.getInt(); - Plot plot = area.getOwnedPlot(id); - - if (plot == null) { - return; - } - - final Location location = Location.at(plot.getWorldName(), x, y, z); - if (plot.isLoaded()) { - TaskManager.runTask(() -> { - if (getMeta("teleportOnLogin", true)) { - teleport(location, TeleportCause.LOGIN); - sendMessage( - TranslatableCaption.of("teleport.teleported_to_plot")); - } - }); - } else if (!PlotSquared.get().isMainThread(Thread.currentThread())) { - if (getMeta("teleportOnLogin", true)) { - plot.teleportPlayer( - PlotPlayer.this, - result -> TaskManager.runTask(() -> { - if (getMeta("teleportOnLogin", true)) { - if (plot.isLoaded()) { - teleport(location, TeleportCause.LOGIN); - sendMessage(TranslatableCaption - .of("teleport.teleported_to_plot")); - } - } - }) - ); - } - } - } catch (Throwable e) { - e.printStackTrace(); - } - } - }); - } - } - - byte[] getPersistentMeta(String key) { - return this.metaMap.get(key); - } - - Object removePersistentMeta(String key) { - final Object old = this.metaMap.remove(key); - if (Settings.Enabled_Components.PERSISTENT_META) { - DBFunc.removePersistentMeta(getUUID(), key); - } - return old; - } - - /** - * Access keyed persistent meta data for this player. This returns a meta data - * access instance, that MUST be closed. It is meant to be used with try-with-resources, - * like such: - *
{@code
-     * try (final MetaDataAccess access = player.accessPersistentMetaData(PlayerMetaKeys.GRANTS)) {
-     *     int grants = access.get();
-     *     access.set(grants + 1);
-     * }
-     * }
- * - * @param key Meta data key - * @param Meta data type - * @return Meta data access. MUST be closed after being used - */ - public @NonNull MetaDataAccess accessPersistentMetaData(final @NonNull MetaDataKey key) { - return new PersistentMetaDataAccess<>(this, key, this.lockRepository.lock(key.getLockKey())); - } - - /** - * Access keyed temporary meta data for this player. This returns a meta data - * access instance, that MUST be closed. It is meant to be used with try-with-resources, - * like such: - *
{@code
-     * try (final MetaDataAccess access = player.accessTemporaryMetaData(PlayerMetaKeys.GRANTS)) {
-     *     int grants = access.get();
-     *     access.set(grants + 1);
-     * }
-     * }
- * - * @param key Meta data key - * @param Meta data type - * @return Meta data access. MUST be closed after being used - */ - public @NonNull MetaDataAccess accessTemporaryMetaData(final @NonNull MetaDataKey key) { - return new TemporaryMetaDataAccess<>(this, key, this.lockRepository.lock(key.getLockKey())); - } - - void setPersistentMeta( - final @NonNull MetaDataKey key, - final @NonNull T value - ) { - if (key.getType().getRawType().equals(Integer.class)) { - this.setPersistentMeta(key.toString(), Ints.toByteArray((int) (Object) value)); - } else if (key.getType().getRawType().equals(Boolean.class)) { - this.setPersistentMeta(key.toString(), ByteArrayUtilities.booleanToBytes((boolean) (Object) value)); - } else { - throw new IllegalArgumentException(String.format("Unknown meta data type '%s'", key.getType())); - } - } - - @SuppressWarnings("unchecked") - @Nullable T getPersistentMeta(final @NonNull MetaDataKey key) { - final byte[] value = this.getPersistentMeta(key.toString()); - if (value == null) { - return null; - } - final Object returnValue; - if (key.getType().getRawType().equals(Integer.class)) { - returnValue = Ints.fromByteArray(value); - } else if (key.getType().getRawType().equals(Boolean.class)) { - returnValue = ByteArrayUtilities.bytesToBoolean(value); - } else { - throw new IllegalArgumentException(String.format("Unknown meta data type '%s'", key.getType())); - } - return (T) returnValue; - } - - void setPersistentMeta(String key, byte[] value) { - boolean delete = hasPersistentMeta(key); - this.metaMap.put(key, value); - if (Settings.Enabled_Components.PERSISTENT_META) { - DBFunc.addPersistentMeta(getUUID(), key, value, delete); - } - } - - /** - * Send a title to the player that fades in, in 10 ticks, stays for 50 ticks and fades - * out in 20 ticks - * - * @param title Title text - * @param subtitle Subtitle text - * @param replacements Variable replacements - */ - public void sendTitle( - final @NonNull Caption title, final @NonNull Caption subtitle, - final @NonNull TagResolver... replacements - ) { - sendTitle( - title, - subtitle, - Settings.Titles.TITLES_FADE_IN, - Settings.Titles.TITLES_STAY, - Settings.Titles.TITLES_FADE_OUT, - replacements - ); - } - - /** - * Send a title to the player - * - * @param title Title - * @param subtitle Subtitle - * @param fadeIn Fade in time (in ticks) - * @param stay The title stays for (in ticks) - * @param fadeOut Fade out time (in ticks) - * @param replacements Variable replacements - */ - public void sendTitle( - final @NonNull Caption title, final @NonNull Caption subtitle, - final int fadeIn, final int stay, final int fadeOut, - final @NonNull TagResolver... replacements - ) { - final Component titleComponent = MiniMessage.miniMessage().deserialize(title.getComponent(this), replacements); - final Component subtitleComponent = - MiniMessage.miniMessage().deserialize(subtitle.getComponent(this), replacements); - final Title.Times times = Title.Times.times( - Duration.of(Settings.Titles.TITLES_FADE_IN * 50L, ChronoUnit.MILLIS), - Duration.of(Settings.Titles.TITLES_STAY * 50L, ChronoUnit.MILLIS), - Duration.of(Settings.Titles.TITLES_FADE_OUT * 50L, ChronoUnit.MILLIS) - ); - getAudience().showTitle(Title - .title(titleComponent, subtitleComponent, times)); - } - - /** - * Method designed to send an ActionBar to a player. - * - * @param caption Caption - * @param replacements Variable replacements - */ - public void sendActionBar( - final @NonNull Caption caption, - final @NonNull TagResolver... replacements - ) { - String message; - try { - message = caption.getComponent(this); - } catch (final CaptionMap.NoSuchCaptionException exception) { - // This sends feedback to the player - message = NON_EXISTENT_CAPTION + ((TranslatableCaption) caption).getKey(); - // And this also prints it to the console - exception.printStackTrace(); - } - if (message.isEmpty()) { - return; - } - // Replace placeholders, etc - message = CaptionUtility.format(this, message) - .replace('\u2010', '%').replace('\u2020', '&').replace('\u2030', '&') - .replace("", TranslatableCaption.of("core.prefix").getComponent(this)); - - - final Component component = MiniMessage.miniMessage().deserialize(message, replacements); - getAudience().sendActionBar(component); - } - - @Override - public void sendMessage( - final @NonNull Caption caption, - final @NonNull TagResolver... replacements - ) { - String message; - try { - message = caption.getComponent(this); - } catch (final CaptionMap.NoSuchCaptionException exception) { - // This sends feedback to the player - message = NON_EXISTENT_CAPTION + ((TranslatableCaption) caption).getKey(); - // And this also prints it to the console - exception.printStackTrace(); - } - if (message.isEmpty()) { - return; - } - // Replace placeholders, etc - message = CaptionUtility.format(this, message) - .replace('\u2010', '%').replace('\u2020', '&').replace('\u2030', '&') - .replace("", TranslatableCaption.of("core.prefix").getComponent(this)); - // Parse the message - final Component component = MiniMessage.miniMessage().deserialize(message, replacements); - if (!Objects.equal(component, this.getMeta("lastMessage")) - || System.currentTimeMillis() - this.getMeta("lastMessageTime") > 5000) { - setMeta("lastMessage", component); - setMeta("lastMessageTime", System.currentTimeMillis()); - getAudience().sendMessage(component); - } - } - - /** - * Sends a message to the command caller, when the future is resolved - * - * @param caption Caption to send - * @param asyncReplacement Async variable replacement - * @return A Future to be resolved, after the message was sent - * @since 7.1.0 - */ - public final CompletableFuture sendMessage( - @NonNull Caption caption, - CompletableFuture<@NonNull TagResolver> asyncReplacement - ) { - return sendMessage(caption, new CompletableFuture[]{asyncReplacement}); - } - - /** - * Sends a message to the command caller, when all futures are resolved - * - * @param caption Caption to send - * @param asyncReplacements Async variable replacements - * @param replacements Sync variable replacements - * @return A Future to be resolved, after the message was sent - * @since 7.1.0 - */ - public final CompletableFuture sendMessage( - @NonNull Caption caption, - CompletableFuture<@NonNull TagResolver>[] asyncReplacements, - @NonNull TagResolver... replacements - ) { - return CompletableFuture.allOf(asyncReplacements).whenComplete((unused, throwable) -> { - Set resolvers = new HashSet<>(Arrays.asList(replacements)); - if (throwable != null) { - sendMessage( - TranslatableCaption.of("errors.error"), - TagResolver.resolver("value", Tag.inserting( - Component.text("Failed to resolve asynchronous caption replacements") - )) - ); - LOGGER.error("Failed to resolve asynchronous tagresolver(s) for " + caption, throwable); - } else { - for (final CompletableFuture asyncReplacement : asyncReplacements) { - resolvers.add(asyncReplacement.join()); - } - } - sendMessage(caption, resolvers.toArray(TagResolver[]::new)); - }); - } - - // Redefine from PermissionHolder as it's required from CommandCaller - @Override - public boolean hasPermission(@NonNull String permission) { - return hasPermission(null, permission); - } - - boolean hasPersistentMeta(String key) { - return this.metaMap.containsKey(key); - } - - /** - * Check if the player is able to see the other player. - * This does not mean that the other player is in line of sight of the player, - * but rather that the player is permitted to see the other player. - * - * @param other Other player - * @return {@code true} if the player is able to see the other player, {@code false} if not - */ - public abstract boolean canSee(PlotPlayer other); - - public abstract void stopSpectating(); - - public boolean hasDebugMode() { - return this.getAttribute("debug"); - } - - @NonNull - @Override - public Locale getLocale() { - if (this.locale == null) { - this.locale = Locale.forLanguageTag(Settings.Enabled_Components.DEFAULT_LOCALE); - } - return this.locale; - } - - @Override - public void setLocale(final @NonNull Locale locale) { - if (!PlotSquared.get().getCaptionMap(TranslatableCaption.DEFAULT_NAMESPACE).supportsLocale(locale)) { - this.locale = Locale.forLanguageTag(Settings.Enabled_Components.DEFAULT_LOCALE); - } else { - this.locale = locale; - } - } - - @Override - public int hashCode() { - if (this.hash == 0 || this.hash == 485) { - this.hash = 485 + this.getUUID().hashCode(); - } - return this.hash; - } - - @Override - public boolean equals(final Object obj) { - if (!(obj instanceof final PlotPlayer other)) { - return false; - } - return this.getUUID().equals(other.getUUID()); - } - - /** - * Get the {@link Audience} that represents this plot player - * - * @return Player audience - */ - public @NonNull - abstract Audience getAudience(); - - /** - * Get this player's {@link LockRepository} - * - * @return Lock repository instance - */ - public @NonNull LockRepository getLockRepository() { - return this.lockRepository; - } - - /** - * Removes any effects present of the given type. - * - * @param name the name of the type to remove - * @since 6.10.0 - */ - public abstract void removeEffect(@NonNull String name); - - @FunctionalInterface - public interface PlotPlayerConverter { - - PlotPlayer convert(BaseObject object); - - } - -} \ No newline at end of file diff --git a/fixtures/filters/unparseable/UUIDPipeline.java b/fixtures/filters/unparseable/UUIDPipeline.java deleted file mode 100644 index b21e1f93..00000000 --- a/fixtures/filters/unparseable/UUIDPipeline.java +++ /dev/null @@ -1,434 +0,0 @@ -/* - * PlotSquared, a land and world management plugin for Minecraft. - * Copyright (C) IntellectualSites - * Copyright (C) IntellectualSites team and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.uuid; - -import com.google.common.collect.Lists; -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.configuration.Settings; -import com.plotsquared.core.configuration.caption.TranslatableCaption; -import com.plotsquared.core.player.ConsolePlayer; -import com.plotsquared.core.util.ThreadUtils; -import com.plotsquared.core.util.task.TaskManager; -import net.kyori.adventure.text.minimessage.MiniMessage; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -/** - * An UUID pipeline is essentially an ordered list of - * {@link UUIDService uuid services} that each get the - * opportunity of providing usernames or UUIDs. - *

- * Each request is then passed through a secondary list of - * consumers, that can then be used to cache them, etc - */ -public class UUIDPipeline { - - private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + UUIDPipeline.class.getSimpleName()); - private static final MiniMessage MINI_MESSAGE = MiniMessage.builder().build(); - - private final Executor executor; - private final List serviceList; - private final List>> consumerList; - - /** - * Construct a new UUID pipeline - * - * @param executor Executor that is used to run asynchronous tasks inside - * of the pipeline - */ - public UUIDPipeline(final @NonNull Executor executor) { - this.executor = executor; - this.serviceList = Lists.newLinkedList(); - this.consumerList = Lists.newLinkedList(); - } - - /** - * Register a UUID service - * - * @param uuidService UUID service to register - */ - public void registerService(final @NonNull UUIDService uuidService) { - this.serviceList.add(uuidService); - } - - /** - * Register a mapping consumer - * - * @param mappingConsumer Consumer to register - */ - public void registerConsumer(final @NonNull Consumer<@NonNull List<@NonNull UUIDMapping>> mappingConsumer) { - this.consumerList.add(mappingConsumer); - } - - /** - * Get a copy of the service list - * - * @return Copy of service list - */ - public @NonNull List<@NonNull UUIDService> getServiceListInstance() { - return Collections.unmodifiableList(this.serviceList); - } - - /** - * Let all consumers act on the given mapping. - * - * @param mappings Mappings - */ - public void consume(final @NonNull List<@NonNull UUIDMapping> mappings) { - final Runnable runnable = () -> { - for (final Consumer> consumer : this.consumerList) { - consumer.accept(mappings); - } - }; - if (PlotSquared.get().isMainThread(Thread.currentThread())) { - TaskManager.runTaskAsync(runnable); - } else { - runnable.run(); - } - } - - /** - * Consume a single mapping - * - * @param mapping Mapping to consume - */ - public void consume(final @NonNull UUIDMapping mapping) { - this.consume(Collections.singletonList(mapping)); - } - - /** - * This will store the given username-UUID pair directly, and overwrite - * any existing caches. This can be used to update usernames automatically - * whenever a player joins the server, to make sure an up-to-date UUID - * mapping is stored - * - * @param username Player username - * @param uuid Player uuid - */ - public void storeImmediately(final @NonNull String username, final @NonNull UUID uuid) { - this.consume(new UUIDMapping(uuid, username)); - } - - /** - * Get a single UUID from a username. This is blocking. - * - * @param username Username - * @param timeout Timeout in milliseconds - * @return The mapped uuid. Will return null if the request timed out. - */ - public @Nullable UUID getSingle(final @NonNull String username, final long timeout) { - ThreadUtils.catchSync("Blocking UUID retrieval from the main thread"); - try { - final List mappings = this.getUUIDs(Collections.singletonList(username)).get( - timeout, - TimeUnit.MILLISECONDS - ); - if (mappings.size() == 1) { - return mappings.get(0).uuid(); - } - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); - } catch (TimeoutException ignored) { - // This is completely valid, we just don't care anymore - if (Settings.DEBUG) { - LOGGER.warn("(UUID) Request for {} timed out. Rate limit.", username); - } - } - return null; - } - - /** - * Get a single username from a UUID. This is blocking. - * - * @param uuid UUID - * @param timeout Timeout in milliseconds - * @return The mapped username. Will return null if the request timeout. - */ - public @Nullable String getSingle(final @NonNull UUID uuid, final long timeout) { - ThreadUtils.catchSync("Blocking username retrieval from the main thread"); - try { - final List mappings = this.getNames(Collections.singletonList(uuid)).get(timeout, TimeUnit.MILLISECONDS); - if (mappings.size() == 1) { - return mappings.get(0).username(); - } - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); - } catch (TimeoutException ignored) { - // This is completely valid, we just don't care anymore - if (Settings.DEBUG) { - LOGGER.warn("(UUID) Request for {} timed out. Rate limit.", uuid); - } - } - return null; - } - - /** - * Get a single UUID from a username. This is non-blocking. - * - * @param username Username - * @param uuid UUID consumer - */ - public void getSingle(final @NonNull String username, final @NonNull BiConsumer<@Nullable UUID, @Nullable Throwable> uuid) { - this.getUUIDs(Collections.singletonList(username)) - .orTimeout(Settings.UUID.NON_BLOCKING_TIMEOUT, TimeUnit.MILLISECONDS) - .whenComplete((uuids, throwable) -> { - if (throwable != null) { - uuid.accept(null, throwable); - } else { - if (!uuids.isEmpty()) { - uuid.accept(uuids.get(0).uuid(), null); - } else { - uuid.accept(null, null); - } - } - }); - } - - /** - * Get a single username from a UUID. This is non-blocking. - * - * @param uuid UUID - * @param username Username consumer - */ - public void getSingle(final @NonNull UUID uuid, final @NonNull BiConsumer<@Nullable String, @Nullable Throwable> username) { - this.getNames(Collections.singletonList(uuid)) - .orTimeout(Settings.UUID.NON_BLOCKING_TIMEOUT, TimeUnit.MILLISECONDS) - .whenComplete((uuids, throwable) -> { - if (throwable != null) { - username.accept(null, throwable); - } else { - if (!uuids.isEmpty()) { - username.accept(uuids.get(0).username(), null); - } else { - username.accept(null, null); - } - } - }); - } - - /** - * Asynchronously attempt to fetch the mapping from a list of UUIDs. - *

- * This will timeout after the specified time and throws a {@link TimeoutException} - * if this happens - * - * @param requests UUIDs - * @param timeout Timeout in milliseconds - * @return Mappings - */ - public @NonNull CompletableFuture<@NonNull List<@NonNull UUIDMapping>> getNames( - final @NonNull Collection<@NonNull UUID> requests, - final long timeout - ) { - return this.getNames(requests).orTimeout(timeout, TimeUnit.MILLISECONDS); - } - - /** - * Asynchronously attempt to fetch the mapping from a list of names. - *

- * This will timeout after the specified time and throws a {@link TimeoutException} - * if this happens - * - * @param requests Names - * @param timeout Timeout in milliseconds - * @return Mappings - */ - public @NonNull CompletableFuture> getUUIDs( - final @NonNull Collection requests, - final long timeout - ) { - return this.getUUIDs(requests).orTimeout(timeout, TimeUnit.MILLISECONDS); - } - - /** - * Asynchronously attempt to fetch the mapping from a list of UUIDs - * - * @param requests UUIDs - * @return Mappings - */ - public @NonNull CompletableFuture<@NonNull List<@NonNull UUIDMapping>> getNames( - final @NonNull Collection<@NonNull UUID> requests - ) { - if (requests.isEmpty()) { - return CompletableFuture.completedFuture(Collections.emptyList()); - } - - final List serviceList = this.getServiceListInstance(); - final List mappings = new ArrayList<>(requests.size()); - final List remainingRequests = new ArrayList<>(requests); - - for (final UUIDService service : serviceList) { - // We can chain multiple synchronous - // ones in a row - if (service.canBeSynchronous()) { - final List completedRequests = service.getNames(remainingRequests); - for (final UUIDMapping mapping : completedRequests) { - remainingRequests.remove(mapping.uuid()); - } - mappings.addAll(completedRequests); - } else { - break; - } - if (remainingRequests.isEmpty()) { - return CompletableFuture.completedFuture(mappings); - } - } - - return CompletableFuture.supplyAsync(() -> { - for (final UUIDService service : serviceList) { - final List completedRequests = service.getNames(remainingRequests); - for (final UUIDMapping mapping : completedRequests) { - remainingRequests.remove(mapping.uuid()); - } - mappings.addAll(completedRequests); - if (remainingRequests.isEmpty()) { - break; - } - } - - if (mappings.size() == requests.size()) { - this.consume(mappings); - return mappings; - } else if (Settings.DEBUG) { - LOGGER.info("(UUID) Failed to find all usernames"); - } - - if (Settings.UUID.UNKNOWN_AS_DEFAULT) { - for (final UUID uuid : remainingRequests) { - mappings.add(new UUIDMapping( - uuid, - MINI_MESSAGE.escapeTags(TranslatableCaption - .of("info.unknown") - .getComponent(ConsolePlayer.getConsole())) - )); - } - return mappings; - } else { - throw new ServiceError("End of pipeline"); - } - }, this.executor); - } - - /** - * Asynchronously attempt to fetch the mapping from a list of names - * - * @param requests Names - * @return Mappings - */ - public @NonNull CompletableFuture<@NonNull List<@NonNull UUIDMapping>> getUUIDs( - final @NonNull Collection<@NonNull String> requests - ) { - if (requests.isEmpty()) { - return CompletableFuture.completedFuture(Collections.emptyList()); - } - - final List serviceList = this.getServiceListInstance(); - final List mappings = new ArrayList<>(requests.size()); - final List remainingRequests = new ArrayList<>(requests); - - for (final UUIDService service : serviceList) { - // We can chain multiple synchronous - // ones in a row - if (service.canBeSynchronous()) { - final List completedRequests = service.getUUIDs(remainingRequests); - for (final UUIDMapping mapping : completedRequests) { - remainingRequests.remove(mapping.username()); - } - mappings.addAll(completedRequests); - } else { - break; - } - if (remainingRequests.isEmpty()) { - return CompletableFuture.completedFuture(mappings); - } - } - - return CompletableFuture.supplyAsync(() -> { - for (final UUIDService service : serviceList) { - final List completedRequests = service.getUUIDs(remainingRequests); - for (final UUIDMapping mapping : completedRequests) { - remainingRequests.remove(mapping.username()); - } - mappings.addAll(completedRequests); - if (remainingRequests.isEmpty()) { - break; - } - } - - if (mappings.size() == requests.size()) { - this.consume(mappings); - return mappings; - } else if (Settings.DEBUG) { - LOGGER.info("(UUID) Failed to find all UUIDs"); - } - - throw new ServiceError("End of pipeline"); - }, this.executor); - } - - /** - * Get as many UUID mappings as possible under the condition - * that the operation cannot be blocking (for an extended amount of time) - * - * @return All mappings that could be provided immediately - */ - public @NonNull - final Collection<@NonNull UUIDMapping> getAllImmediately() { - final Set mappings = new LinkedHashSet<>(); - for (final UUIDService service : this.getServiceListInstance()) { - mappings.addAll(service.getImmediately()); - } - return mappings; - } - - /** - * Get a single UUID mapping immediately, if possible - * - * @param object Username ({@link String}) or {@link UUID} - * @return Mapping, if it could be found immediately - */ - public @Nullable - final UUIDMapping getImmediately(final @NonNull Object object) { - for (final UUIDService uuidService : this.getServiceListInstance()) { - final UUIDMapping mapping = uuidService.getImmediately(object); - if (mapping != null) { - return mapping; - } - } - return null; - } - -} \ No newline at end of file diff --git a/fixtures/jaxec/src/main/java/com/yegor256/Foo.java b/fixtures/jaxec/src/main/java/com/yegor256/Foo.java deleted file mode 100644 index 79a894c1..00000000 --- a/fixtures/jaxec/src/main/java/com/yegor256/Foo.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2023 Yegor Bugayenko - * - * 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 NON-INFRINGEMENT. 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 com.yegor256; - -/** - * @since 0.0.1 - */ -public final class Foo { -} diff --git a/fixtures/jaxec/src/main/java/com/yegor256/Jaxec.java b/fixtures/jaxec/src/main/java/com/yegor256/Jaxec.java deleted file mode 100644 index 5275c2f4..00000000 --- a/fixtures/jaxec/src/main/java/com/yegor256/Jaxec.java +++ /dev/null @@ -1,353 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2023 Yegor Bugayenko - * - * 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 NON-INFRINGEMENT. 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 com.yegor256; - -import com.jcabi.log.Logger; -import com.jcabi.log.VerboseProcess; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedList; -import java.util.logging.Level; - -/** - * Simple Java shell command executor. - * - *

When you need to run a shell command:

- * - *
 String stdout = new Jaxec("ls", "-al", "/tmp")
- *   .withHome("/home/me") // run it in this directory
- *   .withRedirect(false) // don't redirect STDERR to STDOUT
- *   .exec();
- * - *

If the exit code is not equal to zero, a runtime exception will - * be thrown. Moreover, the STDOUT of the command will be sent to - * the logging facility. If {@link Jaxec#redirect} is set to {@code FALSE}, - * only the STDERR will be sent to the log. Be careful about what the - * command prints to the console, since it will be visible in the - * log in case of error.

- * - *

The default home directory is the one defined - * in "user.dir". You can change this via - * the {@link Jaxec#withHome(File)} method (and its overloaded siblings).

- * - *

By default, STDERR is redirected to STDOUT. You can change - * this by using the {@link Jaxec#withRedirect(boolean)} method.

- * - *

Objects of this class are immutable, meaning that - * on every call to one of with() methods you - * get a new instance of the class.

- * - *

The output of the shell command is sent to - * Slf4j logging facility, - * which you can redirect to Log4j or any other - * logging engine. Log events are sent to the - * com.jcabi.log.VerboseProcess class. - * The level for stdout is `DEBUG`, while the level - * for stderr is `WARN`.

- * - * @since 0.0.1 - */ -@SuppressWarnings("PMD.TooManyMethods") -public final class Jaxec { - - /** - * Arguments. - */ - private final Collection arguments; - - /** - * Home directory. - */ - private final File home; - - /** - * Redirect STDERR to STDOUT? - */ - private final boolean redirect; - - /** - * Check exit code and fail if it's not zero? - */ - private final boolean check; - - /** - * STDIN to send to the process. - */ - private final InputStream stdin; - - /** - * Ctor. - * @param args The command line arguments - */ - public Jaxec(final String... args) { - this(Arrays.asList(args)); - } - - /** - * Ctor. - * @param args The command line arguments - */ - public Jaxec(final Collection args) { - this(args, new File(System.getProperty("user.dir"))); - } - - /** - * Ctor. - * @param args The command line arguments - * @param dir Home directory - */ - public Jaxec(final Collection args, final File dir) { - this(args, dir, true); - } - - /** - * Ctor. - * @param args The command line arguments - * @param dir Home directory - * @param redir Redirect STDERR to STDOUT? - */ - public Jaxec(final Collection args, final File dir, - final boolean redir) { - this(args, dir, redir, true, new ByteArrayInputStream(new byte[] {})); - } - - /** - * Ctor. - * @param args The command line arguments - * @param dir Home directory - * @param redir Redirect STDERR to STDOUT? - * @param chck Check exit code and fail if it's not zero? - * @param input STDIN - * @checkstyle ParameterNumberCheck (5 lines) - */ - public Jaxec(final Collection args, final File dir, - final boolean redir, final boolean chck, final InputStream input) { - this.arguments = Collections.unmodifiableCollection(args); - this.home = dir; - this.redirect = redir; - this.check = chck; - this.stdin = input; - } - - /** - * With these arguments too. - * @param args The arguments to append - * @return New Jaxec with these new arguments - */ - public Jaxec with(final String... args) { - if (args == null) { - throw new IllegalArgumentException("The list of arguments can't be NULL"); - } - return this.with(Arrays.asList(args)); - } - - /** - * With these arguments too. - * @param args The arguments to append - * @return New Jaxec with a new argument - */ - public Jaxec with(final Iterable args) { - if (args == null) { - throw new IllegalArgumentException("The list of arguments can't be NULL"); - } - final Collection extra = new LinkedList<>(this.arguments); - int pos = 0; - for (final String arg : args) { - pos += 1; - if (arg == null) { - throw new IllegalArgumentException( - String.format("The argument no.%d can't be NULL", pos) - ); - } - extra.add(arg); - } - return new Jaxec(extra, this.home, this.redirect, this.check, this.stdin); - } - - /** - * With checking? - * @param chck If it's TRUE, the exit code of the shell command will be checked - * and an exception will be thrown if it's not zero - * @return New Jaxec with a new checking mechanism - */ - public Jaxec withCheck(final boolean chck) { - return new Jaxec(this.arguments, this.home, this.redirect, chck, this.stdin); - } - - /** - * With home directory. - * @param dir Home directory - * @return New Jaxec with a new home directory - */ - public Jaxec withHome(final Path dir) { - if (dir == null) { - throw new IllegalArgumentException("The HOME can't be NULL"); - } - return this.withHome(dir.toFile()); - } - - /** - * With home directory. - * @param dir Home directory - * @return New Jaxec with a new home directory - */ - public Jaxec withHome(final File dir) { - if (dir == null) { - throw new IllegalArgumentException("The HOME can't be NULL"); - } - return new Jaxec(this.arguments, dir, this.redirect, this.check, this.stdin); - } - - /** - * With home directory. - * @param dir Home directory - * @return New Jaxec with a new home directory - */ - public Jaxec withHome(final String dir) { - if (dir == null) { - throw new IllegalArgumentException("The HOME can't be NULL"); - } - return this.withHome(new File(dir)); - } - - /** - * Redirect STDERR to STDOUT? - * @param redir TRUE if redirect is necessary - * @return New Jaxec with a new redirecting status - */ - public Jaxec withRedirect(final boolean redir) { - return new Jaxec(this.arguments, this.home, redir, this.check, this.stdin); - } - - /** - * The STDIN to send to the process. - * @param input STDIN text - * @return New Jaxec with a new STDIN - */ - public Jaxec withStdin(final String input) { - if (input == null) { - throw new IllegalArgumentException("The STDIN can't be NULL"); - } - return this.withStdin( - new ByteArrayInputStream( - input.getBytes(StandardCharsets.UTF_8) - ) - ); - } - - /** - * The STDIN to send to the process. - * @param bytes STDIN to send to the process - * @return New Jaxec with a new STDIN - */ - public Jaxec withStdin(final byte[] bytes) { - if (bytes == null) { - throw new IllegalArgumentException("The STDIN can't be NULL"); - } - return this.withStdin( - new ByteArrayInputStream(bytes) - ); - } - - /** - * The STDIN to send to the process. - * @param input STDIN text - * @return New Jaxec with a new STDIN - */ - public Jaxec withStdin(final InputStream input) { - if (input == null) { - throw new IllegalArgumentException("The STDIN can't be NULL"); - } - return new Jaxec(this.arguments, this.home, this.redirect, this.check, input); - } - - /** - * Execute it and return the output. - * @return Stdout and stderr together - */ - public String exec() { - try { - return this.execUnsafe(); - } catch (final IOException ex) { - throw new IllegalArgumentException(ex); - } - } - - /** - * Execute it and return the output. - * @return Stdout and stderr together - * @throws IOException If fails - */ - public String execUnsafe() throws IOException { - Logger.debug(this, "+%s", String.join(" ", this.arguments)); - final Process proc = new ProcessBuilder() - .command(new LinkedList<>(this.arguments)) - .directory(this.home) - .redirectErrorStream(this.redirect) - .start(); - try (OutputStream stream = proc.getOutputStream()) { - final byte[] buffer = new byte[1024]; - while (true) { - final int len = this.stdin.read(buffer); - if (len < 0) { - break; - } - stream.write(buffer, 0, len); - } - } - final String stdout; - try (VerboseProcess vproc = new VerboseProcess(proc, Level.FINE, Level.WARNING)) { - final VerboseProcess.Result result; - try { - result = vproc.waitFor(); - } catch (final InterruptedException ex) { - Thread.currentThread().interrupt(); - throw new IllegalStateException(ex); - } - if (this.check && result.code() != 0) { - if (this.redirect) { - Logger.error(this, result.stdout()); - } else { - Logger.error(this, result.stderr()); - } - throw new IllegalArgumentException( - String.format( - "Non-zero exit code #%d of '%s'", - result.code(), this.arguments.iterator().next() - ) - ); - } - stdout = result.stdout(); - } - return stdout; - } -} diff --git a/help/delete-not-utf8.sh b/help/delete-not-utf8.sh new file mode 100644 index 00000000..78740ac1 --- /dev/null +++ b/help/delete-not-utf8.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# The MIT License (MIT) +# +# Copyright (c) 2021-2024 Timur Harin +# +# 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 NON-INFRINGEMENT. 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. +set -e +set -o pipefail + +find . -name "*.java" -exec file -I {} \; | grep -v "utf-8" | awk -F: '{print $1; system("rm " $1)}' From 933a183276ced7d67ca91fae161f975ccd0abe6c Mon Sep 17 00:00:00 2001 From: Timur Harin Date: Tue, 27 Feb 2024 19:50:48 +0300 Subject: [PATCH 2/2] move script to right folder and write a test --- .../041-delete-non-unicode.sh | 25 +++++++++- tests/filters/test-041-delete-non-unicode.sh | 46 +++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) rename help/delete-not-utf8.sh => filters/041-delete-non-unicode.sh (68%) create mode 100644 tests/filters/test-041-delete-non-unicode.sh diff --git a/help/delete-not-utf8.sh b/filters/041-delete-non-unicode.sh similarity index 68% rename from help/delete-not-utf8.sh rename to filters/041-delete-non-unicode.sh index 78740ac1..7a47ac65 100644 --- a/help/delete-not-utf8.sh +++ b/filters/041-delete-non-unicode.sh @@ -20,7 +20,30 @@ # 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. + set -e set -o pipefail -find . -name "*.java" -exec file -I {} \; | grep -v "utf-8" | awk -F: '{print $1; system("rm " $1)}' +home=$1 +temp=$2 + +total=$(find "${home}" -type f | wc -l) + +list=${temp}/filter-lists/non-unicode-files.txt +if [ -e "${list}" ]; then + exit +fi + +mkdir -p "$(dirname "${list}")" +find "${home}" -type f -not -name '*.java' -print > "${list}" +while IFS= read -r f; do + rm -f "${f}" +done < "${list}" + +if [ -s "${list}" ]; then + printf "%'d files out of %'d without the .java extension were deleted\n" \ + "$(wc -l < "${list}" | xargs)" "${total}" +else + printf "%'d files were .java files, nothing was deleted\n" \ + "${total}" +fi \ No newline at end of file diff --git a/tests/filters/test-041-delete-non-unicode.sh b/tests/filters/test-041-delete-non-unicode.sh new file mode 100644 index 00000000..8d633149 --- /dev/null +++ b/tests/filters/test-041-delete-non-unicode.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# The MIT License (MIT) +# +# Copyright (c) 2021-2024 Timur Harin +# +# 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 NON-INFRINGEMENT. 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. + +set -e +set -o pipefail + +temp=$1 +stdout=$2 + +{ + mkdir -p "${temp}/foo" + touch "${temp}/foo/utf8_file.java" + touch "${temp}/foo/non_utf8_file.java" + touch "${temp}/foo/other_file.txt" + echo -e "public class Test {\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(\"Hello, world!\");\n\t}\n}" > "${temp}/foo/utf8_file.java" + echo -e "public class Test {\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(\"Hello, world!\");\n\t}\n}" | iconv -c -t ISO-8859-1 > "${temp}/foo/non_utf8_file.java" + msg=$("${LOCAL}/filters/delete-non-utf8-java-files.sh" "${temp}/foo" "${temp}/temp") + echo "${msg}" + echo "${msg}" | grep "1 non-UTF-8 encoded .java files out of 2 were deleted" + test ! -e "${temp}/foo/non_utf8_file.java" + test -e "${temp}/foo/utf8_file.java" + test -e "${temp}/temp/filter-lists/non-utf8-java-files.txt" + test "$(wc -l < "${temp}/temp/filter-lists/non-utf8-java-files.txt" | xargs)" = 1 +} > "${stdout}" 2>&1 + +echo "👍🏻 Non-UTF-8 encoded Java file was deleted" \ No newline at end of file