🚚 Switch namespace

This commit is contained in:
Alexander Söderberg 2020-09-27 23:04:15 +02:00
parent 0064093dbf
commit c74cda3a0f
No known key found for this signature in database
GPG key ID: C0207FF7EA146678
207 changed files with 2689 additions and 611 deletions

View file

@ -0,0 +1,98 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services;
import com.google.common.base.Objects;
import cloud.commandframework.services.annotations.Order;
import cloud.commandframework.services.types.Service;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
class AnnotatedMethodService<Context, Result> implements Service<Context, Result> {
private final ExecutionOrder executionOrder;
private final MethodHandle methodHandle;
private final Method method;
private final Object instance;
AnnotatedMethodService(@Nonnull final Object instance, @Nonnull final Method method)
throws Exception {
ExecutionOrder executionOrder = ExecutionOrder.SOON;
try {
final Order order = method.getAnnotation(Order.class);
if (order != null) {
executionOrder = order.value();
}
} catch (final Exception ignored) {
}
this.instance = instance;
this.executionOrder = executionOrder;
method.setAccessible(true);
this.methodHandle = MethodHandles.lookup().unreflect(method);
this.method = method;
}
@Nullable
@Override
@SuppressWarnings("unchecked")
public Result handle(@Nonnull final Context context) {
try {
return (Result) this.methodHandle.invoke(this.instance, context);
} catch (final Throwable throwable) {
new IllegalStateException(String
.format("Failed to call method service implementation '%s' in class '%s'",
method.getName(), instance.getClass().getCanonicalName()), throwable)
.printStackTrace();
}
return null;
}
@Nonnull
@Override
public ExecutionOrder order() {
return this.executionOrder;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final AnnotatedMethodService<?, ?> that = (AnnotatedMethodService<?, ?>) o;
return Objects.equal(this.methodHandle, that.methodHandle);
}
@Override
public int hashCode() {
return Objects.hashCode(this.methodHandle);
}
}

View file

@ -0,0 +1,61 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services;
import com.google.common.reflect.TypeToken;
import cloud.commandframework.services.annotations.ServiceImplementation;
import cloud.commandframework.services.types.Service;
import javax.annotation.Nonnull;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
enum AnnotatedMethodServiceFactory {
INSTANCE;
Map<? extends Service<?, ?>, TypeToken<? extends Service<?, ?>>> lookupServices(
@Nonnull final Object instance) throws Exception {
final Map<Service<?, ?>, TypeToken<? extends Service<?, ?>>> map = new HashMap<>();
final Class<?> clazz = instance.getClass();
for (final Method method : clazz.getDeclaredMethods()) {
final ServiceImplementation serviceImplementation =
method.getAnnotation(ServiceImplementation.class);
if (serviceImplementation == null) {
continue;
}
if (method.getParameterCount() != 1) {
throw new IllegalArgumentException(String.format(
"Method '%s' in class '%s'" + " has wrong parameter count. Expected 1, got %d",
method.getName(), instance.getClass().getCanonicalName(),
method.getParameterCount()));
}
map.put(new AnnotatedMethodService<>(instance, method),
TypeToken.of(serviceImplementation.value()));
}
return map;
}
}

View file

@ -0,0 +1,32 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services;
/**
* Used to specify the relative priority of a service implementation
*/
@SuppressWarnings("unused")
public enum ExecutionOrder {
LAST, LATER, LATE, SOON, SOONER, FIRST
}

View file

@ -0,0 +1,54 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services;
import javax.annotation.Nonnull;
/**
* Wrapper for exceptions thrown during pipeline execution.
*
* @see #getCause() Use {@link #getCause()} to get the wrapped exception
*/
public final class PipelineException extends RuntimeException {
/**
* Construct a new pipeline exception
*
* @param cause Cause of the exception
*/
public PipelineException(@Nonnull final Exception cause) {
super(cause);
}
/**
* Construct a new pipeline exception
*
* @param message Message explaining the exception
* @param cause Cause of the exception
*/
public PipelineException(@Nonnull final String message, @Nonnull final Exception cause) {
super(message, cause);
}
}

