CDI 2.0: Fun With Composition, Part 3

(Disclaimer: I work for Oracle doing Java EE architecture and other things, but none of my writings here or anywhere else on this site have anything to do with my day job there.  In short, as always, these are just the writings of a Java EE hacker using publicly available stuff.)

In the last post, we saw how you could write a portable extension that starts up a JAX-RS runtime after the CDI container is open for business.  (I recommend reading all the posts in this series, starting with the first one.)

Here’s the extension again:


/*
* Copyright © 2016–2017 Laird Nelson. Released under the terms of the MIT license: https://opensource.org/licenses/MIT
*/
package com.serverco;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.event.Observes;
import javax.enterprise.inject.spi.AfterDeploymentValidation;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.BeforeShutdown;
import javax.enterprise.inject.spi.Extension;
import org.glassfish.grizzly.http.server.HttpServer;
public class HttpServerStartingExtension implements Extension {
private volatile HttpServer server;
private void startHttpServer(@Observes final AfterDeploymentValidation event, final BeanManager beanManager) {
if (beanManager != null && this.server == null) {
final HttpServer server = get(beanManager, HttpServer.class);
if (server != null) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public final void run() {
shutdown(server);
}
});
if (!server.isStarted()) {
try {
server.start();
} catch (final IOException ioException) {
event.addDeploymentProblem(ioException);
}
}
this.server = server;
}
}
}
private void shutdownHttpServer(@Observes final BeforeShutdown event, final BeanManager beanManager) {
if (this.server != null) {
try {
// You should really run this thing on another thread;
// join()ing here just for expediency
Thread.currentThread().join();
} catch (final InterruptedException interruptedException) {
Thread.currentThread().interrupt();
}
shutdown(server);
}
}
private static final <T> T get(final BeanManager beanManager, final Type c, final Annotation… qualifiers) {
T returnValue = null;
if (beanManager != null && c != null) {
final Set<Bean<?>> beans = beanManager.getBeans(c, qualifiers);
if (beans != null && !beans.isEmpty()) {
final Bean<?> bean = beanManager.resolve(beans);
assert bean != null;
final CreationalContext<?> creationalContext = beanManager.createCreationalContext(bean);
assert creationalContext != null;
@SuppressWarnings("unchecked")
final T reference = (T)beanManager.getReference(bean, c, creationalContext);
returnValue = reference;
}
}
return returnValue;
}
private static final void shutdown(final HttpServer server) {
if (server != null && server.isStarted()) {
try {
server.shutdown().get();
} catch (final ExecutionException ignore) {
} catch (final InterruptedException interruptedException) {
Thread.currentThread().interrupt();
}
}
}
}

For this extension to work, though, line 34 has to return a non-null HttpServer.  As you can see, there’s nothing in this extension that makes such a thing.  The extension is, fortunately, relatively fault-tolerant (or at least that’s the idea 😀), so if no such HttpServer is around, then the extension should just silently do nothing.

In CDI in general, you write things so that the supplying of an object you need is SEP (someone else’s problem).  That is, quite apart from the mechanics of injection and so on, the important part of dependency injection is that if you need something, you just presume that it will be handed to you.  So here we presume that somehow, some way, an HttpServer will be available in the CDI container.  If it turns out that no such object exists, well, OK, we just do no harm.

So how could an HttpServer get in to the container so that it would be picked up by this extension?  Well, it could be a bean itself.  Maybe we’ll get lucky?  But probably not, as the Javadoc shows.  Sure enough, although HttpServer has a zero argument constructor, and hence could be a CDI bean, there are no further injection points on it, and furthermore the Grizzly module of which it is a part does not feature a META-INF/beans.xml descriptor, suggesting, though not proving, that we’re not going to get lucky.  So HttpServer is technically speaking a valid CDI bean, but a pretty limited one if discovered or added programmatically to a CDI container as-is.

How else could it get in there?  Well, there could be a producer method.  This seems like a good way to go.  A producer method makes bean instances out of raw materials available in the CDI container.  That sounds like exactly what we want.  So let’s say that ServerCo, writes one to make an HttpServer using the features of the GrizzlyHttpServerFactory class present in Jersey.  Let’s say it looks like this, and, just for kicks, lives in a different jar file than the one that houses the portable extension:


