@@ -12,6 +12,7 @@ public class OpenAPIWorkflowValidator {
1212 private OpenAPIWorkflow openAPIWorkflow = null ;
1313 Set <String > workflowIds = new HashSet <>();
1414 Map <String , Set <String >> stepIds = new HashMap <>();
15+ Set <String > operationIds = new HashSet <>();
1516 Set <Schema > components = new HashSet <>();
1617
1718 OpenAPIWorkflowValidator () {
@@ -27,8 +28,9 @@ public OpenAPIWorkflowValidatorResult validate() {
2728 throw new RuntimeException ("OpenAPIWorkflow is not provided" );
2829 }
2930
30- loadWorkflowIds (this .openAPIWorkflow . getWorkflows () );
31+ loadWorkflowIds (this .openAPIWorkflow );
3132 loadStepIds (this .openAPIWorkflow .getWorkflows ());
33+ loadOperationIds (this .openAPIWorkflow );
3234
3335 OpenAPIWorkflowValidatorResult result = new OpenAPIWorkflowValidatorResult ();
3436
@@ -346,8 +348,8 @@ List<String> validateComponents(Components components) {
346348 if (components .getParameters () != null ) {
347349
348350 for (String key : components .getParameters ().keySet ()) {
349- if (isValidComponentKey (key )) {
350- errors .add ("'Component parameter " + key + " is invalid (should match regex " + getComponentKeyRegularExpression () + ")" );
351+ if (! isValidComponentKey (key )) {
352+ errors .add ("'Component parameter name " + key + " is invalid (should match regex " + getComponentKeyRegularExpression () + ")" );
351353 }
352354 }
353355
@@ -356,13 +358,11 @@ List<String> validateComponents(Components components) {
356358 }
357359 }
358360 if (components .getInputs () != null ) {
359-
360361 for (String key : components .getInputs ().keySet ()) {
361- if (isValidComponentKey (key )) {
362+ if (! isValidComponentKey (key )) {
362363 errors .add ("'Component input " + key + " is invalid (should match regex " + getComponentKeyRegularExpression () + ")" );
363364 }
364365 }
365-
366366 }
367367 }
368368
@@ -400,18 +400,24 @@ String getOutputsKeyRegularExpression() {
400400 return "^[a-zA-Z0-9\\ .\\ -_]+$" ;
401401 }
402402
403- List <String > loadWorkflowIds (List < Workflow > workflows ) {
403+ List <String > loadWorkflowIds (OpenAPIWorkflow openAPIWorkflow ) {
404404 List <String > errors = new ArrayList <>();
405405
406- if (workflows != null ) {
407- for (Workflow workflow : workflows ) {
408- if (!this .workflowIds .add (workflow .getWorkflowId ())) {
409- // id already exists
410- errors .add ("WorkflowId is not unique: " + workflow .getWorkflowId ());
411- }
406+ boolean multipleWorkflowsSpec = getNumWorkflowsSpecSourceDescriptions (openAPIWorkflow .getSourceDescriptions ()) > 1 ? true : false ;
407+
408+
409+ if (openAPIWorkflow .getWorkflows () != null ) {
410+ validateWorkflowIdsUniqueness (openAPIWorkflow .getWorkflows ());
411+
412+ for (Workflow workflow : openAPIWorkflow .getWorkflows ()) {
413+ errors .addAll (validateStepsWorkflowIds (workflow .getSteps (), multipleWorkflowsSpec ));
412414 }
413- }
414415
416+ for (Workflow workflow : openAPIWorkflow .getWorkflows ()) {
417+ this .workflowIds .add (workflow .getWorkflowId ());
418+ }
419+
420+ }
415421 return errors ;
416422 }
417423
@@ -440,10 +446,82 @@ List<String> loadStepIds(List<Workflow> workflows) {
440446 return errors ;
441447 }
442448
449+ List <String > loadOperationIds (OpenAPIWorkflow openAPIWorkflow ) {
450+ List <String > errors = new ArrayList <>();
451+
452+ boolean multipleOpenApiFiles = getNumOpenApiSourceDescriptions (openAPIWorkflow .getSourceDescriptions ()) > 1 ? true : false ;
453+
454+ for (Workflow workflow : openAPIWorkflow .getWorkflows ()) {
455+ errors .addAll (validateStepsOperationIds (workflow .getSteps (), multipleOpenApiFiles ));
456+
457+ for (Step step : workflow .getSteps ()) {
458+ if (step .getOperationId () != null ) {
459+ this .operationIds .add (step .getOperationId ());
460+ }
461+ }
462+ }
463+
464+ return errors ;
465+ }
466+
467+ public List <String > validateStepsOperationIds (List <Step > steps , boolean multipleOpenApiFiles ) {
468+ List <String > errors = new ArrayList <>();
469+
470+ for (Step step : steps ) {
471+ if (multipleOpenApiFiles ) {
472+ // must use runtime expression to map applicable SourceDescription
473+ if (step .getOperationId () != null && !step .getOperationId ().startsWith ("$sourceDescriptions." )) {
474+ errors .add ("Operation " + step .getOperationId () + " must be specified using a runtime expression (e.g., $sourceDescriptions.<name>.<operationId>)" );
475+ }
476+ }
477+ }
478+
479+ return errors ;
480+ }
481+
482+ // num of SourceDescriptions with type 'openapi'
483+ int getNumOpenApiSourceDescriptions (List <SourceDescription > sourceDescriptions ) {
484+ return (int ) sourceDescriptions .stream ().filter (p -> p .isOpenApi ()).count ();
485+ }
486+
487+ // num of SourceDescriptions with type 'workflowsSpec'
488+ int getNumWorkflowsSpecSourceDescriptions (List <SourceDescription > sourceDescriptions ) {
489+ return (int ) sourceDescriptions .stream ().filter (p -> p .isWorkflowsSpec ()).count ();
490+ }
491+
443492 boolean stepExists (String workflowId , String stepId ) {
444493 return this .stepIds .get (workflowId ) != null && this .stepIds .get (workflowId ).contains (stepId );
445494 }
446495
496+ List <String > validateWorkflowIdsUniqueness (List <Workflow > workflows ) {
497+ List <String > errors = new ArrayList <>();
498+
499+ Set <String > ids = new HashSet <>();
500+ for (Workflow workflow : workflows ) {
501+ if (!ids .add (workflow .getWorkflowId ())) {
502+ // id already exists
503+ errors .add ("WorkflowId is not unique: " + workflow .getWorkflowId ());
504+ }
505+ }
506+ return errors ;
507+ }
508+
509+ List <String > validateStepsWorkflowIds (List <Step > steps , boolean multipleWorkflowsSpecFiles ) {
510+ List <String > errors = new ArrayList <>();
511+
512+ for (Step step : steps ) {
513+ if (multipleWorkflowsSpecFiles ) {
514+ // must use runtime expression to map applicable SourceDescription
515+ if (step .getWorkflowId () != null && !step .getWorkflowId ().startsWith ("$sourceDescriptions." )) {
516+ errors .add ("Operation " + step .getWorkflowId () + " must be specified using a runtime expression (e.g., $sourceDescriptions.<name>.<workflowId>)" );
517+ }
518+ }
519+ }
520+
521+ return errors ;
522+ }
523+
524+
447525 public boolean isValidJsonPointer (String jsonPointerString ) {
448526
449527 boolean ret ;
0 commit comments