Skip to content

Commit

Permalink
Adds integrations for pseudo-XA datasources (#3089)
Browse files Browse the repository at this point in the history
Signed-off-by: Laird Nelson <laird.nelson@oracle.com>
  • Loading branch information
ljnelson authored Oct 15, 2021
1 parent 1a6113e commit b68ef5b
Show file tree
Hide file tree
Showing 20 changed files with 627 additions and 250 deletions.
10 changes: 10 additions & 0 deletions bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,16 @@
<artifactId>helidon-integrations-common-rest</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.integrations.jdbc</groupId>
<artifactId>helidon-integrations-jdbc</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.integrations.jta</groupId>
<artifactId>helidon-integrations-jta-jdbc</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.integrations.micrometer</groupId>
<artifactId>helidon-integrations-micrometer</artifactId>
Expand Down
5 changes: 5 additions & 0 deletions integrations/cdi/jpa-cdi/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@
<artifactId>helidon-integrations-cdi-reference-counted-context</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.helidon.integrations.jta</groupId>
<artifactId>helidon-integrations-jta-jdbc</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>

<build>
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, 2021 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 All @@ -19,6 +19,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.BeforeDestroyed;
Expand All @@ -30,11 +31,18 @@
import javax.inject.Named;
import javax.sql.DataSource;
import javax.sql.XADataSource;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.TransactionScoped;
import javax.transaction.TransactionSynchronizationRegistry;
import javax.transaction.xa.XAResource;

import io.helidon.integrations.jta.jdbc.JtaDataSource;
import io.helidon.integrations.jta.jdbc.XADataSourceWrappingDataSource;

@ApplicationScoped
class JtaDataSourceProvider implements PersistenceUnitInfoBean.DataSourceProvider {
Expand Down Expand Up @@ -85,31 +93,31 @@ class JtaDataSourceProvider implements PersistenceUnitInfoBean.DataSourceProvide
private final TransactionSynchronizationRegistry tsr;

/**
* A thread-safe {@link Map} (usually a {@link ConcurrentHashMap})
* A {@link ConcurrentMap} (usually a {@link ConcurrentHashMap})
* that stores {@link JtaDataSource} instances under their names.
*
* <p>This field is never {@code null}.</p>
*
* <h2>Design Notes</h2>
*
* <p>{@link DataSource} instances used by instances of this class
* are normally CDI contextual references, so are client proxies.
* Per the specification, a client proxy's {@link
* are normally CDI contextual references, so are often client
* proxies. Per the specification, a client proxy's {@link
* Object#equals(Object)} and {@link Object#hashCode()} methods do
* not behave in such a way that their underlying contextual
* instances can be tested for equality. When these {@link
* DataSource}s are wrapped by {@link JtaDataSource} instances, we
* need to ensure that the same {@link JtaDataSource} is handed
* out each time a given data source name is supplied. This
* {@link Map} provides those semantics.</p>
* {@link ConcurrentMap} provides those semantics.</p>
*
* @see JtaDataSource
*
* @see <a
* href="https://jakarta.ee/specifications/cdi/2.0/cdi-spec-2.0.html#client_proxy_invocation">section
* 5.4.1 of the CDI 2.0 specification</a>
*/
private final Map<String, DataSource> dataSourcesByName;
private final ConcurrentMap<String, DataSource> dataSourcesByName;


/*
Expand Down Expand Up @@ -260,13 +268,32 @@ private DataSource convert(final XADataSource xaDataSource, final boolean jta, f
throws SQLException {
Objects.requireNonNull(xaDataSource);
final DataSource returnValue =
this.dataSourcesByName.computeIfAbsent(dataSourceName == null ? NULL_DATASOURCE_NAME : dataSourceName,
ignoredKey -> new XADataSourceWrappingDataSource(xaDataSource,
dataSourceName,
this.transactionManager));
this.dataSourcesByName
.computeIfAbsent(dataSourceName == null ? NULL_DATASOURCE_NAME : dataSourceName,
ignoredKey -> new XADataSourceWrappingDataSource(xaDataSource,
this::enlistResource));
return returnValue;
}

private boolean activeTransaction() {
try {
return this.transactionManager.getStatus() == Status.STATUS_ACTIVE;
} catch (final SystemException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}

private void enlistResource(final XAResource resource) {
try {
final Transaction transaction = this.transactionManager.getTransaction();
if (transaction != null && transaction.getStatus() == Status.STATUS_ACTIVE) {
transaction.enlistResource(resource);
}
} catch (final RollbackException | SystemException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}

/**
* Converts the supplied {@link DataSource} to a {@link
* DataSource} and returns it.
Expand Down Expand Up @@ -303,9 +330,7 @@ private DataSource convert(final DataSource dataSource, final boolean jta, final
} else {
returnValue =
this.dataSourcesByName.computeIfAbsent(dataSourceName == null ? NULL_DATASOURCE_NAME : dataSourceName,
ignoredKey -> new JtaDataSource(dataSource,
dataSourceName,
this.transactionManager));
k -> new JtaDataSource(dataSource, this::activeTransaction));
this.registerSynchronizationIfTransactionIsActive(returnValue);
}
return returnValue;
Expand Down
27 changes: 18 additions & 9 deletions integrations/cdi/jpa-cdi/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,29 @@
*
* @see io.helidon.integrations.cdi.jpa.PersistenceUnitInfoBean
*/
@SuppressWarnings({ "requires-automatic", "requires-transitive-automatic" })
module io.helidon.integrations.cdi.jpa {

requires java.xml.bind;
requires java.transaction;
requires java.annotation;
requires jakarta.activation;
requires java.sql;
requires java.persistence;
requires jakarta.interceptor.api;
requires jakarta.inject.api;
requires jakarta.enterprise.cdi.api;
requires io.helidon.integrations.cdi.referencecountedcontext;

requires jakarta.inject.api; // automatic module
requires jakarta.interceptor.api; // automatic module

requires io.helidon.integrations.cdi.delegates;
requires io.helidon.integrations.cdi.referencecountedcontext;

requires transitive jakarta.enterprise.cdi.api; // automatic module
requires transitive java.annotation; // automatic module
requires transitive java.persistence; // automatic module
requires transitive java.sql;

// JTA is optional at runtime, as well as the modules that support
// it.
requires static java.transaction; // automatic module
requires static io.helidon.integrations.jta.jdbc;

exports io.helidon.integrations.cdi.jpa;
exports io.helidon.integrations.cdi.jpa.jaxb;

provides javax.enterprise.inject.spi.Extension with io.helidon.integrations.cdi.jpa.JpaExtension;
}
31 changes: 31 additions & 0 deletions integrations/jdbc/jdbc/etc/spotbugs/exclude.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2021 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.
-->
<FindBugsFilter
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://github.com/spotbugs/filter/3.1.0"
xsi:schemaLocation="https://github.com/spotbugs/filter/3.1.0
https://raw.githubusercontent.com/spotbugs/spotbugs/3.1.0/spotbugs/etc/findbugsfilter.xsd">
<!-- These are delegating classes. User input validation would need to occur upstream -->
<Match>
<Class name="io.helidon.integrations.jdbc.DelegatingConnection"/>
<Bug pattern="EXTERNAL_CONFIG_CONTROL"/>
</Match>
<Match>
<Class name="io.helidon.integrations.jdbc.DelegatingConnection"/>
<Bug pattern="SQL_INJECTION_JDBC"/>
</Match>
</FindBugsFilter>
38 changes: 38 additions & 0 deletions integrations/jdbc/jdbc/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2021 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.
-->

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.helidon.integrations</groupId>
<artifactId>helidon-integrations-jdbc-project</artifactId>
<version>2.4.0-SNAPSHOT</version>
</parent>

<groupId>io.helidon.integrations.jdbc</groupId>
<artifactId>helidon-integrations-jdbc</artifactId>

<name>Helidon Integrations JDBC</name>
<description>JDBC-related integration classes</description>

<properties>
<spotbugs.exclude>etc/spotbugs/exclude.xml</spotbugs.exclude>
</properties>

</project>
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) 2021 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 All @@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.helidon.integrations.cdi.jpa;
package io.helidon.integrations.jdbc;

import java.io.PrintWriter;
import java.sql.SQLException;
Expand All @@ -22,7 +22,11 @@

import javax.sql.CommonDataSource;

abstract class AbstractCommonDataSource implements CommonDataSource {
/**
* A skeletal implementation of the {@link CommonDataSource}
* interface.
*/
public abstract class AbstractCommonDataSource implements CommonDataSource {

private int loginTimeout;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021 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 All @@ -13,13 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.helidon.integrations.cdi.jpa;
package io.helidon.integrations.jdbc;

import java.sql.SQLException;

import javax.sql.DataSource;

abstract class AbstractDataSource extends AbstractCommonDataSource implements DataSource {
/**
* A skeletal implementation of the {@link DataSource} interface.
*/
public abstract class AbstractDataSource extends AbstractCommonDataSource implements DataSource {

protected AbstractDataSource() {
super();
Expand Down
Loading

0 comments on commit b68ef5b

Please sign in to comment.