diff options
author | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-06-15 23:09:44 +0200 |
commit | 72231250ed81e10d66bfe70701e64fa5fe50f712 (patch) | |
tree | 2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /jdisc_core/src/main/java/com/yahoo/jdisc/service |
Publish
Diffstat (limited to 'jdisc_core/src/main/java/com/yahoo/jdisc/service')
9 files changed, 343 insertions, 0 deletions
diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/service/AbstractClientProvider.java b/jdisc_core/src/main/java/com/yahoo/jdisc/service/AbstractClientProvider.java new file mode 100644 index 00000000000..3f2ebc67aa5 --- /dev/null +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/service/AbstractClientProvider.java @@ -0,0 +1,20 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.service; + +import com.yahoo.jdisc.Request; +import com.yahoo.jdisc.handler.AbstractRequestHandler; +import com.yahoo.jdisc.handler.ResponseHandler; + +/** + * <p>This is a convenient parent class for {@link ClientProvider} with default implementations for all but the + * essential {@link #handleRequest(Request, ResponseHandler)} method.</p> + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public abstract class AbstractClientProvider extends AbstractRequestHandler implements ClientProvider { + + @Override + public void start() { + + } +} diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/service/AbstractServerProvider.java b/jdisc_core/src/main/java/com/yahoo/jdisc/service/AbstractServerProvider.java new file mode 100644 index 00000000000..15363ded3e0 --- /dev/null +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/service/AbstractServerProvider.java @@ -0,0 +1,30 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.service; + +import com.google.inject.Inject; +import com.yahoo.jdisc.AbstractResource; +import com.yahoo.jdisc.Request; + +import java.util.Objects; + +/** + * <p>This is a convenient parent class for {@link ServerProvider} with default implementations for all but the + * essential {@link #start()} and {@link #close()} methods. It requires that the {@link CurrentContainer} is injected in + * the constructor, since that interface is needed to dispatch {@link Request}s.</p> + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public abstract class AbstractServerProvider extends AbstractResource implements ServerProvider { + + private final CurrentContainer container; + + @Inject + protected AbstractServerProvider(CurrentContainer container) { + Objects.requireNonNull(container, "container"); + this.container = container; + } + + public final CurrentContainer container() { + return container; + } +} diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/service/BindingSetNotFoundException.java b/jdisc_core/src/main/java/com/yahoo/jdisc/service/BindingSetNotFoundException.java new file mode 100644 index 00000000000..b02fab2eba8 --- /dev/null +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/service/BindingSetNotFoundException.java @@ -0,0 +1,38 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.service; + +import com.yahoo.jdisc.application.BindingSet; + +import java.net.URI; + +/** + * This exception is used to signal that a named {@link BindingSet} was not found. An instance of this class will be + * thrown by the {@link CurrentContainer#newReference(URI)} method when a BindingSet with the specified name does not + * exist. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public final class BindingSetNotFoundException extends RuntimeException { + + private final String bindingSet; + + /** + * Constructs a new instance of this class with a detail message that contains the name of the {@link BindingSet} + * that was not found. + * + * @param bindingSet The name of the {@link BindingSet} that was not found. + */ + public BindingSetNotFoundException(String bindingSet) { + super("No binding set named '" + bindingSet + "'."); + this.bindingSet = bindingSet; + } + + /** + * Returns the name of the {@link BindingSet} that was not found. + * + * @return The name of the BindingSet. + */ + public String bindingSet() { + return bindingSet; + } +} diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/service/ClientProvider.java b/jdisc_core/src/main/java/com/yahoo/jdisc/service/ClientProvider.java new file mode 100644 index 00000000000..96583217721 --- /dev/null +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/service/ClientProvider.java @@ -0,0 +1,24 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.service; + +import com.yahoo.jdisc.Container; +import com.yahoo.jdisc.application.*; +import com.yahoo.jdisc.handler.RequestHandler; + +/** + * <p>This interface defines a component that is capable of acting as a client to an external server. To activate a + * ClientProvider it must be {@link BindingRepository#bind(String, Object) bound} to a {@link UriPattern} within a + * {@link ContainerBuilder}, and that builder must be {@link ContainerActivator#activateContainer(ContainerBuilder) + * activated}.</p> + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public interface ClientProvider extends RequestHandler { + + /** + * <p>This is a synchronous method to configure this ClientProvider. The {@link Container} does <em>not</em> call + * this method, instead it is a required step in the {@link Application} initialization code.</p> + */ + void start(); + +} diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/service/ContainerNotReadyException.java b/jdisc_core/src/main/java/com/yahoo/jdisc/service/ContainerNotReadyException.java new file mode 100644 index 00000000000..fa9dfd3b6f6 --- /dev/null +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/service/ContainerNotReadyException.java @@ -0,0 +1,26 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.service; + +import com.yahoo.jdisc.Container; +import com.yahoo.jdisc.Request; +import com.yahoo.jdisc.application.ContainerActivator; +import com.yahoo.jdisc.application.ContainerBuilder; + +import java.net.URI; + +/** + * This exception is used to signal that no {@link Container} is ready to serve {@link Request}s. An instance of this + * class will be thrown by the {@link CurrentContainer#newReference(URI)} method if it is called before a Container has + * been activated, or after a <em>null</em> argument has been passed to {@link ContainerActivator#activateContainer(ContainerBuilder)}. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public final class ContainerNotReadyException extends RuntimeException { + + /** + * Constructs a new instance of this class with a detail message. + */ + public ContainerNotReadyException() { + super("Container not ready."); + } +} diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/service/CurrentContainer.java b/jdisc_core/src/main/java/com/yahoo/jdisc/service/CurrentContainer.java new file mode 100644 index 00000000000..7e4625277be --- /dev/null +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/service/CurrentContainer.java @@ -0,0 +1,37 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.service; + +import com.yahoo.jdisc.Container; +import com.yahoo.jdisc.Request; +import com.yahoo.jdisc.application.BindingSet; +import com.yahoo.jdisc.application.BindingSetSelector; +import com.yahoo.jdisc.handler.RequestHandler; + +import java.net.URI; + +/** + * This interface declares a method to retrieve a reference to the current {@link Container}. Note that a {@link + * Container} which has <em>not</em> been {@link Container#release() closed} will actively keep it alive, preventing it + * from shutting down when expired. Failure to call close() will eventually lead to an {@link OutOfMemoryError}. A + * {@link ServerProvider} should have an instance of this class injected in its constructor, and simply use the {@link + * Request#Request(CurrentContainer, URI) appropriate Request constructor} to avoid having to worry about the keep-alive + * issue. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public interface CurrentContainer { + + /** + * Returns a reference to the currently active {@link Container}. Until {@link Container#release()} has been called, + * the Container can not shut down. + * + * @param uri The identifier used to match this Request to an appropriate {@link ClientProvider} or {@link + * RequestHandler}. The hostname must be "localhost" or a fully qualified domain name. + * @return A reference to the current Container. + * @throws NoBindingSetSelectedException If no {@link BindingSet} was selected by the {@link BindingSetSelector}. + * @throws BindingSetNotFoundException If the named BindingSet was not found. + * @throws ContainerNotReadyException If no active Container was found, this can only happen during initial + * setup. + */ + public Container newReference(URI uri); +} diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/service/NoBindingSetSelectedException.java b/jdisc_core/src/main/java/com/yahoo/jdisc/service/NoBindingSetSelectedException.java new file mode 100644 index 00000000000..382262e52cd --- /dev/null +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/service/NoBindingSetSelectedException.java @@ -0,0 +1,39 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.service; + +import com.yahoo.jdisc.application.BindingSet; +import com.yahoo.jdisc.application.BindingSetSelector; + +import java.net.URI; + +/** + * This exception is used to signal that no {@link BindingSet} was selected for a given {@link URI}. An instance of this + * class will be thrown by the {@link CurrentContainer#newReference(URI)} method if {@link + * BindingSetSelector#select(URI)} returned <em>null</em>. + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public final class NoBindingSetSelectedException extends RuntimeException { + + private final URI uri; + + /** + * Constructs a new instance of this class with a detail message that contains the {@link URI} for which there was + * no {@link BindingSet} selected. + * + * @param uri The URI for which there was no BindingSet selected. + */ + public NoBindingSetSelectedException(URI uri) { + super("No binding set selected for URI '" + uri + "'."); + this.uri = uri; + } + + /** + * Returns the {@link URI} for which there was no {@link BindingSet} selected. + * + * @return The URI. + */ + public URI uri() { + return uri; + } +} diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/service/ServerProvider.java b/jdisc_core/src/main/java/com/yahoo/jdisc/service/ServerProvider.java new file mode 100644 index 00000000000..ea895088492 --- /dev/null +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/service/ServerProvider.java @@ -0,0 +1,52 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.jdisc.service; + +import com.yahoo.jdisc.Container; +import com.yahoo.jdisc.Request; +import com.yahoo.jdisc.SharedResource; +import com.yahoo.jdisc.application.Application; +import com.yahoo.jdisc.application.ContainerActivator; +import com.yahoo.jdisc.application.ContainerBuilder; +import com.yahoo.jdisc.application.ServerRepository; + +import java.net.URI; + +/** + * <p>This interface defines a component that is capable of acting as a server for an external client. To activate a + * ServerProvider it must be {@link ServerRepository#install(ServerProvider) installed} in a {@link ContainerBuilder}, + * and that builder must be {@link ContainerActivator#activateContainer(ContainerBuilder) activated}.</p> + * + * <p>If a ServerProvider is to expire due to {@link Application} reconfiguration, it is necessary to close() that + * ServerProvider before deactivating the owning {@link Container}. Typically:</p> + * + * <pre> + * myExpiredServers.close(); + * reconfiguredContainerBuilder.servers().install(myRetainedServers); + * containerActivator.activateContainer(reconfiguredContainerBuilder); + * </pre> + * + * <p>All implementations of this interface will need to have a {@link CurrentContainer} injected into its constructor + * so that it is able to create and dispatch new {@link Request}s.</p> + * + * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + */ +public interface ServerProvider extends SharedResource { + + /** + * <p>This is a synchronous method to configure this ServerProvider and bind the listen port (or equivalent). The + * {@link Container} does <em>not</em> call this method, instead it is a required step in the {@link Application} + * initialization code.</p> + */ + public void start(); + + /** + * <p>This is a synchronous method to close the listen port (or equivalent) of this ServerProvider and flush any + * input buffers that will cause calls to {@link CurrentContainer#newReference(URI)}. This method <em>must not</em> + * return until the implementation can guarantee that there will be no further calls to CurrentContainer. All + * previously dispatched {@link Request}s are processed as before.</p> + * + * <p>The {@link Container} does <em>not</em> call this method, instead it is a required step in the {@link + * Application} shutdown code.</p> + */ + public void close(); +} diff --git a/jdisc_core/src/main/java/com/yahoo/jdisc/service/package-info.java b/jdisc_core/src/main/java/com/yahoo/jdisc/service/package-info.java new file mode 100644 index 00000000000..445ddd9c726 --- /dev/null +++ b/jdisc_core/src/main/java/com/yahoo/jdisc/service/package-info.java @@ -0,0 +1,77 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +/** + * <p>Provides classes and interfaces for implementing a {@link com.yahoo.jdisc.service.ClientProvider ClientProvider} or + * a {@link com.yahoo.jdisc.service.ServerProvider ServerProvider}.</p> + * + * <h3>ServerProvider</h3> + * <p>All {@link com.yahoo.jdisc.Request Requests} that are processed in a jDISC application are created by + * ServerProviders. These are components created by the {@link com.yahoo.jdisc.application.Application Application}, and + * they are the parts of jDISC that accept incoming connections. The ServerProvider creates and dispatches Request + * instances to the {@link com.yahoo.jdisc.service.CurrentContainer CurrentContainer}. No Request is ever dispatched to a + * ServerProvider, so a ServerProvider is considered part of the Application and not part of a Container (as opposed to + * {@link com.yahoo.jdisc.handler.RequestHandler RequestHandlers} and ClientProviders). To create a Request the + * ServerProvider first composes a URI on the form <code><scheme>://localhost[:<port>]/<path></code> + * that matches the content of the accepted connection, and passes that URI to the CurrentContainer interface. This + * creates a com.yahoo.jdisc.core.ContainerSnapshot that holds a reference to the {@link + * com.yahoo.jdisc.Container Container} that is currently active, and resolves the appropriate {@link + * com.yahoo.jdisc.application.BindingSet BindingSet} for the given URI through the Application's {@link + * com.yahoo.jdisc.application.BindingSetSelector BindingSetSelector}. This snapshot becomes the context of the new + * Request to ensure that all further processing of that Request happens within the same Container instace. Finally, the + * appropriate RequestHandler is resolved by the selected BindingSet, and the Request is dispatched.</p> + * +<pre> +private final ServerProvider server; + +@Inject +MyApplication(CurrentContainer container) { + server = new MyServerProvider(container); + server.start(); +} +</pre> + * + * <h3>ClientProvider</h3> + * <p>A ClientProvider extends the RequestHandler interface, adding a method for initiating the startup of the provider. + * This is to allow an Application to develop a common ClientProvider install path. As opposed to RequestHandlers that + * are bound to URIs with the "localhost" hostname that the ServerProviders use when creating a Request, a + * ClientProvider is typically bound using a hostname wildcard (the '*' character). Because BindingSet considers a + * wildcard match to be weaker than a verbatim match, only Requests with URIs that are not bound to a local + * RequestHandler are passed to the ClientProvider.</p> + * +<pre> +private final ClientProvider client; + +@Inject +MyApplication(ContainerActivator activator, CurrentContainer container) { + client = new MyClientProvider(); + client.start(); + + ContainerBuilder builder = activator.newContainerBuilder(); + builder.serverBindings().bind("http://localhost/*", new MyRequestHandler()); + builder.clientBindings().bind("http://*/*", client); + activator.activateContainer(builder); +} +</pre> + * + * <p>Because the dispatch to a ClientProvider uses the same mechanics as the dispatch to an ordinary RequestHandler + * (i.e. the BindingSet), it is possible to create a test-mode BindingSet and a test-aware BindingSetSelector which + * dispatches to mock-up RequestHandlers instead of remote servers. The immediate benefit of this is that regression + * tests can be run on an Application otherwise configured for production traffic, allowing you to stress actual + * production code instead of targeted-only unit tests. This is how you would install a custom BindingSetSelector:</p> + * +<pre> +@Inject +MyApplication(ContainerActivator activator, CurrentContainer container) { + ContainerBuilder builder = activator.newContainerBuilder(); + builder.clientBindings().bind("http://bing.com/*", new BingClientProvider()); + builder.clientBindings("test").bind("http://bing.com/*", new BingMockupProvider()); + builder.guiceModules().install(new MyBindingSetSelector()); + activator.activateContainer(builder); +} +</pre> + * + * @see com.yahoo.jdisc + * @see com.yahoo.jdisc.application + * @see com.yahoo.jdisc.handler + */ +@com.yahoo.api.annotations.PublicApi +package com.yahoo.jdisc.service; |