/*
* Copyright 2016 Laird Nelson. Released under the terms of the MIT license: https://opensource.org/licenses/MIT
*/
package serverco;
import java.net.URI;
import java.net.URISyntaxException;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.CreationException;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.Produces;
import javax.ws.rs.core.Application;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpContainer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ContainerFactory;
@ApplicationScoped
class Producers {
private Producers() {
super();
}
@Produces
@Dependent
private static final GrizzlyHttpContainer produceGrizzlyHttpContainer(final Instance<Application> applicationInstance) {
final GrizzlyHttpContainer returnValue;
if (applicationInstance == null || applicationInstance.isUnsatisfied()) {
returnValue = null;
} else {
returnValue = ContainerFactory.createContainer(GrizzlyHttpContainer.class, applicationInstance.get());
}
return returnValue;
}
@Produces
@Dependent
private static final HttpServer produceHttpServer(final Instance<GrizzlyHttpContainer> handlerInstance) {
final HttpServer returnValue;
if (handlerInstance == null || handlerInstance.isUnsatisfied()) {
returnValue = null;
} else {
URI uri = null;
try {
uri = new URI("ignored", null /* no userInfo */, "localhost", 80, null, null /* no query */, null /* no fragment */);
} catch (final URISyntaxException uriSyntaxException) {
throw new CreationException(uriSyntaxException);
}
returnValue = GrizzlyHttpServerFactory.createHttpServer(uri, handlerInstance.get(), false, null, false);
}
return returnValue;
}
}

Let’s look at line 46 above.  This is a producer method that creates an HttpServer if one is needed.  To do so, it requires a GrizzlyHttpContainer, but such a thing might not exist.  To express this kind of optional behavior, it requests that an Instance<GrizzlyHttpContainer> be supplied to it.  The CDI container will make such a thing available whether its underlying “payload” exists or not, so we can test things about it here.  See line 48: if the Instance is unsatisfied—that is, if there isn’t a GrizzlyHttpContainer in the CDI container anywhere, nor a means for one to be synthesized or manufactured—then we can return null here, and the portable extension we saw earlier will effectively quietly become one big no-op.

On the other hand, starting at line 51, if there is a GrizzlyHttpContainer we can work with, well, then, it’s a pretty simple matter to use it to construct a new HttpServer (line 57).

Very cool.  OK, so where does the GrizzlyHttpContainer come from?

That’s the purpose of the first producer method, that you can see at line 34.  That method says how a GrizzlyHttpContainer can be created, provided that someone supplies a javax.ws.rs.core.Application object.  Obviously, if no such object is available in the CDI container then the method should effectively quietly do nothing, so you can see at lines 36 and 37 that’s what happens.

OK, so clearly the first producer method makes something that the second producer method needs.  And the first producer method works if there’s an Application.  And the portable extension consumes the output of the second producer method and uses it to start a server when the container comes up.

So where does the Application come from?

Let us turn back to our poor developer, who, you recall from my last post, was done.  She had written a JAX-RS application and a root resource class and—right at that point—wanted to be finished.  She simply wanted some magic to happen that would let her application start.  She didn’t want to write a main method.  She didn’t want to go start an application server and run some complicated deployment recipe.

Recall also that if you’re keeping track we have several notional jar files (or directory locations—classpath roots, really) that we’ve stuck in fictional corners.  We have:

  • A CDI 2.0 EDR2 implementation (like weld-se-core version 3.0.0.Alpha17 or later)
  • the developer’s classpath root, containing nothing but her Application subclass and her root resource class
  • ServerCo’s portable extension jar file described in Part 2
  • A classpath root that contains the boilerplate main class that brings a CDI container up and shuts it down, described in my first post
  • ServerCo’s jar file containing the producer methods noted above

What’s really neat is if you run this:

java -classpath /path/to/weld-se-core-3.0.0.Alpha17.jar:/path/to/weld-se-core/dependencies:/path/to/developer/code:/path/to/serverco/portable-extension-1.0.jar:/path/to/boilerplate/code:/path/to/serverco/producers-1.0.jar:/path/to/serverco/dependencies com.foobar.Main

…then I hope to have shown that you will get an HTTP endpoint up and running on localhost port 80 that runs our developer’s JAX-RS application.

 

CDI 2.0: Fun With Composition, Part 2

