Skip to content

Commit

Permalink
EDU-2293: Update source code for "Run your first app in Java"
Browse files Browse the repository at this point in the history
    * Change amount from double to int
    * Added toggles to control the success of the deposit and refund
    * Add compensation mechanism to refund failed deposit

JIRA: https://temporalio.atlassian.net/browse/EDU-2293
  • Loading branch information
fairlydurable committed Apr 23, 2024
1 parent e276c21 commit 80c4add
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 23 deletions.
4 changes: 2 additions & 2 deletions src/main/java/moneytransfer/AccountActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
public interface AccountActivity {
// Withdraw an amount of money from the source account
@ActivityMethod
void withdraw(String accountId, String referenceId, double amount);
void withdraw(String accountId, String referenceId, int amount);

// Deposit an amount of money into the destination account
@ActivityMethod
void deposit(String accountId, String referenceId, double amount);
void deposit(String accountId, String referenceId, int amount, boolean activityShouldSucceed);
}
// @@@SNIPEND
16 changes: 10 additions & 6 deletions src/main/java/moneytransfer/AccountActivityImpl.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
// @@@SNIPSTART money-transfer-java-activity-implementation
package moneytransferapp;

import io.temporal.activity.*;

public class AccountActivityImpl implements AccountActivity {
// Mock up the withdrawal of an amount of money from the source account
@Override
public void withdraw(String accountId, String referenceId, double amount) {
public void withdraw(String accountId, String referenceId, int amount) {
System.out.printf(
"\nWithdrawing $%.2f from account %s.\n[ReferenceId: %s]\n",
"\nWithdrawing $%d from account %s.\n[ReferenceId: %s]\n",
amount, accountId, referenceId
);
}

// Mock up the deposit of an amount of money from the destination account
@Override
public void deposit(String accountId, String referenceId, double amount) {
public void deposit(String accountId, String referenceId, int amount, boolean activityShouldSucceed) {
System.out.printf(
"\nDepositing $%.2f into account %s.\n[ReferenceId: %s]\n",
"\nDepositing $%d into account %s.\n[ReferenceId: %s]\n",
amount, accountId, referenceId
);

// TO SIMULATE AN ACTIVITY ERROR: Uncomment the following line
// throw Activity.wrap(new RuntimeException("Simulated Activity error"));
if (!activityShouldSucceed) {
System.out.println("Deposit failed");
throw Activity.wrap(new RuntimeException("Simulated Activity error during deposit of funds"));
}
}
}
// @@@SNIPEND
7 changes: 4 additions & 3 deletions src/main/java/moneytransfer/CoreTransactionDetails.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public class CoreTransactionDetails implements TransactionDetails {
private String sourceAccountId;
private String destinationAccountId;
private String transactionReferenceId;
private double amountToTransfer;
private int amountToTransfer;

// MARK: Constructor

Expand All @@ -16,7 +16,8 @@ public CoreTransactionDetails() {
public CoreTransactionDetails(String sourceAccountId,
String destinationAccountId,
String transactionReferenceId,
double amountToTransfer) {
int amountToTransfer)
{
this.sourceAccountId = sourceAccountId;
this.destinationAccountId = destinationAccountId;
this.transactionReferenceId = transactionReferenceId;
Expand All @@ -37,7 +38,7 @@ public String getTransactionReferenceId() {
return transactionReferenceId;
}

public double getAmountToTransfer() {
public int getAmountToTransfer() {
return amountToTransfer;
}
}
Expand Down
67 changes: 62 additions & 5 deletions src/main/java/moneytransfer/MoneyTransferWorkflowImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,68 @@ public class MoneyTransferWorkflowImpl implements MoneyTransferWorkflow {
// other Activity methods.
@Override
public void transfer(TransactionDetails transaction) {
System.out.println("Starting");
accountActivityStub.withdraw(transaction.getSourceAccountId(), transaction.getTransactionReferenceId(), transaction.getAmountToTransfer());
System.out.println("Working");
accountActivityStub.deposit(transaction.getDestinationAccountId(), transaction.getTransactionReferenceId(), transaction.getAmountToTransfer());
System.out.println("Done");
String sourceAccountId = transaction.getSourceAccountId();
String destinationAccountId = transaction.getDestinationAccountId();
String transactionReferenceId = transaction.getTransactionReferenceId();
int amountToTransfer = transaction.getAmountToTransfer();

try {
accountActivityStub.withdraw(sourceAccountId, transactionReferenceId, amountToTransfer);
} catch (Exception e) {
// If the withdrawal fails, for any exception
System.out.printf("[%s] Withdrawal of $%d from account %s failed",
transactionReferenceId, amountToTransfer, sourceAccountId);
System.out.flush();

// Transaction ends here
return;
}

// Change this from true to false to force the deposit to fail
boolean transferShouldSucceed = true;

try {
accountActivityStub.deposit(destinationAccountId, transactionReferenceId, amountToTransfer, transferShouldSucceed);

// Successful. Transaction ends here
System.out.printf("[%s] Transaction succeeded.\n", transactionReferenceId);
System.out.flush();
return;
} catch (Exception e) {
// If the deposit fails, for any exception
System.out.printf("[%s] Deposit of $%d to account %s failed.\n",
transactionReferenceId, amountToTransfer, destinationAccountId);
System.out.flush();
}

// Continue by reversing transaction

// Change this from true to false to force the recovery compensation to fail
boolean refundShouldSucceed = true;

try {
// Refund the withdrawal
System.out.printf("[%s] Refunding $%d to account %s.\n",
transactionReferenceId, amountToTransfer, destinationAccountId);
System.out.flush();
accountActivityStub.deposit(sourceAccountId, transactionReferenceId, amountToTransfer, refundShouldSucceed);

// Recovery successful. Transaction ends here
System.out.printf("[%s] Refund to originating account was successful.\n",
transactionReferenceId);
System.out.printf("[%s] Transaction is complete. No transfer made.\n",
transactionReferenceId);
return;
} catch (Exception e) {
// A recovery mechanism can fail too. Handle any exception
System.out.printf("[%s] Deposit of $%d to account %s failed. Did not compensate withdrawal.\n",
transactionReferenceId, amountToTransfer, destinationAccountId);
System.out.flush();
}

System.out.printf("[%s] Ended transaction in inconsistent state.\n",
transactionReferenceId);
System.out.flush();
}
}
// @@@SNIPEND
2 changes: 1 addition & 1 deletion src/main/java/moneytransfer/TransactionDetails.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public interface TransactionDetails {
String getSourceAccountId();
String getDestinationAccountId();
String getTransactionReferenceId();
double getAmountToTransfer();
int getAmountToTransfer();
}
// @@@SNIPEND

6 changes: 3 additions & 3 deletions src/main/java/moneytransfer/TransferApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class TransferApp {
}

public static String randomAccountIdentifier() {
return IntStream.range(0, 11)
return IntStream.range(0, 9)
.mapToObj(i -> String.valueOf(random.nextInt(10)))
.collect(Collectors.joining());
}
Expand Down Expand Up @@ -56,15 +56,15 @@ public static void main(String[] args) throws Exception {
String referenceId = UUID.randomUUID().toString().substring(0, 18);
String fromAccount = randomAccountIdentifier();
String toAccount = randomAccountIdentifier();
double amountToTransfer = ThreadLocalRandom.current().nextDouble(15.0, 25.0);
int amountToTransfer = ThreadLocalRandom.current().nextInt(15, 75);
TransactionDetails transaction = new CoreTransactionDetails(fromAccount, toAccount, referenceId, amountToTransfer);

// Perform asynchronous execution.
// This process exits after making this call and printing details.
WorkflowExecution we = WorkflowClient.start(workflow::transfer, transaction);

System.out.printf("\nMONEY TRANSFER PROJECT\n\n");
System.out.printf("Initiating transfer of $%.2f from [Account %s] to [Account %s].\n\n",
System.out.printf("Initiating transfer of $%d from [Account %s] to [Account %s].\n\n",
amountToTransfer, fromAccount, toAccount);
System.out.printf("[WorkflowID: %s]\n[RunID: %s]\n\n", we.getWorkflowId(), we.getRunId());
System.exit(0);
Expand Down
6 changes: 3 additions & 3 deletions src/test/java/moneytransfer/MoneyTransferWorkflowTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ public void testTransfer() {
.setTaskQueue(Shared.MONEY_TRANSFER_TASK_QUEUE)
.build();
MoneyTransferWorkflow workflow = workflowClient.newWorkflowStub(MoneyTransferWorkflow.class, options);
TransactionDetails transaction = new CoreTransactionDetails("account1", "account2", "reference1", 1.23);
TransactionDetails transaction = new CoreTransactionDetails("account1", "account2", "reference1", 10);
workflow.transfer(transaction);
verify(activities).withdraw(eq("account1"), eq("reference1"), eq(1.23));
verify(activities).deposit(eq("account2"), eq("reference1"), eq(1.23));
verify(activities).withdraw(eq("account1"), eq("reference1"), eq(10));
// Cannot reliably test deposit as the failure configurations will affect this
}
}
// @@@SNIPEND

0 comments on commit 80c4add

Please sign in to comment.