View file

@ -0,0 +1,53 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services;
import cloud.commandframework.services.types.Service;
import javax.annotation.Nonnull;
import java.util.function.Predicate;
enum ServiceFilterHandler {
INSTANCE;
<Context> boolean passes(
@Nonnull final ServiceRepository<Context, ?>.ServiceWrapper<? extends Service<Context, ?>> service,
@Nonnull final Context context) {
if (!service.isDefaultImplementation()) {
for (final Predicate<Context> predicate : service.getFilters()) {
try {
if (!predicate.test(context)) {
return false;
}
} catch (final Exception e) {
throw new PipelineException(String
.format("Failed to evaluate filter '%s' for '%s'",
predicate.getClass().getCanonicalName(), service.toString()), e);
}
}
}
return true;
}
}

View file

@ -0,0 +1,153 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services;
import com.google.common.reflect.TypeToken;
import cloud.commandframework.services.annotations.Order;
import cloud.commandframework.services.types.Service;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;
/**
* Repository that contains implementations for a given service type
*
* @param <Context> Service context
* @param <Response> Service response type
*/
public final class ServiceRepository<Context, Response> {
private final Object lock = new Object();
private final TypeToken<? extends Service<Context, Response>> serviceType;
private final List<ServiceWrapper<? extends Service<Context, Response>>> implementations;
private int registrationOrder = 0;
/**
* Create a new service repository for a given service type
*
* @param serviceType Service type
*/
ServiceRepository(@Nonnull final TypeToken<? extends Service<Context, Response>> serviceType) {
this.serviceType = serviceType;
this.implementations = new LinkedList<>();
}
/**
* Register a new implementation for the service
*
* @param service Implementation
* @param filters Filters that will be used to determine whether or not the service gets used
* @param <T> Type of the implementation
*/
<T extends Service<Context, Response>> void registerImplementation(@Nonnull final T service,
@Nonnull final Collection<Predicate<Context>> filters) {
synchronized (this.lock) {
this.implementations.add(new ServiceWrapper<>(service, filters));
}
}
/**
* Get a queue containing all implementations
*
* @return Queue containing all implementations
*/
@Nonnull
LinkedList<ServiceWrapper<? extends Service<Context, Response>>> getQueue() {
synchronized (this.lock) {
return new LinkedList<>(this.implementations);
}
}
/**
* Used to store {@link Service} implementations together with their state
*
* @param <T> Service type
*/
final class ServiceWrapper<T extends Service<Context, Response>>
implements Comparable<ServiceWrapper<T>> {
private final boolean defaultImplementation;
private final T implementation;
private final Collection<Predicate<Context>> filters;
private final int registrationOrder = ServiceRepository.this.registrationOrder++;
private final ExecutionOrder executionOrder;
private ServiceWrapper(@Nonnull final T implementation,
@Nonnull final Collection<Predicate<Context>> filters) {
this.defaultImplementation = implementations.isEmpty();
this.implementation = implementation;
this.filters = filters;
ExecutionOrder executionOrder = implementation.order();
if (executionOrder == null) {
final Order order = implementation.getClass().getAnnotation(Order.class);
if (order != null) {
executionOrder = order.value();
} else {
executionOrder = ExecutionOrder.SOON;
}
}
this.executionOrder = executionOrder;
}
@Nonnull
T getImplementation() {
return this.implementation;
}
@Nonnull
Collection<Predicate<Context>> getFilters() {
return Collections.unmodifiableCollection(this.filters);
}
boolean isDefaultImplementation() {
return this.defaultImplementation;
}
@Override
public String toString() {
return String
.format("ServiceWrapper{type=%s,implementation=%s}", serviceType.toString(),
TypeToken.of(implementation.getClass()).toString());
}
@Override
public int compareTo(@Nonnull final ServiceWrapper<T> other) {
return Comparator.<ServiceWrapper<T>>comparingInt(
wrapper -> wrapper.isDefaultImplementation()
? Integer.MIN_VALUE
: Integer.MAX_VALUE).thenComparingInt(wrapper -> wrapper.executionOrder.ordinal())
.thenComparingInt(wrapper -> wrapper.registrationOrder).compare(this, other);
}
}
}