In my last post I laid the groundwork for a compositional approach to deploying applications in CDI 2.0.  The main method doesn’t need to do anything.  Portable extensions don’t need to know anything about the main method.  User code doesn’t need to know anything about portable extensions.

Recall that our developer has written the following standards-compliant JAX-RS application:


/*
* Copyright 2016 Laird Nelson. Released under the terms of the MIT license: https://opensource.org/licenses/MIT
*/
package developer;
import java.util.Collections;
import java.util.Set;
import javax.ws.rs.core.Application;
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class HelloWorldApplication extends Application {
public HelloWorldApplication() {
super();
}
@Override
public Set<Class<?>> getClasses() {
return Collections.singleton(HelloWorldResource.class);
}
}


/*
* Copyright 2016 Laird Nelson. Released under the terms of the MIT license: https://opensource.org/licenses/MIT
*/
package developer;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.core.Application;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
@Path("hello")
@RequestScoped
public class HelloWorldResource {
@GET
@Produces("text/plain")
public String hello() {
return "Hello, world!";
}
}

…and just wants to run it.  But she also wants to be done here, and doesn’t want to write a main method or depend in code on vendor-specific classes.  Also, because we are living in The Future™, she wants to avoid deploying to some application server by hand.

Enter portable extensions and composition.

First, recall our generic main method, parked over in a corner in a jar of its own:


/*
* Copyright 2016 Laird Nelson. Released under the terms of the MIT license: https://opensource.org/licenses/MIT
*/
package com.foobar;
import javax.enterprise.inject.se.SeContainer;
import javax.enterprise.inject.se.SeContainerInitializer;
public class Main {
public static final void main(final String[] args) throws Exception {
final SeContainerInitializer containerInitializer = SeContainerInitializer.newInstance();
assert containerInitializer != null;
try (final SeContainer container = containerInitializer.initialize()) {
assert container != null;
}
}
}

Now let’s say ServerCo authors this nice little extension:


/*
* Copyright © 2016–2017 Laird Nelson. Released under the terms of the MIT license: https://opensource.org/licenses/MIT
*/
package com.serverco;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.event.Observes;
import javax.enterprise.inject.spi.AfterDeploymentValidation;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.BeforeShutdown;
import javax.enterprise.inject.spi.Extension;
import org.glassfish.grizzly.http.server.HttpServer;
public class HttpServerStartingExtension implements Extension {
private volatile HttpServer server;
private void startHttpServer(@Observes final AfterDeploymentValidation event, final BeanManager beanManager) {
if (beanManager != null && this.server == null) {
final HttpServer server = get(beanManager, HttpServer.class);
if (server != null) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public final void run() {
shutdown(server);
}
});
if (!server.isStarted()) {
try {
server.start();
} catch (final IOException ioException) {
event.addDeploymentProblem(ioException);
}
}
this.server = server;
}
}
}
private void shutdownHttpServer(@Observes final BeforeShutdown event, final BeanManager beanManager) {
if (this.server != null) {
try {
// You should really run this thing on another thread;
// join()ing here just for expediency
Thread.currentThread().join();
} catch (final InterruptedException interruptedException) {
Thread.currentThread().interrupt();
}
shutdown(server);
}
}
private static final <T> T get(final BeanManager beanManager, final Type c, final Annotation… qualifiers) {
T returnValue = null;
if (beanManager != null && c != null) {
final Set<Bean<?>> beans = beanManager.getBeans(c, qualifiers);
if (beans != null && !beans.isEmpty()) {
final Bean<?> bean = beanManager.resolve(beans);
assert bean != null;
final CreationalContext<?> creationalContext = beanManager.createCreationalContext(bean);
assert creationalContext != null;
@SuppressWarnings("unchecked")
final T reference = (T)beanManager.getReference(bean, c, creationalContext);
returnValue = reference;
}
}
return returnValue;
}
private static final void shutdown(final HttpServer server) {
if (server != null && server.isStarted()) {
try {
server.shutdown().get();
} catch (final ExecutionException ignore) {
} catch (final InterruptedException interruptedException) {
Thread.currentThread().interrupt();
}
}
}
}

Ignoring the utility methods for a moment, at line 32 the extension is notified that the CDI container it’s a part of is now open for business.

At line 34, using the get() utility method (see line 65), it asks the container for an HttpServer instance, if there is one.

If indeed there is one, then it starts the server.

