Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restart support for CDI regardless of mode used. #1613

Merged
merged 1 commit into from
Apr 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -30,6 +30,7 @@
final class ContainerInstanceHolder {
private static final AtomicReference<HelidonContainer> CONTAINER = new AtomicReference<>();
private static final List<Runnable> RESET_LISTENERS = new LinkedList<>();
private static boolean isReset = false;

private ContainerInstanceHolder() {
}
Expand All @@ -38,7 +39,12 @@ static void set(HelidonContainer container) {
CONTAINER.set(container);
}

static HelidonContainer get() {
// return true if the container was reset, indicating somebody started CDI by hand and then shut it down
static synchronized boolean isReset() {
return isReset;
}
danielkec marked this conversation as resolved.
Show resolved Hide resolved

static synchronized HelidonContainer get() {
HelidonContainer helidonContainer = CONTAINER.get();
if (null == helidonContainer) {
helidonContainer = fromBuildTimeInitializer();
Expand All @@ -57,6 +63,7 @@ static synchronized void addListener(Runnable runnable) {
}

static synchronized void reset() {
isReset = true;
CONTAINER.set(null);
for (Runnable resetListener : RESET_LISTENERS) {
resetListener.run();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.helidon.microprofile.cdi;

import java.util.concurrent.atomic.AtomicReference;

import javax.enterprise.inject.spi.CDI;
import javax.enterprise.inject.spi.CDIProvider;

class HelidonCdiProvider implements CDIProvider {
private static final AtomicReference<CDI<Object>> CURRENT_CDI = new AtomicReference<>();

@Override
public CDI<Object> getCDI() {
return CURRENT_CDI.get();
}

static void setCdi(CDI<Object> cdi) {
CURRENT_CDI.set(cdi);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ final class HelidonContainerImpl extends Weld implements HelidonContainer {
.ifPresent(contextBuilder::parent);

ROOT_CONTEXT = contextBuilder.build();

CDI.setCDIProvider(new HelidonCdiProvider());
}

private final WeldBootstrap bootstrap;
Expand Down Expand Up @@ -198,7 +200,7 @@ public Collection<URL> getResources(String name) {
bootstrap.deployBeans();

cdi = new HelidonCdi(id, bootstrap, deployment);
CDI.setCDIProvider(() -> cdi);
HelidonCdiProvider.setCdi(cdi);

beanManager.getEvent().select(BuildTimeEnd.Literal.INSTANCE).fire(id);

Expand Down Expand Up @@ -251,7 +253,15 @@ private HelidonContainerImpl doStart() {

IN_RUNTIME.set(true);

BeanManager bm = CDI.current().getBeanManager();
BeanManager bm = null;
try {
bm = CDI.current().getBeanManager();
} catch (IllegalStateException e) {
LOGGER.log(Level.FINEST, "Cannot get current CDI, probably restarted", e);
// cannot access CDI - CDI is not yet initialized (probably shut down and started again)
initInContext();
bm = CDI.current().getBeanManager();
}

Config config = (Config) ConfigProvider.getConfig();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,77 +58,92 @@ public HelidonContainerInitializer() {

@Override
public SeContainerInitializer addBeanClasses(Class<?>... classes) {
return container.addBeanClasses(classes);
container.addBeanClasses(classes);
return this;
}

@Override
public SeContainerInitializer addPackages(Class<?>... packageClasses) {
return container.addPackages(packageClasses);
container.addPackages(packageClasses);
return this;
}

@Override
public SeContainerInitializer addPackages(boolean scanRecursively, Class<?>... packageClasses) {
return container.addPackages(scanRecursively, packageClasses);
container.addPackages(scanRecursively, packageClasses);
return this;
}

@Override
public SeContainerInitializer addPackages(Package... packages) {
return container.addPackages(packages);
container.addPackages(packages);
return this;
}

@Override
public SeContainerInitializer addPackages(boolean scanRecursively, Package... packages) {
return container.addPackages(scanRecursively, packages);
container.addPackages(scanRecursively, packages);
return this;
}

@Override
public SeContainerInitializer addExtensions(Extension... extensions) {
return container.addExtensions(extensions);
container.addExtensions(extensions);
return this;
}

@Override
public SeContainerInitializer addExtensions(Class<? extends Extension>... extensions) {
return container.addExtensions(extensions);
container.addExtensions(extensions);
return this;
}

@Override
public SeContainerInitializer enableInterceptors(Class<?>... interceptorClasses) {
return container.enableDecorators(interceptorClasses);
container.enableDecorators(interceptorClasses);
return this;
}

@Override
public SeContainerInitializer enableDecorators(Class<?>... decoratorClasses) {
return container.enableDecorators(decoratorClasses);
container.enableDecorators(decoratorClasses);
return this;
}

@Override
public SeContainerInitializer selectAlternatives(Class<?>... alternativeClasses) {
return container.selectAlternatives(alternativeClasses);
container.selectAlternatives(alternativeClasses);
return this;
}

@Override
public SeContainerInitializer selectAlternativeStereotypes(Class<? extends Annotation>... alternativeStereotypeClasses) {
return container.selectAlternativeStereotypes(alternativeStereotypeClasses);
container.selectAlternativeStereotypes(alternativeStereotypeClasses);
return this;
}

@Override
public SeContainerInitializer addProperty(String key, Object value) {
return container.addProperty(key, value);
container.addProperty(key, value);
return this;
}

@Override
public SeContainerInitializer setProperties(Map<String, Object> properties) {
return container.setProperties(properties);
container.setProperties(properties);
return this;
}

@Override
public SeContainerInitializer disableDiscovery() {
return container.disableDiscovery();
container.disableDiscovery();
return this;
}

@Override
public SeContainerInitializer setClassLoader(ClassLoader classLoader) {
return container.setClassLoader(classLoader);
container.setClassLoader(classLoader);
return this;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -46,6 +46,8 @@ public final class Main {
CONTAINER = ContainerInstanceHolder.get();
}

private static HelidonContainer inUse;

private Main() {
}

Expand All @@ -58,13 +60,21 @@ private Main() {
* @param args command line arguments, currently ignored
*/
public static void main(String[] args) {
CONTAINER.start();
if (ContainerInstanceHolder.isReset()) {
// in case somebody restarted the container, we need to get a new one
inUse = ContainerInstanceHolder.get();
} else {
// use the statically initialized one
inUse = CONTAINER;
}

inUse.start();
danielkec marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Shutdown CDI container.
*/
public static void shutdown() {
CONTAINER.shutdown();
inUse.shutdown();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,17 @@

import java.util.Map;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.se.SeContainer;
import javax.enterprise.inject.se.SeContainerInitializer;
import javax.enterprise.inject.spi.CDI;

import io.helidon.config.Config;
import io.helidon.config.ConfigSources;

import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static org.hamcrest.CoreMatchers.instanceOf;
Expand All @@ -34,14 +39,85 @@
* Unit test for {@link HelidonContainerInitializer}.
*/
class HelidonContainerInitializerTest {
private static ConfigProviderResolver configResolver;
private static ClassLoader cl;
private static org.eclipse.microprofile.config.Config defaultConfig;

@BeforeAll
static void initClass() {
configResolver = ConfigProviderResolver.instance();
cl = Thread.currentThread().getContextClassLoader();
defaultConfig = configResolver.getBuilder().build();
}

@AfterEach
void resetConfig() {
// restore the config to default
configResolver.registerConfig(defaultConfig, cl);
}

@Test
void testRestart() {
// this is a reproducer for bug 1554
Config config = Config.create(ConfigSources.create(Map.of(HelidonContainerInitializer.CONFIG_ALLOW_INITIALIZER, "true")));
configResolver.registerConfig((org.eclipse.microprofile.config.Config) config, cl);
// now we can start using SeContainerInitializer
SeContainer container = SeContainerInitializer.newInstance()
.disableDiscovery()
.addBeanClasses(TestBean.class)
.initialize();

container.close();

try {
Main.main(new String[0]);
} finally {
Main.shutdown();
}
}

@Test
void testRestart2() {
// this is a reproducer for bug 1554
Config config = Config.create(ConfigSources.create(Map.of(HelidonContainerInitializer.CONFIG_ALLOW_INITIALIZER, "true")));
configResolver.registerConfig((org.eclipse.microprofile.config.Config) config, cl);
// now we can start using SeContainerInitializer
SeContainerInitializer seContainerInitializer = SeContainerInitializer.newInstance();
assertThat(seContainerInitializer, instanceOf(HelidonContainerInitializer.class));
seContainerInitializer
.disableDiscovery()
.addBeanClasses(TestBean.class)
.initialize();

((SeContainer) CDI.current()).close();

try {
Main.main(new String[0]);
} finally {
Main.shutdown();
}
}

@Test
void testSeInitializerFails() {

assertThrows(IllegalStateException.class, SeContainerInitializer::newInstance);

Config config = Config.create(ConfigSources.create(Map.of(HelidonContainerInitializer.CONFIG_ALLOW_INITIALIZER, "true")));
ConfigProviderResolver.instance().registerConfig((org.eclipse.microprofile.config.Config) config, Thread.currentThread().getContextClassLoader());
configResolver.registerConfig((org.eclipse.microprofile.config.Config) config, cl);

SeContainerInitializer seContainerInitializer = SeContainerInitializer.newInstance();
assertThat(seContainerInitializer, instanceOf(HelidonContainerInitializer.class));
seContainerInitializer.initialize().close();

try (SeContainer container = seContainerInitializer.initialize()) {
// do nothing
}
}

@ApplicationScoped
public static class TestBean {
public String test() {
return "test";
}
}
}