View file

@ -0,0 +1,173 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services;
import com.google.common.reflect.TypeToken;
import cloud.commandframework.services.types.ConsumerService;
import cloud.commandframework.services.types.Service;
import cloud.commandframework.services.types.SideEffectService;
import javax.annotation.Nonnull;
import java.util.LinkedList;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
/**
* Class that outputs results from the given context, using the specified service type
*
* @param <Context> Context type
* @param <Result> Result type
*/
public final class ServiceSpigot<Context, Result> {
private final Context context;
private final ServicePipeline pipeline;
private final ServiceRepository<Context, Result> repository;
ServiceSpigot(@Nonnull final ServicePipeline pipeline, @Nonnull final Context context,
@Nonnull final TypeToken<? extends Service<Context, Result>> type) {
this.context = context;
this.pipeline = pipeline;
this.repository = pipeline.getRepository(type);
}
/**
* Get the first result that is generated for the given context. This cannot return {@code null}.
* If nothing manages to produce a result, an exception will be thrown. If the pipeline has been
* constructed properly, this will never happen.
*
* @return Generated result
* @throws IllegalStateException If no result was found. This only happens if the pipeline has not
* been constructed properly. The most likely cause is a faulty
* default implementation
* @throws IllegalStateException If a {@link SideEffectService} returns {@code null}
* @throws PipelineException Any exceptions thrown during result retrieval from the
* implementations will be wrapped by {@link PipelineException}. Use
* {@link PipelineException#getCause()} to get the exception that
* was thrown.
* @throws PipelineException Any exceptions thrown during filtering will be wrapped by {@link
* PipelineException}. Use {@link PipelineException#getCause()} to
* get the exception that was thrown.
* @see PipelineException PipelineException wraps exceptions thrown during filtering and result
* retrieval
*/
@Nonnull
@SuppressWarnings("unchecked")
public Result getResult()
throws IllegalStateException, PipelineException {
final LinkedList<? extends ServiceRepository<Context, Result>.ServiceWrapper<? extends Service<Context, Result>>>
queue = this.repository.getQueue();
queue.sort(null); // Sort using the built in comparator method
ServiceRepository<Context, Result>.ServiceWrapper<? extends Service<Context, Result>>
wrapper;
boolean consumerService = false;
while ((wrapper = queue.pollLast()) != null) {
consumerService = wrapper.getImplementation() instanceof ConsumerService;
if (!ServiceFilterHandler.INSTANCE.passes(wrapper, this.context)) {
continue;
}
final Result result;
try {
result = wrapper.getImplementation().handle(this.context);
} catch (final Exception e) {
throw new PipelineException(
String.format("Failed to retrieve result from %s", wrapper.toString()), e);
}
if (wrapper.getImplementation() instanceof SideEffectService) {
if (result == null) {
throw new IllegalStateException(
String.format("SideEffectService '%s' returned null", wrapper.toString()));
} else if (result == State.ACCEPTED) {
return result;
}
} else if (result != null) {
return result;
}
}
// This is hack to make it so that the default
// consumer implementation does not have to call #interrupt
if (consumerService) {
return (Result) State.ACCEPTED;
}
throw new IllegalStateException(
"No service consumed the context. This means that the pipeline was not constructed properly.");
}
/**
* Get the first result that is generated for the given context. If nothing manages to produce a
* result, an exception will be thrown. If the pipeline has been constructed properly, this will
* never happen. The exception passed to the consumer will be unwrapped, in the case that it's a
* {@link PipelineException}. Thus, the actual exception will be given instead of the wrapper.
*
* @param consumer Result consumer. If an exception was wrong, the result will be {@code null},
* otherwise the exception will be non-null and the exception will be {@code
* null}.
* @throws IllegalStateException If no result was found. This only happens if the pipeline has not
* been constructed properly. The most likely cause is a faulty
* default implementation
* @throws IllegalStateException If a {@link SideEffectService} returns {@code null}
*/
public void getResult(@Nonnull final BiConsumer<Result, Throwable> consumer) {
try {
consumer.accept(getResult(), null);
} catch (final PipelineException pipelineException) {
consumer.accept(null, pipelineException.getCause());
} catch (final Exception e) {
consumer.accept(null, e);
}
}
/**
* Get the first result that is generated for the given context. This cannot return null. If
* nothing manages to produce a result, an exception will be thrown. If the pipeline has been
* constructed properly, this will never happen.
*
* @return Generated result
*/
@Nonnull
public CompletableFuture<Result> getResultAsynchronously() {
return CompletableFuture.supplyAsync(this::getResult, this.pipeline.getExecutor());
}
/**
* Forward the request through the original pipeline.
*
* @return New pump, for the result of this request
*/
@Nonnull
public ServicePump<Result> forward() {
return this.pipeline.pump(this.getResult());
}
/**
* Forward the request through the original pipeline.
*
* @return New pump, for the result of this request
*/
@Nonnull
public CompletableFuture<ServicePump<Result>> forwardAsynchronously() {
return this.getResultAsynchronously().thenApply(pipeline::pump);
}
}

