docs: @Override
      public void validate(ValidationHelper helper, Context context, String key, Callback t) {
          String message;
          for (String urlTemplate : t.keySet()) {
              // validate urlTemplate is valid
              if (urlTemplate.isEmpty()) {
                  message = Tr.formatMessage(tc, "callbackURLTemplateEmpty");
                  helper.addValidationEvent(new ValidationEvent(ValidationEvent.Severity.ERROR, context.getLocation(), message));
                  continue;
              }
  
              List<String> vars = RuntimeExpressionUtils.extractURLVars(urlTemplate);
              if (vars == null) {
                  message = Tr.formatMessage(tc, "callbackInvalidSubstitutionVariables", urlTemplate);
                  helper.addValidationEvent(new ValidationEvent(ValidationEvent.Severity.ERROR, context.getLocation(), message));
              } else {
                  // validate replacement items
                  for (String v : vars) {
                      if (!RuntimeExpressionUtils.isRuntimeExpression(v)) {
                          message = Tr.formatMessage(tc, "callbackMustBeRuntimeExpression", v);
                          helper.addValidationEvent(new ValidationEvent(ValidationEvent.Severity.ERROR, context.getLocation(), message));
                      }
                  }
                  // replace template fields with sample data
                  String buildURL = urlTemplate;
                  for (String v : vars) {
                      String templateVar = "{" + v + "}";
                      buildURL = buildURL.replace(templateVar, "e"); //buildURL.replace(templateVar, "e"); // Sample data
                  }
  
                  if (urlTemplate.contains("{$")) {
                      //Path within a Callback can contain variables (e.g. {$request.query.callbackUrl}/data ) which shouldn't be validated since they are not path params
                      if (OpenAPIUtils.isDebugEnabled(tc)) {
                          Tr.debug(tc, "Path contains variables. Skip validation of url: " + key);
                      }
                  } else {
                      // validate remaining url
                      //validating buildURL as URI to account for relative paths
                      if (!ValidatorUtils.isValidURI(buildURL)) {
                          message = Tr.formatMessage(tc, "callbackInvalidURL", urlTemplate);
                          helper.addValidationEvent(new ValidationEvent(ValidationEvent.Severity.ERROR, context.getLocation(), message));
                      }
                  }
              }
              // validate Path item
              Object pathItem = t.get(urlTemplate);
              if (!(pathItem instanceof PathItem)) {
                  message = Tr.formatMessage(tc, "callbackInvalidPathItem", urlTemplate);
                  helper.addValidationEvent(new ValidationEvent(ValidationEvent.Severity.ERROR, context.getLocation(), message));
              }
          }
      }