2525import io .serverlessworkflow .api .functions .FunctionDefinition ;
2626import io .serverlessworkflow .api .interfaces .State ;
2727import io .serverlessworkflow .api .interfaces .WorkflowValidator ;
28+ import io .serverlessworkflow .api .retry .RetryDefinition ;
2829import io .serverlessworkflow .api .states .*;
2930import io .serverlessworkflow .api .switchconditions .DataCondition ;
3031import io .serverlessworkflow .api .switchconditions .EventCondition ;
@@ -78,7 +79,7 @@ public List<ValidationError> validate() {
7879
7980 // if there are schema validation errors
8081 // there is no point of doing the workflow validation
81- if (validationErrors .size () > 0 ) {
82+ if (! validationErrors .isEmpty () ) {
8283 return validationErrors ;
8384 } else if (workflow == null ) {
8485 workflow = Workflow .fromSource (source );
@@ -101,6 +102,19 @@ public List<ValidationError> validate() {
101102 "Workflow version should not be empty" , ValidationError .WORKFLOW_VALIDATION );
102103 }
103104
105+ if (workflow .getRetries () != null && workflow .getRetries ().getRetryDefs () != null ) {
106+ workflow
107+ .getRetries ()
108+ .getRetryDefs ()
109+ .forEach (
110+ r -> {
111+ if (r .getName () == null || r .getName ().isEmpty ()) {
112+ addValidationError (
113+ "Retry name should not be empty" , ValidationError .WORKFLOW_VALIDATION );
114+ }
115+ });
116+ }
117+
104118 if (workflow .getStates () == null || workflow .getStates ().isEmpty ()) {
105119 addValidationError ("No states found" , ValidationError .WORKFLOW_VALIDATION );
106120 }
@@ -149,7 +163,7 @@ public List<ValidationError> validate() {
149163
150164 if (s instanceof EventState ) {
151165 EventState eventState = (EventState ) s ;
152- if (eventState .getOnEvents () == null || eventState .getOnEvents ().size () < 1 ) {
166+ if (eventState .getOnEvents () == null || eventState .getOnEvents ().isEmpty () ) {
153167 addValidationError (
154168 "Event State has no eventActions defined" ,
155169 ValidationError .WORKFLOW_VALIDATION );
@@ -158,13 +172,13 @@ public List<ValidationError> validate() {
158172 for (OnEvents onEvents : eventsActionsList ) {
159173
160174 List <String > eventRefs = onEvents .getEventRefs ();
161- if (eventRefs == null || eventRefs .size () < 1 ) {
175+ if (eventRefs == null || eventRefs .isEmpty () ) {
162176 addValidationError (
163177 "Event State eventsActions has no event refs" ,
164178 ValidationError .WORKFLOW_VALIDATION );
165179 } else {
166180 for (String eventRef : eventRefs ) {
167- if (! haveEventsDefinition (eventRef , events )) {
181+ if (isMissingEventsDefinition (eventRef , events )) {
168182 addValidationError (
169183 "Event State eventsActions eventRef does not match a declared workflow event definition" ,
170184 ValidationError .WORKFLOW_VALIDATION );
@@ -177,9 +191,9 @@ public List<ValidationError> validate() {
177191 if (s instanceof SwitchState ) {
178192 SwitchState switchState = (SwitchState ) s ;
179193 if ((switchState .getDataConditions () == null
180- || switchState .getDataConditions ().size () < 1 )
194+ || switchState .getDataConditions ().isEmpty () )
181195 && (switchState .getEventConditions () == null
182- || switchState .getEventConditions ().size () < 1 )) {
196+ || switchState .getEventConditions ().isEmpty () )) {
183197 addValidationError (
184198 "Switch state should define either data or event conditions" ,
185199 ValidationError .WORKFLOW_VALIDATION );
@@ -192,10 +206,10 @@ public List<ValidationError> validate() {
192206 }
193207
194208 if (switchState .getEventConditions () != null
195- && switchState .getEventConditions ().size () > 0 ) {
209+ && ! switchState .getEventConditions ().isEmpty () ) {
196210 List <EventCondition > eventConditions = switchState .getEventConditions ();
197211 for (EventCondition ec : eventConditions ) {
198- if (! haveEventsDefinition (ec .getEventRef (), events )) {
212+ if (isMissingEventsDefinition (ec .getEventRef (), events )) {
199213 addValidationError (
200214 "Switch state event condition eventRef does not reference a defined workflow event" ,
201215 ValidationError .WORKFLOW_VALIDATION );
@@ -207,7 +221,7 @@ public List<ValidationError> validate() {
207221 }
208222
209223 if (switchState .getDataConditions () != null
210- && switchState .getDataConditions ().size () > 0 ) {
224+ && ! switchState .getDataConditions ().isEmpty () ) {
211225 List <DataCondition > dataConditions = switchState .getDataConditions ();
212226 for (DataCondition dc : dataConditions ) {
213227 if (dc .getEnd () != null ) {
@@ -219,7 +233,7 @@ public List<ValidationError> validate() {
219233
220234 if (s instanceof SleepState ) {
221235 SleepState sleepState = (SleepState ) s ;
222- if (sleepState .getDuration () == null || sleepState .getDuration ().length () < 1 ) {
236+ if (sleepState .getDuration () == null || sleepState .getDuration ().isEmpty () ) {
223237 addValidationError (
224238 "Sleep state should have a non-empty time delay" ,
225239 ValidationError .WORKFLOW_VALIDATION );
@@ -260,13 +274,13 @@ public List<ValidationError> validate() {
260274 if (s instanceof CallbackState ) {
261275 CallbackState callbackState = (CallbackState ) s ;
262276
263- if (! haveEventsDefinition (callbackState .getEventRef (), events )) {
277+ if (isMissingEventsDefinition (callbackState .getEventRef (), events )) {
264278 addValidationError (
265279 "CallbackState event ref does not reference a defined workflow event definition" ,
266280 ValidationError .WORKFLOW_VALIDATION );
267281 }
268282
269- if (! haveFunctionDefinition (
283+ if (isMissingFunctionDefinition (
270284 callbackState .getAction ().getFunctionRef ().getRefName (), functions )) {
271285 addValidationError (
272286 "CallbackState action function ref does not reference a defined workflow function definition" ,
@@ -316,7 +330,7 @@ private void checkActionsDefinition(
316330 ValidationError .WORKFLOW_VALIDATION );
317331 }
318332
319- if (! haveFunctionDefinition (action .getFunctionRef ().getRefName (), functions )) {
333+ if (isMissingFunctionDefinition (action .getFunctionRef ().getRefName (), functions )) {
320334 addValidationError (
321335 String .format (
322336 "State action '%s' functionRef does not reference an existing workflow function definition" ,
@@ -327,51 +341,64 @@ private void checkActionsDefinition(
327341
328342 if (action .getEventRef () != null ) {
329343
330- if (! haveEventsDefinition (action .getEventRef ().getTriggerEventRef (), events )) {
344+ if (isMissingEventsDefinition (action .getEventRef ().getTriggerEventRef (), events )) {
331345 addValidationError (
332346 String .format (
333347 "State action '%s' trigger event def does not reference an existing workflow event definition" ,
334348 action .getName ()),
335349 ValidationError .WORKFLOW_VALIDATION );
336350 }
337351
338- if (! haveEventsDefinition (action .getEventRef ().getResultEventRef (), events )) {
352+ if (isMissingEventsDefinition (action .getEventRef ().getResultEventRef (), events )) {
339353 addValidationError (
340354 String .format (
341355 "State action '%s' results event def does not reference an existing workflow event definition" ,
342356 action .getName ()),
343357 ValidationError .WORKFLOW_VALIDATION );
344358 }
345359 }
360+
361+ if (action .getRetryRef () != null
362+ && isMissingRetryDefinition (action .getRetryRef (), workflow .getRetries ().getRetryDefs ())) {
363+ addValidationError (
364+ String .format (
365+ "Operation State action '%s' retryRef does not reference an existing workflow retry definition" ,
366+ action .getName ()),
367+ ValidationError .WORKFLOW_VALIDATION );
368+ }
346369 }
347370 }
348371
349- private boolean haveFunctionDefinition (String functionName , List <FunctionDefinition > functions ) {
372+ private boolean isMissingFunctionDefinition (
373+ String functionName , List <FunctionDefinition > functions ) {
350374 if (functions != null ) {
351- FunctionDefinition fun =
352- functions .stream ().filter (f -> f .getName ().equals (functionName )).findFirst ().orElse (null );
353-
354- return fun == null ? false : true ;
375+ return !functions .stream ().anyMatch (f -> f .getName ().equals (functionName ));
355376 } else {
356- return false ;
377+ return true ;
357378 }
358379 }
359380
360- private boolean haveEventsDefinition (String eventName , List <EventDefinition > events ) {
381+ private boolean isMissingEventsDefinition (String eventName , List <EventDefinition > events ) {
361382 if (eventName == null ) {
362- return true ;
383+ return false ;
363384 }
364385 if (events != null ) {
365- EventDefinition eve =
366- events .stream ().filter (e -> e .getName ().equals (eventName )).findFirst ().orElse (null );
367- return eve == null ? false : true ;
386+ return !events .stream ().anyMatch (e -> e .getName ().equals (eventName ));
368387 } else {
369- return false ;
388+ return true ;
370389 }
371390 }
372391
392+ private boolean isMissingRetryDefinition (String retryName , List <RetryDefinition > retries ) {
393+ return retries == null
394+ || !retries .stream ().anyMatch (f -> f .getName () != null && f .getName ().equals (retryName ));
395+ }
396+
373397 private static final Set <String > skipMessages =
374- Set .of ("$.start: string found, object expected" , "$.functions: array found, object expected" );
398+ Set .of (
399+ "$.start: string found, object expected" ,
400+ "$.functions: array found, object expected" ,
401+ "$.retries: array found, object expected" );
375402
376403 private void addValidationError (String message , String type ) {
377404 if (skipMessages .contains (message )) {
0 commit comments