summaryrefslogtreecommitdiffstats
path: root/jdisc_core/src/main/java/com/yahoo/jdisc/service
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
committerJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
commit72231250ed81e10d66bfe70701e64fa5fe50f712 (patch)
tree2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /jdisc_core/src/main/java/com/yahoo/jdisc/service
Publish
Diffstat (limited to 'jdisc_core/src/main/java/com/yahoo/jdisc/service')
-rw-r--r--jdisc_core/src/main/java/com/yahoo/jdisc/service/AbstractClientProvider.java20
-rw-r--r--jdisc_core/src/main/java/com/yahoo/jdisc/service/AbstractServerProvider.java30
-rw-r--r--jdisc_core/src/main/java/com/yahoo/jdisc/service/BindingSetNotFoundException.java38
-rw-r--r--jdisc_core/src/main/java/com/yahoo/jdisc/service/ClientProvider.java24
-rw-r--r--jdisc_core/src/main/java/com/yahoo/jdisc/service/ContainerNotReadyException.java26
-rw-r--r--jdisc_core/src/main/java/com/yahoo/jdisc/service/CurrentContainer.java37
-rw-r--r--jdisc_core/src/main/java/com/yahoo/jdisc/service/NoBindingSetSelectedException.java39
-rw-r--r--jdisc_core/src/main/java/com/yahoo/jdisc/service/ServerProvider.java52
-rw-r--r--jdisc_core/src/main/java/com/yahoo/jdisc/service/package-info.java77
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>&lt;scheme&gt;://localhost[:&lt;port&gt;]/&lt;path&gt;</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;
+
+&#64;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;
+
+&#64;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://&#42;/*", 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>
+&#64;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;