Skip to content

Commit

Permalink
Lets unit tests validating JpaExtension and unit tests validating Per…
Browse files Browse the repository at this point in the history
…sistenceExtension run side-by-side; continuation of overall fix for nested transaction problems (helidon-io#7118)

* Lets unit tests validating JpaExtension and unit tests validating PersistenceExtension run side-by-side; continuation of overall fix for nested transaction problems

Signed-off-by: Laird Nelson <laird.nelson@oracle.com>
  • Loading branch information
ljnelson authored Jul 13, 2023
1 parent 49a85da commit 096217b
Show file tree
Hide file tree
Showing 17 changed files with 2,886 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
import jakarta.enterprise.inject.spi.BeforeBeanDiscovery;
import jakarta.enterprise.inject.spi.Extension;
import jakarta.enterprise.inject.spi.ProcessAnnotatedType;
import jakarta.enterprise.inject.spi.ProcessBeanAttributes;
import jakarta.enterprise.inject.spi.ProcessInjectionPoint;
import jakarta.enterprise.inject.spi.WithAnnotations;
import jakarta.enterprise.inject.spi.configurator.AnnotatedFieldConfigurator;
Expand Down Expand Up @@ -150,6 +151,8 @@ public final class PersistenceExtension implements Extension {

private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];

private static final Logger LOGGER = Logger.getLogger(PersistenceExtension.class.getName());


/*
* Instance fields.
Expand Down Expand Up @@ -298,6 +301,31 @@ private <T> void makePersistencePropertyARepeatableQualifier(@Observes BeforeBea
event.addQualifier(PersistenceProperty.class);
}

/**
* {@linkplain ProcessBeanAttributes#veto() Vetoes} any bean whose bean types includes the deprecated {@link
* JtaDataSourceProvider} class, since it is replaced by {@link JtaAdaptingDataSourceProvider}.
*
* @param event the {@link ProcessBeanAttributes} event in question; must not be {@code null}
*
* @exception NullPointerException if {@code event} is {@code null}
*
* @see JtaAdaptingDataSourceProvider
*/
private void vetoDeprecatedJtaDataSourceProvider(@Observes ProcessBeanAttributes<JtaDataSourceProvider> event) {
if (!this.enabled) {
return;
}
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.logp(Level.FINE, this.getClass().getName(), "vetoDeprecatedJtaDataSourceProvider",
"Vetoing BeanAttributes {0} representing "
+ JtaDataSourceProvider.class
+ " because it is deprecated and "
+ JtaAdaptingDataSourceProvider.class
+ " replaces it", event.getBeanAttributes());
}
event.veto();
}

private <T> void rewriteJpaAnnotations(@Observes
@WithAnnotations({PersistenceContext.class, PersistenceUnit.class})
ProcessAnnotatedType<T> event) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Copyright (c) 2023 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.integrations.cdi.jpa;

import jakarta.annotation.sql.DataSourceDefinition;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.Dependent;
import jakarta.enterprise.inject.se.SeContainer;
import jakarta.enterprise.inject.se.SeContainerInitializer;
import jakarta.enterprise.inject.Instance;
import jakarta.enterprise.inject.Produces;
import jakarta.inject.Inject;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.fail;

class TestPersistenceExtension {

private SeContainer sec;

private TestPersistenceExtension() {
super();
}

@BeforeEach
@SuppressWarnings("unchecked")
final void initializeCdiContainer() {
System.setProperty(JpaExtension.class.getName() + ".enabled", "false");
System.setProperty(PersistenceExtension.class.getName() + ".enabled", "true");
Class<?> cdiSeJtaPlatformClass;
try {
// Load it dynamically because Hibernate won't be on the classpath when we're testing with Eclipselink
cdiSeJtaPlatformClass =
Class.forName("io.helidon.integrations.cdi.hibernate.CDISEJtaPlatform",
false,
Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException e) {
cdiSeJtaPlatformClass = null;
}
SeContainerInitializer i = SeContainerInitializer.newInstance()
.disableDiscovery()
.addExtensions(PersistenceExtension.class,
com.arjuna.ats.jta.cdi.TransactionExtension.class,
io.helidon.integrations.datasource.hikaricp.cdi.HikariCPBackedDataSourceExtension.class)
.addBeanClasses(Caturgiator.class,
Frobnicator.class);
if (cdiSeJtaPlatformClass != null) {
i = i.addBeanClasses(cdiSeJtaPlatformClass);
}
this.sec = i.initialize();
}

@AfterEach
final void closeCdiContainer() {
if (this.sec != null) {
this.sec.close();
}
System.setProperty(PersistenceExtension.class.getName() + ".enabled", "false");
System.setProperty(JpaExtension.class.getName() + ".enabled", "true");
}

// @Disabled
@Test
final void testSpike() {
Instance<Frobnicator> fi = sec.select(Frobnicator.class);
Frobnicator f = fi.get();
assertThat(f.em.isOpen(), is(true));
assertThat(f.em, instanceOf(JtaEntityManager.class));

Instance<Caturgiator> ci = sec.select(Caturgiator.class);
Caturgiator c = ci.get();
assertThat(c.em, is(f.em));

fi.destroy(f);
assertThat(c.em.isOpen(), is(true));
ci.destroy(c);
}

@DataSourceDefinition(
name = "test",
className = "org.h2.jdbcx.JdbcDataSource",
url = "jdbc:h2:mem:TestPersistenceExtension",
serverName = "",
properties = {
"user=sa"
}
)
@Dependent
private static class Frobnicator {

@PersistenceContext(unitName = "test")
private EntityManager em;

@Inject
Frobnicator() {
super();
}

}

@Dependent
private static class Caturgiator {

@PersistenceContext(unitName = "test")
private EntityManager em;

@Inject
Caturgiator() {
super();
}

}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2022 Oracle and/or its affiliates.
* Copyright (c) 2019, 2023 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 @@ -95,6 +95,7 @@ public class Microblog implements Serializable {
mappedBy = "microblog",
targetEntity = Chirp.class
)
@SuppressWarnings("serial")
private List<Chirp> chirps;

@Deprecated
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright (c) 2023 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.integrations.cdi.jpa.chirp2;

import java.io.Serializable;
import java.util.Objects;

import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Basic;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Access(value = AccessType.FIELD)
@Entity(name = "Author")
@Table(name = "AUTHOR")
public class Author implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@Column(name = "ID",
insertable = true,
nullable = false,
updatable = false)
Integer id;

@Basic(optional = false)
@Column(name = "NAME",
insertable = true,
nullable = false,
unique = true,
updatable = true)
private String name;

@Deprecated
protected Author() {
super();
}

public Author(int id, String name) {
super();
this.id = id;
this.setName(name);
}

public Integer getId() {
return id;
}

public String getName() {
return this.name;
}

public void setName(final String name) {
this.name = Objects.requireNonNull(name);
}

@Override
public int hashCode() {
final Object name = this.getName();
return name == null ? 0 : name.hashCode();
}

@Override
public boolean equals(final Object other) {
if (other == this) {
return true;
} else if (other instanceof Author) {
final Author her = (Author) other;
final Object name = this.getName();
if (name == null) {
if (her.getName() != null) {
return false;
}
} else if (!name.equals(her.getName())) {
return false;
}
return true;
} else {
return false;
}
}

}
Loading

0 comments on commit 096217b

Please sign in to comment.