View file

@ -0,0 +1,38 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services;
/**
* This indicates how a {@link cloud.commandframework.services.types.Service} responded to a given context
*/
public enum State {
/**
* The service consumed the context successfully and the execution should stop
*/
ACCEPTED,
/**
* The service did not consume the context and the execution should continue
*/
REJECTED
}

View file

@ -0,0 +1,54 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services.annotations;
import cloud.commandframework.services.types.Service;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Used to bind methods to services, like such:
*
* <pre>{@code
* {@literal @}Nullable
* {@literal @}ServiceImplementation(YourService.class)
* public YourResult handle(YourContext) {
* return result;
* }
* }</pre>
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ServiceImplementation {
/**
* The service class that the method implements
*
* @return Service to implement
*/
Class<? extends Service<?, ?>> value();
}

View file

@ -0,0 +1,28 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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.
//
/**
* IntellectualSites service pipeline system
*/
package cloud.commandframework.services;

View file

@ -0,0 +1,90 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services.types;
import cloud.commandframework.services.State;
import javax.annotation.Nonnull;
import java.util.function.Consumer;
/**
* Service type where each implementation gets a chance to consume the context. This service type
* effectively turns the pipeline into an event bus.
* <p>
* A service can forcefully terminate execution by calling {@link #interrupt()}
*
* @param <Context> Context
*/
@FunctionalInterface
public interface ConsumerService<Context>
extends SideEffectService<Context>, Consumer<Context> {
/**
* Immediately terminate the execution and return {@link State#ACCEPTED}
*
* @throws PipeBurst Pipe burst
*/
static void interrupt() throws PipeBurst {
throw new PipeBurst();
}
@Nonnull
@Override
default State handle(@Nonnull final Context context) {
try {
this.accept(context);
} catch (final PipeBurst burst) {
return State.ACCEPTED;
}
return State.REJECTED;
}
/**
* Accept the context. Call {@link #interrupt()} to interrupt the entire pipeline and immediately
* return {@link State#ACCEPTED} to the sink
*
* @param context Context to consume
*/
@Override
void accept(@Nonnull Context context);
class PipeBurst extends RuntimeException {
private PipeBurst() {
}
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
@Override
public synchronized Throwable initCause(final Throwable cause) {
return this;
}
}
}

