Skip to content

Commit

Permalink
Support JDBC ObjectStore in narayana-jta extension
Browse files Browse the repository at this point in the history
  • Loading branch information
zhfeng committed Mar 9, 2023
1 parent 9a520b9 commit a0efc85
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 12 deletions.
4 changes: 4 additions & 0 deletions extensions/narayana-jta/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-narayana-jta</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-agroal-spi</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import static io.quarkus.deployment.annotations.ExecutionTime.RUNTIME_INIT;

import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;

import jakarta.annotation.Priority;
import jakarta.interceptor.Interceptor;
Expand Down Expand Up @@ -30,6 +32,7 @@
import com.arjuna.ats.jta.common.JTAEnvironmentBean;
import com.arjuna.common.util.propertyservice.PropertiesFactory;

import io.quarkus.agroal.spi.JdbcDataSourceBuildItem;
import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.ContextRegistrationPhaseBuildItem;
import io.quarkus.arc.deployment.ContextRegistrationPhaseBuildItem.ContextConfiguratorBuildItem;
Expand All @@ -52,6 +55,7 @@
import io.quarkus.gizmo.ClassCreator;
import io.quarkus.narayana.jta.runtime.NarayanaJtaProducers;
import io.quarkus.narayana.jta.runtime.NarayanaJtaRecorder;
import io.quarkus.narayana.jta.runtime.QuarkusDataSource;
import io.quarkus.narayana.jta.runtime.TransactionManagerConfiguration;
import io.quarkus.narayana.jta.runtime.context.TransactionContext;
import io.quarkus.narayana.jta.runtime.interceptor.TestTransactionInterceptor;
Expand Down Expand Up @@ -80,7 +84,8 @@ public void build(NarayanaJtaRecorder recorder,
BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
BuildProducer<RuntimeInitializedClassBuildItem> runtimeInit,
BuildProducer<FeatureBuildItem> feature,
TransactionManagerConfiguration transactions, ShutdownContextBuildItem shutdownContextBuildItem) {
TransactionManagerConfiguration transactions,
List<JdbcDataSourceBuildItem> jdbcDataSourcesBuildItem, ShutdownContextBuildItem shutdownContextBuildItem) {
recorder.handleShutdown(shutdownContextBuildItem, transactions);
feature.produce(new FeatureBuildItem(Feature.NARAYANA_JTA));
additionalBeans.produce(new AdditionalBeanBuildItem(NarayanaJtaProducers.class));
Expand All @@ -95,7 +100,7 @@ public void build(NarayanaJtaRecorder recorder,
runtimeInit.produce(new RuntimeInitializedClassBuildItem(JTAActionStatusServiceXAResourceOrphanFilter.class.getName()));
runtimeInit.produce(new RuntimeInitializedClassBuildItem(AtomicActionExpiryScanner.class.getName()));

reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, JTAEnvironmentBean.class.getName(),
reflectiveClass.produce(ReflectiveClassBuildItem.builder(JTAEnvironmentBean.class.getName(),
UserTransactionImple.class.getName(),
CheckedActionFactoryImple.class.getName(),
TransactionManagerImple.class.getName(),
Expand All @@ -109,7 +114,7 @@ public void build(NarayanaJtaRecorder recorder,
JTATransactionLogXAResourceOrphanFilter.class.getName(),
JTANodeNameXAResourceOrphanFilter.class.getName(),
JTAActionStatusServiceXAResourceOrphanFilter.class.getName(),
ExpiredTransactionStatusManagerScanner.class.getName()));
ExpiredTransactionStatusManagerScanner.class.getName()).methods(false).fields(false).build());

AdditionalBeanBuildItem.Builder builder = AdditionalBeanBuildItem.builder();
builder.addBeanClass(TransactionalInterceptorSupports.class);
Expand All @@ -132,7 +137,10 @@ public void build(NarayanaJtaRecorder recorder,
recorder.disableTransactionStatusManager();
recorder.setNodeName(transactions);
recorder.setDefaultTimeout(transactions);
recorder.setConfig(transactions);
recorder.setConfig(transactions,
jdbcDataSourcesBuildItem.stream()
.map(dataSource -> QuarkusDataSource.of(dataSource.getName(), dataSource.isDefault()))
.collect(Collectors.toList()));
}

@BuildStep(onlyIf = IsTest.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Properties;

import javax.sql.DataSource;

import jakarta.enterprise.inject.literal.NamedLiteral;

import org.jboss.logging.Logger;

import com.arjuna.ats.arjuna.common.CoreEnvironmentBeanException;
Expand All @@ -18,8 +24,10 @@
import com.arjuna.common.internal.util.propertyservice.BeanPopulator;
import com.arjuna.common.util.propertyservice.PropertiesFactory;

import io.quarkus.arc.Arc;
import io.quarkus.runtime.ShutdownContext;
import io.quarkus.runtime.annotations.Recorder;
import io.quarkus.runtime.configuration.ConfigurationException;

@Recorder
public class NarayanaJtaRecorder {
Expand Down Expand Up @@ -71,7 +79,7 @@ public void disableTransactionStatusManager() {
.setTransactionStatusManagerEnable(false);
}

public void setConfig(final TransactionManagerConfiguration transactions) {
public void setConfig(final TransactionManagerConfiguration transactions, final List<QuarkusDataSource> jdbcDataSources) {
BeanPopulator.getDefaultInstance(ObjectStoreEnvironmentBean.class)
.setObjectStoreDir(transactions.objectStoreDirectory);
BeanPopulator.getNamedInstance(ObjectStoreEnvironmentBean.class, "communicationStore")
Expand All @@ -84,17 +92,48 @@ public void setConfig(final TransactionManagerConfiguration transactions) {
.setExpiryScannerClassNames(transactions.expiryScanners);
BeanPopulator.getDefaultInstance(JTAEnvironmentBean.class)
.setXaResourceOrphanFilterClassNames(transactions.xaResourceOrphanFilters);
if (transactions.objectStoreType.equals(ObjectStoreType.JDBC)) {
String dataSource = pickDataSource(transactions, jdbcDataSources);
Arc.container().instance(DataSource.class, NamedLiteral.of(dataSource)).get();
// setJdbcDataSource
}
}

public void handleShutdown(ShutdownContext context, TransactionManagerConfiguration transactions) {
context.addLastShutdownTask(new Runnable() {
@Override
public void run() {
if (transactions.enableRecovery) {
RecoveryManager.manager().terminate(true);
}
TransactionReaper.terminate(false);
context.addLastShutdownTask(() -> {
if (transactions.enableRecovery) {
RecoveryManager.manager().terminate(true);
}
TransactionReaper.terminate(false);
});
}

private String pickDataSource(TransactionManagerConfiguration config, List<QuarkusDataSource> jdbcDataSources) {
if (config.jdbcStoreDataSource.isEmpty()) {
return jdbcDataSources.stream()
.filter(QuarkusDataSource::isDefault)
.findFirst()
.orElseThrow(() -> new ConfigurationException(
"The Narayana JTA extension does not have jdbc datasource configured,"
+ " so it defaults to the default datasource, "
+ " but that datasource is not configured."
+ " referring to https://quarkus.io/guides/datasource for guidance,"
+ " or configure the datasource to use in the Narayana JTA extension "
+ " by setting property 'quarkus.jta.datasource' to the name of a configured datasource."))
.getName();
} else {
return jdbcDataSources.stream()
.filter(i -> i.getName().equals(config.jdbcStoreDataSource.get()))
.findFirst()
.orElseThrow(() -> new ConfigurationException(String.format(Locale.ROOT,
"The Narayana JTA extension is configured to use datasource '%1$s',"
+ " but that datasource is not configured."
+ " To solve this, either configure datasource"
+ " referring to https://quarkus.io/guides/datasource for guidance,"
+ " or configure another datasource to use in the Narayana JTA extension "
+ " by setting property 'quarkus.transaction.object-store.datasource' to the name of a configured datasource.",
config.jdbcStoreDataSource.get())))
.getName();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package io.quarkus.narayana.jta.runtime;

public enum ObjectStoreType {
FileSystem,
JDBC
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.quarkus.narayana.jta.runtime;

public class QuarkusDataSource {
private String name;
private boolean isDefault;

public static QuarkusDataSource of(String name, boolean isDefault) {
return new QuarkusDataSource(name, isDefault);
}

public QuarkusDataSource(String name, boolean isDefault) {
this.name = name;
this.isDefault = isDefault;
}

public String getName() {
return name;
}

public boolean isDefault() {
return isDefault;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.time.Duration;
import java.util.List;
import java.util.Optional;

import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
Expand Down Expand Up @@ -32,6 +33,20 @@ public final class TransactionManagerConfiguration {
@ConfigItem(defaultValue = "ObjectStore")
public String objectStoreDirectory;

/**
* The type of object store.
*/
@ConfigItem(defaultValue = "FileSystem")
public ObjectStoreType objectStoreType;

/**
* The datasource name used in JDBCStore.
* <p>
* If undefined, it will use the default datasource
*/
@ConfigItem(name = "object-store.datasource")
public Optional<String> jdbcStoreDataSource = Optional.empty();

/**
* Start the recovery service on startup.
*/
Expand Down

0 comments on commit a0efc85

Please sign in to comment.