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)); } }
private void addWorkflowType( Class<?> interfaze, Class<?> workflowImplementationType, DataConverter converterOverride, Object[] constructorArgs) throws InstantiationException, IllegalAccessException { Workflow workflowAnnotation = interfaze.getAnnotation(Workflow.class); String interfaceName = interfaze.getSimpleName(); MethodConverterPair workflowImplementationMethod = null; MethodConverterPair getStateMethod = null; WorkflowType workflowType = null; WorkflowTypeRegistrationOptions registrationOptions = null; Map<String, MethodConverterPair> signals = new HashMap<String, MethodConverterPair>(); for (Method method : interfaze.getMethods()) { if (method.getDeclaringClass().getAnnotation(Workflow.class) == null) { continue; } Execute executeAnnotation = method.getAnnotation(Execute.class); Signal signalAnnotation = method.getAnnotation(Signal.class); GetState getStateAnnotation = method.getAnnotation(GetState.class); checkAnnotationUniqueness(method, executeAnnotation, signalAnnotation, getStateAnnotation); if (executeAnnotation != null) { if (workflowImplementationMethod != null) { throw new IllegalArgumentException( "Interface annotated with @Workflow is allowed to have only one method annotated with @Execute. Found " + getMethodFullName(workflowImplementationMethod.getMethod()) + " and " + getMethodFullName(method)); } if (!method.getReturnType().equals(void.class) && !(Promise.class.isAssignableFrom(method.getReturnType()))) { throw new IllegalArgumentException( "Workflow implementation method annotated with @Execute can return only Promise or void: " + getMethodFullName(method)); } if (!method.getDeclaringClass().equals(interfaze)) { throw new IllegalArgumentException( "Interface " + interfaze.getName() + " cannot inherit workflow implementation method annotated with @Execute: " + getMethodFullName(method)); } DataConverter converter = createConverter(workflowAnnotation.dataConverter(), converterOverride); workflowImplementationMethod = new MethodConverterPair(method, converter); workflowType = getWorkflowType(interfaceName, method, executeAnnotation); WorkflowRegistrationOptions registrationOptionsAnnotation = interfaze.getAnnotation(WorkflowRegistrationOptions.class); SkipTypeRegistration skipRegistrationAnnotation = interfaze.getAnnotation(SkipTypeRegistration.class); if (skipRegistrationAnnotation == null) { if (registrationOptionsAnnotation == null) { throw new IllegalArgumentException( "@WorkflowRegistrationOptions is required for the interface that contains method annotated with @Execute"); } registrationOptions = createRegistrationOptions(registrationOptionsAnnotation); } else { if (registrationOptionsAnnotation != null) { throw new IllegalArgumentException( "@WorkflowRegistrationOptions is not allowed for the interface annotated with @SkipTypeRegistration."); } } } if (signalAnnotation != null) { String signalName = signalAnnotation.name(); if (signalName == null || signalName.isEmpty()) { signalName = method.getName(); } DataConverter signalConverter = createConverter(workflowAnnotation.dataConverter(), converterOverride); signals.put(signalName, new MethodConverterPair(method, signalConverter)); } if (getStateAnnotation != null) { if (getStateMethod != null) { throw new IllegalArgumentException( "Interface annotated with @Workflow is allowed to have only one method annotated with @GetState. Found " + getMethodFullName(getStateMethod.getMethod()) + " and " + getMethodFullName(method)); } if (method.getReturnType().equals(void.class) || (Promise.class.isAssignableFrom(method.getReturnType()))) { throw new IllegalArgumentException( "Workflow method annotated with @GetState cannot have void or Promise return type: " + getMethodFullName(method)); } DataConverter converter = createConverter(workflowAnnotation.dataConverter(), converterOverride); getStateMethod = new MethodConverterPair(method, converter); } } if (workflowImplementationMethod == null) { throw new IllegalArgumentException( "Workflow definition does not implement any method annotated with @Execute. " + workflowImplementationType); } POJOWorkflowImplementationFactory implementationFactory = getImplementationFactory(workflowImplementationType, interfaze, workflowType); WorkflowDefinitionFactory factory = new POJOWorkflowDefinitionFactory( implementationFactory, workflowType, registrationOptions, workflowImplementationMethod, signals, getStateMethod, constructorArgs); factories.put(workflowType, factory); workflowImplementationTypes.add(workflowImplementationType); if (factory.getWorkflowRegistrationOptions() != null) { workflowTypesToRegister.add(workflowType); } }