View file

@ -0,0 +1,65 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services.types;
import cloud.commandframework.services.ChunkedRequestContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;
/**
* Service type that allows service to generate partial results for bigger requests
*
* @param <Context> Context type
* @param <Result> Result type
* @param <Chunked> Chunk request context
*/
public interface PartialResultService<Context, Result, Chunked extends ChunkedRequestContext<Context, Result>>
extends Service<Chunked, Map<Context, Result>> {
@Override
@Nullable
default Map<Context, Result> handle(@Nonnull final Chunked context) {
if (!context.isCompleted()) {
this.handleRequests(context.getRemaining()).forEach(context::storeResult);
}
if (context.isCompleted()) {
return context.getAvailableResults();
}
return null;
}
/**
* Attempt to generate results for a list of requests, and return a map of all successful
* requests
*
* @param requests Requests
* @return Map of request-result pairs
*/
@Nonnull
Map<Context, Result> handleRequests(@Nonnull List<Context> requests);
}

View file

@ -0,0 +1,78 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services.types;
import cloud.commandframework.services.ExecutionOrder;
import cloud.commandframework.services.PipelineException;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.function.Function;
/**
* A service is anything that can take in a context, and produce a response. Most service
* implementations will be side effect free, although some service implementations will have side
* effects. Those that do, should be clearly labeled
*
* @param <Context> Context type, this will be the input that is used to generate the response
* @param <Result> Response type, this is what is produced by the service ("provided")
*/
@FunctionalInterface
public interface Service<Context, Result> extends Function<Context, Result> {
/**
* Provide a response for the given context. If the service implementation cannot provide a
* response for the given context, it should return {@code null}
*
* @param context Context used in the generation of the response
* @return Response. If the response isn't {@code null}, the next service in the service chain
* will get to act on the context. Otherwise the execution halts, and the provided response is the
* final response.
* @throws Exception Any exception that occurs during the handling can be thrown, and will be
* wrapped by a {@link PipelineException}
*/
@Nullable
Result handle(@Nonnull Context context) throws Exception;
@Override
default Result apply(@Nonnull Context context) {
try {
return this.handle(context);
} catch (final Exception exception) {
throw new PipelineException(exception);
}
}
/**
* Get the execution order of the service. This should not be overridden, unless you know what you
* are doing
*
* @return Execution order
*/
@Nullable
default ExecutionOrder order() {
return null;
}
}

View file

@ -0,0 +1,55 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services.types;
import cloud.commandframework.services.State;
import javax.annotation.Nonnull;
/**
* Service implementation that alters the state of the owning application in some way. A
* SideEffectService does not return a generated result, instead it returns a response, indicating
* whether or not the context was consumed
*
* @param <Context> Context type.
*/
@FunctionalInterface
public interface SideEffectService<Context> extends Service<Context, State> {
/**
* Consumes the context, if possible. Returns {@link State#ACCEPTED} if the input was consumed,
* else {@link State#REJECTED}
*
* @param context context used in the generation of the response
* @return Response. If the response isn't {@link State#ACCEPTED}, the next service in the service
* chain will get to act on the context. Otherwise the execution halts, and the provided response
* is the final response.
* @throws Exception Any exception that occurs during the handling can be thrown, and will be
* wrapped by a {@link cloud.commandframework.services.PipelineException}
*/
@Override
@Nonnull
State handle(@Nonnull Context context) throws Exception;
}

View file

@ -0,0 +1,28 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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.
//
/**
* Service implementation types
*/
package cloud.commandframework.services.types;

View file

