Skip to content

Commit

Permalink
Virtual Threads: performance impact with Helidon integration fix (pin…
Browse files Browse the repository at this point in the history
…ning threads) (#2181)

Plus new Maven test module to test EclipseLink with Helidon
Skip Helidon tests for <JDK21 - JavaDoc generation

Signed-off-by: Radek Felcman <[email protected]>
rfelcman authored Jul 15, 2024
1 parent 8c0a9ca commit 059428c
Showing 25 changed files with 1,527 additions and 370 deletions.
4 changes: 2 additions & 2 deletions etc/jenkins/pr_verify.groovy
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
@@ -194,7 +194,7 @@ spec:
container('el-build') {
sh """
mvn -B -V clean install -pl :eclipselink -P staging
mvn -B -V verify -pl :org.eclipse.persistence.jpa.modelgen.processor,:org.eclipse.persistence.jpa.jse.test,:org.eclipse.persistence.extension,:org.eclipse.persistence.jpa.jpql,:org.eclipse.persistence.jpa.wdf.test,:org.eclipse.persistence.jpars,:org.eclipse.persistence.dbws,:org.eclipse.persistence.dbws.builder,:eclipselink,:org.eclipse.persistence.distribution.tests -P staging,mysql;
mvn -B -V verify -pl :org.eclipse.persistence.jpa.modelgen.processor,:org.eclipse.persistence.jpa.jse.test,:org.eclipse.persistence.jpa.helidon.test,:org.eclipse.persistence.extension,:org.eclipse.persistence.jpa.jpql,:org.eclipse.persistence.jpa.wdf.test,:org.eclipse.persistence.jpars,:org.eclipse.persistence.dbws,:org.eclipse.persistence.dbws.builder,:eclipselink,:org.eclipse.persistence.distribution.tests -P staging,mysql;
"""
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -24,6 +24,8 @@
import java.util.ListIterator;
import java.util.Spliterator;
import java.util.Vector;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
@@ -98,6 +100,8 @@ public class IndirectList<E> extends Vector<E> implements CollectionChangeTracke
*/
private boolean useLazyInstantiation = true;

private final Lock instanceLock = new ReentrantLock();

/**
* PUBLIC:
* Construct an empty IndirectList so that its internal data array
@@ -350,13 +354,18 @@ public void clearDeferredChanges(){
before merging collections (again, "un-instantiated" collections are not merged).
*/
@Override
public synchronized Object clone() {
IndirectList<E> result = (IndirectList<E>)super.clone();
result.delegate = (Vector<E>)this.getDelegate().clone();
result.valueHolder = new ValueHolder<>(result.delegate);
result.attributeName = null;
result.changeListener = null;
return result;
public Object clone() {
instanceLock.lock();
try {
IndirectList<E> result = (IndirectList<E>)super.clone();
result.delegate = (Vector<E>)this.getDelegate().clone();
result.valueHolder = new ValueHolder<>(result.delegate);
result.attributeName = null;
result.changeListener = null;
return result;
} finally {
instanceLock.unlock();
}
}

/**
@@ -391,8 +400,13 @@ public boolean containsAll(Collection<?> c) {
* @see java.util.Vector#copyInto(java.lang.Object[])
*/
@Override
public synchronized void copyInto(Object[] anArray) {
getDelegate().copyInto(anArray);
public void copyInto(Object[] anArray) {
instanceLock.lock();
try {
getDelegate().copyInto(anArray);
} finally {
instanceLock.unlock();
}
}

/**
@@ -452,11 +466,14 @@ public E get(int index) {
protected Vector<E> getDelegate() {
Vector<E> v = this.delegate;
if (v == null) {
synchronized(this){
instanceLock.lock();
try {
v = this.delegate;
if (v == null) {
this.delegate = v = this.buildDelegate();
}
} finally {
instanceLock.unlock();
}
}
return v;
@@ -482,11 +499,14 @@ public ValueHolderInterface<List<E>> getValueHolder() {
ValueHolderInterface<List<E>> vh = this.valueHolder;
// PERF: lazy initialize value holder and vector as are normally set after creation.
if (vh == null) {
synchronized(this) {
instanceLock.lock();
try {
vh = this.valueHolder;
if (vh == null) {
this.valueHolder = vh = new ValueHolder<>(new Vector<>(this.initialCapacity, this.capacityIncrement));
}
} finally {
instanceLock.unlock();
}
}
return vh;
@@ -877,33 +897,43 @@ public Spliterator<E> spliterator() {
}

@Override
public synchronized void replaceAll(UnaryOperator<E> operator) {
// Must trigger remove/add events if tracked or uow.
if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {
List<E> del = getDelegate();
for (int i = 0; i < del.size(); i++) {
set(i, operator.apply(del.get(i)));
public void replaceAll(UnaryOperator<E> operator) {
instanceLock.lock();
try {
// Must trigger remove/add events if tracked or uow.
if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {
List<E> del = getDelegate();
for (int i = 0; i < del.size(); i++) {
set(i, operator.apply(del.get(i)));
}
} else {
getDelegate().replaceAll(operator);
}
} else {
getDelegate().replaceAll(operator);
} finally {
instanceLock.unlock();
}
}

@Override
public synchronized boolean removeIf(Predicate<? super E> filter) {
// Must trigger remove events if tracked or uow.
if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {
boolean hasChanged = false;
Iterator<E> objects = iterator();
while (objects.hasNext()) {
if (filter.test(objects.next())) {
objects.remove();
hasChanged |= true;
public boolean removeIf(Predicate<? super E> filter) {
instanceLock.lock();
try {
// Must trigger remove events if tracked or uow.
if (hasBeenRegistered() || hasTrackedPropertyChangeListener()) {
boolean hasChanged = false;
Iterator<E> objects = iterator();
while (objects.hasNext()) {
if (filter.test(objects.next())) {
objects.remove();
hasChanged |= true;
}
}
return hasChanged;
}
return hasChanged;
return getDelegate().removeIf(filter);
} finally {
instanceLock.unlock();
}
return getDelegate().removeIf(filter);
}

@Override

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -23,6 +23,8 @@
import java.util.Iterator;
import java.util.Set;
import java.util.Spliterator;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
@@ -118,6 +120,8 @@ public class IndirectSet<E> implements CollectionChangeTracker, Set<E>, Indirect
*/
private boolean useLazyInstantiation = false;

private final Lock instanceLock = new ReentrantLock();

/**
* Construct an empty IndirectSet.
*/
@@ -407,11 +411,14 @@ public void forEach(Consumer<? super E> action) {
protected Set<E> getDelegate() {
Set<E> newDelegate = this.delegate;
if (newDelegate == null) {
synchronized(this){
instanceLock.lock();
try {
newDelegate = this.delegate;
if (newDelegate == null) {
this.delegate = newDelegate = this.buildDelegate();
}
} finally {
instanceLock.unlock();
}
}
return newDelegate;
@@ -437,11 +444,14 @@ public ValueHolderInterface<Set<E>> getValueHolder() {
ValueHolderInterface<Set<E>> vh = this.valueHolder;
// PERF: lazy initialize value holder and vector as are normally set after creation.
if (vh == null) {
synchronized(this){
instanceLock.lock();
try {
vh = this.valueHolder;
if (vh == null) {
this.valueHolder = vh = new ValueHolder<>(new HashSet<>(initialCapacity, loadFactor));
}
} finally {
instanceLock.unlock();
}
}
return vh;
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020 IBM Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
@@ -29,6 +29,9 @@
import org.eclipse.persistence.sessions.SessionProfiler;
import org.eclipse.persistence.sessions.server.ConnectionPool;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* INTERNAL:
* <code>DatasourceAccessor</code> is an abstract implementation
@@ -152,6 +155,8 @@ public abstract class DatasourceAccessor implements Accessor {

protected ConnectionPool pool;

private final Lock instanceLock = new ReentrantLock();

/**
* Default Constructor.
*/
@@ -289,54 +294,64 @@ public void beginTransaction(AbstractSession session) throws DatabaseException {
* Used for load balancing and external pooling.
*/
@Override
public synchronized void decrementCallCount() {
int count = this.callCount;
// Avoid decrementing count if already zero, (failure before increment).
if (count <= 0) {
return;
}
this.callCount--;
if (this.usesExternalConnectionPooling && (!this.isInTransaction) && (currentSession == null || !currentSession.isExclusiveConnectionRequired()) && (count == 1)) {
try {
closeConnection();
} catch (DatabaseException ignore) {
// Don't allow for errors to be masked by disconnect.
public void decrementCallCount() {
instanceLock.lock();
try {
int count = this.callCount;
// Avoid decrementing count if already zero, (failure before increment).
if (count <= 0) {
return;
}
this.callCount--;
if (this.usesExternalConnectionPooling && (!this.isInTransaction) && (currentSession == null || !currentSession.isExclusiveConnectionRequired()) && (count == 1)) {
try {
closeConnection();
} catch (DatabaseException ignore) {
// Don't allow for errors to be masked by disconnect.
}
}
} finally {
instanceLock.unlock();
}
}

/**
* Used for load balancing and external pooling.
*/
@Override
public synchronized void incrementCallCount(AbstractSession session) {
this.callCount++;
public void incrementCallCount(AbstractSession session) {
instanceLock.lock();
try {
this.callCount++;

if (this.callCount == 1) {
// If the login is null, then this accessor has never been connected.
if (this.login == null) {
throw DatabaseException.databaseAccessorNotConnected();
}
if (this.callCount == 1) {
// If the login is null, then this accessor has never been connected.
if (this.login == null) {
throw DatabaseException.databaseAccessorNotConnected();
}

// If the connection is no longer connected, it may have timed out.
if (this.datasourceConnection != null) {
if (shouldCheckConnection && !isConnected()) {
if (this.isInTransaction) {
throw DatabaseException.databaseAccessorNotConnected();
} else {
reconnect(session);
// If the connection is no longer connected, it may have timed out.
if (this.datasourceConnection != null) {
if (shouldCheckConnection && !isConnected()) {
if (this.isInTransaction) {
throw DatabaseException.databaseAccessorNotConnected();
} else {
reconnect(session);
}
}
}
} else {
// If ExternalConnectionPooling is used, the connection can be re-established.
if (this.usesExternalConnectionPooling) {
reconnect(session);
session.postAcquireConnection(this);
currentSession = session;
} else {
throw DatabaseException.databaseAccessorNotConnected();
// If ExternalConnectionPooling is used, the connection can be re-established.
if (this.usesExternalConnectionPooling) {
reconnect(session);
session.postAcquireConnection(this);
currentSession = session;
} else {
throw DatabaseException.databaseAccessorNotConnected();
}
}
}
} finally {
instanceLock.unlock();
}
}

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -25,6 +25,9 @@
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* DatabaseValueHolder wraps a database-stored object and implements
* behavior to access it. The object is read only once from database
@@ -56,6 +59,8 @@ public abstract class DatabaseValueHolder<T> implements WeavedAttributeValueHold
*/
protected boolean isCoordinatedWithProperty = false;

private final Lock instanceLock = new ReentrantLock();

/**
* Default constructor.
*/
@@ -96,7 +101,8 @@ public ValueHolderInterface<?> getWrappedValueHolder() {
public T getValue() {
boolean instantiated = this.isInstantiated;
if (!instantiated) {
synchronized (this) {
instanceLock.lock();
try {
instantiated = this.isInstantiated;
if (!instantiated) {
// The value must be set directly because the setValue can also cause instantiation under UOW.
@@ -105,6 +111,8 @@ public T getValue() {
postInstantiate();
resetFields();
}
} finally {
instanceLock.unlock();
}
}
return value;
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -25,6 +25,9 @@
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
import org.eclipse.persistence.logging.SessionLog;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* A UnitOfWorkValueHolder is put in a clone object.
* It wraps the value holder in the original object to delay
@@ -59,6 +62,8 @@ public abstract class UnitOfWorkValueHolder<T> extends DatabaseValueHolder<T> im
protected String sourceAttributeName;
protected ObjID wrappedValueHolderRemoteID;

private final Lock wrappedValueHolderLock = new ReentrantLock();

protected UnitOfWorkValueHolder() {
super();
}
@@ -146,7 +151,8 @@ protected T instantiateImpl() {
Object value;
// Bug 3835202 - Ensure access to valueholders is thread safe. Several of the methods
// called below are not threadsafe alone.
synchronized (this.wrappedValueHolder) {
wrappedValueHolderLock.lock();
try {
if (this.wrappedValueHolder instanceof DatabaseValueHolder) {
DatabaseValueHolder<T> wrapped = (DatabaseValueHolder<T>)this.wrappedValueHolder;
UnitOfWorkImpl unitOfWork = getUnitOfWork();
@@ -174,6 +180,8 @@ protected T instantiateImpl() {
}
}
value = this.wrappedValueHolder.getValue();
} finally {
wrappedValueHolderLock.unlock();
}
return buildCloneFor(value);
}

Large diffs are not rendered by default.

244 changes: 244 additions & 0 deletions jpa/eclipselink.jpa.helidon.test/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0,
or the Eclipse Distribution License v. 1.0 which is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Contributors:
Oracle - initial API and implementation
-->

<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>

<name>EclipseLink JPA Helidon Test</name>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa.helidon.test</artifactId>
<packaging>jar</packaging>

<parent>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.parent</artifactId>
<version>4.0.4-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<properties>
<mainClass>org.eclipse.persistence.testing.helidon.Main</mainClass>
<!--Properties used for test resources filtering/replacement-->
<!--DB connection properties-->
<dbPlatform>${db.platform}</dbPlatform>
<dbUser>${db.user}</dbUser>
<dbPassword>${db.pwd}</dbPassword>
<driverClass>${db.driver}</driverClass>
<dbURL>${db.url}</dbURL>
<!--Log level-->
<loglevel>${logging.level}</loglevel>

<test-skip-jpa-helidon>${skipTests}</test-skip-jpa-helidon> <!-- Spring 4 is not supported with jakarta.persistence -->
</properties>

<dependencies>
<!--Other modules-->
<!--EclipseLink JPA-->
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa</artifactId>
</dependency>
<!--API dependencies-->
<dependency>
<groupId>jakarta.transaction</groupId>
<artifactId>jakarta.transaction-api</artifactId>
</dependency>
<!--Other libraries dependencies-->
<dependency>
<groupId>io.helidon.microprofile.bundles</groupId>
<artifactId>helidon-microprofile</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.jersey</groupId>
<artifactId>helidon-jersey-client</artifactId>
</dependency>
<!--Test dependencies-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!--JDBC driver (test dependency)-->
<dependency>
<groupId>${db.driver.groupId}</groupId>
<artifactId>${db.driver.artifactId}</artifactId>
<version>${db.driver.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<!--Filtering enables generate/substitute test properties from Maven into *.xml files.-->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<testResources>
<testResource>
<directory>${integration.test.resources.directory}</directory>
<filtering>true</filtering>
</testResource>
</testResources>

<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<skipMain>true</skipMain>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<!-- need javadoc even in normal/short build
for inclusion in binary distribution -->
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<skip>true</skip>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.carlspring.maven</groupId>
<artifactId>derby-maven-plugin</artifactId>
<executions>
<execution>
<id>start-derby</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop-derby</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>helidon-tests</id>
<activation>
<jdk>(21,</jdk>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<skip>false</skip>
</configuration>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<skipMain>false</skipMain>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<workingDirectory>${project.build.directory}/test-run</workingDirectory>
<!--Set system properties required for tests-->
<systemPropertiesFile>${test.properties.file}</systemPropertiesFile>
</configuration>
<executions>
<execution>
<id>test-jpa-helidon</id>
<goals>
<goal>integration-test</goal>
</goals>
<configuration>
<skipTests>${test-skip-jpa-helidon}</skipTests>
<!--Analyze Virtual threads pinning issue
<argLine>-Djdk.tracePinnedThreads=full</argLine>
-->
<reportNameSuffix>test-jpa-helidon</reportNameSuffix>
<includes>
<include>org.eclipse.persistence.testing.helidon.TestMaster</include>
</includes>
</configuration>
</execution>
<execution>
<id>verify-integration-tests</id>
<goals>
<goal>verify</goal>
</goals>
<configuration>
<skip>${integration.test.skip.verify}</skip>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>oracle</id>
<dependencies>
<!--db.platform=org.eclipse.persistence.platform.database.oracle.Oracle23Platform comes from there-->
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.oracle</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
<profile>
<id>test-jpa-helidon</id>
<properties>
<test-skip-jpa-helidon>false</test-skip-jpa-helidon>
</properties>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

// Contributors:
// Oracle - initial API and implementation
package org.eclipse.persistence.testing.helidon;

import java.util.List;

import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.core.Response;

import org.eclipse.persistence.testing.helidon.models.MasterEntity;

import io.helidon.microprofile.server.Server;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class TestMaster {

private static Server server;

@BeforeClass
public static void startServer() throws Exception {
server = Main.startServer();
}

@AfterClass
public static void stopServer() throws Exception {
if (server != null) {
server.stop();
}
}

@Test
public void testMasterOneRest() throws Exception {
Client client = ClientBuilder.newClient();
MasterEntity masterEntity = client
.target("http://localhost:8080/master/one")
.request("application/json")
.get(MasterEntity.class);
assertEquals(1L, masterEntity.getId());
assertEquals("Master 1", masterEntity.getName());
}

@Test
public void testMasterAllRest() throws Exception {
Client client = ClientBuilder.newClient();
List<MasterEntity> masterEntities = client
.target("http://localhost:8080/master/all")
.request("application/json")
.get(List.class);
assertTrue(masterEntities.size() >= 2);
}

@Test
public void testMasterCreateRemoveRest() throws Exception {
Client client = ClientBuilder.newClient();
Response response = client
.target("http://localhost:8080/master/create_remove")
.request("application/json")
.get();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

// Contributors:
// Oracle - initial API and implementation
package org.eclipse.persistence.testing.helidon;

import io.helidon.microprofile.server.Server;

public class Main {

public static void main(String[] args) {
startServer();
}

static Server startServer() {
return Server.builder().retainDiscoveredApplications(true).
build().
start();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

// Contributors:
// Oracle - initial API and implementation
package org.eclipse.persistence.testing.helidon.dao;

import java.util.List;

import jakarta.enterprise.context.Dependent;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;

import org.eclipse.persistence.testing.helidon.models.BaseEntity;

@Dependent
public class BaseDao<T extends BaseEntity> {

private EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("HelidonPu");

public void create(T entity) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
try {
entityManager.getTransaction().begin();
entityManager.persist(entity);
entityManager.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
} finally {
if (entityManager.getTransaction().isActive()) {
entityManager.getTransaction().rollback();
}
entityManager.close();
}
}

public void remove(T entity) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
try {
entityManager.getTransaction().begin();
T entity2 = entityManager.merge(entity);;
entityManager.remove(entity2);
entityManager.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
} finally {
if (entityManager.getTransaction().isActive()) {
entityManager.getTransaction().rollback();
}
entityManager.close();
}
}

public T update(T entity) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
T result = null;
try {
entityManager.getTransaction().begin();
result = entityManager.merge(entity);
entityManager.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
} finally {
if (entityManager.getTransaction().isActive()) {
entityManager.getTransaction().rollback();
}
entityManager.close();
}
return result;
}

public T find(Class<T> clazz, long id) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
try {
return entityManager.find(clazz, id);
} finally {
if (entityManager.getTransaction().isActive()) {
entityManager.getTransaction().rollback();
}
entityManager.close();
}
}

public List<T> findByNamedQuery(String query) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
List<T> result = null;
try {
entityManager.getTransaction().begin();
result = entityManager.createNamedQuery(query).getResultList();
entityManager.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
} finally {
if (entityManager.getTransaction().isActive()) {
entityManager.getTransaction().rollback();
}
entityManager.close();
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

// Contributors:
// Oracle - initial API and implementation
package org.eclipse.persistence.testing.helidon.dao;

import jakarta.enterprise.context.Dependent;

import org.eclipse.persistence.testing.helidon.models.DetailEntity;

@Dependent
public class DetailDao extends BaseDao<DetailEntity> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

// Contributors:
// Oracle - initial API and implementation
package org.eclipse.persistence.testing.helidon.dao;

import jakarta.enterprise.context.Dependent;

import org.eclipse.persistence.testing.helidon.models.MasterEntity;

@Dependent
public class MasterDao extends BaseDao<MasterEntity> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
package org.eclipse.persistence.testing.helidon.models;

import jakarta.persistence.Id;
import jakarta.persistence.MappedSuperclass;

@MappedSuperclass
public class BaseEntity {

@Id
private long id;

public BaseEntity() {
}

public BaseEntity(long id) {
this.id = id;
}

public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
package org.eclipse.persistence.testing.helidon.models;

import jakarta.json.bind.annotation.JsonbTransient;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;

@Entity
@Table(name = "HELIDON_TAB_DETAIL")
public class DetailEntity extends BaseEntity {

private String name;

@ManyToOne()
@JoinColumn(name = "MASTER_ID_FK")
@JsonbTransient
private MasterEntity master;

public DetailEntity() {
}

public DetailEntity(long id) {
super(id);
}

public DetailEntity(long id, String name) {
super(id);
this.name = name;
}

public String getName() {
return name;
}

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

public MasterEntity getMaster() {
return master;
}

public void setMaster(MasterEntity master) {
this.master = master;
}

@Override
public String toString() {
return "DetailEntity{" +
"id='" + getId() + '\'' +
"name='" + name + '\'' +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

// Contributors:
// Oracle - initial API and implementation
package org.eclipse.persistence.testing.helidon.models;

import jakarta.persistence.Entity;
import jakarta.persistence.NamedQueries;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Entity
@Table(name = "HELIDON_TAB_MASTER")
@NamedQueries({
@NamedQuery(name = "MasterEntity.findAll", query = "SELECT e FROM MasterEntity e"),
})
public class MasterEntity extends BaseEntity {

private String name;

@OneToMany(mappedBy = "master")
private List<DetailEntity> details = new ArrayList<>();

public MasterEntity() {
}

public MasterEntity(long id) {
super(id);
}

public MasterEntity(long id, String name) {
super(id);
this.name = name;
}

public String getName() {
return name;
}

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

public List<DetailEntity> getDetails() {
return details;
}

public void setDetails(List<DetailEntity> details) {
this.details = details;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MasterEntity that = (MasterEntity) o;
return getId() == that.getId() && Objects.equals(name, that.name) && Objects.equals(details, that.details);
}

@Override
public int hashCode() {
return Objects.hash(getId(), name, details);
}

@Override
public String toString() {
return "MasterEntity{" +
"id='" + getId() + '\'' +
"name='" + name + '\'' +
", details=" + details +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

// Contributors:
// Oracle - initial API and implementation
package org.eclipse.persistence.testing.helidon.provider;

import java.util.List;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import org.eclipse.persistence.testing.helidon.dao.MasterDao;
import org.eclipse.persistence.testing.helidon.models.MasterEntity;

@ApplicationScoped
public class MasterProvider {

@Inject
private MasterDao masterDao;

public MasterEntity getMasterOne() {
MasterEntity masterEntity = masterDao.find(MasterEntity.class, 1L);
return masterEntity;
}

public List<MasterEntity> getMasterAll() {
List<MasterEntity> masterEntities = masterDao.findByNamedQuery("MasterEntity.findAll");
return masterEntities;
}

public void createRemove() {
MasterEntity masterEntity = new MasterEntity(3L, "Master 3");
masterDao.create(masterEntity);
masterDao.remove(masterEntity);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

// Contributors:
// Oracle - initial API and implementation
package org.eclipse.persistence.testing.helidon.resource;

import java.util.List;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

import org.eclipse.persistence.testing.helidon.models.MasterEntity;
import org.eclipse.persistence.testing.helidon.provider.MasterProvider;

@Path("/master")
public class MasterResource {

@Inject
MasterProvider masterProvider;

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("one")
public MasterEntity masterOne() {
return masterProvider.getMasterOne();
}

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("all")
public List<MasterEntity> masterAll() {
return masterProvider.getMasterAll();
}

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("create_remove")
public void createRemove() {
masterProvider.createRemove();;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0,
or the Eclipse Distribution License v. 1.0 which is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Contributors:
Oracle - initial API and implementation
-->
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemalocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/beans_3_0.xsd"
version="3.0"
bean-discovery-mode="annotated">
</beans>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#
# Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0,
# or the Eclipse Distribution License v. 1.0 which is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
# Contributors:
# Oracle - initial API and implementation

# Microprofile server properties
server.port=8080
server.host=0.0.0.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!--
Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0,
or the Eclipse Distribution License v. 1.0 which is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
Contributors:
Oracle - initial API and implementation
-->
<persistence xmlns="https://jakarta.ee/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd" version="3.0">

<persistence-unit name="HelidonPu" transaction-type="RESOURCE_LOCAL">
<class>org.eclipse.persistence.testing.helidon.models.MasterEntity</class>
<class>org.eclipse.persistence.testing.helidon.models.DetailEntity</class>
<properties>
<property name="jakarta.persistence.jdbc.driver" value="@driverClass@" />
<property name="jakarta.persistence.jdbc.url" value="@dbURL@" />
<property name="jakarta.persistence.jdbc.user" value="@dbUser@" />
<property name="jakarta.persistence.jdbc.password" value="@dbPassword@" />
<!--property name="eclipselink.logging.level" value="FINE"/-->
<!-- <property name="eclipselink.ddl-generation" value="drop-and-create-tables" />-->
<property name="jakarta.persistence.sql-load-script-source" value="META-INF/sql/init.sql"/>
</properties>
</persistence-unit>

</persistence>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--
-- Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
--
-- This program and the accompanying materials are made available under the
-- terms of the Eclipse Public License v. 2.0 which is available at
-- http://www.eclipse.org/legal/epl-2.0,
-- or the Eclipse Distribution License v. 1.0 which is available at
-- http://www.eclipse.org/org/documents/edl-v10.php.
--
-- SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
--
-- Contributors:
-- Oracle - initial API and implementation

DROP TABLE HELIDON_TAB_DETAIL
DROP TABLE HELIDON_TAB_MASTER
CREATE TABLE HELIDON_TAB_MASTER (ID INTEGER PRIMARY KEY, NAME VARCHAR(200))
CREATE TABLE HELIDON_TAB_DETAIL (ID INTEGER PRIMARY KEY, MASTER_ID_FK INTEGER, NAME VARCHAR(200))
ALTER TABLE HELIDON_TAB_DETAIL ADD CONSTRAINT TEST_TAB_FK_DETAIL FOREIGN KEY ( MASTER_ID_FK ) REFERENCES HELIDON_TAB_MASTER (ID)

INSERT INTO HELIDON_TAB_MASTER (ID, NAME)VALUES (1, 'Master 1')
INSERT INTO HELIDON_TAB_MASTER (ID, NAME)VALUES (2, 'Master 2')
INSERT INTO HELIDON_TAB_DETAIL (ID, MASTER_ID_FK, NAME)VALUES (101, 1, 'Detail 101')
INSERT INTO HELIDON_TAB_DETAIL (ID, MASTER_ID_FK, NAME)VALUES (102, 1, 'Detail 102')
INSERT INTO HELIDON_TAB_DETAIL (ID, MASTER_ID_FK, NAME)VALUES (201, 2, 'Detail 201')
INSERT INTO HELIDON_TAB_DETAIL (ID, MASTER_ID_FK, NAME)VALUES (202, 2, 'Detail 202')
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2021 IBM Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
@@ -36,6 +36,8 @@
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import jakarta.persistence.Cache;
import jakarta.persistence.EntityGraph;
@@ -152,6 +154,8 @@ public class EntityManagerFactoryDelegate implements EntityManagerFactory, Persi
/** Pointer to the EntityManagerFactoryImpl that created me */
protected JpaEntityManagerFactory owner = null;

private final Lock instanceLock = new ReentrantLock();

/**
* Will return an instance of the Factory. Should only be called by
* EclipseLink.
@@ -208,7 +212,8 @@ public DatabaseSessionImpl getDatabaseSession() {
public AbstractSession getAbstractSession() {
if (this.session == null) {
// PERF: Avoid synchronization.
synchronized (this) {
instanceLock.lock();
try {
// DCL ok as isLoggedIn is volatile boolean, set after login is
// complete.
if (this.session == null) {
@@ -230,6 +235,8 @@ public AbstractSession getAbstractSession() {
processProperties(propertiesToProcess);
this.session = tempSession;
}
} finally {
instanceLock.unlock();
}
}
return this.session;
@@ -274,18 +281,23 @@ public SessionBroker getSessionBroker() {
* will return <code>false</code>.
*/
@Override
public synchronized void close() {
verifyOpen();
isOpen = false;
// Do not invalidate the metaModel field
// (a reopened emf will re-populate the same metaModel)
// (a new persistence unit will generate a new metaModel)
if (setupImpl != null) {
// 260511 null check so that closing a EM
// created from the constructor no longer throws a NPE
setupImpl.undeploy();
public void close() {
instanceLock.lock();
try {
verifyOpen();
isOpen = false;
// Do not invalidate the metaModel field
// (a reopened emf will re-populate the same metaModel)
// (a new persistence unit will generate a new metaModel)
if (setupImpl != null) {
// 260511 null check so that closing a EM
// created from the constructor no longer throws a NPE
setupImpl.undeploy();
}
owner = null;
} finally {
instanceLock.unlock();
}
owner = null;
}

/**
17 changes: 15 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2019, 2023 Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0 which is available at
@@ -205,7 +205,8 @@
<jaxb.version>4.0.5</jaxb.version>
<jaxb.api.version>4.0.2</jaxb.api.version>
<soap.api.version>3.0.2</soap.api.version>
<jersey.version>3.1.6</jersey.version>
<helidon.version>4.0.10</helidon.version>
<jersey.version>3.1.7</jersey.version>
<jms.version>3.1.0</jms.version>
<json.version>2.1.3</json.version>
<jpa.api.version>3.1.0</jpa.api.version>
@@ -918,6 +919,16 @@
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.microprofile.bundles</groupId>
<artifactId>helidon-microprofile</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.jersey</groupId>
<artifactId>helidon-jersey-client</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>jakarta.el</groupId>
<artifactId>jakarta.el-api</artifactId>
@@ -2164,6 +2175,8 @@
<module>jpa/eclipselink.jpa.test</module>
<!--JPA JSE test module-->
<module>jpa/eclipselink.jpa.test.jse</module>
<!--JPA Helidon test module-->
<module>jpa/eclipselink.jpa.helidon.test</module>
<!--JPA Spring test module-->
<module>jpa/eclipselink.jpa.spring.test</module>
<!--JPA WDF test module-->

0 comments on commit 059428c

Please sign in to comment.