Skip to content

Commit

Permalink
Ensures that the enabled flag is honored in JpaExtension's observer m…
Browse files Browse the repository at this point in the history
…ethods (helidon-io#8235)

* Ensures that the enabled flag is honored in JpaExtension's observer methods

Signed-off-by: Laird Nelson <laird.nelson@oracle.com>

* Squashable commit; repairs common archetype to call closeAll() on MetricsFactory in an @afterall rule

Signed-off-by: Laird Nelson <laird.nelson@oracle.com>

* Squashable commit; works around what is likely a Weld bug related to Bean metadata creation in certain codepaths

Signed-off-by: Laird Nelson <laird.nelson@oracle.com>

---------

Signed-off-by: Laird Nelson <laird.nelson@oracle.com>
  • Loading branch information
ljnelson committed Jan 14, 2024
1 parent 4802c6b commit 224f99d
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 12 deletions.
10 changes: 5 additions & 5 deletions archetypes/helidon/src/main/archetype/common/observability.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2022, 2023 Oracle and/or its affiliates.
Copyright (c) 2022, 2024 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 @@ -103,14 +103,14 @@ curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics
<value>io.helidon.metrics.api.MetricsFactory</value>
</list>
<list key="MainTest-other-imports">
<value>org.junit.jupiter.api.BeforeAll</value>
<value>org.junit.jupiter.api.AfterAll</value>
</list>
<list key="MainTest-static-imports">
<value>static org.junit.jupiter.api.Assertions.assertEquals</value>
</list>
<list key="MainTest-methods" order="999">
<value><![CDATA[
@BeforeAll
@AfterAll
static void clear() {
MetricsFactory.closeAll();
}
Expand Down Expand Up @@ -199,7 +199,7 @@ curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics
<value>io.helidon.metrics.api.MetricsFactory</value>
</list>
<list key="MainTest-other-imports">
<value>org.junit.jupiter.api.BeforeAll</value>
<value>org.junit.jupiter.api.AfterAll</value>
</list>
<list key="MainTest-static-fields">
<value><![CDATA[
Expand All @@ -208,7 +208,7 @@ curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics
</list>
<list key="MainTest-methods" order="999">
<value><![CDATA[
@BeforeAll
@AfterAll
static void clear() {
MetricsFactory.closeAll();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2023 Oracle and/or its affiliates.
* Copyright (c) 2019, 2024 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 @@ -2049,7 +2049,7 @@ private void onStartup(@Observes
Object event,
@ContainerManaged
Instance<EntityManagerFactory> emfs) {
if (!emfs.isUnsatisfied()) {
if (this.enabled && !emfs.isUnsatisfied()) {
for (EntityManagerFactory emfProxy : emfs) {
// Container-managed EntityManagerFactory instances are client proxies, so we call a business method to
// force "inflation" of the proxied instance. This, in turn, may run DDL and persistence provider
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
* Copyright (c) 2023, 2024 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 @@ -55,7 +55,9 @@

import jakarta.annotation.PreDestroy;
import jakarta.annotation.Priority;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.Dependent;
import jakarta.enterprise.context.Initialized;
import jakarta.enterprise.context.spi.CreationalContext;
import jakarta.enterprise.event.Event;
import jakarta.enterprise.event.Observes;
Expand Down Expand Up @@ -107,6 +109,7 @@
import jakarta.xml.bind.Unmarshaller;

import static jakarta.interceptor.Interceptor.Priority.LIBRARY_AFTER;
import static jakarta.interceptor.Interceptor.Priority.LIBRARY_BEFORE;
import static jakarta.persistence.PersistenceContextType.EXTENDED;
import static jakarta.persistence.SynchronizationType.SYNCHRONIZED;
import static jakarta.persistence.SynchronizationType.UNSYNCHRONIZED;
Expand Down Expand Up @@ -620,6 +623,52 @@ private void addSyntheticBeans(@Observes @Priority(LIBRARY_AFTER) AfterBeanDisco
this.unlistedManagedClassesByUnitNames.clear();
}

// This will take some explaining.
//
// Weld 5.1.2.Final and later has a bug? interesting feature? where if a very, very particular way of acquiring a
// contextual reference is the first such way that Weld encounters, a Bean metadata bean
// (https://jakarta.ee/specifications/cdi/4.0/jakarta-cdi-spec-4.0#bean_metadata) is NOT properly created for the
// acquisition.
//
// This impacts this class because this give-me-the-Bean-metadata facility helps determine what qualifiers are in
// play for any given bean's means of production. See, for example, #produceEntityManagerFactory(Instance) above.
//
// The path to trigger this bug seems to be something like this:
//
// If the first encounter of an injection point is during the initialization of a contextual reference that must
// exist in order for an observer method to be called on it, then it *seems* that in this one case only the
// CreationalContext hierarchy that Weld uses to keep track of which thing is injecting which other thing breaks
// down, and null is returned where really it shouldn't be. See
// https://github.com/weld/core/blob/5.1.1.SP2/impl/src/main/java/org/jboss/weld/bean/builtin/BeanMetadataBean.java#L59.
//
// The following observer method, whose analog also exists in the (now-deprecated, soon to-be-removed) JpaExtension
// class, works around that problem by ensuring that the first encounter of the type (EntityManagerFactory) will
// never meet the criteria outlined above. (It will, in fact, be when emfs.next() is effectively called below.)
//
// This observer method also calls a business method
// (https://jakarta.ee/specifications/cdi/4.0/jakarta-cdi-spec-4.0#biz_method) on each EntityManagerFactory. It
// doesn't matter which one. This will cause the contextual reference's underlying contextual instance to become
// fully initialized. If the user has instructed the EntityManagerFactory to predeploy persistence units, such
// predeployment will happen here as a convenient result.
private void
workAroundWeldBeanMetadataCreationBug(@Observes
@Initialized(ApplicationScoped.class)
@Priority(LIBRARY_BEFORE + 20) // Must be later than metrics CDI extension priority
Object event,
@ContainerManaged
Instance<EntityManagerFactory> emfs) {
if (this.enabled && !emfs.isUnsatisfied()) {
for (EntityManagerFactory emfProxy : emfs) {
// Container-managed EntityManagerFactory instances are client proxies, so we call a business method (it
// doesn't matter which one, so a speedy simple one will suffice) to force "inflation" of the proxied
// instance. This, in turn, may run DDL and persistence provider validation if the persistence provider
// has been configured to do such things early (like Eclipselink with its eclipselink.deploy-on-startup
// property).
emfProxy.isOpen();
}
}
}


/*
* Other instance methods.
Expand Down Expand Up @@ -1305,7 +1354,7 @@ private void addJtaTransactionScopedEntityManagerBeans(AfterBeanDiscovery event,


private static JtaExtendedEntityManager produceJtaExtendedEntityManager(Instance<Object> instance) {
BeanAttributes<JtaExtendedEntityManager> ba = instance.select(BEAN_JTAEXTENDEDENTITYMANAGER_TYPELITERAL).get();
BeanAttributes<?> ba = instance.select(BEAN_JTAEXTENDEDENTITYMANAGER_TYPELITERAL).get();
Set<Annotation> containerManagedSelectionQualifiers = new HashSet<>();
containerManagedSelectionQualifiers.add(ContainerManaged.Literal.INSTANCE);
Set<Annotation> selectionQualifiers = new HashSet<>();
Expand Down Expand Up @@ -1376,7 +1425,7 @@ private static PersistenceUnitInfoBean producePersistenceUnitInfoBean(Instance<O
}

private static EntityManagerFactory produceEntityManagerFactory(Instance<Object> instance) {
BeanAttributes<EntityManagerFactory> ba = instance.select(BEAN_ENTITYMANAGERFACTORY_TYPELITERAL).get();
BeanAttributes<?> ba = instance.select(BEAN_ENTITYMANAGERFACTORY_TYPELITERAL).get();
Set<Annotation> selectionQualifiers = new HashSet<>();
Set<Annotation> namedSelectionQualifiers = new HashSet<>();
for (Annotation beanQualifier: ba.getQualifiers()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2023 Oracle and/or its affiliates.
* Copyright (c) 2019, 2024 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 @@ -77,7 +77,6 @@ class TestAnnotationRewriting {

@BeforeEach
void startCdiContainer() {
System.setProperty("jpaAnnotationRewritingEnabled", "true");
final SeContainerInitializer initializer = SeContainerInitializer.newInstance()
.addBeanClasses(this.getClass());
assertThat(initializer, notNullValue());
Expand Down

0 comments on commit 224f99d

Please sign in to comment.