@ -0,0 +1,209 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services;
import com.google.common.reflect.TypeToken;
import cloud.commandframework.services.mock.*;
import cloud.commandframework.services.types.Service;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.*;
public class ServicesTest {
@Test
public void testPipeline() throws Exception {
final ServicePipeline servicePipeline = ServicePipeline.builder().build();
Assertions.assertNotNull(servicePipeline);
servicePipeline
.registerServiceType(TypeToken.of(MockService.class), new DefaultMockService());
Assertions.assertThrows(IllegalArgumentException.class, () -> servicePipeline
.registerServiceType(TypeToken.of(MockService.class), new DefaultMockService()));
final SecondaryMockService secondaryMockService = new SecondaryMockService();
servicePipeline
.registerServiceImplementation(TypeToken.of(MockService.class), secondaryMockService,
Collections.singleton(secondaryMockService));
servicePipeline.registerServiceImplementation(MockService.class,
mockContext -> new MockService.MockResult(-91),
Collections.singleton(mockContext -> mockContext.getString().startsWith("-91")));
Assertions.assertEquals(32,
servicePipeline.pump(new MockService.MockContext("Hello")).through(MockService.class)
.getResult().getInteger());
servicePipeline.pump(new MockService.MockContext("Hello")).through(MockService.class)
.getResult(
(mockResult, throwable) -> Assertions.assertEquals(32, mockResult.getInteger()));
Assertions.assertEquals(999,
servicePipeline.pump(new MockService.MockContext("potato")).through(MockService.class)
.getResult().getInteger());
Assertions.assertEquals(-91,
servicePipeline.pump(new MockService.MockContext("-91")).through(MockService.class)
.getResult().getInteger());
Assertions.assertNotNull(
servicePipeline.pump(new MockService.MockContext("oi")).through(MockService.class)
.getResultAsynchronously().get());
}
@Test
public void testSideEffectServices() {
final ServicePipeline servicePipeline = ServicePipeline.builder().build();
servicePipeline.registerServiceType(TypeToken.of(MockSideEffectService.class),
new DefaultSideEffectService());
final MockSideEffectService.MockPlayer mockPlayer =
new MockSideEffectService.MockPlayer(20);
Assertions.assertEquals(20, mockPlayer.getHealth());
Assertions.assertEquals(State.ACCEPTED,
servicePipeline.pump(mockPlayer).through(MockSideEffectService.class).getResult());
Assertions.assertEquals(0, mockPlayer.getHealth());
mockPlayer.setHealth(20);
servicePipeline.registerServiceImplementation(MockSideEffectService.class,
new SecondaryMockSideEffectService(), Collections.emptyList());
Assertions.assertThrows(IllegalStateException.class,
() -> servicePipeline.pump(mockPlayer).through(MockSideEffectService.class)
.getResult());
}
@Test
public void testForwarding() throws Exception {
final ServicePipeline servicePipeline = ServicePipeline.builder().build()
.registerServiceType(TypeToken.of(MockService.class), new DefaultMockService())
.registerServiceType(TypeToken.of(MockResultConsumer.class), new MockResultConsumer());
Assertions.assertEquals(State.ACCEPTED,
servicePipeline.pump(new MockService.MockContext("huh")).through(MockService.class)
.forward().through(MockResultConsumer.class).getResult());
Assertions.assertEquals(State.ACCEPTED,
servicePipeline.pump(new MockService.MockContext("Something"))
.through(MockService.class).forwardAsynchronously()
.thenApply(pump -> pump.through(MockResultConsumer.class))
.thenApply(ServiceSpigot::getResult).get());
}
@Test
public void testSorting() {
final ServicePipeline servicePipeline = ServicePipeline.builder().build()
.registerServiceType(TypeToken.of(MockService.class), new DefaultMockService());
servicePipeline.registerServiceImplementation(MockService.class, new MockOrderedFirst(),
Collections.emptyList());
servicePipeline.registerServiceImplementation(MockService.class, new MockOrderedLast(),
Collections.emptyList());
// Test that the annotations worked
Assertions.assertEquals(1,
servicePipeline.pump(new MockService.MockContext("")).through(MockService.class)
.getResult().getInteger());
}
@Test
public void testRecognisedTypes() {
final ServicePipeline servicePipeline = ServicePipeline.builder().build()
.registerServiceType(TypeToken.of(MockService.class), new DefaultMockService());
Assertions.assertEquals(1, servicePipeline.getRecognizedTypes().size());
}
@Test
public void testImplementationGetters() {
final ServicePipeline servicePipeline = ServicePipeline.builder().build()
.registerServiceType(TypeToken.of(MockService.class), new DefaultMockService());
servicePipeline.registerServiceImplementation(MockService.class, new MockOrderedFirst(),
Collections.emptyList());
servicePipeline.registerServiceImplementation(MockService.class, new MockOrderedLast(),
Collections.emptyList());
final TypeToken<? extends Service<?, ?>> first = TypeToken.of(MockOrderedFirst.class),
last = TypeToken.of(MockOrderedLast.class);
final TypeToken<MockService> mockServiceType = TypeToken.of(MockService.class);
for (TypeToken<?> typeToken : servicePipeline.getRecognizedTypes()) {
Assertions.assertEquals(mockServiceType, typeToken);
}
final Collection<? extends TypeToken<? extends Service<MockService.MockContext, MockService.MockResult>>>
impls = servicePipeline.getImplementations(mockServiceType);
Assertions.assertEquals(3, impls.size());
final Iterator<? extends TypeToken<? extends Service<MockService.MockContext, MockService.MockResult>>>
iterator = impls.iterator();
Assertions.assertEquals(first, iterator.next());
Assertions.assertEquals(last, iterator.next());
Assertions.assertEquals(DefaultMockService.class, iterator.next().getRawType());
}
@Test
public void testAnnotatedMethods() throws Exception {
final ServicePipeline servicePipeline = ServicePipeline.builder().build()
.registerServiceType(TypeToken.of(MockService.class), new DefaultMockService())
.registerMethods(new AnnotatedMethodTest());
final String testString = UUID.randomUUID().toString();
Assertions.assertEquals(testString.length(),
servicePipeline.pump(new MockService.MockContext(testString)).through(MockService.class)
.getResult().getInteger());
}
@Test
public void testConsumerServices() {
final ServicePipeline servicePipeline = ServicePipeline.builder().build()
.registerServiceType(TypeToken.of(MockConsumerService.class),
new StateSettingConsumerService())
.registerServiceImplementation(MockConsumerService.class,
new InterruptingMockConsumer(), Collections.emptyList());
final MockService.MockContext context = new MockService.MockContext("");
servicePipeline.pump(context).through(MockConsumerService.class).getResult();
Assertions.assertEquals("", context.getState());
}
@Test
public void testPartialResultServices() {
final ServicePipeline servicePipeline = ServicePipeline.builder().build()
.registerServiceType(TypeToken.of(MockPartialResultService.class),
new DefaultPartialRequestService())
.registerServiceImplementation(MockPartialResultService.class,
new CompletingPartialResultService(), Collections.emptyList());
final MockChunkedRequest.Animal cow = new MockChunkedRequest.Animal("cow");
final MockChunkedRequest.Animal dog = new MockChunkedRequest.Animal("dog");
final MockChunkedRequest.Animal cat = new MockChunkedRequest.Animal("cat");
final Map<MockChunkedRequest.Animal, MockChunkedRequest.Sound> sounds =
servicePipeline.pump(new MockChunkedRequest(Arrays.asList(cow, dog, cat)))
.through(MockPartialResultService.class).getResult();
Assertions.assertEquals("moo", sounds.get(cow).getSound());
Assertions.assertEquals("woof", sounds.get(dog).getSound());
Assertions.assertEquals("unknown", sounds.get(cat).getSound());
}
@Test
public void testExceptions() {
final ServicePipeline servicePipeline = ServicePipeline.builder().build();
Assertions.assertNotNull(servicePipeline);
servicePipeline
.registerServiceType(TypeToken.of(MockService.class), new DefaultMockService());
final PipelineException pipelineException = Assertions.assertThrows(PipelineException.class,
() -> servicePipeline.pump(new MockService.MockContext("pls throw exception"))
.through(MockService.class).getResult());
Assertions.assertEquals(DefaultMockService.TotallyIntentionalException.class,
pipelineException.getCause().getClass());
servicePipeline.pump(new MockService.MockContext("pls throw exception"))
.through(MockService.class).getResult((result, throwable) -> {
Assertions.assertNotNull(throwable);
Assertions.assertEquals(DefaultMockService.TotallyIntentionalException.class,
throwable.getClass());
Assertions.assertNull(result);
});
}
}

