Begin JavaDoc, Tweaks

This commit is contained in:
Paldiu 2022-11-21 20:45:23 -06:00
parent c8b5afe1dd
commit 93c33512be
7 changed files with 175 additions and 42 deletions

View File

@ -1,32 +1,70 @@
package io.github.simplex.api; package io.github.simplex.api;
import io.github.simplex.simplexss.ServicePool;
import org.bukkit.NamespacedKey;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public abstract class ExecutableService implements IService { public abstract class ExecutableService implements IService {
private final int serviceID; private final NamespacedKey service_name;
private final Plugin plugin; private final Plugin plugin;
private final long delay; private final long delay;
private final long period; private final long period;
private final boolean repeating; private final boolean repeating;
public ExecutableService(Plugin plugin, int serviceID, long delay, long period, boolean repeating) { private boolean cancelled = false;
/**
* Creates a new instance of an executable service.
* The timings are measured in ticks (20 ticks per second).
* You do not need to explicitly define a delay or a period,
* however if you have flagged {@link #repeating} as true, and the period is null,
* then the period will automatically be set to 20 minutes.
* Each service is registered with a {@link NamespacedKey},
* to allow for easy identification within the associated {@link ServicePool}.
* Each service also has a plugin parameter to allow for easy dependency injection.
*
* @param plugin Your plugin
* @param service_name A namespaced key which can be used to identify the service.
* @param delay A specified amount of time (in ticks) to wait before the service runs.
* @param period How long the service should wait between service executions (in ticks).
* @param repeating If the service should be scheduled for repeated executions or not.
*/
public ExecutableService(@NotNull Plugin plugin, @NotNull NamespacedKey service_name, @Nullable Long delay, @Nullable Long period, @NotNull Boolean repeating) {
this.plugin = plugin; this.plugin = plugin;
this.serviceID = serviceID; this.service_name = service_name;
this.repeating = repeating; this.repeating = repeating;
this.delay = delay; this.delay = Objects.requireNonNullElse(delay, 0L);
this.period = period; this.period = Objects.requireNonNullElse(period, (20L * 60L) * 20L);
} }
/**
* @return The NamespacedKey of this service.
*/
@Override @Override
public int getServiceID() { public NamespacedKey getNamespacedKey() {
return serviceID; return service_name;
} }
/**
* @return The plugin which was defined in the constructor.
* This should be an instance of your main plugin class.
*/
@Override @Override
public Plugin getProvidingPlugin() { public Plugin getProvidingPlugin() {
return plugin; return plugin;
} }
/**
* @return
*/
@Override @Override
public long getDelay() { public long getDelay() {
return delay; return delay;
@ -38,7 +76,22 @@ public abstract class ExecutableService implements IService {
} }
@Override @Override
public boolean isRepeating() { public boolean isPeriodic() {
return repeating; return repeating;
} }
@Override
public void setCancelled(boolean mayInterruptIfRunning) {
if (!mayInterruptIfRunning) {
cancelled = false;
}
stop();
cancelled = true;
}
@Override
public boolean isCancelled() {
return this.cancelled;
}
} }

View File

@ -1,14 +1,21 @@
package io.github.simplex.api; package io.github.simplex.api;
import org.bukkit.NamespacedKey;
import org.bukkit.event.Cancellable;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.util.concurrent.RunnableScheduledFuture; public interface IService extends Runnable, Cancellable {
@Contract(" -> new")
static @NotNull NamespacedKey getDefaultNamespacedKey() {
return new NamespacedKey("simplex_ss", "default_service_name");
}
public interface IService extends RunnableScheduledFuture<IService> { NamespacedKey getNamespacedKey();
int getServiceID();
boolean isRepeating(); boolean isPeriodic();
long getPeriod(); long getPeriod();

View File

@ -0,0 +1,20 @@
package io.github.simplex.impl;
import io.github.simplex.simplexss.SchedulingSystem;
import io.github.simplex.simplexss.ServiceManager;
import org.bukkit.plugin.java.JavaPlugin;
public class Main extends JavaPlugin {
private SchedulingSystem scheduler;
private ServiceManager serviceManager;
@Override
public void onEnable() {
this.serviceManager = new ServiceManager(this);
this.scheduler = new SchedulingSystem(serviceManager, this);
}
@Override
public void onDisable() {
}
}

View File

@ -0,0 +1,30 @@
package io.github.simplex.impl;
import io.github.simplex.api.ExecutableService;
import io.github.simplex.api.IService;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono;
import java.util.concurrent.TimeUnit;
public class ServiceImpl extends ExecutableService {
public ServiceImpl(Main plugin) {
super(plugin, IService.getDefaultNamespacedKey(), 20L, 20L * 60L * 10L, true);
}
@Override
public Mono<Void> start() {
return null;
}
@Override
public Mono<Void> stop() {
return null;
}
@Override
public void run() {
super.run();
}
}

View File

@ -3,12 +3,15 @@ package io.github.simplex.simplexss;
import io.github.simplex.api.ISchedule; import io.github.simplex.api.ISchedule;
import io.github.simplex.api.IService; import io.github.simplex.api.IService;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
public final class SchedulingSystem implements ISchedule { public final class SchedulingSystem implements ISchedule {
private final ServiceManager serviceManager; private final ServiceManager serviceManager;
@ -41,7 +44,9 @@ public final class SchedulingSystem implements ISchedule {
public Mono<ServicePool> queue(@NotNull IService service) { public Mono<ServicePool> queue(@NotNull IService service) {
return getServiceManager().flatMap(serviceManager -> { return getServiceManager().flatMap(serviceManager -> {
Mono<ServicePool> pool = serviceManager.getAssociatedServicePool(service); Mono<ServicePool> pool = serviceManager.getAssociatedServicePool(service);
return pool.defaultIfEmpty(Objects.requireNonNull(serviceManager.createServicePool(service).block())); return pool.defaultIfEmpty(Objects.requireNonNull(serviceManager
.createServicePool(ServicePool.getDefaultNamespacedKey(), service)
.block()));
}); });
} }

View File

@ -1,6 +1,7 @@
package io.github.simplex.simplexss; package io.github.simplex.simplexss;
import io.github.simplex.api.IService; import io.github.simplex.api.IService;
import org.bukkit.NamespacedKey;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -10,7 +11,6 @@ import reactor.core.publisher.Mono;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream;
public final class ServiceManager { public final class ServiceManager {
private final Set<ServicePool> servicePools; private final Set<ServicePool> servicePools;
@ -21,22 +21,27 @@ public final class ServiceManager {
servicePools = new HashSet<>(); servicePools = new HashSet<>();
} }
@Contract(pure = true, value = "_ -> new") @Contract(pure = true, value = "_, _ -> new")
public @NotNull Mono<ServicePool> createServicePool(IService... services) { public @NotNull Mono<ServicePool> createServicePool(NamespacedKey poolName, IService... services) {
ServicePool pool = new ServicePool(false); ServicePool pool = new ServicePool(poolName, false);
Stream.of(services).forEach(pool::addService); Flux.fromIterable(Arrays.asList(services)).doOnEach(s -> pool.addService(s.get()));
return Mono.just(pool); return Mono.just(pool);
} }
public @NotNull Mono<ServicePool> multithreadedServicePool(IService... services) { @Contract(pure = true, value = "_, _ -> new")
ServicePool pool = new ServicePool(true); public @NotNull Mono<ServicePool> multithreadedServicePool(NamespacedKey name, IService... services) {
Flux.fromIterable(Arrays.asList(services)).doOnEach(s -> { ServicePool pool = new ServicePool(name, true);
pool.addService(s.get()); Flux.fromIterable(Arrays.asList(services)).doOnEach(s -> pool.addService(s.get()));
});
return Mono.just(pool); return Mono.just(pool);
} }
@Contract("_, _ -> param1") @Contract(pure = true, value = "_, _ -> new")
public @NotNull Mono<ServicePool> emptyServicePool(NamespacedKey poolName, boolean multithreaded) {
ServicePool pool = new ServicePool(poolName, multithreaded);
return Mono.just(pool);
}
@Contract("_, _ -> new")
public @NotNull Mono<ServicePool> addToExistingPool(@NotNull ServicePool pool, IService... services) { public @NotNull Mono<ServicePool> addToExistingPool(@NotNull ServicePool pool, IService... services) {
Flux.fromIterable(Arrays.asList(services)).doOnEach(s -> { Flux.fromIterable(Arrays.asList(services)).doOnEach(s -> {
pool.addService(s.get()); pool.addService(s.get());
@ -44,7 +49,7 @@ public final class ServiceManager {
return Mono.just(pool); return Mono.just(pool);
} }
@Contract("_, _ -> param1") @Contract("_, _ -> new")
public @NotNull Mono<ServicePool> takeFromExistingPool(@NotNull ServicePool pool, IService... services) { public @NotNull Mono<ServicePool> takeFromExistingPool(@NotNull ServicePool pool, IService... services) {
Flux.fromIterable(Arrays.asList(services)).doOnEach(s -> { Flux.fromIterable(Arrays.asList(services)).doOnEach(s -> {
pool.removeService(s.get()); pool.removeService(s.get());
@ -52,14 +57,17 @@ public final class ServiceManager {
return Mono.just(pool); return Mono.just(pool);
} }
@Contract(" -> new")
public @NotNull Flux<ServicePool> getServicePools() { public @NotNull Flux<ServicePool> getServicePools() {
return Flux.fromIterable(servicePools); return Flux.fromIterable(servicePools);
} }
@Contract(pure = true)
public boolean locateServiceWithinPools(IService service) { public boolean locateServiceWithinPools(IService service) {
return servicePools.stream().map(p -> p.isValidService(service)).findFirst().orElseGet(() -> false); return servicePools.stream().map(p -> p.isValidService(service)).findFirst().orElseGet(() -> false);
} }
@Contract("_ -> new")
public @NotNull Mono<ServicePool> getAssociatedServicePool(IService service) { public @NotNull Mono<ServicePool> getAssociatedServicePool(IService service) {
if (!locateServiceWithinPools(service)) return Mono.empty(); if (!locateServiceWithinPools(service)) return Mono.empty();
return getServicePools() return getServicePools()
@ -67,6 +75,7 @@ public final class ServiceManager {
.next(); .next();
} }
@Contract("-> _")
public Plugin getProvidingPlugin() { public Plugin getProvidingPlugin() {
return plugin; return plugin;
} }

View File

@ -1,6 +1,7 @@
package io.github.simplex.simplexss; package io.github.simplex.simplexss;
import io.github.simplex.api.IService; import io.github.simplex.api.IService;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import reactor.core.Disposable; import reactor.core.Disposable;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
@ -17,16 +18,23 @@ import java.util.concurrent.TimeUnit;
public final class ServicePool { public final class ServicePool {
private final Set<IService> associatedServices; private final Set<IService> associatedServices;
private final Scheduler scheduler; private final Scheduler scheduler;
private final NamespacedKey name;
private static final NamespacedKey DEFAULT = new NamespacedKey("simplex_ss", "default_service_pool");
public ServicePool(boolean multithreaded) { public ServicePool(NamespacedKey name, boolean multithreaded) {
this.name = name;
this.associatedServices = new HashSet<>(); this.associatedServices = new HashSet<>();
if (multithreaded) { if (multithreaded) {
this.scheduler = Schedulers.fromExecutorService(Executors.newFixedThreadPool(4)); this.scheduler = Schedulers.newBoundedElastic(4, 10, "");
} else { } else {
this.scheduler = Schedulers.fromExecutorService(Executors.newSingleThreadExecutor()); this.scheduler = Schedulers.fromExecutorService(Executors.newSingleThreadExecutor());
} }
} }
static NamespacedKey getDefaultNamespacedKey() {
return DEFAULT;
}
void addService(IService service) { void addService(IService service) {
getAssociatedServices().add(service); getAssociatedServices().add(service);
} }
@ -40,17 +48,17 @@ public final class ServicePool {
return associatedServices; return associatedServices;
} }
public Mono<Disposable> startService(int serviceID) { public Mono<Disposable> startService(NamespacedKey service_name) {
Mono<IService> service = getService(serviceID); Mono<IService> service = getService(service_name);
return service.map(s -> { return service.map(s -> {
if (s.isRepeating()) { if (s.isPeriodic()) {
return scheduler.schedulePeriodically(s, return scheduler.schedulePeriodically(s,
s.getDelay() * 5, s.getDelay() * 50,
s.getPeriod() * 5, s.getPeriod() * 50,
TimeUnit.MILLISECONDS); TimeUnit.MILLISECONDS);
} }
return scheduler.schedule(s, return scheduler.schedule(s,
s.getDelay() * 5, s.getDelay() * 50,
TimeUnit.MILLISECONDS); TimeUnit.MILLISECONDS);
}); });
@ -60,16 +68,17 @@ public final class ServicePool {
return Mono.just(getAssociatedServices()).flatMapMany(services -> { return Mono.just(getAssociatedServices()).flatMapMany(services -> {
Set<Disposable> disposables = new HashSet<>(); Set<Disposable> disposables = new HashSet<>();
for (IService service : services) { for (IService service : services) {
if (service.isRepeating()) { if (service.isPeriodic()) {
disposables.add(scheduler.schedulePeriodically(service, disposables.add(scheduler.schedulePeriodically(service,
service.getDelay() * 5, service.getDelay() * 50,
service.getPeriod() * 5, service.getPeriod() * 50,
TimeUnit.MILLISECONDS)); TimeUnit.MILLISECONDS));
} else { } else {
disposables.add(scheduler.schedule(service)); disposables.add(scheduler.schedule(service,
service.getDelay() * 50,
TimeUnit.MILLISECONDS));
} }
} }
;
return Flux.fromIterable(disposables); return Flux.fromIterable(disposables);
}); });
} }
@ -78,13 +87,13 @@ public final class ServicePool {
return disposableThread.doOnNext(Disposable::dispose).then(); return disposableThread.doOnNext(Disposable::dispose).then();
} }
public Mono<Void> stopService(int serviceID) { public Mono<Void> stopService(NamespacedKey service_name) {
return getService(serviceID).doOnNext(IService::stop).then(); return getService(service_name).doOnNext(IService::stop).then();
} }
public Mono<IService> getService(int serviceID) { public Mono<IService> getService(NamespacedKey service_name) {
return Flux.fromIterable(getAssociatedServices()) return Flux.fromIterable(getAssociatedServices())
.filter(service -> service.getServiceID() == serviceID) .filter(service -> service.getNamespacedKey().equals(service_name))
.next(); .next();
} }