Question Peer review of my code

AggerTV

New member
Sep 27, 2023
8
0
1
Hello, I was wondering if someone could peer review one of the methods of my gang plugin

Java:
public CompletableFuture<DataResult<Gang>> getGang(String playerUUID) {
        CompletableFuture<DataResult<Integer>> gangIdFuture = CompletableFuture.supplyAsync(() -> memberDAO.getGangID(playerUUID))
                .exceptionally(e -> {
                   LoggerUtil.log(Level.SEVERE, "error getting the gang id");
                   return DataResult.failure();
                });

        CompletableFuture<DataResult<Gang>> gangFuture = gangIdFuture.thenComposeAsync(dataResult ->
                CompletableFuture.supplyAsync(() -> gangDAO.getGang(dataResult.getData()))
                        .exceptionally(e -> {
                            LoggerUtil.log(Level.SEVERE, "could not get the gang data");
                            return DataResult.failure();
                        }));

        CompletableFuture<DataResult<Set<GangMember>>> membersFuture = gangIdFuture.thenComposeAsync(dataResult ->
                CompletableFuture.supplyAsync(() -> memberDAO.getGangMembers(dataResult.getData()))
                        .exceptionally(e -> {
                            LoggerUtil.log(Level.SEVERE, "could not get the gangs member data");
                            return DataResult.failure();
                        }));

        return gangFuture.thenCombineAsync(membersFuture, ((gangDataResult, setDataResult) -> {
            if (gangDataResult.wasSuccessful() && setDataResult.wasSuccessful()) {
                Gang gang = gangDataResult.getData();
                gang.setMembers(setDataResult.getData());

                return DataResult.success(gang);
            }
            LoggerUtil.log(Level.SEVERE, "could not combine the 2 futures");
            return DataResult.failure();
        }));
    }

Explanation
The above code is designed to fetch and construct a Gang object whose data is stored in a database. It performs the following steps:
1. It retrieves the gang's unique identifier.
2. It uses the identifier to get the gang information and all it's members.
3. It combines the fetched data to construct the Gang object.

I have tried making it as efficient as possible, by firstly running the code asynchronously, but more importantly by using the thenCompose method to chain the database calls together.

This is how I use the method, to load the gang objects when a member of any gang joins the server

Java:
@EventHandler(ignoreCancelled = true)
    public void onPlayerJoin(PlayerJoinEvent event) {
        Player player = event.getPlayer();
        if (!gangManager.isGangMember(player.getUniqueId())) {
            return;
        }

        if (!gangManager.isCached(player)) {
            gangService.getGang(player.getUniqueId().toString())
                            .thenAcceptAsync(gangDataResult -> {
                                if (gangDataResult.wasSuccessful()) {
                                    gangManager.cacheGang(gangDataResult.getData());
                                    LoggerUtil.log(Level.INFO, "cached gang: " + gangDataResult.getData().getName());
                                    return;
                                }
                                LoggerUtil.log(Level.SEVERE, "could not cache the gang: " + gangDataResult.getMessage());
                            }, Bukkit.getScheduler().getMainThreadExecutor(plugin));
        }
    }

I am especially interested in hearing if I have my usage of Completablefutures are correct, or if it can be further optimised.