View file

@ -0,0 +1,47 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services.mock;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class DefaultMockService implements MockService {
@Nullable
@Override
public MockResult handle(@Nonnull final MockContext mockContext)
throws Exception {
if (mockContext.getString().equals("pls throw exception")) {
throw new TotallyIntentionalException();
}
return new MockResult(32);
}
public static class TotallyIntentionalException extends Exception {
}
}

View file

@ -0,0 +1,45 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services.mock;
import javax.annotation.Nonnull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DefaultPartialRequestService implements MockPartialResultService {
@Nonnull
@Override
public Map<MockChunkedRequest.Animal, MockChunkedRequest.Sound> handleRequests(
@Nonnull final List<MockChunkedRequest.Animal> requests) {
final Map<MockChunkedRequest.Animal, MockChunkedRequest.Sound> map =
new HashMap<>(requests.size());
for (final MockChunkedRequest.Animal animal : requests) {
map.put(animal, new MockChunkedRequest.Sound("unknown"));
}
return map;
}
}

View file

@ -0,0 +1,37 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services.mock;
import cloud.commandframework.services.types.ConsumerService;
import javax.annotation.Nonnull;
public class InterruptingMockConsumer implements MockConsumerService {
@Override
public void accept(@Nonnull final MockService.MockContext mockContext) {
ConsumerService.interrupt();
}
}

