@PublicApi
Application
.See: Description
Interface | Description |
---|---|
Application |
This interface defines the API of the singleton Application that runs in a jDISC instance.
|
BindingSetSelector |
This interface defines the component that is used by the
CurrentContainer to assign a BindingSet to a
newly created Container based on the given URI . |
ContainerActivator |
This interface defines the API for changing the active
Container of a jDISC application. |
DeactivatedContainer |
This interface represents a
Container which has been deactivated. |
MetricConsumer |
This interface defines the consumer counterpart of the
Metric interface. |
OsgiFramework |
This is an abstraction of the OSGi framework that hides the actual implementation details.
|
Class | Description |
---|---|
AbstractApplication |
This class is a convenient parent class for
Application developers that require simple access to the most
commonly used jDISC APIs. |
BindingMatch<T> |
This class holds the result of a
BindingSet.match(URI) operation. |
BindingRepository<T> |
This is a mutable repository of bindings from
UriPattern s to some target type T. |
BindingSet<T> |
This is an immutable set of ordered bindings from
UriPattern s to some target type T. |
BundleInstaller |
This is a utility class to help with installing, starting, stopping and uninstalling OSGi Bundles.
|
ContainerBuilder |
This is the inactive, mutable
Container . |
ContainerThread |
This class decorates
Thread to allow for internal jDISC optimizations. |
ContainerThread.Factory |
This class implements the
ThreadFactory interface on top of a Provider for MetricConsumer instances. |
GlobPattern | |
GlobPattern.Match | |
GlobPattern.VerbatimPattern | |
GlobPattern.WildcardPattern | |
GuiceRepository |
This is a repository of
Module s. |
GuiceRepository.ElementCollector | |
MetricImpl | |
MetricImpl.LocalConsumer | |
MetricNullProvider | |
MetricProvider | |
OsgiHeader |
This interface acts as a namespace for the supported OSGi bundle headers.
|
ResourcePool |
This is a utility class to help manage
SharedResource s while configuring a ContainerBuilder . |
ServerRepository |
This is a repository of
ServerProvider s. |
UriPattern |
This class holds a regular expression designed so that it only matches certain
URI s. |
UriPattern.Match |
This class holds the result of a
UriPattern.match(URI) operation. |
Exception | Description |
---|---|
ApplicationNotReadyException |
This exception is used to signal that no
Application has been configured. |
BundleInstallationException |
This exception is thrown by
OsgiFramework.installBundle(String) if installation failed. |
Provides classes and interfaces for implementing an Application
.
In every jDISC process there is exactly one Application instance, it is created during jDISC startup, and it is
destroyed during jDISC shutdown. The Application uses the ContainerBuilder
interface to load OSGi Bundles
, install Guice Modules
, create and start ServerProviders
,
inject a BindingSetSelector
, and configure BindingSets
with RequestHandlers
and ClientProviders
. Once the ContainerBuilder is
appropriately configured, it is passed to the local ContainerActivator
to perform
an atomic switch from current to new Container
.
@Inject MyApplication(ContainerActivator activator) { ContainerBuilder builder = activator.newContainerBuilder(); builder.guiceModules().install(new MyBindings()); Bundle bundle = builder.osgiBundles().install("file:$VESPA_HOME/lib/jars/jdisc_http.jar"); builder.serverProviders().install(bundle, "com.yahoo.disc.service.http.HttpServer"); builder.serverBindings().bind("http://localhost/admin/*", new MyAdminHandler()); builder.serverBindings().bind("http://localhost/*", new MyRequestHandler()); activator.activateContainer(builder); }
Because the Request
owns a reference to the Container that was active on Request-
construction, jDISC is able to guarantee that no component is shut down as long as there are pending Requests that
can reach them. When activating a new Container, the previous Container is returned as a DeactivatedContainer
instance - an API that can be used by the
Application to asynchronously wait for Container termination in order to completely shut down components that are no
longer required. This activation pattern is used both for Application startup, runtime reconfigurations, as well as
for Application shutdown. It allows all jDISC Application to continously serve Requests during reconfiguration,
causing no down time other than what the Application itself explicitly enforces.
void reconfigureApplication() { (...) reconfiguredContainerBuilder.handlers().install(myRetainedClients); reconfiguredContainerBuilder.servers().install(myRetainedServers); myExpiredServers.close(); DeactivatedContainer deactivatedContainer = containerActivator.activateContainer(reconfiguredContainerBuilder); deactivatedContainer.notifyTermination(new Runnable() { void run() { myExpiredClients.destroy(); myExpiredServers.destroy(); } }); }
At the heart of jDISC is an OSGi framework. An Application is always packaged as an OSGi bundle. The OSGi technology itself is a set of specifications that define a dynamic component system for Java. These specifications enable a development model where applications are (dynamically) composed of many different (reusable) components. The OSGi specifications enable components to hide their implementations from other components while communicating through common interfaces (in our case, defined by jDISC's core API) or services (which are objects that are explicitly shared between components). Initially this framework is used to load and bootstrap the application from an OSGi bundle specified on deployment, but because it is exposed through the ContainerBuilder interface, an Application itself can load other bundles as required.
The OSGi integration in jDISC adds the following manifest instructions:
BundleActivator
. If privileges can not be provided, this bundle should not be
installed. Only the Application bundle and its dependencies can ever be given privileges, as jDISC itself drops
its privileges after the bootstrapping step.
One of the benefits of using OSGi is that it provides Classloader isolation, meaning that one bundle can not inadvertently affect the inernals of another. jDISC leverages this to isolate the different implementations of RequestHandlers, ServerProviders, and jDISC's core internals.
The OSGi manifest instruction "X-JDisc-Application" tells jDISC the name of the Application class to inject from
the loaded bundle during startup. To this end, it is necessary for the named Application to offer an
injection-enabled constructor (annotated with the Inject
keyword). At a minimum, an Application
typically needs to have the ContainerActivator injected and saved to a member variable. Because of jDISC's additional
OSGi manifest instruction "X-JDisc-Preinstall-Bundle", an Application bundle can be built with compile-time
dependencies on other OSGi bundles (using the "provided" scope in maven) without having to repack those dependency
into the application itself. Unless incompatible API changes are made to 3rd party jDISC components, it should be
possible to upgrade dependencies without having to recompile and redeploy the Application.
jDISC allows a single binary to execute any application without having to change the command line parameters. Instead of modifying the parameters of the single application binary, changing the application is achieved by setting a single environment variable. The planned method of deployment is therefore to 1) install the application's OSGi bundle, 2) set the necessary "jdisc.application" environment variable, and 3) restart the package.
$ install myapp_jar $ set jdisc.application="myapp.jar" $ restart jdiscFor testing and development, the jDISC binary also supports command line parameters to start and stop a local application.
$ install jdisc-dev $ emacs src/main/java/edu/disc/MyApplication.java $ mvn install $ sudo jdisc_start target/myapp.jar
It is the responsibility of the Application itself to create, configure and activate a Container instance. Although jDISC offers an API that allows for- and manages the change of an active Container instance, making the necessary calls to do so is also considered Application logic. When jDISC receives an external signal to shut down, it instructs the running Application to initiate a graceful shutdown, and waits for it to terminate. Any in-flight Requests should complete, and all services will close.
Because jDISC runs as a Daemon it has the opportunity to run code with root privileges, and it can be configured to provide these privileges to an application's initialization code. However, 1) deployment-time configuration must explicitly enable this capability (by setting the environment variable "jdisc.privileged" to "true"), and 2) the application bundle must explicitly declare that it requires privileges (by including the manifest header "X-JDisc-Privileged-Activator" with the value "true"). If privileges are required but unavailable, deployment of the application will fail. Code that requires privileges will never be run WITHOUT privileges, and code that does not explicitly request privileges will never be run WITH privileges. Finally, the code snippet that is run with privileges is separate from the Application class to avoid unintentionally passing privileges to third-party code.
com.yahoo.jdisc
,
com.yahoo.jdisc.handler
,
com.yahoo.jdisc.service
Copyright © 2018. All rights reserved.