public WorkflowTestBase(DecisionContext decisionContext) { this.decisionContext = decisionContext; workflowContext = (TestWorkflowContext) decisionContext.getWorkflowContext(); workflowClock = (TestWorkflowClock) decisionContext.getWorkflowClock(); WorkflowExecution we = new WorkflowExecution(); we.setWorkflowId("testWorkflowId"); we.setRunId("testRunId"); workflowContext.setWorkflowExecution(we); WorkflowType wt = new WorkflowType(); wt.setName("testWorkflow"); wt.setVersion("0.0"); workflowContext.setWorkflowType(wt); }
@Override protected void doFinally() throws Throwable { if (!failed) { continueAsNew.set(childContext.getWorkflowContext().getContinueAsNewOnCompletion()); if (continueAsNew.get() == null && executeResult.isReady()) { result.set(executeResult.get()); } } else { continueAsNew.set(null); } workflowExecutions.remove(this.childExecution.getWorkflowId()); }
public void continueAsNewOnCompletion(ContinueAsNewWorkflowExecutionParameters parameters) { DecisionContext decisionContext = decisionContextProvider.getDecisionContext(); decisionContext.getWorkflowContext().setContinueAsNewOnCompletion(parameters); }
private void startChildWorkflow( final StartChildWorkflowExecutionParameters parameters, final Settable<StartChildWorkflowReply> reply, final Settable<String> result) { String workflowId = parameters.getWorkflowId(); WorkflowType workflowType = parameters.getWorkflowType(); WorkflowExecution childExecution = new WorkflowExecution(); final String runId = UUID.randomUUID().toString(); // TODO: Validate parameters against registration options to find missing timeouts or other // options try { DecisionContext parentDecisionContext = decisionContextProvider.getDecisionContext(); if (workflowId == null) { workflowId = decisionContextProvider.getDecisionContext().getWorkflowClient().generateUniqueId(); } childExecution.setWorkflowId(workflowId); childExecution.setRunId(runId); final GenericActivityClient activityClient = parentDecisionContext.getActivityClient(); final WorkflowClock workflowClock = parentDecisionContext.getWorkflowClock(); WorkflowDefinitionFactory factory; if (factoryFactory == null) { throw new IllegalStateException("required property factoryFactory is null"); } factory = factoryFactory.getWorkflowDefinitionFactory(workflowType); if (factory == null) { String cause = StartChildWorkflowExecutionFailedCause.WORKFLOW_TYPE_DOES_NOT_EXIST.toString(); throw new StartChildWorkflowFailedException(0, childExecution, workflowType, cause); } TestWorkflowContext workflowContext = new TestWorkflowContext(); workflowContext.setWorkflowExecution(childExecution); workflowContext.setWorkflowType(parameters.getWorkflowType()); workflowContext.setParentWorkflowExecution( parentDecisionContext.getWorkflowContext().getWorkflowExecution()); workflowContext.setTagList(parameters.getTagList()); workflowContext.setTaskList(parameters.getTaskList()); DecisionContext context = new TestDecisionContext( activityClient, TestGenericWorkflowClient.this, workflowClock, workflowContext); // this, parameters, childExecution, workflowClock, activityClient); final WorkflowDefinition childWorkflowDefinition = factory.getWorkflowDefinition(context); final ChildWorkflowTryCatchFinally tryCatch = new ChildWorkflowTryCatchFinally( parameters, childExecution, childWorkflowDefinition, context, result); workflowContext.setRootTryCatch(tryCatch); ChildWorkflowTryCatchFinally currentRun = workflowExecutions.get(workflowId); if (currentRun != null) { String cause = StartChildWorkflowExecutionFailedCause.WORKFLOW_ALREADY_RUNNING.toString(); throw new StartChildWorkflowFailedException(0, childExecution, workflowType, cause); } workflowExecutions.put(workflowId, tryCatch); continueAsNewWorkflowExecution(tryCatch, result); } catch (StartChildWorkflowFailedException e) { throw e; } catch (Throwable e) { // This cause is chosen to represent internal error for sub-workflow creation String cause = StartChildWorkflowExecutionFailedCause.OPEN_CHILDREN_LIMIT_EXCEEDED.toString(); StartChildWorkflowFailedException failure = new StartChildWorkflowFailedException(0, childExecution, workflowType, cause); failure.initCause(e); throw failure; } finally { reply.set(new StartChildWorkflowReplyImpl(result, runId)); } }
public class NonTxWorkflowImpl implements NonTxWorkflow { DecisionContextProvider contextProvider = new DecisionContextProviderImpl(); DecisionContextProvider provider = new DecisionContextProviderImpl(); DecisionContext context = provider.getDecisionContext(); private WorkflowClock clock = context.getWorkflowClock(); private final int confirmationPeriod = 3500; BitcoindActivitiesClient bcdClient = new BitcoindActivitiesClientImpl(); MessagingActivitiesClient msgClient = new MessagingActivitiesClientImpl(); @Override public void executeCommand(final DataSet data) { new TryCatch() { @Override protected void doTry() throws Throwable { if (data.getAction() == Action.DEPOSIT_REQ) { Promise<String> bcAddress = bcdClient.getNewAddress(data.getCn()); respondDepositReq(bcAddress, data); } else if (data.getAction() == Action.SIGNUP) { Promise<Void> done = msgClient.sendMessage(data); createAddress(done, data); } else if (data.getAction() == Action.GW_DEPOSIT_REQ) { Promise<String> bcAddress = bcdClient.getNewAddress(data.getCn()); respondDataReq(bcAddress, data); } else if (data.getAction() == Action.BALANCE) { Promise<BigDecimal> balance = bcdClient.getAccountBalance(data.getCn()); Promise<BigDecimal> fee = msgClient.readAccountFee(data.getCn()); respondBalance(balance, fee, data); } else if (data.getAction() == Action.GW_BALANCE) { Promise<BigDecimal> balance = bcdClient.getAccountBalance(data.getCn()); cacheBalance(balance, data); } else if (data.getAction() == Action.TRANSACTION) { Promise<List<Transaction>> transactions = bcdClient.getAccountTransactions(data.getCn()); respondTransactions(transactions, data); } else if (data.getAction() == Action.VOICE) { final Settable<DataSet> confirm = new Settable<>(); final Promise<Action> response = msgClient.phoneConfirmation( data, contextProvider .getDecisionContext() .getWorkflowContext() .getWorkflowExecution() .getWorkflowId()); final OrPromise confirmOrTimer = new OrPromise(startDaemonTimer(confirmationPeriod), response); new TryCatch() { @Override protected void doTry() throws Throwable { setConfirm(confirm, confirmOrTimer, response, data); } @Override protected void doCatch(Throwable e) throws Throwable { data.setAction(Action.TIMEOUT); msgClient.sendMessage(data); cancel(e); } }; handleVoice(confirm); } else if (data.getAction() == Action.DEPOSIT_CONF || data.getAction() == Action.DEPOSIT_NOT) { Withdrawal w = (Withdrawal) data.getPayload(); Promise<BigDecimal> balance = null; if (w.getBalance() == null) { balance = bcdClient.getAccountBalance(data.getCn()); } Promise<BigDecimal> fee = null; if (w.getFee() == null) { fee = msgClient.readAccountFee(data.getCn()); } if (data.getTo() == null) { respondDepositConfMessage(balance, fee, msgClient.readMessageAddress(data)); } else { Settable<DataSet> ds = new Settable<>(); respondDepositConfMessage(balance, fee, ds); ds.set(data); } } else { throw new RuntimeException("unknown action"); } } @Override protected void doCatch(Throwable e) throws Throwable { data.setAction(Action.UNAVAILABLE); msgClient.sendMessage(data); e.printStackTrace(); cancel(e); } }; } @Asynchronous public void handleVoice(Promise<DataSet> rsp) { msgClient.sendMessage(rsp.get()); } @Asynchronous public void setConfirm( @NoWait Settable<DataSet> account, OrPromise trigger, Promise<Action> isConfirmed, DataSet data) throws Throwable { if (isConfirmed.isReady()) { if (null != isConfirmed.get() && isConfirmed.get() != Action.WITHDRAWAL_REQ) { data.setAction(isConfirmed.get()); } account.set(data); } else { throw new Throwable("user did not confirm transaction."); } } @Asynchronous public void createAddress(Promise<Void> done, DataSet data) { Promise<String> bcAddress = bcdClient.getNewAddress(data.getCn()); respondDataReq(bcAddress, data); } @Asynchronous(daemon = true) private Promise<Void> startDaemonTimer(int seconds) { Promise<Void> timer = clock.createTimer(seconds); return timer; } @Asynchronous public void respondDepositReq(Promise<String> bcAddress, DataSet data) { data.setPayload( new PaymentAddress().setAddress(bcAddress.get()).setAddressType(PaymentType.BTC)); msgClient.sendMessage(data); } @Asynchronous public void respondDataReq(Promise<String> bcAddress, DataSet data) { data.setPayload( new PaymentAddress().setAddress(bcAddress.get()).setAddressType(PaymentType.BTC)); msgClient.putAddressCache(data); } @Asynchronous public void respondBalance(Promise<BigDecimal> balance, Promise<BigDecimal> fee, DataSet data) { data.setPayload(new Withdrawal().setBalance(balance.get().subtract(fee.get()))); msgClient.sendMessage(data); } @Asynchronous public void cacheBalance(Promise<BigDecimal> balance, DataSet data) { data.setPayload(new Withdrawal().setBalance(balance.get())); msgClient.putCache(data); } @Asynchronous public void respondTransactions(Promise<List<Transaction>> transactions, DataSet data) { data.setPayload(transactions.get()); msgClient.sendMessage(data); } @Asynchronous public void respondDepositConfMessage( Promise<BigDecimal> balance, Promise<BigDecimal> fee, Promise<DataSet> addr) { DataSet ds = addr.get(); Withdrawal dep = (Withdrawal) ds.getPayload(); BigDecimal bal = (dep.getBalance() != null) ? dep.getBalance() : balance.get(); BigDecimal f = (dep.getFee() != null) ? dep.getFee() : fee.get(); dep.setBalance(bal.subtract(f)); msgClient.sendMessage(ds); } }