Tubing Core

The core plugin provides the IocContainer for Tubing framework. This dependency is always needed when developing a Tubing plugin

Beans

A Tubing bean is an instance of a class registered inside the Tubing IOC container. A bean can be registered in 2 ways.

  • Annotating the class with a bean annotation. The core plugin only provides @IocBean. But other dependencies can declare there own annotations to instantiate beans. This can be seen, for example, in the tubing-bukkit extension.

  • Providing the bean through a @TubingConfiguration class and provider method

A Tubing bean can only have one constructor! The parameters of the constructor can only be other Tubing beans or configuration properties injected with an @ConfigProperty annotation

Tubing can inject beans in 3 ways:

  • Inject a concrete class instance

  • Inject an interface with exactly one implementation

  • Inject a List of interface implementations.

Injection

Constructor injection

To inject properties we need to provide all needed beans inside the constructor of the class. Tubing will search for the dependencies and inject them.

@IocBean
public class ReportService {

    private final PermissionHandler permission;
    private final ReportRepository reportRepository;

    public ReportService(PermissionHandler permission, ReportRepository reportRepository) {
        this.permission = permission;
        this.reportRepository= reportRepository;
    }
}

Interface injection

If you have an interface with one implementation registered at runtime, Tubing will inject this one implementation. If you have multiple implementation of one interface at runtime Tubing will throw an exception indicating it can not inject the dependency as it does not know which to Inject. The permission handler is a good example of this. If you want multiple implementations of an interface you need a @IocMultiProvider and use List Injection.

List injection

You can inject a list of classes which all implement the same interface. To do so you need to annotate the bean with @IocMultiProvider and when injection you need to use the @IocMulti annotation.

An example of this could be (this is not a good example):

@IocBean
@IocMultiProvider(Listener.class)
public class PlayerJoinListener implements Listener {
}
@IocBean
@IocMultiProvider(Listener.class)
public class AsyncPlayerChatListener implements Listener {
}
@IocBean
public class AllListenersExample {

    private final List<Listener> listeners;
    
    public AllListenersExample(@IocMulti(Listener.class) List<Listener> listeners){
        this.listeners = listeners;
    }
}

Example

ReportService bean

The ReportService is an example of a concrete class that is registered as a Tubing bean

import be.garagepoort.mcioc.IocBean;

@IocBean
public class ReportService {

    private final PermissionHandler permission;
    private final ReportRepository reportRepository;

    public ReportService(PermissionHandler permission, ReportRepository reportRepository) {
        this.permission = permission;
        this.reportRepository= reportRepository;
    }
 
    ...
}

ReportRepository bean

The ReportRepository is an interface that will have at runtime one bean registered inside the IOC container.

public interface ReportRepository {

    int addReport(Report report);

}

Mysql implementation

Notice the conditionalOnProperty . This means this specific implementation will only be instantiated and registered if the storage.type inside the config.yml is set to mysql.

@IocBean(conditionalOnProperty = "storage.type=mysql")
public class MysqlReportRepository implements ReportRepository {

    @Override
    public int addReport(Report report) {
        ...
    }

}

Sqlite implementation

Notice the conditionalOnProperty . This means this specific implementation will only be instantiated and registered if the storage.type inside the config.yml is set to sqlite.

@IocBean(conditionalOnProperty = "storage.type=sqlite")
public class SqliteReportRepository implements ReportRepository {

    @Override
    public int addReport(Report report) {
        ...
    }

}

PermissionHandler bean

The permission handler in this example is an interface that will have at runtime one bean registered.

public interface PermissionHandler {

    boolean has(Player player, String permission);

}

The below implementations are not annotated with the @IocBean annotation. This is because they are registered with a provider method.

DefaultPermissionHandler

public class DefaultPermissionHandler implements PermissionHandler {
    private Options options;

    public DefaultPermissionHandler(Options options) {
        this.options = options;
    }

    public boolean has(Player player, String permission) {
        ...
    }
}

GroupManagerPermissionHandler

public class GroupManagerPermissionHandler implements PermissionHandler {

    private final Options options;
    private final GroupManager gMplugin;

    public GroupManagerPermissionHandler(Options options) {
        this.options = options;
        ...
    }

    public boolean has(Player player, String permission) {
        ...
    }
}

VaultPermissionHandler

public class VaultPermissionHandler implements PermissionHandler {

    private static Permission perms = null;
    private final Options options;

    public VaultPermissionHandler(Options options) {
        this.options = options;
        ...
    }

    public boolean has(Player player, String permission) {
        ...
    }

}

Provider method

The below method decides which bean to register at runtime. This is another way to conditionally choose which interface implementation to register at runtime.

The provider method needs to be static!

@TubingConfiguration
public class TubingConfiguration {

    @IocBeanProvider
    public static PermissionHandler instantiatePermissionHandler(Options options) {
        final PluginManager pluginManager = TubingExample.get().getServer().getPluginManager();
        Plugin gMplugin = pluginManager.getPlugin("GroupManager");
        if(gMplugin != null && gMplugin.isEnabled()) {
            TubingExample.get().getLogger().info("GroupManager found. Permissions will be handled by GroupManager");
            return new GroupManagerPermissionHandler(options);
        }

        RegisteredServiceProvider<Permission> registration = Bukkit.getServer().getServicesManager().getRegistration(Permission.class);
        if (registration != null) {
            TubingExample.get().getLogger().info("Vault found. Permissions will be handled by Vault");
            return new VaultPermissionHandler(options);
        }

        TubingExample.get().getLogger().info("Permissions handled by Bukkit");
        return new DefaultPermissionHandler(options);
    }
}

Last updated