View file

@ -0,0 +1,30 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services.mock;
import cloud.commandframework.services.types.ConsumerService;
public interface MockConsumerService extends ConsumerService<MockService.MockContext> {
}

View file

@ -0,0 +1,41 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services.mock;
import cloud.commandframework.services.ExecutionOrder;
import cloud.commandframework.services.annotations.Order;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@Order(ExecutionOrder.FIRST)
public class MockOrderedFirst implements MockService {
@Nullable
@Override
public MockResult handle(@Nonnull final MockContext mockContext) {
return new MockResult(1);
}
}

View file

@ -0,0 +1,41 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services.mock;
import cloud.commandframework.services.ExecutionOrder;
import cloud.commandframework.services.annotations.Order;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@Order(ExecutionOrder.LAST)
public class MockOrderedLast implements MockService {
@Nullable
@Override
public MockResult handle(@Nonnull final MockContext mockContext) {
return new MockResult(2);
}
}

View file

@ -0,0 +1,31 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services.mock;
import cloud.commandframework.services.types.PartialResultService;
public interface MockPartialResultService extends
PartialResultService<MockChunkedRequest.Animal, MockChunkedRequest.Sound, MockChunkedRequest> {
}

View file

@ -0,0 +1,38 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services.mock;
import cloud.commandframework.services.State;
import javax.annotation.Nonnull;
public class SecondaryMockSideEffectService implements MockSideEffectService {
@Nonnull
@Override
public State handle(@Nonnull final MockPlayer mockPlayer) {
return null;
}
}

View file

@ -0,0 +1,35 @@
//
// MIT License
//
// Copyright (c) 2020 IntellectualSites
//
// 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 NONINFRINGEMENT. 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 cloud.commandframework.services.mock;
import javax.annotation.Nonnull;
public class StateSettingConsumerService implements MockConsumerService {
@Override
public void accept(@Nonnull final MockService.MockContext mockContext) {
mockContext.setState("");
}
}