TransactionTemplate.java
/*
* @copyright defined in LICENSE.txt
*/
package hera.client;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static hera.api.function.Functions.identify;
import static hera.client.ClientConstants.TRANSACTION_COMMIT;
import static hera.client.ClientConstants.TRANSACTION_GETTX;
import static hera.client.ClientConstants.TRANSACTION_SEND;
import com.google.common.base.Function;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import hera.ContextProvider;
import hera.ContextProviderInjectable;
import hera.annotation.ApiAudience;
import hera.annotation.ApiStability;
import hera.api.TransactionOperation;
import hera.api.function.Function1;
import hera.api.function.Function3;
import hera.api.model.AccountAddress;
import hera.api.model.Aer;
import hera.api.model.Transaction;
import hera.api.model.TxHash;
import hera.client.internal.TransactionBaseTemplate;
import hera.exception.RpcException;
import hera.exception.RpcExceptionConverter;
import hera.strategy.PriorityProvider;
import hera.strategy.StrategyApplier;
import hera.util.ExceptionConverter;
import io.grpc.ManagedChannel;
import java.util.concurrent.Future;
import lombok.AccessLevel;
import lombok.Getter;
@ApiAudience.Private
@ApiStability.Unstable
public class TransactionTemplate
implements TransactionOperation, ChannelInjectable, ContextProviderInjectable {
protected final ExceptionConverter<RpcException> exceptionConverter = new RpcExceptionConverter();
protected TransactionBaseTemplate transactionBaseTemplate = new TransactionBaseTemplate();
protected ContextProvider contextProvider;
@Getter(lazy = true, value = AccessLevel.PROTECTED)
private final StrategyApplier strategyApplier =
StrategyApplier.of(contextProvider.get(), PriorityProvider.get());
@Override
public void setChannel(final ManagedChannel channel) {
this.transactionBaseTemplate.setChannel(channel);
}
@Override
public void setContextProvider(final ContextProvider contextProvider) {
this.contextProvider = contextProvider;
this.transactionBaseTemplate.setContextProvider(contextProvider);
}
private final Function1<TxHash, Future<Transaction>> convertedTransactionFunction =
new Function1<TxHash, Future<Transaction>>() {
@Override
public Future<Transaction> apply(final TxHash txHash) {
final ListenableFuture<Transaction> txInMemory =
(ListenableFuture<Transaction>) transactionBaseTemplate.getTransactionFunction()
.apply(txHash);
final ListenableFuture<Transaction> future =
Futures.catching(txInMemory, Throwable.class, new Function<Throwable, Transaction>() {
@Override
public Transaction apply(final Throwable input) {
try {
return transactionBaseTemplate.getTransactionInBlockFunction().apply(txHash)
.get();
} catch (Exception e) {
// TODO: fixme
throw new RpcException(e);
}
}
}, directExecutor());
return future;
}
};
@Getter(lazy = true, value = AccessLevel.PROTECTED)
private final Function1<TxHash, Future<Transaction>> transactionFunction =
getStrategyApplier().apply(identify(convertedTransactionFunction,
TRANSACTION_GETTX));
@Getter(lazy = true, value = AccessLevel.PROTECTED)
private final Function1<Transaction, Future<TxHash>> commitFunction =
getStrategyApplier()
.apply(identify(this.transactionBaseTemplate.getCommitFunction(), TRANSACTION_COMMIT));
@Getter(lazy = true, value = AccessLevel.PROTECTED)
private final Function3<AccountAddress, AccountAddress, Aer,
Future<TxHash>> sendFunction =
getStrategyApplier()
.apply(identify(this.transactionBaseTemplate.getSendFunction(), TRANSACTION_SEND));
@Override
public Transaction getTransaction(final TxHash txHash) {
try {
return getTransactionFunction().apply(txHash).get();
} catch (Exception e) {
throw exceptionConverter.convert(e);
}
}
@Override
public TxHash commit(final Transaction transaction) {
try {
return getCommitFunction().apply(transaction).get();
} catch (Exception e) {
throw exceptionConverter.convert(e);
}
}
@Override
public TxHash send(final AccountAddress sender,
final AccountAddress recipient,
final Aer amount) {
try {
return getSendFunction().apply(sender, recipient, amount).get();
} catch (Exception e) {
throw exceptionConverter.convert(e);
}
}
}