com.scalar.db.sql.SqlTransactionFactory Maven / Gradle / Ivy
package com.scalar.db.sql;
import com.google.common.collect.ImmutableMap;
import com.scalar.db.sql.common.SqlError;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.ServiceLoader;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A factory class for {@link SqlTransactionManager} and {@link
* SqlTwoPhaseCommitTransactionManager}.
*/
@ThreadSafe
public class SqlTransactionFactory {
private static final Logger logger = LoggerFactory.getLogger(SqlTransactionFactory.class);
// a cache for SqlTransactionProvider instances
private static final Map SQL_TRANSACTION_PROVIDERS;
static {
// load SqlTransactionProvider with ServiceLoader
ImmutableMap.Builder sqlTransactionProviderBuilder =
ImmutableMap.builder();
for (SqlTransactionProvider sqlTransactionProvider :
ServiceLoader.load(SqlTransactionProvider.class)) {
sqlTransactionProviderBuilder.put(
sqlTransactionProvider.getName().toLowerCase(Locale.ROOT), sqlTransactionProvider);
}
SQL_TRANSACTION_PROVIDERS = sqlTransactionProviderBuilder.build();
}
private final SqlConfig config;
private final Properties properties;
private SqlTransactionFactory(Properties properties) {
config = new SqlConfig(properties);
this.properties = new Properties();
this.properties.putAll(properties);
}
/**
* Creates an instance of {@link SqlTransactionManager} for the connection mode.
*
* @return an instance of {@link SqlTransactionManager} for the connection mode
*/
public SqlTransactionManager createSqlTransactionManager() {
return getSqlTransactionProvider(config.getConnectionMode().orElse(null))
.createSqlTransactionManager(properties);
}
/**
* Creates an instance of {@link SqlTwoPhaseCommitTransactionManager} for the connection mode.
*
* @return an instance of {@link SqlTwoPhaseCommitTransactionManager} for the connection mode. If
* the transaction manager does not support the two-phase commit interface, returns {@code
* null}.
*/
@Nullable
public SqlTwoPhaseCommitTransactionManager createSqlTwoPhaseCommitTransactionManager() {
return getSqlTransactionProvider(config.getConnectionMode().orElse(null))
.createSqlTwoPhaseCommitTransactionManager(properties);
}
private SqlTransactionProvider getSqlTransactionProvider(@Nullable String connectionMode) {
if (SQL_TRANSACTION_PROVIDERS.isEmpty()) {
throw new IllegalArgumentException(
SqlError.NO_CONNECTION_MODE_IMPLEMENTATIONS.buildMessage());
}
if (connectionMode == null) {
// if the connection mode is not specified, use the only provider if there is only one
if (SQL_TRANSACTION_PROVIDERS.size() == 1) {
SqlTransactionProvider provider = SQL_TRANSACTION_PROVIDERS.values().iterator().next();
logger.info(
"Connection mode is not specified. Only one connection mode is found. Using it: {}",
provider.getName());
return provider;
}
throw new IllegalArgumentException(
SqlError.CONNECTION_MODE_NOT_SPECIFIED_BUT_MULTIPLE_IMPLEMENTATIONS_FOUND.buildMessage(
SQL_TRANSACTION_PROVIDERS.keySet()));
}
String lowerCaseConnectionMode = connectionMode.toLowerCase(Locale.ROOT);
if (!SQL_TRANSACTION_PROVIDERS.containsKey(lowerCaseConnectionMode)) {
throw new IllegalArgumentException(
SqlError.CONNECTION_MODE_NOT_FOUND.buildMessage(
connectionMode, SQL_TRANSACTION_PROVIDERS.keySet()));
}
return SQL_TRANSACTION_PROVIDERS.get(lowerCaseConnectionMode);
}
/**
* Returns a builder object for {@link SqlTransactionFactory}.
*
* @return a builder object for {@link SqlTransactionFactory}
*/
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final Properties properties = new Properties();
/**
* Specifies a properties file path.
*
* @param path a properties file path
* @return this object
*/
public Builder withPropertiesFile(String path) {
return withPropertiesFile(Paths.get(path));
}
/**
* Specifies a properties file path.
*
* @param path a properties file path
* @return this object
*/
public Builder withPropertiesFile(Path path) {
try (InputStream inputStream = Files.newInputStream(path)) {
properties.load(inputStream);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return this;
}
/**
* Adds a property.
*
* @param name a property name
* @param value a property value
* @return this object
*/
public Builder withProperty(String name, String value) {
properties.setProperty(name, value);
return this;
}
/**
* Adds properties.
*
* @param properties properties to add
* @return this object
*/
public Builder withProperties(Properties properties) {
this.properties.putAll(properties);
return this;
}
/**
* Specifies a connection mode.
*
* @param connectionMode a connection mode
* @return this object
*/
public Builder withConnectionMode(String connectionMode) {
properties.setProperty(SqlConfig.CONNECTION_MODE, connectionMode);
return this;
}
/**
* Builds a {@link SqlTransactionFactory} object with the specified configurations.
*
* @return a {@link SqlTransactionFactory} object
*/
public SqlTransactionFactory build() {
return new SqlTransactionFactory(properties);
}
}
}