Control flows back to the main method.  Specifically, the main method now has an SeContainer in its hands.  It promptly, of course, does nothing, and so the container starts to shut down.

At line 54 above, the portable extension is notified that unless something else happens, the container is going to shut down.  It arranges for the server to stay up with the join() call on line 57, and until the server is interrupted or killed or otherwise stopped we will block here.

Look, a JAX-RS server that comes up as a side effect of a CDI container starting up!

But wait…at line 35…will that HttpServer ever be non-null?  Who put an HttpServer into the CDI container?  Did anyone?

No.  Not yet.

We’ll address that in the next post!

CDI 2.0: Fun With Composition, Part 1

(Disclaimer: I work for Oracle doing Java EE architecture and other things, but none of my writings here or anywhere else on this site have anything to do with my day job there.  In short, as always, these are just the writings of a Java EE hacker using publicly available stuff.)

So in my last post I was musing on the fact that a CDI SE application that appears to do nothing may do a great deal indeed.

Recall that you start a CDI container from Java SE like this:


/*
* Copyright 2016 Laird Nelson. Released under the terms of the MIT license: https://opensource.org/licenses/MIT
*/
package com.foobar;
import javax.enterprise.inject.se.SeContainer;
import javax.enterprise.inject.se.SeContainerInitializer;
public class Main {
public static final void main(final String[] args) throws Exception {
final SeContainerInitializer containerInitializer = SeContainerInitializer.newInstance();
assert containerInitializer != null;
try (final SeContainer container = containerInitializer.initialize()) {
assert container != null;
}
}
}

Now let’s write a portable extension that is notified after the container is open for business:


package com.serverco;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterDeploymentValidation;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.Extension;
public class SimplePortableExtension implements Extension {
public SimplePortableExtension() {
super();
// Called by java.util.ServiceLoader
}
public void containerIsOpenForBusiness(@Observes final AfterDeploymentValidation event, final BeanManager beanManager) {
System.out.println("*** container is open for business!");
}
}

This extension is not a CDI bean exactly.  It doesn’t have a scope (that’s a bit of a white lie, but substantially true).  It is created by the java.util.ServiceLoader mechanism once as part of container initialization.  That means it needs a no-argument constructor (see line 11) and an entry in its containing archive’s META-INF/services/javax.enterprise.inject.spi.Extension file that, in this case, looks like this:

com.serverco.SimplePortableExtension

So let’s mentally park com.serverco’s extension over in the corner in its own jar file, and the main method we outlined above over in the other corner in another jar file.

If we were to run that main method with a classpath consisting of both jar files, we would see:

*** container is open for business!

…on the console, even though neither the main method nor the extension inherently knew about each other.

That’s pretty neat.

Now, just for fun, let’s say our developer creates a simple, standard JAX-RS application (no Jersey, no RestEasy, just standards):


/*
* Copyright 2016 Laird Nelson. Released under the terms of the MIT license: https://opensource.org/licenses/MIT
*/
package developer;
import java.util.Collections;
import java.util.Set;
import javax.ws.rs.core.Application;
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class HelloWorldApplication extends Application {
public HelloWorldApplication() {
super();
}
@Override
public Set<Class<?>> getClasses() {
return Collections.singleton(HelloWorldResource.class);
}
}


/*
* Copyright 2016 Laird Nelson. Released under the terms of the MIT license: https://opensource.org/licenses/MIT
*/
package developer;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.core.Application;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
@Path("hello")
@RequestScoped
public class HelloWorldResource {
@GET
@Produces("text/plain")
public String hello() {
return "Hello, world!";
}
}

Let’s say now our developer wants to be done, right here, and in the abstract in some sense wants to just run this application right here, right now.

Well, she’s going to need some kind of container to do so.  She could package this thing up in a .war file and deploy it somewhere, but that is not The Future™, so instead she just wants to run this application.

Jersey, of course, is one implementation of the JAX-RS standard.  Our developer could embed Jersey’s recipe for starting an embedded Grizzly server in a main() method she writes, and…but she wanted to be done!  She doesn’t want to write a main method with this recipe in it:


