- * @param+ * @param + * @param+ * @param */ -public interface CompositeMiddleware< - W extends CompositeMiddleware , - L extends ChainLifecycle, - C extends ChainContext , - I extends Input , - O extends Output , - M extends Matcher , - Q, - H> extends Middleware { +public interface CompositeMiddleware , I extends Input , + O extends Output , S extends Selector, W extends CompositeMiddleware , K> + extends Middleware { + + /** + * TODO: doc + * + * @param first + * @param rest + * @param + * @return + */ + > W use(N first, N... rest); /** * TODO: doc * - * @param matcher + * @param selector * @param first * @param rest * @param * @return */ - @SuppressWarnings("unchecked") - > W use(M matcher, N first, N... rest); + > W use(S selector, N first, N... rest); } diff --git a/unchained-api/src/main/java/unchained/Configuration.java b/unchained-api/src/main/java/unchained/Configuration.java index cea43fb..5a9ad2f 100644 --- a/unchained-api/src/main/java/unchained/Configuration.java +++ b/unchained-api/src/main/java/unchained/Configuration.java @@ -114,9 +114,7 @@ default boolean disabled(Option> option) { * @param the type. * @return the value or {@code null} if it was never configured. */ - default E get(String key) { - return get(key, null); - } + E get(String key); /** * Returns the value of the given option, or the corresponding default value for this option if it was never @@ -143,6 +141,8 @@ default
E get(Option option) { * @param the type. * @return the configured value or the provided default. */ - E get(String key, E defaultValue); + default E get(String key, E defaultValue) { + return has(key) ? get(key) : defaultValue; + } } diff --git a/unchained-api/src/main/java/unchained/Input.java b/unchained-api/src/main/java/unchained/Input.java index 062908d..9f6b2eb 100644 --- a/unchained-api/src/main/java/unchained/Input.java +++ b/unchained-api/src/main/java/unchained/Input.java @@ -6,9 +6,7 @@ * @param the lifecycle type. * @param the context type. */ -public interface Input< - L extends ChainLifecycle, - C extends ChainContext > { +public interface Input > { /** * Gives access to the context associated with this input. diff --git a/unchained-api/src/main/java/unchained/Matcher.java b/unchained-api/src/main/java/unchained/Matcher.java deleted file mode 100644 index de6686b..0000000 --- a/unchained-api/src/main/java/unchained/Matcher.java +++ /dev/null @@ -1,57 +0,0 @@ -package unchained; - -/** - * TODO: doc - * - * @param - * @param - * @param - */ -public interface Matcher< - C extends ChainContext , - I extends Input extends ChainLifecycle, C>, - E> { - - /** - * TODO: doc - * - * @param - * @param - * @param - * @param - * @param- */ - interface Compiler< - C extends ChainContext , - I extends Input extends ChainLifecycle, C>, - M extends Matcher , - S, - T> { - - /** - * TODO: doc - * - * @param expression - * @return - */ - M compile(S expression); - - } - - interface Hit { - - boolean matched(); - - T value(); - - } - - /** - * TODO: doc - * - * @param input - * @return - */ - Hit test(I input); - -} diff --git a/unchained-api/src/main/java/unchained/Middleware.java b/unchained-api/src/main/java/unchained/Middleware.java index b0ddc25..22fdec5 100644 --- a/unchained-api/src/main/java/unchained/Middleware.java +++ b/unchained-api/src/main/java/unchained/Middleware.java @@ -12,14 +12,10 @@ * @param the type of context bound to this middleware's input. * @param the type of input this middleware works with. * @param the type of output this middleware can deal with. - * @param the type of output for this middleware. + * @paramthe type of outcome for this middleware. */ -public interface Middleware< - L extends ChainLifecycle, - C extends ChainContext , - I extends Input , - O extends Output , - Q> { +public interface Middleware , I extends Input , + O extends Output , K> { /** * Handles the incoming input and works on the input and output. This is a very generic method which will be called @@ -30,6 +26,6 @@ public interface Middleware< * @return a future whose completion represents the completion of the middleware itself. * @throws Exception in case the underlying logic causes an error. */ - CompletableFuture execute(I input, O output) throws Exception; + CompletableFutureexecute(I input, O output) throws Exception; } diff --git a/unchained-api/src/main/java/unchained/MutableConfiguration.java b/unchained-api/src/main/java/unchained/MutableConfiguration.java index 5b1dbc1..946ce6d 100644 --- a/unchained-api/src/main/java/unchained/MutableConfiguration.java +++ b/unchained-api/src/main/java/unchained/MutableConfiguration.java @@ -3,9 +3,8 @@ /** * Mutable configuration. * - * @param */ -public interface MutableConfiguration extends Configuration { +public interface MutableConfiguration extends Configuration { /** * Enables the provided key by setting it to {@code true}. @@ -13,7 +12,7 @@ public interface MutableConfiguration extends Co * @param key the key to enable. * @return the configuration itself to use for chaining method calls. */ - default M enable(String key) { + default MutableConfiguration enable(String key) { return set(key, true); } @@ -23,7 +22,7 @@ default M enable(String key) { * @param option the option to enable. * @return the configuration itself to use for chaining method calls. */ - default M enable(Option option) { + default MutableConfiguration enable(Option option) { return set(option, true); } @@ -33,7 +32,7 @@ default M enable(Option option) { * @param key the key to disable. * @return the configuration itself to use for chaining method calls. */ - default M disable(String key) { + default MutableConfiguration disable(String key) { return set(key, false); } @@ -43,7 +42,7 @@ default M disable(String key) { * @param option the option to disable. * @return the configuration itself to use for chaining method calls. */ - default M disable(Option option) { + default MutableConfiguration disable(Option option) { return set(option, false); } @@ -54,7 +53,7 @@ default M disable(Option option) { * @param value the value. * @return the configuration itself to use for chaining method calls. */ - M set(String key, E value); + MutableConfiguration set(String key, E value); /** * Sets the value of the provided option to the given value. @@ -64,7 +63,7 @@ default M disable(Option option) { * @param the type of the value. * @return the configuration itself to use for chaining method calls. */ - default M set(Option option, E value) { + default MutableConfiguration set(Option option, E value) { return set(option.key(), value); } @@ -92,4 +91,12 @@ default E unset(Option> option) { return unset(option.key()); } + /** + * Snapshots this configuration object and returns an immutable copy of it. Further changes to this object do not + * reflect in the returned copy. + * + * @return A immutable snapshot of this configuration. + */ + Configuration snapshot(); + } diff --git a/unchained-api/src/main/java/unchained/Output.java b/unchained-api/src/main/java/unchained/Output.java index 6c19339..99338c0 100644 --- a/unchained-api/src/main/java/unchained/Output.java +++ b/unchained-api/src/main/java/unchained/Output.java @@ -7,10 +7,7 @@ * @param the context type. * @param the input type. */ -public interface Output< - L extends ChainLifecycle, - C extends ChainContext , - I extends Input > { +public interface Output , I extends Input > { /** * Gives access to the input associated with this output. diff --git a/unchained-api/src/main/java/unchained/Selector.java b/unchained-api/src/main/java/unchained/Selector.java new file mode 100644 index 0000000..8a923a9 --- /dev/null +++ b/unchained-api/src/main/java/unchained/Selector.java @@ -0,0 +1,54 @@ +package unchained; + +/** + * TODO: doc + * + * @param + * @param + */ +public interface Selector, M> { + + /** + * TODO: doc + * + * @param + */ + interface Compiler, ?>> { + + /** + * TODO: doc + * + * @param expressions + * @return + */ + S compile(String... expressions); + + } + + interface Hit{ + + /** + * TODO: doc + * + * @return + */ + boolean matched(); + + /** + * TODO: doc + * + * @return + */ + M value(); + + } + + /** + * TODO: doc + * + * @param input + * @return + */ + Hit test(I input); + +} diff --git a/unchained-api/src/main/java/unchained/Unchained.java b/unchained-api/src/main/java/unchained/Unchained.java new file mode 100644 index 0000000..39ce795 --- /dev/null +++ b/unchained-api/src/main/java/unchained/Unchained.java @@ -0,0 +1,44 @@ +package unchained; + +import unchained.contract.Factory; +import unchained.http.HttpApplication; +import unchained.http.HttpRoute; +import unchained.web.Route; + +public final class Unchained { + + private Unchained() { } + + public static Configuration emptyConfiguration() { + return Factory.forType(Configuration.class).create(); + } + + public static MutableConfiguration newConfiguration() { + return Factory.forType(MutableConfiguration.class).create(); + } + + public static HttpApplication newHttpApplication(Configuration configuration) { + return newApplication(HttpApplication.class, configuration); + } + + public static T newApplication(Class type, Configuration configuration) { + return Factory.forType(type).create(configuration); + } + + public static T newRoute(Class type) { + return Factory.forType(type).create(); + } + + public static HttpRoute newHttpRoute() { + return newRoute(HttpRoute.class); + } + + static { + try { + Class.forName("unchained.Utils"); + } catch (Exception ignored) { + ignored.printStackTrace(); + } + } + +} diff --git a/unchained-api/src/main/java/unchained/error/ContextException.java b/unchained-api/src/main/java/unchained/error/ContextException.java deleted file mode 100644 index 9012757..0000000 --- a/unchained-api/src/main/java/unchained/error/ContextException.java +++ /dev/null @@ -1,13 +0,0 @@ -package unchained.error; - -public abstract class ContextException extends FrameworkException { - - public ContextException(String message) { - super(message); - } - - public ContextException(String message, Throwable cause) { - super(message, cause); - } - -} diff --git a/unchained-api/src/main/java/unchained/http/BodyReader.java b/unchained-api/src/main/java/unchained/http/BodyReader.java deleted file mode 100644 index 45de809..0000000 --- a/unchained-api/src/main/java/unchained/http/BodyReader.java +++ /dev/null @@ -1,21 +0,0 @@ -package unchained.http; - -import java.io.InputStream; -import java.lang.reflect.Type; -import java.nio.charset.Charset; - -public interface BodyReader { - - InputStream asStream(); - - byte[] asBytes(); - - String asString(); - - String asString(Charset charset); - - E as(Class type); - - E as(Type type); - -} diff --git a/unchained-api/src/main/java/unchained/http/BodyWriter.java b/unchained-api/src/main/java/unchained/http/BodyWriter.java deleted file mode 100644 index 85c899d..0000000 --- a/unchained-api/src/main/java/unchained/http/BodyWriter.java +++ /dev/null @@ -1,17 +0,0 @@ -package unchained.http; - -import java.io.OutputStream; - -public interface BodyWriter { - - OutputStream asStream(); - - void set(byte[] body); - - void set(String body); - - void set(E body); - - void done(); - -} diff --git a/unchained-api/src/main/java/unchained/http/HttpApplication.java b/unchained-api/src/main/java/unchained/http/HttpApplication.java new file mode 100644 index 0000000..45d018e --- /dev/null +++ b/unchained-api/src/main/java/unchained/http/HttpApplication.java @@ -0,0 +1,13 @@ +package unchained.http; + +import unchained.Application; +import unchained.web.RequestContext; +import unchained.web.RequestLifecycle; + +/** + * TODO: doc + */ +public interface HttpApplication extends Application , HttpRouteDefiner { + +} diff --git a/unchained-api/src/main/java/unchained/http/HttpBodyReader.java b/unchained-api/src/main/java/unchained/http/HttpBodyReader.java new file mode 100644 index 0000000..09f2e86 --- /dev/null +++ b/unchained-api/src/main/java/unchained/http/HttpBodyReader.java @@ -0,0 +1,11 @@ +package unchained.http; + +import unchained.web.PayloadReader; + +/** + * TODO: doc + * + */ +public interface HttpBodyReader extends PayloadReader { + +} diff --git a/unchained-api/src/main/java/unchained/http/HttpBodyWriter.java b/unchained-api/src/main/java/unchained/http/HttpBodyWriter.java new file mode 100644 index 0000000..85a787b --- /dev/null +++ b/unchained-api/src/main/java/unchained/http/HttpBodyWriter.java @@ -0,0 +1,10 @@ +package unchained.http; + +import unchained.web.PayloadWriter; + +/** + * TODO: doc + */ +public interface HttpBodyWriter extends PayloadWriter { + +} diff --git a/unchained-api/src/main/java/unchained/http/HttpMethod.java b/unchained-api/src/main/java/unchained/http/HttpMethod.java new file mode 100644 index 0000000..067df82 --- /dev/null +++ b/unchained-api/src/main/java/unchained/http/HttpMethod.java @@ -0,0 +1,7 @@ +package unchained.http; + +public interface HttpMethod { + + String GET = "GET"; + +} diff --git a/unchained-api/src/main/java/unchained/http/HttpRequest.java b/unchained-api/src/main/java/unchained/http/HttpRequest.java index 8af28fa..0635184 100644 --- a/unchained-api/src/main/java/unchained/http/HttpRequest.java +++ b/unchained-api/src/main/java/unchained/http/HttpRequest.java @@ -4,13 +4,36 @@ import java.net.InetSocketAddress; -public interface HttpRequest extends Request { +public interface HttpRequest extends Request , HttpBodyReader { /** * @return the HTTP method/verb associated with this request. */ String method(); + /** + * TODO: doc + * + * @param method + * @return + */ + HttpRequest method(String method); + + /** + * TODO: doc + * + * @return + */ + String uri(); + + /** + * TODO: doc + * + * @param uri + * @return + */ + HttpRequest uri(String uri); + /** * @return the HTTP scheme used to run this request (e.g. https). */ @@ -26,4 +49,25 @@ public interface HttpRequest extends Request { */ InetSocketAddress remote(); + /** + * TODO: doc + * + * @return + */ + @Override + default String target() { + return uri(); + } + + /** + * TODO: doc + * + * @param target + * @return + */ + @Override + default HttpRequest target(String target) { + return uri(target); + } + } diff --git a/unchained-api/src/main/java/unchained/http/HttpRequestHandler.java b/unchained-api/src/main/java/unchained/http/HttpRequestHandler.java index 18f4ba4..7faf599 100644 --- a/unchained-api/src/main/java/unchained/http/HttpRequestHandler.java +++ b/unchained-api/src/main/java/unchained/http/HttpRequestHandler.java @@ -4,15 +4,6 @@ import java.util.concurrent.CompletableFuture; -public interface HttpRequestHandler extends RequestHandler { - - void handle(HttpRequest request, HttpResponse response); - - @Override - default CompletableFuture execute(HttpRequest input, HttpResponse output) throws Exception { - return CompletableFuture - .allOf(input.payload(), output.payload()) - .thenRunAsync(() -> handle(input, output)); - } +public interface HttpRequestHandler extends RequestHandler { } diff --git a/unchained-api/src/main/java/unchained/http/HttpRequestLine.java b/unchained-api/src/main/java/unchained/http/HttpRequestLine.java new file mode 100644 index 0000000..696a0c1 --- /dev/null +++ b/unchained-api/src/main/java/unchained/http/HttpRequestLine.java @@ -0,0 +1,29 @@ +package unchained.http; + +/** + * TODO: doc + */ +public interface HttpRequestLine { + + /** + * TODO: doc + * + * @return + */ + String method(); + + /** + * TODO: doc + * + * @return + */ + String target(); + + /** + * TODO: doc + * + * @return + */ + String version(); + +} diff --git a/unchained-api/src/main/java/unchained/http/HttpResponse.java b/unchained-api/src/main/java/unchained/http/HttpResponse.java index 58663d3..3ef6f4a 100644 --- a/unchained-api/src/main/java/unchained/http/HttpResponse.java +++ b/unchained-api/src/main/java/unchained/http/HttpResponse.java @@ -2,12 +2,36 @@ import unchained.web.Response; -public interface HttpResponse extends Response { +/** + * + */ +public interface HttpResponse extends Response , HttpBodyWriter { + /** + * + * @return + */ int status(); + /** + * + * @return + */ String statusText(); + /** + * + * @param status + * @return + */ + HttpResponse status(int status); + + /** + * + * @param status + * @param text + * @return + */ HttpResponse status(int status, String text); } diff --git a/unchained-api/src/main/java/unchained/http/HttpRoute.java b/unchained-api/src/main/java/unchained/http/HttpRoute.java new file mode 100644 index 0000000..c2313cc --- /dev/null +++ b/unchained-api/src/main/java/unchained/http/HttpRoute.java @@ -0,0 +1,8 @@ +package unchained.http; + +import unchained.web.Route; + +public interface HttpRoute extends Route , + HttpRouteDefiner { + +} diff --git a/unchained-api/src/main/java/unchained/http/HttpRouteDefiner.java b/unchained-api/src/main/java/unchained/http/HttpRouteDefiner.java new file mode 100644 index 0000000..a4f16ef --- /dev/null +++ b/unchained-api/src/main/java/unchained/http/HttpRouteDefiner.java @@ -0,0 +1,57 @@ +package unchained.http; + +import unchained.Middleware; +import unchained.web.RequestContext; +import unchained.web.RequestLifecycle; + +public interface HttpRouteDefiner { + + > T use(N first, N... rest); + + default T use(HttpRequestHandler first, HttpRequestHandler... rest) { + return use((Middleware ) first, rest); + } + + default T use(ReturningHttpRequestHandler first, ReturningHttpRequestHandler... rest) { + return use((Middleware ) first, rest); + } + + > T use(String pattern, N first, N... rest); + + default T use(String pattern, HttpRequestHandler first, HttpRequestHandler... rest) { + return use(pattern, (Middleware ) first, rest); + } + + > T all(String pattern, N first, N... rest); + + default T all(String pattern, HttpRequestHandler first, HttpRequestHandler... rest) { + return all(pattern, (Middleware ) first, rest); + } + + default T all(String pattern, ReturningHttpRequestHandler first, ReturningHttpRequestHandler... rest) { + return all(pattern, (Middleware ) first, rest); + } + + > T custom(String method, String pattern, N first, N... rest); + + default T custom(String method, String pattern, HttpRequestHandler first, HttpRequestHandler... rest) { + return custom(method, pattern, (Middleware ) first, rest); + } + + default T custom(String method, String pattern, ReturningHttpRequestHandler first, ReturningHttpRequestHandler... rest) { + return custom(method, pattern, (Middleware ) first, rest); + } + + default > T get(String pattern, N first, N... rest) { + return custom(HttpMethod.GET, pattern, first, rest); + } + + default T get(String pattern, HttpRequestHandler first, HttpRequestHandler... rest) { + return get(pattern, (Middleware ) first, rest); + } + + default T get(String pattern, ReturningHttpRequestHandler first, ReturningHttpRequestHandler... rest) { + return get(pattern, (Middleware ) first, rest); + } + +} diff --git a/unchained-api/src/main/java/unchained/http/HttpSelector.java b/unchained-api/src/main/java/unchained/http/HttpSelector.java new file mode 100644 index 0000000..2538e6a --- /dev/null +++ b/unchained-api/src/main/java/unchained/http/HttpSelector.java @@ -0,0 +1,11 @@ +package unchained.http; + +import unchained.Selector; + +public interface HttpSelector extends Selector { + + interface Compiler extends Selector.Compiler { + + } + +} diff --git a/unchained-api/src/main/java/unchained/http/ReturningHttpRequestHandler.java b/unchained-api/src/main/java/unchained/http/ReturningHttpRequestHandler.java index 5c2540e..8a81855 100644 --- a/unchained-api/src/main/java/unchained/http/ReturningHttpRequestHandler.java +++ b/unchained-api/src/main/java/unchained/http/ReturningHttpRequestHandler.java @@ -2,17 +2,16 @@ import unchained.web.RequestHandler; +import java.io.IOException; import java.util.concurrent.CompletableFuture; -public interface ReturningHttpRequestHandler extends RequestHandler { +public interface ReturningHttpRequestHandler extends RequestHandler { Object handle(HttpRequest request); @Override - default CompletableFuture execute(HttpRequest input, HttpResponse output) throws Exception { - return CompletableFuture - .allOf(input.payload(), output.payload()) - .thenRunAsync(() -> output.payload().join().set(handle(input))); + default void handle(HttpRequest request, HttpResponse response) { + response.write(handle(request)); } } diff --git a/unchained-api/src/main/java/unchained/web/PayloadReader.java b/unchained-api/src/main/java/unchained/web/PayloadReader.java new file mode 100644 index 0000000..5ad0bae --- /dev/null +++ b/unchained-api/src/main/java/unchained/web/PayloadReader.java @@ -0,0 +1,70 @@ +package unchained.web; + +import java.io.InputStream; +import java.io.Reader; +import java.lang.reflect.Type; +import java.nio.charset.Charset; + +/** + * TODO: doc + * + * @param + */ +public interface PayloadReader> { + + /** + * TODO: doc + * + * @return + */ + InputStream asStream(); + + /** + * TODO: doc + * + * @param charset + * @return + */ + Reader asReader(Charset charset); + + /** + * TODO: doc + * + * @return + */ + byte[] asBytes(); + + /** + * TODO: doc + * + * @return + */ + String asString(); + + /** + * TODO: doc + * + * @param charset + * @return + */ + String asString(Charset charset); + + /** + * TODO: doc + * + * @param type + * @param + * @return + */ + E as(Class type); + + /** + * TODO: doc + * + * @param type + * @param + * @return + */ + E as(Type type); + +} diff --git a/unchained-api/src/main/java/unchained/web/PayloadWriter.java b/unchained-api/src/main/java/unchained/web/PayloadWriter.java new file mode 100644 index 0000000..fd47315 --- /dev/null +++ b/unchained-api/src/main/java/unchained/web/PayloadWriter.java @@ -0,0 +1,70 @@ +package unchained.web; + +import java.io.OutputStream; +import java.io.Writer; +import java.nio.charset.Charset; + +/** + * TODO: doc + * + * @param + */ +public interface PayloadWriter > { + + /** + * TODO: doc + * + * @return + */ + OutputStream asStream(); + + /** + * TODO: doc + * + * @param charset + * @return + */ + Writer asWriter(Charset charset); + + /** + * TODO: doc + * + * @param payload + * @return + */ + O write(byte[] payload); + + /** + * TODO: doc + * + * @param payload + * @return + */ + O write(String payload, Charset charset); + + /** + * TODO: doc + * + * @param payload + * @return + */ + @SuppressWarnings("unchecked") + O write(String payload); + + /** + * TODO: doc + * + * @param payload + * @param + * @return + */ + O write(E payload); + + /** + * TODO: doc + * + * @return + */ + O done(); + +} diff --git a/unchained-api/src/main/java/unchained/web/Request.java b/unchained-api/src/main/java/unchained/web/Request.java index 6e1d8a5..82dff6c 100644 --- a/unchained-api/src/main/java/unchained/web/Request.java +++ b/unchained-api/src/main/java/unchained/web/Request.java @@ -4,28 +4,25 @@ import java.util.Map; import java.util.Set; -import java.util.concurrent.CompletableFuture; /** * TODO: doc - * - * @param */ -public interface Request extends Input { +public interface Request> extends Input , PayloadReader { /** * TODO: doc * * @return */ - String uri(); + String target(); /** * TODO: doc * - * @param uri + * @param target */ - void uri(String uri); + I target(String target); /** * TODO: doc @@ -73,20 +70,6 @@ public interface Request extends Input { * @param name * @param value */ - E header(String name, E value); - - /** - * TODO: doc - * - * @return - */ - CompletableFuture payload(); - - /** - * TODO: doc - * - * @param payload - */ - void payload(T payload); + I header(String name, E value); } diff --git a/unchained-api/src/main/java/unchained/web/RequestContext.java b/unchained-api/src/main/java/unchained/web/RequestContext.java index bc680d1..dc3b474 100644 --- a/unchained-api/src/main/java/unchained/web/RequestContext.java +++ b/unchained-api/src/main/java/unchained/web/RequestContext.java @@ -3,19 +3,16 @@ import unchained.ChainContext; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ForkJoinPool; /** * TODO: doc */ -public interface RequestContext extends ChainContext { +public interface RequestContext extends ChainContext { - /** - * Convenient method to get access to the {@link Executor} bound to this context. - * - * @return the {@link Executor} bound to this context. - */ default Executor executor() { - return get(Executor.class); + return has(Executor.class) ? get(Executor.class) : ForkJoinPool.commonPool(); } } diff --git a/unchained-api/src/main/java/unchained/web/RequestHandler.java b/unchained-api/src/main/java/unchained/web/RequestHandler.java index b4357c6..c1c76d6 100644 --- a/unchained-api/src/main/java/unchained/web/RequestHandler.java +++ b/unchained-api/src/main/java/unchained/web/RequestHandler.java @@ -2,17 +2,22 @@ import unchained.Middleware; +import java.util.concurrent.CompletableFuture; + /** * TODO: doc * - * @param - * @param* @param * @param */ -public interface RequestHandler< - S, T, - I extends Request , - O extends Response> extends Middleware{ +public interface RequestHandler, O extends Response> + extends Middleware { + + void handle(I input, O output); + @Override + default CompletableFuture execute(I input, O output) throws Exception { + return CompletableFuture + .runAsync(() -> handle(input, output), input.context().executor()); + } } diff --git a/unchained-api/src/main/java/unchained/web/Response.java b/unchained-api/src/main/java/unchained/web/Response.java index c0c53c4..e8633da 100644 --- a/unchained-api/src/main/java/unchained/web/Response.java +++ b/unchained-api/src/main/java/unchained/web/Response.java @@ -4,15 +4,14 @@ import java.util.Map; import java.util.Set; -import java.util.concurrent.CompletableFuture; /** + * TODO: doc * - * @param - * @param* @param */ -public interface Response > extends Output{ +public interface Response, O extends Response> extends + Output , PayloadWriter { /** * TODO: doc @@ -60,20 +59,6 @@ public interface Response > extends OutputE header(String name, E value); - - /** - * TODO: doc - * - * @return - */ - CompletableFuture payload(); - - /** - * TODO: doc - * - * @param payload - */ - void payload(T payload); + O header(String name, E value); } diff --git a/unchained-api/src/main/java/unchained/web/Route.java b/unchained-api/src/main/java/unchained/web/Route.java new file mode 100644 index 0000000..5ef0e2f --- /dev/null +++ b/unchained-api/src/main/java/unchained/web/Route.java @@ -0,0 +1,25 @@ +package unchained.web; + +import unchained.CompositeMiddleware; +import unchained.Selector; + +/** + * TODO: doc + * + * @param + * @param + * @param + * @param+ * @param + */ +public interface Route, O extends Response, S extends Selector, M, + R extends Route> extends CompositeMiddleware { + + /** + * TODO: doc + * + * @return + */ + M domain(); + +} diff --git a/unchained-build/pom.xml b/unchained-build/pom.xml index 3681235..2ab8f23 100644 --- a/unchained-build/pom.xml +++ b/unchained-build/pom.xml @@ -26,6 +26,7 @@ ../unchained-commons ../unchained-api ../unchained-spi +../unchained-examples diff --git a/unchained-commons/src/main/java/unchained/contract/DefaultRegistry.java b/unchained-commons/src/main/java/unchained/contract/DefaultRegistry.java index ae46f74..b8b5a90 100644 --- a/unchained-commons/src/main/java/unchained/contract/DefaultRegistry.java +++ b/unchained-commons/src/main/java/unchained/contract/DefaultRegistry.java @@ -4,19 +4,19 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantReadWriteLock; -class DefaultRegistryimplements Registry { +class DefaultRegistry > implements Registry { - private final Map entries = new ConcurrentHashMap<>(); + private final Map entries = new ConcurrentHashMap<>(); private DefaultRegistry() {} @Override - public T get(String key) { + public T get(K key) { return entries.get(key); } @Override - public boolean has(String key) { + public boolean has(K key) { return entries.containsKey(key); } @@ -26,7 +26,7 @@ public void register(T value) { } @Override - public Set keys() { + public Set keys() { return Collections.unmodifiableSet(entries.keySet()); } @@ -35,14 +35,14 @@ public Set values() { return Collections.unmodifiableSet(new HashSet<>(entries.values())); } - private static final Map , Registry extends Registrable>> ALL = new HashMap<>(); + private static final Map , Registry, ? extends Registrable>>> ALL = new HashMap<>(); private static final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock(); @SuppressWarnings("unchecked") - static Registry lookup(Class type) { + static > Registry lookup(Class type) { LOCK.readLock().lock(); try { - Registry result = (Registry ) ALL.get(type); + Registry result = (Registry ) ALL.get(type); if (result == null) { LOCK.readLock().unlock(); LOCK.writeLock().lock(); diff --git a/unchained-commons/src/main/java/unchained/contract/Factory.java b/unchained-commons/src/main/java/unchained/contract/Factory.java index 4ee5102..db4e821 100644 --- a/unchained-commons/src/main/java/unchained/contract/Factory.java +++ b/unchained-commons/src/main/java/unchained/contract/Factory.java @@ -2,38 +2,44 @@ import unchained.error.FactoryNotFoundException; -public interface Factory extends Registrable { +public interface Factory extends Registrable > { Class type(); - T create(A configuration); - - interface Arguments {} - - class NoArgument implements Arguments { - - public static final NoArgument INSTANCE = new NoArgument(); + T create(U arguments); + default T create() { + return create(null); } @Override - default String registryKey() { - return type().getCanonicalName(); + default Class> registryKey() { + return type(); } - static void register(Factory factory) { + @SuppressWarnings("unchecked") + static void register(Factory factory) { Registry.lookup(Factory.class).register(factory); } @SuppressWarnings("unchecked") - static Factory forType(Class type) { - // WARNING: duplicate logic at `type.getCanonicalName()`. - Factory result = Registry.lookup(Factory.class).get(type.getCanonicalName()); + static Factory forType(Class type) { + /* + + NOTE: + + This is an oversimplified logic to implement factory lookup. + A more advanced implementation must be able to find the best + factory among a set of candidate factories. + + */ + Factory result = (Factory ) Registry.lookup(Factory.class).get(type); + if (result == null) { throw new FactoryNotFoundException(type); } try { - return (Factory ) result; + return (Factory ) result; } catch (ClassCastException e) { throw new FactoryNotFoundException(type, e); } diff --git a/unchained-commons/src/main/java/unchained/contract/Registrable.java b/unchained-commons/src/main/java/unchained/contract/Registrable.java index 54df2f5..624f698 100644 --- a/unchained-commons/src/main/java/unchained/contract/Registrable.java +++ b/unchained-commons/src/main/java/unchained/contract/Registrable.java @@ -1,7 +1,7 @@ package unchained.contract; -public interface Registrable { +public interface Registrable