Coder Social home page Coder Social logo

microbean / microbean-helidon-webserver-cdi Goto Github PK

View Code? Open in Web Editor NEW
1.0 2.0 0.0 602 KB

Embeds the Helidon WebServer in CDI.

Home Page: https://microbean.github.io/microbean-helidon-webserver-cdi

License: Apache License 2.0

Java 99.83% CSS 0.17%
cdi cdi-extension cdi2 cdi20 helidon java portable-extension helidon-webserver helidon-se cdi-ecosystem

microbean-helidon-webserver-cdi's Introduction

microBean Helidon WebServer CDI

Build Status Maven Central

Overview

This project consists of a CDI portable extension that embeds a Helidon WebServer into a CDI environment and starts it.

The portable extension will look for any Service class it can find that is detectable. It will instantiate it and call its update(Routing.Rules) method prior to starting the WebServer.

Why Would I Want To Use This?

You may be thinking: why would I want to put a web server in a CDI container? This is probably because you are thinking of CDI as a component of a Java EE application server. But CDI 2.0 is usable in Java SE.

If you start the CDI container from your own main method like so:

try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
  // deliberately empty
}

...or, equivalently, use the microbean-main project's Main class to do this for you, then a CDI container comes up and goes down. In between all of your CDI beans are instantiated and wired appropriately.

So don't think of a CDI container as something that lives inside a web server or alongside one. Think instead of a web server as just another Java component in the CDI ecosystem.

At this point you can probably see that if Helidon SE is just another component in the CDI ecosystem, and your Service implementations are just another component in the CDI ecosystem, then the CDI container can instantiate and autowire all of them equivalently.

This gives you all the benefits of Helidon SE and all the benefits of CDI at the expense of roughly 50 milliseconds of additional startup time while letting you write a simple Java SE application from a component-oriented perspective.

Simple Example

Suppose you write a Service like this:

import io.helidon.webserver.Service;
import io.helidon.webserver.Routing;
import io.helidon.webserver.ServerRequest;
import io.helidon.webserver.ServerResponse;

@ApplicationScoped
public class MyService implements Service {

  private final SomeClientForSomething client;

  @Inject
  public MyService(final SomeClientForSomething client) {
    super();
    this.client = Objects.requireNonNull(client);
  }

  @Override
  public void update(final Routing.Rules rules) {
    rules.get("/foo", this::handleFoo); // handle GET requests with the handleFoo method
  }
  
  private void handleFoo(final ServerRequest request,
                         final ServerResponse response) {
    // You can use this.client here.
  }

}

The presence of this class on the classpath will cause the CDI container to create an instance of MyService, supply it with an instance of SomeClientForSomething assuming that this bean is present in the CDI container, and call its update method. A Helidon WebServer will then be created and started using default configuration. The webserver will stop when it receives a CTRL-C signal.

Customization

All intermediate objects required to create and start a WebServer are treated as CDI beans as well, with the end user's versions of those beans (if any) being preferred over the built-in defaults. So, for example, if you were to supply your own WebServer producer method, that WebServer instance would be used instead.

If you do nothing, a default Config.Builder will be created to build a Config object. The Config object so built will be used to create a ServerConfiguration.Builder, which, in turn, will be used to build a ServerConfiguration. This general pattern applies all the way up to the WebServer itself (built by a WebServer.Builder).

Each of these objects is treated as a CDI bean. If the CDI bean in question does not exist, then a "normal" instance of the object in question is registered as a bean and instantiated appropriately by the CDI container.

In the case of such default instantiations, you can customize them if you want. For example, maybe you don't want to actually supply an alternate Config implementation—the default one is just fine—but you do want to slightly change how it's made. To perform simple customization of this sort, you declare an observer method that receives the relevant Builder object as its observed parameter. For example, somewhere in your CDI application, you can write:

private static final void customizeConfigBuilder(@Observes final Config.Builder configBuilder) {
  builder.disableSystemPropertiesSource(); // or whatever
}

The Builder so customized will be used internally by this project to produce Config objects (as CDI beans) that may be required by other Helidon objects.

microbean-helidon-webserver-cdi's People

Contributors

ljnelson avatar

Stargazers

 avatar

Watchers

 avatar  avatar

microbean-helidon-webserver-cdi's Issues

Race condition?

The TestBasicScenario test fails every now and again. Some changes I'm making locally added just enough delay somewhere in the mechanism to make this reproducible one time out of about three.

Sample output and stack trace:

INFO] Running org.microbean.helidon.webserver.cdi.TestBasicScenario
Jan 11, 2019 1:14:51 PM org.jboss.weld.bootstrap.WeldStartup <clinit>
INFO: WELD-000900: 3.0.5 (Final)
Jan 11, 2019 1:14:51 PM org.hibernate.validator.internal.util.Version <clinit>
INFO: HV000001: Hibernate Validator 6.0.13.Final
Jan 11, 2019 1:14:52 PM org.jboss.weld.environment.deployment.discovery.DiscoveryStrategyFactory create
INFO: WELD-ENV-000020: Using jandex for bean discovery
Jan 11, 2019 1:14:52 PM org.jboss.weld.bootstrap.MissingDependenciesRegistry handleResourceLoadingException
INFO: WELD-000119: Not generating any bean definitions from org.microbean.jpa.org.hibernate.engine.transaction.jta.platform.CDISEJtaPlatform because of underlying class loading error: Type org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform not found.  If this is unexpected, enable DEBUG logging to see the full error.
Jan 11, 2019 1:14:53 PM org.jboss.weld.environment.se.WeldContainer fireContainerInitializedEvent
INFO: WELD-ENV-002003: Weld SE container bc9317d1-3d3a-4a82-91e9-14e284244ccc initialized
*** HelidonWebServerExtension onStartup fired
*** initializing serviceBean
[EL Info]: 2019-01-11 13:14:54.054--ServerSession(2066366456)--EclipseLink, version: Eclipse Persistence Services - 2.7.2.v20180622-f627448
Jan 11, 2019 1:14:54 PM com.zaxxer.hikari.HikariDataSource <init>
INFO: test - Starting...
Jan 11, 2019 1:14:54 PM com.zaxxer.hikari.HikariDataSource <init>
INFO: test - Start completed.
[EL Info]: 2019-01-11 13:14:54.381--ServerSession(2066366456)--/file:/Users/LANELSON/Projects/github/microbean/microbean-helidon-webserver-cdi/target/_test login successful
[EL Warning]: 2019-01-11 13:14:54.417--The collection of metamodel types is empty. Model classes may not have been found during entity search for Java SE and some Java EE container managed persistence units.  Please verify that your entity classes are referenced in persistence.xml using either <class> elements or a global <exclude-unlisted-classes>false</exclude-unlisted-classes> element
*** serviceBean initialized
Jan 11, 2019 1:14:55 PM io.netty.util.internal.logging.Slf4JLogger info
INFO: Your platform does not provide complete low-level API for accessing direct buffers reliably. Unless explicitly requested, heap buffer will always be preferred to avoid potential system instability.
*** test onStartup fired
Jan 11, 2019 1:14:55 PM io.helidon.webserver.netty.NettyWebServer lambda$start$7
INFO: Channel '@default' started: [id: 0xe2d7a600, L:/0:0:0:0:0:0:0:0:50290]
Jan 11, 2019 1:14:55 PM io.helidon.webserver.netty.NettyWebServer lambda$start$5
INFO: Channel '@default' closed: [id: 0xe2d7a600, L:/0:0:0:0:0:0:0:0:50290]
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 3.839 s <<< FAILURE! - in org.microbean.helidon.webserver.cdi.TestBasicScenario
[ERROR] test(org.microbean.helidon.webserver.cdi.TestBasicScenario)  Time elapsed: 3.796 s  <<< ERROR!
javax.enterprise.event.ObserverException
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at java.lang.Class.newInstance(Class.java:442)
	at org.jboss.weld.security.NewInstanceAction.run(NewInstanceAction.java:33)
	at java.security.AccessController.doPrivileged(Native Method)
	at org.jboss.weld.injection.Exceptions.rethrowException(Exceptions.java:40)
	at org.jboss.weld.injection.Exceptions.rethrowException(Exceptions.java:78)
	at org.jboss.weld.injection.StaticMethodInjectionPoint.invoke(StaticMethodInjectionPoint.java:103)
	at org.jboss.weld.injection.StaticMethodInjectionPoint.invoke(StaticMethodInjectionPoint.java:85)
	at org.jboss.weld.injection.MethodInvocationStrategy$DefaultMethodInvocationStrategy.invoke(MethodInvocationStrategy.java:109)
	at org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:330)
	at org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:308)
	at org.jboss.weld.event.ObserverMethodImpl.notify(ObserverMethodImpl.java:286)
	at javax.enterprise.inject.spi.ObserverMethod.notify(ObserverMethod.java:124)
	at org.jboss.weld.util.Observers.notify(Observers.java:166)
	at org.jboss.weld.event.ObserverNotifier.notifySyncObservers(ObserverNotifier.java:285)
	at org.jboss.weld.event.ObserverNotifier.notify(ObserverNotifier.java:273)
	at org.jboss.weld.event.ObserverNotifier.fireEvent(ObserverNotifier.java:177)
	at org.jboss.weld.event.ObserverNotifier.fireEvent(ObserverNotifier.java:159)
	at org.jboss.weld.manager.BeanManagerImpl.fireEvent(BeanManagerImpl.java:632)
	at org.jboss.weld.environment.se.WeldContainer.fireContainerInitializedEvent(WeldContainer.java:236)
	at org.jboss.weld.environment.se.WeldContainer.endInitialization(WeldContainer.java:188)
	at org.jboss.weld.environment.se.Weld.initialize(Weld.java:803)
	at org.jboss.weld.environment.se.Weld.initialize(Weld.java:176)
	at org.microbean.helidon.webserver.cdi.TestBasicScenario.startCdiContainer(TestBasicScenario.java:80)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:365)
	at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:273)
	at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:238)
	at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:159)
	at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:384)
	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:345)
	at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:126)
	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:418)
Caused by: java.io.FileNotFoundException: http://0.0.0.0:50290/hoopy
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1890)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492)
	at java.net.URLConnection.getContent(URLConnection.java:739)
	at java.net.URL.getContent(URL.java:1059)
	at org.microbean.helidon.webserver.cdi.TestBasicScenario.onStartup(TestBasicScenario.java:118)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.jboss.weld.injection.StaticMethodInjectionPoint.invoke(StaticMethodInjectionPoint.java:95)
	... 43 more

This test deliberately brings in a couple of other extensions but is reflective of real-world usage.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.