java.net.URI baseUri = javax.ws.rs.core.UriBuilder.fromUri("http://localhost/&quot;).port(9998).build();
org.glassfish.jersey.server.ResourceConfig config = new org.glassfish.jersey.server.ResourceConfig(developer.HelloWorldResource.class);
org.glassfish.grizzly.http.server.HttpServer server = org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory.createHttpServer(baseUri, config);
// and so on and so on

Well, OK, someone else could write this main method, and accept her application as a command line argument…which is sort of like deploying, and that’s not The Future™ either.

It would be kind of cool if our developer’s application, when placed on a classpath with potentially other jar files, one of which contains a main method, another of which contains a server implementation, etc., just ran.

It would also be kind of cool if our developer could easily try switching from using Jersey to using RestEasy without really doing much.

CDI 2.0 as you’ve probably guessed makes this pretty simple.  Stay tuned for the next post.

CDI 2.0

(Disclaimer: I work for Oracle doing Java EE architecture and other things, but none of my writings here or anywhere else on this site have anything to do with my day job there.  In short, as always, these are just the writings of a Java EE hacker using publicly available stuff.)

Have you taken a look at CDI 2.0 (Early Draft 2) yet?

You really should.

If you weren’t paying attention, CDI added a few interesting things that are on their way to being part of the official standard.

Perhaps the most notable is that CDI is no longer a parasite.

A parasite is a being that lives inside a host.  Just so, CDI in versions prior to 2.0 could be instantiated only in non-standardized manners.  That is, you would have to invoke Weld classes, or OpenWebBeans classes, to get a CDI environment up and running that your code could play in.

But no longer.  Now you can discover and instantiate a CDI container from Java SE in a vendor independent fashion.  Here’s what it looks like, and 80% of the following snippet is license text and documentation:


/*
* Copyright 2016 Laird Nelson.
*
* 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 com.foobar;
import javax.enterprise.inject.se.SeContainer;
import javax.enterprise.inject.se.SeContainerInitializer;
/**
* A class whose {@linkplain #main(String[]) <code>main</code> method}
* {@linkplain SeContainerInitializer#initialize() initializes} a new
* {@link SeContainer}.
*
* @author <a href="http://about.me/lairdnelson&quot; target="_parent">Laird Nelson</a>
*
* @see SeContainerInitializer#initialize()
*/
public class Main {
/**
* Creates a new {@link Main}.
*/
public Main() {
super();
}
/**
* {@linkplain SeContainerInitializer#initialize() Initializes} a
* new {@link SeContainer} and then {@linkplain SeContainer#close()
* closes} it.
*
* @param args command-line arguments; may be {@code null}
*
* @exception Exception if an error occurs
*
* @see SeContainerInitializer#newInstance()
*
* @see SeContainerInitializer#initialize()
*
* @see SeContainer#close()
*/
public static final void main(final String[] args) throws Exception {
final SeContainerInitializer containerInitializer = SeContainerInitializer.newInstance();
assert containerInitializer != null;
try (final SeContainer container = containerInitializer.initialize()) {
assert container != null;
}
}
}

view raw

Main.java

hosted with ❤ by GitHub

See line 61 above?  That gets an SeContainerInitializer.  From there, you call initialize(), and that gets you an SeContainer.  From there, you can get its BeanManager, and from there you can do anything you like.

But what’s really interesting is what is not going on on line 65 above.

On line 65 above, nothing is happening!  That means the container comes up (line 63), and when it has come up, it goes down again (the implicit close() called by the try-with-resources block, also at line 63).  Hmm; I guess this application doesn’t do anything.

Actually, you don’t know that.

In between coming up and going down, the container has found and created all the portable extensions on the classpath, if there were any, run through its startup lifecycle (which portable extensions can be involved in and affect), discovered all the bean archives on the classpath whether by itself or with the assistance of portable extensions and alerted (potentially) every bean that its ApplicationScoped scope has initialized.  Then depending on what injection any observing bean might perform, it may notify other beans about the availability of other scopes.

Lastly, it notifies the beans about the scopes going away, and then it notifies extensions that the container is about to go down.

In the meantime all the beans and portable extensions involved can fire events of any kind on the local event bus to notify each other of interesting things.

That’s an awful lot of valuable stuff for an application that doesn’t do anything.

It also means that you could have an executable that doesn’t presume anything about the work to be done, but still frees the developer from having to supply a main method, and provides an integration backplane for a whole host of technologies.

For example, the act of placing a JAX-RS application in a jar file could—depending on the portable extensions in play in any given CDI container environment—result in that JAX-RS application being deployed on an embedded server.

I’ll leave you with that before my next post.