Skip to content
LeeGod edited this page Dec 2, 2021 · 2 revisions

ComponentRegistry

ComponentRegistry is the parent handler of Component. When scanning through Component, it will search existing ComponentRegistry to find which ComponentRegistry accepts it. It will only accept Component object that are instance of one of the class in a list where you provided. after accepted, the Component will be completely managed by ComponentRegistry, including constructing, onEnable, onDisable etc.

Define acceptable class

Before creating registry, you should define a class that this registry accepts. Here's some example:

In this example, it will be an expand from Service's example. We want to add a DataChecker system for ExampleService where it verifies the data got added is valid. and for maximum flexibility, we want an easier way to add more DataCheckers. In this case the Component system will fit the case perfectly.

package io.fairyproject.examplePlugin;

import java.util.UUID;

public interface DataChecker {
    
    boolean verify(UUID uuid, String data);
    
}

The acceptable class can be either abstract class or interface, BUT shouldn't be final class that cannot be extend/implemented

Create a Registry

After defining the acceptable class, We want to register the Registry in order to accept it and made it working. To create a Registry, you will need to create an instance of io.fairyproject.container.ComponentHolder.

There are two ways you can do it.

1. Builder Pattern

        io.fairyproject.container.ComponentHolder componentHolder = ComponentHolder.builder()
                .type(CLASS.class)
                .onEnable(obj -> {
                    // On instance enabled
                })
                .onDisable(obj -> {
                    // On instance disabled
                })
                .build();

2. Class Pattern

        io.fairyproject.container.ComponentHolder componentHolder = new ComponentHolder() {
            @Override
            public Class<?>[] type() {
                return new Class[] { CLASS.class };
            }

            @Override
            public void onEnable(Object obj) {
                // On instance enabled
            }

            @Override
            public void onDisable(Object obj) {
                // On instance disabled
            }
        };

After having ComponentHolder, you can use io.fairyproject.container.ComponentRegistry.registerComponentHolder(componentHolder) to register it.

In our example we will be using Builder Pattern.

So for our example, we want to accept DataChecker in our registry, and storing the Component instance somewhere so we can iterate through whenever a data is adding in. So here is the example code:

package io.fairyproject.examplePlugin;

import io.fairyproject.container.ComponentHolder;
import io.fairyproject.container.ComponentRegistry;
import io.fairyproject.container.PostInitialize;
import io.fairyproject.container.PreInitialize;
import io.fairyproject.container.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Service
public class ExampleService {
    private Map<UUID, String> dataByUuid;
    private List<DataChecker> dataCheckers; // The list of DataChecker instances we are storing
    private UUID mainUuid;

    // We are doing it on PRE_INIT state.
    // This is very important, we will explain after
    @PreInitialize
    public void onPreInitialize() {
        final ComponentHolder componentHolder = ComponentHolder.builder()
                .type(DataChecker.class) // We accepts DataChecker here, but note that it support multiple types
                .onEnable(obj -> this.dataCheckers.add((DataChecker) obj)) // Add the instance into list on Enable
                .onDisable(obj -> this.dataCheckers.remove((DataChecker) obj)) // Remove the instance from list on Disable
                .build();
        ComponentRegistry.register(componentHolder);
    }
...

Important note for registering Component Registry

Component Registry must be registered before Components initialization, otherwise when Component getting intialize it couldn't find an acceptable registry for it. That's why in the example above, we are registering in PRE_INIT state.

Creating Component

After everything above, you've done the basic setup for ComponentRegistry, now you can start creating component for your registry! Detailed Component Explaination

package io.fairyproject.examplePlugin;

import io.fairyproject.container.Component;

import java.util.UUID;

@Component
public class ExampleDataChecker implements DataChecker {
    @Override
    public boolean verify(UUID uuid, String data) {
        return data.equals("example");
    }
}

Start using registered component instances

Now we can start iterate through the components we've registered!

    public void add(UUID uuid, String data) {
        // Iterate through data checker list
        for (DataChecker dataChecker : this.dataCheckers) {
            if (!dataChecker.verify(uuid, data)) {
                throw new IllegalArgumentException("Failed to pass Data Checker " + dataChecker.getClass().getSimpleName());
            }
        }
        this.dataByUuid.put(uuid, data);
    }

And after all of these, when we try to do ExampleService.add(uuid, "example"), if you received IllegalArgumentException, that means it registered successfully!

More Real World Scenarios

  • UHC's Scenarios
  • AntiCheat's Checks
  • and even more similar structures!